merge mozilla-inbound to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Tue, 19 Apr 2016 11:59:23 +0200
changeset 331610 ae7413abfa4d3954a6a4ce7c1613a7100f367f9a
parent 331514 9a8ff2f4978493c3fd9982652a09ffcdf2333a75 (current diff)
parent 331609 d0376a3bc28621dbd95730c7ea12ccc8e8bc267f (diff)
child 331624 ae63d8eb0e4a110e3019f6a084117102cf850d49
child 331730 53376d36d3cf6b740e48cd0c10fca34b32b013db
push id6048
push userkmoir@mozilla.com
push dateMon, 06 Jun 2016 19:02:08 +0000
treeherdermozilla-beta@46d72a56c57d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone48.0a1
first release with
nightly linux32
ae7413abfa4d / 48.0a1 / 20160419030312 / files
nightly linux64
ae7413abfa4d / 48.0a1 / 20160419030312 / files
nightly mac
ae7413abfa4d / 48.0a1 / 20160419030312 / files
nightly win32
ae7413abfa4d / 48.0a1 / 20160419030312 / files
nightly win64
ae7413abfa4d / 48.0a1 / 20160419030312 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge mozilla-inbound to mozilla-central a=merge
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -753,21 +753,21 @@
                   !!(aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT);
                 // If userTypedClear > 0, the document loaded correctly and we should be
                 // clearing the user typed value. We also need to clear the typed value
                 // if the document failed to load, to make sure the urlbar reflects the
                 // failed URI (particularly for SSL errors). However, don't clear the value
                 // if the error page's URI is about:blank, because that causes complete
                 // loss of urlbar contents for invalid URI errors (see bug 867957).
                 // Another reason to clear the userTypedValue is if this was an anchor
-                // navigation.
+                // navigation initiated by the user.
                 if (this.mBrowser.userTypedClear > 0 ||
                     ((aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_ERROR_PAGE) &&
                      aLocation.spec != "about:blank") ||
-                     isSameDocument) {
+                     (isSameDocument && this.mBrowser.inLoadURI)) {
                   this.mBrowser.userTypedValue = null;
                 }
 
                 // If the browser was playing audio, we should remove the playing state.
                 if (this.mTab.hasAttribute("soundplaying") && !isSameDocument) {
                   this.mTab.removeAttribute("soundplaying");
                   this.mTabBrowser._tabAttrModified(this.mTab, ["soundplaying"]);
                 }
--- a/browser/base/content/test/urlbar/browser.ini
+++ b/browser/base/content/test/urlbar/browser.ini
@@ -1,7 +1,10 @@
 [browser_moz_action_link.js]
 [browser_urlbar_blanking.js]
 support-files =
   file_blank_but_not_blank.html
+[browser_urlbar_locationchange_urlbar_edit_dos.js]
+support-files =
+  file_urlbar_edit_dos.html
 [browser_urlbar_stop_pending.js]
 support-files =
   slow-page.sjs
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_urlbar_locationchange_urlbar_edit_dos.js
@@ -0,0 +1,41 @@
+"use strict";
+
+function* checkURLBarValueStays(browser) {
+  gURLBar.select();
+  EventUtils.synthesizeKey("a", {});
+  is(gURLBar.value, "a", "URL bar value should match after sending a key");
+  yield new Promise(resolve => {
+    let listener = {
+      onLocationChange(aWebProgress, aRequest, aLocation, aFlags) {
+        ok(aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT,
+           "Should only get a same document location change");
+        gBrowser.selectedBrowser.removeProgressListener(filter);
+        filter = null;
+        resolve();
+      },
+    };
+    let filter = Cc["@mozilla.org/appshell/component/browser-status-filter;1"]
+                     .createInstance(Ci.nsIWebProgress);
+    filter.addProgressListener(listener, Ci.nsIWebProgress.NOTIFY_ALL);
+    gBrowser.selectedBrowser.addProgressListener(filter);
+  });
+  is(gURLBar.value, "a", "URL bar should not have been changed by location changes.");
+}
+
+add_task(function*() {
+  yield BrowserTestUtils.withNewTab({
+    gBrowser,
+    url: "http://example.com/browser/browser/base/content/test/urlbar/file_urlbar_edit_dos.html"
+  }, function*(browser) {
+    yield ContentTask.spawn(browser, "", function() {
+      content.wrappedJSObject.dos_hash();
+    });
+    yield checkURLBarValueStays(browser);
+    yield ContentTask.spawn(browser, "", function() {
+      content.clearTimeout(content.wrappedJSObject.dos_timeout);
+      content.wrappedJSObject.dos_pushState();
+    });
+    yield checkURLBarValueStays(browser);
+  });
+});
+
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/urlbar/file_urlbar_edit_dos.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Try editing the URL bar</title>
+<meta http-equiv="Content-Type" content="text/html;charset=utf-8"></meta>
+</head>
+<body>
+<script>
+var dos_timeout = null;
+function dos_hash() {
+  dos_timeout = setTimeout(function() {
+    location.hash = "#";
+  }, 50);
+}
+
+function dos_pushState() {
+  dos_timeout = setTimeout(function() {
+    history.pushState({}, "Some title", "");
+  }, 50);
+}
+</script>
+</body>
+</html>
--- a/browser/config/mozconfigs/whitelist
+++ b/browser/config/mozconfigs/whitelist
@@ -60,17 +60,16 @@ whitelist['nightly']['win32'] += [
     '. "$topsrcdir/build/mozconfig.cache"',
     'if test "$IS_NIGHTLY" != ""; then',
     'ac_add_options --disable-auto-deps',
     'fi',
 ]
 whitelist['nightly']['win64'] += [
     '. "$topsrcdir/browser/config/mozconfigs/win64/common-win64"',
     '. "$topsrcdir/build/mozconfig.cache"',
-    '. "$topsrcdir/build/mozconfig.rust"',
 ]
 
 for platform in all_platforms:
     whitelist['release'][platform] = [
         'ac_add_options --enable-update-channel=release',
         'ac_add_options --enable-official-branding',
         'mk_add_options MOZ_MAKE_FLAGS="-j4"',
         'export BUILDING_RELEASE=1',
--- a/browser/config/mozconfigs/win64/beta
+++ b/browser/config/mozconfigs/win64/beta
@@ -9,9 +9,11 @@ fi
 . "$topsrcdir/browser/config/mozconfigs/win64/common-win64"
 . "$topsrcdir/browser/config/mozconfigs/win64/common-opt"
 
 mk_add_options MOZ_PGO=1
 
 ac_add_options --enable-official-branding
 ac_add_options --enable-verify-mar
 
+. "$topsrcdir/build/mozconfig.rust"
+
 . "$topsrcdir/build/mozconfig.common.override"
--- a/browser/config/mozconfigs/win64/release
+++ b/browser/config/mozconfigs/win64/release
@@ -15,9 +15,11 @@ mk_add_options MOZ_PGO=1
 
 ac_add_options --enable-official-branding
 ac_add_options --enable-verify-mar
 
 # safeguard against someone forgetting to re-set EARLY_BETA_OR_EARLIER in
 # defines.sh during the beta cycle
 export BUILDING_RELEASE=1
 
+. "$topsrcdir/build/mozconfig.rust"
+
 . "$topsrcdir/build/mozconfig.common.override"
--- a/build/clang-plugin/clang-plugin.cpp
+++ b/build/clang-plugin/clang-plugin.cpp
@@ -89,17 +89,22 @@ private:
     virtual void run(const MatchFinder::MatchResult &Result);
   };
 
   class NeedsNoVTableTypeChecker : public MatchFinder::MatchCallback {
   public:
     virtual void run(const MatchFinder::MatchResult &Result);
   };
 
-  class NonMemMovableChecker : public MatchFinder::MatchCallback {
+  class NonMemMovableTemplateArgChecker : public MatchFinder::MatchCallback {
+  public:
+    virtual void run(const MatchFinder::MatchResult &Result);
+  };
+
+  class NonMemMovableMemberChecker : public MatchFinder::MatchCallback {
   public:
     virtual void run(const MatchFinder::MatchResult &Result);
   };
 
   class ExplicitImplicitChecker : public MatchFinder::MatchCallback {
   public:
     virtual void run(const MatchFinder::MatchResult &Result);
   };
@@ -123,17 +128,18 @@ private:
   ArithmeticArgChecker arithmeticArgChecker;
   TrivialCtorDtorChecker trivialCtorDtorChecker;
   NaNExprChecker nanExprChecker;
   NoAddRefReleaseOnReturnChecker noAddRefReleaseOnReturnChecker;
   RefCountedInsideLambdaChecker refCountedInsideLambdaChecker;
   ExplicitOperatorBoolChecker explicitOperatorBoolChecker;
   NoDuplicateRefCntMemberChecker noDuplicateRefCntMemberChecker;
   NeedsNoVTableTypeChecker needsNoVTableTypeChecker;
-  NonMemMovableChecker nonMemMovableChecker;
+  NonMemMovableTemplateArgChecker nonMemMovableTemplateArgChecker;
+  NonMemMovableMemberChecker nonMemMovableMemberChecker;
   ExplicitImplicitChecker explicitImplicitChecker;
   NoAutoTypeChecker noAutoTypeChecker;
   NoExplicitMoveConstructorChecker noExplicitMoveConstructorChecker;
   RefCountedCopyConstructorChecker refCountedCopyConstructorChecker;
   MatchFinder astMatcher;
 };
 
 namespace {
@@ -702,20 +708,25 @@ AST_MATCHER(CXXRecordDecl, hasNeedsNoVTa
 }
 
 /// This matcher will select classes which are non-memmovable
 AST_MATCHER(QualType, isNonMemMovable) {
   return NonMemMovable.hasEffectiveAnnotation(Node);
 }
 
 /// This matcher will select classes which require a memmovable template arg
-AST_MATCHER(CXXRecordDecl, needsMemMovable) {
+AST_MATCHER(CXXRecordDecl, needsMemMovableTemplateArg) {
   return MozChecker::hasCustomAnnotation(&Node, "moz_needs_memmovable_type");
 }
 
+/// This matcher will select classes which require all members to be memmovable
+AST_MATCHER(CXXRecordDecl, needsMemMovableMembers) {
+  return MozChecker::hasCustomAnnotation(&Node, "moz_needs_memmovable_members");
+}
+
 AST_MATCHER(CXXConstructorDecl, isInterestingImplicitCtor) {
   const CXXConstructorDecl *decl = Node.getCanonicalDecl();
   return
       // Skip ignored namespaces and paths
       !isInIgnoredNamespaceForImplicitCtor(decl) &&
       !isIgnoredPathForImplicitCtor(decl) &&
       // We only want Converting constructors
       decl->isConvertingConstructor(false) &&
@@ -1007,20 +1018,26 @@ DiagnosticsMatcher::DiagnosticsMatcher()
           allOf(hasAnyTemplateArgument(refersToType(hasVTable())),
                 hasNeedsNoVTableTypeAttr()))
           .bind("node"),
       &needsNoVTableTypeChecker);
 
   // Handle non-mem-movable template specializations
   astMatcher.addMatcher(
       classTemplateSpecializationDecl(
-          allOf(needsMemMovable(),
+          allOf(needsMemMovableTemplateArg(),
                 hasAnyTemplateArgument(refersToType(isNonMemMovable()))))
           .bind("specialization"),
-      &nonMemMovableChecker);
+      &nonMemMovableTemplateArgChecker);
+
+  // Handle non-mem-movable members
+  astMatcher.addMatcher(
+      cxxRecordDecl(needsMemMovableMembers())
+          .bind("decl"),
+      &nonMemMovableMemberChecker);
 
   astMatcher.addMatcher(cxxConstructorDecl(isInterestingImplicitCtor(),
                                            ofClass(allOf(isConcreteClass(),
                                                          decl().bind("class"))),
                                            unless(isMarkedImplicit()))
                             .bind("ctor"),
                         &explicitImplicitChecker);
 
@@ -1377,17 +1394,17 @@ void DiagnosticsMatcher::NeedsNoVTableTy
   }
 
   Diag.Report(specialization->getLocStart(), errorID) << specialization
                                                       << offender;
   Diag.Report(specialization->getPointOfInstantiation(), noteID)
       << specialization;
 }
 
-void DiagnosticsMatcher::NonMemMovableChecker::run(
+void DiagnosticsMatcher::NonMemMovableTemplateArgChecker::run(
     const MatchFinder::MatchResult &Result) {
   DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
   unsigned errorID = Diag.getDiagnosticIDs()->getCustomDiagID(
       DiagnosticIDs::Error,
       "Cannot instantiate %0 with non-memmovable template argument %1");
   unsigned note1ID = Diag.getDiagnosticIDs()->getCustomDiagID(
       DiagnosticIDs::Note, "instantiation of %0 requested here");
 
@@ -1396,17 +1413,17 @@ void DiagnosticsMatcher::NonMemMovableCh
       Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>("specialization");
   SourceLocation requestLoc = specialization->getPointOfInstantiation();
 
   // Report an error for every template argument which is non-memmovable
   const TemplateArgumentList &args =
       specialization->getTemplateInstantiationArgs();
   for (unsigned i = 0; i < args.size(); ++i) {
     QualType argType = args[i].getAsType();
-    if (NonMemMovable.hasEffectiveAnnotation(args[i].getAsType())) {
+    if (NonMemMovable.hasEffectiveAnnotation(argType)) {
       Diag.Report(specialization->getLocation(), errorID) << specialization
                                                           << argType;
       // XXX It would be really nice if we could get the instantiation stack
       // information
       // from Sema such that we could print a full template instantiation stack,
       // however,
       // it seems as though that information is thrown out by the time we get
       // here so we
@@ -1414,16 +1431,39 @@ void DiagnosticsMatcher::NonMemMovableCh
       // cases won't
       // be useful)
       Diag.Report(requestLoc, note1ID) << specialization;
       NonMemMovable.dumpAnnotationReason(Diag, argType, requestLoc);
     }
   }
 }
 
+void DiagnosticsMatcher::NonMemMovableMemberChecker::run(
+    const MatchFinder::MatchResult &Result) {
+  DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
+  unsigned errorID = Diag.getDiagnosticIDs()->getCustomDiagID(
+      DiagnosticIDs::Error,
+      "class %0 cannot have non-memmovable member %1 of type %2");
+
+  // Get the specialization
+  const CXXRecordDecl* Decl =
+      Result.Nodes.getNodeAs<CXXRecordDecl>("decl");
+
+  // Report an error for every member which is non-memmovable
+  for (const FieldDecl *Field : Decl->fields()) {
+    QualType Type = Field->getType();
+    if (NonMemMovable.hasEffectiveAnnotation(Type)) {
+      Diag.Report(Field->getLocation(), errorID) << Decl
+                                                 << Field
+                                                 << Type;
+      NonMemMovable.dumpAnnotationReason(Diag, Type, Decl->getLocation());
+    }
+  }
+}
+
 void DiagnosticsMatcher::ExplicitImplicitChecker::run(
     const MatchFinder::MatchResult &Result) {
   DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
   unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID(
       DiagnosticIDs::Error, "bad implicit conversion constructor for %0");
   unsigned NoteID = Diag.getDiagnosticIDs()->getCustomDiagID(
       DiagnosticIDs::Note,
       "consider adding the explicit keyword to the constructor");
--- a/build/clang-plugin/tests/TestNonMemMovable.cpp
+++ b/build/clang-plugin/tests/TestNonMemMovable.cpp
@@ -1,43 +1,44 @@
 #define MOZ_NON_MEMMOVABLE __attribute__((annotate("moz_non_memmovable")))
 #define MOZ_NEEDS_MEMMOVABLE_TYPE __attribute__((annotate("moz_needs_memmovable_type")))
+#define MOZ_NEEDS_MEMMOVABLE_MEMBERS __attribute__((annotate("moz_needs_memmovable_members")))
 
 /*
   These are a bunch of structs with variable levels of memmovability.
   They will be used as template parameters to the various NeedyTemplates
 */
 struct MOZ_NON_MEMMOVABLE NonMovable {};
 struct Movable {};
 
 // Subclasses
-struct S_NonMovable : NonMovable {}; // expected-note 48 {{'S_NonMovable' is a non-memmove()able type because it inherits from a non-memmove()able type 'NonMovable'}}
+struct S_NonMovable : NonMovable {}; // expected-note 51 {{'S_NonMovable' is a non-memmove()able type because it inherits from a non-memmove()able type 'NonMovable'}}
 struct S_Movable : Movable {};
 
 // Members
 struct W_NonMovable {
-  NonMovable m; // expected-note 32 {{'W_NonMovable' is a non-memmove()able type because member 'm' is a non-memmove()able type 'NonMovable'}}
+  NonMovable m; // expected-note 34 {{'W_NonMovable' is a non-memmove()able type because member 'm' is a non-memmove()able type 'NonMovable'}}
 };
 struct W_Movable {
   Movable m;
 };
 
 // Wrapped Subclasses
 struct WS_NonMovable {
-  S_NonMovable m; // expected-note 32 {{'WS_NonMovable' is a non-memmove()able type because member 'm' is a non-memmove()able type 'S_NonMovable'}}
+  S_NonMovable m; // expected-note 34 {{'WS_NonMovable' is a non-memmove()able type because member 'm' is a non-memmove()able type 'S_NonMovable'}}
 };
 struct WS_Movable {
   S_Movable m;
 };
 
 // Combinations of the above
-struct SW_NonMovable : W_NonMovable {}; // expected-note 16 {{'SW_NonMovable' is a non-memmove()able type because it inherits from a non-memmove()able type 'W_NonMovable'}}
+struct SW_NonMovable : W_NonMovable {}; // expected-note 17 {{'SW_NonMovable' is a non-memmove()able type because it inherits from a non-memmove()able type 'W_NonMovable'}}
 struct SW_Movable : W_Movable {};
 
-struct SWS_NonMovable : WS_NonMovable {}; // expected-note 16 {{'SWS_NonMovable' is a non-memmove()able type because it inherits from a non-memmove()able type 'WS_NonMovable'}}
+struct SWS_NonMovable : WS_NonMovable {}; // expected-note 17 {{'SWS_NonMovable' is a non-memmove()able type because it inherits from a non-memmove()able type 'WS_NonMovable'}}
 struct SWS_Movable : WS_Movable {};
 
 // Basic templated wrapper
 template <class T>
 struct Template_Inline {
   T m; // expected-note-re 56 {{'Template_Inline<{{.*}}>' is a non-memmove()able type because member 'm' is a non-memmove()able type '{{.*}}'}}
 };
 
@@ -805,8 +806,25 @@ void specialization() {
   S_NeedyTemplate2<S_SpecializedNonMovable> c2;
   W_NeedyTemplate3<S_SpecializedNonMovable> c3;
   WS_NeedyTemplate4<S_SpecializedNonMovable> c4;
   SW_NeedyTemplate5<S_SpecializedNonMovable> c5;
   Defaulted_SW_NeedyTemplate6<S_SpecializedNonMovable> c6;
   Defaulted_Templated_NeedyTemplate7<S_SpecializedNonMovable> c7;
   W_Defaulted_Templated_NeedyTemplate8<S_SpecializedNonMovable> c8;
 }
+
+class MOZ_NEEDS_MEMMOVABLE_MEMBERS NeedsMemMovableMembers {
+  Movable m1;
+  NonMovable m2; // expected-error {{class 'NeedsMemMovableMembers' cannot have non-memmovable member 'm2' of type 'NonMovable'}}
+  S_Movable sm1;
+  S_NonMovable sm2; // expected-error {{class 'NeedsMemMovableMembers' cannot have non-memmovable member 'sm2' of type 'S_NonMovable'}}
+  W_Movable wm1;
+  W_NonMovable wm2; // expected-error {{class 'NeedsMemMovableMembers' cannot have non-memmovable member 'wm2' of type 'W_NonMovable'}}
+  SW_Movable swm1;
+  SW_NonMovable swm2; // expected-error {{class 'NeedsMemMovableMembers' cannot have non-memmovable member 'swm2' of type 'SW_NonMovable'}}
+  WS_Movable wsm1;
+  WS_NonMovable wsm2; // expected-error {{class 'NeedsMemMovableMembers' cannot have non-memmovable member 'wsm2' of type 'WS_NonMovable'}}
+  SWS_Movable swsm1;
+  SWS_NonMovable swsm2; // expected-error {{class 'NeedsMemMovableMembers' cannot have non-memmovable member 'swsm2' of type 'SWS_NonMovable'}}
+};
+
+class NeedsMemMovableMembersDerived : public NeedsMemMovableMembers {};
--- a/dom/base/File.cpp
+++ b/dom/base/File.cpp
@@ -617,17 +617,17 @@ File::Constructor(const GlobalObject& aG
 
 /* static */ already_AddRefed<File>
 File::Constructor(const GlobalObject& aGlobal,
                   const nsAString& aData,
                   const ChromeFilePropertyBag& aBag,
                   ErrorResult& aRv)
 {
   if (!nsContentUtils::ThreadsafeIsCallerChrome()) {
-    aRv.Throw(NS_ERROR_FAILURE);
+    aRv.ThrowTypeError<MSG_MISSING_ARGUMENTS>(NS_LITERAL_STRING("File"));
     return nullptr;
   }
 
   nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal.GetAsSupports());
 
   RefPtr<MultipartBlobImpl> impl = new MultipartBlobImpl(EmptyString());
   impl->InitializeChromeFile(window, aData, aBag, aRv);
   if (aRv.Failed()) {
--- a/dom/base/test/mochitest.ini
+++ b/dom/base/test/mochitest.ini
@@ -888,8 +888,9 @@ skip-if = buildapp == 'b2g' #no ssl supp
 [test_bug1187157.html]
 [test_bug769117.html]
 [test_bug1250148.html]
 [test_bug1240471.html]
 [test_mozbrowser_apis_allowed.html]
 [test_mozbrowser_apis_blocked.html]
 [test_document_register.html]
 [test_bug962251.html]
+[test_bug1259588.html]
new file mode 100644
--- /dev/null
+++ b/dom/base/test/test_bug1259588.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test for Bug 1259588</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+test(function() {
+  assert_throws(new TypeError, function() {
+    new File("");
+  }, "new File(\"\") should throw TypeError exception");
+}, "Test new File(\"\") should throw exception");
+</script>
--- a/dom/camera/GonkCameraControl.cpp
+++ b/dom/camera/GonkCameraControl.cpp
@@ -2377,17 +2377,17 @@ nsGonkCameraControl::OnPoster(void* aDat
 void
 nsGonkCameraControl::OnNewPreviewFrame(layers::TextureClient* aBuffer)
 {
 #ifdef MOZ_WIDGET_GONK
   RefPtr<GrallocImage> frame = new GrallocImage();
 
   IntSize picSize(mCurrentConfiguration.mPreviewSize.width,
                   mCurrentConfiguration.mPreviewSize.height);
-  frame->SetData(aBuffer, picSize);
+  frame->AdoptData(aBuffer, picSize);
 
   if (mCapturePoster.exchange(false)) {
     CreatePoster(frame,
                  mCurrentConfiguration.mPreviewSize.width,
                  mCurrentConfiguration.mPreviewSize.height,
                  mVideoRotation);
     return;
   }
--- a/dom/media/MediaData.cpp
+++ b/dom/media/MediaData.cpp
@@ -242,19 +242,19 @@ bool VideoData::SetVideoDataToImage(Plan
   data.mCrSkip = Cr.mSkip;
   data.mPicX = aPicture.x;
   data.mPicY = aPicture.y;
   data.mPicSize = aPicture.Size();
   data.mStereoMode = aInfo.mStereoMode;
 
   aVideoImage->SetDelayedConversion(true);
   if (aCopyData) {
-    return aVideoImage->SetData(data);
+    return aVideoImage->CopyData(data);
   } else {
-    return aVideoImage->SetDataNoCopy(data);
+    return aVideoImage->AdoptData(data);
   }
 }
 
 /* static */
 already_AddRefed<VideoData>
 VideoData::Create(const VideoInfo& aInfo,
                   ImageContainer* aContainer,
                   Image* aImage,
@@ -475,17 +475,17 @@ VideoData::Create(const VideoInfo& aInfo
                                       aTime,
                                       aDuration,
                                       aKeyframe,
                                       aTimecode,
                                       aInfo.mDisplay,
                                       0));
 
   RefPtr<layers::GrallocImage> image = new layers::GrallocImage();
-  image->SetData(aBuffer, aPicture.Size());
+  image->AdoptData(aBuffer, aPicture.Size());
   v->mImage = image;
 
   return v.forget();
 }
 #endif  // MOZ_OMX_DECODER
 
 MediaRawData::MediaRawData()
   : MediaData(RAW_DATA, 0)
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -683,21 +683,21 @@ private:
     return mPlayState == MediaDecoder::PLAY_STATE_PLAYING ||
            mNextPlayState == MediaDecoder::PLAY_STATE_PLAYING;
   }
 
   // Queued seek - moves to mCurrentSeek when DecodeFirstFrame completes.
   SeekJob mQueuedSeek;
 
   // mSeekTask is responsible for executing the current seek request.
-  RefPtr<media::SeekTask> mSeekTask;
-  MozPromiseRequestHolder<media::SeekTask::SeekTaskPromise> mSeekTaskRequest;
+  RefPtr<SeekTask> mSeekTask;
+  MozPromiseRequestHolder<SeekTask::SeekTaskPromise> mSeekTaskRequest;
 
-  void OnSeekTaskResolved(media::SeekTaskResolveValue aValue);
-  void OnSeekTaskRejected(media::SeekTaskRejectValue aValue);
+  void OnSeekTaskResolved(SeekTaskResolveValue aValue);
+  void OnSeekTaskRejected(SeekTaskRejectValue aValue);
 
   // Media Fragment end time in microseconds. Access controlled by decoder monitor.
   int64_t mFragmentEndTime;
 
   // The media sink resource.  Used on the state machine thread.
   RefPtr<media::MediaSink> mMediaSink;
 
   // The reader, don't call its methods with the decoder monitor held.
--- a/dom/media/MediaStreamGraph.cpp
+++ b/dom/media/MediaStreamGraph.cpp
@@ -885,17 +885,17 @@ SetImageToBlackPixel(PlanarYCbCrImage* a
   uint8_t blackPixel[] = { 0x10, 0x80, 0x80 };
 
   PlanarYCbCrData data;
   data.mYChannel = blackPixel;
   data.mCbChannel = blackPixel + 1;
   data.mCrChannel = blackPixel + 2;
   data.mYStride = data.mCbCrStride = 1;
   data.mPicSize = data.mYSize = data.mCbCrSize = IntSize(1, 1);
-  aImage->SetData(data);
+  aImage->CopyData(data);
 }
 
 class VideoFrameContainerInvalidateRunnable : public nsRunnable {
 public:
   explicit VideoFrameContainerInvalidateRunnable(VideoFrameContainer* aVideoFrameContainer)
     : mVideoFrameContainer(aVideoFrameContainer)
   {}
   NS_IMETHOD Run()
--- a/dom/media/SeekTask.cpp
+++ b/dom/media/SeekTask.cpp
@@ -30,18 +30,16 @@ extern LazyLogModule gMediaSampleLog;
   LOG(gMediaSampleLog, LogLevel::Debug, x, ##__VA_ARGS__)
 
 // Somehow MSVC doesn't correctly delete the comma before ##__VA_ARGS__
 // when __VA_ARGS__ expands to nothing. This is a workaround for it.
 #define DECODER_WARN_HELPER(a, b) NS_WARNING b
 #define DECODER_WARN(x, ...) \
   DECODER_WARN_HELPER(0, (nsPrintfCString("Decoder=%p " x, mDecoderID, ##__VA_ARGS__).get()))
 
-namespace media {
-
 /*static*/ already_AddRefed<SeekTask>
 SeekTask::CreateSeekTask(const void* aDecoderID,
                          AbstractThread* aThread,
                          MediaDecoderReader* aReader,
                          MediaDecoderReaderWrapper* aReaderWrapper,
                          SeekJob&& aSeekJob,
                          const MediaInfo& aInfo,
                          const media::TimeUnit& aDuration,
@@ -720,10 +718,9 @@ SeekTask::OnVideoNotDecoded(MediaDecoder
     }
 
     mIsVideoQueueFinished = true;
     mDropVideoUntilNextDiscontinuity = false; // To make IsVideoSeekComplete() return TRUE.
     CheckIfSeekComplete();
   }
 }
 
-} // namespace media
 } // namespace mozilla
--- a/dom/media/SeekTask.h
+++ b/dom/media/SeekTask.h
@@ -12,18 +12,16 @@
 #include "SeekJob.h"
 
 namespace mozilla {
 
 class AbstractThread;
 class MediaData;
 class MediaDecoderReaderWrapper;
 
-namespace media {
-
 struct SeekTaskResolveValue
 {
   RefPtr<MediaData> mSeekedAudioData;
   RefPtr<MediaData> mSeekedVideoData;
   bool mIsAudioQueueFinished;
   bool mIsVideoQueueFinished;
   bool mNeedToStopPrerollingAudio;
   bool mNeedToStopPrerollingVideo;
@@ -173,12 +171,11 @@ protected:
   RefPtr<MediaData> mSeekedAudioData;
   RefPtr<MediaData> mSeekedVideoData;
   bool mIsAudioQueueFinished;
   bool mIsVideoQueueFinished;
   bool mNeedToStopPrerollingAudio;
   bool mNeedToStopPrerollingVideo;
 };
 
-} // namespace media
 } // namespace mozilla
 
 #endif /* SEEK_TASK_H */
--- a/dom/media/VideoSegment.cpp
+++ b/dom/media/VideoSegment.cpp
@@ -74,18 +74,18 @@ VideoFrame::CreateBlackImage(const gfx::
   data.mCbChannel = frame.get() + aSize.height * data.mYStride;
   data.mCrChannel = data.mCbChannel + aSize.height * data.mCbCrStride / 2;
   data.mCbCrSize = gfx::IntSize(aSize.width / 2, aSize.height / 2);
   data.mPicX = 0;
   data.mPicY = 0;
   data.mPicSize = gfx::IntSize(aSize.width, aSize.height);
   data.mStereoMode = StereoMode::MONO;
 
-  // SetData copies data, so we can free data.
-  if (!image->SetData(data)) {
+  // Copies data, so we can free data.
+  if (!image->CopyData(data)) {
     MOZ_ASSERT(false);
     return nullptr;
   }
 
   return image.forget();
 }
 
 VideoChunk::VideoChunk()
--- a/dom/media/android/AndroidMediaReader.cpp
+++ b/dom/media/android/AndroidMediaReader.cpp
@@ -416,17 +416,17 @@ AndroidMediaReader::ImageBufferCallback:
   frameDesc.mYSkip = 0;
   frameDesc.mCbSkip = 0;
   frameDesc.mCrSkip = 0;
 
   frameDesc.mPicX = 0;
   frameDesc.mPicY = 0;
   frameDesc.mPicSize = IntSize(aWidth, aHeight);
 
-  yuvImage->SetDataNoCopy(frameDesc);
+  yuvImage->AdoptData(frameDesc);
 
   return buffer;
 }
 
 already_AddRefed<Image>
 AndroidMediaReader::ImageBufferCallback::GetImage()
 {
   return mImage.forget();
--- a/dom/media/gtest/TestVideoTrackEncoder.cpp
+++ b/dom/media/gtest/TestVideoTrackEncoder.cpp
@@ -82,17 +82,17 @@ private:
     data.mCbChannel = cb;
     data.mCbSkip = 0;
 
     // CrCb plane vectors.
     data.mCbCrStride = halfWidth;
     data.mCbCrSize.width = halfWidth;
     data.mCbCrSize.height = halfHeight;
 
-    image->SetData(data);
+    image->CopyData(data);
     return image;
   }
 
   Image *CreateNV12Image()
   {
     PlanarYCbCrImage *image = new RecyclingPlanarYCbCrImage(new BufferRecycleBin());
     PlanarYCbCrData data;
     data.mPicSize = mImageSize;
@@ -119,17 +119,17 @@ private:
     data.mCbChannel = cb;
     data.mCbSkip = 1;
 
     // 4:2:0.
     data.mCbCrStride = mImageSize.width;
     data.mCbCrSize.width = halfWidth;
     data.mCbCrSize.height = halfHeight;
 
-    image->SetData(data);
+    image->CopyData(data);
     return image;
   }
 
   Image *CreateNV21Image()
   {
     PlanarYCbCrImage *image = new RecyclingPlanarYCbCrImage(new BufferRecycleBin());
     PlanarYCbCrData data;
     data.mPicSize = mImageSize;
@@ -156,17 +156,17 @@ private:
     data.mCbChannel = cb;
     data.mCbSkip = 1;
 
     // 4:2:0.
     data.mCbCrStride = mImageSize.width;
     data.mCbCrSize.width = halfWidth;
     data.mCbCrSize.height = halfHeight;
 
-    image->SetData(data);
+    image->CopyData(data);
     return image;
   }
 
 private:
   mozilla::gfx::IntSize mImageSize;
   nsTArray<uint8_t> mSourceBuffer;
 };
 
--- a/dom/media/omx/OMXCodecWrapper.cpp
+++ b/dom/media/omx/OMXCodecWrapper.cpp
@@ -484,17 +484,17 @@ OMXVideoEncoder::Encode(const Image* aIm
   ImageFormat format = ImageFormat::PLANAR_YCBCR;
   if (img) {
     format = img->GetFormat();
     gfx::IntSize size = img->GetSize();
     // Validate input image.
     NS_ENSURE_TRUE(aWidth == size.width, NS_ERROR_INVALID_ARG);
     NS_ENSURE_TRUE(aHeight == size.height, NS_ERROR_INVALID_ARG);
     if (format == ImageFormat::PLANAR_YCBCR) {
-      // Test for data, allowing SetDataNoCopy() on an image without an mBuffer
+      // Test for data, allowing AdoptData() on an image without an mBuffer
       // (as used from WebrtcOMXH264VideoCodec, and a few other places) - bug 1067442
       const PlanarYCbCrData* yuv = static_cast<PlanarYCbCrImage*>(img)->GetData();
       NS_ENSURE_TRUE(yuv->mYChannel, NS_ERROR_INVALID_ARG);
     } else if (format == ImageFormat::GRALLOC_PLANAR_YCBCR) {
       // Reject unsupported gralloc-ed buffers.
       int halFormat = static_cast<GrallocImage*>(img)->GetGraphicBuffer()->getPixelFormat();
       NS_ENSURE_TRUE(halFormat == HAL_PIXEL_FORMAT_YCrCb_420_SP ||
                      halFormat == HAL_PIXEL_FORMAT_YV12 ||
--- a/dom/media/platforms/android/AndroidDecoderModule.cpp
+++ b/dom/media/platforms/android/AndroidDecoderModule.cpp
@@ -497,17 +497,17 @@ MediaCodecDataDecoder::QueueSample(const
   PodCopy(static_cast<uint8_t*>(directBuffer), aSample->Data(), aSample->Size());
 
   res = mDecoder->QueueInputBuffer(inputIndex, 0, aSample->Size(),
                                    aSample->mTime, 0);
   if (NS_FAILED(res)) {
     return res;
   }
 
-  mDurations.push(TimeUnit::FromMicroseconds(aSample->mDuration));
+  mDurations.push_back(TimeUnit::FromMicroseconds(aSample->mDuration));
   return NS_OK;
 }
 
 nsresult
 MediaCodecDataDecoder::QueueEOS()
 {
   mMonitor.AssertCurrentThreadOwns();
 
@@ -542,17 +542,17 @@ MediaCodecDataDecoder::HandleEOS(int32_t
   mDecoder->ReleaseOutputBuffer(aOutputStatus, false);
 }
 
 TimeUnit
 MediaCodecDataDecoder::GetOutputDuration()
 {
   MOZ_ASSERT(!mDurations.empty(), "Should have had a duration queued");
   const TimeUnit duration = mDurations.front();
-  mDurations.pop();
+  mDurations.pop_front();
   return duration;
 }
 
 nsresult
 MediaCodecDataDecoder::ProcessOutput(
     BufferInfo::Param aInfo, MediaFormat::Param aFormat, int32_t aStatus)
 {
   AutoLocalJNIFrame frame(jni::GetEnvForThread(), 1);
@@ -595,17 +595,17 @@ MediaCodecDataDecoder::DecoderLoop()
     }
 
     if (sample) {
       res = QueueSample(sample);
       if (NS_SUCCEEDED(res)) {
         // We've fed this into the decoder, so remove it from the queue.
         MonitorAutoLock lock(mMonitor);
         MOZ_RELEASE_ASSERT(mQueue.size(), "Queue may not be empty");
-        mQueue.pop();
+        mQueue.pop_front();
         isOutputDone = false;
       }
     }
 
     if (isOutputDone) {
       continue;
     }
 
@@ -693,38 +693,30 @@ MediaCodecDataDecoder::State(ModuleState
   if (ok) {
     LOG("%s -> %s", ModuleStateStr(mState), ModuleStateStr(aState));
     mState = aState;
   }
 
   return ok;
 }
 
-template<typename T>
-void
-Clear(T& aCont)
-{
-  T aEmpty = T();
-  swap(aCont, aEmpty);
-}
-
 void
 MediaCodecDataDecoder::ClearQueue()
 {
   mMonitor.AssertCurrentThreadOwns();
 
-  Clear(mQueue);
-  Clear(mDurations);
+  mQueue.clear();
+  mDurations.clear();
 }
 
 nsresult
 MediaCodecDataDecoder::Input(MediaRawData* aSample)
 {
   MonitorAutoLock lock(mMonitor);
-  mQueue.push(aSample);
+  mQueue.push_back(aSample);
   lock.NotifyAll();
 
   return NS_OK;
 }
 
 nsresult
 MediaCodecDataDecoder::ResetInputBuffers()
 {
--- a/dom/media/platforms/android/AndroidDecoderModule.h
+++ b/dom/media/platforms/android/AndroidDecoderModule.h
@@ -7,21 +7,21 @@
 
 #include "PlatformDecoderModule.h"
 
 #include "MediaCodec.h"
 #include "SurfaceTexture.h"
 #include "TimeUnits.h"
 #include "mozilla/Monitor.h"
 
-#include <queue>
+#include <deque>
 
 namespace mozilla {
 
-typedef std::queue<RefPtr<MediaRawData>> SampleQueue;
+typedef std::deque<RefPtr<MediaRawData>> SampleQueue;
 
 class AndroidDecoderModule : public PlatformDecoderModule {
 public:
   already_AddRefed<MediaDataDecoder>
   CreateVideoDecoder(const VideoInfo& aConfig,
                      layers::LayersBackend aLayersBackend,
                      layers::ImageContainer* aImageContainer,
                      FlushableTaskQueue* aVideoTaskQueue,
@@ -129,14 +129,14 @@ protected:
 
   // Only these members are protected by mMonitor.
   Monitor mMonitor;
 
   ModuleState mState;
 
   SampleQueue mQueue;
   // Durations are stored in microseconds.
-  std::queue<media::TimeUnit> mDurations;
+  std::deque<media::TimeUnit> mDurations;
 };
 
 } // namespace mozilla
 
 #endif
--- a/dom/media/webrtc/MediaEngineDefault.cpp
+++ b/dom/media/webrtc/MediaEngineDefault.cpp
@@ -246,17 +246,17 @@ MediaEngineDefaultVideoSource::Notify(ns
 #ifdef MOZ_WEBRTC
   uint64_t timestamp = PR_Now();
   YuvStamper::Encode(mOpts.mWidth, mOpts.mHeight, mOpts.mWidth,
 		     data.mYChannel,
 		     reinterpret_cast<unsigned char*>(&timestamp), sizeof(timestamp),
 		     0, 0);
 #endif
 
-  bool setData = ycbcr_image->SetData(data);
+  bool setData = ycbcr_image->CopyData(data);
   MOZ_ASSERT(setData);
 
   // SetData copies data, so we can free the frame
   ReleaseFrame(data);
 
   if (!setData) {
     return NS_ERROR_FAILURE;
   }
--- a/dom/media/webrtc/MediaEngineGonkVideoSource.cpp
+++ b/dom/media/webrtc/MediaEngineGonkVideoSource.cpp
@@ -784,17 +784,17 @@ MediaEngineGonkVideoSource::RotateImage(
                           dstPtr + (yStride * dstHeight), uvStride,
                           0, 0,
                           graphicBuffer->getStride(), aHeight,
                           aWidth, aHeight,
                           static_cast<libyuv::RotationMode>(mRotation),
                           libyuv::FOURCC_NV21);
     destBuffer->unlock();
 
-    image->AsGrallocImage()->SetData(textureClient, gfx::IntSize(dstWidth, dstHeight));
+    image->AsGrallocImage()->AdoptData(textureClient, gfx::IntSize(dstWidth, dstHeight));
   } else {
     // Handle out of gralloc case.
     image = mImageContainer->CreatePlanarYCbCrImage();
     uint8_t* dstPtr = image->AsPlanarYCbCrImage()->AllocateAndGetNewBuffer(size);
 
     libyuv::ConvertToI420(srcPtr, size,
                           dstPtr, dstWidth,
                           dstPtr + (dstWidth * dstHeight), half_width,
@@ -816,17 +816,17 @@ MediaEngineGonkVideoSource::RotateImage(
     data.mCbChannel = dstPtr + dstHeight * data.mYStride;
     data.mCrChannel = data.mCbChannel + data.mCbCrStride * (dstHeight / 2);
     data.mCbCrSize = IntSize(dstWidth / 2, dstHeight / 2);
     data.mPicX = 0;
     data.mPicY = 0;
     data.mPicSize = IntSize(dstWidth, dstHeight);
     data.mStereoMode = StereoMode::MONO;
 
-    image->AsPlanarYCbCrImage()->SetDataNoCopy(data);
+    image->AsPlanarYCbCrImage()->AdoptData(data);
   }
   graphicBuffer->unlock();
 
   // Implicitly releases last preview image.
   mImage = image.forget();
 }
 
 bool
--- a/dom/media/webrtc/MediaEngineRemoteVideoSource.cpp
+++ b/dom/media/webrtc/MediaEngineRemoteVideoSource.cpp
@@ -337,17 +337,17 @@ MediaEngineRemoteVideoSource::DeliverFra
   data.mCbChannel = frame + mHeight * data.mYStride;
   data.mCrChannel = data.mCbChannel + ((mHeight+1)/2) * data.mCbCrStride;
   data.mCbCrSize = IntSize((mWidth+1)/ 2, (mHeight+1)/ 2);
   data.mPicX = 0;
   data.mPicY = 0;
   data.mPicSize = IntSize(mWidth, mHeight);
   data.mStereoMode = StereoMode::MONO;
 
-  if (!image->SetData(data)) {
+  if (!image->CopyData(data)) {
     MOZ_ASSERT(false);
     return 0;
   }
 
 #ifdef DEBUG
   static uint32_t frame_num = 0;
   LOGFRAME(("frame %d (%dx%d); timestamp %u, ntp_time %" PRIu64 ", render_time %" PRIu64,
             frame_num++, mWidth, mHeight, time_stamp, ntp_time, render_time));
--- a/dom/notification/Notification.cpp
+++ b/dom/notification/Notification.cpp
@@ -2570,18 +2570,18 @@ public:
 
     RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
     RefPtr<ServiceWorkerRegistrationInfo> registration =
       swm->GetRegistration(principal, mScope);
 
     // This is coming from a ServiceWorkerRegistrationWorkerThread.
     MOZ_ASSERT(registration);
 
-    if (!registration->mActiveWorker ||
-        registration->mActiveWorker->ID() != mWorkerPrivate->ServiceWorkerID()) {
+    if (!registration->GetActive() ||
+        registration->GetActive()->ID() != mWorkerPrivate->ServiceWorkerID()) {
       mRv = NS_ERROR_NOT_AVAILABLE;
     }
 
     return true;
   }
 
   nsresult
   Result()
--- a/dom/workers/ServiceWorkerInfo.cpp
+++ b/dom/workers/ServiceWorkerInfo.cpp
@@ -1,16 +1,18 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ServiceWorkerInfo.h"
 
+#include "ServiceWorkerScriptCache.h"
+
 BEGIN_WORKERS_NAMESPACE
 
 NS_IMPL_ISUPPORTS(ServiceWorkerInfo, nsIServiceWorkerInfo)
 
 NS_IMETHODIMP
 ServiceWorkerInfo::GetScriptSpec(nsAString& aScriptSpec)
 {
   AssertIsOnMainThread();
@@ -134,16 +136,19 @@ ServiceWorkerInfo::UpdateState(ServiceWo
   // TODO: Do we care that these events will race with the propagation of the
   //       state change?
   if (aState == ServiceWorkerState::Activated && mState != aState) {
     mServiceWorkerPrivate->Activated();
   }
   mState = aState;
   nsCOMPtr<nsIRunnable> r = new ChangeStateUpdater(mInstances, mState);
   MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(r.forget()));
+  if (mState == ServiceWorkerState::Redundant) {
+    serviceWorkerScriptCache::PurgeCache(mPrincipal, mCacheName);
+  }
 }
 
 ServiceWorkerInfo::ServiceWorkerInfo(nsIPrincipal* aPrincipal,
                                      const nsACString& aScope,
                                      const nsACString& aScriptSpec,
                                      const nsAString& aCacheName)
   : mPrincipal(aPrincipal)
   , mScope(aScope)
--- a/dom/workers/ServiceWorkerManager.cpp
+++ b/dom/workers/ServiceWorkerManager.cpp
@@ -177,19 +177,19 @@ PopulateRegistrationData(nsIPrincipal* a
 
   aData.scope() = aRegistration->mScope;
 
   RefPtr<ServiceWorkerInfo> newest = aRegistration->Newest();
   if (NS_WARN_IF(!newest)) {
     return NS_ERROR_FAILURE;
   }
 
-  if (aRegistration->mActiveWorker) {
-    aData.currentWorkerURL() = aRegistration->mActiveWorker->ScriptSpec();
-    aData.cacheName() = aRegistration->mActiveWorker->CacheName();
+  if (aRegistration->GetActive()) {
+    aData.currentWorkerURL() = aRegistration->GetActive()->ScriptSpec();
+    aData.cacheName() = aRegistration->GetActive()->CacheName();
   }
 
   return NS_OK;
 }
 
 class TeardownRunnable final : public nsRunnable
 {
 public:
@@ -1176,17 +1176,17 @@ ServiceWorkerManager::CheckReadyPromise(
   MOZ_ASSERT(doc);
 
   nsCOMPtr<nsIPrincipal> principal = doc->NodePrincipal();
   MOZ_ASSERT(principal);
 
   RefPtr<ServiceWorkerRegistrationInfo> registration =
     GetServiceWorkerRegistrationInfo(principal, aURI);
 
-  if (registration && registration->mActiveWorker) {
+  if (registration && registration->GetActive()) {
     NS_ConvertUTF8toUTF16 scope(registration->mScope);
     RefPtr<ServiceWorkerRegistrationMainThread> swr =
       aWindow->GetServiceWorkerRegistration(scope);
     aPromise->MaybeResolve(swr);
     return true;
   }
 
   return false;
@@ -1206,32 +1206,32 @@ ServiceWorkerManager::GetActiveWorkerInf
   nsCOMPtr<nsIPrincipal> principal =
     BasePrincipal::CreateCodebasePrincipal(scopeURI, aOriginAttributes);
   RefPtr<ServiceWorkerRegistrationInfo> registration =
     GetServiceWorkerRegistrationInfo(principal, scopeURI);
   if (!registration) {
     return nullptr;
   }
 
-  return registration->mActiveWorker;
+  return registration->GetActive();
 }
 
 ServiceWorkerInfo*
 ServiceWorkerManager::GetActiveWorkerInfoForDocument(nsIDocument* aDocument)
 {
   AssertIsOnMainThread();
 
   RefPtr<ServiceWorkerRegistrationInfo> registration;
   GetDocumentRegistration(aDocument, getter_AddRefs(registration));
 
   if (!registration) {
     return nullptr;
   }
 
-  return registration->mActiveWorker;
+  return registration->GetActive();
 }
 
 namespace {
 
 class UnregisterJobCallback final : public ServiceWorkerJob::Callback
 {
   nsCOMPtr<nsIServiceWorkerUnregisterCallback> mCallback;
 
@@ -1596,29 +1596,29 @@ ServiceWorkerManager::LoadRegistration(
 
   RefPtr<ServiceWorkerRegistrationInfo> registration =
     GetRegistration(principal, aRegistration.scope());
   if (!registration) {
     registration = CreateNewRegistration(aRegistration.scope(), principal);
   } else {
     // If active worker script matches our expectations for a "current worker",
     // then we are done.
-    if (registration->mActiveWorker &&
-        registration->mActiveWorker->ScriptSpec() == aRegistration.currentWorkerURL()) {
+    if (registration->GetActive() &&
+        registration->GetActive()->ScriptSpec() == aRegistration.currentWorkerURL()) {
       // No needs for updates.
       return;
     }
   }
 
   const nsCString& currentWorkerURL = aRegistration.currentWorkerURL();
   if (!currentWorkerURL.IsEmpty()) {
-    registration->mActiveWorker =
+    registration->SetActive(
       new ServiceWorkerInfo(registration->mPrincipal, registration->mScope,
-                            currentWorkerURL, aRegistration.cacheName());
-    registration->mActiveWorker->SetActivateStateUncheckedWithoutEvent(ServiceWorkerState::Activated);
+                            currentWorkerURL, aRegistration.cacheName()));
+    registration->GetActive()->SetActivateStateUncheckedWithoutEvent(ServiceWorkerState::Activated);
   }
 }
 
 void
 ServiceWorkerManager::LoadRegistrations(
                   const nsTArray<ServiceWorkerRegistrationData>& aRegistrations)
 {
   AssertIsOnMainThread();
@@ -2018,19 +2018,19 @@ ServiceWorkerManager::StopControllingADo
 {
   aRegistration->StopControllingADocument();
   if (!aRegistration->IsControllingDocuments()) {
     if (aRegistration->mPendingUninstall) {
       RemoveRegistration(aRegistration);
     } else {
       // If the registration has an active worker that is running
       // this might be a good time to stop it.
-      if (aRegistration->mActiveWorker) {
+      if (aRegistration->GetActive()) {
         ServiceWorkerPrivate* serviceWorkerPrivate =
-          aRegistration->mActiveWorker->WorkerPrivate();
+          aRegistration->GetActive()->WorkerPrivate();
         serviceWorkerPrivate->NoteStoppedControllingDocuments();
       }
       aRegistration->TryToActivateAsync();
     }
   }
 }
 
 NS_IMETHODIMP
@@ -2153,21 +2153,21 @@ ServiceWorkerManager::GetServiceWorkerFo
   RefPtr<ServiceWorkerRegistrationInfo> registration =
     GetRegistration(documentPrincipal, scope);
   if (NS_WARN_IF(!registration)) {
     return NS_ERROR_FAILURE;
   }
 
   RefPtr<ServiceWorkerInfo> info;
   if (aWhichWorker == WhichServiceWorker::INSTALLING_WORKER) {
-    info = registration->mInstallingWorker;
+    info = registration->GetInstalling();
   } else if (aWhichWorker == WhichServiceWorker::WAITING_WORKER) {
-    info = registration->mWaitingWorker;
+    info = registration->GetWaiting();
   } else if (aWhichWorker == WhichServiceWorker::ACTIVE_WORKER) {
-    info = registration->mActiveWorker;
+    info = registration->GetActive();
   } else {
     MOZ_CRASH("Invalid worker type");
   }
 
   if (NS_WARN_IF(!info)) {
     return NS_ERROR_DOM_NOT_FOUND_ERR;
   }
 
@@ -2296,18 +2296,18 @@ ServiceWorkerManager::DispatchFetchEvent
       GetServiceWorkerRegistrationInfo(principal, uri);
     if (!registration) {
       NS_WARNING("No registration found when dispatching the fetch event");
       aRv.Throw(NS_ERROR_FAILURE);
       return;
     }
 
     // This should only happen if IsAvailable() returned true.
-    MOZ_ASSERT(registration->mActiveWorker);
-    serviceWorker = registration->mActiveWorker;
+    MOZ_ASSERT(registration->GetActive());
+    serviceWorker = registration->GetActive();
 
     AddNavigationInterception(serviceWorker->Scope(), aChannel);
   }
 
   if (NS_WARN_IF(aRv.Failed()) || !serviceWorker) {
     return;
   }
 
@@ -2338,17 +2338,17 @@ bool
 ServiceWorkerManager::IsAvailable(nsIPrincipal* aPrincipal,
                                   nsIURI* aURI)
 {
   MOZ_ASSERT(aPrincipal);
   MOZ_ASSERT(aURI);
 
   RefPtr<ServiceWorkerRegistrationInfo> registration =
     GetServiceWorkerRegistrationInfo(aPrincipal, aURI);
-  return registration && registration->mActiveWorker;
+  return registration && registration->GetActive();
 }
 
 bool
 ServiceWorkerManager::IsControlled(nsIDocument* aDoc, ErrorResult& aRv)
 {
   MOZ_ASSERT(aDoc);
 
   if (nsContentUtils::IsInPrivateBrowsing(aDoc)) {
@@ -2373,17 +2373,17 @@ ServiceWorkerManager::GetDocumentRegistr
                                               ServiceWorkerRegistrationInfo** aRegistrationInfo)
 {
   RefPtr<ServiceWorkerRegistrationInfo> registration;
   if (!mControlledDocuments.Get(aDoc, getter_AddRefs(registration))) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   // If the document is controlled, the current worker MUST be non-null.
-  if (!registration->mActiveWorker) {
+  if (!registration->GetActive()) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   registration.forget(aRegistrationInfo);
   return NS_OK;
 }
 
 /*
@@ -2401,19 +2401,19 @@ ServiceWorkerManager::GetDocumentControl
   }
 
   RefPtr<ServiceWorkerRegistrationInfo> registration;
   nsresult rv = GetDocumentRegistration(doc, getter_AddRefs(registration));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
-  MOZ_ASSERT(registration->mActiveWorker);
+  MOZ_ASSERT(registration->GetActive());
   RefPtr<ServiceWorker> serviceWorker =
-    registration->mActiveWorker->GetOrCreateInstance(aWindow);
+    registration->GetActive()->GetOrCreateInstance(aWindow);
 
   serviceWorker.forget(aServiceWorker);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 ServiceWorkerManager::GetInstalling(nsPIDOMWindowInner* aWindow,
                                     const nsAString& aScope,
@@ -2518,17 +2518,17 @@ ServiceWorkerManager::SoftUpdate(const P
   }
 
   // "If registration's uninstalling flag is set, abort these steps."
   if (registration->mPendingUninstall) {
     return;
   }
 
   // "If registration's installing worker is not null, abort these steps."
-  if (registration->mInstallingWorker) {
+  if (registration->GetInstalling()) {
     return;
   }
 
   // "Let newestWorker be the result of running Get Newest Worker algorithm
   // passing registration as its argument.
   // If newestWorker is null, abort these steps."
   RefPtr<ServiceWorkerInfo> newest = registration->Newest();
   if (!newest) {
@@ -2789,17 +2789,17 @@ ServiceWorkerManager::GetAllClients(nsIP
   }
 }
 
 void
 ServiceWorkerManager::MaybeClaimClient(nsIDocument* aDocument,
                                        ServiceWorkerRegistrationInfo* aWorkerRegistration)
 {
   MOZ_ASSERT(aWorkerRegistration);
-  MOZ_ASSERT(aWorkerRegistration->mActiveWorker);
+  MOZ_ASSERT(aWorkerRegistration->GetActive());
 
   // Same origin check
   if (!aWorkerRegistration->mPrincipal->Equals(aDocument->NodePrincipal())) {
     return;
   }
 
   // The registration that should be controlling the client
   RefPtr<ServiceWorkerRegistrationInfo> matchingRegistration =
@@ -2824,18 +2824,18 @@ ServiceWorkerManager::MaybeClaimClient(n
 
 nsresult
 ServiceWorkerManager::ClaimClients(nsIPrincipal* aPrincipal,
                                    const nsCString& aScope, uint64_t aId)
 {
   RefPtr<ServiceWorkerRegistrationInfo> registration =
     GetRegistration(aPrincipal, aScope);
 
-  if (!registration || !registration->mActiveWorker ||
-      !(registration->mActiveWorker->ID() == aId)) {
+  if (!registration || !registration->GetActive() ||
+      !(registration->GetActive()->ID() == aId)) {
     // The worker is not active.
     return NS_ERROR_DOM_INVALID_STATE_ERR;
   }
 
   RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
   for (auto iter = mAllDocuments.Iter(); !iter.Done(); iter.Next()) {
     nsCOMPtr<nsIDocument> document = do_QueryInterface(iter.Get()->GetKey());
     swm->MaybeClaimClient(document, registration);
@@ -2850,23 +2850,23 @@ ServiceWorkerManager::SetSkipWaitingFlag
                                          uint64_t aServiceWorkerID)
 {
   RefPtr<ServiceWorkerRegistrationInfo> registration =
     GetRegistration(aPrincipal, aScope);
   if (NS_WARN_IF(!registration)) {
     return NS_ERROR_FAILURE;
   }
 
-  if (registration->mInstallingWorker &&
-      (registration->mInstallingWorker->ID() == aServiceWorkerID)) {
-    registration->mInstallingWorker->SetSkipWaitingFlag();
-  } else if (registration->mWaitingWorker &&
-             (registration->mWaitingWorker->ID() == aServiceWorkerID)) {
-    registration->mWaitingWorker->SetSkipWaitingFlag();
-    if (registration->mWaitingWorker->State() == ServiceWorkerState::Installed) {
+  if (registration->GetInstalling() &&
+      (registration->GetInstalling()->ID() == aServiceWorkerID)) {
+    registration->GetInstalling()->SetSkipWaitingFlag();
+  } else if (registration->GetWaiting() &&
+             (registration->GetWaiting()->ID() == aServiceWorkerID)) {
+    registration->GetWaiting()->SetSkipWaitingFlag();
+    if (registration->GetWaiting()->State() == ServiceWorkerState::Installed) {
       registration->TryToActivateAsync();
     }
   } else {
     NS_WARNING("Failed to set skipWaiting flag, no matching worker.");
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
--- a/dom/workers/ServiceWorkerRegistrationInfo.cpp
+++ b/dom/workers/ServiceWorkerRegistrationInfo.cpp
@@ -15,46 +15,29 @@ ServiceWorkerRegistrationInfo::Clear()
     mInstallingWorker->UpdateState(ServiceWorkerState::Redundant);
     mInstallingWorker->WorkerPrivate()->NoteDeadServiceWorkerInfo();
     mInstallingWorker = nullptr;
     // FIXME(nsm): Abort any inflight requests from installing worker.
   }
 
   if (mWaitingWorker) {
     mWaitingWorker->UpdateState(ServiceWorkerState::Redundant);
-
-    nsresult rv = serviceWorkerScriptCache::PurgeCache(mPrincipal,
-                                                       mWaitingWorker->CacheName());
-    if (NS_FAILED(rv)) {
-      NS_WARNING("Failed to purge the waiting cache.");
-    }
-
     mWaitingWorker->WorkerPrivate()->NoteDeadServiceWorkerInfo();
     mWaitingWorker = nullptr;
   }
 
   if (mActiveWorker) {
     mActiveWorker->UpdateState(ServiceWorkerState::Redundant);
-
-    nsresult rv = serviceWorkerScriptCache::PurgeCache(mPrincipal,
-                                                       mActiveWorker->CacheName());
-    if (NS_FAILED(rv)) {
-      NS_WARNING("Failed to purge the active cache.");
-    }
-
     mActiveWorker->WorkerPrivate()->NoteDeadServiceWorkerInfo();
     mActiveWorker = nullptr;
   }
 
-  RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-  MOZ_ASSERT(swm);
-  swm->InvalidateServiceWorkerRegistrationWorker(this,
-                                                 WhichServiceWorker::INSTALLING_WORKER |
-                                                 WhichServiceWorker::WAITING_WORKER |
-                                                 WhichServiceWorker::ACTIVE_WORKER);
+  NotifyListenersOnChange(WhichServiceWorker::INSTALLING_WORKER |
+                          WhichServiceWorker::WAITING_WORKER |
+                          WhichServiceWorker::ACTIVE_WORKER);
 }
 
 ServiceWorkerRegistrationInfo::ServiceWorkerRegistrationInfo(const nsACString& aScope,
                                                              nsIPrincipal* aPrincipal)
   : mControlledDocumentsCounter(0)
   , mUpdateState(NoUpdate)
   , mLastUpdateCheckTime(0)
   , mScope(aScope)
@@ -200,53 +183,27 @@ ServiceWorkerRegistrationInfo::TryToActi
   if (!IsControllingDocuments() ||
       // Waiting worker will be removed if the registration is removed
       (mWaitingWorker && mWaitingWorker->SkipWaitingFlag())) {
     Activate();
   }
 }
 
 void
-ServiceWorkerRegistrationInfo::PurgeActiveWorker()
-{
-  RefPtr<ServiceWorkerInfo> exitingWorker = mActiveWorker.forget();
-  if (!exitingWorker)
-    return;
-
-  // FIXME(jaoo): Bug 1170543 - Wait for exitingWorker to finish and terminate it.
-  exitingWorker->UpdateState(ServiceWorkerState::Redundant);
-  nsresult rv = serviceWorkerScriptCache::PurgeCache(mPrincipal,
-                                                     exitingWorker->CacheName());
-  if (NS_FAILED(rv)) {
-    NS_WARNING("Failed to purge the activating cache.");
-  }
-  RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-  swm->InvalidateServiceWorkerRegistrationWorker(this, WhichServiceWorker::ACTIVE_WORKER);
-}
-
-void
 ServiceWorkerRegistrationInfo::Activate()
 {
-  RefPtr<ServiceWorkerInfo> activatingWorker = mWaitingWorker;
-  if (!activatingWorker) {
+  if (!mWaitingWorker) {
     return;
   }
 
-  PurgeActiveWorker();
-
-  RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-  swm->InvalidateServiceWorkerRegistrationWorker(this, WhichServiceWorker::WAITING_WORKER);
-
-  mActiveWorker = activatingWorker.forget();
-  mWaitingWorker = nullptr;
-  mActiveWorker->UpdateState(ServiceWorkerState::Activating);
-  NotifyListenersOnChange();
+  TransitionWaitingToActive();
 
   // FIXME(nsm): Unlink appcache if there is one.
 
+  RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
   swm->CheckPendingReadyPromises();
 
   // "Queue a task to fire a simple event named controllerchange..."
   nsCOMPtr<nsIRunnable> controllerChangeRunnable =
     NS_NewRunnableMethodWithArg<RefPtr<ServiceWorkerRegistrationInfo>>(
       swm, &ServiceWorkerManager::FireControllerChange, this);
   NS_DispatchToMainThread(controllerChangeRunnable);
 
@@ -306,18 +263,26 @@ ServiceWorkerRegistrationInfo::IsLastUpd
   if ((mLastUpdateCheckTime != 0) &&
       (now - mLastUpdateCheckTime > kSecondsPerDay)) {
     return true;
   }
   return false;
 }
 
 void
-ServiceWorkerRegistrationInfo::NotifyListenersOnChange()
+ServiceWorkerRegistrationInfo::NotifyListenersOnChange(WhichServiceWorker aChangedWorkers)
 {
+  AssertIsOnMainThread();
+  MOZ_ASSERT(aChangedWorkers & (WhichServiceWorker::INSTALLING_WORKER |
+                                WhichServiceWorker::WAITING_WORKER |
+                                WhichServiceWorker::ACTIVE_WORKER));
+
+  RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+  swm->InvalidateServiceWorkerRegistrationWorker(this, aChangedWorkers);
+
   nsTArray<nsCOMPtr<nsIServiceWorkerRegistrationInfoListener>> listeners(mListeners);
   for (size_t index = 0; index < listeners.Length(); ++index) {
     listeners[index]->OnChange();
   }
 }
 
 void
 ServiceWorkerRegistrationInfo::MaybeScheduleTimeCheckAndUpdate()
@@ -362,9 +327,124 @@ ServiceWorkerRegistrationInfo::CheckAndC
                (mUpdateState == NeedTimeCheckAndUpdate &&
                 IsLastUpdateCheckTimeOverOneDay());
 
   mUpdateState = NoUpdate;
 
   return result;
 }
 
+ServiceWorkerInfo*
+ServiceWorkerRegistrationInfo::GetInstalling() const
+{
+  AssertIsOnMainThread();
+  return mInstallingWorker;
+}
+
+ServiceWorkerInfo*
+ServiceWorkerRegistrationInfo::GetWaiting() const
+{
+  AssertIsOnMainThread();
+  return mWaitingWorker;
+}
+
+ServiceWorkerInfo*
+ServiceWorkerRegistrationInfo::GetActive() const
+{
+  AssertIsOnMainThread();
+  return mActiveWorker;
+}
+
+void
+ServiceWorkerRegistrationInfo::ClearInstalling()
+{
+  AssertIsOnMainThread();
+
+  if (!mInstallingWorker) {
+    return;
+  }
+
+  mInstallingWorker->UpdateState(ServiceWorkerState::Redundant);
+  mInstallingWorker = nullptr;
+  NotifyListenersOnChange(WhichServiceWorker::INSTALLING_WORKER);
+}
+
+void
+ServiceWorkerRegistrationInfo::SetInstalling(ServiceWorkerInfo* aServiceWorker)
+{
+  AssertIsOnMainThread();
+  MOZ_ASSERT(aServiceWorker);
+  MOZ_ASSERT(!mInstallingWorker);
+  MOZ_ASSERT(mWaitingWorker != aServiceWorker);
+  MOZ_ASSERT(mActiveWorker != aServiceWorker);
+
+  mInstallingWorker = aServiceWorker;
+  mInstallingWorker->UpdateState(ServiceWorkerState::Installing);
+  NotifyListenersOnChange(WhichServiceWorker::INSTALLING_WORKER);
+}
+
+void
+ServiceWorkerRegistrationInfo::TransitionInstallingToWaiting()
+{
+  AssertIsOnMainThread();
+  MOZ_ASSERT(mInstallingWorker);
+
+  if (mWaitingWorker) {
+    MOZ_ASSERT(mInstallingWorker->CacheName() != mWaitingWorker->CacheName());
+    mWaitingWorker->UpdateState(ServiceWorkerState::Redundant);
+  }
+
+  mWaitingWorker = mInstallingWorker.forget();
+  mWaitingWorker->UpdateState(ServiceWorkerState::Installed);
+  NotifyListenersOnChange(WhichServiceWorker::INSTALLING_WORKER |
+                          WhichServiceWorker::WAITING_WORKER);
+
+  RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+  swm->StoreRegistration(mPrincipal, this);
+}
+
+void
+ServiceWorkerRegistrationInfo::SetActive(ServiceWorkerInfo* aServiceWorker)
+{
+  AssertIsOnMainThread();
+  MOZ_ASSERT(aServiceWorker);
+
+  // TODO: Assert installing, waiting, and active are nullptr once the SWM
+  //       moves to the parent process.  After that happens this code will
+  //       only run for browser initialization and not for cross-process
+  //       overrides.
+  MOZ_ASSERT(mInstallingWorker != aServiceWorker);
+  MOZ_ASSERT(mWaitingWorker != aServiceWorker);
+  MOZ_ASSERT(mActiveWorker != aServiceWorker);
+
+  if (mActiveWorker) {
+    MOZ_ASSERT(aServiceWorker->CacheName() != mActiveWorker->CacheName());
+    mActiveWorker->UpdateState(ServiceWorkerState::Redundant);
+  }
+
+  // The active worker is being overriden due to initial load or
+  // another process activating a worker.  Move straight to the
+  // Activated state.
+  mActiveWorker = aServiceWorker;
+  mActiveWorker->SetActivateStateUncheckedWithoutEvent(ServiceWorkerState::Activated);
+  NotifyListenersOnChange(WhichServiceWorker::ACTIVE_WORKER);
+}
+
+void
+ServiceWorkerRegistrationInfo::TransitionWaitingToActive()
+{
+  AssertIsOnMainThread();
+  MOZ_ASSERT(mWaitingWorker);
+
+  if (mActiveWorker) {
+    MOZ_ASSERT(mWaitingWorker->CacheName() != mActiveWorker->CacheName());
+    mActiveWorker->UpdateState(ServiceWorkerState::Redundant);
+  }
+
+  // We are transitioning from waiting to active normally, so go to
+  // the activating state.
+  mActiveWorker = mWaitingWorker.forget();
+  mActiveWorker->UpdateState(ServiceWorkerState::Activating);
+  NotifyListenersOnChange(WhichServiceWorker::WAITING_WORKER |
+                          WhichServiceWorker::ACTIVE_WORKER);
+}
+
 END_WORKERS_NAMESPACE
--- a/dom/workers/ServiceWorkerRegistrationInfo.h
+++ b/dom/workers/ServiceWorkerRegistrationInfo.h
@@ -22,30 +22,30 @@ class ServiceWorkerRegistrationInfo fina
   {
     NoUpdate,
     NeedTimeCheckAndUpdate,
     NeedUpdate
   } mUpdateState;
 
   uint64_t mLastUpdateCheckTime;
 
+  RefPtr<ServiceWorkerInfo> mActiveWorker;
+  RefPtr<ServiceWorkerInfo> mWaitingWorker;
+  RefPtr<ServiceWorkerInfo> mInstallingWorker;
+
   virtual ~ServiceWorkerRegistrationInfo();
 
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSISERVICEWORKERREGISTRATIONINFO
 
-  nsCString mScope;
+  const nsCString mScope;
 
   nsCOMPtr<nsIPrincipal> mPrincipal;
 
-  RefPtr<ServiceWorkerInfo> mActiveWorker;
-  RefPtr<ServiceWorkerInfo> mWaitingWorker;
-  RefPtr<ServiceWorkerInfo> mInstallingWorker;
-
   nsTArray<nsCOMPtr<nsIServiceWorkerRegistrationInfoListener>> mListeners;
 
   // When unregister() is called on a registration, it is not immediately
   // removed since documents may be controlled. It is marked as
   // pendingUninstall and when all controlling documents go away, removed.
   bool mPendingUninstall;
 
   ServiceWorkerRegistrationInfo(const nsACString& aScope,
@@ -87,19 +87,16 @@ public:
   {
     return mActiveWorker && mControlledDocumentsCounter;
   }
 
   void
   Clear();
 
   void
-  PurgeActiveWorker();
-
-  void
   TryToActivateAsync();
 
   void
   TryToActivate();
 
   void
   Activate();
 
@@ -108,25 +105,63 @@ public:
 
   void
   RefreshLastUpdateCheckTime();
 
   bool
   IsLastUpdateCheckTimeOverOneDay() const;
 
   void
-  NotifyListenersOnChange();
+  NotifyListenersOnChange(WhichServiceWorker aChangedWorkers);
 
   void
   MaybeScheduleTimeCheckAndUpdate();
 
   void
   MaybeScheduleUpdate();
 
   bool
   CheckAndClearIfUpdateNeeded();
+
+  ServiceWorkerInfo*
+  GetInstalling() const;
+
+  ServiceWorkerInfo*
+  GetWaiting() const;
+
+  ServiceWorkerInfo*
+  GetActive() const;
+
+  // Remove an existing installing worker, if present.  The worker will
+  // be transitioned to the Redundant state.
+  void
+  ClearInstalling();
+
+  // Set a new installing worker.  This may only be called if there is no
+  // existing installing worker.  The worker is transitioned to the Installing
+  // state.
+  void
+  SetInstalling(ServiceWorkerInfo* aServiceWorker);
+
+  // Transition the current installing worker to be the waiting worker.  The
+  // workers state is updated to Installed.
+  void
+  TransitionInstallingToWaiting();
+
+  // Override the current active worker.  This is used during browser
+  // initialization to load persisted workers.  Its also used to propagate
+  // active workers across child processes in e10s.  This second use will
+  // go away once the ServiceWorkerManager moves to the parent process.
+  // The worker is transitioned to the Activated state.
+  void
+  SetActive(ServiceWorkerInfo* aServiceWorker);
+
+  // Transition the current waiting worker to be the new active worker.  The
+  // worker is updated to the Activating state.
+  void
+  TransitionWaitingToActive();
 };
 
 } // namespace workers
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_workers_serviceworkerregistrationinfo_h
--- a/dom/workers/ServiceWorkerUpdateJob.cpp
+++ b/dom/workers/ServiceWorkerUpdateJob.cpp
@@ -145,29 +145,19 @@ ServiceWorkerUpdateJob::FailUpdateJob(Er
   // cleanup on every non-successful exit.
   if (mRegistration) {
     if (mServiceWorker) {
       mServiceWorker->UpdateState(ServiceWorkerState::Redundant);
       serviceWorkerScriptCache::PurgeCache(mRegistration->mPrincipal,
                                            mServiceWorker->CacheName());
     }
 
-    RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+    mRegistration->ClearInstalling();
 
-    if (mRegistration->mInstallingWorker) {
-      mRegistration->mInstallingWorker->UpdateState(ServiceWorkerState::Redundant);
-      serviceWorkerScriptCache::PurgeCache(mRegistration->mPrincipal,
-                                           mRegistration->mInstallingWorker->CacheName());
-      mRegistration->mInstallingWorker = nullptr;
-      if (swm) {
-        swm->InvalidateServiceWorkerRegistrationWorker(mRegistration,
-                                                       WhichServiceWorker::INSTALLING_WORKER);
-      }
-    }
-
+    RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
     if (swm) {
       swm->MaybeRemoveRegistration(mRegistration);
     }
   }
 
   mServiceWorker = nullptr;
   mRegistration = nullptr;
 
@@ -237,17 +227,17 @@ ServiceWorkerUpdateJob::SetRegistration(
 void
 ServiceWorkerUpdateJob::Update()
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(!Canceled());
 
   // SetRegistration() must be called before Update().
   MOZ_ASSERT(mRegistration);
-  MOZ_ASSERT(!mRegistration->mInstallingWorker);
+  MOZ_ASSERT(!mRegistration->GetInstalling());
 
   // Begin the script download and comparison steps starting at step 5
   // of the Update algorithm.
 
   RefPtr<ServiceWorkerInfo> workerInfo = mRegistration->Newest();
   nsAutoString cacheName;
 
   // If the script has not changed, we need to perform a byte-for-byte
@@ -408,37 +398,34 @@ ServiceWorkerUpdateJob::ContinueUpdateAf
 }
 
 void
 ServiceWorkerUpdateJob::Install()
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(!Canceled());
 
-  MOZ_ASSERT(!mRegistration->mInstallingWorker);
+  MOZ_ASSERT(!mRegistration->GetInstalling());
 
   // Begin step 2 of the Install algorithm.
   //
   //  https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#installation-algorithm
 
   MOZ_ASSERT(mServiceWorker);
-  mRegistration->mInstallingWorker = mServiceWorker.forget();
-  mRegistration->mInstallingWorker->UpdateState(ServiceWorkerState::Installing);
-  mRegistration->NotifyListenersOnChange();
-
-  RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-  swm->InvalidateServiceWorkerRegistrationWorker(mRegistration,
-                                                 WhichServiceWorker::INSTALLING_WORKER);
+  mRegistration->SetInstalling(mServiceWorker);
+  mServiceWorker = nullptr;
 
   // Step 6 of the Install algorithm resolving the job promise.
   InvokeResultCallbacks(NS_OK);
 
   // The job promise cannot be rejected after this point, but the job can
   // still fail; e.g. if the install event handler throws, etc.
 
+  RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+
   // fire the updatefound event
   nsCOMPtr<nsIRunnable> upr =
     NS_NewRunnableMethodWithArg<RefPtr<ServiceWorkerRegistrationInfo>>(
       swm,
       &ServiceWorkerManager::FireUpdateFoundOnServiceWorkerRegistrations,
       mRegistration);
   NS_DispatchToMainThread(upr);
 
@@ -448,59 +435,43 @@ ServiceWorkerUpdateJob::Install()
     (this, &ServiceWorkerUpdateJob::ContinueAfterInstallEvent, false);
 
   nsMainThreadPtrHandle<ServiceWorkerUpdateJob> handle(
     new nsMainThreadPtrHolder<ServiceWorkerUpdateJob>(this));
   RefPtr<LifeCycleEventCallback> callback = new ContinueInstallRunnable(handle);
 
   // Send the install event to the worker thread
   ServiceWorkerPrivate* workerPrivate =
-    mRegistration->mInstallingWorker->WorkerPrivate();
+    mRegistration->GetInstalling()->WorkerPrivate();
   nsresult rv = workerPrivate->SendLifeCycleEvent(NS_LITERAL_STRING("install"),
                                                   callback, failRunnable);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     ContinueAfterInstallEvent(false /* aSuccess */);
   }
 }
 
 void
 ServiceWorkerUpdateJob::ContinueAfterInstallEvent(bool aInstallEventSuccess)
 {
   if (Canceled()) {
     return FailUpdateJob(NS_ERROR_DOM_ABORT_ERR);
   }
 
-  MOZ_ASSERT(mRegistration->mInstallingWorker);
-
-  RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+  MOZ_ASSERT(mRegistration->GetInstalling());
 
   // Continue executing the Install algorithm at step 12.
 
   // "If installFailed is true"
   if (NS_WARN_IF(!aInstallEventSuccess)) {
     // The installing worker is cleaned up by FailUpdateJob().
     FailUpdateJob(NS_ERROR_DOM_ABORT_ERR);
     return;
   }
 
-  // "If registration's waiting worker is not null"
-  if (mRegistration->mWaitingWorker) {
-    mRegistration->mWaitingWorker->WorkerPrivate()->TerminateWorker();
-    mRegistration->mWaitingWorker->UpdateState(ServiceWorkerState::Redundant);
-    serviceWorkerScriptCache::PurgeCache(mRegistration->mPrincipal,
-                                         mRegistration->mWaitingWorker->CacheName());
-  }
-
-  mRegistration->mWaitingWorker = mRegistration->mInstallingWorker.forget();
-  mRegistration->mWaitingWorker->UpdateState(ServiceWorkerState::Installed);
-  mRegistration->NotifyListenersOnChange();
-  swm->StoreRegistration(mPrincipal, mRegistration);
-  swm->InvalidateServiceWorkerRegistrationWorker(mRegistration,
-                                                 WhichServiceWorker::INSTALLING_WORKER |
-                                                 WhichServiceWorker::WAITING_WORKER);
+  mRegistration->TransitionInstallingToWaiting();
 
   Finish(NS_OK);
 
   // Step 20 calls for explicitly waiting for queued event tasks to fire.  Instead,
   // we simply queue a runnable to execute Activate.  This ensures the events are
   // flushed from the queue before proceeding.
 
   // Step 22 of the Install algorithm.  Activate is executed after the completion
--- a/gfx/2d/DrawTargetCairo.cpp
+++ b/gfx/2d/DrawTargetCairo.cpp
@@ -824,17 +824,17 @@ PaintWithAlpha(cairo_t* aContext, const 
 
 void
 DrawTargetCairo::DrawSurface(SourceSurface *aSurface,
                              const Rect &aDest,
                              const Rect &aSource,
                              const DrawSurfaceOptions &aSurfOptions,
                              const DrawOptions &aOptions)
 {
-  if (mTransformSingular) {
+  if (mTransformSingular || aDest.IsEmpty()) {
     return;
   }
 
   if (!IsValid() || !aSurface) {
     gfxCriticalNote << "DrawSurface with bad surface " << cairo_surface_status(cairo_get_group_target(mContext));
     return;
   }
 
--- a/gfx/2d/Rect.h
+++ b/gfx/2d/Rect.h
@@ -118,16 +118,20 @@ struct IntRectTyped :
     // This is here only to keep IPDL-generated code happy. DO NOT USE.
     bool operator==(const IntRectTyped<units>& aRect) const
     {
       return IntRectTyped<units>::IsEqualEdges(aRect);
     }
 
     void InflateToMultiple(const IntSizeTyped<units>& aTileSize)
     {
+      if (this->IsEmpty()) {
+        return;
+      }
+
       int32_t yMost = this->YMost();
       int32_t xMost = this->XMost();
 
       this->x = mozilla::RoundDownToMultiple(this->x, aTileSize.width);
       this->y = mozilla::RoundDownToMultiple(this->y, aTileSize.height);
       xMost = mozilla::RoundUpToMultiple(xMost, aTileSize.width);
       yMost = mozilla::RoundUpToMultiple(yMost, aTileSize.height);
 
--- a/gfx/layers/GrallocImages.cpp
+++ b/gfx/layers/GrallocImages.cpp
@@ -139,17 +139,17 @@ GrallocImage::SetData(const Data& aData)
   // though some gralloc hals implementation maps it when it is allocated.
   mData.mYChannel     = nullptr;
   mData.mCrChannel    = nullptr;
   mData.mCbChannel    = nullptr;
   return true;
 }
 
 void
-GrallocImage::SetData(TextureClient* aGraphicBuffer, const gfx::IntSize& aSize)
+GrallocImage::AdoptData(TextureClient* aGraphicBuffer, const gfx::IntSize& aSize)
 {
   mTextureClient = aGraphicBuffer;
   mSize = aSize;
 }
 
 /**
  * Converts YVU420 semi planar frames to RGB565, possibly taking different
  * stride values.
--- a/gfx/layers/GrallocImages.h
+++ b/gfx/layers/GrallocImages.h
@@ -58,21 +58,22 @@ public:
   virtual ~GrallocImage();
 
   /**
    * This makes a copy of the data buffers, in order to support functioning
    * in all different layer managers.
    */
   virtual bool SetData(const Data& aData);
 
+  using RecyclingPlanarYCbCrImage::AdoptData;
   /**
    *  Share the SurfaceDescriptor without making the copy, in order
    *  to support functioning in all different layer managers.
    */
-  void SetData(TextureClient* aGraphicBuffer, const gfx::IntSize& aSize);
+  void AdoptData(TextureClient* aGraphicBuffer, const gfx::IntSize& aSize);
 
   // From [android 4.0.4]/hardware/msm7k/libgralloc-qsd8k/gralloc_priv.h
   enum {
     /* OEM specific HAL formats */
     HAL_PIXEL_FORMAT_YCbCr_422_P            = 0x102,
     HAL_PIXEL_FORMAT_YCbCr_420_P            = 0x103,
     HAL_PIXEL_FORMAT_YCbCr_420_SP           = 0x109,
     HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO    = 0x10A,
--- a/gfx/layers/ImageContainer.cpp
+++ b/gfx/layers/ImageContainer.cpp
@@ -529,32 +529,26 @@ RecyclingPlanarYCbCrImage::CopyData(cons
             mData.mCbCrSize, mData.mCbCrStride, mData.mCbSkip);
   CopyPlane(mData.mCrChannel, aData.mCrChannel,
             mData.mCbCrSize, mData.mCbCrStride, mData.mCrSkip);
 
   mSize = aData.mPicSize;
   return true;
 }
 
-bool
-RecyclingPlanarYCbCrImage::SetData(const Data &aData)
-{
-  return CopyData(aData);
-}
-
 gfxImageFormat
 PlanarYCbCrImage::GetOffscreenFormat()
 {
   return mOffscreenFormat == SurfaceFormat::UNKNOWN ?
     gfxPlatform::GetPlatform()->GetOffscreenFormat() :
     mOffscreenFormat;
 }
 
 bool
-PlanarYCbCrImage::SetDataNoCopy(const Data &aData)
+PlanarYCbCrImage::AdoptData(const Data &aData)
 {
   mData = aData;
   mSize = aData.mPicSize;
   return true;
 }
 
 uint8_t*
 RecyclingPlanarYCbCrImage::AllocateAndGetNewBuffer(uint32_t aSize)
--- a/gfx/layers/ImageContainer.h
+++ b/gfx/layers/ImageContainer.h
@@ -722,26 +722,26 @@ public:
   };
 
   virtual ~PlanarYCbCrImage() {}
 
   /**
    * This makes a copy of the data buffers, in order to support functioning
    * in all different layer managers.
    */
-  virtual bool SetData(const Data& aData) = 0;
+  virtual bool CopyData(const Data& aData) = 0;
 
   /**
    * This doesn't make a copy of the data buffers. Can be used when mBuffer is
-   * pre allocated with AllocateAndGetNewBuffer(size) and then SetDataNoCopy is
+   * pre allocated with AllocateAndGetNewBuffer(size) and then AdoptData is
    * called to only update the picture size, planes etc. fields in mData.
    * The GStreamer media backend uses this to decode into PlanarYCbCrImage(s)
    * directly.
    */
-  virtual bool SetDataNoCopy(const Data &aData);
+  virtual bool AdoptData(const Data &aData);
 
   /**
    * This allocates and returns a new buffer
    */
   virtual uint8_t* AllocateAndGetNewBuffer(uint32_t aSize) = 0;
 
   /**
    * Ask this Image to not convert YUV to RGB during SetData, and make
@@ -788,26 +788,20 @@ protected:
   nsCountedRef<nsMainThreadSourceSurfaceRef> mSourceSurface;
   uint32_t mBufferSize;
 };
 
 class RecyclingPlanarYCbCrImage: public PlanarYCbCrImage {
 public:
   explicit RecyclingPlanarYCbCrImage(BufferRecycleBin *aRecycleBin) : mRecycleBin(aRecycleBin) {}
   virtual ~RecyclingPlanarYCbCrImage() override;
-  virtual bool SetData(const Data& aData) override;
+  virtual bool CopyData(const Data& aData) override;
   virtual uint8_t* AllocateAndGetNewBuffer(uint32_t aSize) override;
   virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override;
 protected:
-  /**
-   * Make a copy of the YCbCr data into local storage.
-   *
-   * @param aData           Input image data.
-   */
-  bool CopyData(const Data& aData);
 
   /**
    * Return a buffer to store image data in.
    */
   mozilla::UniquePtr<uint8_t[]> AllocateBuffer(uint32_t aSize);
 
   RefPtr<BufferRecycleBin> mRecycleBin;
   mozilla::UniquePtr<uint8_t[]> mBuffer;
--- a/gfx/layers/LayerTreeInvalidation.cpp
+++ b/gfx/layers/LayerTreeInvalidation.cpp
@@ -127,17 +127,16 @@ NotifySubdocumentInvalidationRecursive(L
 }
 
 struct LayerPropertiesBase : public LayerProperties
 {
   explicit LayerPropertiesBase(Layer* aLayer)
     : mLayer(aLayer)
     , mMaskLayer(nullptr)
     , mVisibleRegion(mLayer->GetLocalVisibleRegion().ToUnknownRegion())
-    , mInvalidRegion(aLayer->GetInvalidRegion())
     , mPostXScale(aLayer->GetPostXScale())
     , mPostYScale(aLayer->GetPostYScale())
     , mOpacity(aLayer->GetLocalOpacity())
     , mUseClipRect(!!aLayer->GetEffectiveClipRect())
   {
     MOZ_COUNT_CTOR(LayerPropertiesBase);
     if (aLayer->GetMaskLayer()) {
       mMaskLayer = CloneLayerTreePropertiesInternal(aLayer->GetMaskLayer(), true);
@@ -197,17 +196,17 @@ struct LayerPropertiesBase : public Laye
       aGeometryChanged = true;
       result = OldTransformedBounds();
       AddRegion(result, NewTransformedBounds());
 
       // We can't bail out early because we need to update mChildrenChanged.
     }
 
     AddRegion(result, ComputeChangeInternal(aCallback, aGeometryChanged));
-    AddTransformedRegion(result, mLayer->GetInvalidRegion(), mTransform);
+    AddTransformedRegion(result, mLayer->GetInvalidRegion().GetRegion(), mTransform);
 
     if (mMaskLayer && otherMask) {
       AddTransformedRegion(result, mMaskLayer->ComputeChange(aCallback, aGeometryChanged),
                            mTransform);
     }
 
     for (size_t i = 0;
          i < std::min(mAncestorMaskLayers.Length(), mLayer->GetAncestorMaskLayerCount());
@@ -247,17 +246,16 @@ struct LayerPropertiesBase : public Laye
   {
     return IntRect();
   }
 
   RefPtr<Layer> mLayer;
   UniquePtr<LayerPropertiesBase> mMaskLayer;
   nsTArray<UniquePtr<LayerPropertiesBase>> mAncestorMaskLayers;
   nsIntRegion mVisibleRegion;
-  nsIntRegion mInvalidRegion;
   Matrix4x4 mTransform;
   float mPostXScale;
   float mPostYScale;
   float mOpacity;
   ParentLayerIntRect mClipRect;
   bool mUseClipRect;
 };
 
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -23,16 +23,17 @@
 #include "mozilla/Maybe.h"              // for Maybe
 #include "mozilla/RefPtr.h"             // for already_AddRefed
 #include "mozilla/StyleAnimationValue.h" // for StyleAnimationValue, etc
 #include "mozilla/TimeStamp.h"          // for TimeStamp, TimeDuration
 #include "mozilla/UniquePtr.h"          // for UniquePtr
 #include "mozilla/gfx/BaseMargin.h"     // for BaseMargin
 #include "mozilla/gfx/BasePoint.h"      // for BasePoint
 #include "mozilla/gfx/Point.h"          // for IntSize
+#include "mozilla/gfx/TiledRegion.h"    // for TiledIntRegion
 #include "mozilla/gfx/Types.h"          // for SurfaceFormat
 #include "mozilla/gfx/UserData.h"       // for UserData, etc
 #include "mozilla/layers/LayersTypes.h"
 #include "mozilla/mozalloc.h"           // for operator delete, etc
 #include "nsAutoPtr.h"                  // for nsAutoPtr, nsRefPtr, etc
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsCSSProperty.h"              // for nsCSSProperty
 #include "nsDebug.h"                    // for NS_ASSERTION
@@ -1657,30 +1658,34 @@ public:
   void GetDisplayListLog(nsCString& log);
 
   static bool IsLogEnabled() { return LayerManager::IsLogEnabled(); }
 
   /**
    * Returns the current area of the layer (in layer-space coordinates)
    * marked as needed to be recomposited.
    */
-  const nsIntRegion& GetInvalidRegion() { return mInvalidRegion; }
+  const gfx::TiledIntRegion& GetInvalidRegion() { return mInvalidRegion; }
   void AddInvalidRegion(const nsIntRegion& aRegion) {
-    mInvalidRegion.Or(mInvalidRegion, aRegion);
+    mInvalidRegion.Add(aRegion);
   }
 
   /**
    * Mark the entirety of the layer's visible region as being invalid.
    */
-  void SetInvalidRectToVisibleRegion() { mInvalidRegion = GetVisibleRegion().ToUnknownRegion(); }
+  void SetInvalidRectToVisibleRegion()
+  {
+    mInvalidRegion.SetEmpty();
+    mInvalidRegion.Add(GetVisibleRegion().ToUnknownRegion());
+  }
 
   /**
    * Adds to the current invalid rect.
    */
-  void AddInvalidRect(const gfx::IntRect& aRect) { mInvalidRegion.Or(mInvalidRegion, aRect); }
+  void AddInvalidRect(const gfx::IntRect& aRect) { mInvalidRegion.Add(aRect); }
 
   /**
    * Clear the invalid rect, marking the layer as being identical to what is currently
    * composited.
    */
   void ClearInvalidRect() { mInvalidRegion.SetEmpty(); }
 
   // These functions allow attaching an AsyncPanZoomController to this layer,
@@ -1828,17 +1833,17 @@ protected:
   // See mPendingTransform above.
   nsAutoPtr<AnimationArray> mPendingAnimations;
   InfallibleTArray<AnimData> mAnimationData;
   float mOpacity;
   gfx::CompositionOp mMixBlendMode;
   bool mForceIsolatedGroup;
   Maybe<ParentLayerIntRect> mClipRect;
   gfx::IntRect mTileSourceRect;
-  nsIntRegion mInvalidRegion;
+  gfx::TiledIntRegion mInvalidRegion;
   nsTArray<RefPtr<AsyncPanZoomController> > mApzcs;
   uint32_t mContentFlags;
   bool mUseTileSourceRect;
   bool mIsFixedPosition;
   bool mTransformIsPerspective;
   struct FixedPositionData {
     FrameMetrics::ViewID mScrollId;
     LayerPoint mAnchor;
--- a/gfx/layers/apz/src/InputBlockState.cpp
+++ b/gfx/layers/apz/src/InputBlockState.cpp
@@ -20,32 +20,44 @@
 namespace mozilla {
 namespace layers {
 
 static uint64_t sBlockCounter = InputBlockState::NO_BLOCK_ID + 1;
 
 InputBlockState::InputBlockState(const RefPtr<AsyncPanZoomController>& aTargetApzc,
                                  bool aTargetConfirmed)
   : mTargetApzc(aTargetApzc)
-  , mTargetConfirmed(aTargetConfirmed)
+  , mTargetConfirmed(aTargetConfirmed ? TargetConfirmationState::eConfirmed
+                                      : TargetConfirmationState::eUnconfirmed)
   , mBlockId(sBlockCounter++)
   , mTransformToApzc(aTargetApzc->GetTransformToThis())
 {
   // We should never be constructed with a nullptr target.
   MOZ_ASSERT(mTargetApzc);
   mOverscrollHandoffChain = mTargetApzc->BuildOverscrollHandoffChain();
 }
 
 bool
-InputBlockState::SetConfirmedTargetApzc(const RefPtr<AsyncPanZoomController>& aTargetApzc)
+InputBlockState::SetConfirmedTargetApzc(const RefPtr<AsyncPanZoomController>& aTargetApzc,
+                                        TargetConfirmationState aState)
 {
-  if (mTargetConfirmed) {
+  MOZ_ASSERT(aState == TargetConfirmationState::eConfirmed
+          || aState == TargetConfirmationState::eTimedOut);
+
+  if (mTargetConfirmed == TargetConfirmationState::eTimedOut &&
+      aState == TargetConfirmationState::eConfirmed) {
+    // The main thread finally responded. We had already timed out the
+    // confirmation, but we want to update the state internally so that we
+    // can record the time for telemetry purposes.
+    mTargetConfirmed = TargetConfirmationState::eTimedOutAndMainThreadResponded;
+  }
+  if (mTargetConfirmed != TargetConfirmationState::eUnconfirmed) {
     return false;
   }
-  mTargetConfirmed = true;
+  mTargetConfirmed = aState;
 
   TBS_LOG("%p got confirmed target APZC %p\n", this, mTargetApzc.get());
   if (mTargetApzc == aTargetApzc) {
     // The confirmed target is the same as the tentative one, so we're done.
     return true;
   }
 
   TBS_LOG("%p replacing unconfirmed target %p with real target %p\n",
@@ -80,17 +92,24 @@ uint64_t
 InputBlockState::GetBlockId() const
 {
   return mBlockId;
 }
 
 bool
 InputBlockState::IsTargetConfirmed() const
 {
-  return mTargetConfirmed;
+  return mTargetConfirmed != TargetConfirmationState::eUnconfirmed;
+}
+
+bool
+InputBlockState::HasReceivedRealConfirmedTarget() const
+{
+  return mTargetConfirmed == TargetConfirmationState::eConfirmed ||
+         mTargetConfirmed == TargetConfirmationState::eTimedOutAndMainThreadResponded;
 }
 
 bool
 InputBlockState::IsDownchainOf(AsyncPanZoomController* aA, AsyncPanZoomController* aB) const
 {
   if (aA == aB) {
     return true;
   }
@@ -187,17 +206,17 @@ CancelableBlockState::IsDefaultPrevented
 {
   MOZ_ASSERT(mContentResponded || mContentResponseTimerExpired);
   return mPreventDefault;
 }
 
 bool
 CancelableBlockState::HasReceivedAllContentNotifications() const
 {
-  return IsTargetConfirmed() && mContentResponded;
+  return HasReceivedRealConfirmedTarget() && mContentResponded;
 }
 
 bool
 CancelableBlockState::IsReadyForHandling() const
 {
   if (!IsTargetConfirmed()) {
     return false;
   }
@@ -354,28 +373,29 @@ WheelBlockState::SetContentResponse(bool
 {
   if (aPreventDefault) {
     EndTransaction();
   }
   return CancelableBlockState::SetContentResponse(aPreventDefault);
 }
 
 bool
-WheelBlockState::SetConfirmedTargetApzc(const RefPtr<AsyncPanZoomController>& aTargetApzc)
+WheelBlockState::SetConfirmedTargetApzc(const RefPtr<AsyncPanZoomController>& aTargetApzc,
+                                        TargetConfirmationState aState)
 {
   // The APZC that we find via APZCCallbackHelpers may not be the same APZC
   // ESM or OverscrollHandoff would have computed. Make sure we get the right
   // one by looking for the first apzc the next pending event can scroll.
   RefPtr<AsyncPanZoomController> apzc = aTargetApzc;
   if (apzc && mEvents.Length() > 0) {
     const ScrollWheelInput& event = mEvents.ElementAt(0);
     apzc = apzc->BuildOverscrollHandoffChain()->FindFirstScrollable(event);
   }
 
-  InputBlockState::SetConfirmedTargetApzc(apzc);
+  InputBlockState::SetConfirmedTargetApzc(apzc, aState);
   return true;
 }
 
 void
 WheelBlockState::Update(ScrollWheelInput& aEvent)
 {
   // We might not be in a transaction if the block never started in a
   // transaction - for example, if nothing was scrollable.
@@ -598,32 +618,33 @@ PanGestureBlockState::PanGestureBlockSta
 
     if (apzc && apzc != GetTargetApzc()) {
       UpdateTargetApzc(apzc);
     }
   }
 }
 
 bool
-PanGestureBlockState::SetConfirmedTargetApzc(const RefPtr<AsyncPanZoomController>& aTargetApzc)
+PanGestureBlockState::SetConfirmedTargetApzc(const RefPtr<AsyncPanZoomController>& aTargetApzc,
+                                             TargetConfirmationState aState)
 {
   // The APZC that we find via APZCCallbackHelpers may not be the same APZC
   // ESM or OverscrollHandoff would have computed. Make sure we get the right
   // one by looking for the first apzc the next pending event can scroll.
   RefPtr<AsyncPanZoomController> apzc = aTargetApzc;
   if (apzc && mEvents.Length() > 0) {
     const PanGestureInput& event = mEvents.ElementAt(0);
     RefPtr<AsyncPanZoomController> scrollableApzc =
       apzc->BuildOverscrollHandoffChain()->FindFirstScrollable(event);
     if (scrollableApzc) {
       apzc = scrollableApzc;
     }
   }
 
-  InputBlockState::SetConfirmedTargetApzc(apzc);
+  InputBlockState::SetConfirmedTargetApzc(apzc, aState);
   return true;
 }
 
 void
 PanGestureBlockState::AddEvent(const PanGestureInput& aEvent)
 {
   mEvents.AppendElement(aEvent);
 }
--- a/gfx/layers/apz/src/InputBlockState.h
+++ b/gfx/layers/apz/src/InputBlockState.h
@@ -34,43 +34,52 @@ class PanGestureBlockState;
  * from inside AsyncPanZoomController should ensure that the APZC lock is not
  * held.
  */
 class InputBlockState
 {
 public:
   static const uint64_t NO_BLOCK_ID = 0;
 
+  enum class TargetConfirmationState {
+    eUnconfirmed,
+    eTimedOut,
+    eTimedOutAndMainThreadResponded,
+    eConfirmed
+  };
+
   explicit InputBlockState(const RefPtr<AsyncPanZoomController>& aTargetApzc,
                            bool aTargetConfirmed);
   virtual ~InputBlockState()
   {}
 
-  virtual bool SetConfirmedTargetApzc(const RefPtr<AsyncPanZoomController>& aTargetApzc);
+  virtual bool SetConfirmedTargetApzc(const RefPtr<AsyncPanZoomController>& aTargetApzc,
+                                      TargetConfirmationState aState);
   const RefPtr<AsyncPanZoomController>& GetTargetApzc() const;
   const RefPtr<const OverscrollHandoffChain>& GetOverscrollHandoffChain() const;
   uint64_t GetBlockId() const;
 
   bool IsTargetConfirmed() const;
+  bool HasReceivedRealConfirmedTarget() const;
 
   void SetScrolledApzc(AsyncPanZoomController* aApzc);
   AsyncPanZoomController* GetScrolledApzc() const;
   bool IsDownchainOfScrolledApzc(AsyncPanZoomController* aApzc) const;
 
 protected:
   virtual void UpdateTargetApzc(const RefPtr<AsyncPanZoomController>& aTargetApzc);
 
 private:
   // Checks whether |aA| is an ancestor of |aB| (or the same as |aB|) in
   // |mOverscrollHandoffChain|.
   bool IsDownchainOf(AsyncPanZoomController* aA, AsyncPanZoomController* aB) const;
 
 private:
   RefPtr<AsyncPanZoomController> mTargetApzc;
-  bool mTargetConfirmed;
+  TargetConfirmationState mTargetConfirmed;
   const uint64_t mBlockId;
 
   // The APZC that was actually scrolled by events in this input block.
   // This is used in configurations where a single input block is only
   // allowed to scroll a single APZC (configurations where gfxPrefs::
   // APZAllowImmediateHandoff() is false).
   // Set the first time an input event in this block scrolls an APZC.
   RefPtr<AsyncPanZoomController> mScrolledApzc;
@@ -222,17 +231,18 @@ public:
                   const ScrollWheelInput& aEvent);
 
   bool SetContentResponse(bool aPreventDefault) override;
   bool HasEvents() const override;
   void DropEvents() override;
   void HandleEvents() override;
   bool MustStayActive() override;
   const char* Type() override;
-  bool SetConfirmedTargetApzc(const RefPtr<AsyncPanZoomController>& aTargetApzc) override;
+  bool SetConfirmedTargetApzc(const RefPtr<AsyncPanZoomController>& aTargetApzc,
+                              TargetConfirmationState aState) override;
 
   void AddEvent(const ScrollWheelInput& aEvent);
 
   WheelBlockState *AsWheelBlock() override {
     return this;
   }
 
   /**
@@ -343,17 +353,18 @@ public:
   bool SetContentResponse(bool aPreventDefault) override;
   bool HasReceivedAllContentNotifications() const override;
   bool IsReadyForHandling() const override;
   bool HasEvents() const override;
   void DropEvents() override;
   void HandleEvents() override;
   bool MustStayActive() override;
   const char* Type() override;
-  bool SetConfirmedTargetApzc(const RefPtr<AsyncPanZoomController>& aTargetApzc) override;
+  bool SetConfirmedTargetApzc(const RefPtr<AsyncPanZoomController>& aTargetApzc,
+                              TargetConfirmationState aState) override;
 
   void AddEvent(const PanGestureInput& aEvent);
 
   PanGestureBlockState *AsPanGestureBlock() override {
     return this;
   }
 
   /**
--- a/gfx/layers/apz/src/InputQueue.cpp
+++ b/gfx/layers/apz/src/InputQueue.cpp
@@ -113,17 +113,18 @@ InputQueue::ReceiveTouchInput(const RefP
         block->GetOverscrollHandoffChain()->HasFastFlungApzc() &&
         haveBehaviors) {
       // If we're already in a fast fling, and a single finger goes down, then
       // we want special handling for the touch event, because it shouldn't get
       // delivered to content. Note that we don't set this flag when going
       // from a fast fling to a pinch state (i.e. second finger goes down while
       // the first finger is moving).
       block->SetDuringFastFling();
-      block->SetConfirmedTargetApzc(aTarget);
+      block->SetConfirmedTargetApzc(aTarget,
+          InputBlockState::TargetConfirmationState::eConfirmed);
       if (gfxPrefs::TouchActionEnabled()) {
         block->SetAllowedTouchBehaviors(currentBehaviors);
       }
       INPQ_LOG("block %p tagged as fast-motion\n", block);
     }
 
     CancelAnimationsForNewBlock(block);
 
@@ -581,17 +582,19 @@ InputQueue::MainThreadTimeout(const uint
   INPQ_LOG("got a main thread timeout; block=%" PRIu64 "\n", aInputBlockId);
   bool success = false;
   for (size_t i = 0; i < mInputBlockQueue.Length(); i++) {
     if (mInputBlockQueue[i]->GetBlockId() == aInputBlockId) {
       // time out the touch-listener response and also confirm the existing
       // target apzc in the case where the main thread doesn't get back to us
       // fast enough.
       success = mInputBlockQueue[i]->TimeoutContentResponse();
-      success |= mInputBlockQueue[i]->SetConfirmedTargetApzc(mInputBlockQueue[i]->GetTargetApzc());
+      success |= mInputBlockQueue[i]->SetConfirmedTargetApzc(
+          mInputBlockQueue[i]->GetTargetApzc(),
+          InputBlockState::TargetConfirmationState::eTimedOut);
       break;
     }
   }
   if (success) {
     ProcessInputBlocks();
   }
 }
 
@@ -619,17 +622,18 @@ InputQueue::SetConfirmedTargetApzc(uint6
   APZThreadUtils::AssertOnControllerThread();
 
   INPQ_LOG("got a target apzc; block=%" PRIu64 " guid=%s\n",
     aInputBlockId, aTargetApzc ? Stringify(aTargetApzc->GetGuid()).c_str() : "");
   bool success = false;
   for (size_t i = 0; i < mInputBlockQueue.Length(); i++) {
     CancelableBlockState* block = mInputBlockQueue[i].get();
     if (block->GetBlockId() == aInputBlockId) {
-      success = block->SetConfirmedTargetApzc(aTargetApzc);
+      success = block->SetConfirmedTargetApzc(aTargetApzc,
+          InputBlockState::TargetConfirmationState::eConfirmed);
       block->RecordContentResponseTime();
       break;
     }
   }
   if (success) {
     ProcessInputBlocks();
   }
 }
@@ -642,17 +646,18 @@ InputQueue::ConfirmDragBlock(uint64_t aI
 
   INPQ_LOG("got a target apzc; block=%" PRIu64 " guid=%s\n",
     aInputBlockId, aTargetApzc ? Stringify(aTargetApzc->GetGuid()).c_str() : "");
   bool success = false;
   for (size_t i = 0; i < mInputBlockQueue.Length(); i++) {
     DragBlockState* block = mInputBlockQueue[i]->AsDragBlock();
     if (block && block->GetBlockId() == aInputBlockId) {
       block->SetDragMetrics(aDragMetrics);
-      success = block->SetConfirmedTargetApzc(aTargetApzc);
+      success = block->SetConfirmedTargetApzc(aTargetApzc,
+          InputBlockState::TargetConfirmationState::eConfirmed);
       block->RecordContentResponseTime();
       break;
     }
   }
   if (success) {
     ProcessInputBlocks();
   }
 }
--- a/gfx/layers/basic/BasicImages.cpp
+++ b/gfx/layers/basic/BasicImages.cpp
@@ -44,17 +44,17 @@ public:
   {
     if (mDecodedBuffer) {
       // Right now this only happens if the Image was never drawn, otherwise
       // this will have been tossed away at surface destruction.
       mRecycleBin->RecycleBuffer(Move(mDecodedBuffer), mSize.height * mStride);
     }
   }
 
-  virtual bool SetData(const Data& aData) override;
+  virtual bool CopyData(const Data& aData) override;
   virtual void SetDelayedConversion(bool aDelayed) override { mDelayedConversion = aDelayed; }
 
   already_AddRefed<gfx::SourceSurface> GetAsSourceSurface() override;
 
   virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override
   {
     return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
   }
@@ -81,19 +81,19 @@ public:
   virtual RefPtr<PlanarYCbCrImage>
   CreatePlanarYCbCrImage(const gfx::IntSize& aScaleHint, BufferRecycleBin* aRecycleBin)
   {
     return new BasicPlanarYCbCrImage(aScaleHint, gfxPlatform::GetPlatform()->GetOffscreenFormat(), aRecycleBin);
   }
 };
 
 bool
-BasicPlanarYCbCrImage::SetData(const Data& aData)
+BasicPlanarYCbCrImage::CopyData(const Data& aData)
 {
-  RecyclingPlanarYCbCrImage::SetData(aData);
+  RecyclingPlanarYCbCrImage::CopyData(aData);
 
   if (mDelayedConversion) {
     return false;
   }
 
   // Do some sanity checks to prevent integer overflow
   if (aData.mYSize.width > PlanarYCbCrImage::MAX_DIMENSION ||
       aData.mYSize.height > PlanarYCbCrImage::MAX_DIMENSION) {
--- a/gfx/layers/basic/BasicPaintedLayer.h
+++ b/gfx/layers/basic/BasicPaintedLayer.h
@@ -49,19 +49,18 @@ public:
     NS_ASSERTION(BasicManager()->InConstruction(),
                  "Can only set properties in construction phase");
     PaintedLayer::SetVisibleRegion(aRegion);
   }
   virtual void InvalidateRegion(const nsIntRegion& aRegion) override
   {
     NS_ASSERTION(BasicManager()->InConstruction(),
                  "Can only set properties in construction phase");
-    mInvalidRegion.Or(mInvalidRegion, aRegion);
-    mInvalidRegion.SimplifyOutward(20);
-    mValidRegion.Sub(mValidRegion, mInvalidRegion);
+    mInvalidRegion.Add(aRegion);
+    mValidRegion.Sub(mValidRegion, mInvalidRegion.GetRegion());
   }
 
   virtual void PaintThebes(gfxContext* aContext,
                            Layer* aMaskLayer,
                            LayerManager::DrawPaintedLayerCallback aCallback,
                            void* aCallbackData) override;
 
   virtual void Validate(LayerManager::DrawPaintedLayerCallback aCallback,
--- a/gfx/layers/client/ClientPaintedLayer.h
+++ b/gfx/layers/client/ClientPaintedLayer.h
@@ -55,19 +55,18 @@ public:
     NS_ASSERTION(ClientManager()->InConstruction(),
                  "Can only set properties in construction phase");
     PaintedLayer::SetVisibleRegion(aRegion);
   }
   virtual void InvalidateRegion(const nsIntRegion& aRegion) override
   {
     NS_ASSERTION(ClientManager()->InConstruction(),
                  "Can only set properties in construction phase");
-    mInvalidRegion.Or(mInvalidRegion, aRegion);
-    mInvalidRegion.SimplifyOutward(20);
-    mValidRegion.Sub(mValidRegion, mInvalidRegion);
+    mInvalidRegion.Add(aRegion);
+    mValidRegion.Sub(mValidRegion, mInvalidRegion.GetRegion());
   }
 
   virtual void RenderLayer() override { RenderLayerWithReadback(nullptr); }
 
   virtual void RenderLayerWithReadback(ReadbackProcessor *aReadback) override;
 
   virtual void ClearCachedResources() override
   {
--- a/gfx/layers/client/ClientTiledPaintedLayer.h
+++ b/gfx/layers/client/ClientTiledPaintedLayer.h
@@ -49,20 +49,20 @@ protected:
 
 public:
   // Override name to distinguish it from ClientPaintedLayer in layer dumps
   virtual const char* Name() const override { return "TiledPaintedLayer"; }
 
   // PaintedLayer
   virtual Layer* AsLayer() override { return this; }
   virtual void InvalidateRegion(const nsIntRegion& aRegion) override {
-    mInvalidRegion.Or(mInvalidRegion, aRegion);
-    mInvalidRegion.SimplifyOutward(20);
-    mValidRegion.Sub(mValidRegion, mInvalidRegion);
-    mLowPrecisionValidRegion.Sub(mLowPrecisionValidRegion, mInvalidRegion);
+    mInvalidRegion.Add(aRegion);
+    nsIntRegion invalidRegion = mInvalidRegion.GetRegion();
+    mValidRegion.Sub(mValidRegion, invalidRegion);
+    mLowPrecisionValidRegion.Sub(mLowPrecisionValidRegion, invalidRegion);
   }
 
   // Shadow methods
   virtual void FillSpecificAttributes(SpecificLayerAttributes& aAttrs) override;
   virtual ShadowableLayer* AsShadowableLayer() override { return this; }
 
   virtual void Disconnect() override
   {
--- a/gfx/layers/ipc/APZChild.cpp
+++ b/gfx/layers/ipc/APZChild.cpp
@@ -73,22 +73,27 @@ APZChild::Create(const dom::TabId& aTabI
       return nullptr;
     }
     apz->SetObserver(observer);
   }
 
   return apz.forget();
 }
 
+APZChild::APZChild()
+  : mDestroyed(false)
+{
+}
+
 APZChild::~APZChild()
 {
   if (mObserver) {
     nsCOMPtr<nsIObserverService> os = services::GetObserverService();
     os->RemoveObserver(mObserver, "tab-child-created");
-  } else {
+  } else if (mBrowser) {
     mBrowser->SetAPZChild(nullptr);
   }
 }
 
 bool
 APZChild::RecvUpdateFrame(const FrameMetrics& aFrameMetrics)
 {
   return mBrowser->UpdateFrame(aFrameMetrics);
@@ -138,30 +143,47 @@ APZChild::RecvNotifyFlushComplete()
   nsCOMPtr<nsIPresShell> shell;
   if (nsCOMPtr<nsIDocument> doc = mBrowser->GetDocument()) {
     shell = doc->GetShell();
   }
   APZCCallbackHelper::NotifyFlushComplete(shell.get());
   return true;
 }
 
+bool
+APZChild::RecvDestroy()
+{
+  mDestroyed = true;
+  if (mBrowser) {
+    mBrowser->SetAPZChild(nullptr);
+    mBrowser = nullptr;
+  }
+  PAPZChild::Send__delete__(this);
+  return true;
+}
+
 void
 APZChild::SetObserver(nsIObserver* aObserver)
 {
   MOZ_ASSERT(!mBrowser);
   mObserver = aObserver;
 }
 
 void
 APZChild::SetBrowser(dom::TabChild* aBrowser)
 {
   MOZ_ASSERT(!mBrowser);
   if (mObserver) {
     nsCOMPtr<nsIObserverService> os = services::GetObserverService();
     os->RemoveObserver(mObserver, "tab-child-created");
     mObserver = nullptr;
   }
-  mBrowser = aBrowser;
-  mBrowser->SetAPZChild(this);
+  // We might get the tab-child-created notification after we receive a
+  // Destroy message from the parent. In that case we don't want to install
+  // ourselves with the browser.
+  if (!mDestroyed) {
+    mBrowser = aBrowser;
+    mBrowser->SetAPZChild(this);
+  }
 }
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/ipc/APZChild.h
+++ b/gfx/layers/ipc/APZChild.h
@@ -43,24 +43,27 @@ public:
                                  const uint64_t& aInputBlockId) override;
 
   virtual bool RecvNotifyAPZStateChange(const ViewID& aViewId,
                                         const APZStateChange& aChange,
                                         const int& aArg) override;
 
   virtual bool RecvNotifyFlushComplete() override;
 
+  virtual bool RecvDestroy() override;
+
   void SetBrowser(dom::TabChild* aBrowser);
 
 private:
-  APZChild() {};
+  APZChild();
 
   void SetObserver(nsIObserver* aObserver);
 
   RefPtr<dom::TabChild> mBrowser;
   RefPtr<nsIObserver> mObserver;
+  bool mDestroyed;
 };
 
 } // namespace layers
 
 } // namespace mozilla
 
 #endif // mozilla_layers_APZChild_h
--- a/gfx/layers/ipc/PAPZ.ipdl
+++ b/gfx/layers/ipc/PAPZ.ipdl
@@ -78,25 +78,27 @@ parent:
   /**
    * Updates the zoom constraints for a scrollable frame in this tab.
    * The zoom controller code lives on the parent side and so this allows it to
    * have up-to-date zoom constraints.
    */
   async UpdateZoomConstraints(uint32_t aPresShellId, ViewID aViewId,
                               MaybeZoomConstraints aConstraints);
 
+  async __delete__();
+
 child:
   async UpdateFrame(FrameMetrics frame);
 
   // The following methods correspond to functions on the GeckoContentController
   // interface in gfx/layers/apz/public/GeckoContentController.h. Refer to documentation
   // in that file for these functions.
   async HandleDoubleTap(CSSPoint aPoint, Modifiers aModifiers, ScrollableLayerGuid aGuid);
   async HandleSingleTap(CSSPoint aPoint, Modifiers aModifiers, ScrollableLayerGuid aGuid, bool aCallTakeFocusForClickFromTap);
   async HandleLongTap(CSSPoint point, Modifiers aModifiers, ScrollableLayerGuid aGuid, uint64_t aInputBlockId);
   async NotifyAPZStateChange(ViewID aViewId, APZStateChange aChange, int aArg);
   async NotifyFlushComplete();
 
-  async __delete__();
+  async Destroy();
 };
 
 } // layers
 } // mozilla
--- a/gfx/layers/ipc/RemoteContentController.cpp
+++ b/gfx/layers/ipc/RemoteContentController.cpp
@@ -20,31 +20,30 @@
 #include "Units.h"
 #ifdef MOZ_WIDGET_ANDROID
 #include "AndroidBridge.h"
 #endif
 
 namespace mozilla {
 namespace layers {
 
+static std::map<uint64_t, RefPtr<RemoteContentController>> sDestroyedControllers;
+
 RemoteContentController::RemoteContentController(uint64_t aLayersId,
                                                  dom::TabParent* aBrowserParent)
   : mUILoop(MessageLoop::current())
   , mLayersId(aLayersId)
   , mBrowserParent(aBrowserParent)
   , mMutex("RemoteContentController")
 {
   MOZ_ASSERT(NS_IsMainThread());
 }
 
 RemoteContentController::~RemoteContentController()
 {
-  if (mBrowserParent) {
-    Unused << PAPZParent::Send__delete__(this);
-  }
 }
 
 void
 RemoteContentController::RequestContentRepaint(const FrameMetrics& aFrameMetrics)
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (CanSend()) {
     Unused << SendUpdateFrame(aFrameMetrics);
@@ -294,36 +293,40 @@ RemoteContentController::RecvUpdateZoomC
 void
 RemoteContentController::ActorDestroy(ActorDestroyReason aWhy)
 {
   {
     MutexAutoLock lock(mMutex);
     mApzcTreeManager = nullptr;
   }
   mBrowserParent = nullptr;
-}
 
-// TODO: Remove once upgraded to GCC 4.8+ on linux. Calling a static member
-//       function (like PAPZParent::Send__delete__) in a lambda leads to a bogus
-//       error: "'this' was not captured for this lambda function".
-//
-//       (see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51494)
-static void
-DeletePAPZParent(PAPZParent* aPAPZ)
-{
-  Unused << PAPZParent::Send__delete__(aPAPZ);
+  uint64_t key = mLayersId;
+  NS_DispatchToMainThread(NS_NewRunnableFunction([key]() {
+    // sDestroyedControllers may or may not contain the key, depending on
+    // whether or not SendDestroy() was successfully sent out or not.
+    sDestroyedControllers.erase(key);
+  }));
 }
 
 void
 RemoteContentController::Destroy()
 {
   RefPtr<RemoteContentController> controller = this;
   NS_DispatchToMainThread(NS_NewRunnableFunction([controller] {
     if (controller->CanSend()) {
-      DeletePAPZParent(controller);
+      // Gfx code is done with this object, and it will probably get destroyed
+      // soon. However, if CanSend() is true, ActorDestroy has not yet been
+      // called, which means IPC code still has a handle to this object. We need
+      // to keep it alive until we get the ActorDestroy call, either via the
+      // __delete__ message or via IPC shutdown on our end.
+      uint64_t key = controller->mLayersId;
+      MOZ_ASSERT(sDestroyedControllers.find(key) == sDestroyedControllers.end());
+      sDestroyedControllers[key] = controller;
+      Unused << controller->SendDestroy();
     }
   }));
 }
 
 void
 RemoteContentController::ChildAdopted()
 {
   // Clear the cached APZCTreeManager.
--- a/gfx/layers/ipc/ShadowLayers.cpp
+++ b/gfx/layers/ipc/ShadowLayers.cpp
@@ -839,17 +839,17 @@ ShadowLayerForwarder::EndTransaction(Inf
     common.forceIsolatedGroup() = mutant->GetForceIsolatedGroup();
     if (Layer* maskLayer = mutant->GetMaskLayer()) {
       common.maskLayerChild() = Shadow(maskLayer->AsShadowableLayer());
     } else {
       common.maskLayerChild() = nullptr;
     }
     common.maskLayerParent() = nullptr;
     common.animations() = mutant->GetAnimations();
-    common.invalidRegion() = mutant->GetInvalidRegion();
+    common.invalidRegion() = mutant->GetInvalidRegion().GetRegion();
     common.scrollMetadata() = mutant->GetAllScrollMetadata();
     for (size_t i = 0; i < mutant->GetAncestorMaskLayerCount(); i++) {
       auto layer = Shadow(mutant->GetAncestorMaskLayerAt(i)->AsShadowableLayer());
       common.ancestorMaskLayersChild().AppendElement(layer);
     }
     nsCString log;
     mutant->GetDisplayListLog(log);
     common.displayListLog() = log;
--- a/gfx/layers/ipc/SharedPlanarYCbCrImage.cpp
+++ b/gfx/layers/ipc/SharedPlanarYCbCrImage.cpp
@@ -77,17 +77,17 @@ SharedPlanarYCbCrImage::GetAsSourceSurfa
   if (!mTextureClient) {
     NS_WARNING("Can't get as surface");
     return nullptr;
   }
   return PlanarYCbCrImage::GetAsSourceSurface();
 }
 
 bool
-SharedPlanarYCbCrImage::SetData(const PlanarYCbCrData& aData)
+SharedPlanarYCbCrImage::CopyData(const PlanarYCbCrData& aData)
 {
   // If mTextureClient has not already been allocated (through Allocate(aData))
   // allocate it. This code path is slower than the one used when Allocate has
   // been called since it will trigger a full copy.
   PlanarYCbCrData data = aData;
   if (!mTextureClient && !Allocate(data)) {
     return false;
   }
@@ -135,19 +135,19 @@ SharedPlanarYCbCrImage::AllocateAndGetNe
     // buffer which is where the y channel starts by default.
     return mapped.y.data;
   } else {
     MOZ_CRASH();
   }
 }
 
 bool
-SharedPlanarYCbCrImage::SetDataNoCopy(const Data &aData)
+SharedPlanarYCbCrImage::AdoptData(const Data &aData)
 {
-  // SetDataNoCopy is used to update YUV plane offsets without (re)allocating
+  // AdoptData is used to update YUV plane offsets without (re)allocating
   // memory previously allocated with AllocateAndGetNewBuffer().
 
   MOZ_ASSERT(mTextureClient, "This Image should have already allocated data");
   if (!mTextureClient) {
     return false;
   }
   mData = aData;
   mSize = aData.mPicSize;
--- a/gfx/layers/ipc/SharedPlanarYCbCrImage.h
+++ b/gfx/layers/ipc/SharedPlanarYCbCrImage.h
@@ -29,18 +29,18 @@ public:
 protected:
   ~SharedPlanarYCbCrImage();
 
 public:
   virtual TextureClient* GetTextureClient(CompositableClient* aClient) override;
   virtual uint8_t* GetBuffer() override;
 
   virtual already_AddRefed<gfx::SourceSurface> GetAsSourceSurface() override;
-  virtual bool SetData(const PlanarYCbCrData& aData) override;
-  virtual bool SetDataNoCopy(const Data &aData) override;
+  virtual bool CopyData(const PlanarYCbCrData& aData) override;
+  virtual bool AdoptData(const Data &aData) override;
 
   virtual bool Allocate(PlanarYCbCrData& aData);
   virtual uint8_t* AllocateAndGetNewBuffer(uint32_t aSize) override;
 
   virtual bool IsValid() override;
 
   virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override
   {
new file mode 100644
--- /dev/null
+++ b/gfx/src/TiledRegion.cpp
@@ -0,0 +1,357 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "TiledRegion.h"
+
+#include <algorithm>
+
+#include "mozilla/fallible.h"
+
+namespace mozilla {
+namespace gfx {
+
+static const int32_t kTileSize = 256;
+
+/**
+ * TiledRegionImpl stores an array of non-empty rectangles (pixman_box32_ts) to
+ * represent the region. Each rectangle is contained in a single tile;
+ * rectangles never cross tile boundaries. The rectangles are sorted by their
+ * tile's origin in top-to-bottom, left-to-right order.
+ * (Note that this can mean that a rectangle r1 can come before another
+ * rectangle r2 even if r2.y1 < r1.y1, as long as the two rects are in the same
+ * row of tiles and r1.x1 < r2.x1.)
+ * Empty tiles take up no space in the array - there is no rectangle stored for
+ * them. As a result, any algorithm that needs to deal with empty tiles will
+ * iterate through the mRects array and compare the positions of two
+ * consecutive rects to figure out whether there are any empty tiles between
+ * them.
+ */
+
+static pixman_box32_t
+IntersectionOfNonEmptyBoxes(const pixman_box32_t& aBox1,
+                            const pixman_box32_t& aBox2)
+{
+  return pixman_box32_t {
+    std::max(aBox1.x1, aBox2.x1),
+    std::max(aBox1.y1, aBox2.y1),
+    std::min(aBox1.x2, aBox2.x2),
+    std::min(aBox1.y2, aBox2.y2)
+  };
+}
+
+// A TileIterator points to a specific tile inside a certain tile range, or to
+// the end of the tile range. Advancing a TileIterator will move to the next
+// tile inside the range (or to the range end). The next tile is either the
+// tile to the right of the current one, or the first tile of the next tile
+// row if the current tile is already the last tile in the row.
+class TileIterator {
+public:
+  TileIterator(const pixman_box32_t& aTileBounds, const IntPoint& aPosition)
+    : mTileBounds(aTileBounds)
+    , mPos(aPosition)
+  {}
+
+  bool operator!=(const TileIterator& aOther) { return mPos != aOther.mPos; }
+  bool operator==(const TileIterator& aOther) { return mPos == aOther.mPos; }
+
+  IntPoint operator*() const { return mPos; }
+
+  const TileIterator& operator++() {
+    mPos.x += kTileSize;
+    if (mPos.x >= mTileBounds.x2) {
+      mPos.x = mTileBounds.x1;
+      mPos.y += kTileSize;
+    }
+    return *this;
+  }
+
+  TileIterator& operator=(const IntPoint& aPosition)
+  {
+    mPos = aPosition;
+    return *this;
+  }
+
+  bool IsBeforeTileContainingPoint(const IntPoint& aPoint) const
+  {
+    return (mPos.y + kTileSize) <= aPoint.y  ||
+      (mPos.y <= aPoint.y && (mPos.x + kTileSize) <= aPoint.x);
+  }
+
+  bool IsAtTileContainingPoint(const IntPoint& aPoint) const
+  {
+    return mPos.y <= aPoint.y && aPoint.y < (mPos.y + kTileSize) &&
+           mPos.x <= aPoint.x && aPoint.x < (mPos.x + kTileSize);
+
+  }
+
+  pixman_box32_t IntersectionWith(const pixman_box32_t& aRect) const
+  {
+    pixman_box32_t tile = { mPos.x, mPos.y,
+                            mPos.x + kTileSize, mPos.y + kTileSize };
+    return IntersectionOfNonEmptyBoxes(tile, aRect);
+  }
+
+private:
+  const pixman_box32_t& mTileBounds;
+  IntPoint mPos;
+};
+
+// A TileRange describes a range of tiles contained inside a certain tile
+// bounds (which is a rectangle that includes all tiles that you're
+// interested in). The tile range can start and end at any point inside a
+// tile row.
+// The tile range end is described by the tile that starts at the bottom
+// left corner of the tile bounds, i.e. the first tile under the tile
+// bounds.
+class TileRange {
+public:
+  // aTileBounds, aStart and aEnd need to be aligned with the tile grid.
+  TileRange(const pixman_box32_t& aTileBounds,
+            const IntPoint& aStart, const IntPoint& aEnd)
+    : mTileBounds(aTileBounds)
+    , mStart(aStart)
+    , mEnd(aEnd)
+  {}
+  // aTileBounds needs to be aligned with the tile grid.
+  explicit TileRange(const pixman_box32_t& aTileBounds)
+    : mTileBounds(aTileBounds)
+    , mStart(mTileBounds.x1, mTileBounds.y1)
+    , mEnd(mTileBounds.x1, mTileBounds.y2)
+  {}
+
+  TileIterator Begin() const { return TileIterator(mTileBounds, mStart); }
+  TileIterator End() const { return TileIterator(mTileBounds, mEnd); }
+
+  // The number of tiles in this tile range.
+  size_t Length() const
+  {
+    if (mEnd.y == mStart.y) {
+      return (mEnd.x - mStart.x) / kTileSize;
+    }
+    size_t numberOfFullRows = (mEnd.y - mStart.y) / kTileSize - 1;
+    return ((mTileBounds.x2 - mStart.x) +
+            (mTileBounds.x2 - mTileBounds.x1) * numberOfFullRows +
+            (mEnd.x - mTileBounds.x1)) / kTileSize;
+  }
+
+  // If aTileOrigin does not describe a tile inside our tile bounds, move it
+  // to the next tile that you'd encounter by "advancing" a tile iterator
+  // inside these tile bounds. If aTileOrigin is after the last tile inside
+  // our tile bounds, move it to the range end tile.
+  // The result of this method is a valid end tile for a tile range with our
+  // tile bounds.
+  IntPoint MoveIntoBounds(const IntPoint& aTileOrigin) const
+  {
+    IntPoint p = aTileOrigin;
+    if (p.x < mTileBounds.x1) {
+      p.x = mTileBounds.x1;
+    } else if (p.x >= mTileBounds.x2) {
+      p.x = mTileBounds.x1;
+      p.y += kTileSize;
+    }
+    if (p.y < mTileBounds.y1) {
+      p.y = mTileBounds.y1;
+      p.x = mTileBounds.x1;
+    } else if (p.y >= mTileBounds.y2) {
+      // There's only one valid state after the end of the tile range, and that's
+      // the bottom left point of the tile bounds.
+      p.x = mTileBounds.x1;
+      p.y = mTileBounds.y2;
+    }
+    return p;
+  }
+
+private:
+  const pixman_box32_t& mTileBounds;
+  const IntPoint mStart;
+  const IntPoint mEnd;
+};
+
+static IntPoint
+TileContainingPoint(const IntPoint& aPoint)
+{
+  return IntPoint(RoundDownToMultiple(aPoint.x, kTileSize),
+                  RoundDownToMultiple(aPoint.y, kTileSize));
+}
+
+enum class IterationAction : uint8_t {
+  CONTINUE,
+  STOP
+};
+
+enum class IterationEndReason : uint8_t {
+  NOT_STOPPED,
+  STOPPED
+};
+
+template<
+  typename HandleEmptyTilesFunction,
+  typename HandleNonEmptyTileFunction,
+  typename RectArrayT>
+IterationEndReason ProcessIntersectedTiles(const pixman_box32_t& aRect,
+                                           RectArrayT& aRectArray,
+                                           HandleEmptyTilesFunction aHandleEmptyTiles,
+                                           HandleNonEmptyTileFunction aHandleNonEmptyTile)
+{
+  pixman_box32_t tileBounds = {
+    RoundDownToMultiple(aRect.x1, kTileSize),
+    RoundDownToMultiple(aRect.y1, kTileSize),
+    RoundUpToMultiple(aRect.x2, kTileSize),
+    RoundUpToMultiple(aRect.y2, kTileSize)
+  };
+
+  TileRange tileRange(tileBounds);
+  TileIterator rangeEnd = tileRange.End();
+
+  // tileIterator points to the next tile in tileRange, or to rangeEnd if we're
+  // done.
+  TileIterator tileIterator = tileRange.Begin();
+
+  // We iterate over the rectangle array. Depending on the position of the
+  // rectangle we encounter, we may need to advance tileIterator by zero, one,
+  // or more tiles:
+  //  - Zero if the rectangle we encountered is outside the tiles that
+  //    intersect aRect.
+  //  - One if the rectangle is in the exact tile that we're interested in next
+  //    (i.e. the tile that tileIterator points at).
+  //  - More than one if the encountered rectangle is in a tile that's further
+  //    to the right or to the bottom than tileIterator. In that case there is
+  //    at least one empty tile between the last rectangle we encountered and
+  //    the current one.
+  for (size_t i = 0; i < aRectArray.Length() && tileIterator != rangeEnd; i++) {
+    MOZ_ASSERT(aRectArray[i].x1 < aRectArray[i].x2 && aRectArray[i].y1 < aRectArray[i].y2, "empty rect");
+    IntPoint rectOrigin(aRectArray[i].x1, aRectArray[i].y1);
+    if (tileIterator.IsBeforeTileContainingPoint(rectOrigin)) {
+      IntPoint tileOrigin = TileContainingPoint(rectOrigin);
+      IntPoint afterEmptyTiles = tileRange.MoveIntoBounds(tileOrigin);
+      TileRange emptyTiles(tileBounds, *tileIterator, afterEmptyTiles);
+      if (aHandleEmptyTiles(aRectArray, i, emptyTiles) == IterationAction::STOP) {
+        return IterationEndReason::STOPPED;
+      }
+      tileIterator = afterEmptyTiles;
+      if (tileIterator == rangeEnd) {
+        return IterationEndReason::NOT_STOPPED;
+      }
+    }
+    if (tileIterator.IsAtTileContainingPoint(rectOrigin)) {
+      pixman_box32_t rectIntersection = tileIterator.IntersectionWith(aRect);
+      if (aHandleNonEmptyTile(aRectArray, i, rectIntersection) == IterationAction::STOP) {
+        return IterationEndReason::STOPPED;
+      }
+      ++tileIterator;
+    }
+  }
+
+  if (tileIterator != rangeEnd) {
+    // We've looked at all of our existing rectangles but haven't covered all
+    // of the tiles that we're interested in yet. So we need to deal with the
+    // remaining tiles now.
+    size_t endIndex = aRectArray.Length();
+    TileRange emptyTiles(tileBounds, *tileIterator, *rangeEnd);
+    if (aHandleEmptyTiles(aRectArray, endIndex, emptyTiles) == IterationAction::STOP) {
+      return IterationEndReason::STOPPED;
+    }
+  }
+  return IterationEndReason::NOT_STOPPED;
+}
+
+static pixman_box32_t
+UnionBoundsOfNonEmptyBoxes(const pixman_box32_t& aBox1,
+                           const pixman_box32_t& aBox2)
+{
+  return { std::min(aBox1.x1, aBox2.x1),
+           std::min(aBox1.y1, aBox2.y1),
+           std::max(aBox1.x2, aBox2.x2),
+           std::max(aBox1.y2, aBox2.y2) };
+}
+
+// Returns true when adding the rectangle was successful, and false if
+// allocation failed.
+// When this returns false, our internal state might not be consistent and we
+// need to be cleared.
+bool
+TiledRegionImpl::AddRect(const pixman_box32_t& aRect)
+{
+  // We are adding a rectangle that can span multiple tiles.
+  // For each empty tile that aRect intersects, we need to add the intersection
+  // of aRect with that tile to mRects, respecting the order of mRects.
+  // For each tile that already has a rectangle, we need to enlarge that
+  // existing rectangle to include the intersection of aRect with the tile.
+  return ProcessIntersectedTiles(aRect, mRects,
+    [&aRect](nsTArray<pixman_box32_t>& rects, size_t& rectIndex, TileRange emptyTiles) {
+      if (!rects.InsertElementsAt(rectIndex, emptyTiles.Length(), fallible)) {
+        return IterationAction::STOP;
+      }
+      for (TileIterator tileIt = emptyTiles.Begin();
+           tileIt != emptyTiles.End();
+           ++tileIt, ++rectIndex) {
+        rects[rectIndex] = tileIt.IntersectionWith(aRect);
+      }
+      return IterationAction::CONTINUE;
+    },
+    [](nsTArray<pixman_box32_t>& rects, size_t rectIndex, const pixman_box32_t& rectIntersectionWithTile) {
+      rects[rectIndex] =
+        UnionBoundsOfNonEmptyBoxes(rects[rectIndex], rectIntersectionWithTile);
+      return IterationAction::CONTINUE;
+    }) == IterationEndReason::NOT_STOPPED;
+}
+
+static bool
+NonEmptyBoxesIntersect(const pixman_box32_t& aBox1, const pixman_box32_t& aBox2)
+{
+  return aBox1.x1 < aBox2.x2 && aBox2.x1 < aBox1.x2 &&
+         aBox1.y1 < aBox2.y2 && aBox2.y1 < aBox1.y2;
+}
+
+bool
+TiledRegionImpl::Intersects(const pixman_box32_t& aRect) const
+{
+  // aRect intersects this region if it intersects any of our rectangles.
+  return ProcessIntersectedTiles(aRect, mRects,
+    [](const nsTArray<pixman_box32_t>& rects, size_t& rectIndex, TileRange emptyTiles) {
+      // Ignore empty tiles and keep on iterating.
+      return IterationAction::CONTINUE;
+    },
+    [](const nsTArray<pixman_box32_t>& rects, size_t rectIndex, const pixman_box32_t& rectIntersectionWithTile) {
+      if (NonEmptyBoxesIntersect(rects[rectIndex], rectIntersectionWithTile)) {
+        // Found an intersecting rectangle, so aRect intersects this region.
+        return IterationAction::STOP;
+      }
+      return IterationAction::CONTINUE;
+    }) == IterationEndReason::STOPPED;
+}
+
+static bool
+NonEmptyBoxContainsNonEmptyBox(const pixman_box32_t& aBox1, const pixman_box32_t& aBox2)
+{
+  return aBox1.x1 <= aBox2.x1 && aBox2.x2 <= aBox1.x2 &&
+         aBox1.y1 <= aBox2.y1 && aBox2.y2 <= aBox1.y2;
+}
+
+bool
+TiledRegionImpl::Contains(const pixman_box32_t& aRect) const
+{
+  // aRect is contained in this region if aRect does not intersect any empty
+  // tiles and, for each non-empty tile, if the intersection of aRect with that
+  // tile is contained in the existing rectangle we have in that tile.
+  return ProcessIntersectedTiles(aRect, mRects,
+    [](const nsTArray<pixman_box32_t>& rects, size_t& rectIndex, TileRange emptyTiles) {
+      // Found an empty tile that intersects aRect, so aRect is not contained
+      // in this region.
+      return IterationAction::STOP;
+    },
+    [](const nsTArray<pixman_box32_t>& rects, size_t rectIndex, const pixman_box32_t& rectIntersectionWithTile) {
+      if (!NonEmptyBoxContainsNonEmptyBox(rects[rectIndex], rectIntersectionWithTile)) {
+        // Our existing rectangle in this tile does not cover the part of aRect that
+        // intersects this tile, so aRect is not contained in this region.
+        return IterationAction::STOP;
+      }
+      return IterationAction::CONTINUE;
+    }) == IterationEndReason::NOT_STOPPED;
+}
+
+} // namespace gfx
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/src/TiledRegion.h
@@ -0,0 +1,198 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef MOZILLA_GFX_TILEDREGION_H_
+#define MOZILLA_GFX_TILEDREGION_H_
+
+#include "mozilla/ArrayView.h"
+#include "mozilla/gfx/Rect.h"
+#include "mozilla/Move.h"
+#include "nsRegion.h"
+#include "pixman.h"
+
+namespace mozilla {
+namespace gfx {
+
+// See TiledRegion.cpp for documentation on TiledRegionImpl.
+class TiledRegionImpl {
+public:
+  void Clear() { mRects.Clear(); }
+  bool AddRect(const pixman_box32_t& aRect);
+  bool Intersects(const pixman_box32_t& aRect) const;
+  bool Contains(const pixman_box32_t& aRect) const;
+  operator ArrayView<pixman_box32_t>() const { return ArrayView<pixman_box32_t>(mRects); }
+
+private:
+  nsTArray<pixman_box32_t> mRects;
+};
+
+/**
+ * A auto-simplifying region type that supports one rectangle per tile.
+ * The virtual tile grid is anchored at (0, 0) and has quadratic tiles whose
+ * size is hard-coded as kTileSize in TiledRegion.cpp.
+ * A TiledRegion starts out empty. You can add rectangles or (regular) regions
+ * into it by calling Add(). Add() is a mutating union operation (similar to
+ * OrWith on nsRegion) that's *not* exact, because it will enlarge the region as
+ * necessary to satisfy the "one rectangle per tile" requirement.
+ * Tiled regions convert implicitly to the underlying regular region type.
+ * The only way to remove parts from a TiledRegion is by calling SetEmpty().
+ */
+template<typename RegionT>
+class TiledRegion {
+public:
+  typedef typename RegionT::RectType RectT;
+
+  TiledRegion()
+    : mCoversBounds(false)
+  {}
+
+  TiledRegion(const TiledRegion& aOther)
+    : mBounds(aOther.mBounds)
+    , mImpl(aOther.mImpl)
+    , mCoversBounds(false)
+  {}
+
+  TiledRegion(TiledRegion&& aOther)
+    : mBounds(aOther.mBounds)
+    , mImpl(Move(aOther.mImpl))
+    , mCoversBounds(false)
+  {}
+
+  RegionT GetRegion() const
+  {
+    if (mBounds.IsEmpty()) {
+      return RegionT();
+    }
+    if (mCoversBounds) {
+      // Rect limit hit or allocation failed, treat as 1 rect.
+      return RegionT(mBounds);
+    }
+    return RegionT(mImpl);
+  }
+
+  TiledRegion& operator=(const TiledRegion& aOther)
+  {
+    if (&aOther != this) {
+      mBounds = aOther.mBounds;
+      mImpl = aOther.mImpl;
+      mCoversBounds = aOther.mCoversBounds;
+    }
+    return *this;
+  }
+
+  void Add(const RectT& aRect)
+  {
+    if (aRect.IsEmpty()) {
+      return;
+    }
+
+    mBounds = mBounds.Union(aRect);
+
+    if (mCoversBounds) {
+      return;
+    }
+    if (ExceedsMaximumSize()) {
+      FallBackToBounds();
+      return;
+    }
+
+    if (!mImpl.AddRect(RectToBox(aRect))) {
+      FallBackToBounds();
+    }
+  }
+
+  void Add(const RegionT& aRegion)
+  {
+    mBounds = mBounds.Union(aRegion.GetBounds());
+
+    if (mCoversBounds) {
+      return;
+    }
+    if (ExceedsMaximumSize()) {
+      FallBackToBounds();
+      return;
+    }
+
+    for (auto iter = aRegion.RectIter(); !iter.Done(); iter.Next()) {
+      RectT r = iter.Get();
+      MOZ_ASSERT(!r.IsEmpty());
+      if (!mImpl.AddRect(RectToBox(r))) {
+        FallBackToBounds();
+        return;
+      }
+    }
+  }
+
+  bool IsEmpty() const { return mBounds.IsEmpty(); }
+
+  void SetEmpty()
+  {
+    mBounds.SetEmpty();
+    mImpl.Clear();
+    mCoversBounds = false;
+  }
+
+  RectT GetBounds() const { return mBounds; }
+
+  bool Intersects(const RectT& aRect) const
+  {
+    if (!mBounds.Intersects(aRect)) {
+      return false;
+    }
+    if (mCoversBounds) {
+      return true;
+    }
+
+    return mImpl.Intersects(RectToBox(aRect));
+  }
+
+  bool Contains(const RectT& aRect) const
+  {
+    if (!mBounds.Contains(aRect)) {
+      return false;
+    }
+    if (mCoversBounds) {
+      return true;
+    }
+    return mImpl.Contains(RectToBox(aRect));
+  }
+
+private:
+
+  bool ExceedsMaximumSize() const
+  {
+    // This stops us from allocating insane numbers of tiles.
+    return mBounds.width >= 50 * 256 || mBounds.height >= 50 * 256;
+  }
+
+  void FallBackToBounds()
+  {
+    mCoversBounds = true;
+    mImpl.Clear();
+  }
+
+  static pixman_box32_t RectToBox(const RectT& aRect)
+  {
+    return { aRect.x, aRect.y, aRect.XMost(), aRect.YMost() };
+  }
+
+  RectT mBounds;
+  TiledRegionImpl mImpl;
+
+  // mCoversBounds is true if we bailed out due to a large number of tiles.
+  // mCoversBounds being true means that this TiledRegion is just a simple
+  // rectangle (our mBounds).
+  // Once set to true, the TiledRegion will stay in this state until SetEmpty
+  // is called.
+  bool mCoversBounds;
+};
+
+typedef TiledRegion<IntRegion> TiledIntRegion;
+
+} // namespace gfx
+} // namespace mozilla
+
+#endif /* MOZILLA_GFX_TILEDREGION_H_ */
--- a/gfx/src/moz.build
+++ b/gfx/src/moz.build
@@ -41,16 +41,20 @@ EXPORTS += [
     'RegionBuilder.h',
 ]
 
 EXPORTS.mozilla += [
     'AppUnits.h',
     'ArrayView.h',
 ]
 
+EXPORTS.mozilla.gfx += [
+    'TiledRegion.h',
+]
+
 if CONFIG['MOZ_X11']:
     EXPORTS.mozilla += ['X11Util.h']
     SOURCES += [
         'X11Util.cpp',
     ]
 
 UNIFIED_SOURCES += [
     'DriverCrashGuard.cpp',
@@ -61,16 +65,17 @@ UNIFIED_SOURCES += [
     'nsFont.cpp',
     'nsFontMetrics.cpp',
     'nsRect.cpp',
     'nsRegion.cpp',
     'nsScriptableRegion.cpp',
     'nsThebesFontEnumerator.cpp',
     'nsThebesGfxFactory.cpp',
     'nsTransform2D.cpp',
+    'TiledRegion.cpp',
 ]
 
 # nsDeviceContext.cpp cannot be built in unified mode because it pulls in OS X system headers.
 SOURCES += [
     'nsDeviceContext.cpp',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
--- a/gfx/tests/gtest/TestRegion.cpp
+++ b/gfx/tests/gtest/TestRegion.cpp
@@ -6,18 +6,20 @@
 #include <algorithm>
 
 #include "PingPongRegion.h"
 #include "gtest/gtest.h"
 #include "gtest/MozGTestBench.h"
 #include "nsRect.h"
 #include "nsRegion.h"
 #include "RegionBuilder.h"
+#include "mozilla/gfx/TiledRegion.h"
 
 using namespace std;
+using namespace mozilla::gfx;
 
 class TestLargestRegion {
 public:
   static void TestSingleRect(nsRect r) {
     nsRegion region(r);
     EXPECT_TRUE(region.GetLargestRectangle().IsEqualInterior(r));
   }
   // Construct a rectangle, remove part of it, then check the remainder
@@ -592,16 +594,107 @@ TEST(Gfx, PingPongRegion) {
     for (size_t i = 0; i < size; i++) {
       ar.SubOut(rects[i]);
       r.SubOut(rects[i]);
       EXPECT_TRUE(ar.Region().IsEqual(r));
     }
   }
 }
 
+// The TiledRegion tests use nsIntRect / IntRegion because nsRect doesn't have
+// InflateToMultiple which is required by TiledRegion.
+TEST(Gfx, TiledRegionNoSimplification2Rects) {
+  // Add two rectangles, both rectangles are completely inside
+  // different tiles.
+  nsIntRegion region;
+  region.OrWith(nsIntRect(50, 50, 50, 50));
+  region.OrWith(nsIntRect(300, 50, 50, 50));
+
+  TiledIntRegion tiledRegion;
+  tiledRegion.Add(nsIntRect(50, 50, 50, 50));
+  tiledRegion.Add(nsIntRect(300, 50, 50, 50));
+
+  // No simplification should have happened.
+  EXPECT_TRUE(region.IsEqual(tiledRegion.GetRegion()));
+}
+
+TEST(Gfx, TiledRegionNoSimplification1Region) {
+  // Add two rectangles, both rectangles are completely inside
+  // different tiles.
+  nsIntRegion region;
+  region.OrWith(nsIntRect(50, 50, 50, 50));
+  region.OrWith(nsIntRect(300, 50, 50, 50));
+
+  TiledIntRegion tiledRegion;
+  tiledRegion.Add(region);
+
+  // No simplification should have happened.
+  EXPECT_TRUE(region.IsEqual(tiledRegion.GetRegion()));
+}
+
+TEST(Gfx, TiledRegionWithSimplification3Rects) {
+  // Add three rectangles. The first two rectangles are completely inside
+  // different tiles, but the third rectangle intersects both tiles.
+  TiledIntRegion tiledRegion;
+  tiledRegion.Add(nsIntRect(50, 50, 50, 50));
+  tiledRegion.Add(nsIntRect(300, 50, 50, 50));
+  tiledRegion.Add(nsIntRect(250, 70, 10, 10));
+
+  // Both tiles should have simplified their rectangles, and those two
+  // rectangles are adjacent to each other, so they just build up one rect.
+  EXPECT_TRUE(tiledRegion.GetRegion().IsEqual(nsIntRect(50, 50, 300, 50)));
+}
+
+TEST(Gfx, TiledRegionWithSimplification1Region) {
+  // Add three rectangles. The first two rectangles are completely inside
+  // different tiles, but the third rectangle intersects both tiles.
+  nsIntRegion region;
+  region.OrWith(nsIntRect(50, 50, 50, 50));
+  region.OrWith(nsIntRect(300, 50, 50, 50));
+  region.OrWith(nsIntRect(250, 70, 10, 10));
+
+  TiledIntRegion tiledRegion;
+  tiledRegion.Add(region);
+
+  // Both tiles should have simplified their rectangles, and those two
+  // rectangles are adjacent to each other, so they just build up one rect.
+  EXPECT_TRUE(tiledRegion.GetRegion().IsEqual(nsIntRect(50, 50, 300, 50)));
+}
+
+TEST(Gfx, TiledRegionContains) {
+  // Add three rectangles. The first two rectangles are completely inside
+  // different tiles, but the third rectangle intersects both tiles.
+  TiledIntRegion tiledRegion;
+  tiledRegion.Add(nsIntRect(50, 50, 50, 50));
+  tiledRegion.Add(nsIntRect(300, 50, 50, 50));
+  tiledRegion.Add(nsIntRect(250, 70, 10, 10));
+
+  // Both tiles should have simplified their rectangles, and those two
+  // rectangles are adjacent to each other, so they just build up one rect.
+  EXPECT_TRUE(tiledRegion.Contains(nsIntRect(50, 50, 300, 50)));
+  EXPECT_TRUE(tiledRegion.Contains(nsIntRect(50, 50, 50, 50)));
+  EXPECT_FALSE(tiledRegion.Contains(nsIntRect(50, 50, 301, 50)));
+}
+
+TEST(Gfx, TiledRegionIntersects) {
+  // Add three rectangles. The first two rectangles are completely inside
+  // different tiles, but the third rectangle intersects both tiles.
+  TiledIntRegion tiledRegion;
+  tiledRegion.Add(nsIntRect(50, 50, 50, 50));
+  tiledRegion.Add(nsIntRect(300, 50, 50, 50));
+  tiledRegion.Add(nsIntRect(250, 70, 10, 10));
+
+  // Both tiles should have simplified their rectangles, and those two
+  // rectangles are adjacent to each other, so they just build up one rect.
+  EXPECT_TRUE(tiledRegion.Intersects(nsIntRect(50, 50, 300, 50)));
+  EXPECT_TRUE(tiledRegion.Intersects(nsIntRect(200, 10, 10, 50)));
+  EXPECT_TRUE(tiledRegion.Intersects(nsIntRect(50, 50, 301, 50)));
+  EXPECT_FALSE(tiledRegion.Intersects(nsIntRect(0, 0, 50, 500)));
+}
+
 MOZ_GTEST_BENCH(GfxBench, RegionOr, []{
   const int size = 5000;
 
   nsRegion r;
   for (int i = 0; i < size; i++) {
     r = r.Or(r, nsRect(i, i, i + 10, i + 10));
   }
 
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -65,17 +65,16 @@ JSCompartment::JSCompartment(Zone* zone,
     globalWriteBarriered(false),
     detachedTypedObjects(0),
     objectMetadataState(ImmediateMetadata()),
     propertyTree(thisForCtor()),
     baseShapes(zone, BaseShapeSet()),
     initialShapes(zone, InitialShapeSet()),
     selfHostingScriptSource(nullptr),
     objectMetadataTable(nullptr),
-    innerViews(zone, InnerViewTable()),
     lazyArrayBuffers(nullptr),
     nonSyntacticLexicalScopes_(nullptr),
     gcIncomingGrayPointers(nullptr),
     debugModeBits(0),
     watchpointMap(nullptr),
     scriptCountsMap(nullptr),
     debugScriptMap(nullptr),
     debugScopes(nullptr),
@@ -663,16 +662,22 @@ JSCompartment::sweepAfterMinorGC()
 {
     globalWriteBarriered = false;
 
     if (innerViews.needsSweepAfterMinorGC())
         innerViews.sweepAfterMinorGC();
 }
 
 void
+JSCompartment::sweepInnerViews()
+{
+    innerViews.sweep();
+}
+
+void
 JSCompartment::sweepSavedStacks()
 {
     savedStacks_.sweep();
 }
 
 void
 JSCompartment::sweepGlobalObject(FreeOp* fop)
 {
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -459,17 +459,17 @@ struct JSCompartment
      */
     js::ReadBarrieredScriptSourceObject selfHostingScriptSource;
 
     // Keep track of the metadata objects which can be associated with each JS
     // object. Both keys and values are in this compartment.
     js::ObjectWeakMap* objectMetadataTable;
 
     // Map from array buffers to views sharing that storage.
-    JS::WeakCache<js::InnerViewTable> innerViews;
+    js::InnerViewTable innerViews;
 
     // Inline transparent typed objects do not initially have an array buffer,
     // but can have that buffer created lazily if it is accessed later. This
     // table manages references from such typed objects to their buffers.
     js::ObjectWeakMap* lazyArrayBuffers;
 
     // All unboxed layouts in the compartment.
     mozilla::LinkedList<js::UnboxedLayout> unboxedLayouts;
@@ -579,16 +579,17 @@ struct JSCompartment
     void traceOutgoingCrossCompartmentWrappers(JSTracer* trc);
     static void traceIncomingCrossCompartmentEdgesForZoneGC(JSTracer* trc);
 
     /* Whether to preserve JIT code on non-shrinking GCs. */
     bool preserveJitCode() { return creationOptions_.preserveJitCode(); }
 
     void sweepAfterMinorGC();
 
+    void sweepInnerViews();
     void sweepCrossCompartmentWrappers();
     void sweepSavedStacks();
     void sweepGlobalObject(js::FreeOp* fop);
     void sweepObjectPendingMetadata();
     void sweepSelfHostingScriptSource();
     void sweepJitCompartment(js::FreeOp* fop);
     void sweepRegExps();
     void sweepDebugScopes();
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -2456,16 +2456,17 @@ GCRuntime::sweepZoneAfterCompacting(Zone
     FreeOp* fop = rt->defaultFreeOp();
     sweepTypesAfterCompacting(zone);
     zone->sweepBreakpoints(fop);
     zone->sweepWeakMaps();
     for (auto* cache : zone->weakCaches_)
         cache->sweep();
 
     for (CompartmentsInZoneIter c(zone); !c.done(); c.next()) {
+        c->sweepInnerViews();
         c->objectGroups.sweep(fop);
         c->sweepRegExps();
         c->sweepSavedStacks();
         c->sweepGlobalObject(fop);
         c->sweepObjectPendingMetadata();
         c->sweepSelfHostingScriptSource();
         c->sweepDebugScopes();
         c->sweepJitCompartment(fop);
@@ -5064,31 +5065,39 @@ class SweepWeakCacheTask : public GCSwee
 
 #define MAKE_GC_SWEEP_TASK(name)                                              \
     class name : public GCSweepTask {                                         \
         void run() override;                                          \
       public:                                                                 \
         explicit name (JSRuntime* rt) : GCSweepTask(rt) {}                    \
     }
 MAKE_GC_SWEEP_TASK(SweepAtomsTask);
+MAKE_GC_SWEEP_TASK(SweepInnerViewsTask);
 MAKE_GC_SWEEP_TASK(SweepCCWrappersTask);
 MAKE_GC_SWEEP_TASK(SweepBaseShapesTask);
 MAKE_GC_SWEEP_TASK(SweepInitialShapesTask);
 MAKE_GC_SWEEP_TASK(SweepObjectGroupsTask);
 MAKE_GC_SWEEP_TASK(SweepRegExpsTask);
 MAKE_GC_SWEEP_TASK(SweepMiscTask);
 #undef MAKE_GC_SWEEP_TASK
 
 /* virtual */ void
 SweepAtomsTask::run()
 {
     runtime->sweepAtoms();
 }
 
 /* virtual */ void
+SweepInnerViewsTask::run()
+{
+    for (GCCompartmentGroupIter c(runtime); !c.done(); c.next())
+        c->sweepInnerViews();
+}
+
+/* virtual */ void
 SweepCCWrappersTask::run()
 {
     for (GCCompartmentGroupIter c(runtime); !c.done(); c.next())
         c->sweepCrossCompartmentWrappers();
 }
 
 /* virtual */ void
 SweepObjectGroupsTask::run()
@@ -5159,16 +5168,17 @@ GCRuntime::beginSweepingZoneGroup()
         zone->gcLastZoneGroupIndex = zoneGroupIndex;
 #endif
     }
 
     validateIncrementalMarking();
 
     FreeOp fop(rt);
     SweepAtomsTask sweepAtomsTask(rt);
+    SweepInnerViewsTask sweepInnerViewsTask(rt);
     SweepCCWrappersTask sweepCCWrappersTask(rt);
     SweepObjectGroupsTask sweepObjectGroupsTask(rt);
     SweepRegExpsTask sweepRegExpsTask(rt);
     SweepMiscTask sweepMiscTask(rt);
     mozilla::Vector<SweepWeakCacheTask> sweepCacheTasks;
 
     for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) {
         /* Clear all weakrefs that point to unmarked things. */
@@ -5212,16 +5222,17 @@ GCRuntime::beginSweepingZoneGroup()
     }
 
     {
         gcstats::AutoPhase ap(stats, gcstats::PHASE_SWEEP_COMPARTMENTS);
         gcstats::AutoSCC scc(stats, zoneGroupIndex);
 
         {
             AutoLockHelperThreadState helperLock;
+            startTask(sweepInnerViewsTask, gcstats::PHASE_SWEEP_INNER_VIEWS);
             startTask(sweepCCWrappersTask, gcstats::PHASE_SWEEP_CC_WRAPPER);
             startTask(sweepObjectGroupsTask, gcstats::PHASE_SWEEP_TYPE_OBJECT);
             startTask(sweepRegExpsTask, gcstats::PHASE_SWEEP_REGEXP);
             startTask(sweepMiscTask, gcstats::PHASE_SWEEP_MISC);
             for (auto& task : sweepCacheTasks)
                 startTask(task, gcstats::PHASE_SWEEP_MISC);
         }
 
@@ -5292,16 +5303,17 @@ GCRuntime::beginSweepingZoneGroup()
         joinTask(sweepAtomsTask, gcstats::PHASE_SWEEP_ATOMS);
     }
 
     {
         gcstats::AutoPhase ap(stats, gcstats::PHASE_SWEEP_COMPARTMENTS);
         gcstats::AutoSCC scc(stats, zoneGroupIndex);
 
         AutoLockHelperThreadState helperLock;
+        joinTask(sweepInnerViewsTask, gcstats::PHASE_SWEEP_INNER_VIEWS);
         joinTask(sweepCCWrappersTask, gcstats::PHASE_SWEEP_CC_WRAPPER);
         joinTask(sweepObjectGroupsTask, gcstats::PHASE_SWEEP_TYPE_OBJECT);
         joinTask(sweepRegExpsTask, gcstats::PHASE_SWEEP_REGEXP);
         joinTask(sweepMiscTask, gcstats::PHASE_SWEEP_MISC);
         for (auto& task : sweepCacheTasks)
             joinTask(task, gcstats::PHASE_SWEEP_MISC);
     }
 
--- a/js/src/vm/ArrayBufferObject.cpp
+++ b/js/src/vm/ArrayBufferObject.cpp
@@ -287,21 +287,20 @@ ArrayBufferObject::detach(JSContext* cx,
             oomUnsafe.crash("ArrayBufferObject::detach");
         MarkObjectGroupFlags(cx, cx->global(), OBJECT_FLAG_TYPED_OBJECT_HAS_DETACHED_BUFFER);
         cx->compartment()->detachedTypedObjects = 1;
     }
 
     // Update all views of the buffer to account for the buffer having been
     // detached, and clear the buffer's data and list of views.
 
-    auto& innerViews = cx->compartment()->innerViews;
-    if (InnerViewTable::ViewVector* views = innerViews.maybeViewsUnbarriered(buffer)) {
+    if (InnerViewTable::ViewVector* views = cx->compartment()->innerViews.maybeViewsUnbarriered(buffer)) {
         for (size_t i = 0; i < views->length(); i++)
             NoteViewBufferWasDetached((*views)[i], newContents, cx);
-        innerViews.removeViews(buffer);
+        cx->compartment()->innerViews.removeViews(buffer);
     }
     if (buffer->firstView()) {
         if (buffer->forInlineTypedObject()) {
             // The buffer points to inline data in its first view, so to keep
             // this pointer alive we don't clear out the first view.
             MOZ_ASSERT(buffer->firstView()->is<InlineTransparentTypedObject>());
         } else {
             NoteViewBufferWasDetached(buffer->firstView(), newContents, cx);
@@ -360,18 +359,17 @@ ArrayBufferObject::changeContents(JSCont
 {
     MOZ_ASSERT(!forInlineTypedObject());
 
     // Change buffer contents.
     uint8_t* oldDataPointer = dataPointer();
     setNewOwnedData(cx->runtime()->defaultFreeOp(), newContents);
 
     // Update all views.
-    auto& innerViews = cx->compartment()->innerViews;
-    if (InnerViewTable::ViewVector* views = innerViews.maybeViewsUnbarriered(this)) {
+    if (InnerViewTable::ViewVector* views = cx->compartment()->innerViews.maybeViewsUnbarriered(this)) {
         for (size_t i = 0; i < views->length(); i++)
             changeViewContents(cx, (*views)[i], oldDataPointer, newContents);
     }
     if (firstView())
         changeViewContents(cx, firstView(), oldDataPointer, newContents);
 }
 
 #ifdef ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB
@@ -852,17 +850,17 @@ ArrayBufferObject::addView(JSContext* cx
     // inherit from ArrayBufferViewObject so won't be upcast automatically.
     MOZ_ASSERT(viewArg->is<ArrayBufferViewObject>() || viewArg->is<TypedObject>());
     ArrayBufferViewObject* view = static_cast<ArrayBufferViewObject*>(viewArg);
 
     if (!firstView()) {
         setFirstView(view);
         return true;
     }
-    return cx->compartment()->innerViews.get().addView(cx, this, view);
+    return cx->compartment()->innerViews.addView(cx, this, view);
 }
 
 /*
  * InnerViewTable
  */
 
 static size_t VIEW_LIST_MAX_LENGTH = 500;
 
--- a/js/src/vm/ArrayBufferObject.h
+++ b/js/src/vm/ArrayBufferObject.h
@@ -495,17 +495,16 @@ template<> inline bool TypeIsUnsigned<ui
 // Per-compartment table that manages the relationship between array buffers
 // and the views that use their storage.
 class InnerViewTable
 {
   public:
     typedef Vector<ArrayBufferViewObject*, 1, SystemAllocPolicy> ViewVector;
 
     friend class ArrayBufferObject;
-    friend class WeakCacheBase<InnerViewTable>;
 
   private:
     struct MapGCPolicy {
         static bool needsSweep(JSObject** key, ViewVector* value) {
             return InnerViewTable::sweepEntry(key, *value);
         }
     };
 
@@ -549,45 +548,23 @@ class InnerViewTable
       : nurseryKeysValid(true)
     {}
 
     // Remove references to dead objects in the table and update table entries
     // to reflect moved objects.
     void sweep();
     void sweepAfterMinorGC();
 
-    bool needsSweepAfterMinorGC() const {
+    bool needsSweepAfterMinorGC() {
         return !nurseryKeys.empty() || !nurseryKeysValid;
     }
 
     size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf);
 };
 
-template <>
-class WeakCacheBase<InnerViewTable>
-{
-    InnerViewTable& table() {
-        return static_cast<JS::WeakCache<InnerViewTable>*>(this)->get();
-    }
-    const InnerViewTable& table() const {
-        return static_cast<const JS::WeakCache<InnerViewTable>*>(this)->get();
-    }
-
-  public:
-    InnerViewTable::ViewVector* maybeViewsUnbarriered(ArrayBufferObject* obj) {
-        return table().maybeViewsUnbarriered(obj);
-    }
-    void removeViews(ArrayBufferObject* obj) { table().removeViews(obj); }
-    void sweepAfterMinorGC() { table().sweepAfterMinorGC(); }
-    bool needsSweepAfterMinorGC() const { return table().needsSweepAfterMinorGC(); }
-    size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) {
-        return table().sizeOfExcludingThis(mallocSizeOf);
-    }
-};
-
 extern JSObject*
 InitArrayBufferClass(JSContext* cx, HandleObject obj);
 
 } // namespace js
 
 template <>
 bool
 JSObject::is<js::ArrayBufferViewObject>() const;
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -1482,26 +1482,16 @@ public:
   nsIntRegion mRegionToInvalidate;
 
   // The offset between the active scrolled root of this layer
   // and the root of the container for the previous and current
   // paints respectively.
   nsPoint mLastAnimatedGeometryRootOrigin;
   nsPoint mAnimatedGeometryRootOrigin;
 
-  // If mIgnoreInvalidationsOutsideRect is set, this contains the bounds of the
-  // layer's old visible region, in layer pixels.
-  nsIntRect mOldVisibleBounds;
-
-  // If set, invalidations that fall outside of this rect should not result in
-  // calls to layer->InvalidateRegion during DLBI. Instead, the parts outside
-  // this rectangle will be invalidated in InvalidateVisibleBoundsChangesForScrolledLayer.
-  // See the comment in ComputeAndSetIgnoreInvalidationRect for more information.
-  Maybe<nsIntRect> mIgnoreInvalidationsOutsideRect;
-
   RefPtr<ColorLayer> mColorLayer;
   RefPtr<ImageLayer> mImageLayer;
 
   // The region for which display item visibility for this layer has already
   // been calculated. Used to reduce the number of calls to
   // RecomputeVisibilityForItems if it is known in advance that a larger
   // region will be painted during a transaction than in a single call to
   // DrawPaintedLayer, for example when progressive paint is enabled.
@@ -1640,53 +1630,47 @@ AppendToString(nsACString& s, const nsIn
   return s += sfx;
 }
 
 /**
  * Invalidate aRegion in aLayer. aLayer is in the coordinate system
  * *after* aTranslation has been applied, so we need to
  * apply the inverse of that transform before calling InvalidateRegion.
  */
-template<typename RegionOrRect> void
-InvalidatePostTransformRegion(PaintedLayer* aLayer, const RegionOrRect& aRegion,
-                              const nsIntPoint& aTranslation,
-                              PaintedDisplayItemLayerUserData* aData)
+static void
+InvalidatePostTransformRegion(PaintedLayer* aLayer, const nsIntRegion& aRegion,
+                              const nsIntPoint& aTranslation)
 {
   // Convert the region from the coordinates of the container layer
   // (relative to the snapped top-left of the display list reference frame)
   // to the PaintedLayer's own coordinates
-  RegionOrRect rgn = aRegion;
+  nsIntRegion rgn = aRegion;
   rgn.MoveBy(-aTranslation);
-  if (aData->mIgnoreInvalidationsOutsideRect) {
-    rgn = rgn.Intersect(*aData->mIgnoreInvalidationsOutsideRect);
-  }
-  if (!rgn.IsEmpty()) {
-    aLayer->InvalidateRegion(rgn);
+  aLayer->InvalidateRegion(rgn);
 #ifdef MOZ_DUMP_PAINTING
-    if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
-      nsAutoCString str;
-      AppendToString(str, rgn);
-      printf_stderr("Invalidating layer %p: %s\n", aLayer, str.get());
-    }
+  if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
+    nsAutoCString str;
+    AppendToString(str, rgn);
+    printf_stderr("Invalidating layer %p: %s\n", aLayer, str.get());
+  }
 #endif
-  }
 }
 
 static void
 InvalidatePostTransformRegion(PaintedLayer* aLayer, const nsRect& aRect,
                               const DisplayItemClip& aClip,
                               const nsIntPoint& aTranslation)
 {
   PaintedDisplayItemLayerUserData* data =
       static_cast<PaintedDisplayItemLayerUserData*>(aLayer->GetUserData(&gPaintedDisplayItemLayerUserData));
 
   nsRect rect = aClip.ApplyNonRoundedIntersection(aRect);
 
   nsIntRect pixelRect = rect.ScaleToOutsidePixels(data->mXScale, data->mYScale, data->mAppUnitsPerDevPixel);
-  InvalidatePostTransformRegion(aLayer, pixelRect, aTranslation, data);
+  InvalidatePostTransformRegion(aLayer, pixelRect, aTranslation);
 }
 
 
 static nsIntPoint
 GetTranslationForPaintedLayer(PaintedLayer* aLayer)
 {
   PaintedDisplayItemLayerUserData* data =
     static_cast<PaintedDisplayItemLayerUserData*>
@@ -2235,99 +2219,16 @@ ContainerState::RecyclePaintedLayer(Pain
       printf_stderr("Invalidating layer %p: %s\n", aLayer, str.get());
     }
 #endif
     data->mRegionToInvalidate.SetEmpty();
   }
   return data;
 }
 
-static void
-ComputeAndSetIgnoreInvalidationRect(PaintedLayer* aLayer,
-                                    PaintedDisplayItemLayerUserData* aData,
-                                    AnimatedGeometryRoot* aAnimatedGeometryRoot,
-                                    nsDisplayListBuilder* aBuilder,
-                                    const nsIntPoint& aLayerTranslation)
-{
-  if (!aLayer->Manager()->IsWidgetLayerManager()) {
-    // This optimization is only useful for layers with retained content.
-    return;
-  }
-
-  const nsIFrame* parentFrame = (*aAnimatedGeometryRoot)->GetParent();
-
-  // GetDirtyRectForScrolledContents will return an empty rect if parentFrame
-  // is not a scrollable frame.
-  nsRect dirtyRect = aBuilder->GetDirtyRectForScrolledContents(parentFrame);
-
-  if (dirtyRect.IsEmpty()) {
-    // parentFrame is not a scrollable frame, or we didn't encounter it during
-    // display list building (though this shouldn't happen), or it's empty.
-    // In all those cases this optimization is not needed.
-    return;
-  }
-
-  // parentFrame is a scrollable frame, and aLayer contains the scrolled
-  // contents of that frame.
-
-  // maxNewVisibleBounds is a conservative approximation of the new visible
-  // region of aLayer.
-  nsIntRect maxNewVisibleBounds =
-    dirtyRect.ScaleToOutsidePixels(aData->mXScale, aData->mYScale,
-                                   aData->mAppUnitsPerDevPixel) - aLayerTranslation;
-  aData->mOldVisibleBounds = aLayer->GetVisibleRegion().ToUnknownRegion().GetBounds();
-
-  // When the visible region of aLayer changes (e.g. due to scrolling),
-  // three distinct types of invalidations need to be triggered:
-  //  (1) Items (or parts of items) that have left the visible region need
-  //      to be invalidated so that the pixels they painted are no longer
-  //      part of the layer's valid region.
-  //  (2) Items (or parts of items) that weren't in the old visible region
-  //      but are in the new visible region need to be invalidated. This
-  //      invalidation isn't required for painting the right layer
-  //      contents, because these items weren't part of the layer's valid
-  //      region, so they'd be painted anyway. It is, however, necessary in
-  //      order to get an accurate invalid region for the layer tree that
-  //      aLayer is in, for example for partial compositing.
-  //  (3) Any changes that happened in the intersection of the old and the
-  //      new visible region need to be invalidated. There shouldn't be any
-  //      of these when scrolling static content.
-  //
-  // We'd like to guarantee that we won't invalidate anything in the
-  // intersection area of the old and the new visible region if all
-  // invalidation are of type (1) and (2). However, if we just call
-  // aLayer->InvalidateRegion for the invalidations of type (1) and (2),
-  // at some point we'll hit the complexity limit of the layer's invalid
-  // region. And the resulting region simplification can cause the region
-  // to intersect with the intersection of the old and the new visible
-  // region.
-  // In order to get around this problem, we're using the following approach:
-  //  - aData->mIgnoreInvalidationsOutsideRect is set to a conservative
-  //    approximation of the intersection of the old and the new visible
-  //    region. At this point we don't know the layer's new visible region.
-  //  - As long as we don't know the layer's new visible region, we ignore all
-  //    invalidations outside that rectangle, so roughly some of the
-  //    invalidations of type (1) and (2).
-  //  - Once we know the layer's new visible region, which happens at some
-  //    point during PostprocessRetainedLayers, we invalidate a conservative
-  //    approximation of (1) and (2). Specifically, we invalidate the region
-  //    union of the old visible bounds and the new visible bounds, minus
-  //    aData->mIgnoreInvalidationsOutsideRect. That region is simple enough
-  //    that it will never be simplified on its own.
-  //    We unset mIgnoreInvalidationsOutsideRect at this point.
-  //  - Any other invalidations that happen on the layer after this point, e.g.
-  //    during WillEndTransaction, will just happen regularly. If they are of
-  //    type (1) or (2), they won't change the layer's invalid region because
-  //    they fall inside the region we invalidated in the previous step.
-  // Consequently, aData->mIgnoreInvalidationsOutsideRect is safe from
-  // invalidations as long as there are no invalidations of type (3).
-  aData->mIgnoreInvalidationsOutsideRect =
-    Some(maxNewVisibleBounds.Intersect(aData->mOldVisibleBounds));
-}
-
 void
 ContainerState::PreparePaintedLayerForUse(PaintedLayer* aLayer,
                                           PaintedDisplayItemLayerUserData* aData,
                                           AnimatedGeometryRoot* aAnimatedGeometryRoot,
                                           const nsIFrame* aReferenceFrame,
                                           const nsPoint& aTopLeft,
                                           bool didResetScrollPositionForLayerPixelAlignment)
 {
@@ -2351,18 +2252,16 @@ ContainerState::PreparePaintedLayerForUs
   // is close to aData->mAnimatedGeometryRootPosition if possible.
   nsIntPoint pixOffset(RoundToMatchResidual(scaledOffset.x, aData->mAnimatedGeometryRootPosition.x),
                        RoundToMatchResidual(scaledOffset.y, aData->mAnimatedGeometryRootPosition.y));
   aData->mTranslation = pixOffset;
   pixOffset += mParameters.mOffset;
   Matrix matrix = Matrix::Translation(pixOffset.x, pixOffset.y);
   aLayer->SetBaseTransform(Matrix4x4::From2D(matrix));
 
-  ComputeAndSetIgnoreInvalidationRect(aLayer, aData, aAnimatedGeometryRoot, mBuilder, pixOffset);
-
   aData->mVisibilityComputedRegion.SetEmpty();
 
   // FIXME: Temporary workaround for bug 681192 and bug 724786.
 #ifndef MOZ_WIDGET_ANDROID
   // Calculate exact position of the top-left of the active scrolled root.
   // This might not be 0,0 due to the snapping in ScaleToNearestPixels.
   gfxPoint animatedGeometryRootTopLeft = scaledOffset - ThebesPoint(matrix.GetTranslation()) + mParameters.mOffset;
   // If it has changed, then we need to invalidate the entire layer since the
@@ -4377,18 +4276,17 @@ FrameLayerBuilder::ComputeGeometryChange
 #endif
   }
   if (!combined.IsEmpty()) {
     if (notifyRenderingChanged) {
       item->NotifyRenderingChanged();
     }
     InvalidatePostTransformRegion(paintedLayer,
         combined.ScaleToOutsidePixels(layerData->mXScale, layerData->mYScale, layerData->mAppUnitsPerDevPixel),
-        layerData->mTranslation,
-        layerData);
+        layerData->mTranslation);
   }
 
   aData->EndUpdate(geometry);
 }
 
 void
 FrameLayerBuilder::AddPaintedDisplayItem(PaintedLayerData* aLayerData,
                                         nsDisplayItem* aItem,
@@ -4507,18 +4405,17 @@ FrameLayerBuilder::AddPaintedDisplayItem
 #endif
         invalid.ScaleRoundOut(paintedData->mXScale, paintedData->mYScale);
 
         if (hasClip) {
           invalid.And(invalid, intClip);
         }
 
         InvalidatePostTransformRegion(layer, invalid,
-                                      GetTranslationForPaintedLayer(layer),
-                                      paintedData);
+                                      GetTranslationForPaintedLayer(layer));
       }
     }
     ClippedDisplayItem* cdi =
       entry->mItems.AppendElement(ClippedDisplayItem(aItem,
                                                      mContainerLayerGeneration));
     cdi->mInactiveLayerManager = tempManager;
   }
 }
@@ -4770,49 +4667,16 @@ ContainerState::SetupScrollingMetadata(N
     metricsArray.AppendElement(*metadata);
   }
 
   // Watch out for FrameMetrics copies in profiles
   aEntry->mLayer->SetScrollMetadata(metricsArray);
   aEntry->mLayer->SetAncestorMaskLayers(maskLayers);
 }
 
-static void
-InvalidateVisibleBoundsChangesForScrolledLayer(PaintedLayer* aLayer)
-{
-  PaintedDisplayItemLayerUserData* data =
-    static_cast<PaintedDisplayItemLayerUserData*>(aLayer->GetUserData(&gPaintedDisplayItemLayerUserData));
-
-  if (data->mIgnoreInvalidationsOutsideRect) {
-    // We haven't invalidated anything outside *data->mIgnoreInvalidationsOutsideRect
-    // during DLBI. Now is the right time to do that, because at this point aLayer
-    // knows its new visible region.
-    // We use the visible regions' bounds here (as opposed to the true region)
-    // in order to limit rgn's complexity. The only possible disadvantage of
-    // this is that it might cause us to unnecessarily recomposite parts of the
-    // window that are in the visible region's bounds but not in the visible
-    // region itself, but that is acceptable for scrolled layers.
-    nsIntRegion rgn;
-    rgn.Or(data->mOldVisibleBounds, aLayer->GetVisibleRegion().ToUnknownRegion().GetBounds());
-    rgn.Sub(rgn, *data->mIgnoreInvalidationsOutsideRect);
-    if (!rgn.IsEmpty()) {
-      aLayer->InvalidateRegion(rgn);
-#ifdef MOZ_DUMP_PAINTING
-      if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
-        printf_stderr("Invalidating changes of the visible region bounds of the scrolled contents\n");
-        nsAutoCString str;
-        AppendToString(str, rgn);
-        printf_stderr("Invalidating layer %p: %s\n", aLayer, str.get());
-      }
-#endif
-    }
-    data->mIgnoreInvalidationsOutsideRect = Nothing();
-  }
-}
-
 static inline const Maybe<ParentLayerIntRect>&
 GetStationaryClipInContainer(Layer* aLayer)
 {
   if (size_t metricsCount = aLayer->GetScrollMetadataCount()) {
     return aLayer->GetScrollMetadata(metricsCount - 1).GetClipRect();
   }
   return aLayer->GetClipRect();
 }
@@ -4851,21 +4715,16 @@ ContainerState::PostprocessRetainedLayer
       }
     }
 
     SetOuterVisibleRegionForLayer(e->mLayer,
                                   e->mVisibleRegion,
                                   e->mLayerContentsVisibleRect.width >= 0 ? &e->mLayerContentsVisibleRect : nullptr,
                                   e->mUntransformedVisibleRegion);
 
-    PaintedLayer* p = e->mLayer->AsPaintedLayer();
-    if (p) {
-      InvalidateVisibleBoundsChangesForScrolledLayer(p);
-    }
-
     if (!e->mOpaqueRegion.IsEmpty()) {
       AnimatedGeometryRoot* animatedGeometryRootToCover = animatedGeometryRootForOpaqueness;
       if (e->mOpaqueForAnimatedGeometryRootParent &&
           e->mAnimatedGeometryRoot->mParentAGR == mContainerAnimatedGeometryRoot) {
         animatedGeometryRootToCover = mContainerAnimatedGeometryRoot;
         data = FindOpaqueRegionEntry(opaqueRegions, animatedGeometryRootToCover);
       }
 
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -1428,34 +1428,16 @@ nsDisplayListBuilder::ExitSVGEffectsCont
 void
 nsDisplayListBuilder::AppendNewScrollInfoItemForHoisting(nsDisplayScrollInfoLayer* aScrollInfoItem)
 {
   MOZ_ASSERT(ShouldBuildScrollInfoItemsForHoisting());
   MOZ_ASSERT(mScrollInfoItemsForHoisting);
   mScrollInfoItemsForHoisting->AppendNewToTop(aScrollInfoItem);
 }
 
-void
-nsDisplayListBuilder::StoreDirtyRectForScrolledContents(const nsIFrame* aScrollableFrame,
-                                                        const nsRect& aDirty)
-{
-  mDirtyRectForScrolledContents.Put(const_cast<nsIFrame*>(aScrollableFrame),
-                                    aDirty + ToReferenceFrame(aScrollableFrame));
-}
-
-nsRect
-nsDisplayListBuilder::GetDirtyRectForScrolledContents(const nsIFrame* aScrollableFrame) const
-{
-  nsRect result;
-  if (!mDirtyRectForScrolledContents.Get(const_cast<nsIFrame*>(aScrollableFrame), &result)) {
-    return nsRect();
-  }
-  return result;
-}
-
 bool
 nsDisplayListBuilder::IsBuildingLayerEventRegions()
 {
   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() ||
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -1065,32 +1065,16 @@ public:
   void ExitSVGEffectsContents();
 
   bool ShouldBuildScrollInfoItemsForHoisting() const
   { return mSVGEffectsBuildingDepth > 0; }
 
   void AppendNewScrollInfoItemForHoisting(nsDisplayScrollInfoLayer* aScrollInfoItem);
 
   /**
-   * Store the dirty rect of the scrolled contents of aScrollableFrame. This
-   * is a bound for the extents of the new visible region of the scrolled
-   * layer.
-   * @param aScrollableFrame the scrollable frame
-   * @param aDirty           the dirty rect, relative to aScrollableFrame
-   */
-  void StoreDirtyRectForScrolledContents(const nsIFrame* aScrollableFrame, const nsRect& aDirty);
-
-  /**
-   * Retrieve the stored dirty rect for the scrolled contents of aScrollableFrame.
-   * @param  aScrollableFrame the scroll frame
-   * @return                  the dirty rect, relative to aScrollableFrame's *reference frame*
-   */
-  nsRect GetDirtyRectForScrolledContents(const nsIFrame* aScrollableFrame) const;
-
-  /**
    * A helper class to install/restore nsDisplayListBuilder::mPreserves3DCtx.
    *
    * mPreserves3DCtx is used by class AutoAccumulateTransform &
    * AutoAccumulateRect to passing data between frames in the 3D
    * context.  If a frame create a new 3D context, it should restore
    * the value of mPreserves3DCtx before returning back to the parent.
    * This class do it for the users.
    */
@@ -1216,19 +1200,16 @@ private:
   // and thus is in-budget.
   nsTHashtable<nsPtrHashKey<nsIFrame> > mWillChangeBudgetSet;
 
   // Area of animated geometry root budget already allocated
   uint32_t mUsedAGRBudget;
   // Set of frames already counted in budget
   nsTHashtable<nsPtrHashKey<nsIFrame> > mAGRBudgetSet;
 
-  // rects are relative to the frame's reference frame
-  nsDataHashtable<nsPtrHashKey<nsIFrame>, nsRect> mDirtyRectForScrolledContents;
-
   // Relative to mCurrentFrame.
   nsRect                         mDirtyRect;
   nsRegion                       mWindowExcludeGlassRegion;
   nsRegion                       mWindowOpaqueRegion;
   LayoutDeviceIntRegion          mWindowDraggingRegion;
   LayoutDeviceIntRegion          mWindowNoDraggingRegion;
   // The display item for the Windows window glass background, if any
   nsDisplayItem*                 mGlassDisplayItem;
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -1213,25 +1213,25 @@ nsLayoutUtils::SetDisplayPortMargins(nsI
 
   DisplayPortMarginsPropertyData* currentData =
     static_cast<DisplayPortMarginsPropertyData*>(aContent->GetProperty(nsGkAtoms::DisplayPortMargins));
   if (currentData && currentData->mPriority > aPriority) {
     return false;
   }
 
   nsRect oldDisplayPort;
-  bool hadDisplayPort = GetDisplayPort(aContent, &oldDisplayPort);
+  bool hadDisplayPort = GetHighResolutionDisplayPort(aContent, &oldDisplayPort);
 
   aContent->SetProperty(nsGkAtoms::DisplayPortMargins,
                         new DisplayPortMarginsPropertyData(
                             aMargins, aPriority),
                         nsINode::DeleteProperty<DisplayPortMarginsPropertyData>);
 
   nsRect newDisplayPort;
-  DebugOnly<bool> hasDisplayPort = GetDisplayPort(aContent, &newDisplayPort);
+  DebugOnly<bool> hasDisplayPort = GetHighResolutionDisplayPort(aContent, &newDisplayPort);
   MOZ_ASSERT(hasDisplayPort);
 
   bool changed = !hadDisplayPort ||
         !oldDisplayPort.IsEqualEdges(newDisplayPort);
 
   if (gfxPrefs::LayoutUseContainersForRootFrames()) {
     nsIFrame* rootScrollFrame = aPresShell->GetRootScrollFrame();
     if (rootScrollFrame &&
@@ -1319,16 +1319,25 @@ nsLayoutUtils::GetCriticalDisplayPort(ns
 }
 
 bool
 nsLayoutUtils::HasCriticalDisplayPort(nsIContent* aContent)
 {
   return GetCriticalDisplayPort(aContent, nullptr);
 }
 
+bool
+nsLayoutUtils::GetHighResolutionDisplayPort(nsIContent* aContent, nsRect* aResult)
+{
+  if (gfxPrefs::UseLowPrecisionBuffer()) {
+    return GetCriticalDisplayPort(aContent, aResult);
+  }
+  return GetDisplayPort(aContent, aResult);
+}
+
 void
 nsLayoutUtils::RemoveDisplayPort(nsIContent* aContent)
 {
   aContent->DeleteProperty(nsGkAtoms::DisplayPort);
   aContent->DeleteProperty(nsGkAtoms::DisplayPortMargins);
 }
 
 nsContainerFrame*
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -249,16 +249,22 @@ public:
   static bool GetCriticalDisplayPort(nsIContent* aContent, nsRect* aResult);
 
   /**
    * Check whether the given element has a critical display port.
    */
   static bool HasCriticalDisplayPort(nsIContent* aContent);
 
   /**
+   * If low-precision painting is turned on, delegates to GetCriticalDisplayPort.
+   * Otherwise, delegates to GetDisplayPort.
+   */
+  static bool GetHighResolutionDisplayPort(nsIContent* aContent, nsRect* aResult);
+
+  /**
    * Remove the displayport for the given element.
    */
   static void RemoveDisplayPort(nsIContent* aContent);
 
   /**
    * Use heuristics to figure out the child list that
    * aChildFrame is currently in.
    */
--- a/layout/base/tests/test_transformed_scrolling_repaints.html
+++ b/layout/base/tests/test_transformed_scrolling_repaints.html
@@ -2,20 +2,20 @@
 <html>
 <head>
   <title>Test that scaled elements with scrolled contents don't repaint unnecessarily when we scroll inside them</title>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <script type="text/javascript" src="/tests/SimpleTest/paint_listener.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 </head>
 <body onload="setPrefAndStartTest()">
-<div id="t" style="-moz-transform: scale(1.2, 1.2); -moz-transform-origin:top left; width:200px; height:100px; background:yellow; overflow:hidden">
+<div id="t" style="-moz-transform: scale(1.2, 1.2); -moz-transform-origin:top left; width:200px; height:500px; background:yellow; overflow:auto">
   <div style="height:40px;">Hello</div>
   <div id="e" style="height:30px; background:lime">Kitty</div>
-  <div style="height:300px; background:yellow">Kitty</div>
+  <div style="height:800px; background:yellow">Kitty</div>
 </div>
 <pre id="test">
 <script type="application/javascript">
 SimpleTest.waitForExplicitFinish();
 
 var t = document.getElementById("t");
 var e = document.getElementById("e");
 var utils = SpecialPowers.getDOMWindowUtils(window);
--- a/layout/base/tests/transformed_scrolling_repaints_3_window.html
+++ b/layout/base/tests/transformed_scrolling_repaints_3_window.html
@@ -1,17 +1,17 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <title>Test that scaled elements with scrolled contents don't repaint unnecessarily when we scroll inside them</title>
   <script type="text/javascript" src="/tests/SimpleTest/paint_listener.js"></script>
 </head>
 <!-- Need a timeout here to allow paint unsuppression before we start the test -->
 <body onload="setTimeout(startTest,0)" style="background:white;">
-<iframe id="t" style="-moz-transform: scale(0.48979); -moz-transform-origin:top left; width:500px; height:300px;"
+<iframe id="t" style="-moz-transform: scale(0.48979); -moz-transform-origin:top left; width:500px; height:600px;"
         src="data:text/html,
 <body style='background:yellow;'>
 <p>My graduate adviser was the most patient, understanding, and helpful
 person I've ever had the joy of dealing with. That doesn't change that 
 there are some real dicks out there, and some of them happen to be 
 scientists.
 <p id='e'>My graduate adviser was the most patient, understanding, and helpful
 person I've ever had the joy of dealing with. That doesn't change that 
@@ -28,16 +28,48 @@ scientists.
 <p>My graduate adviser was the most patient, understanding, and helpful
 person I've ever had the joy of dealing with. That doesn't change that 
 there are some real dicks out there, and some of them happen to be 
 scientists.
 <p>My graduate adviser was the most patient, understanding, and helpful
 person I've ever had the joy of dealing with. That doesn't change that 
 there are some real dicks out there, and some of them happen to be 
 scientists.
+<p>My graduate adviser was the most patient, understanding, and helpful
+person I've ever had the joy of dealing with. That doesn't change that 
+there are some real dicks out there, and some of them happen to be 
+scientists.
+<p>My graduate adviser was the most patient, understanding, and helpful
+person I've ever had the joy of dealing with. That doesn't change that 
+there are some real dicks out there, and some of them happen to be 
+scientists.
+<p>My graduate adviser was the most patient, understanding, and helpful
+person I've ever had the joy of dealing with. That doesn't change that 
+there are some real dicks out there, and some of them happen to be 
+scientists.
+<p>My graduate adviser was the most patient, understanding, and helpful
+person I've ever had the joy of dealing with. That doesn't change that 
+there are some real dicks out there, and some of them happen to be 
+scientists.
+<p>My graduate adviser was the most patient, understanding, and helpful
+person I've ever had the joy of dealing with. That doesn't change that 
+there are some real dicks out there, and some of them happen to be 
+scientists.
+<p>My graduate adviser was the most patient, understanding, and helpful
+person I've ever had the joy of dealing with. That doesn't change that 
+there are some real dicks out there, and some of them happen to be 
+scientists.
+<p>My graduate adviser was the most patient, understanding, and helpful
+person I've ever had the joy of dealing with. That doesn't change that 
+there are some real dicks out there, and some of them happen to be 
+scientists.
+<p>My graduate adviser was the most patient, understanding, and helpful
+person I've ever had the joy of dealing with. That doesn't change that 
+there are some real dicks out there, and some of them happen to be 
+scientists.
 </body>"></iframe>
 <pre id="test">
 <script type="application/javascript">
 var SimpleTest = window.opener.SimpleTest;
 var SpecialPowers = window.opener.SpecialPowers;
 var is = window.opener.is;
 var t, e, utils, iterations;
 var smoothScrollPref = "general.smoothScroll";
--- a/layout/forms/nsColorControlFrame.cpp
+++ b/layout/forms/nsColorControlFrame.cpp
@@ -15,40 +15,40 @@
 #include "nsIDOMNode.h"
 #include "nsIFormControl.h"
 #include "mozilla/StyleSetHandle.h"
 #include "mozilla/StyleSetHandleInlines.h"
 #include "nsIDocument.h"
 
 using mozilla::dom::Element;
 
-nsColorControlFrame::nsColorControlFrame(nsStyleContext* aContext):
-  nsColorControlFrameSuper(aContext)
+nsColorControlFrame::nsColorControlFrame(nsStyleContext* aContext)
+  : nsHTMLButtonControlFrame(aContext)
 {
 }
 
 nsIFrame*
 NS_NewColorControlFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
   return new (aPresShell) nsColorControlFrame(aContext);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsColorControlFrame)
 
 NS_QUERYFRAME_HEAD(nsColorControlFrame)
   NS_QUERYFRAME_ENTRY(nsColorControlFrame)
   NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator)
-NS_QUERYFRAME_TAIL_INHERITING(nsColorControlFrameSuper)
+NS_QUERYFRAME_TAIL_INHERITING(nsHTMLButtonControlFrame)
 
 
 void nsColorControlFrame::DestroyFrom(nsIFrame* aDestructRoot)
 {
   nsFormControlFrame::RegUnRegAccessKey(static_cast<nsIFrame*>(this), false);
   nsContentUtils::DestroyAnonymousContent(&mColorContent);
-  nsColorControlFrameSuper::DestroyFrom(aDestructRoot);
+  nsHTMLButtonControlFrame::DestroyFrom(aDestructRoot);
 }
 
 nsIAtom*
 nsColorControlFrame::GetType() const
 {
   return nsGkAtoms::colorControlFrame;
 }
 
@@ -121,17 +121,17 @@ nsColorControlFrame::AttributeChanged(in
   // If the value attribute is set, update the color box, but only if we're
   // still a color control, which might not be the case if the type attribute
   // was removed/changed.
   nsCOMPtr<nsIFormControl> fctrl = do_QueryInterface(GetContent());
   if (fctrl->GetType() == NS_FORM_INPUT_COLOR &&
       aNameSpaceID == kNameSpaceID_None && nsGkAtoms::value == aAttribute) {
     UpdateColor();
   }
-  return nsColorControlFrameSuper::AttributeChanged(aNameSpaceID, aAttribute,
+  return nsHTMLButtonControlFrame::AttributeChanged(aNameSpaceID, aAttribute,
                                                     aModType);
 }
 
 nsContainerFrame*
 nsColorControlFrame::GetContentInsertionFrame()
 {
   return this;
 }
--- a/layout/forms/nsColorControlFrame.h
+++ b/layout/forms/nsColorControlFrame.h
@@ -9,21 +9,19 @@
 #include "nsCOMPtr.h"
 #include "nsHTMLButtonControlFrame.h"
 #include "nsIAnonymousContentCreator.h"
 
 namespace mozilla {
 enum class CSSPseudoElementType : uint8_t;
 } // namespace mozilla
 
-typedef nsHTMLButtonControlFrame nsColorControlFrameSuper;
-
 // Class which implements the input type=color
 
-class nsColorControlFrame final : public nsColorControlFrameSuper,
+class nsColorControlFrame final : public nsHTMLButtonControlFrame,
                                   public nsIAnonymousContentCreator
 {
   typedef mozilla::CSSPseudoElementType CSSPseudoElementType;
   typedef mozilla::dom::Element Element;
 
 public:
   friend nsIFrame* NS_NewColorControlFrame(nsIPresShell* aPresShell,
                                            nsStyleContext* aContext);
--- a/layout/forms/nsFormControlFrame.cpp
+++ b/layout/forms/nsFormControlFrame.cpp
@@ -12,42 +12,42 @@
 #include "mozilla/LookAndFeel.h"
 #include "nsDeviceContext.h"
 #include "nsIContent.h"
 
 using namespace mozilla;
 
 //#define FCF_NOISY
 
-nsFormControlFrame::nsFormControlFrame(nsStyleContext* aContext) :
-  nsFormControlFrameSuper(aContext)
+nsFormControlFrame::nsFormControlFrame(nsStyleContext* aContext)
+  : nsAtomicContainerFrame(aContext)
 {
 }
 
 nsFormControlFrame::~nsFormControlFrame()
 {
 }
 
 nsIAtom*
 nsFormControlFrame::GetType() const
 {
-  return nsGkAtoms::formControlFrame; 
+  return nsGkAtoms::formControlFrame;
 }
 
 void
 nsFormControlFrame::DestroyFrom(nsIFrame* aDestructRoot)
 {
   // Unregister the access key registered in reflow
   nsFormControlFrame::RegUnRegAccessKey(static_cast<nsIFrame*>(this), false);
-  nsFormControlFrameSuper::DestroyFrom(aDestructRoot);
+  nsAtomicContainerFrame::DestroyFrom(aDestructRoot);
 }
 
 NS_QUERYFRAME_HEAD(nsFormControlFrame)
   NS_QUERYFRAME_ENTRY(nsIFormControlFrame)
-NS_QUERYFRAME_TAIL_INHERITING(nsFormControlFrameSuper)
+NS_QUERYFRAME_TAIL_INHERITING(nsAtomicContainerFrame)
 
 /* virtual */ nscoord
 nsFormControlFrame::GetMinISize(nsRenderingContext *aRenderingContext)
 {
   nscoord result;
   DISPLAY_MIN_WIDTH(this, result);
   result = GetIntrinsicISize();
   return result;
--- a/layout/forms/nsFormControlFrame.h
+++ b/layout/forms/nsFormControlFrame.h
@@ -6,39 +6,37 @@
 #ifndef nsFormControlFrame_h___
 #define nsFormControlFrame_h___
 
 #include "mozilla/Attributes.h"
 #include "nsIFormControlFrame.h"
 #include "nsAtomicContainerFrame.h"
 #include "nsDisplayList.h"
 
-typedef nsAtomicContainerFrame nsFormControlFrameSuper;
-
-/** 
+/**
  * nsFormControlFrame is the base class for radio buttons and
  * checkboxes.  It also has two static methods (RegUnRegAccessKey and
  * GetScreenHeight) that are used by other form controls.
  */
-class nsFormControlFrame : public nsFormControlFrameSuper,
+class nsFormControlFrame : public nsAtomicContainerFrame,
                            public nsIFormControlFrame
 {
 public:
   /**
     * Main constructor
     * @param aContent the content representing this frame
     * @param aParentFrame the parent frame
     */
   explicit nsFormControlFrame(nsStyleContext*);
 
   virtual nsIAtom* GetType() const override;
 
   virtual bool IsFrameOfType(uint32_t aFlags) const override
   {
-    return nsFormControlFrameSuper::IsFrameOfType(aFlags &
+    return nsAtomicContainerFrame::IsFrameOfType(aFlags &
       ~(nsIFrame::eReplaced | nsIFrame::eReplacedContainsBlock));
   }
 
   NS_DECL_QUERYFRAME
   NS_DECL_ABSTRACT_FRAME(nsFormControlFrame)
 
   // nsIFrame replacements
   virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
@@ -63,21 +61,21 @@ public:
                   mozilla::WritingMode aWritingMode,
                   const mozilla::LogicalSize& aCBSize,
                   nscoord aAvailableISize,
                   const mozilla::LogicalSize& aMargin,
                   const mozilla::LogicalSize& aBorder,
                   const mozilla::LogicalSize& aPadding,
                   bool aShrinkWrap) override;
 
-  /** 
+  /**
     * Respond to a gui event
     * @see nsIFrame::HandleEvent
     */
-  virtual nsresult HandleEvent(nsPresContext* aPresContext, 
+  virtual nsresult HandleEvent(nsPresContext* aPresContext,
                                mozilla::WidgetGUIEvent* aEvent,
                                nsEventStatus* aEventStatus) override;
 
   virtual nscoord GetLogicalBaseline(mozilla::WritingMode aWritingMode)
     const override;
 
   /**
     * Respond to the request to resize and/or reflow
@@ -112,17 +110,17 @@ protected:
 
   nscoord GetIntrinsicISize();
   nscoord GetIntrinsicBSize();
 
 //
 //-------------------------------------------------------------------------------------
 //  Utility methods for managing checkboxes and radiobuttons
 //-------------------------------------------------------------------------------------
-//   
+//
    /**
     * Get the state of the checked attribute.
     * @param aState set to true if the checked attribute is set,
     * false if the checked attribute has been removed
     */
 
   void GetCurrentCheckState(bool* aState);
 };
--- a/layout/forms/nsImageControlFrame.cpp
+++ b/layout/forms/nsImageControlFrame.cpp
@@ -10,18 +10,17 @@
 #include "nsStyleConsts.h"
 #include "nsFormControlFrame.h"
 #include "nsLayoutUtils.h"
 #include "mozilla/MouseEvents.h"
 #include "nsIContent.h"
 
 using namespace mozilla;
 
-typedef nsImageFrame nsImageControlFrameSuper;
-class nsImageControlFrame : public nsImageControlFrameSuper,
+class nsImageControlFrame : public nsImageFrame,
                             public nsIFormControlFrame
 {
 public:
   explicit nsImageControlFrame(nsStyleContext* aContext);
   ~nsImageControlFrame();
 
   virtual void DestroyFrom(nsIFrame* aDestructRoot) override;
   virtual void Init(nsIContent*       aContent,
@@ -51,100 +50,100 @@ public:
     return MakeFrameName(NS_LITERAL_STRING("ImageControl"), aResult);
   }
 #endif
 
   virtual nsresult GetCursor(const nsPoint&    aPoint,
                              nsIFrame::Cursor& aCursor) override;
   // nsIFormContromFrame
   virtual void SetFocus(bool aOn, bool aRepaint) override;
-  virtual nsresult SetFormProperty(nsIAtom* aName, 
+  virtual nsresult SetFormProperty(nsIAtom* aName,
                                    const nsAString& aValue) override;
 };
 
 
-nsImageControlFrame::nsImageControlFrame(nsStyleContext* aContext):
-  nsImageControlFrameSuper(aContext)
+nsImageControlFrame::nsImageControlFrame(nsStyleContext* aContext)
+  : nsImageFrame(aContext)
 {
 }
 
 nsImageControlFrame::~nsImageControlFrame()
 {
 }
 
 void
 nsImageControlFrame::DestroyFrom(nsIFrame* aDestructRoot)
 {
   if (!GetPrevInFlow()) {
     nsFormControlFrame::RegUnRegAccessKey(this, false);
   }
-  nsImageControlFrameSuper::DestroyFrom(aDestructRoot);
+  nsImageFrame::DestroyFrom(aDestructRoot);
 }
 
 nsIFrame*
 NS_NewImageControlFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
   return new (aPresShell) nsImageControlFrame(aContext);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsImageControlFrame)
 
 void
 nsImageControlFrame::Init(nsIContent*       aContent,
                           nsContainerFrame* aParent,
                           nsIFrame*         aPrevInFlow)
 {
-  nsImageControlFrameSuper::Init(aContent, aParent, aPrevInFlow);
+  nsImageFrame::Init(aContent, aParent, aPrevInFlow);
 
   if (aPrevInFlow) {
     return;
   }
-  
+
   mContent->SetProperty(nsGkAtoms::imageClickedPoint,
                         new nsIntPoint(0, 0),
                         nsINode::DeleteProperty<nsIntPoint>);
 }
 
 NS_QUERYFRAME_HEAD(nsImageControlFrame)
   NS_QUERYFRAME_ENTRY(nsIFormControlFrame)
-NS_QUERYFRAME_TAIL_INHERITING(nsImageControlFrameSuper)
+NS_QUERYFRAME_TAIL_INHERITING(nsImageFrame)
 
 #ifdef ACCESSIBILITY
 a11y::AccType
 nsImageControlFrame::AccessibleType()
 {
   if (mContent->IsAnyOfHTMLElements(nsGkAtoms::button, nsGkAtoms::input)) {
     return a11y::eHTMLButtonType;
   }
 
   return a11y::eNoType;
 }
 #endif
 
 nsIAtom*
 nsImageControlFrame::GetType() const
 {
-  return nsGkAtoms::imageControlFrame; 
+  return nsGkAtoms::imageControlFrame;
 }
 
 void
 nsImageControlFrame::Reflow(nsPresContext*           aPresContext,
                             nsHTMLReflowMetrics&     aDesiredSize,
                             const nsHTMLReflowState& aReflowState,
                             nsReflowStatus&          aStatus)
 {
   DO_GLOBAL_REFLOW_COUNT("nsImageControlFrame");
   DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
   if (!GetPrevInFlow() && (mState & NS_FRAME_FIRST_REFLOW)) {
     nsFormControlFrame::RegUnRegAccessKey(this, true);
   }
-  return nsImageControlFrameSuper::Reflow(aPresContext, aDesiredSize, aReflowState, aStatus);
+  return nsImageFrame::Reflow(aPresContext, aDesiredSize, aReflowState, aStatus);
 }
 
-nsresult 
+nsresult
 nsImageControlFrame::HandleEvent(nsPresContext* aPresContext,
                                  WidgetGUIEvent* aEvent,
                                  nsEventStatus* aEventStatus)
 {
   NS_ENSURE_ARG_POINTER(aEventStatus);
 
   // Don't do anything if the event has already been handled by someone
   if (nsEventStatus_eConsumeNoDefault == *aEventStatus) {
@@ -170,21 +169,20 @@ nsImageControlFrame::HandleEvent(nsPresC
       static_cast<nsIntPoint*>
                  (mContent->GetProperty(nsGkAtoms::imageClickedPoint));
     if (lastClickPoint) {
       // normally lastClickedPoint is not null, as it's allocated in Init()
       nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, this);
       TranslateEventCoords(pt, *lastClickPoint);
     }
   }
-  return nsImageControlFrameSuper::HandleEvent(aPresContext, aEvent,
-                                               aEventStatus);
+  return nsImageFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
 }
 
-void 
+void
 nsImageControlFrame::SetFocus(bool aOn, bool aRepaint)
 {
 }
 
 nsresult
 nsImageControlFrame::GetCursor(const nsPoint&    aPoint,
                                nsIFrame::Cursor& aCursor)
 {
--- a/layout/generic/nsFlexContainerFrame.cpp
+++ b/layout/generic/nsFlexContainerFrame.cpp
@@ -2025,17 +2025,17 @@ public:
 
 //----------------------------------------------------------------------
 
 // Frame class boilerplate
 // =======================
 
 NS_QUERYFRAME_HEAD(nsFlexContainerFrame)
   NS_QUERYFRAME_ENTRY(nsFlexContainerFrame)
-NS_QUERYFRAME_TAIL_INHERITING(nsFlexContainerFrameSuper)
+NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
 
 NS_IMPL_FRAMEARENA_HELPERS(nsFlexContainerFrame)
 
 nsContainerFrame*
 NS_NewFlexContainerFrame(nsIPresShell* aPresShell,
                          nsStyleContext* aContext)
 {
   return new (aPresShell) nsFlexContainerFrame(aContext);
--- a/layout/generic/nsFlexContainerFrame.h
+++ b/layout/generic/nsFlexContainerFrame.h
@@ -15,19 +15,17 @@
 namespace mozilla {
 template <class T> class LinkedList;
 class LogicalPoint;
 } // namespace mozilla
 
 nsContainerFrame* NS_NewFlexContainerFrame(nsIPresShell* aPresShell,
                                            nsStyleContext* aContext);
 
-typedef nsContainerFrame nsFlexContainerFrameSuper;
-
-class nsFlexContainerFrame : public nsFlexContainerFrameSuper {
+class nsFlexContainerFrame : public nsContainerFrame {
 public:
   NS_DECL_FRAMEARENA_HELPERS
   NS_DECL_QUERYFRAME_TARGET(nsFlexContainerFrame)
   NS_DECL_QUERYFRAME
 
   // Factory method:
   friend nsContainerFrame* NS_NewFlexContainerFrame(nsIPresShell* aPresShell,
                                                     nsStyleContext* aContext);
@@ -57,18 +55,18 @@ public:
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const override;
 #endif
   // Flexbox-specific public methods
   bool IsHorizontal();
 
 protected:
   // Protected constructor & destructor
-  explicit nsFlexContainerFrame(nsStyleContext* aContext) :
-    nsFlexContainerFrameSuper(aContext)
+  explicit nsFlexContainerFrame(nsStyleContext* aContext)
+    : nsContainerFrame(aContext)
   {}
   virtual ~nsFlexContainerFrame();
 
   /*
    * This method does the bulk of the flex layout, implementing the algorithm
    * described at:
    *   http://dev.w3.org/csswg/css-flexbox/#layout-algorithm
    * (with a few initialization pieces happening in the caller, Reflow().
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -2704,17 +2704,17 @@ ScrollFrameHelper::ScrollToImpl(nsPoint 
 
   // notify the listeners.
   for (uint32_t i = 0; i < mListeners.Length(); i++) {
     mListeners[i]->ScrollPositionWillChange(pt.x, pt.y);
   }
 
   nsRect oldDisplayPort;
   nsIContent* content = mOuter->GetContent();
-  nsLayoutUtils::GetDisplayPort(content, &oldDisplayPort);
+  nsLayoutUtils::GetHighResolutionDisplayPort(content, &oldDisplayPort);
   oldDisplayPort.MoveBy(-mScrolledFrame->GetPosition());
 
   // Update frame position for scrolling
   mScrolledFrame->SetPosition(mScrollPort.TopLeft() - pt);
   mLastScrollOrigin = aOrigin;
   mLastSmoothScrollOrigin = nullptr;
   mScrollGeneration = ++sScrollGenerationCounter;
 
@@ -2730,30 +2730,28 @@ ScrollFrameHelper::ScrollToImpl(nsPoint 
     //    APZ to update the scroll position. Again we make this conditional on
     //    the tile-aligned displayport being unchanged.
     // We do the displayport check first since it's common to all scenarios,
     // and then if the displayport is unchanged, we check if APZ triggered,
     // or can handle, this scroll. If so, we set schedulePaint to false and
     // skip the paint.
     nsRect displayPort;
     bool usingDisplayPort =
-      nsLayoutUtils::GetDisplayPort(content, &displayPort);
+      nsLayoutUtils::GetHighResolutionDisplayPort(content, &displayPort);
     displayPort.MoveBy(-mScrolledFrame->GetPosition());
 
-    PAINT_SKIP_LOG("New scrollpos %s usingDP %d dpEqual %d scrollableByApz %d plugins %d sle %d\n",
+    PAINT_SKIP_LOG("New scrollpos %s usingDP %d dpEqual %d scrollableByApz %d plugins %d\n",
         Stringify(CSSPoint::FromAppUnits(GetScrollPosition())).c_str(),
         usingDisplayPort, displayPort.IsEqualEdges(oldDisplayPort),
-        mScrollableByAPZ, HasPluginFrames(),
-        content->GetComposedDoc()->HasScrollLinkedEffect());
+        mScrollableByAPZ, HasPluginFrames());
     if (usingDisplayPort && displayPort.IsEqualEdges(oldDisplayPort)) {
       if (LastScrollOrigin() == nsGkAtoms::apz) {
         schedulePaint = false;
         PAINT_SKIP_LOG("Skipping due to APZ scroll\n");
-      } else if (mScrollableByAPZ && !HasPluginFrames() &&
-                 !content->GetComposedDoc()->HasScrollLinkedEffect()) {
+      } else if (mScrollableByAPZ && !HasPluginFrames()) {
         nsIWidget* widget = presContext->GetNearestWidget();
         LayerManager* manager = widget ? widget->GetLayerManager() : nullptr;
         if (manager) {
           mozilla::layers::FrameMetrics::ViewID id;
           DebugOnly<bool> success = nsLayoutUtils::FindIDFor(content, &id);
           MOZ_ASSERT(success); // we have a displayport, we better have an ID
 
           // Schedule an empty transaction to carry over the scroll offset update,
@@ -3331,17 +3329,16 @@ ScrollFrameHelper::BuildDisplayList(nsDi
         if (mClipAllDescendants) {
           inactiveScrollClip = clipStateForScrollClip.InsertInactiveScrollClipForContentDescendants(aBuilder, sf);
         } else {
           inactiveScrollClip = clipStateForScrollClip.InsertInactiveScrollClipForContainingBlockDescendants(aBuilder, sf);
         }
         MOZ_ASSERT(!inactiveScrollClip->mIsAsyncScrollable);
       }
 
-      aBuilder->StoreDirtyRectForScrolledContents(mOuter, dirtyRect);
       mOuter->BuildDisplayListForChild(aBuilder, mScrolledFrame, dirtyRect, scrolledContent);
     }
 
     if (contentBoxClipForNonCaretContent) {
       DisplayListClipState::AutoSaveRestore contentBoxClipState(aBuilder);
       if (mClipAllDescendants) {
         contentBoxClipState.ClipContentDescendants(*contentBoxClipForNonCaretContent);
       } else {
--- a/layout/generic/nsImageFrame.cpp
+++ b/layout/generic/nsImageFrame.cpp
@@ -131,17 +131,17 @@ NS_NewImageFrame(nsIPresShell* aPresShel
 {
   return new (aPresShell) nsImageFrame(aContext);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsImageFrame)
 
 
 nsImageFrame::nsImageFrame(nsStyleContext* aContext) :
-  ImageFrameSuper(aContext),
+  nsAtomicContainerFrame(aContext),
   mComputedSize(0, 0),
   mIntrinsicRatio(0, 0),
   mDisplayingIcon(false),
   mFirstFrameComplete(false),
   mReflowCallbackPosted(false),
   mForceSyncDecoding(false)
 {
   EnableVisibilityTracking();
@@ -153,17 +153,17 @@ nsImageFrame::nsImageFrame(nsStyleContex
 }
 
 nsImageFrame::~nsImageFrame()
 {
 }
 
 NS_QUERYFRAME_HEAD(nsImageFrame)
   NS_QUERYFRAME_ENTRY(nsImageFrame)
-NS_QUERYFRAME_TAIL_INHERITING(ImageFrameSuper)
+NS_QUERYFRAME_TAIL_INHERITING(nsAtomicContainerFrame)
 
 #ifdef ACCESSIBILITY
 a11y::AccType
 nsImageFrame::AccessibleType()
 {
   // Don't use GetImageMap() to avoid reentrancy into accessibility.
   if (HasImageMap()) {
     return a11y::eHTMLImageMapType;
@@ -217,23 +217,23 @@ nsImageFrame::DestroyFrom(nsIFrame* aDes
   }
   
   mListener = nullptr;
 
   // If we were displaying an icon, take ourselves off the list
   if (mDisplayingIcon)
     gIconLoad->RemoveIconObserver(this);
 
-  ImageFrameSuper::DestroyFrom(aDestructRoot);
+  nsAtomicContainerFrame::DestroyFrom(aDestructRoot);
 }
 
 void
 nsImageFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
 {
-  ImageFrameSuper::DidSetStyleContext(aOldStyleContext);
+  nsAtomicContainerFrame::DidSetStyleContext(aOldStyleContext);
 
   if (!mImage) {
     // We'll pick this change up whenever we do get an image.
     return;
   }
 
   nsStyleImageOrientation newOrientation = StyleVisibility()->mImageOrientation;
 
@@ -253,17 +253,17 @@ nsImageFrame::DidSetStyleContext(nsStyle
   }
 }
 
 void
 nsImageFrame::Init(nsIContent*       aContent,
                    nsContainerFrame* aParent,
                    nsIFrame*         aPrevInFlow)
 {
-  ImageFrameSuper::Init(aContent, aParent, aPrevInFlow);
+  nsAtomicContainerFrame::Init(aContent, aParent, aPrevInFlow);
 
   mListener = new nsImageListener(this);
 
   nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(aContent);
   if (!imageLoader) {
     NS_RUNTIMEABORT("Why do we have an nsImageFrame here at all?");
   }
 
@@ -1993,17 +1993,17 @@ nsImageFrame::HandleEvent(nsPresContext*
           }
           nsContentUtils::TriggerLink(anchorNode, aPresContext, uri, target,
                                       clicked, true, true);
         }
       }
     }
   }
 
-  return ImageFrameSuper::HandleEvent(aPresContext, aEvent, aEventStatus);
+  return nsAtomicContainerFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
 }
 
 nsresult
 nsImageFrame::GetCursor(const nsPoint& aPoint,
                         nsIFrame::Cursor& aCursor)
 {
   nsImageMap* map = GetImageMap();
   if (nullptr != map) {
@@ -2030,18 +2030,18 @@ nsImageFrame::GetCursor(const nsPoint& a
   return nsFrame::GetCursor(aPoint, aCursor);
 }
 
 nsresult
 nsImageFrame::AttributeChanged(int32_t aNameSpaceID,
                                nsIAtom* aAttribute,
                                int32_t aModType)
 {
-  nsresult rv = ImageFrameSuper::AttributeChanged(aNameSpaceID,
-                                                  aAttribute, aModType);
+  nsresult rv = nsAtomicContainerFrame::AttributeChanged(aNameSpaceID,
+                                                         aAttribute, aModType);
   if (NS_FAILED(rv)) {
     return rv;
   }
   if (nsGkAtoms::alt == aAttribute)
   {
     PresContext()->PresShell()->FrameNeedsReflow(this,
                                                  nsIPresShell::eStyleChange,
                                                  NS_FRAME_IS_DIRTY);
@@ -2052,27 +2052,27 @@ nsImageFrame::AttributeChanged(int32_t a
 
 void
 nsImageFrame::OnVisibilityChange(Visibility aNewVisibility,
                                  Maybe<OnNonvisible> aNonvisibleAction)
 {
   nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mContent);
   if (!imageLoader) {
     MOZ_ASSERT_UNREACHABLE("Should have an nsIImageLoadingContent");
-    ImageFrameSuper::OnVisibilityChange(aNewVisibility, aNonvisibleAction);
+    nsAtomicContainerFrame::OnVisibilityChange(aNewVisibility, aNonvisibleAction);
     return;
   }
 
   imageLoader->OnVisibilityChange(aNewVisibility, aNonvisibleAction);
 
   if (aNewVisibility == Visibility::APPROXIMATELY_VISIBLE) {
     MaybeDecodeForPredictedSize();
   }
 
-  ImageFrameSuper::OnVisibilityChange(aNewVisibility, aNonvisibleAction);
+  nsAtomicContainerFrame::OnVisibilityChange(aNewVisibility, aNonvisibleAction);
 }
 
 nsIAtom*
 nsImageFrame::GetType() const
 {
   return nsGkAtoms::imageFrame;
 }
 
--- a/layout/generic/nsImageFrame.h
+++ b/layout/generic/nsImageFrame.h
@@ -53,20 +53,18 @@ public:
   NS_DECL_IMGINOTIFICATIONOBSERVER
 
   void SetFrame(nsImageFrame *frame) { mFrame = frame; }
 
 private:
   nsImageFrame *mFrame;
 };
 
-typedef nsAtomicContainerFrame ImageFrameSuper;
-
-class nsImageFrame : public ImageFrameSuper,
-                     public nsIReflowCallback {
+class nsImageFrame : public nsAtomicContainerFrame
+                   , public nsIReflowCallback {
 public:
   template <typename T> using Maybe = mozilla::Maybe<T>;
   using Nothing = mozilla::Nothing;
   using Visibility = mozilla::Visibility;
 
   typedef mozilla::image::DrawResult DrawResult;
   typedef mozilla::layers::ImageContainer ImageContainer;
   typedef mozilla::layers::ImageLayer ImageLayer;
@@ -114,17 +112,17 @@ public:
 #ifdef ACCESSIBILITY
   virtual mozilla::a11y::AccType AccessibleType() override;
 #endif
 
   virtual nsIAtom* GetType() const override;
 
   virtual bool IsFrameOfType(uint32_t aFlags) const override
   {
-    return ImageFrameSuper::IsFrameOfType(aFlags &
+    return nsAtomicContainerFrame::IsFrameOfType(aFlags &
       ~(nsIFrame::eReplaced | nsIFrame::eReplacedSizing));
   }
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const override;
   void List(FILE* out = stderr, const char* aPrefix = "", 
             uint32_t aFlags = 0) const override;
 #endif
--- a/layout/generic/nsInlineFrame.cpp
+++ b/layout/generic/nsInlineFrame.cpp
@@ -66,30 +66,30 @@ nsInlineFrame::InvalidateFrame(uint32_t 
 {
   if (IsSVGText()) {
     nsIFrame* svgTextFrame =
       nsLayoutUtils::GetClosestFrameOfType(GetParent(),
                                            nsGkAtoms::svgTextFrame);
     svgTextFrame->InvalidateFrame();
     return;
   }
-  nsInlineFrameBase::InvalidateFrame(aDisplayItemKey);
+  nsContainerFrame::InvalidateFrame(aDisplayItemKey);
 }
 
 void
 nsInlineFrame::InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey)
 {
   if (IsSVGText()) {
     nsIFrame* svgTextFrame =
       nsLayoutUtils::GetClosestFrameOfType(GetParent(),
                                            nsGkAtoms::svgTextFrame);
     svgTextFrame->InvalidateFrame();
     return;
   }
-  nsInlineFrameBase::InvalidateFrameWithRect(aRect, aDisplayItemKey);
+  nsContainerFrame::InvalidateFrameWithRect(aRect, aDisplayItemKey);
 }
 
 static inline bool
 IsMarginZero(const nsStyleCoord &aCoord)
 {
   return aCoord.GetUnit() == eStyleUnit_Auto ||
          nsLayoutUtils::IsMarginZero(aCoord);
 }
@@ -477,17 +477,17 @@ nsInlineFrame::Reflow(nsPresContext*    
 }
 
 nsresult 
 nsInlineFrame::AttributeChanged(int32_t aNameSpaceID,
                                 nsIAtom* aAttribute,
                                 int32_t aModType)
 {
   nsresult rv =
-    nsInlineFrameBase::AttributeChanged(aNameSpaceID, aAttribute, aModType);
+    nsContainerFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
 
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   if (IsSVGText()) {
     SVGTextFrame* f = static_cast<SVGTextFrame*>(
       nsLayoutUtils::GetClosestFrameOfType(this, nsGkAtoms::svgTextFrame));
--- a/layout/generic/nsInlineFrame.h
+++ b/layout/generic/nsInlineFrame.h
@@ -8,25 +8,23 @@
 #ifndef nsInlineFrame_h___
 #define nsInlineFrame_h___
 
 #include "mozilla/Attributes.h"
 #include "nsContainerFrame.h"
 
 class nsLineLayout;
 
-typedef nsContainerFrame nsInlineFrameBase;
-
 /**
  * Inline frame class.
  *
  * This class manages a list of child frames that are inline frames. Working with
  * nsLineLayout, the class will reflow and place inline frames on a line.
  */
-class nsInlineFrame : public nsInlineFrameBase
+class nsInlineFrame : public nsContainerFrame
 {
 public:
   NS_DECL_QUERYFRAME_TARGET(nsInlineFrame)
   NS_DECL_QUERYFRAME
   NS_DECL_FRAMEARENA_HELPERS
 
   friend nsInlineFrame* NS_NewInlineFrame(nsIPresShell* aPresShell,
                                           nsStyleContext* aContext);
--- a/layout/generic/nsPluginFrame.cpp
+++ b/layout/generic/nsPluginFrame.cpp
@@ -145,17 +145,17 @@ protected:
     return false;
   }
 
   uint64_t mLastSequenceNumber;
   nsPluginFrame* mFrame;
 };
 
 nsPluginFrame::nsPluginFrame(nsStyleContext* aContext)
-  : nsPluginFrameSuper(aContext)
+  : nsFrame(aContext)
   , mInstanceOwner(nullptr)
   , mReflowCallbackPosted(false)
   , mIsHiddenDueToScroll(false)
 {
   MOZ_LOG(sPluginFrameLog, LogLevel::Debug,
          ("Created new nsPluginFrame %p\n", this));
 }
 
@@ -163,17 +163,17 @@ nsPluginFrame::~nsPluginFrame()
 {
   MOZ_LOG(sPluginFrameLog, LogLevel::Debug,
          ("nsPluginFrame %p deleted\n", this));
 }
 
 NS_QUERYFRAME_HEAD(nsPluginFrame)
   NS_QUERYFRAME_ENTRY(nsPluginFrame)
   NS_QUERYFRAME_ENTRY(nsIObjectFrame)
-NS_QUERYFRAME_TAIL_INHERITING(nsPluginFrameSuper)
+NS_QUERYFRAME_TAIL_INHERITING(nsFrame)
 
 #ifdef ACCESSIBILITY
 a11y::AccType
 nsPluginFrame::AccessibleType()
 {
   return a11y::ePluginType;
 }
 
@@ -189,17 +189,17 @@ NS_IMETHODIMP nsPluginFrame::GetPluginPo
 void
 nsPluginFrame::Init(nsIContent*       aContent,
                     nsContainerFrame* aParent,
                     nsIFrame*         aPrevInFlow)
 {
   MOZ_LOG(sPluginFrameLog, LogLevel::Debug,
          ("Initializing nsPluginFrame %p for content %p\n", this, aContent));
 
-  nsPluginFrameSuper::Init(aContent, aParent, aPrevInFlow);
+  nsFrame::Init(aContent, aParent, aPrevInFlow);
 }
 
 void
 nsPluginFrame::DestroyFrom(nsIFrame* aDestructRoot)
 {
   if (mReflowCallbackPosted) {
     PresContext()->PresShell()->CancelReflowCallback(this);
   }
@@ -218,33 +218,33 @@ nsPluginFrame::DestroyFrom(nsIFrame* aDe
     mInstanceOwner->SetFrame(nullptr);
   }
   objContent->HasNewFrame(nullptr);
 
   if (mBackgroundSink) {
     mBackgroundSink->Destroy();
   }
 
-  nsPluginFrameSuper::DestroyFrom(aDestructRoot);
+  nsFrame::DestroyFrom(aDestructRoot);
 }
 
 /* virtual */ void
 nsPluginFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
 {
   if (HasView()) {
     nsView* view = GetView();
     nsViewManager* vm = view->GetViewManager();
     if (vm) {
       nsViewVisibility visibility = 
         IsHidden() ? nsViewVisibility_kHide : nsViewVisibility_kShow;
       vm->SetViewVisibility(view, visibility);
     }
   }
 
-  nsPluginFrameSuper::DidSetStyleContext(aOldStyleContext);
+  nsFrame::DidSetStyleContext(aOldStyleContext);
 }
 
 nsIAtom*
 nsPluginFrame::GetType() const
 {
   return nsGkAtoms::objectFrame; 
 }
 
@@ -732,17 +732,17 @@ nsPluginFrame::SetInstanceOwner(nsPlugin
   }
 }
 
 bool
 nsPluginFrame::IsFocusable(int32_t *aTabIndex, bool aWithMouse)
 {
   if (aTabIndex)
     *aTabIndex = -1;
-  return nsPluginFrameSuper::IsFocusable(aTabIndex, aWithMouse);
+  return nsFrame::IsFocusable(aTabIndex, aWithMouse);
 }
 
 bool
 nsPluginFrame::IsHidden(bool aCheckVisibilityStyle) const
 {
   if (aCheckVisibilityStyle) {
     if (!StyleVisibility()->IsVisibleOrCollapsed())
       return true;    
@@ -846,17 +846,17 @@ nsPluginFrame::DidReflow(nsPresContext* 
   // NS_FRAME_FIRST_REFLOW
   if (aStatus == nsDidReflowStatus::FINISHED &&
       (GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
     nsCOMPtr<nsIObjectLoadingContent> objContent(do_QueryInterface(mContent));
     NS_ASSERTION(objContent, "Why not an object loading content?");
     objContent->HasNewFrame(this);
   }
 
-  nsPluginFrameSuper::DidReflow(aPresContext, aReflowState, aStatus);
+  nsFrame::DidReflow(aPresContext, aReflowState, aStatus);
 
   // The view is created hidden; once we have reflowed it and it has been
   // positioned then we show it.
   if (aStatus != nsDidReflowStatus::FINISHED)
     return;
 
   if (HasView()) {
     nsView* view = GetView();
@@ -1665,17 +1665,17 @@ nsPluginFrame::HandleEvent(nsPresContext
       anEvent->IsNativeEventDelivererForPlugin()) {
     *anEventStatus = mInstanceOwner->ProcessEvent(*anEvent);
     // Due to plugin code reentering Gecko, this frame may be dead at this
     // point.
     return rv;
   }
 
 #ifdef XP_WIN
-  rv = nsPluginFrameSuper::HandleEvent(aPresContext, anEvent, anEventStatus);
+  rv = nsFrame::HandleEvent(aPresContext, anEvent, anEventStatus);
   return rv;
 #endif
 
 #ifdef XP_MACOSX
   // we want to process some native mouse events in the cocoa event model
   if ((anEvent->mMessage == eMouseEnterIntoWidget ||
        anEvent->mMessage == eWheel) &&
       mInstanceOwner->GetEventModel() == NPEventModelCocoa) {
@@ -1689,20 +1689,20 @@ nsPluginFrame::HandleEvent(nsPresContext
   // and mouse-up) are needed to make the routing of mouse events while
   // dragging conform to standard OS X practice, and to the Cocoa NPAPI spec.
   // See bug 525078 and bug 909678.
   if (anEvent->mMessage == eMouseDown) {
     nsIPresShell::SetCapturingContent(GetContent(), CAPTURE_IGNOREALLOWED);
   }
 #endif
 
-  rv = nsPluginFrameSuper::HandleEvent(aPresContext, anEvent, anEventStatus);
+  rv = nsFrame::HandleEvent(aPresContext, anEvent, anEventStatus);
 
   // We need to be careful from this point because the call to
-  // nsPluginFrameSuper::HandleEvent() might have killed us.
+  // nsFrame::HandleEvent() might have killed us.
 
 #ifdef XP_MACOSX
   if (anEvent->mMessage == eMouseUp) {
     nsIPresShell::SetCapturingContent(nullptr, 0);
   }
 #endif
 
   return rv;
@@ -1777,17 +1777,17 @@ nsPluginFrame::GetCursor(const nsPoint& 
     return NS_ERROR_FAILURE;
   }
 
   bool useDOMCursor = static_cast<nsNPAPIPluginInstance*>(inst.get())->UsesDOMForCursor();
   if (!useDOMCursor) {
     return NS_ERROR_FAILURE;
   }
 
-  return nsPluginFrameSuper::GetCursor(aPoint, aCursor);
+  return nsFrame::GetCursor(aPoint, aCursor);
 }
 
 void
 nsPluginFrame::SetIsDocumentActive(bool aIsActive)
 {
   if (mInstanceOwner) {
     mInstanceOwner->UpdateDocumentActiveState(aIsActive);
   }
--- a/layout/generic/nsPluginFrame.h
+++ b/layout/generic/nsPluginFrame.h
@@ -37,23 +37,21 @@ class nsPluginInstanceOwner;
 namespace mozilla {
 namespace layers {
 class ImageContainer;
 class Layer;
 class LayerManager;
 } // namespace layers
 } // namespace mozilla
 
-typedef nsFrame nsPluginFrameSuper;
-
 class PluginFrameDidCompositeObserver;
 
-class nsPluginFrame : public nsPluginFrameSuper,
-                      public nsIObjectFrame,
-                      public nsIReflowCallback
+class nsPluginFrame : public nsFrame
+                    , public nsIObjectFrame
+                    , public nsIReflowCallback
 {
 public:
   typedef mozilla::LayerState LayerState;
   typedef mozilla::LayoutDeviceIntPoint LayoutDeviceIntPoint;
   typedef mozilla::LayoutDeviceIntRect LayoutDeviceIntRect;
   typedef mozilla::LayoutDeviceIntRegion LayoutDeviceIntRegion;
   typedef mozilla::layers::Layer Layer;
   typedef mozilla::layers::LayerManager LayerManager;
@@ -86,17 +84,17 @@ public:
   virtual nsresult  HandleEvent(nsPresContext* aPresContext,
                                 mozilla::WidgetGUIEvent* aEvent,
                                 nsEventStatus* aEventStatus) override;
 
   virtual nsIAtom* GetType() const override;
 
   virtual bool IsFrameOfType(uint32_t aFlags) const override
   {
-    return nsPluginFrameSuper::IsFrameOfType(aFlags &
+    return nsFrame::IsFrameOfType(aFlags &
       ~(nsIFrame::eReplaced | nsIFrame::eReplacedSizing));
   }
 
   virtual bool NeedsView() override { return true; }
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const override;
 #endif
--- a/layout/generic/nsRubyBaseFrame.cpp
+++ b/layout/generic/nsRubyBaseFrame.cpp
@@ -17,17 +17,17 @@ using namespace mozilla;
 
 //----------------------------------------------------------------------
 
 // Frame class boilerplate
 // =======================
 
 NS_QUERYFRAME_HEAD(nsRubyBaseFrame)
   NS_QUERYFRAME_ENTRY(nsRubyBaseFrame)
-NS_QUERYFRAME_TAIL_INHERITING(nsRubyBaseFrameSuper)
+NS_QUERYFRAME_TAIL_INHERITING(nsRubyContentFrame)
 
 NS_IMPL_FRAMEARENA_HELPERS(nsRubyBaseFrame)
 
 nsContainerFrame*
 NS_NewRubyBaseFrame(nsIPresShell* aPresShell,
                     nsStyleContext* aContext)
 {
   return new (aPresShell) nsRubyBaseFrame(aContext);
--- a/layout/generic/nsRubyBaseFrame.h
+++ b/layout/generic/nsRubyBaseFrame.h
@@ -6,26 +6,24 @@
 
 /* rendering object for CSS "display: ruby-base" */
 
 #ifndef nsRubyBaseFrame_h___
 #define nsRubyBaseFrame_h___
 
 #include "nsRubyContentFrame.h"
 
-typedef nsRubyContentFrame nsRubyBaseFrameSuper;
-
 /**
  * Factory function.
  * @return a newly allocated nsRubyBaseFrame (infallible)
  */
 nsContainerFrame* NS_NewRubyBaseFrame(nsIPresShell* aPresShell,
                                       nsStyleContext* aContext);
 
-class nsRubyBaseFrame final : public nsRubyBaseFrameSuper
+class nsRubyBaseFrame final : public nsRubyContentFrame
 {
 public:
   NS_DECL_FRAMEARENA_HELPERS
   NS_DECL_QUERYFRAME_TARGET(nsRubyBaseFrame)
   NS_DECL_QUERYFRAME
 
   // nsIFrame overrides
   virtual nsIAtom* GetType() const override;
@@ -33,12 +31,12 @@ public:
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const override;
 #endif
 
 protected:
   friend nsContainerFrame* NS_NewRubyBaseFrame(nsIPresShell* aPresShell,
                                                nsStyleContext* aContext);
   explicit nsRubyBaseFrame(nsStyleContext* aContext)
-    : nsRubyBaseFrameSuper(aContext) {}
+    : nsRubyContentFrame(aContext) {}
 };
 
 #endif /* nsRubyBaseFrame_h___ */
--- a/layout/generic/nsRubyContentFrame.cpp
+++ b/layout/generic/nsRubyContentFrame.cpp
@@ -19,17 +19,17 @@ using namespace mozilla;
 // ======================================
 
 /* virtual */ bool
 nsRubyContentFrame::IsFrameOfType(uint32_t aFlags) const
 {
   if (aFlags & eBidiInlineContainer) {
     return false;
   }
-  return nsRubyContentFrameSuper::IsFrameOfType(aFlags);
+  return nsInlineFrame::IsFrameOfType(aFlags);
 }
 
 bool
 nsRubyContentFrame::IsIntraLevelWhitespace() const
 {
   nsIAtom* pseudoType = StyleContext()->GetPseudo();
   if (pseudoType != nsCSSAnonBoxes::rubyBase &&
       pseudoType != nsCSSAnonBoxes::rubyText) {
--- a/layout/generic/nsRubyContentFrame.h
+++ b/layout/generic/nsRubyContentFrame.h
@@ -6,31 +6,29 @@
 
 /* base class for ruby rendering objects that directly contain content */
 
 #ifndef nsRubyContentFrame_h___
 #define nsRubyContentFrame_h___
 
 #include "nsInlineFrame.h"
 
-typedef nsInlineFrame nsRubyContentFrameSuper;
-
-class nsRubyContentFrame : public nsRubyContentFrameSuper
+class nsRubyContentFrame : public nsInlineFrame
 {
 public:
   NS_DECL_ABSTRACT_FRAME(nsRubyContentFrame)
 
   // nsIFrame overrides
   virtual bool IsFrameOfType(uint32_t aFlags) const override;
 
   // Indicates whether this is an "intra-level whitespace" frame, i.e.
   // an anonymous frame that was created to contain non-droppable
   // whitespaces directly inside a ruby level container. This impacts
   // ruby pairing behavior.
   // See http://dev.w3.org/csswg/css-ruby/#anon-gen-interpret-space
   bool IsIntraLevelWhitespace() const;
 
 protected:
   explicit nsRubyContentFrame(nsStyleContext* aContext)
-    : nsRubyContentFrameSuper(aContext) {}
+    : nsInlineFrame(aContext) {}
 };
 
 #endif /* nsRubyContentFrame_h___ */
--- a/layout/generic/nsRubyFrame.cpp
+++ b/layout/generic/nsRubyFrame.cpp
@@ -21,17 +21,17 @@ using namespace mozilla;
 
 //----------------------------------------------------------------------
 
 // Frame class boilerplate
 // =======================
 
 NS_QUERYFRAME_HEAD(nsRubyFrame)
   NS_QUERYFRAME_ENTRY(nsRubyFrame)
-NS_QUERYFRAME_TAIL_INHERITING(nsRubyFrameSuper)
+NS_QUERYFRAME_TAIL_INHERITING(nsInlineFrame)
 
 NS_IMPL_FRAMEARENA_HELPERS(nsRubyFrame)
 
 nsContainerFrame*
 NS_NewRubyFrame(nsIPresShell* aPresShell,
                 nsStyleContext* aContext)
 {
   return new (aPresShell) nsRubyFrame(aContext);
@@ -49,17 +49,17 @@ nsRubyFrame::GetType() const
 }
 
 /* virtual */ bool
 nsRubyFrame::IsFrameOfType(uint32_t aFlags) const
 {
   if (aFlags & eBidiInlineContainer) {
     return false;
   }
-  return nsRubyFrameSuper::IsFrameOfType(aFlags);
+  return nsInlineFrame::IsFrameOfType(aFlags);
 }
 
 #ifdef DEBUG_FRAME_DUMP
 nsresult
 nsRubyFrame::GetFrameName(nsAString& aResult) const
 {
   return MakeFrameName(NS_LITERAL_STRING("Ruby"), aResult);
 }
--- a/layout/generic/nsRubyFrame.h
+++ b/layout/generic/nsRubyFrame.h
@@ -8,26 +8,24 @@
 
 #ifndef nsRubyFrame_h___
 #define nsRubyFrame_h___
 
 #include "nsInlineFrame.h"
 
 class nsRubyBaseContainerFrame;
 
-typedef nsInlineFrame nsRubyFrameSuper;
-
 /**
  * Factory function.
  * @return a newly allocated nsRubyFrame (infallible)
  */
 nsContainerFrame* NS_NewRubyFrame(nsIPresShell* aPresShell,
                                   nsStyleContext* aContext);
 
-class nsRubyFrame final : public nsRubyFrameSuper
+class nsRubyFrame final : public nsInlineFrame
 {
 public:
   NS_DECL_FRAMEARENA_HELPERS
   NS_DECL_QUERYFRAME_TARGET(nsRubyFrame)
   NS_DECL_QUERYFRAME
 
   // nsIFrame overrides
   virtual nsIAtom* GetType() const override;
@@ -50,17 +48,17 @@ public:
     aStartLeading = mBStartLeading;
     aEndLeading = mBEndLeading;
   }
 
 protected:
   friend nsContainerFrame* NS_NewRubyFrame(nsIPresShell* aPresShell,
                                            nsStyleContext* aContext);
   explicit nsRubyFrame(nsStyleContext* aContext)
-    : nsRubyFrameSuper(aContext) {}
+    : nsInlineFrame(aContext) {}
 
   void ReflowSegment(nsPresContext* aPresContext,
                      const nsHTMLReflowState& aReflowState,
                      nsRubyBaseContainerFrame* aBaseContainer,
                      nsReflowStatus& aStatus);
 
   nsRubyBaseContainerFrame* PullOneSegment(const nsLineLayout* aLineLayout,
                                            ContinuationTraversingState& aState);
--- a/layout/generic/nsRubyTextContainerFrame.cpp
+++ b/layout/generic/nsRubyTextContainerFrame.cpp
@@ -55,51 +55,51 @@ nsRubyTextContainerFrame::GetFrameName(n
 #endif
 
 /* virtual */ bool
 nsRubyTextContainerFrame::IsFrameOfType(uint32_t aFlags) const
 {
   if (aFlags & eSupportsCSSTransforms) {
     return false;
   }
-  return nsRubyTextContainerFrameSuper::IsFrameOfType(aFlags);
+  return nsContainerFrame::IsFrameOfType(aFlags);
 }
 
 /* virtual */ void
 nsRubyTextContainerFrame::SetInitialChildList(ChildListID aListID,
                                               nsFrameList& aChildList)
 {
-  nsRubyTextContainerFrameSuper::SetInitialChildList(aListID, aChildList);
+  nsContainerFrame::SetInitialChildList(aListID, aChildList);
   if (aListID == kPrincipalList) {
     UpdateSpanFlag();
   }
 }
 
 /* virtual */ void
 nsRubyTextContainerFrame::AppendFrames(ChildListID aListID,
                                        nsFrameList& aFrameList)
 {
-  nsRubyTextContainerFrameSuper::AppendFrames(aListID, aFrameList);
+  nsContainerFrame::AppendFrames(aListID, aFrameList);
   UpdateSpanFlag();
 }
 
 /* virtual */ void
 nsRubyTextContainerFrame::InsertFrames(ChildListID aListID,
                                        nsIFrame* aPrevFrame,
                                        nsFrameList& aFrameList)
 {
-  nsRubyTextContainerFrameSuper::InsertFrames(aListID, aPrevFrame, aFrameList);
+  nsContainerFrame::InsertFrames(aListID, aPrevFrame, aFrameList);
   UpdateSpanFlag();
 }
 
 /* virtual */ void
 nsRubyTextContainerFrame::RemoveFrame(ChildListID aListID,
                                       nsIFrame* aOldFrame)
 {
-  nsRubyTextContainerFrameSuper::RemoveFrame(aListID, aOldFrame);
+  nsContainerFrame::RemoveFrame(aListID, aOldFrame);
   UpdateSpanFlag();
 }
 
 void
 nsRubyTextContainerFrame::UpdateSpanFlag()
 {
   bool isSpan = false;
   // The continuation checks are safe here because spans never break.
--- a/layout/generic/nsRubyTextContainerFrame.h
+++ b/layout/generic/nsRubyTextContainerFrame.h
@@ -6,26 +6,24 @@
 
 /* rendering object for CSS "display: ruby-text-container" */
 
 #ifndef nsRubyTextContainerFrame_h___
 #define nsRubyTextContainerFrame_h___
 
 #include "nsBlockFrame.h"
 
-typedef nsContainerFrame nsRubyTextContainerFrameSuper;
-
 /**
  * Factory function.
  * @return a newly allocated nsRubyTextContainerFrame (infallible)
  */
 nsContainerFrame* NS_NewRubyTextContainerFrame(nsIPresShell* aPresShell,
                                                nsStyleContext* aContext);
 
-class nsRubyTextContainerFrame final : public nsRubyTextContainerFrameSuper
+class nsRubyTextContainerFrame final : public nsContainerFrame
 {
 public:
   NS_DECL_FRAMEARENA_HELPERS
   NS_DECL_QUERYFRAME_TARGET(nsRubyTextContainerFrame)
   NS_DECL_QUERYFRAME
 
   // nsIFrame overrides
   virtual nsIAtom* GetType() const override;
@@ -54,17 +52,17 @@ public:
     return GetStateBits() & NS_RUBY_TEXT_CONTAINER_IS_SPAN;
   }
 
 protected:
   friend nsContainerFrame*
     NS_NewRubyTextContainerFrame(nsIPresShell* aPresShell,
                                  nsStyleContext* aContext);
   explicit nsRubyTextContainerFrame(nsStyleContext* aContext)
-    : nsRubyTextContainerFrameSuper(aContext)
+    : nsContainerFrame(aContext)
     , mISize(0) {}
 
   void UpdateSpanFlag();
 
   friend class nsRubyBaseContainerFrame;
   void SetISize(nscoord aISize) { mISize = aISize; }
 
   // The intended inline size of the ruby text container. It is set by
--- a/layout/generic/nsRubyTextFrame.cpp
+++ b/layout/generic/nsRubyTextFrame.cpp
@@ -17,17 +17,17 @@ using namespace mozilla;
 
 //----------------------------------------------------------------------
 
 // Frame class boilerplate
 // =======================
 
 NS_QUERYFRAME_HEAD(nsRubyTextFrame)
   NS_QUERYFRAME_ENTRY(nsRubyTextFrame)
-NS_QUERYFRAME_TAIL_INHERITING(nsRubyTextFrameSuper)
+NS_QUERYFRAME_TAIL_INHERITING(nsRubyContentFrame)
 
 NS_IMPL_FRAMEARENA_HELPERS(nsRubyTextFrame)
 
 nsContainerFrame*
 NS_NewRubyTextFrame(nsIPresShell* aPresShell,
                     nsStyleContext* aContext)
 {
   return new (aPresShell) nsRubyTextFrame(aContext);
@@ -65,33 +65,32 @@ nsRubyTextFrame::GetFrameName(nsAString&
 nsRubyTextFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                   const nsRect&           aDirtyRect,
                                   const nsDisplayListSet& aLists)
 {
   if (IsAutoHidden()) {
     return;
   }
 
-  nsRubyTextFrameSuper::BuildDisplayList(aBuilder, aDirtyRect, aLists);
+  nsRubyContentFrame::BuildDisplayList(aBuilder, aDirtyRect, aLists);
 }
 
 /* virtual */ void
 nsRubyTextFrame::Reflow(nsPresContext* aPresContext,
                         nsHTMLReflowMetrics& aDesiredSize,
                         const nsHTMLReflowState& aReflowState,
                         nsReflowStatus& aStatus)
 {
   // Even if we want to hide this frame, we have to reflow it first.
   // If we leave it dirty, changes to its content will never be
   // propagated to the ancestors, then it won't be displayed even if
   // the content is no longer the same, until next reflow triggered by
   // some other change. In general, we always reflow all the frames we
   // created. There might be other problems if we don't do that.
-  nsRubyTextFrameSuper::Reflow(aPresContext, aDesiredSize,
-                               aReflowState, aStatus);
+  nsRubyContentFrame::Reflow(aPresContext, aDesiredSize, aReflowState, aStatus);
 
   if (IsAutoHidden()) {
     // Reset the ISize. The BSize is not changed so that it won't
     // affect vertical positioning in unexpected way.
     WritingMode lineWM = aReflowState.mLineLayout->GetWritingMode();
     aDesiredSize.ISize(lineWM) = 0;
     aDesiredSize.SetOverflowAreasToDesiredBounds();
   }
--- a/layout/generic/nsRubyTextFrame.h
+++ b/layout/generic/nsRubyTextFrame.h
@@ -6,26 +6,24 @@
 
 /* rendering object for CSS "display: ruby-text" */
 
 #ifndef nsRubyTextFrame_h___
 #define nsRubyTextFrame_h___
 
 #include "nsRubyContentFrame.h"
 
-typedef nsRubyContentFrame nsRubyTextFrameSuper;
-
 /**
  * Factory function.
  * @return a newly allocated nsRubyTextFrame (infallible)
  */
 nsContainerFrame* NS_NewRubyTextFrame(nsIPresShell* aPresShell,
                                       nsStyleContext* aContext);
 
-class nsRubyTextFrame final : public nsRubyTextFrameSuper
+class nsRubyTextFrame final : public nsRubyContentFrame
 {
 public:
   NS_DECL_FRAMEARENA_HELPERS
   NS_DECL_QUERYFRAME_TARGET(nsRubyTextFrame)
   NS_DECL_QUERYFRAME
 
   // nsIFrame overrides
   virtual nsIAtom* GetType() const override;
@@ -48,12 +46,12 @@ public:
   {
     return GetStateBits() & NS_RUBY_TEXT_FRAME_AUTOHIDE;
   }
 
 protected:
   friend nsContainerFrame* NS_NewRubyTextFrame(nsIPresShell* aPresShell,
                                                nsStyleContext* aContext);
   explicit nsRubyTextFrame(nsStyleContext* aContext)
-    : nsRubyTextFrameSuper(aContext) {}
+    : nsRubyContentFrame(aContext) {}
 };
 
 #endif /* nsRubyTextFrame_h___ */
--- a/layout/generic/nsSubDocumentFrame.cpp
+++ b/layout/generic/nsSubDocumentFrame.cpp
@@ -51,17 +51,17 @@ GetDocumentFromView(nsView* aView)
   NS_PRECONDITION(aView, "");
 
   nsViewManager* vm = aView->GetViewManager();
   nsIPresShell* ps =  vm ? vm->GetPresShell() : nullptr;
   return ps ? ps->GetDocument() : nullptr;
 }
 
 nsSubDocumentFrame::nsSubDocumentFrame(nsStyleContext* aContext)
-  : nsSubDocumentFrameSuper(aContext)
+  : nsAtomicContainerFrame(aContext)
   , mIsInline(false)
   , mPostedReflowCallback(false)
   , mDidCreateDoc(false)
   , mCallingShow(false)
 {
 }
 
 #ifdef ACCESSIBILITY
@@ -69,17 +69,17 @@ a11y::AccType
 nsSubDocumentFrame::AccessibleType()
 {
   return a11y::eOuterDocType;
 }
 #endif
 
 NS_QUERYFRAME_HEAD(nsSubDocumentFrame)
   NS_QUERYFRAME_ENTRY(nsSubDocumentFrame)
-NS_QUERYFRAME_TAIL_INHERITING(nsSubDocumentFrameSuper)
+NS_QUERYFRAME_TAIL_INHERITING(nsAtomicContainerFrame)
 
 class AsyncFrameInit : public nsRunnable
 {
 public:
   explicit AsyncFrameInit(nsIFrame* aFrame) : mFrame(aFrame) {}
   NS_IMETHOD Run()
   {
     PROFILER_LABEL("mozilla", "AsyncFrameInit::Run", js::ProfileEntry::Category::OTHER);
@@ -102,17 +102,17 @@ void
 nsSubDocumentFrame::Init(nsIContent*       aContent,
                          nsContainerFrame* aParent,
                          nsIFrame*         aPrevInFlow)
 {
   // determine if we are a <frame> or <iframe>
   nsCOMPtr<nsIDOMHTMLFrameElement> frameElem = do_QueryInterface(aContent);
   mIsInline = frameElem ? false : true;
 
-  nsSubDocumentFrameSuper::Init(aContent, aParent, aPrevInFlow);
+  nsAtomicContainerFrame::Init(aContent, aParent, aPrevInFlow);
 
   // We are going to create an inner view.  If we need a view for the
   // OuterFrame but we wait for the normal view creation path in
   // nsCSSFrameConstructor, then we will lose because the inner view's
   // parent will already have been set to some outer view (e.g., the
   // canvas) when it really needs to have this frame's view as its
   // parent. So, create this frame's view right away, whether we
   // really need it or not, and the inner view will get it as the
@@ -684,27 +684,27 @@ nsSubDocumentFrame::GetPrefISize(nsRende
 
 /* virtual */ IntrinsicSize
 nsSubDocumentFrame::GetIntrinsicSize()
 {
   nsIFrame* subDocRoot = ObtainIntrinsicSizeFrame();
   if (subDocRoot) {
     return subDocRoot->GetIntrinsicSize();
   }
-  return nsSubDocumentFrameSuper::GetIntrinsicSize();
+  return nsAtomicContainerFrame::GetIntrinsicSize();
 }
 
 /* virtual */ nsSize
 nsSubDocumentFrame::GetIntrinsicRatio()
 {
   nsIFrame* subDocRoot = ObtainIntrinsicSizeFrame();
   if (subDocRoot) {
     return subDocRoot->GetIntrinsicRatio();
   }
-  return nsSubDocumentFrameSuper::GetIntrinsicRatio();
+  return nsAtomicContainerFrame::GetIntrinsicRatio();
 }
 
 /* virtual */
 LogicalSize
 nsSubDocumentFrame::ComputeAutoSize(nsRenderingContext *aRenderingContext,
                                     WritingMode aWM,
                                     const LogicalSize& aCBSize,
                                     nscoord aAvailableISize,
@@ -742,20 +742,20 @@ nsSubDocumentFrame::ComputeSize(nsRender
                             aRenderingContext, this,
                             subDocRoot->GetIntrinsicSize(),
                             subDocRoot->GetIntrinsicRatio(),
                             aCBSize,
                             aMargin,
                             aBorder,
                             aPadding);
   }
-  return nsSubDocumentFrameSuper::ComputeSize(aRenderingContext, aWM,
-                                              aCBSize, aAvailableISize,
-                                              aMargin, aBorder, aPadding,
-                                              aFlags);
+  return nsAtomicContainerFrame::ComputeSize(aRenderingContext, aWM,
+                                             aCBSize, aAvailableISize,
+                                             aMargin, aBorder, aPadding,
+                                             aFlags);
 }
 
 void
 nsSubDocumentFrame::Reflow(nsPresContext*           aPresContext,
                            nsHTMLReflowMetrics&     aDesiredSize,
                            const nsHTMLReflowState& aReflowState,
                            nsReflowStatus&          aStatus)
 {
@@ -990,17 +990,17 @@ nsSubDocumentFrame::DestroyFrom(nsIFrame
     // safely determine whether the frame is being reframed or destroyed.
     nsContentUtils::AddScriptRunner(
       new nsHideViewer(mContent,
                        frameloader,
                        PresContext()->PresShell(),
                        (mDidCreateDoc || mCallingShow)));
   }
 
-  nsSubDocumentFrameSuper::DestroyFrom(aDestructRoot);
+  nsAtomicContainerFrame::DestroyFrom(aDestructRoot);
 }
 
 CSSIntSize
 nsSubDocumentFrame::GetMarginAttributes()
 {
   CSSIntSize result(-1, -1);
   nsGenericHTMLElement *content = nsGenericHTMLElement::FromContent(mContent);
   if (content) {
--- a/layout/generic/nsSubDocumentFrame.h
+++ b/layout/generic/nsSubDocumentFrame.h
@@ -7,22 +7,20 @@
 #define NSSUBDOCUMENTFRAME_H_
 
 #include "mozilla/Attributes.h"
 #include "nsAtomicContainerFrame.h"
 #include "nsIReflowCallback.h"
 #include "nsFrameLoader.h"
 #include "Units.h"
 
-typedef nsAtomicContainerFrame nsSubDocumentFrameSuper;
-
 /******************************************************************************
  * nsSubDocumentFrame
  *****************************************************************************/
-class nsSubDocumentFrame : public nsSubDocumentFrameSuper,
+class nsSubDocumentFrame : public nsAtomicContainerFrame,
                            public nsIReflowCallback
 {
 public:
   NS_DECL_QUERYFRAME_TARGET(nsSubDocumentFrame)
   NS_DECL_FRAMEARENA_HELPERS
 
   explicit nsSubDocumentFrame(nsStyleContext* aContext);
 
@@ -32,17 +30,17 @@ public:
 #endif
 
   NS_DECL_QUERYFRAME
 
   virtual nsIAtom* GetType() const override;
 
   virtual bool IsFrameOfType(uint32_t aFlags) const override
   {
-    return nsSubDocumentFrameSuper::IsFrameOfType(aFlags &
+    return nsAtomicContainerFrame::IsFrameOfType(aFlags &
       ~(nsIFrame::eReplaced |
         nsIFrame::eReplacedSizing |
         nsIFrame::eReplacedContainsBlock));
   }
 
   virtual void Init(nsIContent*       aContent,
                     nsContainerFrame* aParent,
                     nsIFrame*         aPrevInFlow) override;
--- a/layout/generic/nsVideoFrame.cpp
+++ b/layout/generic/nsVideoFrame.cpp
@@ -37,29 +37,29 @@ nsIFrame*
 NS_NewHTMLVideoFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
   return new (aPresShell) nsVideoFrame(aContext);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsVideoFrame)
 
 nsVideoFrame::nsVideoFrame(nsStyleContext* aContext)
-  : nsVideoFrameBase(aContext)
+  : nsContainerFrame(aContext)
 {
   EnableVisibilityTracking();
 }
 
 nsVideoFrame::~nsVideoFrame()
 {
 }
 
 NS_QUERYFRAME_HEAD(nsVideoFrame)
   NS_QUERYFRAME_ENTRY(nsVideoFrame)
   NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator)
-NS_QUERYFRAME_TAIL_INHERITING(nsVideoFrameBase)
+NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
 
 nsresult
 nsVideoFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
 {
   nsNodeInfoManager *nodeInfoManager = GetContent()->GetComposedDoc()->NodeInfoManager();
   RefPtr<NodeInfo> nodeInfo;
   Element *element;
 
@@ -140,17 +140,17 @@ nsVideoFrame::AppendAnonymousContentTo(n
 }
 
 void
 nsVideoFrame::DestroyFrom(nsIFrame* aDestructRoot)
 {
   nsContentUtils::DestroyAnonymousContent(&mCaptionDiv);
   nsContentUtils::DestroyAnonymousContent(&mVideoControls);
   nsContentUtils::DestroyAnonymousContent(&mPosterImage);
-  nsVideoFrameBase::DestroyFrom(aDestructRoot);
+  nsContainerFrame::DestroyFrom(aDestructRoot);
 }
 
 bool
 nsVideoFrame::IsLeaf() const
 {
   return true;
 }
 
@@ -607,34 +607,34 @@ nsVideoFrame::UpdatePosterSource(bool aN
 nsresult
 nsVideoFrame::AttributeChanged(int32_t aNameSpaceID,
                                nsIAtom* aAttribute,
                                int32_t aModType)
 {
   if (aAttribute == nsGkAtoms::poster && HasVideoElement()) {
     UpdatePosterSource(true);
   }
-  return nsVideoFrameBase::AttributeChanged(aNameSpaceID,
+  return nsContainerFrame::AttributeChanged(aNameSpaceID,
                                             aAttribute,
                                             aModType);
 }
 
 void
 nsVideoFrame::OnVisibilityChange(Visibility aNewVisibility,
                                  Maybe<OnNonvisible> aNonvisibleAction)
 {
   nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mPosterImage);
   if (!imageLoader) {
-    nsVideoFrameBase::OnVisibilityChange(aNewVisibility, aNonvisibleAction);
+    nsContainerFrame::OnVisibilityChange(aNewVisibility, aNonvisibleAction);
     return;
   }
 
   imageLoader->OnVisibilityChange(aNewVisibility, aNonvisibleAction);
 
-  nsVideoFrameBase::OnVisibilityChange(aNewVisibility, aNonvisibleAction);
+  nsContainerFrame::OnVisibilityChange(aNewVisibility, aNonvisibleAction);
 }
 
 bool nsVideoFrame::HasVideoElement() {
   nsCOMPtr<nsIDOMHTMLMediaElement> mediaDomElement = do_QueryInterface(mContent);
   return mediaDomElement->IsVideo();
 }
 
 bool nsVideoFrame::HasVideoData()
--- a/layout/generic/nsVideoFrame.h
+++ b/layout/generic/nsVideoFrame.h
@@ -21,19 +21,18 @@ class Layer;
 class LayerManager;
 } // namespace layers
 } // namespace mozilla
 
 class nsAString;
 class nsPresContext;
 class nsDisplayItem;
 
-typedef nsContainerFrame nsVideoFrameBase;
-
-class nsVideoFrame : public nsVideoFrameBase, public nsIAnonymousContentCreator
+class nsVideoFrame : public nsContainerFrame
+                   , public nsIAnonymousContentCreator
 {
 public:
   template <typename T> using Maybe = mozilla::Maybe<T>;
   using Nothing = mozilla::Nothing;
   using Visibility = mozilla::Visibility;
 
   typedef mozilla::layers::Layer Layer;
   typedef mozilla::layers::LayerManager LayerManager;
--- a/layout/generic/nsViewportFrame.cpp
+++ b/layout/generic/nsViewportFrame.cpp
@@ -31,17 +31,17 @@ NS_QUERYFRAME_HEAD(ViewportFrame)
   NS_QUERYFRAME_ENTRY(ViewportFrame)
 NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
 
 void
 ViewportFrame::Init(nsIContent*       aContent,
                     nsContainerFrame* aParent,
                     nsIFrame*         aPrevInFlow)
 {
-  Super::Init(aContent, aParent, aPrevInFlow);
+  nsContainerFrame::Init(aContent, aParent, aPrevInFlow);
 
   nsIFrame* parent = nsLayoutUtils::GetCrossDocParentFrame(this);
   if (parent) {
     nsFrameState state = parent->GetStateBits();
 
     mState |= state & (NS_FRAME_IN_POPUP);
   }
 }
--- a/layout/generic/nsViewportFrame.h
+++ b/layout/generic/nsViewportFrame.h
@@ -22,18 +22,16 @@ class nsPresContext;
   * list.
   */
 class ViewportFrame : public nsContainerFrame {
 public:
   NS_DECL_QUERYFRAME_TARGET(ViewportFrame)
   NS_DECL_QUERYFRAME
   NS_DECL_FRAMEARENA_HELPERS
 
-  typedef nsContainerFrame Super;
-
   explicit ViewportFrame(nsStyleContext* aContext)
     : nsContainerFrame(aContext)
   {}
   virtual ~ViewportFrame() { } // useful for debugging
 
   virtual void Init(nsIContent*       aContent,
                     nsContainerFrame* aParent,
                     nsIFrame*         aPrevInFlow) override;
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -1193,19 +1193,19 @@ test-pref(dom.use_xbl_scopes_for_remote_
 == 454361.html about:blank
 == 455105-1.html 455105-ref.html
 == 455105-2.html 455105-ref.html
 == 455171-5.html 455171-5-ref.html
 == 455280-1.xhtml 455280-1-ref.xhtml
 skip-if(B2G||Mulet) == 455826-1.html 455826-1-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(B2G||Mulet) fails-if(cocoaWidget) fails-if(Android) == 456147.xul 456147-ref.html # bug 458047 # Initial mulet triage: parity with B2G/B2G Desktop
 # The next three tests are fuzzy due to bug 1128229.
-fuzzy-if(Android||B2G,11,41) fuzzy-if(d2d&&(/^Windows\x20NT\x2010\.0/.test(http.oscpu)||/^Windows\x20NT\x206\.2/.test(http.oscpu)),1,69) == 456219-1a.html 456219-1-ref.html # bug 853273
+fuzzy-if(Android||B2G,11,41) fuzzy-if(d2d&&(/^Windows\x20NT\x2010\.0/.test(http.oscpu)||/^Windows\x20NT\x206\.2/.test(http.oscpu)),1,69) fuzzy-if(gtkWidget,1,1) == 456219-1a.html 456219-1-ref.html # bug 853273
 fuzzy-if(Android||B2G,11,41) fuzzy-if(d2d&&(/^Windows\x20NT\x2010\.0/.test(http.oscpu)||/^Windows\x20NT\x206\.2/.test(http.oscpu)),1,69) == 456219-1b.html 456219-1-ref.html # bug 853273
-fuzzy-if(Android||B2G,11,41) fuzzy-if(d2d&&(/^Windows\x20NT\x2010\.0/.test(http.oscpu)||/^Windows\x20NT\x206\.2/.test(http.oscpu)),1,69) == 456219-1c.html 456219-1-ref.html # bug 853273
+fuzzy-if(Android||B2G,11,41) fuzzy-if(d2d&&(/^Windows\x20NT\x2010\.0/.test(http.oscpu)||/^Windows\x20NT\x206\.2/.test(http.oscpu)),1,69) fuzzy-if(gtkWidget,4,3) == 456219-1c.html 456219-1-ref.html # bug 853273
 fuzzy-if(skiaContent,1,45) == 456219-2.html 456219-2-ref.html
 == 456330-1.gif 456330-1-ref.png
 == 456484-1.html 456484-1-ref.html
 == 457398-1.html 457398-1-ref.html
 == 457398-2.html 457398-2-ref.html
 skip-if(B2G||Mulet) == 458296-1a.html 458296-1a-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(B2G||Mulet) == 458296-1b.html 458296-1-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(B2G||Mulet) == 458296-1c.html 458296-1-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
--- a/layout/reftests/flexbox/reftest.list
+++ b/layout/reftests/flexbox/reftest.list
@@ -104,10 +104,10 @@ fails == flexbox-inlinecontent-horiz-1b.
 skip-if(B2G||Mulet) fuzzy-if(skiaContent,1,5) == flexbox-resizeviewport-1.xhtml flexbox-resizeviewport-1-ref.xhtml # Initial mulet triage: parity with B2G/B2G Desktop
 
 # Tests for flexbox styling on things that don't support it
 == flexbox-styling-on-svg-1.svg flexbox-styling-on-svg-1-ref.svg
 
 # Tests with widgets as flex items
 fuzzy-if(gtkWidget,1,66) == flexbox-widget-flex-items-1.html flexbox-widget-flex-items-1-ref.html
 fuzzy-if(gtkWidget,1,74) == flexbox-widget-flex-items-2.html flexbox-widget-flex-items-2-ref.html
-fuzzy-if(gtkWidget,1,58) == flexbox-widget-flex-items-3.html flexbox-widget-flex-items-3-ref.html
+skip-if(gtkWidget) == flexbox-widget-flex-items-3.html flexbox-widget-flex-items-3-ref.html # bug 1260965
 fuzzy-if(gtkWidget,1,31) == flexbox-widget-flex-items-4.html flexbox-widget-flex-items-4-ref.html
--- a/layout/reftests/forms/select/reftest.list
+++ b/layout/reftests/forms/select/reftest.list
@@ -1,9 +1,9 @@
-skip-if(B2G||Mulet) == out-of-bounds-selectedindex.html out-of-bounds-selectedindex-ref.html # test for bug 471741 # Initial mulet triage: parity with B2G/B2G Desktop
+fuzzy-if(Android,2,2) skip-if(B2G||Mulet) == out-of-bounds-selectedindex.html out-of-bounds-selectedindex-ref.html # test for bug 471741 # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(B2G||Mulet) == multiple.html multiple-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 == boguskids.html boguskids-ref.html
 == dynamic-boguskids.html boguskids-ref.html
 == option-children.html option-children-ref.html
 fuzzy(1,4) == padding-button-placement.html padding-button-placement-ref.html
 HTTP(../..) == vertical-centering.html vertical-centering-ref.html
 == 997709-2.html 997709-2-ref.html
 needs-focus == focusring-1.html focusring-1-ref.html
--- a/layout/reftests/text/reftest.list
+++ b/layout/reftests/text/reftest.list
@@ -118,17 +118,17 @@ skip-if((Android)||(B2G&&browserIsRemote
 == wordbreak-5.html wordbreak-5-ref.html
 fails-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu)) == wordbreak-6.html wordbreak-6-ref.html # Bug 1258239
 skip-if(B2G||Mulet) HTTP(..) == wordbreak-7a.html wordbreak-7a-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 fails HTTP(..) == wordbreak-7b.html wordbreak-7b-ref.html # bug 479829
 == wordbreak-8.html wordbreak-8-ref.html
 pref(gfx.font_rendering.graphite.enabled,true) HTTP(..) == wordbreak-9.html wordbreak-9-ref.html
 == wordwrap-01.html wordwrap-01-ref.html
 HTTP(..) == wordwrap-02.html wordwrap-02-ref.html
-fuzzy-if(gtkWidget,1,44) fuzzy-if(skiaContent,1,50) skip-if(B2G||Mulet) HTTP(..) == wordwrap-03.html wordwrap-03-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
+fuzzy-if(gtkWidget,1,177) fuzzy-if(skiaContent,1,50) skip-if(B2G||Mulet) HTTP(..) == wordwrap-03.html wordwrap-03-ref.html # Initial mulet triage: parity with B2G/B2G Desktop # Fuzzy on Linux because the native textbox gradient is painted in a slightly different position depending on the invalid area.
 == wordwrap-04.html wordwrap-04-ref.html
 == wordwrap-05.html wordwrap-05-ref.html
 == wordwrap-06.html wordwrap-06-ref.html
 == wordwrap-07.html wordwrap-07-ref.html
 skip-if(B2G||Mulet) != wordwrap-08.html wordwrap-01-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(B2G||Mulet) == wordwrap-08.html wordwrap-08-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(B2G||Mulet) != wordwrap-09.html wordwrap-01-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 skip-if(B2G||Mulet) == wordwrap-09.html wordwrap-09-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
--- a/layout/reftests/w3c-css/submitted/masking/reftest.list
+++ b/layout/reftests/w3c-css/submitted/masking/reftest.list
@@ -1,17 +1,17 @@
 # All mask properties test cases are meant to be failed
 # until bug 1251161 is fixed, which means enabling mask shorthand.
 # To enable it in compile time, refer to bug 1243734
 
 # mask-composite test cases
 fails == mask-composite-1a.html mask-composite-1-ref.html
 fails == mask-composite-1b.html mask-composite-1-ref.html
-fails fails-if(cocoaWidget) == mask-composite-2a.html mask-composite-2-ref.html # bug 1231643;
-fails fails-if(cocoaWidget) == mask-composite-2b.html mask-composite-2-ref.html # bug 1231643;
+fails == mask-composite-2a.html mask-composite-2-ref.html
+fails == mask-composite-2b.html mask-composite-2-ref.html
 
 # mask-mode test cases
 fails == mask-mode-a.html mask-mode-ref.html
 fails == mask-mode-b.html mask-mode-ref.html
 
 # mask-image test cases
 fails == mask-image-1a.html mask-image-1-ref.html
 fails == mask-image-1b.html mask-image-1-ref.html
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -5256,17 +5256,17 @@ nsRuleNode::ComputeDisplayData(void* aSt
 
   // CSS Transitions
   uint32_t numTransitions =
     CountTransitionProps(transitionPropInfo, transitionPropData,
                          ArrayLength(transitionPropData),
                          display, parentDisplay, aRuleData,
                          conditions);
 
-  display->mTransitions.SetLength(numTransitions);
+  display->mTransitions.SetLengthNonZero(numTransitions);
 
   FOR_ALL_TRANSITION_PROPS(p) {
     const TransitionPropInfo& i = transitionPropInfo[p];
     TransitionPropData& d = transitionPropData[p];
 
     display->*(i.sdCount) = d.num;
   }
 
@@ -5413,17 +5413,17 @@ nsRuleNode::ComputeDisplayData(void* aSt
   // CSS Animations.
 
   uint32_t numAnimations =
     CountTransitionProps(animationPropInfo, animationPropData,
                          ArrayLength(animationPropData),
                          display, parentDisplay, aRuleData,
                          conditions);
 
-  display->mAnimations.SetLength(numAnimations);
+  display->mAnimations.SetLengthNonZero(numAnimations);
 
   FOR_ALL_ANIMATION_PROPS(p) {
     const TransitionPropInfo& i = animationPropInfo[p];
     TransitionPropData& d = animationPropData[p];
 
     display->*(i.sdCount) = d.num;
   }
 
@@ -6720,18 +6720,18 @@ struct BackgroundItemComputer<nsCSSValue
                "contain/cover apply to both dimensions or to neither");
   }
 };
 
 template <class ComputedValueItem>
 static void
 SetImageLayerList(nsStyleContext* aStyleContext,
                   const nsCSSValue& aValue,
-                  AutoTArray< nsStyleImageLayers::Layer, 1> &aLayers,
-                  const AutoTArray<nsStyleImageLayers::Layer, 1> &aParentLayers,
+                  nsStyleAutoArray<nsStyleImageLayers::Layer>& aLayers,
+                  const nsStyleAutoArray<nsStyleImageLayers::Layer>& aParentLayers,
                   ComputedValueItem nsStyleImageLayers::Layer::* aResultLocation,
                   ComputedValueItem aInitialValue,
                   uint32_t aParentItemCount,
                   uint32_t& aItemCount,
                   uint32_t& aMaxItemCount,
                   bool& aRebuild,
                   RuleNodeCacheConditions& aConditions)
 {
@@ -6785,19 +6785,18 @@ SetImageLayerList(nsStyleContext* aStyle
   if (aItemCount > aMaxItemCount)
     aMaxItemCount = aItemCount;
 }
 
 template <class ComputedValueItem>
 static void
 SetImageLayerPairList(nsStyleContext* aStyleContext,
                       const nsCSSValue& aValue,
-                      AutoTArray< nsStyleImageLayers::Layer, 1> &aLayers,
-                      const AutoTArray<nsStyleImageLayers::Layer, 1>
-                                                                 &aParentLayers,
+                      nsStyleAutoArray<nsStyleImageLayers::Layer>& aLayers,
+                      const nsStyleAutoArray<nsStyleImageLayers::Layer>& aParentLayers,
                       ComputedValueItem nsStyleImageLayers::Layer::*
                                                                 aResultLocation,
                       ComputedValueItem aInitialValue,
                       uint32_t aParentItemCount,
                       uint32_t& aItemCount,
                       uint32_t& aMaxItemCount,
                       bool& aRebuild,
                       RuleNodeCacheConditions& aConditions)
@@ -6852,17 +6851,18 @@ SetImageLayerPairList(nsStyleContext* aS
   }
 
   if (aItemCount > aMaxItemCount)
     aMaxItemCount = aItemCount;
 }
 
 template <class ComputedValueItem>
 static void
-FillBackgroundList(AutoTArray< nsStyleImageLayers::Layer, 1> &aLayers,
+FillBackgroundList(
+    nsStyleAutoArray<nsStyleImageLayers::Layer>& aLayers,
     ComputedValueItem nsStyleImageLayers::Layer::* aResultLocation,
     uint32_t aItemCount, uint32_t aFillCount)
 {
   NS_PRECONDITION(aFillCount <= aLayers.Length(), "unexpected array length");
   for (uint32_t sourceLayer = 0, destLayer = aItemCount;
        destLayer < aFillCount;
        ++sourceLayer, ++destLayer) {
     aLayers[destLayer].*aResultLocation =
@@ -6974,17 +6974,17 @@ nsRuleNode::ComputeBackgroundData(void* 
                         &nsStyleImageLayers::Layer::mSize,
                         initialSize, parentBG->mImage.mSizeCount,
                         bg->mImage.mSizeCount, maxItemCount, rebuild,
                         conditions);
 
   if (rebuild) {
     // Delete any extra items.  We need to keep layers in which any
     // property was specified.
-    bg->mImage.mLayers.TruncateLength(maxItemCount);
+    bg->mImage.mLayers.TruncateLengthNonZero(maxItemCount);
 
     uint32_t fillCount = bg->mImage.mImageCount;
     FillBackgroundList(bg->mImage.mLayers,
                        &nsStyleImageLayers::Layer::mImage,
                        bg->mImage.mImageCount, fillCount);
     FillBackgroundList(bg->mImage.mLayers,
                        &nsStyleImageLayers::Layer::mRepeat,
                        bg->mImage.mRepeatCount, fillCount);
@@ -9789,17 +9789,17 @@ nsRuleNode::ComputeSVGResetData(void* aS
                     &nsStyleImageLayers::Layer::mComposite,
                     uint8_t(NS_STYLE_MASK_COMPOSITE_ADD),
                     parentSVGReset->mMask.mCompositeCount,
                     svgReset->mMask.mCompositeCount, maxItemCount, rebuild, conditions);
 
   if (rebuild) {
     // Delete any extra items.  We need to keep layers in which any
     // property was specified.
-    svgReset->mMask.mLayers.TruncateLength(maxItemCount);
+    svgReset->mMask.mLayers.TruncateLengthNonZero(maxItemCount);
 
     uint32_t fillCount = svgReset->mMask.mImageCount;
 
     FillBackgroundList(svgReset->mMask.mLayers,
                        &nsStyleImageLayers::Layer::mImage,
                        svgReset->mMask.mImageCount, fillCount);
     FillBackgroundList(svgReset->mMask.mLayers,
                        &nsStyleImageLayers::Layer::mSourceURI,
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -2319,20 +2319,19 @@ nsStyleImageLayers::nsStyleImageLayers()
   , mOriginCount(1)
   , mRepeatCount(1)
   , mPositionCount(1)
   , mImageCount(1)
   , mSizeCount(1)
   , mMaskModeCount(1)
   , mBlendModeCount(1)
   , mCompositeCount(1)
+  , mLayers(nsStyleAutoArray<Layer>::WITH_SINGLE_INITIAL_ELEMENT)
 {
   MOZ_COUNT_CTOR(nsStyleImageLayers);
-  mLayers.AppendElement();
-  NS_ASSERTION(mLayers.Length() == 1, "auto array must have room for 1 element");
 }
 
 nsStyleImageLayers::nsStyleImageLayers(const nsStyleImageLayers &aSource)
   : mAttachmentCount(aSource.mAttachmentCount)
   , mClipCount(aSource.mClipCount)
   , mOriginCount(aSource.mOriginCount)
   , mRepeatCount(aSource.mRepeatCount)
   , mPositionCount(aSource.mPositionCount)
@@ -2840,16 +2839,18 @@ mozilla::StyleAnimation::operator==(cons
          mDirection == aOther.mDirection &&
          mFillMode == aOther.mFillMode &&
          mPlayState == aOther.mPlayState &&
          mIterationCount == aOther.mIterationCount;
 }
 
 nsStyleDisplay::nsStyleDisplay(StyleStructContext aContext)
   : mWillChangeBitField(0)
+  , mTransitions(nsStyleAutoArray<StyleTransition>::WITH_SINGLE_INITIAL_ELEMENT)
+  , mAnimations(nsStyleAutoArray<StyleAnimation>::WITH_SINGLE_INITIAL_ELEMENT)
 {
   MOZ_COUNT_CTOR(nsStyleDisplay);
   mAppearance = NS_THEME_NONE;
   mDisplay = NS_STYLE_DISPLAY_INLINE;
   mOriginalDisplay = mDisplay;
   mContain = NS_STYLE_CONTAIN_NONE;
   mPosition = NS_STYLE_POSITION_STATIC;
   mFloats = NS_STYLE_FLOAT_NONE;
@@ -2880,28 +2881,22 @@ nsStyleDisplay::nsStyleDisplay(StyleStru
   mScrollBehavior = NS_STYLE_SCROLL_BEHAVIOR_AUTO;
   mScrollSnapTypeX = NS_STYLE_SCROLL_SNAP_TYPE_NONE;
   mScrollSnapTypeY = NS_STYLE_SCROLL_SNAP_TYPE_NONE;
   mScrollSnapPointsX.SetNoneValue();
   mScrollSnapPointsY.SetNoneValue();
   // Initial value for mScrollSnapDestination is "0px 0px"
   mScrollSnapDestination.SetInitialZeroValues();
 
-  mTransitions.AppendElement();
-  MOZ_ASSERT(mTransitions.Length() == 1,
-             "appending within auto buffer should never fail");
   mTransitions[0].SetInitialValues();
   mTransitionTimingFunctionCount = 1;
   mTransitionDurationCount = 1;
   mTransitionDelayCount = 1;
   mTransitionPropertyCount = 1;
 
-  mAnimations.AppendElement();
-  MOZ_ASSERT(mAnimations.Length() == 1,
-             "appending within auto buffer should never fail");
   mAnimations[0].SetInitialValues();
   mAnimationTimingFunctionCount = 1;
   mAnimationDurationCount = 1;
   mAnimationDelayCount = 1;
   mAnimationNameCount = 1;
   mAnimationDirectionCount = 1;
   mAnimationFillModeCount = 1;
   mAnimationPlayStateCount = 1;
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -145,17 +145,17 @@ struct nsRect_Simple {
 
 static_assert(sizeof(nsRect_Simple) == sizeof(nsRect), "Wrong nsRect_Simple size");
 static_assert(offsetof(nsRect_Simple, x) == offsetof(nsRect, x), "Wrong nsRect_Simple member alignment");
 static_assert(offsetof(nsRect_Simple, y) == offsetof(nsRect, y), "Wrong nsRect_Simple member alignment");
 static_assert(offsetof(nsRect_Simple, width) == offsetof(nsRect, width), "Wrong nsRect_Simple member alignment");
 static_assert(offsetof(nsRect_Simple, height) == offsetof(nsRect, height), "Wrong nsRect_Simple member alignment");
 
 // The lifetime of these objects is managed by the presshell's arena.
-struct nsStyleFont
+struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleFont
 {
   nsStyleFont(const nsFont& aFont, StyleStructContext aContext);
   nsStyleFont(const nsStyleFont& aStyleFont);
   explicit nsStyleFont(StyleStructContext aContext);
   ~nsStyleFont(void) {
     MOZ_COUNT_DTOR(nsStyleFont);
   }
 
@@ -414,17 +414,17 @@ private:
 
   // This is _currently_ used only in conjunction with eStyleImageType_Image.
   nsAutoPtr<nsStyleSides> mCropRect;
 #ifdef DEBUG
   bool mImageTracked;
 #endif
 };
 
-struct nsStyleColor
+struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleColor
 {
   explicit nsStyleColor(StyleStructContext aContext);
   nsStyleColor(const nsStyleColor& aOther);
   ~nsStyleColor(void) {
     MOZ_COUNT_DTOR(nsStyleColor);
   }
 
   nsChangeHint CalcDifference(const nsStyleColor& aOther) const;
@@ -448,16 +448,75 @@ struct nsStyleColor
       FreeByObjectID(mozilla::eArenaObjectID_nsStyleColor, this);
   }
 
   // Don't add ANY members to this struct!  We can achieve caching in the rule
   // tree (rather than the style tree) by letting color stay by itself! -dwh
   nscolor mColor;                 // [inherited]
 };
 
+/**
+ * An array of objects, similar to AutoTArray<T,1> but which is memmovable. It
+ * always has length >= 1.
+ */
+template<typename T>
+class nsStyleAutoArray
+{
+public:
+  // This constructor places a single element in mFirstElement.
+  enum WithSingleInitialElement { WITH_SINGLE_INITIAL_ELEMENT };
+  explicit nsStyleAutoArray(WithSingleInitialElement) {}
+  nsStyleAutoArray(const nsStyleAutoArray& aOther) { *this = aOther; }
+  nsStyleAutoArray& operator=(const nsStyleAutoArray& aOther) {
+    mFirstElement = aOther.mFirstElement;
+    mOtherElements = aOther.mOtherElements;
+    return *this;
+  }
+
+  bool operator==(const nsStyleAutoArray& aOther) const {
+    return Length() == aOther.Length() &&
+           mFirstElement == aOther.mFirstElement &&
+           mOtherElements == aOther.mOtherElements;
+  }
+  bool operator!=(const nsStyleAutoArray& aOther) const {
+    return !(*this == aOther);
+  }
+
+  size_t Length() const {
+    return mOtherElements.Length() + 1;
+  }
+  const T& operator[](size_t aIndex) const {
+    return aIndex == 0 ? mFirstElement : mOtherElements[aIndex - 1];
+  }
+  T& operator[](size_t aIndex) {
+    return aIndex == 0 ? mFirstElement : mOtherElements[aIndex - 1];
+  }
+
+  void EnsureLengthAtLeast(size_t aMinLen) {
+    if (aMinLen > 0) {
+      mOtherElements.EnsureLengthAtLeast(aMinLen - 1);
+    }
+  }
+
+  void SetLengthNonZero(size_t aNewLen) {
+    MOZ_ASSERT(aNewLen > 0);
+    mOtherElements.SetLength(aNewLen - 1);
+  }
+
+  void TruncateLengthNonZero(size_t aNewLen) {
+    MOZ_ASSERT(aNewLen > 0);
+    MOZ_ASSERT(aNewLen <= Length());
+    mOtherElements.TruncateLength(aNewLen - 1);
+  }
+
+private:
+  T mFirstElement;
+  nsTArray<T> mOtherElements;
+};
+
 struct nsStyleImageLayers {
   nsStyleImageLayers();
   nsStyleImageLayers(const nsStyleImageLayers &aSource);
   ~nsStyleImageLayers() {
     MOZ_COUNT_DTOR(nsStyleImageLayers);
   }
 
   // Indices into kBackgroundLayerTable and kMaskLayerTable
@@ -688,17 +747,17 @@ struct nsStyleImageLayers {
   // should come from the background-image property.  We create
   // additional |Layer| objects for *any* property, not just
   // background-image.  This means that the bottommost layer that
   // callers in layout care about (which is also the one whose
   // background-clip applies to the background-color) may not be last
   // layer.  In layers below the bottom layer, properties will be
   // uninitialized unless their count, above, indicates that they are
   // present.
-  AutoTArray<Layer, 1> mLayers;
+  nsStyleAutoArray<Layer> mLayers;
 
   const Layer& BottomLayer() const { return mLayers[mImageCount - 1]; }
 
   void TrackImages(nsPresContext* aContext) {
     for (uint32_t i = 0; i < mImageCount; ++i) {
         mLayers[i].TrackImages(aContext);
     }
   }
@@ -717,17 +776,17 @@ struct nsStyleImageLayers {
   #define NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(var_, layers_) \
     for (uint32_t var_ = (layers_).mImageCount; var_-- != 0; )
   #define NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT_WITH_RANGE(var_, layers_, start_, count_) \
     NS_ASSERTION((int32_t)(start_) >= 0 && (uint32_t)(start_) < (layers_).mImageCount, "Invalid layer start!"); \
     NS_ASSERTION((count_) > 0 && (count_) <= (start_) + 1, "Invalid layer range!"); \
     for (uint32_t var_ = (start_) + 1; var_-- != (uint32_t)((start_) + 1 - (count_)); )
 };
 
-struct nsStyleBackground {
+struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleBackground {
   explicit nsStyleBackground(StyleStructContext aContext);
   nsStyleBackground(const nsStyleBackground& aOther);
   ~nsStyleBackground();
 
   void* operator new(size_t sz, nsStyleBackground* aSelf) CPP_THROW_NEW { return aSelf; }
   void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
     return aContext->PresShell()->
       AllocateByObjectID(mozilla::eArenaObjectID_nsStyleBackground, sz);
@@ -770,17 +829,17 @@ struct nsStyleBackground {
 #define BORDER_COLOR_SPECIAL      0xA0
 #define BORDER_STYLE_MASK         0x1F
 
 #define NS_SPACING_MARGIN   0
 #define NS_SPACING_PADDING  1
 #define NS_SPACING_BORDER   2
 
 
-struct nsStyleMargin
+struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleMargin
 {
   explicit nsStyleMargin(StyleStructContext aContext);
   nsStyleMargin(const nsStyleMargin& aMargin);
   ~nsStyleMargin(void) {
     MOZ_COUNT_DTOR(nsStyleMargin);
   }
 
   void* operator new(size_t sz, nsStyleMargin* aSelf) CPP_THROW_NEW { return aSelf; }
@@ -816,17 +875,17 @@ struct nsStyleMargin
   }
 
 protected:
   bool          mHasCachedMargin;
   nsMargin      mCachedMargin;
 };
 
 
-struct nsStylePadding
+struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStylePadding
 {
   explicit nsStylePadding(StyleStructContext aContext);
   nsStylePadding(const nsStylePadding& aPadding);
   ~nsStylePadding(void) {
     MOZ_COUNT_DTOR(nsStylePadding);
   }
 
   void* operator new(size_t sz, nsStylePadding* aSelf) CPP_THROW_NEW { return aSelf; }
@@ -1019,17 +1078,17 @@ private:
 
 // Returns if the given border style type is visible or not
 static bool IsVisibleBorderStyle(uint8_t aStyle)
 {
   return (aStyle != NS_STYLE_BORDER_STYLE_NONE &&
           aStyle != NS_STYLE_BORDER_STYLE_HIDDEN);
 }
 
-struct nsStyleBorder
+struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleBorder
 {
   explicit nsStyleBorder(StyleStructContext aContext);
   nsStyleBorder(const nsStyleBorder& aBorder);
   ~nsStyleBorder();
 
   void* operator new(size_t sz, nsStyleBorder* aSelf) CPP_THROW_NEW { return aSelf; }
   void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
     return aContext->PresShell()->
@@ -1246,17 +1305,17 @@ protected:
                                   // border.  not used for -moz-border-colors
 private:
   nscoord       mTwipsPerPixel;
 
   nsStyleBorder& operator=(const nsStyleBorder& aOther) = delete;
 };
 
 
-struct nsStyleOutline
+struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleOutline
 {
   explicit nsStyleOutline(StyleStructContext aContext);
   nsStyleOutline(const nsStyleOutline& aOutline);
   ~nsStyleOutline(void) {
     MOZ_COUNT_DTOR(nsStyleOutline);
   }
 
   void* operator new(size_t sz, nsStyleOutline* aSelf) CPP_THROW_NEW { return aSelf; }
@@ -1362,17 +1421,17 @@ public:
   typedef nsTArray<std::pair<nsString, nsString>> QuotePairArray;
   NS_INLINE_DECL_REFCOUNTING(nsStyleQuoteValues);
   QuotePairArray mQuotePairs;
 
 private:
   ~nsStyleQuoteValues() {}
 };
 
-struct nsStyleList
+struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleList
 {
   explicit nsStyleList(StyleStructContext aContext);
   nsStyleList(const nsStyleList& aStyleList);
   ~nsStyleList(void);
 
   void* operator new(size_t sz, nsStyleList* aSelf) CPP_THROW_NEW { return aSelf; }
   void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
     return aContext->PresShell()->
@@ -1588,17 +1647,17 @@ struct nsStyleGridTemplate
   }
 
   bool IsRepeatAutoIndex(uint32_t aIndex) const {
     MOZ_ASSERT(aIndex < uint32_t(2*nsStyleGridLine::kMaxLine));
     return int32_t(aIndex) == mRepeatAutoIndex;
   }
 };
 
-struct nsStylePosition
+struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStylePosition
 {
   explicit nsStylePosition(StyleStructContext aContext);
   nsStylePosition(const nsStylePosition& aOther);
   ~nsStylePosition(void);
 
   void* operator new(size_t sz, nsStylePosition* aSelf) CPP_THROW_NEW { return aSelf; }
   void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
     return aContext->PresShell()->
@@ -1839,17 +1898,17 @@ struct nsStyleTextOverflow
     return mLogicalDirections ? nullptr : &mRight;
   }
 
   nsStyleTextOverflowSide mLeft;  // start side when mLogicalDirections is true
   nsStyleTextOverflowSide mRight; // end side when mLogicalDirections is true
   bool mLogicalDirections;  // true when only one value was specified
 };
 
-struct nsStyleTextReset
+struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleTextReset
 {
   explicit nsStyleTextReset(StyleStructContext aContext);
   nsStyleTextReset(const nsStyleTextReset& aOther);
   ~nsStyleTextReset(void);
 
   void* operator new(size_t sz, nsStyleTextReset* aSelf) CPP_THROW_NEW { return aSelf; }
   void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
     return aContext->PresShell()->
@@ -1924,17 +1983,17 @@ struct nsStyleTextReset
   uint8_t mTextDecorationLine;          // [reset] see nsStyleConsts.h
   uint8_t mUnicodeBidi;                 // [reset] see nsStyleConsts.h
 protected:
   uint8_t mTextDecorationStyle;         // [reset] see nsStyleConsts.h
 
   nscolor mTextDecorationColor;         // [reset] the colors to use for a decoration lines, not used at currentColor
 };
 
-struct nsStyleText
+struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleText
 {
   explicit nsStyleText(StyleStructContext aContext);
   nsStyleText(const nsStyleText& aOther);
   ~nsStyleText(void);
 
   void* operator new(size_t sz, nsStyleText* aSelf) CPP_THROW_NEW { return aSelf; }
   void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
     return aContext->PresShell()->
@@ -2134,17 +2193,17 @@ protected:
 
   explicit nsStyleImageOrientation(uint8_t aOrientation)
     : mOrientation(aOrientation)
   { }
 
   uint8_t mOrientation;
 };
 
-struct nsStyleVisibility
+struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleVisibility
 {
   explicit nsStyleVisibility(StyleStructContext aContext);
   nsStyleVisibility(const nsStyleVisibility& aVisibility);
   ~nsStyleVisibility() {
     MOZ_COUNT_DTOR(nsStyleVisibility);
   }
 
   void* operator new(size_t sz, nsStyleVisibility* aSelf) CPP_THROW_NEW { return aSelf; }
@@ -2415,17 +2474,17 @@ private:
   dom::PlaybackDirection mDirection;
   dom::FillMode mFillMode;
   uint8_t mPlayState;
   float mIterationCount; // mozilla::PositiveInfinity<float>() means infinite
 };
 
 } // namespace mozilla
 
-struct nsStyleDisplay
+struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleDisplay
 {
   explicit nsStyleDisplay(StyleStructContext aContext);
   nsStyleDisplay(const nsStyleDisplay& aOther);
   ~nsStyleDisplay() {
     MOZ_COUNT_DTOR(nsStyleDisplay);
   }
 
   void* operator new(size_t sz, nsStyleDisplay* aSelf) CPP_THROW_NEW { return aSelf; }
@@ -2486,17 +2545,17 @@ struct nsStyleDisplay
   uint8_t mIsolation;           // [reset] see nsStyleConsts.h
   uint8_t mTopLayer;            // [reset] see nsStyleConsts.h
   uint8_t mWillChangeBitField;  // [reset] see nsStyleConsts.h. Stores a
                                 // bitfield representation of the properties
                                 // that are frequently queried. This should
                                 // match mWillChange. Also tracks if any of the
                                 // properties in the will-change list require
                                 // a stacking context.
-  AutoTArray<nsString, 1> mWillChange;
+  nsTArray<nsString> mWillChange;
 
   uint8_t mTouchAction;         // [reset] see nsStyleConsts.h
   uint8_t mScrollBehavior;      // [reset] see nsStyleConsts.h NS_STYLE_SCROLL_BEHAVIOR_*
   uint8_t mScrollSnapTypeX;     // [reset] see nsStyleConsts.h NS_STYLE_SCROLL_SNAP_TYPE_*
   uint8_t mScrollSnapTypeY;     // [reset] see nsStyleConsts.h NS_STYLE_SCROLL_SNAP_TYPE_*
   nsStyleCoord mScrollSnapPointsX; // [reset]
   nsStyleCoord mScrollSnapPointsY; // [reset]
   Position mScrollSnapDestination; // [reset]
@@ -2511,25 +2570,25 @@ struct nsStyleDisplay
   uint8_t mTransformBox;        // [reset] see nsStyleConsts.h
   RefPtr<nsCSSValueSharedList> mSpecifiedTransform; // [reset]
   nsStyleCoord mTransformOrigin[3]; // [reset] percent, coord, calc, 3rd param is coord, calc only
   nsStyleCoord mChildPerspective; // [reset] none, coord
   nsStyleCoord mPerspectiveOrigin[2]; // [reset] percent, coord, calc
 
   nsStyleCoord mVerticalAlign;  // [reset] coord, percent, calc, enum (see nsStyleConsts.h)
 
-  AutoTArray<mozilla::StyleTransition, 1> mTransitions; // [reset]
+  nsStyleAutoArray<mozilla::StyleTransition> mTransitions; // [reset]
   // The number of elements in mTransitions that are not from repeating
   // a list due to another property being longer.
   uint32_t mTransitionTimingFunctionCount,
            mTransitionDurationCount,
            mTransitionDelayCount,
            mTransitionPropertyCount;
 
-  AutoTArray<mozilla::StyleAnimation, 1> mAnimations; // [reset]
+  nsStyleAutoArray<mozilla::StyleAnimation> mAnimations; // [reset]
   // The number of elements in mAnimations that are not from repeating
   // a list due to another property being longer.
   uint32_t mAnimationTimingFunctionCount,
            mAnimationDurationCount,
            mAnimationDelayCount,
            mAnimationNameCount,
            mAnimationDirectionCount,
            mAnimationFillModeCount,
@@ -2687,17 +2746,17 @@ struct nsStyleDisplay
 
   // Return the 'float' and 'clear' properties, with inline-{start,end} values
   // resolved to {left,right} according to the given writing mode. These are
   // defined in WritingModes.h.
   inline uint8_t PhysicalFloats(mozilla::WritingMode aWM) const;
   inline uint8_t PhysicalBreakType(mozilla::WritingMode aWM) const;
 };
 
-struct nsStyleTable
+struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleTable
 {
   explicit nsStyleTable(StyleStructContext aContext);
   nsStyleTable(const nsStyleTable& aOther);
   ~nsStyleTable(void);
 
   void* operator new(size_t sz, nsStyleTable* aSelf) CPP_THROW_NEW { return aSelf; }
   void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
     return aContext->PresShell()->
@@ -2720,17 +2779,17 @@ struct nsStyleTable
            nsChangeHint_ReflowChangesSizeOrPosition |
            nsChangeHint_ClearAncestorIntrinsics;
   }
 
   uint8_t       mLayoutStrategy;// [reset] see nsStyleConsts.h NS_STYLE_TABLE_LAYOUT_*
   int32_t       mSpan;          // [reset] the number of columns spanned by a colgroup or col
 };
 
-struct nsStyleTableBorder
+struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleTableBorder
 {
   explicit nsStyleTableBorder(StyleStructContext aContext);
   nsStyleTableBorder(const nsStyleTableBorder& aOther);
   ~nsStyleTableBorder(void);
 
   void* operator new(size_t sz, nsStyleTableBorder* aSelf) CPP_THROW_NEW { return aSelf; }
   void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
     return aContext->PresShell()->
@@ -2820,17 +2879,17 @@ struct nsStyleCounterData
 {
   nsString  mCounter;
   int32_t   mValue;
 };
 
 
 #define DELETE_ARRAY_IF(array)  if (array) { delete[] array; array = nullptr; }
 
-struct nsStyleContent
+struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleContent
 {
   explicit nsStyleContent(StyleStructContext aContext);
   nsStyleContent(const nsStyleContent& aContent);
   ~nsStyleContent(void);
 
   void* operator new(size_t sz, nsStyleContent* aSelf) CPP_THROW_NEW { return aSelf; }
   void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
     return aContext->PresShell()->
@@ -2931,17 +2990,17 @@ protected:
   nsStyleCounterData* mIncrements;
   nsStyleCounterData* mResets;
 
   uint32_t            mContentCount;
   uint32_t            mIncrementCount;
   uint32_t            mResetCount;
 };
 
-struct nsStyleUIReset
+struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleUIReset
 {
   explicit nsStyleUIReset(StyleStructContext aContext);
   nsStyleUIReset(const nsStyleUIReset& aOther);
   ~nsStyleUIReset(void);
 
   void* operator new(size_t sz, nsStyleUIReset* aSelf) CPP_THROW_NEW { return aSelf; }
   void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
     return aContext->PresShell()->
@@ -2997,17 +3056,17 @@ struct nsCursorImage
   imgIRequest* GetImage() const {
     return mImage;
   }
 
 private:
   nsCOMPtr<imgIRequest> mImage;
 };
 
-struct nsStyleUserInterface
+struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleUserInterface
 {
   explicit nsStyleUserInterface(StyleStructContext aContext);
   nsStyleUserInterface(const nsStyleUserInterface& aOther);
   ~nsStyleUserInterface(void);
 
   void* operator new(size_t sz, nsStyleUserInterface* aSelf) CPP_THROW_NEW { return aSelf; }
   void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
     return aContext->PresShell()->
@@ -3048,17 +3107,17 @@ struct nsStyleUserInterface
 
   // Does not free mCursorArray; the caller is responsible for calling
   // |delete [] mCursorArray| first if it is needed.
   void CopyCursorArrayFrom(const nsStyleUserInterface& aSource);
 
   inline uint8_t GetEffectivePointerEvents(nsIFrame* aFrame) const;
 };
 
-struct nsStyleXUL
+struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleXUL
 {
   explicit nsStyleXUL(StyleStructContext aContext);
   nsStyleXUL(const nsStyleXUL& aSource);
   ~nsStyleXUL();
 
   void* operator new(size_t sz, nsStyleXUL* aSelf) CPP_THROW_NEW { return aSelf; }
   void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
     return aContext->PresShell()->
@@ -3086,17 +3145,17 @@ struct nsStyleXUL
   uint32_t      mBoxOrdinal;            // [reset] see nsStyleConsts.h
   uint8_t       mBoxAlign;              // [reset] see nsStyleConsts.h
   uint8_t       mBoxDirection;          // [reset] see nsStyleConsts.h
   uint8_t       mBoxOrient;             // [reset] see nsStyleConsts.h
   uint8_t       mBoxPack;               // [reset] see nsStyleConsts.h
   bool          mStretchStack;          // [reset] see nsStyleConsts.h
 };
 
-struct nsStyleColumn
+struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleColumn
 {
   explicit nsStyleColumn(StyleStructContext aContext);
   nsStyleColumn(const nsStyleColumn& aSource);
   ~nsStyleColumn();
 
   void* operator new(size_t sz, nsStyleColumn* aSelf) CPP_THROW_NEW { return aSelf; }
   void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
     return aContext->PresShell()->
@@ -3181,17 +3240,17 @@ struct nsStyleSVGPaint
   nsStyleSVGPaint& operator=(const nsStyleSVGPaint& aOther);
   bool operator==(const nsStyleSVGPaint& aOther) const;
 
   bool operator!=(const nsStyleSVGPaint& aOther) const {
     return !(*this == aOther);
   }
 };
 
-struct nsStyleSVG
+struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleSVG
 {
   explicit nsStyleSVG(StyleStructContext aContext);
   nsStyleSVG(const nsStyleSVG& aSource);
   ~nsStyleSVG();
 
   void* operator new(size_t sz, nsStyleSVG* aSelf) CPP_THROW_NEW { return aSelf; }
   void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
     return aContext->PresShell()->
@@ -3467,17 +3526,17 @@ private:
 };
 
 template<>
 struct nsTArray_CopyChooser<nsStyleFilter>
 {
   typedef nsTArray_CopyWithConstructors<nsStyleFilter> Type;
 };
 
-struct nsStyleSVGReset
+struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleSVGReset
 {
   explicit nsStyleSVGReset(StyleStructContext aContext);
   nsStyleSVGReset(const nsStyleSVGReset& aSource);
   ~nsStyleSVGReset();
 
   void* operator new(size_t sz, nsStyleSVGReset* aSelf) CPP_THROW_NEW { return aSelf; }
   void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
     return aContext->PresShell()->
@@ -3517,17 +3576,17 @@ struct nsStyleSVGReset
   float            mStopOpacity;      // [reset]
   float            mFloodOpacity;     // [reset]
 
   uint8_t          mDominantBaseline; // [reset] see nsStyleConsts.h
   uint8_t          mVectorEffect;     // [reset] see nsStyleConsts.h
   uint8_t          mMaskType;         // [reset] see nsStyleConsts.h
 };
 
-struct nsStyleVariables
+struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleVariables
 {
   explicit nsStyleVariables(StyleStructContext aContext);
   nsStyleVariables(const nsStyleVariables& aSource);
   ~nsStyleVariables();
 
   void* operator new(size_t sz, nsStyleVariables* aSelf) CPP_THROW_NEW { return aSelf; }
   void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
     return aContext->PresShell()->
@@ -3547,17 +3606,17 @@ struct nsStyleVariables
     // CalcDifference never returns nsChangeHint_NeedReflow or
     // nsChangeHint_ClearAncestorIntrinsics at all.
     return nsChangeHint(0);
   }
 
   mozilla::CSSVariableValues mVariables;
 };
 
-struct nsStyleEffects
+struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleEffects
 {
   explicit nsStyleEffects(StyleStructContext aContext);
   nsStyleEffects(const nsStyleEffects& aSource);
   ~nsStyleEffects();
 
   void* operator new(size_t sz, nsStyleEffects* aSelf) CPP_THROW_NEW { return aSelf; }
   void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
     return aContext->PresShell()->
--- a/layout/svg/SVGFEContainerFrame.cpp
+++ b/layout/svg/SVGFEContainerFrame.cpp
@@ -6,39 +6,37 @@
 // Keep in (case-insensitive) order:
 #include "nsContainerFrame.h"
 #include "nsGkAtoms.h"
 #include "nsIFrame.h"
 #include "nsLiteralString.h"
 #include "nsSVGEffects.h"
 #include "nsSVGFilters.h"
 
-typedef nsContainerFrame SVGFEContainerFrameBase;
-
 /*
  * This frame is used by filter primitive elements that
  * have special child elements that provide parameters.
  */
-class SVGFEContainerFrame : public SVGFEContainerFrameBase
+class SVGFEContainerFrame : public nsContainerFrame
 {
   friend nsIFrame*
   NS_NewSVGFEContainerFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 protected:
   explicit SVGFEContainerFrame(nsStyleContext* aContext)
-    : SVGFEContainerFrameBase(aContext)
+    : nsContainerFrame(aContext)
   {
     AddStateBits(NS_FRAME_SVG_LAYOUT | NS_FRAME_IS_NONDISPLAY);
   }
 
 public:
   NS_DECL_FRAMEARENA_HELPERS
 
   virtual bool IsFrameOfType(uint32_t aFlags) const override
   {
-    return SVGFEContainerFrameBase::IsFrameOfType(
+    return nsContainerFrame::IsFrameOfType(
             aFlags & ~(nsIFrame::eSVG | nsIFrame::eSVGContainer));
   }
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const override
   {
     return MakeFrameName(NS_LITERAL_STRING("SVGFEContainer"), aResult);
   }
@@ -79,17 +77,17 @@ void
 SVGFEContainerFrame::Init(nsIContent*       aContent,
                           nsContainerFrame* aParent,
                           nsIFrame*         aPrevInFlow)
 {
   NS_ASSERTION(aContent->IsNodeOfType(nsINode::eFILTER),
                "Trying to construct an SVGFEContainerFrame for a "
                "content element that doesn't support the right interfaces");
 
-  SVGFEContainerFrameBase::Init(aContent, aParent, aPrevInFlow);
+  nsContainerFrame::Init(aContent, aParent, aPrevInFlow);
 }
 #endif /* DEBUG */
 
 nsIAtom *
 SVGFEContainerFrame::GetType() const
 {
   return nsGkAtoms::svgFEContainerFrame;
 }
@@ -101,11 +99,10 @@ SVGFEContainerFrame::AttributeChanged(in
 {
   nsSVGFE *element = static_cast<nsSVGFE*>(mContent);
   if (element->AttributeAffectsRendering(aNameSpaceID, aAttribute)) {
     MOZ_ASSERT(GetParent()->GetType() == nsGkAtoms::svgFilterFrame,
                "Observers observe the filter, so that's what we must invalidate");
     nsSVGEffects::InvalidateDirectRenderingObservers(GetParent());
   }
 
-  return SVGFEContainerFrameBase::AttributeChanged(aNameSpaceID,
-                                                     aAttribute, aModType);
+  return nsContainerFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
 }
--- a/layout/svg/SVGFEImageFrame.cpp
+++ b/layout/svg/SVGFEImageFrame.cpp
@@ -11,25 +11,23 @@
 #include "nsLiteralString.h"
 #include "nsSVGEffects.h"
 #include "nsSVGFilters.h"
 #include "mozilla/dom/SVGFEImageElement.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
-typedef nsFrame SVGFEImageFrameBase;
-
-class SVGFEImageFrame : public SVGFEImageFrameBase
+class SVGFEImageFrame : public nsFrame
 {
   friend nsIFrame*
   NS_NewSVGFEImageFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 protected:
   explicit SVGFEImageFrame(nsStyleContext* aContext)
-    : SVGFEImageFrameBase(aContext)
+    : nsFrame(aContext)
   {
     AddStateBits(NS_FRAME_SVG_LAYOUT | NS_FRAME_IS_NONDISPLAY);
 
     // This frame isn't actually displayed, but it contains an image and we want
     // to use the nsImageLoadingContent machinery for managing images, which
     // requires visibility tracking, so we enable visibility tracking and
     // forcibly mark it visible below.
     EnableVisibilityTracking();
@@ -40,17 +38,17 @@ public:
 
   virtual void Init(nsIContent*       aContent,
                     nsContainerFrame* aParent,
                     nsIFrame*         aPrevInFlow) override;
   virtual void DestroyFrom(nsIFrame* aDestructRoot) override;
 
   virtual bool IsFrameOfType(uint32_t aFlags) const override
   {
-    return SVGFEImageFrameBase::IsFrameOfType(aFlags & ~(nsIFrame::eSVG));
+    return nsFrame::IsFrameOfType(aFlags & ~(nsIFrame::eSVG));
   }
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const override
   {
     return MakeFrameName(NS_LITERAL_STRING("SVGFEImage"), aResult);
   }
 #endif
@@ -84,40 +82,40 @@ NS_NewSVGFEImageFrame(nsIPresShell* aPre
 NS_IMPL_FRAMEARENA_HELPERS(SVGFEImageFrame)
 
 /* virtual */ void
 SVGFEImageFrame::DestroyFrom(nsIFrame* aDestructRoot)
 {
   DecApproximateVisibleCount();
 
   nsCOMPtr<nsIImageLoadingContent> imageLoader =
-    do_QueryInterface(SVGFEImageFrameBase::mContent);
+    do_QueryInterface(nsFrame::mContent);
   if (imageLoader) {
     imageLoader->FrameDestroyed(this);
   }
 
-  SVGFEImageFrameBase::DestroyFrom(aDestructRoot);
+  nsFrame::DestroyFrom(aDestructRoot);
 }
 
 void
 SVGFEImageFrame::Init(nsIContent*       aContent,
                       nsContainerFrame* aParent,
                       nsIFrame*         aPrevInFlow)
 {
   NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::feImage),
                "Trying to construct an SVGFEImageFrame for a "
                "content element that doesn't support the right interfaces");
 
-  SVGFEImageFrameBase::Init(aContent, aParent, aPrevInFlow);
+  nsFrame::Init(aContent, aParent, aPrevInFlow);
 
   // We assume that feImage's are always visible.
   IncApproximateVisibleCount();
 
   nsCOMPtr<nsIImageLoadingContent> imageLoader =
-    do_QueryInterface(SVGFEImageFrameBase::mContent);
+    do_QueryInterface(nsFrame::mContent);
   if (imageLoader) {
     imageLoader->FrameCreated(this);
   }
 }
 
 nsIAtom *
 SVGFEImageFrame::GetType() const
 {
@@ -139,28 +137,27 @@ SVGFEImageFrame::AttributeChanged(int32_
       aAttribute == nsGkAtoms::href) {
     if (element->mStringAttributes[SVGFEImageElement::HREF].IsExplicitlySet()) {
       element->LoadSVGImage(true, true);
     } else {
       element->CancelImageRequests(true);
     }
   }
 
-  return SVGFEImageFrameBase::AttributeChanged(aNameSpaceID,
-                                               aAttribute, aModType);
+  return nsFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
 }
 
 void
 SVGFEImageFrame::OnVisibilityChange(Visibility aNewVisibility,
                                     Maybe<OnNonvisible> aNonvisibleAction)
 {
   nsCOMPtr<nsIImageLoadingContent> imageLoader =
-    do_QueryInterface(SVGFEImageFrameBase::mContent);
+    do_QueryInterface(nsFrame::mContent);
   if (!imageLoader) {
     MOZ_ASSERT_UNREACHABLE("Should have an nsIImageLoadingContent");
-    SVGFEImageFrameBase::OnVisibilityChange(aNewVisibility, aNonvisibleAction);
+    nsFrame::OnVisibilityChange(aNewVisibility, aNonvisibleAction);
     return;
   }
 
   imageLoader->OnVisibilityChange(aNewVisibility, aNonvisibleAction);
 
-  SVGFEImageFrameBase::OnVisibilityChange(aNewVisibility, aNonvisibleAction);
+  nsFrame::OnVisibilityChange(aNewVisibility, aNonvisibleAction);
 }
--- a/layout/svg/SVGFELeafFrame.cpp
+++ b/layout/svg/SVGFELeafFrame.cpp
@@ -5,45 +5,43 @@
 
 // Keep in (case-insensitive) order:
 #include "nsContainerFrame.h"
 #include "nsFrame.h"
 #include "nsGkAtoms.h"
 #include "nsSVGEffects.h"
 #include "nsSVGFilters.h"
 
-typedef nsFrame SVGFELeafFrameBase;
-
 /*
  * This frame is used by filter primitive elements that don't
  * have special child elements that provide parameters.
  */
-class SVGFELeafFrame : public SVGFELeafFrameBase
+class SVGFELeafFrame : public nsFrame
 {
   friend nsIFrame*
   NS_NewSVGFELeafFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 protected:
   explicit SVGFELeafFrame(nsStyleContext* aContext)
-    : SVGFELeafFrameBase(aContext)
+    : nsFrame(aContext)
   {
     AddStateBits(NS_FRAME_SVG_LAYOUT | NS_FRAME_IS_NONDISPLAY);
   }
 
 public:
   NS_DECL_FRAMEARENA_HELPERS
 
 #ifdef DEBUG
   virtual void Init(nsIContent*       aContent,
                     nsContainerFrame* aParent,
                     nsIFrame*         aPrevInFlow) override;
 #endif
 
   virtual bool IsFrameOfType(uint32_t aFlags) const override
   {
-    return SVGFELeafFrameBase::IsFrameOfType(aFlags & ~(nsIFrame::eSVG));
+    return nsFrame::IsFrameOfType(aFlags & ~(nsIFrame::eSVG));
   }
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const override
   {
     return MakeFrameName(NS_LITERAL_STRING("SVGFELeaf"), aResult);
   }
 #endif
@@ -78,17 +76,17 @@ void
 SVGFELeafFrame::Init(nsIContent*       aContent,
                      nsContainerFrame* aParent,
                      nsIFrame*         aPrevInFlow)
 {
   NS_ASSERTION(aContent->IsNodeOfType(nsINode::eFILTER),
                "Trying to construct an SVGFELeafFrame for a "
                "content element that doesn't support the right interfaces");
 
-  SVGFELeafFrameBase::Init(aContent, aParent, aPrevInFlow);
+  nsFrame::Init(aContent, aParent, aPrevInFlow);
 }
 #endif /* DEBUG */
 
 nsIAtom *
 SVGFELeafFrame::GetType() const
 {
   return nsGkAtoms::svgFELeafFrame;
 }
@@ -100,11 +98,10 @@ SVGFELeafFrame::AttributeChanged(int32_t
 {
   nsSVGFE *element = static_cast<nsSVGFE*>(mContent);
   if (element->AttributeAffectsRendering(aNameSpaceID, aAttribute)) {
     MOZ_ASSERT(GetParent()->GetType() == nsGkAtoms::svgFilterFrame,
                "Observers observe the filter, so that's what we must invalidate");
     nsSVGEffects::InvalidateDirectRenderingObservers(GetParent());
   }
 
-  return SVGFELeafFrameBase::AttributeChanged(aNameSpaceID,
-                                              aAttribute, aModType);
+  return nsFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
 }
--- a/layout/svg/SVGFEUnstyledLeafFrame.cpp
+++ b/layout/svg/SVGFEUnstyledLeafFrame.cpp
@@ -5,39 +5,37 @@
 
 // Keep in (case-insensitive) order:
 #include "nsContainerFrame.h"
 #include "nsFrame.h"
 #include "nsGkAtoms.h"
 #include "nsSVGEffects.h"
 #include "nsSVGFilters.h"
 
-typedef nsFrame SVGFEUnstyledLeafFrameBase;
-
-class SVGFEUnstyledLeafFrame : public SVGFEUnstyledLeafFrameBase
+class SVGFEUnstyledLeafFrame : public nsFrame
 {
   friend nsIFrame*
   NS_NewSVGFEUnstyledLeafFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 protected:
   explicit SVGFEUnstyledLeafFrame(nsStyleContext* aContext)
-    : SVGFEUnstyledLeafFrameBase(aContext)
+    : nsFrame(aContext)
   {
     AddStateBits(NS_FRAME_SVG_LAYOUT | NS_FRAME_IS_NONDISPLAY);
   }
 
 public:
   NS_DECL_FRAMEARENA_HELPERS
 
   virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder,
                                 const nsRect&           aDirtyRect,
                                 const nsDisplayListSet& aLists) override {}
 
   virtual bool IsFrameOfType(uint32_t aFlags) const override
   {
-    return SVGFEUnstyledLeafFrameBase::IsFrameOfType(aFlags & ~(nsIFrame::eSVG));
+    return nsFrame::IsFrameOfType(aFlags & ~(nsIFrame::eSVG));
   }
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const override
   {
     return MakeFrameName(NS_LITERAL_STRING("SVGFEUnstyledLeaf"), aResult);
   }
 #endif
@@ -80,11 +78,10 @@ SVGFEUnstyledLeafFrame::AttributeChanged
 {
   SVGFEUnstyledElement *element = static_cast<SVGFEUnstyledElement*>(mContent);
   if (element->AttributeAffectsRendering(aNameSpaceID, aAttribute)) {
     MOZ_ASSERT(GetParent()->GetParent()->GetType() == nsGkAtoms::svgFilterFrame,
                "Observers observe the filter, so that's what we must invalidate");
     nsSVGEffects::InvalidateDirectRenderingObservers(GetParent()->GetParent());
   }
 
-  return SVGFEUnstyledLeafFrameBase::AttributeChanged(aNameSpaceID,
-                                                        aAttribute, aModType);
+  return nsFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
 }
--- a/layout/svg/SVGTextFrame.cpp
+++ b/layout/svg/SVGTextFrame.cpp
@@ -3204,17 +3204,17 @@ nsDisplaySVGText::Paint(nsDisplayListBui
   ctx->Restore();
 }
 
 // ---------------------------------------------------------------------
 // nsQueryFrame methods
 
 NS_QUERYFRAME_HEAD(SVGTextFrame)
   NS_QUERYFRAME_ENTRY(SVGTextFrame)
-NS_QUERYFRAME_TAIL_INHERITING(SVGTextFrameBase)
+NS_QUERYFRAME_TAIL_INHERITING(nsSVGDisplayContainerFrame)
 
 // ---------------------------------------------------------------------
 // Implementation
 
 nsIFrame*
 NS_NewSVGTextFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
   return new (aPresShell) SVGTextFrame(aContext);
@@ -3227,17 +3227,17 @@ NS_IMPL_FRAMEARENA_HELPERS(SVGTextFrame)
 
 void
 SVGTextFrame::Init(nsIContent*       aContent,
                    nsContainerFrame* aParent,
                    nsIFrame*         aPrevInFlow)
 {
   NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::text), "Content is not an SVG text");
 
-  SVGTextFrameBase::Init(aContent, aParent, aPrevInFlow);
+  nsSVGDisplayContainerFrame::Init(aContent, aParent, aPrevInFlow);
   AddStateBits((aParent->GetStateBits() & NS_STATE_SVG_CLIPPATH_CHILD) |
                NS_FRAME_SVG_LAYOUT | NS_FRAME_IS_SVG_TEXT);
 
   mMutationObserver = new MutationObserver(this);
 }
 
 void
 SVGTextFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
@@ -3921,17 +3921,17 @@ SVGTextFrame::ReflowSVG()
 
   nsRect overflow = nsRect(nsPoint(0,0), mRect.Size());
   nsOverflowAreas overflowAreas(overflow, overflow);
   FinishAndStoreOverflow(overflowAreas, mRect.Size());
 
   // XXX nsSVGContainerFrame::ReflowSVG only looks at its nsISVGChildFrame
   // children, and calls ConsiderChildOverflow on them.  Does it matter
   // that ConsiderChildOverflow won't be called on our children?
-  SVGTextFrameBase::ReflowSVG();
+  nsSVGDisplayContainerFrame::ReflowSVG();
 }
 
 /**
  * Converts nsSVGUtils::eBBox* flags into TextRenderedRun flags appropriate
  * for the specified rendered run.
  */
 static uint32_t
 TextRenderedRunFlagsForBBoxContribution(const TextRenderedRun& aRun,
--- a/layout/svg/SVGTextFrame.h
+++ b/layout/svg/SVGTextFrame.h
@@ -17,18 +17,16 @@
 #include "nsStubMutationObserver.h"
 #include "nsSVGPaintServerFrame.h"
 
 class gfxContext;
 class nsDisplaySVGText;
 class SVGTextFrame;
 class nsTextFrame;
 
-typedef nsSVGDisplayContainerFrame SVGTextFrameBase;
-
 namespace mozilla {
 
 class CharIterator;
 class nsISVGPoint;
 class TextFrameIterator;
 class TextNodeCorrespondenceRecorder;
 struct TextRenderedRun;
 class TextRenderedRunIterator;
@@ -240,17 +238,17 @@ public:
  * object.  The TextRenderedRunIterator class performs that splitting and
  * returns a TextRenderedRun for each bit of text to be painted separately.
  *
  * Each rendered run is painted by calling nsTextFrame::PaintText.  If the text
  * formatting is simple enough (solid fill, no stroking, etc.), PaintText will
  * itself do the painting.  Otherwise, a DrawPathCallback is passed to
  * PaintText so that we can fill the text geometry with SVG paint servers.
  */
-class SVGTextFrame final : public SVGTextFrameBase
+class SVGTextFrame final : public nsSVGDisplayContainerFrame
 {
   friend nsIFrame*
   NS_NewSVGTextFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 
   friend class mozilla::CharIterator;
   friend class mozilla::GlyphMetricsUpdater;
   friend class mozilla::TextFrameIterator;
   friend class mozilla::TextNodeCorrespondenceRecorder;
@@ -262,20 +260,20 @@ class SVGTextFrame final : public SVGTex
   typedef gfxTextRun::Range Range;
   typedef mozilla::gfx::DrawTarget DrawTarget;
   typedef mozilla::gfx::Path Path;
   typedef mozilla::gfx::Point Point;
   typedef mozilla::SVGTextContextPaint SVGTextContextPaint;
 
 protected:
   explicit SVGTextFrame(nsStyleContext* aContext)
-    : SVGTextFrameBase(aContext),
-      mFontSizeScaleFactor(1.0f),
-      mLastContextScale(1.0f),
-      mLengthAdjustScaleFactor(1.0f)
+    : nsSVGDisplayContainerFrame(aContext)
+    , mFontSizeScaleFactor(1.0f)
+    , mLastContextScale(1.0f)
+    , mLengthAdjustScaleFactor(1.0f)
   {
     AddStateBits(NS_STATE_SVG_POSITIONING_DIRTY);
   }
 
   ~SVGTextFrame() {}
 
 public:
   NS_DECL_QUERYFRAME_TARGET(SVGTextFrame)
--- a/layout/svg/SVGViewFrame.cpp
+++ b/layout/svg/SVGViewFrame.cpp
@@ -5,49 +5,47 @@
 
 // Keep in (case-insensitive) order:
 #include "nsFrame.h"
 #include "nsGkAtoms.h"
 #include "nsSVGOuterSVGFrame.h"
 #include "mozilla/dom/SVGSVGElement.h"
 #include "mozilla/dom/SVGViewElement.h"
 
-typedef nsFrame SVGViewFrameBase;
-
 using namespace mozilla::dom;
 
 /**
  * While views are not directly rendered in SVG they can be linked to
  * and thereby override attributes of an <svg> element via a fragment
  * identifier. The SVGViewFrame class passes on any attribute changes
  * the view receives to the overridden <svg> element (if there is one).
  **/
-class SVGViewFrame : public SVGViewFrameBase
+class SVGViewFrame : public nsFrame
 {
   friend nsIFrame*
   NS_NewSVGViewFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 protected:
   explicit SVGViewFrame(nsStyleContext* aContext)
-    : SVGViewFrameBase(aContext)
+    : nsFrame(aContext)
   {
     AddStateBits(NS_FRAME_IS_NONDISPLAY);
   }
 
 public:
   NS_DECL_FRAMEARENA_HELPERS
 
 #ifdef DEBUG
   virtual void Init(nsIContent*       aContent,
                     nsContainerFrame* aParent,
                     nsIFrame*         aPrevInFlow) override;
 #endif
 
   virtual bool IsFrameOfType(uint32_t aFlags) const override
   {
-    return SVGViewFrameBase::IsFrameOfType(aFlags & ~(nsIFrame::eSVG));
+    return nsFrame::IsFrameOfType(aFlags & ~(nsIFrame::eSVG));
   }
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const override
   {
     return MakeFrameName(NS_LITERAL_STRING("SVGView"), aResult);
   }
 #endif
@@ -81,17 +79,17 @@ NS_IMPL_FRAMEARENA_HELPERS(SVGViewFrame)
 void
 SVGViewFrame::Init(nsIContent*       aContent,
                    nsContainerFrame* aParent,
                    nsIFrame*         aPrevInFlow)
 {
   NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::view),
                "Content is not an SVG view");
 
-  SVGViewFrameBase::Init(aContent, aParent, aPrevInFlow);
+  nsFrame::Init(aContent, aParent, aPrevInFlow);
 }
 #endif /* DEBUG */
 
 nsIAtom *
 SVGViewFrame::GetType() const
 {
   return nsGkAtoms::svgViewFrame;
 }
@@ -120,11 +118,10 @@ SVGViewFrame::AttributeChanged(int32_t  
 
     if (svgElement->IsOverriddenBy(viewID)) {
       // We're the view that's providing overrides, so pretend that the frame
       // we're overriding was updated.
       outerSVGFrame->AttributeChanged(aNameSpaceID, aAttribute, aModType);
     }
   }
 
-  return SVGViewFrameBase::AttributeChanged(aNameSpaceID,
-                                            aAttribute, aModType);
+  return nsFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
 }
--- a/layout/svg/nsSVGAFrame.cpp
+++ b/layout/svg/nsSVGAFrame.cpp
@@ -8,25 +8,23 @@
 #include "mozilla/dom/SVGAElement.h"
 #include "nsSVGContainerFrame.h"
 #include "nsSVGIntegrationUtils.h"
 #include "nsSVGUtils.h"
 #include "SVGLengthList.h"
 
 using namespace mozilla;
 
-typedef nsSVGDisplayContainerFrame nsSVGAFrameBase;
-
-class nsSVGAFrame : public nsSVGAFrameBase
+class nsSVGAFrame : public nsSVGDisplayContainerFrame
 {
   friend nsIFrame*
   NS_NewSVGAFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 protected:
-  explicit nsSVGAFrame(nsStyleContext* aContext) :
-    nsSVGAFrameBase(aContext) {}
+  explicit nsSVGAFrame(nsStyleContext* aContext)
+    : nsSVGDisplayContainerFrame(aContext) {}
 
 public:
   NS_DECL_FRAMEARENA_HELPERS
 
 #ifdef DEBUG
   virtual void Init(nsIContent*       aContent,
                     nsContainerFrame* aParent,
                     nsIFrame*         aPrevInFlow) override;
@@ -78,17 +76,17 @@ void
 nsSVGAFrame::Init(nsIContent*       aContent,
                   nsContainerFrame* aParent,
                   nsIFrame*         aPrevInFlow)
 {
   NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::a),
                "Trying to construct an SVGAFrame for a "
                "content element that doesn't support the right interfaces");
 
-  nsSVGAFrameBase::Init(aContent, aParent, aPrevInFlow);
+  nsSVGDisplayContainerFrame::Init(aContent, aParent, aPrevInFlow);
 }
 #endif /* DEBUG */
 
 nsresult
 nsSVGAFrame::AttributeChanged(int32_t         aNameSpaceID,
                               nsIAtom*        aAttribute,
                               int32_t         aModType)
 {
@@ -119,17 +117,17 @@ nsSVGAFrame::NotifySVGChanged(uint32_t a
   MOZ_ASSERT(aFlags & (TRANSFORM_CHANGED | COORD_CONTEXT_CHANGED),
              "Invalidation logic may need adjusting");
 
   if (aFlags & TRANSFORM_CHANGED) {
     // make sure our cached transform matrix gets (lazily) updated
     mCanvasTM = nullptr;
   }
 
-  nsSVGAFrameBase::NotifySVGChanged(aFlags);
+  nsSVGDisplayContainerFrame::NotifySVGChanged(aFlags);
 }
 
 //----------------------------------------------------------------------
 // nsSVGContainerFrame methods:
 
 gfxMatrix
 nsSVGAFrame::GetCanvasTM()
 {
--- a/layout/svg/nsSVGClipPathFrame.cpp
+++ b/layout/svg/nsSVGClipPathFrame.cpp
@@ -413,30 +413,30 @@ nsSVGClipPathFrame::AttributeChanged(int
       nsSVGUtils::NotifyChildrenOfSVGChange(this,
                                             nsISVGChildFrame::TRANSFORM_CHANGED);
     }
     if (aAttribute == nsGkAtoms::clipPathUnits) {
       nsSVGEffects::InvalidateDirectRenderingObservers(this);
     }
   }
 
-  return nsSVGClipPathFrameBase::AttributeChanged(aNameSpaceID,
-                                                  aAttribute, aModType);
+  return nsSVGContainerFrame::AttributeChanged(aNameSpaceID,
+                                               aAttribute, aModType);
 }
 
 void
 nsSVGClipPathFrame::Init(nsIContent*       aContent,
                          nsContainerFrame* aParent,
                          nsIFrame*         aPrevInFlow)
 {
   NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::clipPath),
                "Content is not an SVG clipPath!");
 
   AddStateBits(NS_STATE_SVG_CLIPPATH_CHILD);
-  nsSVGClipPathFrameBase::Init(aContent, aParent, aPrevInFlow);
+  nsSVGContainerFrame::Init(aContent, aParent, aPrevInFlow);
 }
 
 nsIAtom *
 nsSVGClipPathFrame::GetType() const
 {
   return nsGkAtoms::svgClipPathFrame;
 }
 
--- a/layout/svg/nsSVGClipPathFrame.h
+++ b/layout/svg/nsSVGClipPathFrame.h
@@ -10,29 +10,27 @@
 #include "gfxMatrix.h"
 #include "mozilla/Attributes.h"
 #include "nsSVGContainerFrame.h"
 #include "nsSVGUtils.h"
 
 class gfxContext;
 class nsISVGChildFrame;
 
-typedef nsSVGContainerFrame nsSVGClipPathFrameBase;
-
-class nsSVGClipPathFrame : public nsSVGClipPathFrameBase
+class nsSVGClipPathFrame : public nsSVGContainerFrame
 {
   friend nsIFrame*
   NS_NewSVGClipPathFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 
   typedef mozilla::gfx::Matrix Matrix;
   typedef mozilla::gfx::SourceSurface SourceSurface;
 
 protected:
   explicit nsSVGClipPathFrame(nsStyleContext* aContext)
-    : nsSVGClipPathFrameBase(aContext)
+    : nsSVGContainerFrame(aContext)
     , mReferencing(mozilla::AutoReferenceLimiter::notReferencing)
   {
     AddStateBits(NS_FRAME_IS_NONDISPLAY);
   }
 
 public:
   NS_DECL_FRAMEARENA_HELPERS
 
--- a/layout/svg/nsSVGContainerFrame.cpp
+++ b/layout/svg/nsSVGContainerFrame.cpp
@@ -15,17 +15,17 @@
 #include "nsSVGUtils.h"
 #include "nsSVGAnimatedTransformList.h"
 #include "SVGTextFrame.h"
 
 using namespace mozilla;
 
 NS_QUERYFRAME_HEAD(nsSVGContainerFrame)
   NS_QUERYFRAME_ENTRY(nsSVGContainerFrame)
-NS_QUERYFRAME_TAIL_INHERITING(nsSVGContainerFrameBase)
+NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
 
 NS_QUERYFRAME_HEAD(nsSVGDisplayContainerFrame)
   NS_QUERYFRAME_ENTRY(nsSVGDisplayContainerFrame)
   NS_QUERYFRAME_ENTRY(nsISVGChildFrame)
 NS_QUERYFRAME_TAIL_INHERITING(nsSVGContainerFrame)
 
 nsIFrame*
 NS_NewSVGContainerFrame(nsIPresShell* aPresShell,
@@ -73,17 +73,17 @@ nsSVGContainerFrame::RemoveFrame(ChildLi
 bool
 nsSVGContainerFrame::UpdateOverflow()
 {
   if (mState & NS_FRAME_IS_NONDISPLAY) {
     // We don't maintain overflow rects.
     // XXX It would have be better if the restyle request hadn't even happened.
     return false;
   }
-  return nsSVGContainerFrameBase::UpdateOverflow();
+  return nsContainerFrame::UpdateOverflow();
 }
 
 /**
  * Traverses a frame tree, marking any SVGTextFrame frames as dirty
  * and calling InvalidateRenderingObservers() on it.
  *
  * The reason that this helper exists is because SVGTextFrame is special.
  * None of the other SVG frames ever need to be reflowed when they have the
--- a/layout/svg/nsSVGContainerFrame.h
+++ b/layout/svg/nsSVGContainerFrame.h
@@ -18,37 +18,35 @@
 class gfxContext;
 class nsFrameList;
 class nsIContent;
 class nsIPresShell;
 class nsStyleContext;
 
 struct nsRect;
 
-typedef nsContainerFrame nsSVGContainerFrameBase;
-
 /**
  * Base class for SVG container frames. Frame sub-classes that do not
  * display their contents directly (such as the frames for <marker> or
  * <pattern>) just inherit this class. Frame sub-classes that do or can
  * display their contents directly (such as the frames for inner-<svg> or
  * <g>) inherit our nsDisplayContainerFrame sub-class.
  *
  *                               *** WARNING ***
  *
  * Do *not* blindly cast to SVG element types in this class's methods (see the
  * warning comment for nsSVGDisplayContainerFrame below). 
  */
-class nsSVGContainerFrame : public nsSVGContainerFrameBase
+class nsSVGContainerFrame : public nsContainerFrame
 {
   friend nsIFrame* NS_NewSVGContainerFrame(nsIPresShell* aPresShell,
                                            nsStyleContext* aContext);
 protected:
   explicit nsSVGContainerFrame(nsStyleContext* aContext)
-    : nsSVGContainerFrameBase(aContext)
+    : nsContainerFrame(aContext)
   {
     AddStateBits(NS_FRAME_SVG_LAYOUT);
   }
 
 public:
   NS_DECL_QUERYFRAME_TARGET(nsSVGContainerFrame)
   NS_DECL_QUERYFRAME
   NS_DECL_FRAMEARENA_HELPERS
@@ -75,17 +73,17 @@ public:
   virtual void InsertFrames(ChildListID     aListID,
                             nsIFrame*       aPrevFrame,
                             nsFrameList&    aFrameList) override;
   virtual void RemoveFrame(ChildListID     aListID,
                            nsIFrame*       aOldFrame) override;
 
   virtual bool IsFrameOfType(uint32_t aFlags) const override
   {
-    return nsSVGContainerFrameBase::IsFrameOfType(
+    return nsContainerFrame::IsFrameOfType(
             aFlags & ~(nsIFrame::eSVG | nsIFrame::eSVGContainer));
   }
 
   virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                 const nsRect&           aDirtyRect,
                                 const nsDisplayListSet& aLists) override {}
 
   virtual bool UpdateOverflow() override;
--- a/layout/svg/nsSVGFilterFrame.cpp
+++ b/layout/svg/nsSVGFilterFrame.cpp
@@ -174,30 +174,30 @@ nsSVGFilterFrame::AttributeChanged(int32
   } else if (aNameSpaceID == kNameSpaceID_XLink &&
              aAttribute == nsGkAtoms::href) {
     // Blow away our reference, if any
     Properties().Delete(nsSVGEffects::HrefProperty());
     mNoHRefURI = false;
     // And update whoever references us
     nsSVGEffects::InvalidateDirectRenderingObservers(this);
   }
-  return nsSVGFilterFrameBase::AttributeChanged(aNameSpaceID,
-                                                aAttribute, aModType);
+  return nsSVGContainerFrame::AttributeChanged(aNameSpaceID,
+                                               aAttribute, aModType);
 }
 
 #ifdef DEBUG
 void
 nsSVGFilterFrame::Init(nsIContent*       aContent,
                        nsContainerFrame* aParent,
                        nsIFrame*         aPrevInFlow)
 {
   NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::filter),
                "Content is not an SVG filter");
 
-  nsSVGFilterFrameBase::Init(aContent, aParent, aPrevInFlow);
+  nsSVGContainerFrame::Init(aContent, aParent, aPrevInFlow);
 }
 #endif /* DEBUG */
 
 nsIAtom *
 nsSVGFilterFrame::GetType() const
 {
   return nsGkAtoms::svgFilterFrame;
 }
--- a/layout/svg/nsSVGFilterFrame.h
+++ b/layout/svg/nsSVGFilterFrame.h
@@ -22,27 +22,25 @@ class nsSVGLength2;
 struct nsRect;
 
 namespace mozilla {
 namespace dom {
 class SVGFilterElement;
 } // namespace dom
 } // namespace mozilla
 
-typedef nsSVGContainerFrame nsSVGFilterFrameBase;
-
-class nsSVGFilterFrame : public nsSVGFilterFrameBase
+class nsSVGFilterFrame : public nsSVGContainerFrame
 {
   friend nsIFrame*
   NS_NewSVGFilterFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 protected:
   explicit nsSVGFilterFrame(nsStyleContext* aContext)
-    : nsSVGFilterFrameBase(aContext),
-      mLoopFlag(false),
-      mNoHRefURI(false)
+    : nsSVGContainerFrame(aContext)
+    , mLoopFlag(false)
+    , mNoHRefURI(false)
   {
     AddStateBits(NS_FRAME_IS_NONDISPLAY);
   }
 
 public:
   NS_DECL_FRAMEARENA_HELPERS
 
   // nsIFrame methods:
--- a/layout/svg/nsSVGForeignObjectFrame.cpp
+++ b/layout/svg/nsSVGForeignObjectFrame.cpp
@@ -32,54 +32,54 @@ NS_NewSVGForeignObjectFrame(nsIPresShell
                             nsStyleContext *aContext)
 {
   return new (aPresShell) nsSVGForeignObjectFrame(aContext);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsSVGForeignObjectFrame)
 
 nsSVGForeignObjectFrame::nsSVGForeignObjectFrame(nsStyleContext* aContext)
-  : nsSVGForeignObjectFrameBase(aContext),
-    mInReflow(false)
+  : nsContainerFrame(aContext)
+  , mInReflow(false)
 {
   AddStateBits(NS_FRAME_REFLOW_ROOT | NS_FRAME_MAY_BE_TRANSFORMED |
                NS_FRAME_SVG_LAYOUT);
 }
 
 //----------------------------------------------------------------------
 // nsIFrame methods
 
 NS_QUERYFRAME_HEAD(nsSVGForeignObjectFrame)
   NS_QUERYFRAME_ENTRY(nsISVGChildFrame)
-NS_QUERYFRAME_TAIL_INHERITING(nsSVGForeignObjectFrameBase)
+NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
 
 void
 nsSVGForeignObjectFrame::Init(nsIContent*       aContent,
                               nsContainerFrame* aParent,
                               nsIFrame*         aPrevInFlow)
 {
   NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::foreignObject),
                "Content is not an SVG foreignObject!");
 
-  nsSVGForeignObjectFrameBase::Init(aContent, aParent, aPrevInFlow);
+  nsContainerFrame::Init(aContent, aParent, aPrevInFlow);
   AddStateBits(aParent->GetStateBits() & NS_STATE_SVG_CLIPPATH_CHILD);
   AddStateBits(NS_FRAME_FONT_INFLATION_CONTAINER |
                NS_FRAME_FONT_INFLATION_FLOW_ROOT);
   if (!(mState & NS_FRAME_IS_NONDISPLAY)) {
     nsSVGUtils::GetOuterSVGFrame(this)->RegisterForeignObject(this);
   }
 }
 
 void nsSVGForeignObjectFrame::DestroyFrom(nsIFrame* aDestructRoot)
 {
   // Only unregister if we registered in the first place:
   if (!(mState & NS_FRAME_IS_NONDISPLAY)) {
       nsSVGUtils::GetOuterSVGFrame(this)->UnregisterForeignObject(this);
   }
-  nsSVGForeignObjectFrameBase::DestroyFrom(aDestructRoot);
+  nsContainerFrame::DestroyFrom(aDestructRoot);
 }
 
 nsIAtom *
 nsSVGForeignObjectFrame::GetType() const
 {
   return nsGkAtoms::svgForeignObjectFrame;
 }
 
--- a/layout/svg/nsSVGForeignObjectFrame.h
+++ b/layout/svg/nsSVGForeignObjectFrame.h
@@ -10,20 +10,18 @@
 #include "nsContainerFrame.h"
 #include "nsIPresShell.h"
 #include "nsISVGChildFrame.h"
 #include "nsRegion.h"
 #include "nsSVGUtils.h"
 
 class gfxContext;
 
-typedef nsContainerFrame nsSVGForeignObjectFrameBase;
-
-class nsSVGForeignObjectFrame : public nsSVGForeignObjectFrameBase,
-                                public nsISVGChildFrame
+class nsSVGForeignObjectFrame : public nsContainerFrame
+                              , public nsISVGChildFrame
 {
   friend nsContainerFrame*
   NS_NewSVGForeignObjectFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 protected:
   explicit nsSVGForeignObjectFrame(nsStyleContext* aContext);
 
 public:
   NS_DECL_QUERYFRAME
@@ -55,17 +53,17 @@ public:
    * Get the "type" of the frame
    *
    * @see nsGkAtoms::svgForeignObjectFrame
    */
   virtual nsIAtom* GetType() const override;
 
   virtual bool IsFrameOfType(uint32_t aFlags) const override
   {
-    return nsSVGForeignObjectFrameBase::IsFrameOfType(aFlags &
+    return nsContainerFrame::IsFrameOfType(aFlags &
       ~(nsIFrame::eSVG | nsIFrame::eSVGForeignObject));
   }
 
   virtual bool IsSVGTransformed(Matrix *aOwnTransform,
                                 Matrix *aFromParentTransform) const override;
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const override
--- a/layout/svg/nsSVGGFrame.cpp
+++ b/layout/svg/nsSVGGFrame.cpp
@@ -16,33 +16,33 @@
 
 using namespace mozilla::dom;
 
 //----------------------------------------------------------------------
 // Implementation
 
 nsIFrame*
 NS_NewSVGGFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
-{  
+{
   return new (aPresShell) nsSVGGFrame(aContext);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsSVGGFrame)
 
 #ifdef DEBUG
 void
 nsSVGGFrame::Init(nsIContent*       aContent,
                   nsContainerFrame* aParent,
                   nsIFrame*         aPrevInFlow)
 {
   NS_ASSERTION(aContent->IsSVGElement() &&
                static_cast<nsSVGElement*>(aContent)->IsTransformable(),
                "The element doesn't support nsIDOMSVGTransformable");
 
-  nsSVGGFrameBase::Init(aContent, aParent, aPrevInFlow);
+  nsSVGDisplayContainerFrame::Init(aContent, aParent, aPrevInFlow);
 }
 #endif /* DEBUG */
 
 nsIAtom *
 nsSVGGFrame::GetType() const
 {
   return nsGkAtoms::svgGFrame;
 }
@@ -56,17 +56,17 @@ nsSVGGFrame::NotifySVGChanged(uint32_t a
   MOZ_ASSERT(aFlags & (TRANSFORM_CHANGED | COORD_CONTEXT_CHANGED),
              "Invalidation logic may need adjusting");
 
   if (aFlags & TRANSFORM_CHANGED) {
     // make sure our cached transform matrix gets (lazily) updated
     mCanvasTM = nullptr;
   }
 
-  nsSVGGFrameBase::NotifySVGChanged(aFlags);
+  nsSVGDisplayContainerFrame::NotifySVGChanged(aFlags);
 }
 
 gfxMatrix
 nsSVGGFrame::GetCanvasTM()
 {
   if (!mCanvasTM) {
     NS_ASSERTION(GetParent(), "null parent");
 
@@ -88,11 +88,11 @@ nsSVGGFrame::AttributeChanged(int32_t   
   if (aNameSpaceID == kNameSpaceID_None &&
       aAttribute == nsGkAtoms::transform) {
     // We don't invalidate for transform changes (the layers code does that).
     // Also note that SVGTransformableElement::GetAttributeChangeHint will
     // return nsChangeHint_UpdateOverflow for "transform" attribute changes
     // and cause DoApplyRenderingChangeToTree to make the SchedulePaint call.
     NotifySVGChanged(TRANSFORM_CHANGED);
   }
-  
+
   return NS_OK;
 }
--- a/layout/svg/nsSVGGFrame.h
+++ b/layout/svg/nsSVGGFrame.h
@@ -5,25 +5,23 @@
 
 #ifndef NSSVGGFRAME_H
 #define NSSVGGFRAME_H
 
 #include "mozilla/Attributes.h"
 #include "gfxMatrix.h"
 #include "nsSVGContainerFrame.h"
 
-typedef nsSVGDisplayContainerFrame nsSVGGFrameBase;
-
-class nsSVGGFrame : public nsSVGGFrameBase
+class nsSVGGFrame : public nsSVGDisplayContainerFrame
 {
   friend nsIFrame*
   NS_NewSVGGFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 protected:
-  explicit nsSVGGFrame(nsStyleContext* aContext) :
-    nsSVGGFrameBase(aContext) {}
+  explicit nsSVGGFrame(nsStyleContext* aContext)
+    : nsSVGDisplayContainerFrame(aContext) {}
 
 public:
   NS_DECL_FRAMEARENA_HELPERS
 
 #ifdef DEBUG
   virtual void Init(nsIContent*       aContent,
                     nsContainerFrame* aParent,
                     nsIFrame*         aPrevInFlow) override;
--- a/layout/svg/nsSVGGenericContainerFrame.h
+++ b/layout/svg/nsSVGGenericContainerFrame.h
@@ -13,25 +13,25 @@
 #include "nsQueryFrame.h"
 #include "nsSVGContainerFrame.h"
 
 class nsIAtom;
 class nsIFrame;
 class nsIPresShell;
 class nsStyleContext;
 
-typedef nsSVGDisplayContainerFrame nsSVGGenericContainerFrameBase;
-
-class nsSVGGenericContainerFrame : public nsSVGGenericContainerFrameBase
+class nsSVGGenericContainerFrame : public nsSVGDisplayContainerFrame
 {
   friend nsIFrame*
   NS_NewSVGGenericContainerFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
+
 protected:
-  explicit nsSVGGenericContainerFrame(nsStyleContext* aContext) : nsSVGGenericContainerFrameBase(aContext) {}
-  
+  explicit nsSVGGenericContainerFrame(nsStyleContext* aContext)
+    : nsSVGDisplayContainerFrame(aContext) {}
+
 public:
   NS_DECL_FRAMEARENA_HELPERS
 
   // nsIFrame:
   virtual nsresult  AttributeChanged(int32_t         aNameSpaceID,
                                      nsIAtom*        aAttribute,
                                      int32_t         aModType) override;
   /**
--- a/layout/svg/nsSVGGradientFrame.cpp
+++ b/layout/svg/nsSVGGradientFrame.cpp
@@ -43,20 +43,20 @@ public:
 private:
   nsSVGGradientFrame *mFrame;
   MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
 //----------------------------------------------------------------------
 // Implementation
 
-nsSVGGradientFrame::nsSVGGradientFrame(nsStyleContext* aContext) :
-  nsSVGGradientFrameBase(aContext),
-  mLoopFlag(false),
-  mNoHRefURI(false)
+nsSVGGradientFrame::nsSVGGradientFrame(nsStyleContext* aContext)
+  : nsSVGPaintServerFrame(aContext)
+  , mLoopFlag(false)
+  , mNoHRefURI(false)
 {
 }
 
 //----------------------------------------------------------------------
 // nsIFrame methods:
 
 nsresult
 nsSVGGradientFrame::AttributeChanged(int32_t         aNameSpaceID,
@@ -72,18 +72,18 @@ nsSVGGradientFrame::AttributeChanged(int
              aAttribute == nsGkAtoms::href) {
     // Blow away our reference, if any
     Properties().Delete(nsSVGEffects::HrefProperty());
     mNoHRefURI = false;
     // And update whoever references us
     nsSVGEffects::InvalidateDirectRenderingObservers(this);
   }
 
-  return nsSVGGradientFrameBase::AttributeChanged(aNameSpaceID,
-                                                  aAttribute, aModType);
+  return nsSVGPaintServerFrame::AttributeChanged(aNameSpaceID,
+                                                 aAttribute, aModType);
 }
 
 //----------------------------------------------------------------------
 
 uint16_t
 nsSVGGradientFrame::GetEnumValue(uint32_t aIndex, nsIContent *aDefault)
 {
   const nsSVGEnum& thisEnum =
@@ -400,17 +400,17 @@ nsSVGGradientFrame::GetStopFrames(nsTArr
 void
 nsSVGLinearGradientFrame::Init(nsIContent*       aContent,
                                nsContainerFrame* aParent,
                                nsIFrame*         aPrevInFlow)
 {
   NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::linearGradient),
                "Content is not an SVG linearGradient");
 
-  nsSVGLinearGradientFrameBase::Init(aContent, aParent, aPrevInFlow);
+  nsSVGGradientFrame::Init(aContent, aParent, aPrevInFlow);
 }
 #endif /* DEBUG */
 
 nsIAtom*
 nsSVGLinearGradientFrame::GetType() const
 {
   return nsGkAtoms::svgLinearGradientFrame;
 }
@@ -469,18 +469,17 @@ nsSVGLinearGradientFrame::GetLinearGradi
   dom::SVGLinearGradientElement* thisElement =
     static_cast<dom::SVGLinearGradientElement*>(mContent);
   const nsSVGLength2 &length = thisElement->mLengthAttributes[aIndex];
 
   if (length.IsExplicitlySet()) {
     return thisElement;
   }
 
-  return nsSVGLinearGradientFrameBase::GetLinearGradientWithLength(aIndex,
-                                                                   aDefault);
+  return nsSVGGradientFrame::GetLinearGradientWithLength(aIndex, aDefault);
 }
 
 bool
 nsSVGLinearGradientFrame::GradientVectorLengthIsZero()
 {
   return GetLengthValue(dom::SVGLinearGradientElement::ATTR_X1) ==
          GetLengthValue(dom::SVGLinearGradientElement::ATTR_X2) &&
          GetLengthValue(dom::SVGLinearGradientElement::ATTR_Y1) ==
@@ -509,17 +508,17 @@ nsSVGLinearGradientFrame::CreateGradient
 void
 nsSVGRadialGradientFrame::Init(nsIContent*       aContent,
                                nsContainerFrame* aParent,
                                nsIFrame*         aPrevInFlow)
 {
   NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::radialGradient),
                "Content is not an SVG radialGradient");
 
-  nsSVGRadialGradientFrameBase::Init(aContent, aParent, aPrevInFlow);
+  nsSVGGradientFrame::Init(aContent, aParent, aPrevInFlow);
 }
 #endif /* DEBUG */
 
 nsIAtom*
 nsSVGRadialGradientFrame::GetType() const
 {
   return nsGkAtoms::svgRadialGradientFrame;
 }
@@ -596,18 +595,17 @@ nsSVGRadialGradientFrame::GetRadialGradi
   dom::SVGRadialGradientElement* thisElement =
     static_cast<dom::SVGRadialGradientElement*>(mContent);
   const nsSVGLength2 &length = thisElement->mLengthAttributes[aIndex];
 
   if (length.IsExplicitlySet()) {
     return thisElement;
   }
 
-  return nsSVGRadialGradientFrameBase::GetRadialGradientWithLength(aIndex,
-                                                                   aDefault);
+  return nsSVGGradientFrame::GetRadialGradientWithLength(aIndex, aDefault);
 }
 
 bool
 nsSVGRadialGradientFrame::GradientVectorLengthIsZero()
 {
   return GetLengthValue(dom::SVGRadialGradientElement::ATTR_R) == 0;
 }
 
--- a/layout/svg/nsSVGGradientFrame.h
+++ b/layout/svg/nsSVGGradientFrame.h
@@ -26,23 +26,21 @@ namespace mozilla {
 class nsSVGAnimatedTransformList;
 
 namespace dom {
 class SVGLinearGradientElement;
 class SVGRadialGradientElement;
 } // namespace dom
 } // namespace mozilla
 
-typedef nsSVGPaintServerFrame nsSVGGradientFrameBase;
-
 /**
  * Gradients can refer to other gradients. We create an nsSVGPaintingProperty
  * with property type nsGkAtoms::href to track the referenced gradient.
  */
-class nsSVGGradientFrame : public nsSVGGradientFrameBase
+class nsSVGGradientFrame : public nsSVGPaintServerFrame
 {
   typedef mozilla::gfx::ExtendMode ExtendMode;
 
 protected:
   explicit nsSVGGradientFrame(nsStyleContext* aContext);
 
 public:
   NS_DECL_ABSTRACT_FRAME(nsSVGGradientFrame)
@@ -121,25 +119,23 @@ private:
   bool                                   mNoHRefURI;
 };
 
 
 // -------------------------------------------------------------------------
 // Linear Gradients
 // -------------------------------------------------------------------------
 
-typedef nsSVGGradientFrame nsSVGLinearGradientFrameBase;
-
-class nsSVGLinearGradientFrame : public nsSVGLinearGradientFrameBase
+class nsSVGLinearGradientFrame : public nsSVGGradientFrame
 {
   friend nsIFrame* NS_NewSVGLinearGradientFrame(nsIPresShell* aPresShell,
                                                 nsStyleContext* aContext);
 protected:
-  explicit nsSVGLinearGradientFrame(nsStyleContext* aContext) :
-    nsSVGLinearGradientFrameBase(aContext) {}
+  explicit nsSVGLinearGradientFrame(nsStyleContext* aContext)
+    : nsSVGGradientFrame(aContext) {}
 
 public:
   NS_DECL_FRAMEARENA_HELPERS
 
   // nsIFrame interface:
 #ifdef DEBUG
   virtual void Init(nsIContent*       aContent,
                     nsContainerFrame* aParent,
@@ -166,25 +162,23 @@ protected:
   virtual bool GradientVectorLengthIsZero() override;
   virtual already_AddRefed<gfxPattern> CreateGradient() override;
 };
 
 // -------------------------------------------------------------------------
 // Radial Gradients
 // -------------------------------------------------------------------------
 
-typedef nsSVGGradientFrame nsSVGRadialGradientFrameBase;
-
-class nsSVGRadialGradientFrame : public nsSVGRadialGradientFrameBase
+class nsSVGRadialGradientFrame : public nsSVGGradientFrame
 {
   friend nsIFrame* NS_NewSVGRadialGradientFrame(nsIPresShell* aPresShell,
                                                 nsStyleContext* aContext);
 protected:
-  explicit nsSVGRadialGradientFrame(nsStyleContext* aContext) :
-    nsSVGRadialGradientFrameBase(aContext) {}
+  explicit nsSVGRadialGradientFrame(nsStyleContext* aContext)
+    : nsSVGGradientFrame(aContext) {}
 
 public:
   NS_DECL_FRAMEARENA_HELPERS
 
   // nsIFrame interface:
 #ifdef DEBUG
   virtual void Init(nsIContent*       aContent,
                     nsContainerFrame* aParent,
--- a/layout/svg/nsSVGImageFrame.cpp
+++ b/layout/svg/nsSVGImageFrame.cpp
@@ -40,27 +40,25 @@ public:
   void SetFrame(nsSVGImageFrame *frame) { mFrame = frame; }
 
 private:
   ~nsSVGImageListener() {}
 
   nsSVGImageFrame *mFrame;
 };
 
-typedef nsSVGPathGeometryFrame nsSVGImageFrameBase;
-
-class nsSVGImageFrame : public nsSVGImageFrameBase,
-                        public nsIReflowCallback
+class nsSVGImageFrame : public nsSVGPathGeometryFrame
+                      , public nsIReflowCallback
 {
   friend nsIFrame*
   NS_NewSVGImageFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 
 protected:
   explicit nsSVGImageFrame(nsStyleContext* aContext)
-    : nsSVGImageFrameBase(aContext)
+    : nsSVGPathGeometryFrame(aContext)
     , mReflowCallbackPosted(false)
   {
     EnableVisibilityTracking();
   }
 
   virtual ~nsSVGImageFrame();
 
 public:
@@ -150,17 +148,17 @@ nsSVGImageFrame::~nsSVGImageFrame()
 void
 nsSVGImageFrame::Init(nsIContent*       aContent,
                       nsContainerFrame* aParent,
                       nsIFrame*         aPrevInFlow)
 {
   NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::image),
                "Content is not an SVG image!");
 
-  nsSVGImageFrameBase::Init(aContent, aParent, aPrevInFlow);
+  nsSVGPathGeometryFrame::Init(aContent, aParent, aPrevInFlow);
 
   if (GetStateBits() & NS_FRAME_IS_NONDISPLAY) {
     // Non-display frames are likely to be patterns, masks or the like.
     // Treat them as always visible.
     IncApproximateVisibleCount();
   }
 
   mListener = new nsSVGImageListener(this);
@@ -232,33 +230,33 @@ nsSVGImageFrame::AttributeChanged(int32_
 
     if (element->mStringAttributes[SVGImageElement::HREF].IsExplicitlySet()) {
       element->LoadSVGImage(true, true);
     } else {
       element->CancelImageRequests(true);
     }
   }
 
-  return nsSVGImageFrameBase::AttributeChanged(aNameSpaceID,
-                                               aAttribute, aModType);
+  return nsSVGPathGeometryFrame::AttributeChanged(aNameSpaceID,
+                                                  aAttribute, aModType);
 }
 
 void
 nsSVGImageFrame::OnVisibilityChange(Visibility aNewVisibility,
                                     Maybe<OnNonvisible> aNonvisibleAction)
 {
   nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mContent);
   if (!imageLoader) {
-    nsSVGImageFrameBase::OnVisibilityChange(aNewVisibility, aNonvisibleAction);
+    nsSVGPathGeometryFrame::OnVisibilityChange(aNewVisibility, aNonvisibleAction);
     return;
   }
 
   imageLoader->OnVisibilityChange(aNewVisibility, aNonvisibleAction);
 
-  nsSVGImageFrameBase::OnVisibilityChange(aNewVisibility, aNonvisibleAction);
+  nsSVGPathGeometryFrame::OnVisibilityChange(aNewVisibility, aNonvisibleAction);
 }
 
 gfx::Matrix
 nsSVGImageFrame::GetRasterImageTransform(int32_t aNativeWidth,
                                          int32_t aNativeHeight)
 {
   float x, y, width, height;
   SVGImageElement *element = static_cast<SVGImageElement*>(mContent);
--- a/layout/svg/nsSVGInnerSVGFrame.cpp
+++ b/layout/svg/nsSVGInnerSVGFrame.cpp
@@ -28,28 +28,28 @@ NS_NewSVGInnerSVGFrame(nsIPresShell* aPr
 NS_IMPL_FRAMEARENA_HELPERS(nsSVGInnerSVGFrame)
 
 //----------------------------------------------------------------------
 // nsIFrame methods
 
 NS_QUERYFRAME_HEAD(nsSVGInnerSVGFrame)
   NS_QUERYFRAME_ENTRY(nsSVGInnerSVGFrame)
   NS_QUERYFRAME_ENTRY(nsISVGSVGFrame)
-NS_QUERYFRAME_TAIL_INHERITING(nsSVGInnerSVGFrameBase)
+NS_QUERYFRAME_TAIL_INHERITING(nsSVGDisplayContainerFrame)
 
 #ifdef DEBUG
 void
 nsSVGInnerSVGFrame::Init(nsIContent*       aContent,
                          nsContainerFrame* aParent,
                          nsIFrame*         aPrevInFlow)
 {
   NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::svg),
                "Content is not an SVG 'svg' element!");
 
-  nsSVGInnerSVGFrameBase::Init(aContent, aParent, aPrevInFlow);
+  nsSVGDisplayContainerFrame::Init(aContent, aParent, aPrevInFlow);
 }
 #endif /* DEBUG */
 
 nsIAtom *
 nsSVGInnerSVGFrame::GetType() const
 {
   return nsGkAtoms::svgInnerSVGFrame;
 }
@@ -79,17 +79,17 @@ nsSVGInnerSVGFrame::PaintSVG(gfxContext&
     }
 
     autoSR.SetContext(&aContext);
     gfxRect clipRect =
       nsSVGUtils::GetClipRectForFrame(this, x, y, width, height);
     nsSVGUtils::SetClipRect(&aContext, aTransform, clipRect);
   }
 
-  return nsSVGInnerSVGFrameBase::PaintSVG(aContext, aTransform, aDirtyRect);
+  return nsSVGDisplayContainerFrame::PaintSVG(aContext, aTransform, aDirtyRect);
 }
 
 nsRect
 nsSVGInnerSVGFrame::GetCoveredRegion()
 {
   float x, y, w, h;
   static_cast<SVGSVGElement*>(mContent)->
     GetAnimatedLengthValues(&x, &y, &w, &h, nullptr);
@@ -119,17 +119,17 @@ nsSVGInnerSVGFrame::ReflowSVG()
                            PresContext()->AppUnitsPerCSSPixel());
 
   // If we have a filter, we need to invalidate ourselves because filter
   // output can change even if none of our descendants need repainting.
   if (StyleEffects()->HasFilters()) {
     InvalidateFrame();
   }
 
-  nsSVGInnerSVGFrameBase::ReflowSVG();
+  nsSVGDisplayContainerFrame::ReflowSVG();
 }
 
 void
 nsSVGInnerSVGFrame::NotifySVGChanged(uint32_t aFlags)
 {
   MOZ_ASSERT(aFlags & (TRANSFORM_CHANGED | COORD_CONTEXT_CHANGED),
              "Invalidation logic may need adjusting");
 
@@ -176,17 +176,17 @@ nsSVGInnerSVGFrame::NotifySVGChanged(uin
     }
   }
 
   if (aFlags & TRANSFORM_CHANGED) {
     // make sure our cached transform matrix gets (lazily) updated
     mCanvasTM = nullptr;
   }
 
-  nsSVGInnerSVGFrameBase::NotifySVGChanged(aFlags);
+  nsSVGDisplayContainerFrame::NotifySVGChanged(aFlags);
 }
 
 nsresult
 nsSVGInnerSVGFrame::AttributeChanged(int32_t  aNameSpaceID,
                                      nsIAtom* aAttribute,
                                      int32_t  aModType)
 {
   if (aNameSpaceID == kNameSpaceID_None &&
@@ -264,17 +264,17 @@ nsSVGInnerSVGFrame::GetFrameForPoint(con
     static_cast<nsSVGElement*>(mContent)->
       GetAnimatedLengthValues(&clip.x, &clip.y,
                               &clip.width, &clip.height, nullptr);
     if (!clip.Contains(ToPoint(aPoint))) {
       return nullptr;
     }
   }
 
-  return nsSVGInnerSVGFrameBase::GetFrameForPoint(aPoint);
+  return nsSVGDisplayContainerFrame::GetFrameForPoint(aPoint);
 }
 
 //----------------------------------------------------------------------
 // nsISVGSVGFrame methods:
 
 void
 nsSVGInnerSVGFrame::NotifyViewportOrTransformChanged(uint32_t aFlags)
 {
--- a/layout/svg/nsSVGInnerSVGFrame.h
+++ b/layout/svg/nsSVGInnerSVGFrame.h
@@ -7,27 +7,25 @@
 #define __NS_SVGINNERSVGFRAME_H__
 
 #include "mozilla/Attributes.h"
 #include "nsSVGContainerFrame.h"
 #include "nsISVGSVGFrame.h"
 
 class gfxContext;
 
-typedef nsSVGDisplayContainerFrame nsSVGInnerSVGFrameBase;
-
-class nsSVGInnerSVGFrame : public nsSVGInnerSVGFrameBase,
-                           public nsISVGSVGFrame
+class nsSVGInnerSVGFrame : public nsSVGDisplayContainerFrame
+                         , public nsISVGSVGFrame
 {
   friend nsIFrame*
   NS_NewSVGInnerSVGFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 protected:
-  explicit nsSVGInnerSVGFrame(nsStyleContext* aContext) :
-    nsSVGInnerSVGFrameBase(aContext) {}
-  
+  explicit nsSVGInnerSVGFrame(nsStyleContext* aContext)
+    : nsSVGDisplayContainerFrame(aContext) {}
+
 public:
   NS_DECL_QUERYFRAME_TARGET(nsSVGInnerSVGFrame)
   NS_DECL_QUERYFRAME
   NS_DECL_FRAMEARENA_HELPERS
 
 #ifdef DEBUG
   virtual void Init(nsIContent*       aContent,
                     nsContainerFrame* aParent,
--- a/layout/svg/nsSVGIntegrationUtils.cpp
+++ b/layout/svg/nsSVGIntegrationUtils.cpp
@@ -562,17 +562,27 @@ nsSVGIntegrationUtils::PaintFramesWithEf
       gfxRect clipRect = aContext.GetClipExtents();
       {
         gfxContextMatrixAutoSaveRestore matRestore(&aContext);
 
         aContext.SetMatrix(gfxMatrix());
         clipRect = aContext.GetClipExtents();
       }
       IntRect drawRect = RoundedOut(ToRect(clipRect));
-      RefPtr<DrawTarget> targetDT = aContext.GetDrawTarget()->CreateSimilarDrawTarget(drawRect.Size(), SurfaceFormat::A8);
+
+      // Mask composition result on CoreGraphic::A8 surface is not correct
+      // when mask-mode is not add(source over). Switch to skia when CG backend
+      // detected.
+      RefPtr<DrawTarget> targetDT =
+        (aContext.GetDrawTarget()->GetBackendType() == BackendType::COREGRAPHICS) ?
+          Factory::CreateDrawTarget(BackendType::SKIA, drawRect.Size(),
+                                    SurfaceFormat::A8) :
+          aContext.GetDrawTarget()->CreateSimilarDrawTarget(drawRect.Size(),
+                                                            SurfaceFormat::A8);
+
       if (!targetDT || !targetDT->IsValid()) {
         aContext.Restore();
         return;
       }
 
       RefPtr<gfxContext> target = gfxContext::ForDrawTarget(targetDT);
       MOZ_ASSERT(target); // alrady checked the draw target above
       target->SetMatrix(matrixAutoSaveRestore.Matrix() * gfxMatrix::Translation(-drawRect.TopLeft()));
--- a/layout/svg/nsSVGMarkerFrame.cpp
+++ b/layout/svg/nsSVGMarkerFrame.cpp
@@ -39,29 +39,29 @@ nsSVGMarkerFrame::AttributeChanged(int32
        aAttribute == nsGkAtoms::markerWidth ||
        aAttribute == nsGkAtoms::markerHeight ||
        aAttribute == nsGkAtoms::orient ||
        aAttribute == nsGkAtoms::preserveAspectRatio ||
        aAttribute == nsGkAtoms::viewBox)) {
     nsSVGEffects::InvalidateDirectRenderingObservers(this);
   }
 
-  return nsSVGMarkerFrameBase::AttributeChanged(aNameSpaceID,
-                                                aAttribute, aModType);
+  return nsSVGContainerFrame::AttributeChanged(aNameSpaceID,
+                                               aAttribute, aModType);
 }
 
 #ifdef DEBUG
 void
 nsSVGMarkerFrame::Init(nsIContent*       aContent,
                        nsContainerFrame* aParent,
                        nsIFrame*         aPrevInFlow)
 {
   NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::marker), "Content is not an SVG marker");
 
-  nsSVGMarkerFrameBase::Init(aContent, aParent, aPrevInFlow);
+  nsSVGContainerFrame::Init(aContent, aParent, aPrevInFlow);
 }
 #endif /* DEBUG */
 
 nsIAtom *
 nsSVGMarkerFrame::GetType() const
 {
   return nsGkAtoms::svgMarkerFrame;
 }
@@ -262,17 +262,17 @@ NS_IMPL_FRAMEARENA_HELPERS(nsSVGMarkerAn
 #ifdef DEBUG
 void
 nsSVGMarkerAnonChildFrame::Init(nsIContent*       aContent,
                                 nsContainerFrame* aParent,
                                 nsIFrame*         aPrevInFlow)
 {
   MOZ_ASSERT(aParent->GetType() == nsGkAtoms::svgMarkerFrame,
              "Unexpected parent");
-  nsSVGMarkerAnonChildFrameBase::Init(aContent, aParent, aPrevInFlow);
+  nsSVGDisplayContainerFrame::Init(aContent, aParent, aPrevInFlow);
 }
 #endif
 
 nsIAtom *
 nsSVGMarkerAnonChildFrame::GetType() const
 {
   return nsGkAtoms::svgMarkerAnonChildFrame;
 }
--- a/layout/svg/nsSVGMarkerFrame.h
+++ b/layout/svg/nsSVGMarkerFrame.h
@@ -21,26 +21,24 @@ class nsSVGPathGeometryFrame;
 namespace mozilla {
 namespace dom {
 class SVGSVGElement;
 } // namespace dom
 } // namespace mozilla
 
 struct nsSVGMark;
 
-typedef nsSVGContainerFrame nsSVGMarkerFrameBase;
-
-class nsSVGMarkerFrame : public nsSVGMarkerFrameBase
+class nsSVGMarkerFrame : public nsSVGContainerFrame
 {
   friend class nsSVGMarkerAnonChildFrame;
   friend nsContainerFrame*
   NS_NewSVGMarkerFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 protected:
   explicit nsSVGMarkerFrame(nsStyleContext* aContext)
-    : nsSVGMarkerFrameBase(aContext)
+    : nsSVGContainerFrame(aContext)
     , mMarkedFrame(nullptr)
     , mInUse(false)
     , mInUse2(false)
   {
     AddStateBits(NS_FRAME_IS_NONDISPLAY);
   }
 
 public:
@@ -130,29 +128,24 @@ private:
 
   // second recursion prevention flag, for GetCanvasTM()
   bool mInUse2;
 };
 
 ////////////////////////////////////////////////////////////////////////
 // nsMarkerAnonChildFrame class
 
-typedef nsSVGDisplayContainerFrame nsSVGMarkerAnonChildFrameBase;
-
-/**
- */
-class nsSVGMarkerAnonChildFrame
-  : public nsSVGMarkerAnonChildFrameBase
+class nsSVGMarkerAnonChildFrame : public nsSVGDisplayContainerFrame
 {
   friend nsContainerFrame*
   NS_NewSVGMarkerAnonChildFrame(nsIPresShell* aPresShell,
                                 nsStyleContext* aContext);
 
   explicit nsSVGMarkerAnonChildFrame(nsStyleContext* aContext)
-    : nsSVGMarkerAnonChildFrameBase(aContext)
+    : nsSVGDisplayContainerFrame(aContext)
   {}
 
 public:
   NS_DECL_FRAMEARENA_HELPERS
 
 #ifdef DEBUG
   virtual void Init(nsIContent*       aContent,
                     nsContainerFrame* aParent,
--- a/layout/svg/nsSVGMaskFrame.cpp
+++ b/layout/svg/nsSVGMaskFrame.cpp
@@ -355,30 +355,30 @@ nsSVGMaskFrame::AttributeChanged(int32_t
        aAttribute == nsGkAtoms::y ||
        aAttribute == nsGkAtoms::width ||
        aAttribute == nsGkAtoms::height||
        aAttribute == nsGkAtoms::maskUnits ||
        aAttribute == nsGkAtoms::maskContentUnits)) {
     nsSVGEffects::InvalidateDirectRenderingObservers(this);
   }
 
-  return nsSVGMaskFrameBase::AttributeChanged(aNameSpaceID,
-                                              aAttribute, aModType);
+  return nsSVGContainerFrame::AttributeChanged(aNameSpaceID,
+                                               aAttribute, aModType);
 }
 
 #ifdef DEBUG
 void
 nsSVGMaskFrame::Init(nsIContent*       aContent,
                      nsContainerFrame* aParent,
                      nsIFrame*         aPrevInFlow)
 {
   NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::mask),
                "Content is not an SVG mask");
 
-  nsSVGMaskFrameBase::Init(aContent, aParent, aPrevInFlow);
+  nsSVGContainerFrame::Init(aContent, aParent, aPrevInFlow);
 }
 #endif /* DEBUG */
 
 nsIAtom *
 nsSVGMaskFrame::GetType() const
 {
   return nsGkAtoms::svgMaskFrame;
 }
--- a/layout/svg/nsSVGMaskFrame.h
+++ b/layout/svg/nsSVGMaskFrame.h
@@ -11,44 +11,42 @@
 #include "mozilla/RefPtr.h"
 #include "gfxPattern.h"
 #include "gfxMatrix.h"
 #include "nsSVGContainerFrame.h"
 #include "nsSVGUtils.h"
 
 class gfxContext;
 
-typedef nsSVGContainerFrame nsSVGMaskFrameBase;
-
 /**
  * Byte offsets of channels in a native packed gfxColor or cairo image surface.
  */
 #ifdef IS_BIG_ENDIAN
 #define GFX_ARGB32_OFFSET_A 0
 #define GFX_ARGB32_OFFSET_R 1
 #define GFX_ARGB32_OFFSET_G 2
 #define GFX_ARGB32_OFFSET_B 3
 #else
 #define GFX_ARGB32_OFFSET_A 3
 #define GFX_ARGB32_OFFSET_R 2
 #define GFX_ARGB32_OFFSET_G 1
 #define GFX_ARGB32_OFFSET_B 0
 #endif
 
-class nsSVGMaskFrame final : public nsSVGMaskFrameBase
+class nsSVGMaskFrame final : public nsSVGContainerFrame
 {
   friend nsIFrame*
   NS_NewSVGMaskFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 
   typedef mozilla::gfx::Matrix Matrix;
   typedef mozilla::gfx::SourceSurface SourceSurface;
 
 protected:
   explicit nsSVGMaskFrame(nsStyleContext* aContext)
-    : nsSVGMaskFrameBase(aContext)
+    : nsSVGContainerFrame(aContext)
     , mInUse(false)
   {
     AddStateBits(NS_FRAME_IS_NONDISPLAY);
   }
 
 public:
   NS_DECL_FRAMEARENA_HELPERS
 
--- a/layout/svg/nsSVGOuterSVGFrame.cpp
+++ b/layout/svg/nsSVGOuterSVGFrame.cpp
@@ -51,24 +51,24 @@ nsSVGOuterSVGFrame::UnregisterForeignObj
   return mForeignObjectHash->RemoveEntry(aFrame);
 }
 
 //----------------------------------------------------------------------
 // Implementation
 
 nsContainerFrame*
 NS_NewSVGOuterSVGFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
-{  
+{
   return new (aPresShell) nsSVGOuterSVGFrame(aContext);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsSVGOuterSVGFrame)
 
 nsSVGOuterSVGFrame::nsSVGOuterSVGFrame(nsStyleContext* aContext)
-    : nsSVGOuterSVGFrameBase(aContext)
+    : nsSVGDisplayContainerFrame(aContext)
     , mFullZoom(aContext->PresContext()->GetFullZoom())
     , mViewportInitialized(false)
     , mIsRootContent(false)
 {
   // Outer-<svg> has CSS layout, so remove this bit:
   RemoveStateBits(NS_FRAME_SVG_LAYOUT);
 }
 
@@ -107,17 +107,17 @@ nsSVGOuterSVGFrame::Init(nsIContent*    
   // prevent them from painting by [ab]use NS_FRAME_IS_NONDISPLAY. The
   // frame will be recreated via an nsChangeHint_ReconstructFrame restyle if
   // the value returned by PassesConditionalProcessingTests changes.
   SVGSVGElement *svg = static_cast<SVGSVGElement*>(aContent);
   if (!svg->PassesConditionalProcessingTests()) {
     AddStateBits(NS_FRAME_IS_NONDISPLAY);
   }
 
-  nsSVGOuterSVGFrameBase::Init(aContent, aParent, aPrevInFlow);
+  nsSVGDisplayContainerFrame::Init(aContent, aParent, aPrevInFlow);
 
   nsIDocument* doc = mContent->GetUncomposedDoc();
   if (doc) {
     // we only care about our content's zoom and pan values if it's the root element
     if (doc->GetRootElement() == mContent) {
       mIsRootContent = true;
 
       nsIFrame* embeddingFrame;
@@ -136,21 +136,20 @@ nsSVGOuterSVGFrame::Init(nsIContent*    
   }
 }
 
 //----------------------------------------------------------------------
 // nsQueryFrame methods
 
 NS_QUERYFRAME_HEAD(nsSVGOuterSVGFrame)
   NS_QUERYFRAME_ENTRY(nsISVGSVGFrame)
-NS_QUERYFRAME_TAIL_INHERITING(nsSVGOuterSVGFrameBase)
+NS_QUERYFRAME_TAIL_INHERITING(nsSVGDisplayContainerFrame)
 
 //----------------------------------------------------------------------
 // nsIFrame methods
-  
 //----------------------------------------------------------------------
 // reflowing
 
 /* virtual */ nscoord
 nsSVGOuterSVGFrame::GetMinISize(nsRenderingContext *aRenderingContext)
 {
   nscoord result;
   DISPLAY_MIN_WIDTH(this, result);
@@ -271,17 +270,17 @@ nsSVGOuterSVGFrame::GetIntrinsicRatio()
     }
     if (viewBoxHeight < 0.0f) {
       viewBoxHeight = 0.0f;
     }
     return nsSize(NSToCoordRoundWithClamp(viewBoxWidth),
                   NSToCoordRoundWithClamp(viewBoxHeight));
   }
 
-  return nsSVGOuterSVGFrameBase::GetIntrinsicRatio();
+  return nsSVGDisplayContainerFrame::GetIntrinsicRatio();
 }
 
 /* virtual */
 LogicalSize
 nsSVGOuterSVGFrame::ComputeSize(nsRenderingContext *aRenderingContext,
                                 WritingMode aWM,
                                 const LogicalSize& aCBSize,
                                 nscoord aAvailableISize,
@@ -503,17 +502,17 @@ nsSVGOuterSVGFrame::Reflow(nsPresContext
   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
 }
 
 void
 nsSVGOuterSVGFrame::DidReflow(nsPresContext*   aPresContext,
                               const nsHTMLReflowState*  aReflowState,
                               nsDidReflowStatus aStatus)
 {
-  nsSVGOuterSVGFrameBase::DidReflow(aPresContext,aReflowState,aStatus);
+  nsSVGDisplayContainerFrame::DidReflow(aPresContext,aReflowState,aStatus);
 
   // Make sure elements styled by :hover get updated if script/animation moves
   // them under or out from under the pointer:
   PresContext()->PresShell()->SynthesizeMouseMove(false);
 }
 
 /* virtual */ bool
 nsSVGOuterSVGFrame::UpdateOverflow()
@@ -951,17 +950,17 @@ NS_IMPL_FRAMEARENA_HELPERS(nsSVGOuterSVG
 #ifdef DEBUG
 void
 nsSVGOuterSVGAnonChildFrame::Init(nsIContent*       aContent,
                                   nsContainerFrame* aParent,
                                   nsIFrame*         aPrevInFlow)
 {
   MOZ_ASSERT(aParent->GetType() == nsGkAtoms::svgOuterSVGFrame,
              "Unexpected parent");
-  nsSVGOuterSVGAnonChildFrameBase::Init(aContent, aParent, aPrevInFlow);
+  nsSVGDisplayContainerFrame::Init(aContent, aParent, aPrevInFlow);
 }
 #endif
 
 nsIAtom *
 nsSVGOuterSVGAnonChildFrame::GetType() const
 {
   return nsGkAtoms::svgOuterSVGAnonChildFrame;
 }
--- a/layout/svg/nsSVGOuterSVGFrame.h
+++ b/layout/svg/nsSVGOuterSVGFrame.h
@@ -12,20 +12,18 @@
 #include "nsRegion.h"
 
 class gfxContext;
 class nsSVGForeignObjectFrame;
 
 ////////////////////////////////////////////////////////////////////////
 // nsSVGOuterSVGFrame class
 
-typedef nsSVGDisplayContainerFrame nsSVGOuterSVGFrameBase;
-
-class nsSVGOuterSVGFrame final : public nsSVGOuterSVGFrameBase,
-                                 public nsISVGSVGFrame
+class nsSVGOuterSVGFrame final : public nsSVGDisplayContainerFrame
+                               , public nsISVGSVGFrame
 {
   friend nsContainerFrame*
   NS_NewSVGOuterSVGFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 protected:
   explicit nsSVGOuterSVGFrame(nsStyleContext* aContext);
 
 public:
   NS_DECL_QUERYFRAME
@@ -204,18 +202,16 @@ protected:
 
   bool mViewportInitialized;
   bool mIsRootContent;
 };
 
 ////////////////////////////////////////////////////////////////////////
 // nsSVGOuterSVGAnonChildFrame class
 
-typedef nsSVGDisplayContainerFrame nsSVGOuterSVGAnonChildFrameBase;
-
 /**
  * nsSVGOuterSVGFrames have a single direct child that is an instance of this
  * class, and which is used to wrap their real child frames. Such anonymous
  * wrapper frames created from this class exist because SVG frames need their
  * GetPosition() offset to be their offset relative to "user space" (in app
  * units) so that they can play nicely with nsDisplayTransform. This is fine
  * for all SVG frames except for direct children of an nsSVGOuterSVGFrame,
  * since an nsSVGOuterSVGFrame can have CSS border and padding (unlike other
@@ -229,25 +225,24 @@ typedef nsSVGDisplayContainerFrame nsSVG
  * keeps both nsDisplayTransform and nsIFrame::GetOffsetTo happy.
  *
  * The reason that this class inherit from nsSVGDisplayContainerFrame rather
  * than simply from nsContainerFrame is so that we can avoid having special
  * handling for these inner wrappers in multiple parts of the SVG code. For
  * example, the implementations of IsSVGTransformed and GetCanvasTM assume
  * nsSVGContainerFrame instances all the way up to the nsSVGOuterSVGFrame.
  */
-class nsSVGOuterSVGAnonChildFrame
-  : public nsSVGOuterSVGAnonChildFrameBase
+class nsSVGOuterSVGAnonChildFrame : public nsSVGDisplayContainerFrame
 {
   friend nsContainerFrame*
   NS_NewSVGOuterSVGAnonChildFrame(nsIPresShell* aPresShell,
                                   nsStyleContext* aContext);
 
   explicit nsSVGOuterSVGAnonChildFrame(nsStyleContext* aContext)
-    : nsSVGOuterSVGAnonChildFrameBase(aContext)
+    : nsSVGDisplayContainerFrame(aContext)
   {}
 
 public:
   NS_DECL_FRAMEARENA_HELPERS
 
 #ifdef DEBUG
   virtual void Init(nsIContent*       aContent,
                     nsContainerFrame* aParent,
--- a/layout/svg/nsSVGPaintServerFrame.h
+++ b/layout/svg/nsSVGPaintServerFrame.h
@@ -21,25 +21,23 @@ class DrawTarget;
 } // namespace mozilla
 
 class gfxContext;
 class gfxPattern;
 class nsStyleContext;
 
 struct gfxRect;
 
-typedef nsSVGContainerFrame nsSVGPaintServerFrameBase;
-
-class nsSVGPaintServerFrame : public nsSVGPaintServerFrameBase
+class nsSVGPaintServerFrame : public nsSVGContainerFrame
 {
 protected:
   typedef mozilla::gfx::DrawTarget DrawTarget;
 
   explicit nsSVGPaintServerFrame(nsStyleContext* aContext)
-    : nsSVGPaintServerFrameBase(aContext)
+    : nsSVGContainerFrame(aContext)
   {
     AddStateBits(NS_FRAME_IS_NONDISPLAY);
   }
 
 public:
   NS_DECL_ABSTRACT_FRAME(nsSVGPaintServerFrame)
 
   /**
@@ -60,13 +58,13 @@ public:
 
   // nsIFrame methods:
   virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                 const nsRect&           aDirtyRect,
                                 const nsDisplayListSet& aLists) override {}
 
   virtual bool IsFrameOfType(uint32_t aFlags) const override
   {
-    return nsSVGPaintServerFrameBase::IsFrameOfType(aFlags & ~nsIFrame::eSVGPaintServer);
+    return nsSVGContainerFrame::IsFrameOfType(aFlags & ~nsIFrame::eSVGPaintServer);
   }
 };
 
 #endif // __NS_SVGPAINTSERVERFRAME_H__
--- a/layout/svg/nsSVGPathGeometryFrame.cpp
+++ b/layout/svg/nsSVGPathGeometryFrame.cpp
@@ -45,17 +45,17 @@ NS_NewSVGPathGeometryFrame(nsIPresShell*
 NS_IMPL_FRAMEARENA_HELPERS(nsSVGPathGeometryFrame)
 
 //----------------------------------------------------------------------
 // nsQueryFrame methods
 
 NS_QUERYFRAME_HEAD(nsSVGPathGeometryFrame)
   NS_QUERYFRAME_ENTRY(nsISVGChildFrame)
   NS_QUERYFRAME_ENTRY(nsSVGPathGeometryFrame)
-NS_QUERYFRAME_TAIL_INHERITING(nsSVGPathGeometryFrameBase)
+NS_QUERYFRAME_TAIL_INHERITING(nsFrame)
 
 //----------------------------------------------------------------------
 // Display list item:
 
 class nsDisplaySVGPathGeometry : public nsDisplayItem {
 public:
   nsDisplaySVGPathGeometry(nsDisplayListBuilder* aBuilder,
                            nsSVGPathGeometryFrame* aFrame)
@@ -118,17 +118,17 @@ nsDisplaySVGPathGeometry::Paint(nsDispla
 // nsIFrame methods
 
 void
 nsSVGPathGeometryFrame::Init(nsIContent*       aContent,
                              nsContainerFrame* aParent,
                              nsIFrame*         aPrevInFlow)
 {
   AddStateBits(aParent->GetStateBits() & NS_STATE_SVG_CLIPPATH_CHILD);
-  nsSVGPathGeometryFrameBase::Init(aContent, aParent, aPrevInFlow);
+  nsFrame::Init(aContent, aParent, aPrevInFlow);
 }
 
 nsresult
 nsSVGPathGeometryFrame::AttributeChanged(int32_t         aNameSpaceID,
                                          nsIAtom*        aAttribute,
                                          int32_t         aModType)
 {
   // We don't invalidate for transform changes (the layers code does that).
@@ -145,17 +145,17 @@ nsSVGPathGeometryFrame::AttributeChanged
     nsSVGUtils::ScheduleReflowSVG(this);
   }
   return NS_OK;
 }
 
 /* virtual */ void
 nsSVGPathGeometryFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
 {
-  nsSVGPathGeometryFrameBase::DidSetStyleContext(aOldStyleContext);
+  nsFrame::DidSetStyleContext(aOldStyleContext);
 
   if (aOldStyleContext) {
     auto oldStyleEffects = aOldStyleContext->PeekStyleEffects();
     if (oldStyleEffects &&
         StyleEffects()->mOpacity != oldStyleEffects->mOpacity &&
         nsSVGUtils::CanOptimizeOpacity(this)) {
       // nsIFrame::BuildDisplayListForStackingContext() is not going to create an
       // nsDisplayOpacity display list item, so DLBI won't invalidate for us.
--- a/layout/svg/nsSVGPathGeometryFrame.h
+++ b/layout/svg/nsSVGPathGeometryFrame.h
@@ -27,48 +27,46 @@ class nsIAtom;
 class nsIFrame;
 class nsIPresShell;
 class nsStyleContext;
 class nsSVGMarkerFrame;
 class nsSVGMarkerProperty;
 
 struct nsRect;
 
-typedef nsFrame nsSVGPathGeometryFrameBase;
-
-class nsSVGPathGeometryFrame : public nsSVGPathGeometryFrameBase,
-                               public nsISVGChildFrame
+class nsSVGPathGeometryFrame : public nsFrame
+                             , public nsISVGChildFrame
 {
   typedef mozilla::gfx::DrawTarget DrawTarget;
 
   friend nsIFrame*
   NS_NewSVGPathGeometryFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 
   friend class nsDisplaySVGPathGeometry;
 
 protected:
   explicit nsSVGPathGeometryFrame(nsStyleContext* aContext)
-    : nsSVGPathGeometryFrameBase(aContext)
+    : nsFrame(aContext)
   {
      AddStateBits(NS_FRAME_SVG_LAYOUT | NS_FRAME_MAY_BE_TRANSFORMED);
   }
 
 public:
   NS_DECL_QUERYFRAME_TARGET(nsSVGPathGeometryFrame)
   NS_DECL_QUERYFRAME
   NS_DECL_FRAMEARENA_HELPERS
 
   // nsIFrame interface:
   virtual void Init(nsIContent*       aContent,
                     nsContainerFrame* aParent,
                     nsIFrame*         aPrevInFlow) override;
 
   virtual bool IsFrameOfType(uint32_t aFlags) const override
   {
-    return nsSVGPathGeometryFrameBase::IsFrameOfType(aFlags & ~(nsIFrame::eSVG | nsIFrame::eSVGGeometry));
+    return nsFrame::IsFrameOfType(aFlags & ~(nsIFrame::eSVG | nsIFrame::eSVGGeometry));
   }
 
   virtual nsresult  AttributeChanged(int32_t         aNameSpaceID,
                                      nsIAtom*        aAttribute,
                                      int32_t         aModType) override;
 
   virtual void DidSetStyleContext(nsStyleContext* aOldStyleContext) override;
 
--- a/layout/svg/nsSVGPatternFrame.cpp
+++ b/layout/svg/nsSVGPatternFrame.cpp
@@ -50,20 +50,20 @@ public:
 private:
   nsSVGPatternFrame *mFrame;
   MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
 //----------------------------------------------------------------------
 // Implementation
 
-nsSVGPatternFrame::nsSVGPatternFrame(nsStyleContext* aContext) :
-  nsSVGPatternFrameBase(aContext),
-  mLoopFlag(false),
-  mNoHRefURI(false)
+nsSVGPatternFrame::nsSVGPatternFrame(nsStyleContext* aContext)
+  : nsSVGPaintServerFrame(aContext)
+  , mLoopFlag(false)
+  , mNoHRefURI(false)
 {
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsSVGPatternFrame)
 
 //----------------------------------------------------------------------
 // nsIFrame methods:
 
@@ -89,29 +89,29 @@ nsSVGPatternFrame::AttributeChanged(int3
       aAttribute == nsGkAtoms::href) {
     // Blow away our reference, if any
     Properties().Delete(nsSVGEffects::HrefProperty());
     mNoHRefURI = false;
     // And update whoever references us
     nsSVGEffects::InvalidateDirectRenderingObservers(this);
   }
 
-  return nsSVGPatternFrameBase::AttributeChanged(aNameSpaceID,
+  return nsSVGPaintServerFrame::AttributeChanged(aNameSpaceID,
                                                  aAttribute, aModType);
 }
 
 #ifdef DEBUG
 void
 nsSVGPatternFrame::Init(nsIContent*       aContent,
                         nsContainerFrame* aParent,
                         nsIFrame*         aPrevInFlow)
 {
   NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::pattern), "Content is not an SVG pattern");
 
-  nsSVGPatternFrameBase::Init(aContent, aParent, aPrevInFlow);
+  nsSVGPaintServerFrame::Init(aContent, aParent, aPrevInFlow);
 }
 #endif /* DEBUG */
 
 nsIAtom*
 nsSVGPatternFrame::GetType() const
 {
   return nsGkAtoms::svgPatternFrame;
 }
--- a/layout/svg/nsSVGPatternFrame.h
+++ b/layout/svg/nsSVGPatternFrame.h
@@ -17,23 +17,21 @@ class nsSVGLength2;
 class nsSVGPathGeometryFrame;
 class nsSVGViewBox;
 
 namespace mozilla {
 class SVGAnimatedPreserveAspectRatio;
 class nsSVGAnimatedTransformList;
 } // namespace mozilla
 
-typedef nsSVGPaintServerFrame  nsSVGPatternFrameBase;
-
 /**
  * Patterns can refer to other patterns. We create an nsSVGPaintingProperty
  * with property type nsGkAtoms::href to track the referenced pattern.
  */
-class nsSVGPatternFrame : public nsSVGPatternFrameBase
+class nsSVGPatternFrame : public nsSVGPaintServerFrame
 {
   typedef mozilla::gfx::SourceSurface SourceSurface;
 
 public:
   NS_DECL_FRAMEARENA_HELPERS
 
   friend nsIFrame* NS_NewSVGPatternFrame(nsIPresShell* aPresShell,
                                          nsStyleContext* aContext);
--- a/layout/svg/nsSVGStopFrame.cpp
+++ b/layout/svg/nsSVGStopFrame.cpp
@@ -9,25 +9,23 @@
 #include "nsGkAtoms.h"
 #include "nsStyleContext.h"
 #include "nsSVGEffects.h"
 
 // This is a very simple frame whose only purpose is to capture style change
 // events and propagate them to the parent.  Most of the heavy lifting is done
 // within the nsSVGGradientFrame, which is the parent for this frame
 
-typedef nsFrame  nsSVGStopFrameBase;
-
-class nsSVGStopFrame : public nsSVGStopFrameBase
+class nsSVGStopFrame : public nsFrame
 {
   friend nsIFrame*
   NS_NewSVGStopFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 protected:
   explicit nsSVGStopFrame(nsStyleContext* aContext)
-    : nsSVGStopFrameBase(aContext)
+    : nsFrame(aContext)
   {
     AddStateBits(NS_FRAME_IS_NONDISPLAY);
   }
 
 public:
   NS_DECL_FRAMEARENA_HELPERS
 
   // nsIFrame interface:
@@ -49,17 +47,17 @@ public:
    * Get the "type" of the frame
    *
    * @see nsGkAtoms::svgStopFrame
    */
   virtual nsIAtom* GetType() const override;
 
   virtual bool IsFrameOfType(uint32_t aFlags) const override
   {
-    return nsSVGStopFrameBase::IsFrameOfType(aFlags & ~(nsIFrame::eSVG));
+    return nsFrame::IsFrameOfType(aFlags & ~(nsIFrame::eSVG));
   }
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const override
   {
     return MakeFrameName(NS_LITERAL_STRING("SVGStop"), aResult);
   }
 #endif
@@ -76,17 +74,17 @@ NS_IMPL_FRAMEARENA_HELPERS(nsSVGStopFram
 #ifdef DEBUG
 void
 nsSVGStopFrame::Init(nsIContent*       aContent,
                      nsContainerFrame* aParent,
                      nsIFrame*         aPrevInFlow)
 {
   NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::stop), "Content is not a stop element");
 
-  nsSVGStopFrameBase::Init(aContent, aParent, aPrevInFlow);
+  nsFrame::Init(aContent, aParent, aPrevInFlow);
 }
 #endif /* DEBUG */
 
 nsIAtom *
 nsSVGStopFrame::GetType() const
 {
   return nsGkAtoms::svgStopFrame;
 }
@@ -99,18 +97,17 @@ nsSVGStopFrame::AttributeChanged(int32_t
   if (aNameSpaceID == kNameSpaceID_None &&
       aAttribute == nsGkAtoms::offset) {
     MOZ_ASSERT(GetParent()->GetType() == nsGkAtoms::svgLinearGradientFrame ||
                GetParent()->GetType() == nsGkAtoms::svgRadialGradientFrame,
                "Observers observe the gradient, so that's what we must invalidate");
     nsSVGEffects::InvalidateDirectRenderingObservers(GetParent());
   }
 
-  return nsSVGStopFrameBase::AttributeChanged(aNameSpaceID,
-                                              aAttribute, aModType);
+  return nsFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
 }
 
 // -------------------------------------------------------------------------
 // Public functions
 // -------------------------------------------------------------------------
 
 nsIFrame* NS_NewSVGStopFrame(nsIPresShell*   aPresShell,
                              nsStyleContext* aContext)
--- a/layout/svg/nsSVGSwitchFrame.cpp
+++ b/layout/svg/nsSVGSwitchFrame.cpp
@@ -7,25 +7,23 @@
 #include "gfxRect.h"
 #include "nsSVGEffects.h"
 #include "nsSVGGFrame.h"
 #include "mozilla/dom/SVGSwitchElement.h"
 #include "nsSVGUtils.h"
 
 using namespace mozilla::gfx;
 
-typedef nsSVGGFrame nsSVGSwitchFrameBase;
-
-class nsSVGSwitchFrame : public nsSVGSwitchFrameBase
+class nsSVGSwitchFrame : public nsSVGGFrame
 {
   friend nsIFrame*
   NS_NewSVGSwitchFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 protected:
-  explicit nsSVGSwitchFrame(nsStyleContext* aContext) :
-    nsSVGSwitchFrameBase(aContext) {}
+  explicit nsSVGSwitchFrame(nsStyleContext* aContext)
+    : nsSVGGFrame(aContext) {}
 
 public:
   NS_DECL_FRAMEARENA_HELPERS
 
 #ifdef DEBUG
   virtual void Init(nsIContent*       aContent,
                     nsContainerFrame* aParent,
                     nsIFrame*         aPrevInFlow) override;
@@ -78,17 +76,17 @@ NS_IMPL_FRAMEARENA_HELPERS(nsSVGSwitchFr
 void
 nsSVGSwitchFrame::Init(nsIContent*       aContent,
                        nsContainerFrame* aParent,
                        nsIFrame*         aPrevInFlow)
 {
   NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::svgSwitch),
                "Content is not an SVG switch");
 
-  nsSVGSwitchFrameBase::Init(aContent, aParent, aPrevInFlow);
+  nsSVGGFrame::Init(aContent, aParent, aPrevInFlow);
 }
 #endif /* DEBUG */
 
 nsIAtom *
 nsSVGSwitchFrame::GetType() const
 {
   return nsGkAtoms::svgSwitchFrame;
 }
--- a/layout/svg/nsSVGUseFrame.cpp
+++ b/layout/svg/nsSVGUseFrame.cpp
@@ -5,37 +5,34 @@
 
 // Keep in (case-insensitive) order:
 #include "nsIAnonymousContentCreator.h"
 #include "nsSVGEffects.h"
 #include "nsSVGGFrame.h"
 #include "mozilla/dom/SVGUseElement.h"
 #include "nsContentList.h"
 
-typedef nsSVGGFrame nsSVGUseFrameBase;
-
 using namespace mozilla::dom;
 
-class nsSVGUseFrame : public nsSVGUseFrameBase,
-                      public nsIAnonymousContentCreator
+class nsSVGUseFrame : public nsSVGGFrame
+                    , public nsIAnonymousContentCreator
 {
   friend nsIFrame*
   NS_NewSVGUseFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 
 protected:
-  explicit nsSVGUseFrame(nsStyleContext* aContext) :
-    nsSVGUseFrameBase(aContext),
-    mHasValidDimensions(true)
+  explicit nsSVGUseFrame(nsStyleContext* aContext)
+    : nsSVGGFrame(aContext)
+    , mHasValidDimensions(true)
   {}
 
 public:
   NS_DECL_QUERYFRAME
   NS_DECL_FRAMEARENA_HELPERS
 
-  
   // nsIFrame interface:
   virtual void Init(nsIContent*       aContent,
                     nsContainerFrame* aParent,
                     nsIFrame*         aPrevInFlow) override;
 
   virtual nsresult  AttributeChanged(int32_t         aNameSpaceID,
                                      nsIAtom*        aAttribute,
                                      int32_t         aModType) override;
@@ -88,33 +85,33 @@ nsSVGUseFrame::GetType() const
   return nsGkAtoms::svgUseFrame;
 }
 
 //----------------------------------------------------------------------
 // nsQueryFrame methods
 
 NS_QUERYFRAME_HEAD(nsSVGUseFrame)
   NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator)
-NS_QUERYFRAME_TAIL_INHERITING(nsSVGUseFrameBase)
+NS_QUERYFRAME_TAIL_INHERITING(nsSVGGFrame)
 
 //----------------------------------------------------------------------
 // nsIFrame methods:
 
 void
 nsSVGUseFrame::Init(nsIContent*       aContent,
                     nsContainerFrame* aParent,
                     nsIFrame*         aPrevInFlow)
 {
   NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::use),
                "Content is not an SVG use!");
 
   mHasValidDimensions =
     static_cast<SVGUseElement*>(aContent)->HasValidDimensions();
 
-  nsSVGUseFrameBase::Init(aContent, aParent, aPrevInFlow);
+  nsSVGGFrame::Init(aContent, aParent, aPrevInFlow);
 }
 
 nsresult
 nsSVGUseFrame::AttributeChanged(int32_t         aNameSpaceID,
                                 nsIAtom*        aAttribute,
                                 int32_t         aModType)
 {
   SVGUseElement *useElement = static_cast<SVGUseElement*>(mContent);
@@ -154,25 +151,24 @@ nsSVGUseFrame::AttributeChanged(int32_t 
       useElement, nsRestyleHint(0),
       nsChangeHint_InvalidateRenderingObservers);
     nsSVGUtils::ScheduleReflowSVG(this);
     useElement->mOriginal = nullptr;
     useElement->UnlinkSource();
     useElement->TriggerReclone();
   }
 
-  return nsSVGUseFrameBase::AttributeChanged(aNameSpaceID,
-                                             aAttribute, aModType);
+  return nsSVGGFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
 }
 
 void
 nsSVGUseFrame::DestroyFrom(nsIFrame* aDestructRoot)
 {
   RefPtr<SVGUseElement> use = static_cast<SVGUseElement*>(mContent);
-  nsSVGUseFrameBase::DestroyFrom(aDestructRoot);
+  nsSVGGFrame::DestroyFrom(aDestructRoot);
   use->DestroyAnonymousContent();
 }
 
 bool
 nsSVGUseFrame::IsLeaf() const
 {
   return true;
 }
@@ -195,17 +191,17 @@ nsSVGUseFrame::ReflowSVG()
                  PresContext()->AppUnitsPerCSSPixel()).TopLeft());
 
   // If we have a filter, we need to invalidate ourselves because filter
   // output can change even if none of our descendants need repainting.
   if (StyleEffects()->HasFilters()) {
     InvalidateFrame();
   }
 
-  nsSVGUseFrameBase::ReflowSVG();
+  nsSVGGFrame::ReflowSVG();
 }
 
 void
 nsSVGUseFrame::NotifySVGChanged(uint32_t aFlags)
 {
   if (aFlags & COORD_CONTEXT_CHANGED &&
       !(aFlags & TRANSFORM_CHANGED)) {
     // Coordinate context changes affect mCanvasTM if we have a
@@ -223,17 +219,17 @@ nsSVGUseFrame::NotifySVGChanged(uint32_t
       nsSVGUtils::ScheduleReflowSVG(this);
     }
   }
 
   // We don't remove the TRANSFORM_CHANGED flag here if we have a viewBox or
   // non-percentage width/height, since if they're set then they are cloned to
   // an anonymous child <svg>, and its nsSVGInnerSVGFrame will do that.
 
-  nsSVGUseFrameBase::NotifySVGChanged(aFlags);
+  nsSVGGFrame::NotifySVGChanged(aFlags);
 }
 
 //----------------------------------------------------------------------
 // nsIAnonymousContentCreator methods:
 
 nsresult
 nsSVGUseFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
 {
--- a/layout/xul/nsTextBoxFrame.cpp
+++ b/layout/xul/nsTextBoxFrame.cpp
@@ -63,17 +63,17 @@ NS_NewTextBoxFrame (nsIPresShell* aPresS
 {
     return new (aPresShell) nsTextBoxFrame(aContext);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsTextBoxFrame)
 
 NS_QUERYFRAME_HEAD(nsTextBoxFrame)
   NS_QUERYFRAME_ENTRY(nsTextBoxFrame)
-NS_QUERYFRAME_TAIL_INHERITING(nsTextBoxFrameSuper)
+NS_QUERYFRAME_TAIL_INHERITING(nsLeafBoxFrame)
 
 nsresult
 nsTextBoxFrame::AttributeChanged(int32_t         aNameSpaceID,
                                  nsIAtom*        aAttribute,
                                  int32_t         aModType)
 {
     bool aResize;
     bool aRedraw;
@@ -110,32 +110,32 @@ nsTextBoxFrame::~nsTextBoxFrame()
 }
 
 
 void
 nsTextBoxFrame::Init(nsIContent*       aContent,
                      nsContainerFrame* aParent,
                      nsIFrame*         aPrevInFlow)
 {
-    nsTextBoxFrameSuper::Init(aContent, aParent, aPrevInFlow);
+    nsLeafBoxFrame::Init(aContent, aParent, aPrevInFlow);
 
     bool aResize;
     bool aRedraw;
     UpdateAttributes(nullptr, aResize, aRedraw); /* update all */
 
     // register access key
     RegUnregAccessKey(true);
 }
 
 void
 nsTextBoxFrame::DestroyFrom(nsIFrame* aDestructRoot)
 {
     // unregister access key
     RegUnregAccessKey(false);
-    nsTextBoxFrameSuper::DestroyFrom(aDestructRoot);
+    nsLeafBoxFrame::DestroyFrom(aDestructRoot);
 }
 
 bool
 nsTextBoxFrame::AlwaysAppendAccessKey()
 {
   if (!gAccessKeyPrefInitialized) 
   {
     gAccessKeyPrefInitialized = true;
@@ -1016,17 +1016,17 @@ nsTextBoxFrame::ComputesOwnOverflowArea(
 {
     return true;
 }
 
 /* virtual */ void
 nsTextBoxFrame::MarkIntrinsicISizesDirty()
 {
     mNeedsRecalc = true;
-    nsTextBoxFrameSuper::MarkIntrinsicISizesDirty();
+    nsLeafBoxFrame::MarkIntrinsicISizesDirty();
 }
 
 void
 nsTextBoxFrame::GetTextSize(nsRenderingContext& aRenderingContext,
                             const nsString& aString,
                             nsSize& aSize, nscoord& aAscent)
 {
     RefPtr<nsFontMetrics> fontMet =
--- a/layout/xul/nsTextBoxFrame.h
+++ b/layout/xul/nsTextBoxFrame.h
@@ -7,18 +7,17 @@
 
 #include "mozilla/Attributes.h"
 #include "nsLeafBoxFrame.h"
 
 class nsAccessKeyInfo;
 class nsAsyncAccesskeyUpdate;
 class nsFontMetrics;
 
-typedef nsLeafBoxFrame nsTextBoxFrameSuper;
-class nsTextBoxFrame : public nsTextBoxFrameSuper
+class nsTextBoxFrame : public nsLeafBoxFrame
 {
 public:
   NS_DECL_QUERYFRAME_TARGET(nsTextBoxFrame)
   NS_DECL_QUERYFRAME
   NS_DECL_FRAMEARENA_HELPERS
 
   virtual nsSize GetPrefSize(nsBoxLayoutState& aBoxLayoutState) override;
   virtual nsSize GetMinSize(nsBoxLayoutState& aBoxLayoutState) override;
--- a/media/mtransport/test/ice_unittest.cpp
+++ b/media/mtransport/test/ice_unittest.cpp
@@ -3289,17 +3289,19 @@ TEST_F(WebRtcIceConnectTest, TestPollCan
 
   r = p2_->GetCandidatePairs(0, &pairs);
   ASSERT_EQ(NS_OK, r);
   ASSERT_NE(0U, pairs.size());
   ASSERT_TRUE(p2_->CandidatePairsPriorityDescending(pairs));
   ASSERT_TRUE(ContainsSucceededPair(pairs));
 }
 
-TEST_F(WebRtcIceConnectTest, TestHostCandPairingFilter) {
+// TODO Bug 1259842 - disabled until we find a better way to handle two
+// candidates from different RFC1918 ranges
+TEST_F(WebRtcIceConnectTest, DISABLED_TestHostCandPairingFilter) {
   Init(false, false, false, false);
   AddStream("first", 1);
   ASSERT_TRUE(Gather());
   SetCandidateFilter(IsIpv4Candidate);
 
   int host_net = p1_->GetCandidatesPrivateIpv4Range(0);
   if (host_net <= 0) {
     // TODO bug 1226838: make this work with multiple private IPs
--- a/media/mtransport/third_party/nICEr/src/ice/ice_component.c
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_component.c
@@ -986,36 +986,31 @@ int nr_ice_component_can_candidate_tcpty
     if (left == TCP_TYPE_SO && right != TCP_TYPE_SO)
       return(0);
     if (left == TCP_TYPE_PASSIVE)
       return(0);
 
     return(1);
   }
 
-/* local vs. remote matters here because we allow private -> public pairing,
- * but discourage public -> private pairing. */
+/* filter out pairings which won't work. */
 int nr_ice_component_can_candidate_addr_pair(nr_transport_addr *local, nr_transport_addr *remote)
   {
     int remote_range;
 
     if(local->ip_version != remote->ip_version)
       return(0);
     if(nr_transport_addr_is_link_local(local) !=
        nr_transport_addr_is_link_local(remote))
       return(0);
     /* This prevents our ice_unittest (or broken clients) from pairing a
      * loopback with a host candidate. */
     if(nr_transport_addr_is_loopback(local) !=
        nr_transport_addr_is_loopback(remote))
       return(0);
-    remote_range = nr_transport_addr_get_private_addr_range(remote);
-    if(remote_range && (nr_transport_addr_get_private_addr_range(local) !=
-       remote_range))
-      return(0);
 
     return(1);
   }
 
 int nr_ice_component_pair_candidate(nr_ice_peer_ctx *pctx, nr_ice_component *pcomp, nr_ice_candidate *lcand, int pair_all_remote)
   {
     int r, _status;
     nr_ice_candidate *pcand;
--- a/media/webrtc/signaling/src/media-conduit/WebrtcOMXH264VideoCodec.cpp
+++ b/media/webrtc/signaling/src/media-conduit/WebrtcOMXH264VideoCodec.cpp
@@ -524,17 +524,17 @@ public:
     RefPtr<layers::TextureClient> buffer = mNativeWindow->getCurrentBuffer();
     if (!buffer) {
       CODEC_LOGE("Decoder NewFrame: Get null buffer");
       return;
     }
 
     gfx::IntSize picSize(buffer->GetSize());
     nsAutoPtr<layers::GrallocImage> grallocImage(new layers::GrallocImage());
-    grallocImage->SetData(buffer, picSize);
+    grallocImage->AdoptData(buffer, picSize);
 
     // Get timestamp of the frame about to render.
     int64_t timestamp = -1;
     int64_t renderTimeMs = -1;
     {
       MutexAutoLock lock(mDecodedFrameLock);
       if (mDecodedFrames.empty()) {
         return;
@@ -999,18 +999,18 @@ WebrtcOMXH264VideoEncoder::Encode(const 
   yuvData.mCbCrStride = aInputImage.stride(webrtc::kUPlane);
   yuvData.mCbChannel = const_cast<uint8_t*>(aInputImage.buffer(webrtc::kUPlane));
   yuvData.mCrChannel = const_cast<uint8_t*>(aInputImage.buffer(webrtc::kVPlane));
   yuvData.mCbCrSize = gfx::IntSize((yuvData.mYSize.width + 1) / 2,
                                    (yuvData.mYSize.height + 1) / 2);
   yuvData.mPicSize = yuvData.mYSize;
   yuvData.mStereoMode = StereoMode::MONO;
   layers::RecyclingPlanarYCbCrImage img(nullptr);
-  // SetDataNoCopy() doesn't need AllocateAndGetNewBuffer(); OMXVideoEncoder is ok with this
-  img.SetDataNoCopy(yuvData);
+  // AdoptData() doesn't need AllocateAndGetNewBuffer(); OMXVideoEncoder is ok with this
+  img.AdoptData(yuvData);
 
   CODEC_LOGD("Encode frame: %dx%d, timestamp %u (%lld), renderTimeMs %" PRIu64,
              aInputImage.width(), aInputImage.height(),
              aInputImage.timestamp(), aInputImage.timestamp() * 1000ll / 90,
              aInputImage.render_time_ms());
 
   nsresult rv = mOMX->Encode(&img,
                              yuvData.mYSize.width,
--- a/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp
+++ b/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp
@@ -2229,17 +2229,17 @@ public:
       yuvData.mCbChannel = frame + height_ * yuvData.mYStride;
       yuvData.mCrChannel = yuvData.mCbChannel + ((height_ + 1) >> 1) * yuvData.mCbCrStride;
       yuvData.mCbCrSize = IntSize(yuvData.mCbCrStride, (height_ + 1) >> 1);
       yuvData.mPicX = 0;
       yuvData.mPicY = 0;
       yuvData.mPicSize = IntSize(width_, height_);
       yuvData.mStereoMode = StereoMode::MONO;
 
-      if (!yuvImage->SetData(yuvData)) {
+      if (!yuvImage->CopyData(yuvData)) {
         MOZ_ASSERT(false);
         return;
       }
 
       image_ = yuvImage;
     }
 #ifdef WEBRTC_GONK
     else {
--- a/media/webrtc/signaling/src/sdp/sipcc/sdp_token.c
+++ b/media/webrtc/signaling/src/sdp/sipcc/sdp_token.c
@@ -753,21 +753,19 @@ sdp_result_e sdp_parse_bandwidth (sdp_t 
         if (cpr_strncasecmp(tmp, sdp_bw_modifier_val[i].name,
                         sdp_bw_modifier_val[i].strlen) == 0) {
             bw_modifier  = (sdp_bw_modifier_e)i;
             break;
         }
     }
 
     if (bw_modifier == SDP_BW_MODIFIER_UNSUPPORTED) {
-        sdp_parse_error(sdp_p,
-            "%s Error: BW Modifier type unsupported (%s).",
-            sdp_p->debug_str, tmp);
-        sdp_p->conf_p->num_invalid_param++;
-        return (SDP_INVALID_PARAMETER);
+        /* We don't understand this parameter, so according to RFC4566 sec 5.8
+         * ignore it. */
+        return (SDP_SUCCESS);
     }
 
     /* Find the BW type value */
     /*sa_ignore NO_NULL_CHK
       {ptr is valid since the pointer was checked earlier and the
        function would have exited if NULL.}*/
     if (*ptr == ':') {
         ptr++;
--- a/media/webrtc/signaling/test/sdp_unittests.cpp
+++ b/media/webrtc/signaling/test/sdp_unittests.cpp
@@ -1041,22 +1041,28 @@ TEST_P(NewSdpTest, CheckGetMissingBandwi
 }
 
 TEST_P(NewSdpTest, CheckGetBandwidth) {
   ParseSdp("v=0" CRLF
            "o=- 4294967296 2 IN IP4 127.0.0.1" CRLF
            "s=SIP Call" CRLF
            "c=IN IP4 198.51.100.7" CRLF
            "b=CT:5000" CRLF
+           "b=FOOBAR:10" CRLF
+           "b=AS:4" CRLF
            "t=0 0" CRLF
            "m=video 56436 RTP/SAVPF 120" CRLF
            "a=rtpmap:120 VP8/90000" CRLF
            );
   ASSERT_EQ(5000U, mSdp->GetBandwidth("CT"))
-    << "Wrong bandwidth in session";
+    << "Wrong CT bandwidth in session";
+  ASSERT_EQ(0U, mSdp->GetBandwidth("FOOBAR"))
+    << "Wrong FOOBAR bandwidth in session";
+  ASSERT_EQ(4U, mSdp->GetBandwidth("AS"))
+    << "Wrong AS bandwidth in session";
 }
 
 TEST_P(NewSdpTest, CheckGetMediaSectionsCount) {
   ParseSdp(kVideoSdp);
   ASSERT_EQ(1U, mSdp->GetMediaSectionCount())
     << "Wrong number of media sections";
 }
 
--- a/mfbt/Attributes.h
+++ b/mfbt/Attributes.h
@@ -517,16 +517,19 @@
  *   a compile time error to instantiate this template with a type parameter which
  *   has a VTable.
  * MOZ_NON_MEMMOVABLE: Applies to class declarations for types that are not safe
  *   to be moved in memory using memmove().
  * MOZ_NEEDS_MEMMOVABLE_TYPE: Applies to template class declarations where the
  *   template arguments are required to be safe to move in memory using
  *   memmove().  Passing MOZ_NON_MEMMOVABLE types to these templates is a
  *   compile time error.
+ * MOZ_NEEDS_MEMMOVABLE_MEMBERS: Applies to class declarations where each member
+ *   must be safe to move in memory using memmove().  MOZ_NON_MEMMOVABLE types
+ *   used in members of these classes are compile time errors.
  * MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS: Applies to template class
  *   declarations where an instance of the template should be considered, for
  *   static analysis purposes, to inherit any type annotations (such as
  *   MOZ_MUST_USE and MOZ_STACK_CLASS) from its template arguments.
  * MOZ_NON_AUTOABLE: Applies to class declarations. Makes it a compile time error to
  *   use `auto` in place of this type in variable declarations.  This is intended to
  *   be used with types which are intended to be implicitly constructed into other
  *   other types before being assigned to variables.
@@ -550,16 +553,17 @@
 #  define MOZ_OWNING_REF __attribute__((annotate("moz_strong_ref")))
 #  define MOZ_NON_OWNING_REF __attribute__((annotate("moz_weak_ref")))
 #  define MOZ_UNSAFE_REF(reason) __attribute__((annotate("moz_weak_ref")))
 #  define MOZ_NO_ADDREF_RELEASE_ON_RETURN __attribute__((annotate("moz_no_addref_release_on_return")))
 #  define MOZ_MUST_USE __attribute__((annotate("moz_must_use")))
 #  define MOZ_NEEDS_NO_VTABLE_TYPE __attribute__((annotate("moz_needs_no_vtable_type")))
 #  define MOZ_NON_MEMMOVABLE __attribute__((annotate("moz_non_memmovable")))
 #  define MOZ_NEEDS_MEMMOVABLE_TYPE __attribute__((annotate("moz_needs_memmovable_type")))
+#  define MOZ_NEEDS_MEMMOVABLE_MEMBERS __attribute__((annotate("moz_needs_memmovable_members")))
 #  define MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS \
     __attribute__((annotate("moz_inherit_type_annotations_from_template_args")))
 #  define MOZ_NON_AUTOABLE __attribute__((annotate("moz_non_autoable")))
 /*
  * It turns out that clang doesn't like void func() __attribute__ {} without a
  * warning, so use pragmas to disable the warning. This code won't work on GCC
  * anyways, so the warning is safe to ignore.
  */
@@ -582,16 +586,17 @@
 #  define MOZ_OWNING_REF /* nothing */
 #  define MOZ_NON_OWNING_REF /* nothing */
 #  define MOZ_UNSAFE_REF(reason) /* nothing */
 #  define MOZ_NO_ADDREF_RELEASE_ON_RETURN /* nothing */
 #  define MOZ_MUST_USE /* nothing */
 #  define MOZ_NEEDS_NO_VTABLE_TYPE /* nothing */
 #  define MOZ_NON_MEMMOVABLE /* nothing */
 #  define MOZ_NEEDS_MEMMOVABLE_TYPE /* nothing */
+#  define MOZ_NEEDS_MEMMOVABLE_MEMBERS /* nothing */
 #  define MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS /* nothing */
 #  define MOZ_NON_AUTOABLE /* nothing */
 #endif /* MOZ_CLANG_PLUGIN */
 
 #define MOZ_RAII MOZ_NON_TEMPORARY_CLASS MOZ_STACK_CLASS
 
 /*
  * MOZ_HAVE_REF_QUALIFIERS is defined for compilers that support C++11's rvalue
--- a/python/mach_commands.py
+++ b/python/mach_commands.py
@@ -63,62 +63,105 @@ class MachCommands(MachCommandBase):
 
         return self.run_process([self.virtualenv_manager.python_path] + args,
             pass_thru=True,  # Allow user to run Python interactively.
             ensure_exit_code=False,  # Don't throw on non-zero exit code.
             # Note: subprocess requires native strings in os.environ on Windows
             append_env={b'PYTHONDONTWRITEBYTECODE': str('1')})
 
     @Command('python-test', category='testing',
-        description='Run Python unit tests.')
+        description='Run Python unit tests with an appropriate test runner.')
     @CommandArgument('--verbose',
         default=False,
         action='store_true',
         help='Verbose output.')
     @CommandArgument('--stop',
         default=False,
         action='store_true',
         help='Stop running tests after the first error or failure.')
+    @CommandArgument('--path-only',
+        default=False,
+        action='store_true',
+        help=('Collect all tests under given path instead of default '
+              'test resolution. Supports pytest-style tests.'))
     @CommandArgument('tests', nargs='*',
         metavar='TEST',
-        help='Tests to run. Each test can be a single file or a directory.')
+        help=('Tests to run. Each test can be a single file or a directory. '
+              'Default test resolution relies on PYTHON_UNIT_TESTS.'))
     def python_test(self,
                     tests=[],
                     test_objects=None,
                     subsuite=None,
                     verbose=False,
+                    path_only=False,
                     stop=False):
         self._activate_virtualenv()
 
+        def find_tests_by_path():
+            import glob
+            files = []
+            for t in tests:
+                if t.endswith('.py') and os.path.isfile(t):
+                    files.append(t)
+                elif os.path.isdir(t):
+                    for root, _, _ in os.walk(t):
+                        files += glob.glob(mozpath.join(root, 'test*.py'))
+                        files += glob.glob(mozpath.join(root, 'unit*.py'))
+                else:
+                    self.log(logging.WARN, 'python-test',
+                                 {'test': t},
+                                 'TEST-UNEXPECTED-FAIL | Invalid test: {test}')
+                    if stop:
+                        break
+            return files
+
         # Python's unittest, and in particular discover, has problems with
         # clashing namespaces when importing multiple test modules. What follows
         # is a simple way to keep environments separate, at the price of
-        # launching Python multiple times. This also runs tests via mozunit,
+        # launching Python multiple times. Most tests are run via mozunit,
         # which produces output in the format Mozilla infrastructure expects.
+        # Some tests are run via pytest, and these should be equipped with a
+        # local mozunit_report plugin to meet output expectations.
         return_code = 0
+        found_tests = False
         if test_objects is None:
             # If we're not being called from `mach test`, do our own
             # test resolution.
-            from mozbuild.testing import TestResolver
-            resolver = self._spawn(TestResolver)
-            if tests:
-                # If we were given test paths, try to find tests matching them.
-                test_objects = resolver.resolve_tests(paths=tests,
-                                                      flavor='python')
+            if path_only:
+                if tests:
+                    self.virtualenv_manager.install_pip_package(
+                       'pytest==2.9.1'
+                    )
+                    test_objects = [{'path': p} for p in find_tests_by_path()]
+                else:
+                    self.log(logging.WARN, 'python-test', {},
+                             'TEST-UNEXPECTED-FAIL | No tests specified')
+                    test_objects = []
             else:
-                # Otherwise just run all Python tests.
-                test_objects = resolver.resolve_tests(flavor='python')
+                from mozbuild.testing import TestResolver
+                resolver = self._spawn(TestResolver)
+                if tests:
+                    # If we were given test paths, try to find tests matching them.
+                    test_objects = resolver.resolve_tests(paths=tests,
+                                                          flavor='python')
+                else:
+                    # Otherwise just run everything in PYTHON_UNIT_TESTS
+                    test_objects = resolver.resolve_tests(flavor='python')
 
         for test in test_objects:
+            found_tests = True
             f = test['path']
             file_displayed_test = []  # Used as a boolean.
 
             def _line_handler(line):
-                if not file_displayed_test and line.startswith('TEST-'):
-                    file_displayed_test.append(True)
+                if not file_displayed_test:
+                    output = ('Ran' in line or 'collected' in line or
+                              line.startswith('TEST-'))
+                    if output:
+                        file_displayed_test.append(True)
 
             inner_return_code = self.run_process(
                 [self.virtualenv_manager.python_path, f],
                 ensure_exit_code=False,  # Don't throw on non-zero exit code.
                 log_name='python-test',
                 # subprocess requires native strings in os.environ on Windows
                 append_env={b'PYTHONDONTWRITEBYTECODE': str('1')},
                 line_handler=_line_handler)
@@ -133,16 +176,23 @@ class MachCommands(MachCommandBase):
                     self.log(logging.INFO, 'python-test', {'file': f},
                              'Test failed: {file}')
                 else:
                     self.log(logging.INFO, 'python-test', {'file': f},
                              'Test passed: {file}')
             if stop and return_code > 0:
                 return 1
 
+        if not found_tests:
+            message = 'TEST-UNEXPECTED-FAIL | No tests collected'
+            if not path_only:
+                 message += ' (Not in PYTHON_UNIT_TESTS? Try --path-only?)'
+            self.log(logging.WARN, 'python-test', {}, message)
+            return 1
+
         return 0 if return_code == 0 else 1
 
     @Command('eslint', category='devenv',
         description='Run eslint or help configure eslint for optimal development.')
     @CommandArgument('-s', '--setup', default=False, action='store_true',
         help='configure eslint for optimal development.')
     @CommandArgument('-e', '--ext', default='[.js,.jsm,.jsx,.xml,.html]',
         help='Filename extensions to lint, default: "[.js,.jsm,.jsx,.xml,.html]".')
--- a/testing/firefox-ui/mach_commands.py
+++ b/testing/firefox-ui/mach_commands.py
@@ -55,26 +55,25 @@ def run_firefox_ui_test(testtype=None, t
 
     fxui_dir = os.path.join(topsrcdir, 'testing', 'firefox-ui')
 
     # Set the resources path which is used to serve test data via wptserve
     if not kwargs['server_root']:
         kwargs['server_root'] = os.path.join(fxui_dir, 'resources')
 
     # If no tests have been selected, set default ones
-    if kwargs.get('tests'):
-        tests = kwargs.get('tests')
-    else:
-        tests = [os.path.join(fxui_dir, 'tests', test)
+    if not kwargs.get('tests'):
+        kwargs['tests'] = [os.path.join(fxui_dir, 'tests', test)
                            for test in test_types[testtype]['default_tests']]
 
     kwargs['logger'] = commandline.setup_logging('Firefox UI - {} Tests'.format(testtype),
                                                  {"mach": sys.stdout})
 
-    args = parser.parse_args(args=tests)
+    # pass tests to parse_args to avoid rereading sys.argv
+    args = parser.parse_args(args=kwargs['tests'])
 
     for k, v in kwargs.iteritems():
         setattr(args, k, v)
 
     parser.verify_usage(args)
 
     failed = test_types[testtype]['cli_module'].cli(args=vars(args))
 
--- a/testing/marionette/harness/marionette/runner/base.py
+++ b/testing/marionette/harness/marionette/runner/base.py
@@ -210,16 +210,20 @@ class MarionetteTestResult(StructuredTes
                     self.logger.info(' '.join(line).encode('ascii', 'replace'))
                 self.logger.info('END LOG:')
 
     def stopTest(self, *args, **kwargs):
         unittest._TextTestResult.stopTest(self, *args, **kwargs)
         if self.marionette.check_for_crash():
             # this tells unittest.TestSuite not to continue running tests
             self.shouldStop = True
+            test = next((a for a in args if isinstance(a, unittest.TestCase)),
+                        None)
+            if test:
+                self.addError(test, sys.exc_info())
 
 
 class MarionetteTextTestRunner(StructuredTestRunner):
 
     resultclass = MarionetteTestResult
 
     def __init__(self, **kwargs):
         self.marionette = kwargs.pop('marionette')
@@ -466,16 +470,21 @@ class BaseMarionetteArguments(ArgumentPa
 
         return dict(prefs())
 
     def verify_usage(self, args):
         if not args.tests:
             print 'must specify one or more test files, manifests, or directories'
             sys.exit(1)
 
+        for path in args.tests:
+            if not os.path.exists(path):
+                print '{0} does not exist'.format(path)
+                sys.exit(1)
+
         if not args.emulator and not args.address and not args.binary:
             print 'must specify --binary, --emulator or --address'
             sys.exit(1)
 
         if args.emulator and args.binary:
             print 'can\'t specify both --emulator and --binary'
             sys.exit(1)
 
@@ -729,16 +738,17 @@ class BaseMarionetteTestRunner(object):
             self.marionette.cleanup()
             if self.marionette.instance:
                 self.marionette.instance = None
         self.marionette = None
 
     def reset_test_stats(self):
         self.passed = 0
         self.failed = 0
+        self.crashed = 0
         self.unexpected_successes = 0
         self.todo = 0
         self.skipped = 0
         self.failures = []
 
     def _build_kwargs(self):
         if self.logdir and not os.access(self.logdir, os.F_OK):
             os.mkdir(self.logdir)
@@ -847,16 +857,25 @@ setReq.onsuccess = function() {
 }
 setReq.onerror = function() {
     marionetteScriptFinished(false);
 }""", script_timeout=60000)
 
         if not result:
             raise Exception("Could not launch test container app")
 
+    def record_crash(self):
+        crash = True
+        try:
+            crash = self.marionette.check_for_crash()
+            self.crashed += int(crash)
+        except Exception:
+            traceback.print_exc()
+        return crash
+
     def run_tests(self, tests):
         assert len(tests) > 0
         assert len(self.test_handlers) > 0
         self.reset_test_stats()
         self.start_time = time.time()
 
         need_external_ip = True
         if not self.marionette:
@@ -959,21 +978,17 @@ setReq.onerror = function() {
         else:
             self.logger.info('todo: %d (skipped: %d)' % (self.todo, self.skipped))
 
         if self.failed > 0:
             self.logger.info('\nFAILED TESTS\n-------')
             for failed_test in self.failures:
                 self.logger.info('%s' % failed_test[0])
 
-        try:
-            self.marionette.check_for_crash()
-        except:
-            traceback.print_exc()
-
+        self.record_crash()
         self.end_time = time.time()
         self.elapsedtime = self.end_time - self.start_time
 
         if self.marionette.instance:
             self.marionette.instance.close()
             self.marionette.instance = None
 
         self.marionette.cleanup()
@@ -1130,17 +1145,17 @@ setReq.onerror = function() {
 
     def run_test_set(self, tests):
         if self.shuffle:
             random.seed(self.shuffle_seed)
             random.shuffle(tests)
 
         for test in tests:
             self.run_test(test['filepath'], test['expected'], test['test_container'])
-            if self.marionette.check_for_crash():
+            if self.record_crash():
                 break
 
     def run_test_sets(self):
         if len(self.tests) < 1:
             raise Exception('There are no tests to run.')
         elif self.total_chunks > len(self.tests):
             raise ValueError('Total number of chunks must be between 1 and %d.' % len(self.tests))
         if self.total_chunks > 1:
--- a/testing/marionette/harness/marionette/runtests.py
+++ b/testing/marionette/harness/marionette/runtests.py
@@ -60,17 +60,17 @@ class MarionetteHarness(object):
             MarionetteTestCase.pydebugger = __import__(self.args['pydebugger'])
 
     def run(self):
         try:
             self.process_args()
             tests = self.args.pop('tests')
             runner = self._runner_class(**self.args)
             runner.run_tests(tests)
-            return runner.failed
+            return runner.failed + runner.crashed
         except Exception:
             logger = self.args.get('logger')
             if logger:
                 logger.error('Failure during test execution.',
                                        exc_info=True)
             raise
 
 
--- a/testing/marionette/harness/marionette/tests/harness_unit/test_marionette_runner.py
+++ b/testing/marionette/harness/marionette/tests/harness_unit/test_marionette_runner.py
@@ -1,24 +1,61 @@
 # 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/.
 import pytest
-from mock import patch, Mock
+from mock import patch, Mock, DEFAULT
 
 from marionette.runtests import (
     MarionetteTestRunner,
     MarionetteHarness,
     cli
 )
+from marionette.runner import MarionetteTestResult
 
 # avoid importing MarionetteJSTestCase to prevent pytest from
 # collecting and running it as part of this test suite
 import marionette.marionette_test as marionette_test
 
+
+def _check_crash_counts(has_crashed, runner, mock_marionette):
+    if has_crashed:
+        assert mock_marionette.check_for_crash.call_count == 1
+        assert runner.crashed == 1
+    else:
+        assert runner.crashed == 0
+
+
+@pytest.fixture()
+def mock_marionette(request):
+    """ Mock marionette instance """
+    import marionette_driver
+    marionette = Mock(spec=marionette_driver.marionette.Marionette)
+    if 'has_crashed' in request.funcargnames:
+        marionette.check_for_crash.return_value = request.getfuncargvalue(
+            'has_crashed'
+        )
+    return marionette
+
+
+@pytest.fixture()
+def empty_marionette_testcase():
+    """ Testable MarionetteTestCase class """
+    class EmptyTestCase(marionette_test.MarionetteTestCase):
+        def test_nothing(self):
+            pass
+
+    return EmptyTestCase
+
+
+@pytest.fixture()
+def empty_marionette_test(mock_marionette, empty_marionette_testcase):
+    return empty_marionette_testcase(lambda: mock_marionette, 'test_nothing')
+
+
 @pytest.fixture(scope='module')
 def logger():
     """
     Fake logger to help with mocking out other runner-related classes.
     """
     import mozlog
     return Mock(spec=mozlog.structuredlog.StructuredLogger)
 
@@ -86,78 +123,92 @@ def mach_parsed_kwargs(logger):
          'tree': 'b2g',
          'type': None,
          'verbose': None,
          'workspace': None,
          'logger': logger,
     }
 
 
+@pytest.fixture()
+def runner(mach_parsed_kwargs):
+    """
+    MarionetteTestRunner instance initialized with default options.
+    """
+    return MarionetteTestRunner(**mach_parsed_kwargs)
+
 
 @pytest.fixture
 def harness_class(request):
     """
     Mock based on MarionetteHarness whose run method just returns a number of
     failures according to the supplied test parameter
     """
-    if 'num_failures' in request.funcargnames:
-        failures = request.getfuncargvalue('num_failures')
+    if 'num_fails_crashed' in request.funcargnames:
+        num_fails_crashed = request.getfuncargvalue('num_fails_crashed')
     else:
-        failures = 0
+        num_fails_crashed = (0, 0)
     harness_cls = Mock(spec=MarionetteHarness)
     harness = harness_cls.return_value
-    if failures is None:
+    if num_fails_crashed is None:
         harness.run.side_effect = Exception
     else:
-        harness.run.return_value = failures
+        harness.run.return_value = sum(num_fails_crashed)
     return harness_cls
 
 
 @pytest.fixture
 def runner_class(request):
     """
-    Mock based on MarionetteTestRunner, wherein the runner.failed
-    attribute is provided by a test parameter
+    Mock based on MarionetteTestRunner, wherein the runner.failed,
+    runner.crashed attributes are provided by a test parameter
     """
-    if 'num_failures' in request.funcargnames:
-        failures = request.getfuncargvalue('num_failures')
+    if 'num_fails_crashed' in request.funcargnames:
+        failures, crashed = request.getfuncargvalue('num_fails_crashed')
     else:
         failures = 0
+        crashed = 0
     mock_runner_class = Mock(spec=MarionetteTestRunner)
     runner = mock_runner_class.return_value
     runner.failed = failures
+    runner.crashed = crashed
     return mock_runner_class
 
 
 @pytest.mark.parametrize(
-    "num_failures,exit_code",
-    [(0, 0), (1, 10), (None, 1)],
+    "num_fails_crashed,exit_code",
+    [((0, 0), 0), ((1, 0), 10), ((0, 1), 10), (None, 1)],
 )
-def test_cli_exit_code(num_failures, exit_code, harness_class):
+def test_cli_exit_code(num_fails_crashed, exit_code, harness_class):
     with pytest.raises(SystemExit) as err:
         cli(harness_class=harness_class)
     assert err.value.code == exit_code
 
 
-@pytest.mark.parametrize("num_failures", [0, 1])
+@pytest.mark.parametrize("num_fails_crashed", [(0, 0), (1, 0), (1, 1)])
 def test_call_harness_with_parsed_args_yields_num_failures(mach_parsed_kwargs,
                                                            runner_class,
-                                                           num_failures):
-    with patch('marionette.runtests.MarionetteHarness.parse_args') as parse_args:
-        failed = MarionetteHarness(runner_class, args=mach_parsed_kwargs).run()
+                                                           num_fails_crashed):
+    with patch(
+        'marionette.runtests.MarionetteHarness.parse_args'
+    ) as parse_args:
+        failed_or_crashed = MarionetteHarness(runner_class,
+                                              args=mach_parsed_kwargs).run()
         parse_args.assert_not_called()
-    assert failed == num_failures
+    assert failed_or_crashed == sum(num_fails_crashed)
 
 
 def test_call_harness_with_no_args_yields_num_failures(runner_class):
-    with patch('marionette.runtests.MarionetteHarness.parse_args') as parse_args:
-        parse_args.return_value = {'tests':[]}
-        failed = MarionetteHarness(runner_class).run()
+    with patch(
+        'marionette.runtests.MarionetteHarness.parse_args'
+    ) as parse_args:
+        parse_args.return_value = {'tests': []}
+        failed_or_crashed = MarionetteHarness(runner_class).run()
         assert parse_args.call_count == 1
-    assert failed == 0
+    assert failed_or_crashed == 0
 
 
 def test_harness_sets_up_default_test_handlers(mach_parsed_kwargs):
     """
     If the necessary TestCase is not in test_handlers,
     tests are omitted silently
     """
     harness = MarionetteHarness(args=mach_parsed_kwargs)
@@ -165,29 +216,77 @@ def test_harness_sets_up_default_test_ha
     runner = harness._runner_class(**mach_parsed_kwargs)
     assert marionette_test.MarionetteTestCase in runner.test_handlers
     assert marionette_test.MarionetteJSTestCase in runner.test_handlers
 
 
 def test_parsing_testvars(mach_parsed_kwargs):
     mach_parsed_kwargs.pop('tests')
     testvars_json_loads = [
-        {"wifi":{"ssid": "blah", "keyManagement": "WPA-PSK", "psk": "foo"}},
-        {"wifi":{"PEAP": "bar"}, "device": {"stuff": "buzz"}}
+        {"wifi": {"ssid": "blah", "keyManagement": "WPA-PSK", "psk": "foo"}},
+        {"wifi": {"PEAP": "bar"}, "device": {"stuff": "buzz"}}
     ]
     expected_dict = {
          "wifi": {
              "ssid": "blah",
              "keyManagement": "WPA-PSK",
              "psk": "foo",
-             "PEAP":"bar"
+             "PEAP": "bar"
          },
-         "device": {"stuff":"buzz"}
+         "device": {"stuff": "buzz"}
     }
-    with patch('marionette.runtests.MarionetteTestRunner._load_testvars') as load:
+    with patch(
+        'marionette.runtests.MarionetteTestRunner._load_testvars'
+    ) as load:
         load.return_value = testvars_json_loads
         runner = MarionetteTestRunner(**mach_parsed_kwargs)
         assert runner.testvars == expected_dict
         assert load.call_count == 1
 
+
+@pytest.mark.parametrize("has_crashed", [True, False])
+def test_crash_is_recorded_as_error(empty_marionette_test,
+                                    logger,
+                                    has_crashed):
+    """ Number of errors is incremented by stopTest iff has_crashed is true """
+    # collect results from the empty test
+    result = MarionetteTestResult(
+        marionette=empty_marionette_test._marionette_weakref(),
+        b2g_pid=0, logcat_stdout=False, logger=logger, verbosity=None,
+        stream=None, descriptions=None,
+    )
+    result.startTest(empty_marionette_test)
+    assert len(result.errors) == 0
+    assert len(result.failures) == 0
+    assert result.testsRun == 1
+    assert result.shouldStop == False
+    result.stopTest(empty_marionette_test)
+    assert result.shouldStop == has_crashed
+    if has_crashed:
+        assert len(result.errors) == 1
+    else:
+        assert len(result.errors) == 0
+
+
+@pytest.mark.parametrize("has_crashed", [True, False])
+def test_increment_crash_count_in_run_test_set(runner, has_crashed,
+                                               mock_marionette):
+    fake_tests = [{'filepath': i,
+                   'expected': 'pass',
+                   'test_container': False} for i in 'abc']
+
+    with patch.multiple(runner, run_test=DEFAULT, marionette=mock_marionette):
+        runner.run_test_set(fake_tests)
+        if not has_crashed:
+            assert runner.marionette.check_for_crash.call_count == len(fake_tests)
+        _check_crash_counts(has_crashed, runner, runner.marionette)
+
+
+@pytest.mark.parametrize("has_crashed", [True, False])
+def test_record_crash(runner, has_crashed, mock_marionette):
+    with patch.object(runner, 'marionette', mock_marionette):
+        assert runner.record_crash() == has_crashed
+        _check_crash_counts(has_crashed, runner, runner.marionette)
+
+
 if __name__ == '__main__':
     import sys
     sys.exit(pytest.main(['--verbose', __file__]))
--- a/testing/mozharness/mozharness/mozilla/building/buildbase.py
+++ b/testing/mozharness/mozharness/mozilla/building/buildbase.py
@@ -1824,16 +1824,18 @@ or run without that action (ie: --no-{ac
 
     def generate_build_stats(self):
         """grab build stats following a compile.
 
         This action handles all statistics from a build: 'count_ctors'
         and then posts to graph server the results.
         We only post to graph server for non nightly build
         """
+        import tarfile
+        import zipfile
         c = self.config
 
         if c.get('enable_count_ctors'):
             self.info("counting ctors...")
             self._count_ctors()
         else:
             self.info("ctors counts are disabled for this build.")
 
@@ -1850,59 +1852,59 @@ or run without that action (ie: --no-{ac
             for ext in ['apk', 'dmg', 'tar.bz2', 'zip']:
                 name = 'target.' + ext
                 if os.path.exists(os.path.join(dist_dir, name)):
                     packageName = name
                     break
             else:
                 self.fatal("could not determine packageName")
 
-        paths = [
-            (packageName, os.path.join(dirs['abs_obj_dir'], 'dist', packageName)),
-            ('omni.ja', os.path.join(dirs['abs_obj_dir'], 'dist', 'fennec', 'omni.ja')),
-            ('classes.dex', os.path.join(dirs['abs_obj_dir'], 'dist', 'fennec', 'classes.dex'))
-        ]
-
-        # Find a stripped version of libxul if possible
-        def find_file(rootPath, fileName):
-            for root, dirs, files in os.walk(rootPath):
-                for file in files:
-                    if file == fileName:
-                        return (fileName, os.path.join(root, file))
-            return None
-
-        # Check in the firefox and fennec dist dirs
-        libxul = None
-        dist_root = os.path.join(dirs['abs_obj_dir'], 'dist')
-        for dist in ('firefox', 'fennec', 'b2g'):
-            libxul = find_file(os.path.join(dist_root, dist), 'libxul.so')
-            if libxul:
-                break
+        interests = ['libxul.so', 'classes.dex', 'omni.ja']
+        installer = os.path.join(dirs['abs_obj_dir'], 'dist', packageName)
+        installer_size = 0
+        size_measurements = []
 
-        if libxul:
-            paths.append(libxul)
-        else:
-            paths.append( ('libxul.so', os.path.join(dirs['abs_obj_dir'], 'dist', 'bin', 'libxul.so')) )
-
-        size_measurements = []
-        installer_size = 0
-        for (name, path) in paths:
-            # FIXME: Remove the tinderboxprints when bug 1161249 is fixed and
-            # we're displaying perfherder data for each job automatically
-            if os.path.exists(path):
-                filesize = self.query_filesize(path)
-                self.info('TinderboxPrint: Size of %s<br/>%s bytes\n' % (
-                    name, filesize))
-                if any(name.endswith(extension) for extension in ['apk',
-                                                                  'dmg',
-                                                                  'bz2',
-                                                                  'zip']):
-                    installer_size = filesize
-                else:
-                    size_measurements.append({'name': name, 'value': filesize})
+        if os.path.exists(installer):
+            installer_size = self.query_filesize(installer)
+            self.info('TinderboxPrint: Size of %s<br/>%s bytes\n' % (
+                packageName, installer_size))
+            try:
+                subtests = {}
+                if zipfile.is_zipfile(installer):
+                    with zipfile.ZipFile(installer, 'r') as zf:
+                        for zi in zf.infolist():
+                            name = os.path.basename(zi.filename)
+                            size = zi.file_size
+                            if name in interests:
+                                if name in subtests:
+                                    # File seen twice in same archive;
+                                    # ignore to avoid confusion.
+                                    subtests[name] = None
+                                else:
+                                    subtests[name] = size
+                elif tarfile.is_tarfile(installer):
+                    with tarfile.open(installer, 'r:*') as tf:
+                        for ti in tf:
+                            name = os.path.basename(ti.name)
+                            size = ti.size
+                            if name in interests:
+                                if name in subtests:
+                                    # File seen twice in same archive;
+                                    # ignore to avoid confusion.
+                                    subtests[name] = None
+                                else:
+                                    subtests[name] = size
+                for name in subtests:
+                    if subtests[name] is not None:
+                        self.info('TinderboxPrint: Size of %s<br/>%s bytes\n' % (
+                            name, subtests[name]))
+                        size_measurements.append({'name': name, 'value': subtests[name]})
+            except:
+                self.info('Unable to search %s for component sizes.' % installer)
+                size_measurements = []
 
         perfherder_data = {
             "framework": {
                 "name": "build_metrics"
             },
             "suites": [],
         }
         if installer_size or size_measurements:
--- a/toolkit/components/passwordmgr/LoginHelper.jsm
+++ b/toolkit/components/passwordmgr/LoginHelper.jsm
@@ -396,10 +396,59 @@ this.LoginHelper = {
         }
       }
     }
     // if the new login is an update or is older than an exiting login, don't add it.
     if (foundMatchingLogin) {
       return;
     }
     Services.logins.addLogin(login);
+  },
+
+  /**
+   * Convert an array of nsILoginInfo to vanilla JS objects suitable for
+   * sending over IPC.
+   *
+   * NB: All members of nsILoginInfo and nsILoginMetaInfo are strings.
+   */
+  loginsToVanillaObjects(logins) {
+    return logins.map(this.loginToVanillaObject);
+  },
+
+  /**
+   * Same as above, but for a single login.
+   */
+  loginToVanillaObject(login) {
+    let obj = {};
+    for (let i in login) {
+      if (typeof login[i] !== 'function') {
+        obj[i] = login[i];
+      }
+    }
+
+    login.QueryInterface(Ci.nsILoginMetaInfo);
+    obj.guid = login.guid;
+    return obj;
+  },
+
+  /**
+   * Convert an object received from IPC into an nsILoginInfo (with guid).
+   */
+  vanillaObjectToLogin(login) {
+    var formLogin = Cc["@mozilla.org/login-manager/loginInfo;1"].
+                  createInstance(Ci.nsILoginInfo);
+    formLogin.init(login.hostname, login.formSubmitURL,
+                   login.httpRealm, login.username,
+                   login.password, login.usernameField,
+                   login.passwordField);
+
+    formLogin.QueryInterface(Ci.nsILoginMetaInfo);
+    formLogin.guid = login.guid;
+    return formLogin;
+  },
+
+  /**
+   * As above, but for an array of objects.
+   */
+  vanillaObjectsToLogins(logins) {
+    return logins.map(this.vanillaObjectToLogin);
   }
 };
--- a/toolkit/components/passwordmgr/LoginManagerContent.jsm
+++ b/toolkit/components/passwordmgr/LoginManagerContent.jsm
@@ -171,56 +171,49 @@ var LoginManagerContent = {
 
     let deferred = Promise.defer();
     requestData.promise = deferred;
     this._requests.set(requestId, requestData);
     return deferred.promise;
   },
 
   receiveMessage: function (msg, window) {
-    // Convert an array of logins in simple JS-object form to an array of
-    // nsILoginInfo objects.
-    function jsLoginsToXPCOM(logins) {
-      return logins.map(login => {
-        var formLogin = Cc["@mozilla.org/login-manager/loginInfo;1"].
-                      createInstance(Ci.nsILoginInfo);
-        formLogin.init(login.hostname, login.formSubmitURL,
-                       login.httpRealm, login.username,
-                       login.password, login.usernameField,
-                       login.passwordField);
-        return formLogin;
-      });
-    }
-
     if (msg.name == "RemoteLogins:fillForm") {
       this.fillForm({
         topDocument: window.document,
         loginFormOrigin: msg.data.loginFormOrigin,
-        loginsFound: jsLoginsToXPCOM(msg.data.logins),
+        loginsFound: LoginHelper.vanillaObjectsToLogins(msg.data.logins),
         recipes: msg.data.recipes,
         inputElement: msg.objects.inputElement,
       });
       return;
     }
 
     let request = this._takeRequest(msg);
     switch (msg.name) {
       case "RemoteLogins:loginsFound": {
-        let loginsFound = jsLoginsToXPCOM(msg.data.logins);
+        let loginsFound = LoginHelper.vanillaObjectsToLogins(msg.data.logins);
         request.promise.resolve({
           form: request.form,
           loginsFound: loginsFound,
           recipes: msg.data.recipes,
         });
         break;
       }
 
       case "RemoteLogins:loginsAutoCompleted": {
-        let loginsFound = jsLoginsToXPCOM(msg.data.logins);
-        request.promise.resolve(loginsFound);
+        let loginsFound =
+          LoginHelper.vanillaObjectsToLogins(msg.data.logins);
+        // If we're in the parent process, don't pass a message manager so our
+        // autocomplete result objects know they can remove the login from the
+        // login manager directly.
+        let messageManager =
+          (Services.appinfo.processType === Services.appinfo.PROCESS_TYPE_CONTENT) ?
+            msg.target : undefined;
+        request.promise.resolve({ logins: loginsFound, messageManager });
         break;
       }
     }
   },
 
   /**
    * Get relevant logins and recipes from the parent
    *
@@ -257,21 +250,26 @@ var LoginManagerContent = {
     let formOrigin = LoginUtils._getPasswordOrigin(doc.documentURI);
     let actionOrigin = LoginUtils._getActionOrigin(form);
 
     let messageManager = messageManagerFromWindow(win);
 
     let remote = (Services.appinfo.processType ===
                   Services.appinfo.PROCESS_TYPE_CONTENT);
 
+    let previousResult = aPreviousResult ?
+                           { searchString: aPreviousResult.searchString,
+                             logins: LoginHelper.loginsToVanillaObjects(aPreviousResult.logins) } :
+                           null;
+
     let requestData = {};
     let messageData = { formOrigin: formOrigin,
                         actionOrigin: actionOrigin,
                         searchString: aSearchString,
-                        previousResult: aPreviousResult,
+                        previousResult: previousResult,
                         rect: aRect,
                         remote: remote };
 
     return this._sendRequest(messageManager, requestData,
                              "RemoteLogins:autoCompleteLogins",
                              messageData);
   },
 
@@ -1175,33 +1173,34 @@ var LoginUtils = {
     if (uriString == "")
       uriString = form.baseURI; // ala bug 297761
 
     return this._getPasswordOrigin(uriString, true);
   },
 };
 
 // nsIAutoComplet