Merge m-c to autoland, a=merge
authorWes Kocher <wkocher@mozilla.com>
Wed, 29 Mar 2017 15:48:28 -0700
changeset 350510 a11e870ae60359e13822885930e06968484dc449
parent 350509 891b2a73a6fc578b3718b5f32b06c47553877637 (current diff)
parent 350446 60d7a0496a3673450ddbc37ec387525148c32604 (diff)
child 350511 68304e449ef741ca787517d042aa787c461612e8
push id31576
push userryanvm@gmail.com
push dateThu, 30 Mar 2017 19:18:48 +0000
treeherdermozilla-central@0156a91a9fba [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-c to autoland, a=merge
dom/base/nsFrameMessageManager.cpp
security/sandbox/chromium-shim/base/MissingBasicTypes.h
security/sandbox/chromium/base/bind_internal_win.h
security/sandbox/chromium/base/memory/scoped_ptr.h
security/sandbox/chromium/base/move.h
security/sandbox/chromium/base/threading/platform_thread_linux.cc
security/sandbox/chromium/base/threading/thread_local_posix.cc
security/sandbox/chromium/base/threading/thread_local_win.cc
security/sandbox/chromium/sandbox/win/src/Wow64.cc
security/sandbox/chromium/sandbox/win/src/Wow64.h
security/sandbox/chromium/sandbox/win/src/Wow64_64.cc
security/sandbox/chromium/sandbox/win/src/app_container.cc
security/sandbox/chromium/sandbox/win/src/app_container.h
security/sandbox/chromium/sandbox/win/src/app_container_unittest.cc
third_party/rust/cgl/.cargo-checksum.json
third_party/rust/cgl/.cargo-ok
third_party/rust/cgl/.gitignore
third_party/rust/cgl/.travis.yml
third_party/rust/cgl/COPYING
third_party/rust/cgl/Cargo.toml
third_party/rust/cgl/LICENSE-APACHE
third_party/rust/cgl/LICENSE-MIT
third_party/rust/cgl/README.md
third_party/rust/cgl/src/cgl.rs
third_party/rust/cgl/src/lib.rs
third_party/rust/error-chain/.cargo-checksum.json
third_party/rust/error-chain/.cargo-ok
third_party/rust/error-chain/.gitignore
third_party/rust/error-chain/.travis.yml
third_party/rust/error-chain/CHANGELOG.md
third_party/rust/error-chain/Cargo.toml
third_party/rust/error-chain/README.md
third_party/rust/error-chain/examples/all.rs
third_party/rust/error-chain/examples/doc.rs
third_party/rust/error-chain/examples/quickstart.rs
third_party/rust/error-chain/examples/size.rs
third_party/rust/error-chain/src/error_chain.rs
third_party/rust/error-chain/src/example_generated.rs
third_party/rust/error-chain/src/lib.rs
third_party/rust/error-chain/src/quick_error.rs
third_party/rust/error-chain/src/quick_main.rs
third_party/rust/error-chain/tests/quick_main.rs
third_party/rust/error-chain/tests/tests.rs
third_party/rust/metadeps/.cargo-checksum.json
third_party/rust/metadeps/.cargo-ok
third_party/rust/metadeps/.gitignore
third_party/rust/metadeps/Cargo.toml
third_party/rust/metadeps/README.md
third_party/rust/metadeps/src/lib.rs
third_party/rust/metadeps/tests/test.rs
third_party/rust/metadeps/tests/testdata.pc
third_party/rust/metadeps/tests/testlib.pc
third_party/rust/metadeps/tests/toml-missing-file/no-cargo-toml-here
third_party/rust/offscreen_gl_context/.cargo-checksum.json
third_party/rust/offscreen_gl_context/.cargo-ok
third_party/rust/offscreen_gl_context/.gitignore
third_party/rust/offscreen_gl_context/.travis.yml
third_party/rust/offscreen_gl_context/Cargo.toml
third_party/rust/offscreen_gl_context/Makefile
third_party/rust/offscreen_gl_context/README.md
third_party/rust/offscreen_gl_context/build.rs
third_party/rust/offscreen_gl_context/src/draw_buffer.rs
third_party/rust/offscreen_gl_context/src/gl_context.rs
third_party/rust/offscreen_gl_context/src/gl_context_attributes.rs
third_party/rust/offscreen_gl_context/src/gl_context_capabilities.rs
third_party/rust/offscreen_gl_context/src/gl_feature.rs
third_party/rust/offscreen_gl_context/src/gl_formats.rs
third_party/rust/offscreen_gl_context/src/gl_limits.rs
third_party/rust/offscreen_gl_context/src/lib.rs
third_party/rust/offscreen_gl_context/src/platform/mod.rs
third_party/rust/offscreen_gl_context/src/platform/not_implemented/mod.rs
third_party/rust/offscreen_gl_context/src/platform/not_implemented/native_gl_context.rs
third_party/rust/offscreen_gl_context/src/platform/with_cgl/mod.rs
third_party/rust/offscreen_gl_context/src/platform/with_cgl/native_gl_context.rs
third_party/rust/offscreen_gl_context/src/platform/with_egl/mod.rs
third_party/rust/offscreen_gl_context/src/platform/with_egl/native_gl_context.rs
third_party/rust/offscreen_gl_context/src/platform/with_egl/utils.rs
third_party/rust/offscreen_gl_context/src/platform/with_glx/mod.rs
third_party/rust/offscreen_gl_context/src/platform/with_glx/native_gl_context.rs
third_party/rust/offscreen_gl_context/src/platform/with_glx/utils.rs
third_party/rust/offscreen_gl_context/src/platform/with_osmesa/mod.rs
third_party/rust/offscreen_gl_context/src/platform/with_wgl/mod.rs
third_party/rust/offscreen_gl_context/src/platform/with_wgl/native_gl_context.rs
third_party/rust/offscreen_gl_context/src/platform/with_wgl/utils.rs
third_party/rust/offscreen_gl_context/src/platform/with_wgl/wgl_attributes.rs
third_party/rust/offscreen_gl_context/src/tests.rs
third_party/rust/osmesa-sys/.cargo-checksum.json
third_party/rust/osmesa-sys/.cargo-ok
third_party/rust/osmesa-sys/.gitignore
third_party/rust/osmesa-sys/Cargo.toml
third_party/rust/osmesa-sys/README.txt
third_party/rust/osmesa-sys/lib.rs
third_party/rust/shared_library/.cargo-checksum.json
third_party/rust/shared_library/.cargo-ok
third_party/rust/shared_library/.gitignore
third_party/rust/shared_library/.travis.yml
third_party/rust/shared_library/Cargo.toml
third_party/rust/shared_library/src/dynamic_library.rs
third_party/rust/shared_library/src/lib.rs
third_party/rust/toml/.cargo-checksum.json
third_party/rust/toml/.cargo-ok
third_party/rust/toml/.gitignore
third_party/rust/toml/.travis.yml
third_party/rust/toml/Cargo.toml
third_party/rust/toml/LICENSE-APACHE
third_party/rust/toml/LICENSE-MIT
third_party/rust/toml/README.md
third_party/rust/toml/examples/toml2json.rs
third_party/rust/toml/src/decoder/mod.rs
third_party/rust/toml/src/decoder/rustc_serialize.rs
third_party/rust/toml/src/decoder/serde.rs
third_party/rust/toml/src/display.rs
third_party/rust/toml/src/encoder/mod.rs
third_party/rust/toml/src/encoder/rustc_serialize.rs
third_party/rust/toml/src/encoder/serde.rs
third_party/rust/toml/src/lib.rs
third_party/rust/toml/src/parser.rs
third_party/rust/toml/tests/README.md
third_party/rust/toml/tests/formatting.rs
third_party/rust/toml/tests/invalid-encoder/array-mixed-types-ints-and-floats.json
third_party/rust/toml/tests/invalid.rs
third_party/rust/toml/tests/invalid/array-mixed-types-arrays-and-ints.toml
third_party/rust/toml/tests/invalid/array-mixed-types-ints-and-floats.toml
third_party/rust/toml/tests/invalid/array-mixed-types-strings-and-ints.toml
third_party/rust/toml/tests/invalid/datetime-malformed-no-leads.toml
third_party/rust/toml/tests/invalid/datetime-malformed-no-secs.toml
third_party/rust/toml/tests/invalid/datetime-malformed-no-t.toml
third_party/rust/toml/tests/invalid/datetime-malformed-no-z.toml
third_party/rust/toml/tests/invalid/datetime-malformed-with-milli.toml
third_party/rust/toml/tests/invalid/duplicate-key-table.toml
third_party/rust/toml/tests/invalid/duplicate-keys.toml
third_party/rust/toml/tests/invalid/duplicate-tables.toml
third_party/rust/toml/tests/invalid/empty-implicit-table.toml
third_party/rust/toml/tests/invalid/empty-table.toml
third_party/rust/toml/tests/invalid/float-no-leading-zero.toml
third_party/rust/toml/tests/invalid/float-no-trailing-digits.toml
third_party/rust/toml/tests/invalid/key-after-array.toml
third_party/rust/toml/tests/invalid/key-after-table.toml
third_party/rust/toml/tests/invalid/key-empty.toml
third_party/rust/toml/tests/invalid/key-hash.toml
third_party/rust/toml/tests/invalid/key-newline.toml
third_party/rust/toml/tests/invalid/key-open-bracket.toml
third_party/rust/toml/tests/invalid/key-single-open-bracket.toml
third_party/rust/toml/tests/invalid/key-space.toml
third_party/rust/toml/tests/invalid/key-start-bracket.toml
third_party/rust/toml/tests/invalid/key-two-equals.toml
third_party/rust/toml/tests/invalid/string-bad-byte-escape.toml
third_party/rust/toml/tests/invalid/string-bad-escape.toml
third_party/rust/toml/tests/invalid/string-byte-escapes.toml
third_party/rust/toml/tests/invalid/string-no-close.toml
third_party/rust/toml/tests/invalid/table-array-implicit.toml
third_party/rust/toml/tests/invalid/table-array-malformed-bracket.toml
third_party/rust/toml/tests/invalid/table-array-malformed-empty.toml
third_party/rust/toml/tests/invalid/table-empty.toml
third_party/rust/toml/tests/invalid/table-nested-brackets-close.toml
third_party/rust/toml/tests/invalid/table-nested-brackets-open.toml
third_party/rust/toml/tests/invalid/table-whitespace.toml
third_party/rust/toml/tests/invalid/table-with-pound.toml
third_party/rust/toml/tests/invalid/text-after-array-entries.toml
third_party/rust/toml/tests/invalid/text-after-integer.toml
third_party/rust/toml/tests/invalid/text-after-string.toml
third_party/rust/toml/tests/invalid/text-after-table.toml
third_party/rust/toml/tests/invalid/text-before-array-separator.toml
third_party/rust/toml/tests/invalid/text-in-array.toml
third_party/rust/toml/tests/valid.rs
third_party/rust/toml/tests/valid/array-empty.json
third_party/rust/toml/tests/valid/array-empty.toml
third_party/rust/toml/tests/valid/array-nospaces.json
third_party/rust/toml/tests/valid/array-nospaces.toml
third_party/rust/toml/tests/valid/arrays-hetergeneous.json
third_party/rust/toml/tests/valid/arrays-hetergeneous.toml
third_party/rust/toml/tests/valid/arrays-nested.json
third_party/rust/toml/tests/valid/arrays-nested.toml
third_party/rust/toml/tests/valid/arrays.json
third_party/rust/toml/tests/valid/arrays.toml
third_party/rust/toml/tests/valid/bool.json
third_party/rust/toml/tests/valid/bool.toml
third_party/rust/toml/tests/valid/comments-everywhere.json
third_party/rust/toml/tests/valid/comments-everywhere.toml
third_party/rust/toml/tests/valid/datetime.json
third_party/rust/toml/tests/valid/datetime.toml
third_party/rust/toml/tests/valid/empty.json
third_party/rust/toml/tests/valid/empty.toml
third_party/rust/toml/tests/valid/example-bom.toml
third_party/rust/toml/tests/valid/example-v0.3.0.json
third_party/rust/toml/tests/valid/example-v0.3.0.toml
third_party/rust/toml/tests/valid/example-v0.4.0.json
third_party/rust/toml/tests/valid/example-v0.4.0.toml
third_party/rust/toml/tests/valid/example.json
third_party/rust/toml/tests/valid/example.toml
third_party/rust/toml/tests/valid/example2.json
third_party/rust/toml/tests/valid/example2.toml
third_party/rust/toml/tests/valid/float.json
third_party/rust/toml/tests/valid/float.toml
third_party/rust/toml/tests/valid/hard_example.json
third_party/rust/toml/tests/valid/hard_example.toml
third_party/rust/toml/tests/valid/implicit-and-explicit-after.json
third_party/rust/toml/tests/valid/implicit-and-explicit-after.toml
third_party/rust/toml/tests/valid/implicit-and-explicit-before.json
third_party/rust/toml/tests/valid/implicit-and-explicit-before.toml
third_party/rust/toml/tests/valid/implicit-groups.json
third_party/rust/toml/tests/valid/implicit-groups.toml
third_party/rust/toml/tests/valid/integer.json
third_party/rust/toml/tests/valid/integer.toml
third_party/rust/toml/tests/valid/key-equals-nospace.json
third_party/rust/toml/tests/valid/key-equals-nospace.toml
third_party/rust/toml/tests/valid/key-space.json
third_party/rust/toml/tests/valid/key-space.toml
third_party/rust/toml/tests/valid/key-special-chars.json
third_party/rust/toml/tests/valid/key-special-chars.toml
third_party/rust/toml/tests/valid/key-with-pound.json
third_party/rust/toml/tests/valid/key-with-pound.toml
third_party/rust/toml/tests/valid/long-float.json
third_party/rust/toml/tests/valid/long-float.toml
third_party/rust/toml/tests/valid/long-integer.json
third_party/rust/toml/tests/valid/long-integer.toml
third_party/rust/toml/tests/valid/multiline-string.json
third_party/rust/toml/tests/valid/multiline-string.toml
third_party/rust/toml/tests/valid/raw-multiline-string.json
third_party/rust/toml/tests/valid/raw-multiline-string.toml
third_party/rust/toml/tests/valid/raw-string.json
third_party/rust/toml/tests/valid/raw-string.toml
third_party/rust/toml/tests/valid/string-empty.json
third_party/rust/toml/tests/valid/string-empty.toml
third_party/rust/toml/tests/valid/string-escapes.json
third_party/rust/toml/tests/valid/string-escapes.toml
third_party/rust/toml/tests/valid/string-simple.json
third_party/rust/toml/tests/valid/string-simple.toml
third_party/rust/toml/tests/valid/string-with-pound.json
third_party/rust/toml/tests/valid/string-with-pound.toml
third_party/rust/toml/tests/valid/table-array-implicit.json
third_party/rust/toml/tests/valid/table-array-implicit.toml
third_party/rust/toml/tests/valid/table-array-many.json
third_party/rust/toml/tests/valid/table-array-many.toml
third_party/rust/toml/tests/valid/table-array-nest.json
third_party/rust/toml/tests/valid/table-array-nest.toml
third_party/rust/toml/tests/valid/table-array-one.json
third_party/rust/toml/tests/valid/table-array-one.toml
third_party/rust/toml/tests/valid/table-empty.json
third_party/rust/toml/tests/valid/table-empty.toml
third_party/rust/toml/tests/valid/table-sub-empty.json
third_party/rust/toml/tests/valid/table-sub-empty.toml
third_party/rust/toml/tests/valid/table-whitespace.json
third_party/rust/toml/tests/valid/table-whitespace.toml
third_party/rust/toml/tests/valid/table-with-pound.json
third_party/rust/toml/tests/valid/table-with-pound.toml
third_party/rust/toml/tests/valid/unicode-escape.json
third_party/rust/toml/tests/valid/unicode-escape.toml
third_party/rust/toml/tests/valid/unicode-literal.json
third_party/rust/toml/tests/valid/unicode-literal.toml
third_party/rust/user32-sys/.cargo-checksum.json
third_party/rust/user32-sys/.cargo-ok
third_party/rust/user32-sys/Cargo.toml
third_party/rust/user32-sys/README.md
third_party/rust/user32-sys/build.rs
third_party/rust/user32-sys/src/lib.rs
third_party/rust/x11/.cargo-checksum.json
third_party/rust/x11/.cargo-ok
third_party/rust/x11/Cargo.toml
third_party/rust/x11/build.rs
third_party/rust/x11/examples/hello-world.rs
third_party/rust/x11/examples/input.rs
third_party/rust/x11/examples/xrecord.rs
third_party/rust/x11/src/dpms.rs
third_party/rust/x11/src/glx.rs
third_party/rust/x11/src/internal.rs
third_party/rust/x11/src/keysym.rs
third_party/rust/x11/src/lib.rs
third_party/rust/x11/src/link.rs
third_party/rust/x11/src/xcursor.rs
third_party/rust/x11/src/xf86vmode.rs
third_party/rust/x11/src/xfixes.rs
third_party/rust/x11/src/xft.rs
third_party/rust/x11/src/xinerama.rs
third_party/rust/x11/src/xinput.rs
third_party/rust/x11/src/xinput2.rs
third_party/rust/x11/src/xlib.rs
third_party/rust/x11/src/xlib_xcb.rs
third_party/rust/x11/src/xmd.rs
third_party/rust/x11/src/xmu.rs
third_party/rust/x11/src/xrandr.rs
third_party/rust/x11/src/xrecord.rs
third_party/rust/x11/src/xrender.rs
third_party/rust/x11/src/xss.rs
third_party/rust/x11/src/xt.rs
third_party/rust/x11/src/xtest.rs
toolkit/components/telemetry/Histograms.json
--- a/CLOBBER
+++ b/CLOBBER
@@ -17,9 +17,9 @@
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
 # Are you updating CLOBBER because you think it's needed for your WebIDL
 # changes to stick? As of bug 928195, this shouldn't be necessary! Please
 # don't change CLOBBER for WebIDL changes any more.
 
-Bug 1265818 - deleted an exported header and added a new .idl to regenerate that same header; and this unfortunately produces an untracked generated header in your source dir whenever you build (probably due to a dangling symlink), unless you clobber
+Bug 1337331 - Required because of removed cc files like security/sandbox/chromium/base/threading/platform_thread_linux.cc
--- a/accessible/generic/DocAccessible.cpp
+++ b/accessible/generic/DocAccessible.cpp
@@ -2183,17 +2183,24 @@ DocAccessible::PutChildrenBack(nsTArray<
     child->SetRelocated(false);
 
     int32_t idxInParent = -1;
     Accessible* origContainer = GetContainerAccessible(child->GetContent());
     if (origContainer) {
       TreeWalker walker(origContainer);
       if (walker.Seek(child->GetContent())) {
         Accessible* prevChild = walker.Prev();
-        idxInParent = prevChild ? prevChild->IndexInParent() + 1 : 0;
+        if (prevChild) {
+          idxInParent = prevChild->IndexInParent() + 1;
+          MOZ_ASSERT(origContainer == prevChild->Parent(), "Broken tree");
+          origContainer = prevChild->Parent();
+        }
+        else {
+          idxInParent = 0;
+        }
       }
     }
     MoveChild(child, origContainer, idxInParent);
   }
 
   aChildren->RemoveElementsAt(aStartIdx, aChildren->Length() - aStartIdx);
 }
 
@@ -2240,16 +2247,21 @@ DocAccessible::MoveChild(Accessible* aCh
   curParent->RemoveChild(aChild);
   rmut.Done();
 
   // No insertion point for the child.
   if (aIdxInParent == -1) {
     return true;
   }
 
+  if (aIdxInParent > static_cast<int32_t>(aNewParent->ChildCount())) {
+    MOZ_ASSERT_UNREACHABLE("Wrong insertion point for a moving child");
+    return true;
+  }
+
   TreeMutation imut(aNewParent);
   aNewParent->InsertChildAt(aIdxInParent, aChild);
   imut.AfterInsertion(aChild);
   imut.Done();
 
 #ifdef A11Y_LOG
   logging::TreeInfo("move child: old parent tree after",
                     logging::eVerbose, curParent);
--- a/accessible/windows/msaa/Platform.cpp
+++ b/accessible/windows/msaa/Platform.cpp
@@ -81,17 +81,20 @@ a11y::ProxyCreated(ProxyAccessible* aPro
   aProxy->SetWrapper(reinterpret_cast<uintptr_t>(wrapper));
 }
 
 void
 a11y::ProxyDestroyed(ProxyAccessible* aProxy)
 {
   AccessibleWrap* wrapper =
     reinterpret_cast<AccessibleWrap*>(aProxy->GetWrapper());
-  MOZ_ASSERT(wrapper);
+
+  // If aProxy is a document that was created, but
+  // RecvPDocAccessibleConstructor failed then aProxy->GetWrapper() will be
+  // null.
   if (!wrapper)
     return;
 
   if (aProxy->IsDoc() && nsWinUtils::IsWindowEmulationStarted()) {
     aProxy->AsDoc()->SetEmulatedWindowHandle(nullptr);
   }
 
   wrapper->Shutdown();
--- a/browser/base/content/tab-content.js
+++ b/browser/base/content/tab-content.js
@@ -706,18 +706,18 @@ if (Services.appinfo.processType == Serv
 }
 
 var WebBrowserChrome = {
   onBeforeLinkTraversal(originalTarget, linkURI, linkNode, isAppTab) {
     return BrowserUtils.onBeforeLinkTraversal(originalTarget, linkURI, linkNode, isAppTab);
   },
 
   // Check whether this URI should load in the current process
-  shouldLoadURI(aDocShell, aURI, aReferrer, aTriggeringPrincipal) {
-    if (!E10SUtils.shouldLoadURI(aDocShell, aURI, aReferrer)) {
+  shouldLoadURI(aDocShell, aURI, aReferrer, aHasPostData, aTriggeringPrincipal) {
+    if (!E10SUtils.shouldLoadURI(aDocShell, aURI, aReferrer, aHasPostData)) {
       E10SUtils.redirectLoad(aDocShell, aURI, aReferrer, aTriggeringPrincipal, false);
       return false;
     }
 
     return true;
   },
 
   shouldLoadURIInThisProcess(aURI) {
--- a/browser/components/originattributes/test/browser/browser_firstPartyIsolation_aboutPages.js
+++ b/browser/components/originattributes/test/browser/browser_firstPartyIsolation_aboutPages.js
@@ -28,28 +28,28 @@ add_task(function* test_remote_window_op
                  "remote about:blank should have firstPartyDomain set");
   });
 
   win.close();
 });
 
 /**
  * For loading the initial about:blank in non-e10s mode, it will be loaded with
- * codebase principal. So we test if it has correct firstPartyDomain set.
+ * a null principal. So we test if it has correct firstPartyDomain set.
  */
 add_task(function* test_nonremote_window_open_aboutBlank() {
   let win = yield BrowserTestUtils.openNewBrowserWindow({remote: false});
   let browser = win.gBrowser.selectedBrowser;
 
   Assert.ok(!browser.isRemoteBrowser, "shouldn't be a remote browser");
 
   let attrs = { firstPartyDomain: "about.ef2a7dd5-93bc-417f-a698-142c3116864f.mozilla" };
   yield ContentTask.spawn(browser, attrs, function* (expectAttrs) {
-    Assert.ok(content.document.nodePrincipal.isCodebasePrincipal,
-              "The principal of non-remote about:blank should be a codebase principal.");
+    Assert.ok(!content.document.nodePrincipal.isCodebasePrincipal,
+              "The principal of non-remote about:blank should not be a codebase principal.");
     Assert.equal(content.document.nodePrincipal.originAttributes.firstPartyDomain,
                  expectAttrs.firstPartyDomain,
                  "non-remote about:blank should have firstPartyDomain set");
   });
 
   win.close();
 });
 
--- a/browser/components/preferences/permissions.js
+++ b/browser/components/preferences/permissions.js
@@ -90,18 +90,19 @@ var gPermissionManager = {
       // `localhost:8080` as having the scheme `localhost`, rather than being
       // an invalid URI. A canonical origin representation is required by the
       // permission manager for storage, so this won't prevent any valid
       // permissions from being entered by the user.
       let uri;
       try {
         uri = Services.io.newURI(input_url);
         principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {});
-        // If we have ended up with an unknown scheme, the following will throw.
-        principal.origin;
+        if (principal.origin.startsWith("moz-nullprincipal:")) {
+          throw "Null principal";
+        }
       } catch (ex) {
         uri = Services.io.newURI("http://" + input_url);
         principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {});
         // If we have ended up with an unknown scheme, the following will throw.
         principal.origin;
       }
     } catch (ex) {
       var message = this._bundle.getString("invalidURI");
--- a/browser/locales/jar.mn
+++ b/browser/locales/jar.mn
@@ -106,16 +106,17 @@
 #else
     locale/browser/searchplugins/               (.deps/generated_@AB_CD@/*.xml)
     locale/browser/searchplugins/list.json      (.deps/generated_@AB_CD@/list.json)
 #endif
     locale/browser/searchplugins/images/amazon.ico     (searchplugins/images/amazon.ico)
     locale/browser/searchplugins/images/wikipedia.ico  (searchplugins/images/wikipedia.ico)
     locale/browser/searchplugins/images/yahoo.ico      (searchplugins/images/yahoo.ico)
     locale/browser/searchplugins/images/yandex-en.ico  (searchplugins/images/yandex-en.ico)
+    locale/browser/searchplugins/images/yandex-ru.ico  (searchplugins/images/yandex-ru.ico)
 % locale browser-region @AB_CD@ %locale/browser-region/
     locale/browser-region/region.properties        (%chrome/browser-region/region.properties)
 # the following files are browser-specific overrides
     locale/browser/netError.dtd                (%chrome/overrides/netError.dtd)
     locale/browser/appstrings.properties       (%chrome/overrides/appstrings.properties)
     locale/browser/downloads/settingsChange.dtd  (%chrome/overrides/settingsChange.dtd)
 % override chrome://global/locale/netError.dtd chrome://browser/locale/netError.dtd
 % override chrome://global/locale/appstrings.properties chrome://browser/locale/appstrings.properties
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..226fc0a0711cf5a048b631a3dfb292ec1c55027b
GIT binary patch
literal 2034
zc$@+92MzcD0096301yxW0096X08;`0044wc03aX$0096X0C@!f0C@rc0EtjeM-2)Z
z3IG5A4M|8uQUCw|5C8xG5C{eU001BJ|6u?C0vbs~K~y-6jgn7DR8bVhfA`G{TG_&J
z8pudpC}}}R2)U>rAquR85F<vbXi=M1;VwvMQ!S)HYB6F9$!%={`y-J>L7O02lwfF4
zqfG-5I{9YayI+gvo8IIizr$IabI<qPbI!d6=m5HbIyQ$HARkQ(7K_D_Hi1H+@C!H*
zB|AWUGTFEVMCkf5k1h_tkyhwU!yX4&pHxG`_OY?CL11T8<earu)>>K5Q@N0r-@jjW
zphuOruT&YoDRsu>xvqTI)$;Q43eX?zz(E2Di*RPAF(2RIUAcw!9l$iVfH7Djh{f2E
zN^Q$#vqQkHP#`7(1K`sKXzRcv(?MKztF8LhLx@Z!GXV7b6_5zrLQ@*Pe*?b~uo4L{
z1|X=hmQ<=~>*(m{8DMvf0DyY?FusqucL#%ka+zR6Fvei5k0dgg)2D!g@lc?O_Ab1u
zw~1f7gnjl9>gvJss$F0VlCTzlm;=PZC5AVtuOFqGp?xnpd^{l6)QG96$w$B&fMIv-
zw?Z$wYw~i}rLKhBrLU^Id@Oaw6|GrZTqpr&0XB|MTEX0(#2!5fjY-VUAJqkhn3%Zx
z1bDsi84Wlurg7%pV}~wai~(zdxz{b9Un-4^j64A5!wwAL3rLvU4g5pL@VdH#<yjF6
z4gtuG=bi$y(XV{@^WuVAT3ylqe12|j6*wOy$AOua*0uytPc6*)i2gtM=h5H~Zcl9I
zXNKMr00000NkvXXu0mjfiBL{Q4GJ0x0000DNk~Le0000W0000W2nGNE0CReJ^Z)<_
zKuJVFR9J<zmuqZPMHI(>Gk19xh|(^FT1<Q)2#Ep#BSeTqLPS)2P$8)V{Avt|35hgO
zY*Gxim7oY{tHxAQQHX+%76^$C5X7W>P=sL6lmhLp$fHo8?amxO%-!C*-MxjxdNwC_
zGmroO%$ak}%qX0U0VV^Z0FVBay+CVJrw5D%9s=?J-OuFsxF`A=FdrywXlQ7-cI}#x
zew2!eij6=i&cl(i6j;{P)n)sWTtp<1NL&Dx0gptHYhVDtfB`WDLQWMM{Qu)Oc(V)^
zO@(`h!(A#<O$zDi1Z#-L^GB{*x9$O;Aj%60SPo#V{UE1_BA}G}`^hHsTWg^Gtm`u%
zgNLF_H>A4Vm}AC`w-&S}nM}4978b4q62P~)JfM8d6l)!MDg`3QM;p-PFF^ZQWYie!
z%GZ(44j`ZILmn@62-?N4q*6Ub$K&x4RaI59fI^@s*BVy<E37q=p{Z`M-JN2)yTtx_
zNbLQiMaCmCvq<d0@7x%Z5^If^x7WD7@!GYe)yHaWZEg2?7Uc4P)81RJwA*^6;hWD<
z=M!K-o_i6d&V-b4Dxf<%Lt6$In}Ibt9v@y=SveaQ2SvRNP=JaEKjhLy_`L}fNMSKD
zYaZ5GtTBk^AtG2Z`K`5xNCr-6Y3Y+b*R<Ro$U(0ZaN!?R;tT-lrcp4q7==YC0n-iE
z_*s&U9fPu|%*;V3D9F#Nu6|>-9}C6V9uOCE8LB-u-6ycx!|E8KV+h*+D)3@~2L!~6
zAxdZAEnQmrgwHqihCBd*3>=6I&2ytWuc9tr2=XSaA|a<*mjQ|_tb&64Vb#^ubAYjF
zF9c~A5d`YyIBM)TXKk_-{yYxWPfsiUxWEACtmvAyq@-k_&p9K*146_v7DFaa0}EU_
zkJ_~@Xh+=ksNf6}ETV`)qhNG===$|lb8s1P>vcVVfSq50jJp#Q=r8Ngo7ckS%V1m@
zikM&rln!ltZoI`$mn`skr^kE`;F2bXSPMnP*q7Ggt$rS^w4*n^24C01J@+9)hM|u%
zIdBBD3SkL3i>&)-K*xd+5e8`G96NU*cEeV@s@3RYhtbW)q2+i8Q3WekVbW~e`udL>
zecpr7l`yR7V4FS%CQWfOhU8)AJ%e4o3Yj$B4OD(w^numZmb|)Z)yw;Fhf{Np2O_rs
zT(R*y)X~G}Jzu!ExczQY<y&CTVDvj4u_K3Yq0|QsP*+!%Ui|@po*0OnCj#1Y+uOJe
z+RuRnyPyOH4GDs+XM8kyBAL8WR#tWpXaoLA8_;(Qq|@xoNz~4I=a5@&!_HsaQ-akE
zTJT}*`@4L;{pq$K3nD$>)Z6hf`fMv`u#Y|q`EexW(l0zW3a7O#(eY||`7eZ4pElsS
zS)k7Ujo!80k&i6EJiN#coN(C<TbwPmwKcnau6^P5P#uUC)wmsf;;1uV?qkRu6Hp?E
z&JLekI4v!wIw~sGHsRg}8CUec15qJx=^|d^Hur)UJOVrKDL^5{1XV9%LN-QCP3<0^
z=ZD^X!8saXfp=gp-r=7>gPAfDJL5q>P@X$Ld(Tn|BxKa7(=8p9m6c7vX>vSJf;5Z}
zZ|l4MX%WLLT;dw7Md_F`0??tuNNbHT>EIMLZF+CF&+%g}d<Coq1|}1USMu_PWf$%U
z(OPE)pZF(Ws4g@&pX``0abgv43aHJA1GE6_{A$O~ot;;skFZ{9t-+d*T7#so^8PWs
zdCQhYpXd9ig(%$3WCj1v!xY@=Yoa<mpdC1gdzz2%+j?KR{)_Ga&P5sUFYJGWr;6fm
QN&o-=07*qoM6N<$g3@QE6951J
--- a/browser/locales/searchplugins/yandex-az.xml
+++ b/browser/locales/searchplugins/yandex-az.xml
@@ -1,17 +1,22 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
 <ShortName>Yandex</ShortName>
 <Description>İnternetdə axtarış üçün Yandexdən istifadə edin.</Description>
 <InputEncoding>UTF-8</InputEncoding>
-<Image width="16" height="16">data:image/x-icon;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAB50lEQVQ4T43SvWsacRgH8OcPCITSLRQ6BSRL1gxZTNZQsgYC3QKunVoMnTKFhBQSnDqIUa5gxNbBCgriC4pv50sJ1lIR5SROpRVbz+O4b5/flbvedekJH+557nvfH8chdbvdIFMYPAgBICdqt9uKpmnw8huNRuDnX8J5QKvVgmEYnqiqClmWwZ113kmger0OXdf/Wv6EIb0BTo+AgB94ceDKJ5MJuHPOMwlUqVSwWq1sevQaxqvn0O5l6HdvgaMdV75cLtFoNMC9Xd6JisWiedNiPNuB9l4yZ+1jEvBvuXJBURRwL8YzUT6fx2KxsGHrKdQPCXNW794Bvieu3CLegrsnlM1mMZ/PbfqeH6vToDkvb2+Bx49cuWU2m4G7bUqn0xiPx7ZpqYRf29v4cXyMxf4+tLU1V24ZDAbgbptSqRSGw6HL9OwM37n4bXPTvP6bC7lcDtw9oWQyiX6/b/vMH1XZ2MAoEMDXqytM+QBnLtRqNXAvxjNRPB5Hr9ez9Q8PMfD50OM/2P3FBb7wAc680+mIMri3yzuRJEloNpsmORTCJy7INzd/9stLc7dyIZPJgDvnPJNA0WgU1WrVkxJ/4FgsBu6s804CRSKRh0KhgHK5/F+JRAL8fJBnslA4HH7NHhg8CDnLwm8IYz560xw92AAAAABJRU5ErkJggg==</Image>
-<Url type="application/x-suggestions+json" method="GET" template="https://suggest.yandex.net/suggest-ff.cgi">
+<Image width="16" height="16">resource://search-plugins/images/yandex-ru.ico</Image>
+<Url type="application/x-suggestions+json" method="GET" template="https://suggest.yandex.ru/suggest-ff.cgi">
   <Param name="part" value="{searchTerms}"/>
 </Url>
 <Url type="text/html" method="GET" template="https://yandex.ru/yandsearch" resultdomain="yandex.ru">
-  <Param name="text" value="{searchTerms}"/>
+  <MozParam name="clid" condition="purpose" purpose="searchbar"   value="2186618"/>
+  <MozParam name="clid" condition="purpose" purpose="keyword"     value="2186621"/>
+  <MozParam name="clid" condition="purpose" purpose="contextmenu" value="2186623"/>
+  <MozParam name="clid" condition="purpose" purpose="homepage"    value="2186617"/>
+  <MozParam name="clid" condition="purpose" purpose="newtab"      value="2186620"/>
+  <Param    name="text" value="{searchTerms}"/>
 </Url>
 <SearchForm>https://www.yandex.ru/</SearchForm>
 </SearchPlugin>
--- a/browser/locales/searchplugins/yandex-by.xml
+++ b/browser/locales/searchplugins/yandex-by.xml
@@ -1,18 +1,18 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
 <ShortName>Яндекс</ShortName>
 <Description>Пошук з дапамогаю Яндекс</Description>
 <InputEncoding>UTF-8</InputEncoding>
-<Image width="16" height="16">data:image/x-icon;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAB50lEQVQ4T43SvWsacRgH8OcPCITSLRQ6BSRL1gxZTNZQsgYC3QKunVoMnTKFhBQSnDqIUa5gxNbBCgriC4pv50sJ1lIR5SROpRVbz+O4b5/flbvedekJH+557nvfH8chdbvdIFMYPAgBICdqt9uKpmnw8huNRuDnX8J5QKvVgmEYnqiqClmWwZ113kmger0OXdf/Wv6EIb0BTo+AgB94ceDKJ5MJuHPOMwlUqVSwWq1sevQaxqvn0O5l6HdvgaMdV75cLtFoNMC9Xd6JisWiedNiPNuB9l4yZ+1jEvBvuXJBURRwL8YzUT6fx2KxsGHrKdQPCXNW794Bvieu3CLegrsnlM1mMZ/PbfqeH6vToDkvb2+Bx49cuWU2m4G7bUqn0xiPx7ZpqYRf29v4cXyMxf4+tLU1V24ZDAbgbptSqRSGw6HL9OwM37n4bXPTvP6bC7lcDtw9oWQyiX6/b/vMH1XZ2MAoEMDXqytM+QBnLtRqNXAvxjNRPB5Hr9ez9Q8PMfD50OM/2P3FBb7wAc680+mIMri3yzuRJEloNpsmORTCJy7INzd/9stLc7dyIZPJgDvnPJNA0WgU1WrVkxJ/4FgsBu6s804CRSKRh0KhgHK5/F+JRAL8fJBnslA4HH7NHhg8CDnLwm8IYz560xw92AAAAABJRU5ErkJggg==</Image>
-<Url type="application/x-suggestions+json" method="GET" template="https://suggest.yandex.net/suggest-ff.cgi">
+<Image width="16" height="16">resource://search-plugins/images/yandex-ru.ico</Image>
+<Url type="application/x-suggestions+json" method="GET" template="https://suggest.yandex.by/suggest-ff.cgi">
   <Param name="part" value="{searchTerms}"/>
 </Url>
 <Url type="text/html" method="GET" template="https://yandex.by/yandsearch" resultdomain="yandex.by">
   <MozParam name="clid" condition="purpose" purpose="searchbar"   value="2186618"/>
   <MozParam name="clid" condition="purpose" purpose="keyword"     value="2186621"/>
   <MozParam name="clid" condition="purpose" purpose="contextmenu" value="2186623"/>
   <MozParam name="clid" condition="purpose" purpose="homepage"    value="2186617"/>
   <MozParam name="clid" condition="purpose" purpose="newtab"      value="2186620"/>
--- a/browser/locales/searchplugins/yandex-kk.xml
+++ b/browser/locales/searchplugins/yandex-kk.xml
@@ -1,18 +1,18 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
 <ShortName>Яндекс</ShortName>
 <Description>Воспользуйтесь Яндексом для поиска в Интернете.</Description>
 <InputEncoding>UTF-8</InputEncoding>
-<Image width="16" height="16">data:image/x-icon;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAB50lEQVQ4T43SvWsacRgH8OcPCITSLRQ6BSRL1gxZTNZQsgYC3QKunVoMnTKFhBQSnDqIUa5gxNbBCgriC4pv50sJ1lIR5SROpRVbz+O4b5/flbvedekJH+557nvfH8chdbvdIFMYPAgBICdqt9uKpmnw8huNRuDnX8J5QKvVgmEYnqiqClmWwZ113kmger0OXdf/Wv6EIb0BTo+AgB94ceDKJ5MJuHPOMwlUqVSwWq1sevQaxqvn0O5l6HdvgaMdV75cLtFoNMC9Xd6JisWiedNiPNuB9l4yZ+1jEvBvuXJBURRwL8YzUT6fx2KxsGHrKdQPCXNW794Bvieu3CLegrsnlM1mMZ/PbfqeH6vToDkvb2+Bx49cuWU2m4G7bUqn0xiPx7ZpqYRf29v4cXyMxf4+tLU1V24ZDAbgbptSqRSGw6HL9OwM37n4bXPTvP6bC7lcDtw9oWQyiX6/b/vMH1XZ2MAoEMDXqytM+QBnLtRqNXAvxjNRPB5Hr9ez9Q8PMfD50OM/2P3FBb7wAc680+mIMri3yzuRJEloNpsmORTCJy7INzd/9stLc7dyIZPJgDvnPJNA0WgU1WrVkxJ/4FgsBu6s804CRSKRh0KhgHK5/F+JRAL8fJBnslA4HH7NHhg8CDnLwm8IYz560xw92AAAAABJRU5ErkJggg==</Image>
-<Url type="application/x-suggestions+json" method="GET" template="https://suggest.yandex.net/suggest-ff.cgi">
+<Image width="16" height="16">resource://search-plugins/images/yandex-ru.ico</Image>
+<Url type="application/x-suggestions+json" method="GET" template="https://suggest.yandex.kz/suggest-ff.cgi">
   <Param name="part" value="{searchTerms}"/>
 </Url>
 <Url type="text/html" method="GET" template="https://yandex.kz/yandsearch" resultdomain="yandex.kz">
   <MozParam name="clid" condition="purpose" purpose="searchbar"   value="2186618"/>
   <MozParam name="clid" condition="purpose" purpose="keyword"     value="2186621"/>
   <MozParam name="clid" condition="purpose" purpose="contextmenu" value="2186623"/>
   <MozParam name="clid" condition="purpose" purpose="homepage"    value="2186617"/>
   <MozParam name="clid" condition="purpose" purpose="newtab"      value="2186620"/>
--- a/browser/locales/searchplugins/yandex-ru.xml
+++ b/browser/locales/searchplugins/yandex-ru.xml
@@ -1,18 +1,18 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
 <ShortName>Яндекс</ShortName>
 <Description>Воспользуйтесь Яндексом для поиска в Интернете.</Description>
 <InputEncoding>UTF-8</InputEncoding>
-<Image width="16" height="16">data:image/x-icon;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAB50lEQVQ4T43SvWsacRgH8OcPCITSLRQ6BSRL1gxZTNZQsgYC3QKunVoMnTKFhBQSnDqIUa5gxNbBCgriC4pv50sJ1lIR5SROpRVbz+O4b5/flbvedekJH+557nvfH8chdbvdIFMYPAgBICdqt9uKpmnw8huNRuDnX8J5QKvVgmEYnqiqClmWwZ113kmger0OXdf/Wv6EIb0BTo+AgB94ceDKJ5MJuHPOMwlUqVSwWq1sevQaxqvn0O5l6HdvgaMdV75cLtFoNMC9Xd6JisWiedNiPNuB9l4yZ+1jEvBvuXJBURRwL8YzUT6fx2KxsGHrKdQPCXNW794Bvieu3CLegrsnlM1mMZ/PbfqeH6vToDkvb2+Bx49cuWU2m4G7bUqn0xiPx7ZpqYRf29v4cXyMxf4+tLU1V24ZDAbgbptSqRSGw6HL9OwM37n4bXPTvP6bC7lcDtw9oWQyiX6/b/vMH1XZ2MAoEMDXqytM+QBnLtRqNXAvxjNRPB5Hr9ez9Q8PMfD50OM/2P3FBb7wAc680+mIMri3yzuRJEloNpsmORTCJy7INzd/9stLc7dyIZPJgDvnPJNA0WgU1WrVkxJ/4FgsBu6s804CRSKRh0KhgHK5/F+JRAL8fJBnslA4HH7NHhg8CDnLwm8IYz560xw92AAAAABJRU5ErkJggg==</Image>
-<Url type="application/x-suggestions+json" method="GET" template="https://suggest.yandex.net/suggest-ff.cgi">
+<Image width="16" height="16">resource://search-plugins/images/yandex-ru.ico</Image>
+<Url type="application/x-suggestions+json" method="GET" template="https://suggest.yandex.ru/suggest-ff.cgi">
   <Param name="part" value="{searchTerms}"/>
 </Url>
 <Url type="text/html" method="GET" template="https://yandex.ru/yandsearch" resultdomain="yandex.ru">
   <MozParam name="clid" condition="purpose" purpose="searchbar"   value="2186618"/>
   <MozParam name="clid" condition="purpose" purpose="keyword"     value="2186621"/>
   <MozParam name="clid" condition="purpose" purpose="contextmenu" value="2186623"/>
   <MozParam name="clid" condition="purpose" purpose="homepage"    value="2186617"/>
   <MozParam name="clid" condition="purpose" purpose="newtab"      value="2186620"/>
--- a/browser/locales/searchplugins/yandex-tr.xml
+++ b/browser/locales/searchplugins/yandex-tr.xml
@@ -1,22 +1,22 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
 <ShortName>Yandex</ShortName>
 <Description>Yandex Türkiye arama motoru</Description>
 <InputEncoding>UTF-8</InputEncoding>
-<Image width="16" height="16">data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAABILAAASCwAAAAAAAAAAAAAAAAAsAAAAUwAAAF8AAABfAAAAXwAAAF8AAABfAAAAXwAAAF8AAABfAAAAXwAAADjBwcEAwcHBAMHBwQDBwcEAAAAAUbq6uurExMT/xMTE/8TExP/ExMT/xMTE/8TExP/ExMT/xMTE/8TExP9ubm6QAAAALcTExADExMQAxMTEAAAAAFrHx8f/x8fH/8fHx/+7u8j/AADS/wAA0v+wsMj/x8fH/8fHx//Hx8f/vr6+7h4eHmQAAAAQx8fHAMfHxwAAAABXy8vL/8vLy//Ly8v/v7/M/wAA2/8AANv/s7PN/8vLy//Ly8v/y8vL/8vLy/+kpKS6AAAAM8vLywDLy8sAAAAAU9DQ0P/Q0ND/0NDQ/8TE0f8AAOX/AADl/7i40v/Q0ND/0NDQ/9DQ0P/Q0ND/0NDQ/2VlZXsAAAAk0NDQAAAAAE/U1NT/1NTU/9TU1P/IyNb/AADw/wAA8P+7u9f/1NTU/9TU1P/U1NT/1NTU/9TU1P/JycnkDw8PUwAAAAcAAABL2dnZ/9nZ2f/Z2dn/np7i/wAA+f8AAPn/goLm/9nZ2f/Z2dn/2dnZ/9nZ2f/Z2dn/2dnZ/6ioqKYAAAAqAAAASOLi4v/i4uL/4uLi/0hI9v8AAP//BQX+/yAg+//f3+L/4uLi/+Li4v/i4uL/4uLi/+Li4v/g4OD7AAAARgAAAETx8fH/8fHx/9jZ8v8LD///HiL+/3h6+P8IDP//lJX3//Hx8f/x8fH/8fHx//Hx8f/x8fH/7+/v+wAAAEIAAABA9vb2//b29v+Ah/v/Ex///3N6+//Z2vf/FiL//ys2/v/r7Pb/9vb2//b29v/29vb/9vb2/8jIyKMAAAAkAAAAPPn5+f/09Pn/NEf+/yA0///Gy/r/+fn5/1hn/f8gNP//jpj8//n5+f/5+fn/+fn5//Dw8OMXFxdBAAAABgAAADj7+/v/tb/8/y5K//9GX///+/v7//v7+/+zvfz/Lkr//zhS///l6Pv/+/v7//v7+/+Tk5NnAAAAGfv7+wAAAAA1/f39/3OM/v85Xf//mqz+//39/f/9/f3/9vf9/0do//85Xf//fpX+//39/f/c3NysAAAAH/39/QD9/f0AAAAAMv7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+/v+VrP//QWn//0Fp///T3PrtPj4+PgAAAAn+/v4A/v7+AAAAACn39/fi////////////////////////////////////////////////tbW1cgAAABf///8A////AP///wAAAAAVAAAAKAAAAC4AAAAuAAAALgAAAC4AAAAuAAAALgAAAC4AAAAuAAAALgAAABv///8A////AP///wD///8AAA8AAAAHAAAAAwAAAAMAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAMAAAADAAAABwAAAA8AAA==</Image>
-<Url type="application/x-suggestions+json" method="GET" template="http://suggest.yandex.com.tr/suggest-ff.cgi">
+<Image width="16" height="16">resource://search-plugins/images/yandex-en.ico</Image>
+<Url type="application/x-suggestions+json" method="GET" template="https://suggest.yandex.com.tr/suggest-ff.cgi">
   <Param name="part" value="{searchTerms}"/>
-  <Param name="uil" value="tr"/>
 </Url>
-<Url type="text/html" rel="searchform" method="GET" template="http://yandex.com.tr/yandsearch" resultdomain="yandex.com.tr">
+<Url type="text/html" method="GET" template="https://yandex.com.tr/yandsearch" resultdomain="yandex.com.tr">
   <MozParam name="clid" condition="purpose" purpose="searchbar"   value="2186618"/>
   <MozParam name="clid" condition="purpose" purpose="keyword"     value="2186621"/>
   <MozParam name="clid" condition="purpose" purpose="contextmenu" value="2186623"/>
   <MozParam name="clid" condition="purpose" purpose="homepage"    value="2186617"/>
   <MozParam name="clid" condition="purpose" purpose="newtab"      value="2186620"/>
-  <Param name="text" value="{searchTerms}"/>
+  <Param    name="text" value="{searchTerms}"/>
 </Url>
+<SearchForm>https://www.yandex.com.tr/</SearchForm>
 </SearchPlugin>
--- a/browser/locales/searchplugins/yandex-uk.xml
+++ b/browser/locales/searchplugins/yandex-uk.xml
@@ -1,16 +1,22 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
 <ShortName>Яндекс</ShortName>
 <Description>Пошук Яндексом.</Description>
 <InputEncoding>UTF-8</InputEncoding>
-<Image width="16" height="16">data:image/x-icon;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAB50lEQVQ4T43SvWsacRgH8OcPCITSLRQ6BSRL1gxZTNZQsgYC3QKunVoMnTKFhBQSnDqIUa5gxNbBCgriC4pv50sJ1lIR5SROpRVbz+O4b5/flbvedekJH+557nvfH8chdbvdIFMYPAgBICdqt9uKpmnw8huNRuDnX8J5QKvVgmEYnqiqClmWwZ113kmger0OXdf/Wv6EIb0BTo+AgB94ceDKJ5MJuHPOMwlUqVSwWq1sevQaxqvn0O5l6HdvgaMdV75cLtFoNMC9Xd6JisWiedNiPNuB9l4yZ+1jEvBvuXJBURRwL8YzUT6fx2KxsGHrKdQPCXNW794Bvieu3CLegrsnlM1mMZ/PbfqeH6vToDkvb2+Bx49cuWU2m4G7bUqn0xiPx7ZpqYRf29v4cXyMxf4+tLU1V24ZDAbgbptSqRSGw6HL9OwM37n4bXPTvP6bC7lcDtw9oWQyiX6/b/vMH1XZ2MAoEMDXqytM+QBnLtRqNXAvxjNRPB5Hr9ez9Q8PMfD50OM/2P3FBb7wAc680+mIMri3yzuRJEloNpsmORTCJy7INzd/9stLc7dyIZPJgDvnPJNA0WgU1WrVkxJ/4FgsBu6s804CRSKRh0KhgHK5/F+JRAL8fJBnslA4HH7NHhg8CDnLwm8IYz560xw92AAAAABJRU5ErkJggg==</Image>
-<Url type="application/x-suggestions+json" method="GET" template="http://suggest.yandex.net/suggest-ff.cgi?part={searchTerms}"/>
-<Url type="text/html" method="GET" template="http://www.yandex.ua/yandsearch" resultdomain="yandex.ua">
-  <Param name="text" value="{searchTerms}"/>
-  <Param name="from" value="fx3"/>
+<Image width="16" height="16">resource://search-plugins/images/yandex-ru.ico</Image>
+<Url type="application/x-suggestions+json" method="GET" template="https://suggest.yandex.ua/suggest-ff.cgi">
+  <Param name="part" value="{searchTerms}"/>
 </Url>
-<SearchForm>http://www.yandex.ua/</SearchForm>
+<Url type="text/html" method="GET" template="https://www.yandex.ua/yandsearch" resultdomain="yandex.ua">
+  <MozParam name="clid" condition="purpose" purpose="searchbar"   value="2186618"/>
+  <MozParam name="clid" condition="purpose" purpose="keyword"     value="2186621"/>
+  <MozParam name="clid" condition="purpose" purpose="contextmenu" value="2186623"/>
+  <MozParam name="clid" condition="purpose" purpose="homepage"    value="2186617"/>
+  <MozParam name="clid" condition="purpose" purpose="newtab"      value="2186620"/>
+  <Param    name="text" value="{searchTerms}"/>
+</Url>
+<SearchForm>https://www.yandex.ua/</SearchForm>
 </SearchPlugin>
--- a/caps/BasePrincipal.cpp
+++ b/caps/BasePrincipal.cpp
@@ -9,58 +9,60 @@
 #include "nsDocShell.h"
 #ifdef MOZ_CRASHREPORTER
 #include "nsExceptionHandler.h"
 #endif
 #include "nsIAddonPolicyService.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsIObjectInputStream.h"
 #include "nsIObjectOutputStream.h"
+#include "nsIStandardURL.h"
 
 #include "ContentPrincipal.h"
 #include "nsNetUtil.h"
 #include "nsIURIWithPrincipal.h"
 #include "NullPrincipal.h"
 #include "nsScriptSecurityManager.h"
 #include "nsServiceManagerUtils.h"
 
 #include "mozilla/dom/ChromeUtils.h"
 #include "mozilla/dom/CSPDictionariesBinding.h"
 #include "mozilla/dom/ToJSValue.h"
 
 namespace mozilla {
 
 BasePrincipal::BasePrincipal(PrincipalKind aKind)
   : mKind(aKind)
-  , mDomainSet(false)
+  , mHasExplicitDomain(false)
+  , mInitialized(false)
 {}
 
 BasePrincipal::~BasePrincipal()
 {}
 
 NS_IMETHODIMP
 BasePrincipal::GetOrigin(nsACString& aOrigin)
 {
+  MOZ_ASSERT(mInitialized);
+
   nsresult rv = GetOriginNoSuffix(aOrigin);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsAutoCString suffix;
   rv = GetOriginSuffix(suffix);
   NS_ENSURE_SUCCESS(rv, rv);
   aOrigin.Append(suffix);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 BasePrincipal::GetOriginNoSuffix(nsACString& aOrigin)
 {
-  if (mOriginNoSuffix) {
-    return mOriginNoSuffix->ToUTF8String(aOrigin);
-  }
-  return GetOriginInternal(aOrigin);
+  MOZ_ASSERT(mInitialized);
+  return mOriginNoSuffix->ToUTF8String(aOrigin);
 }
 
 bool
 BasePrincipal::Subsumes(nsIPrincipal* aOther, DocumentDomainConsideration aConsideration)
 {
   MOZ_ASSERT(aOther);
   MOZ_ASSERT_IF(Kind() == eCodebasePrincipal, mOriginSuffix);
 
@@ -362,18 +364,41 @@ BasePrincipal::AddonHasPermission(const 
 
   bool retval = false;
   nsresult rv = aps->AddonHasPermission(addonId, aPerm, &retval);
   NS_ENSURE_SUCCESS(rv, false);
   return retval;
 }
 
 already_AddRefed<BasePrincipal>
-BasePrincipal::CreateCodebasePrincipal(nsIURI* aURI, const OriginAttributes& aAttrs)
+BasePrincipal::CreateCodebasePrincipal(nsIURI* aURI,
+                                       const OriginAttributes& aAttrs)
 {
+  MOZ_ASSERT(aURI);
+
+  nsAutoCString originNoSuffix;
+  nsresult rv =
+    ContentPrincipal::GenerateOriginNoSuffixFromURI(aURI, originNoSuffix);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    // If the generation of the origin fails, we still want to have a valid
+    // principal. Better to return a null principal here.
+    return NullPrincipal::Create(aAttrs);
+  }
+
+  return CreateCodebasePrincipal(aURI, aAttrs, originNoSuffix);
+}
+
+already_AddRefed<BasePrincipal>
+BasePrincipal::CreateCodebasePrincipal(nsIURI* aURI,
+                                       const OriginAttributes& aAttrs,
+                                       const nsACString& aOriginNoSuffix)
+{
+  MOZ_ASSERT(aURI);
+  MOZ_ASSERT(!aOriginNoSuffix.IsEmpty());
+
   // If the URI is supposed to inherit the security context of whoever loads it,
   // we shouldn't make a codebase principal for it.
   bool inheritsPrincipal;
   nsresult rv = NS_URIChainHasFlags(aURI, nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT,
                                     &inheritsPrincipal);
   if (NS_FAILED(rv) || inheritsPrincipal) {
     return NullPrincipal::Create(aAttrs);
   }
@@ -387,17 +412,17 @@ BasePrincipal::CreateCodebasePrincipal(n
       return NullPrincipal::Create(aAttrs);
     }
     RefPtr<BasePrincipal> concrete = Cast(principal);
     return concrete.forget();
   }
 
   // Mint a codebase principal.
   RefPtr<ContentPrincipal> codebase = new ContentPrincipal();
-  rv = codebase->Init(aURI, aAttrs);
+  rv = codebase->Init(aURI, aAttrs, aOriginNoSuffix);
   NS_ENSURE_SUCCESS(rv, nullptr);
   return codebase.forget();
 }
 
 already_AddRefed<BasePrincipal>
 BasePrincipal::CreateCodebasePrincipal(const nsACString& aOrigin)
 {
   MOZ_ASSERT(!StringBeginsWith(aOrigin, NS_LITERAL_CSTRING("[")),
@@ -451,29 +476,24 @@ BasePrincipal::AddonAllowsLoad(nsIURI* a
   NS_ENSURE_TRUE(aps, false);
 
   bool allowed = false;
   nsresult rv = aps->AddonMayLoadURI(addonId, aURI, aExplicit, &allowed);
   return NS_SUCCEEDED(rv) && allowed;
 }
 
 void
-BasePrincipal::FinishInit()
+BasePrincipal::FinishInit(const nsACString& aOriginNoSuffix,
+                          const OriginAttributes& aOriginAttributes)
 {
+  mInitialized = true;
+  mOriginAttributes = aOriginAttributes;
+
   // First compute the origin suffix since it's infallible.
   nsAutoCString originSuffix;
   mOriginAttributes.CreateSuffix(originSuffix);
   mOriginSuffix = NS_Atomize(originSuffix);
 
-  // Then compute the origin without the suffix.
-  nsAutoCString originNoSuffix;
-  nsresult rv = GetOriginInternal(originNoSuffix);
-  if (NS_FAILED(rv)) {
-    // If GetOriginInternal fails, we will get a null atom for mOriginNoSuffix,
-    // which we deal with anywhere mOriginNoSuffix is used.
-    // Once this is made infallible we can remove those null checks.
-    mOriginNoSuffix = nullptr;
-    return;
-  }
-  mOriginNoSuffix = NS_Atomize(originNoSuffix);
+  MOZ_ASSERT(!aOriginNoSuffix.IsEmpty());
+  mOriginNoSuffix = NS_Atomize(aOriginNoSuffix);
 }
 
 } // namespace mozilla
--- a/caps/BasePrincipal.h
+++ b/caps/BasePrincipal.h
@@ -70,19 +70,26 @@ public:
   NS_IMETHOD GetUserContextId(uint32_t* aUserContextId) final;
   NS_IMETHOD GetPrivateBrowsingId(uint32_t* aPrivateBrowsingId) final;
 
   virtual bool AddonHasPermission(const nsAString& aPerm);
 
   virtual bool IsCodebasePrincipal() const { return false; };
 
   static BasePrincipal* Cast(nsIPrincipal* aPrin) { return static_cast<BasePrincipal*>(aPrin); }
+
+  static already_AddRefed<BasePrincipal>
+  CreateCodebasePrincipal(const nsACString& aOrigin);
+
+  // These following method may not create a codebase principal in case it's
+  // not possible to generate a correct origin from the passed URI. If this
+  // happens, a NullPrincipal is returned.
+
   static already_AddRefed<BasePrincipal>
   CreateCodebasePrincipal(nsIURI* aURI, const OriginAttributes& aAttrs);
-  static already_AddRefed<BasePrincipal> CreateCodebasePrincipal(const nsACString& aOrigin);
 
   const OriginAttributes& OriginAttributesRef() final { return mOriginAttributes; }
   uint32_t AppId() const { return mOriginAttributes.mAppId; }
   uint32_t UserContextId() const { return mOriginAttributes.mUserContextId; }
   uint32_t PrivateBrowsingId() const { return mOriginAttributes.mPrivateBrowsingId; }
   bool IsInIsolatedMozBrowserElement() const { return mOriginAttributes.mInIsolatedMozBrowser; }
 
   PrincipalKind Kind() const { return mKind; }
@@ -99,39 +106,53 @@ public:
   inline bool FastEqualsConsideringDomain(nsIPrincipal* aOther);
   inline bool FastSubsumes(nsIPrincipal* aOther);
   inline bool FastSubsumesConsideringDomain(nsIPrincipal* aOther);
   inline bool FastSubsumesConsideringDomainIgnoringFPD(nsIPrincipal* aOther);
 
 protected:
   virtual ~BasePrincipal();
 
-  virtual nsresult GetOriginInternal(nsACString& aOrigin) = 0;
   // Note that this does not check OriginAttributes. Callers that depend on
   // those must call Subsumes instead.
   virtual bool SubsumesInternal(nsIPrincipal* aOther, DocumentDomainConsideration aConsider) = 0;
 
   // Internal, side-effect-free check to determine whether the concrete
   // principal would allow the load ignoring any common behavior implemented in
   // BasePrincipal::CheckMayLoad.
   virtual bool MayLoadInternal(nsIURI* aURI) = 0;
   friend class ::ExpandedPrincipal;
 
+  void
+  SetHasExplicitDomain()
+  {
+    mHasExplicitDomain = true;
+  }
+
   // This function should be called as the last step of the initialization of the
   // principal objects.  It's typically called as the last step from the Init()
   // method of the child classes.
-  void FinishInit();
+  void FinishInit(const nsACString& aOriginNoSuffix,
+                  const OriginAttributes& aOriginAttributes);
 
   nsCOMPtr<nsIContentSecurityPolicy> mCSP;
   nsCOMPtr<nsIContentSecurityPolicy> mPreloadCSP;
+
+private:
+  static already_AddRefed<BasePrincipal>
+  CreateCodebasePrincipal(nsIURI* aURI, const OriginAttributes& aAttrs,
+                          const nsACString& aOriginNoSuffix);
+
   nsCOMPtr<nsIAtom> mOriginNoSuffix;
   nsCOMPtr<nsIAtom> mOriginSuffix;
+
   OriginAttributes mOriginAttributes;
   PrincipalKind mKind;
-  bool mDomainSet;
+  bool mHasExplicitDomain;
+  bool mInitialized;
 };
 
 inline bool
 BasePrincipal::FastEquals(nsIPrincipal* aOther)
 {
   auto other = Cast(aOther);
   if (Kind() != other->Kind()) {
     // Principals of different kinds can't be equal.
@@ -142,75 +163,65 @@ BasePrincipal::FastEquals(nsIPrincipal* 
   // If the two principals are codebase principals, their origin attributes
   // (aka the origin suffix) must also match.
   // If the two principals are null principals, they're only equal if they're
   // the same object.
   if (Kind() == eNullPrincipal || Kind() == eSystemPrincipal) {
     return this == other;
   }
 
-  if (mOriginNoSuffix) {
-    if (Kind() == eCodebasePrincipal) {
-      return mOriginNoSuffix == other->mOriginNoSuffix &&
-             mOriginSuffix == other->mOriginSuffix;
-    }
-
-    MOZ_ASSERT(Kind() == eExpandedPrincipal);
-    return mOriginNoSuffix == other->mOriginNoSuffix;
+  if (Kind() == eCodebasePrincipal) {
+    return mOriginNoSuffix == other->mOriginNoSuffix &&
+           mOriginSuffix == other->mOriginSuffix;
   }
 
-  // If mOriginNoSuffix is null on one of our principals, we must fall back
-  // to the slow path.
-  return Subsumes(aOther, DontConsiderDocumentDomain) &&
-         other->Subsumes(this, DontConsiderDocumentDomain);
+  MOZ_ASSERT(Kind() == eExpandedPrincipal);
+  return mOriginNoSuffix == other->mOriginNoSuffix;
 }
 
 inline bool
 BasePrincipal::FastEqualsConsideringDomain(nsIPrincipal* aOther)
 {
   // If neither of the principals have document.domain set, we use the fast path
   // in Equals().  Otherwise, we fall back to the slow path below.
   auto other = Cast(aOther);
-  if (!mDomainSet && !other->mDomainSet) {
+  if (!mHasExplicitDomain && !other->mHasExplicitDomain) {
     return FastEquals(aOther);
   }
 
   return Subsumes(aOther, ConsiderDocumentDomain) &&
          other->Subsumes(this, ConsiderDocumentDomain);
 }
 
 inline bool
 BasePrincipal::FastSubsumes(nsIPrincipal* aOther)
 {
   // If two principals are equal, then they both subsume each other.
   // We deal with two special cases first:
   // Null principals only subsume each other if they are equal, and are only
   // equal if they're the same object.
-  // Also, if mOriginNoSuffix is null, FastEquals falls back to the slow path
-  // using Subsumes, so we don't want to use it in that case to avoid an
-  // infinite recursion.
   auto other = Cast(aOther);
   if (Kind() == eNullPrincipal && other->Kind() == eNullPrincipal) {
     return this == other;
   }
-  if (mOriginNoSuffix && FastEquals(aOther)) {
+  if (FastEquals(aOther)) {
     return true;
   }
 
   // Otherwise, fall back to the slow path.
   return Subsumes(aOther, DontConsiderDocumentDomain);
 }
 
 inline bool
 BasePrincipal::FastSubsumesConsideringDomain(nsIPrincipal* aOther)
 {
   // If neither of the principals have document.domain set, we hand off to
   // FastSubsumes() which has fast paths for some special cases. Otherwise, we fall
   // back to the slow path below.
-  if (!mDomainSet && !Cast(aOther)->mDomainSet) {
+  if (!mHasExplicitDomain && !Cast(aOther)->mHasExplicitDomain) {
     return FastSubsumes(aOther);
   }
 
   return Subsumes(aOther, ConsiderDocumentDomain);
 }
 
 inline bool
 BasePrincipal::FastSubsumesConsideringDomainIgnoringFPD(nsIPrincipal* aOther)
--- a/caps/ContentPrincipal.cpp
+++ b/caps/ContentPrincipal.cpp
@@ -77,85 +77,82 @@ ContentPrincipal::InitializeStatics()
                                "signed.applets.codebase_principal_support",
                                false);
 }
 
 ContentPrincipal::ContentPrincipal()
   : BasePrincipal(eCodebasePrincipal)
   , mCodebaseImmutable(false)
   , mDomainImmutable(false)
-  , mInitialized(false)
 {
 }
 
 ContentPrincipal::~ContentPrincipal()
 {
   // let's clear the principal within the csp to avoid a tangling pointer
   if (mCSP) {
     static_cast<nsCSPContext*>(mCSP.get())->clearLoadingPrincipal();
   }
 }
 
 nsresult
 ContentPrincipal::Init(nsIURI *aCodebase,
-                       const OriginAttributes& aOriginAttributes)
+                       const OriginAttributes& aOriginAttributes,
+                       const nsACString& aOriginNoSuffix)
 {
-  NS_ENSURE_STATE(!mInitialized);
   NS_ENSURE_ARG(aCodebase);
 
-  mInitialized = true;
-
   // Assert that the URI we get here isn't any of the schemes that we know we
   // should not get here.  These schemes always either inherit their principal
   // or fall back to a null principal.  These are schemes which return
   // URI_INHERITS_SECURITY_CONTEXT from their protocol handler's
   // GetProtocolFlags function.
   bool hasFlag;
   Unused << hasFlag; // silence possible compiler warnings.
   MOZ_DIAGNOSTIC_ASSERT(
       NS_SUCCEEDED(NS_URIChainHasFlags(aCodebase,
                                        nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT,
                                        &hasFlag)) &&
       !hasFlag);
 
   mCodebase = NS_TryToMakeImmutable(aCodebase);
   mCodebaseImmutable = URIIsImmutable(mCodebase);
-  mOriginAttributes = aOriginAttributes;
 
-  FinishInit();
+  FinishInit(aOriginNoSuffix, aOriginAttributes);
 
   return NS_OK;
 }
 
 nsresult
 ContentPrincipal::GetScriptLocation(nsACString &aStr)
 {
   return mCodebase->GetSpec(aStr);
 }
 
-nsresult
-ContentPrincipal::GetOriginInternal(nsACString& aOrigin)
+/* static */ nsresult
+ContentPrincipal::GenerateOriginNoSuffixFromURI(nsIURI* aURI,
+                                                nsACString& aOriginNoSuffix)
 {
-  if (!mCodebase) {
+  if (!aURI) {
     return NS_ERROR_FAILURE;
   }
 
-  nsCOMPtr<nsIURI> origin = NS_GetInnermostURI(mCodebase);
+  nsCOMPtr<nsIURI> origin = NS_GetInnermostURI(aURI);
   if (!origin) {
     return NS_ERROR_FAILURE;
   }
 
   MOZ_ASSERT(!NS_IsAboutBlank(origin),
              "The inner URI for about:blank must be moz-safe-about:blank");
 
   if (!nsScriptSecurityManager::GetStrictFileOriginPolicy() &&
       NS_URIIsLocalFile(origin)) {
     // If strict file origin policy is not in effect, all local files are
     // considered to be same-origin, so return a known dummy origin here.
-    aOrigin.AssignLiteral("file://UNIVERSAL_FILE_URI_ORIGIN");
+    aOriginNoSuffix.AssignLiteral("file://UNIVERSAL_FILE_URI_ORIGIN");
     return NS_OK;
   }
 
   nsAutoCString hostPort;
 
   // chrome: URLs don't have a meaningful origin, so make
   // sure we just get the full spec for them.
   // XXX this should be removed in favor of the solution in
@@ -185,74 +182,74 @@ ContentPrincipal::GetOriginInternal(nsAC
   bool isBehaved;
   if ((NS_SUCCEEDED(origin->SchemeIs("about", &isBehaved)) && isBehaved) ||
       (NS_SUCCEEDED(origin->SchemeIs("moz-safe-about", &isBehaved)) && isBehaved &&
        // We generally consider two about:foo origins to be same-origin, but
        // about:blank is special since it can be generated from different sources.
        // We check for moz-safe-about:blank since origin is an innermost URI.
        !origin->GetSpecOrDefault().EqualsLiteral("moz-safe-about:blank")) ||
       (NS_SUCCEEDED(origin->SchemeIs("indexeddb", &isBehaved)) && isBehaved)) {
-    rv = origin->GetAsciiSpec(aOrigin);
+    rv = origin->GetAsciiSpec(aOriginNoSuffix);
     NS_ENSURE_SUCCESS(rv, rv);
     // These URIs could technically contain a '^', but they never should.
-    if (NS_WARN_IF(aOrigin.FindChar('^', 0) != -1)) {
-      aOrigin.Truncate();
+    if (NS_WARN_IF(aOriginNoSuffix.FindChar('^', 0) != -1)) {
+      aOriginNoSuffix.Truncate();
       return NS_ERROR_FAILURE;
     }
     return NS_OK;
   }
 
   if (NS_SUCCEEDED(rv) && !isChrome) {
-    rv = origin->GetScheme(aOrigin);
+    rv = origin->GetScheme(aOriginNoSuffix);
     NS_ENSURE_SUCCESS(rv, rv);
-    aOrigin.AppendLiteral("://");
-    aOrigin.Append(hostPort);
+    aOriginNoSuffix.AppendLiteral("://");
+    aOriginNoSuffix.Append(hostPort);
     return NS_OK;
   }
 
   // This URL can be a blobURL. In this case, we should use the 'parent'
   // principal instead.
   nsCOMPtr<nsIURIWithPrincipal> uriWithPrincipal = do_QueryInterface(origin);
   if (uriWithPrincipal) {
     nsCOMPtr<nsIPrincipal> uriPrincipal;
     rv = uriWithPrincipal->GetPrincipal(getter_AddRefs(uriPrincipal));
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (uriPrincipal) {
-      return uriPrincipal->GetOriginNoSuffix(aOrigin);
+      return uriPrincipal->GetOriginNoSuffix(aOriginNoSuffix);
     }
   }
 
   // If we reached this branch, we can only create an origin if we have a
   // nsIStandardURL.  So, we query to a nsIStandardURL, and fail if we aren't
   // an instance of an nsIStandardURL nsIStandardURLs have the good property
   // of escaping the '^' character in their specs, which means that we can be
   // sure that the caret character (which is reserved for delimiting the end
   // of the spec, and the beginning of the origin attributes) is not present
   // in the origin string
   nsCOMPtr<nsIStandardURL> standardURL = do_QueryInterface(origin);
   if (!standardURL) {
     return NS_ERROR_FAILURE;
   }
 
-  rv = origin->GetAsciiSpec(aOrigin);
+  rv = origin->GetAsciiSpec(aOriginNoSuffix);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // The origin, when taken from the spec, should not contain the ref part of
   // the URL.
 
-  int32_t pos = aOrigin.FindChar('?');
-  int32_t hashPos = aOrigin.FindChar('#');
+  int32_t pos = aOriginNoSuffix.FindChar('?');
+  int32_t hashPos = aOriginNoSuffix.FindChar('#');
 
   if (hashPos != kNotFound && (pos == kNotFound || hashPos < pos)) {
     pos = hashPos;
   }
 
   if (pos != kNotFound) {
-    aOrigin.Truncate(pos);
+    aOriginNoSuffix.Truncate(pos);
   }
 
   return NS_OK;
 }
 
 bool
 ContentPrincipal::SubsumesInternal(nsIPrincipal* aOther,
                                    BasePrincipal::DocumentDomainConsideration aConsideration)
@@ -367,17 +364,17 @@ ContentPrincipal::GetDomain(nsIURI** aDo
   return NS_EnsureSafeToReturn(mDomain, aDomain);
 }
 
 NS_IMETHODIMP
 ContentPrincipal::SetDomain(nsIURI* aDomain)
 {
   mDomain = NS_TryToMakeImmutable(aDomain);
   mDomainImmutable = URIIsImmutable(mDomain);
-  mDomainSet = true;
+  SetHasExplicitDomain();
 
   // Recompute all wrappers between compartments using this principal and other
   // non-chrome compartments.
   AutoSafeJSContext cx;
   JSPrincipals *principals = nsJSPrincipals::get(static_cast<nsIPrincipal*>(this));
   bool success = js::RecomputeWrappers(cx, js::ContentCompartmentsOnly(),
                                        js::CompartmentsWithPrincipals(principals));
   NS_ENSURE_TRUE(success, NS_ERROR_FAILURE);
@@ -478,17 +475,21 @@ ContentPrincipal::Read(nsIObjectInputStr
 
   OriginAttributes attrs;
   bool ok = attrs.PopulateFromSuffix(suffix);
   NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
 
   rv = NS_ReadOptionalObject(aStream, true, getter_AddRefs(supports));
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = Init(codebase, attrs);
+  nsAutoCString originNoSuffix;
+  rv = GenerateOriginNoSuffixFromURI(codebase, originNoSuffix);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = Init(codebase, attrs, originNoSuffix);
   NS_ENSURE_SUCCESS(rv, rv);
 
   mCSP = do_QueryInterface(supports, &rv);
   // make sure setRequestContext is called after Init(),
   // to make sure  the principals URI been initalized.
   if (mCSP) {
     mCSP->SetRequestContext(nullptr, this);
   }
--- a/caps/ContentPrincipal.h
+++ b/caps/ContentPrincipal.h
@@ -22,37 +22,39 @@ public:
   NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override;
   NS_IMETHOD GetHashValue(uint32_t* aHashValue) override;
   NS_IMETHOD GetURI(nsIURI** aURI) override;
   NS_IMETHOD GetDomain(nsIURI** aDomain) override;
   NS_IMETHOD SetDomain(nsIURI* aDomain) override;
   NS_IMETHOD GetBaseDomain(nsACString& aBaseDomain) override;
   NS_IMETHOD GetAddonId(nsAString& aAddonId) override;
   bool IsCodebasePrincipal() const override { return true; }
-  nsresult GetOriginInternal(nsACString& aOrigin) override;
 
   ContentPrincipal();
 
   // Init() must be called before the principal is in a usable state.
   nsresult Init(nsIURI* aCodebase,
-                const mozilla::OriginAttributes& aOriginAttributes);
+                const mozilla::OriginAttributes& aOriginAttributes,
+                const nsACString& aOriginNoSuffix);
 
   virtual nsresult GetScriptLocation(nsACString& aStr) override;
 
   /**
    * Called at startup to setup static data, e.g. about:config pref-observers.
    */
   static void InitializeStatics();
 
+  static nsresult
+  GenerateOriginNoSuffixFromURI(nsIURI* aURI, nsACString& aOrigin);
+
   nsCOMPtr<nsIURI> mDomain;
   nsCOMPtr<nsIURI> mCodebase;
   // If mCodebaseImmutable is true, mCodebase is non-null and immutable
   bool mCodebaseImmutable;
   bool mDomainImmutable;
-  bool mInitialized;
 
 protected:
   virtual ~ContentPrincipal();
 
   bool SubsumesInternal(nsIPrincipal* aOther,
                         DocumentDomainConsideration aConsideration) override;
   bool MayLoadInternal(nsIURI* aURI) override;
 
--- a/caps/ExpandedPrincipal.cpp
+++ b/caps/ExpandedPrincipal.cpp
@@ -18,93 +18,87 @@ NS_IMPL_CI_INTERFACE_GETTER(ExpandedPrin
                             nsIPrincipal,
                             nsIExpandedPrincipal)
 
 struct OriginComparator
 {
   bool LessThan(nsIPrincipal* a, nsIPrincipal* b) const
   {
     nsAutoCString originA;
-    nsresult rv = a->GetOrigin(originA);
-    NS_ENSURE_SUCCESS(rv, false);
+    DebugOnly<nsresult> rv = a->GetOrigin(originA);
+    MOZ_ASSERT(NS_SUCCEEDED(rv));
     nsAutoCString originB;
     rv = b->GetOrigin(originB);
-    NS_ENSURE_SUCCESS(rv, false);
+    MOZ_ASSERT(NS_SUCCEEDED(rv));
     return originA < originB;
   }
 
   bool Equals(nsIPrincipal* a, nsIPrincipal* b) const
   {
     nsAutoCString originA;
-    nsresult rv = a->GetOrigin(originA);
-    NS_ENSURE_SUCCESS(rv, false);
+    DebugOnly<nsresult> rv = a->GetOrigin(originA);
+    MOZ_ASSERT(NS_SUCCEEDED(rv));
     nsAutoCString originB;
     rv = b->GetOrigin(originB);
-    NS_ENSURE_SUCCESS(rv, false);
+    MOZ_ASSERT(NS_SUCCEEDED(rv));
     return a == b;
   }
 };
 
-ExpandedPrincipal::ExpandedPrincipal(nsTArray<nsCOMPtr<nsIPrincipal>> &aWhiteList,
-                                     const OriginAttributes& aAttrs)
+ExpandedPrincipal::ExpandedPrincipal(nsTArray<nsCOMPtr<nsIPrincipal>> &aWhiteList)
   : BasePrincipal(eExpandedPrincipal)
 {
   // We force the principals to be sorted by origin so that ExpandedPrincipal
   // origins can have a canonical form.
   OriginComparator c;
   for (size_t i = 0; i < aWhiteList.Length(); ++i) {
     mPrincipals.InsertElementSorted(aWhiteList[i], c);
   }
-  mOriginAttributes = aAttrs;
 }
 
 ExpandedPrincipal::~ExpandedPrincipal()
 { }
 
 already_AddRefed<ExpandedPrincipal>
 ExpandedPrincipal::Create(nsTArray<nsCOMPtr<nsIPrincipal>>& aWhiteList,
                           const OriginAttributes& aAttrs)
 {
-  RefPtr<ExpandedPrincipal> ep = new ExpandedPrincipal(aWhiteList, aAttrs);
-  ep->FinishInit();
+  RefPtr<ExpandedPrincipal> ep = new ExpandedPrincipal(aWhiteList);
+
+  nsAutoCString origin;
+  origin.AssignLiteral("[Expanded Principal [");
+  for (size_t i = 0; i < ep->mPrincipals.Length(); ++i) {
+    if (i != 0) {
+      origin.AppendLiteral(", ");
+    }
+
+    nsAutoCString subOrigin;
+    DebugOnly<nsresult> rv = ep->mPrincipals.ElementAt(i)->GetOrigin(subOrigin);
+    MOZ_ASSERT(NS_SUCCEEDED(rv));
+    origin.Append(subOrigin);
+  }
+  origin.Append("]]");
+
+  ep->FinishInit(origin, aAttrs);
   return ep.forget();
 }
 
 NS_IMETHODIMP
 ExpandedPrincipal::GetDomain(nsIURI** aDomain)
 {
   *aDomain = nullptr;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 ExpandedPrincipal::SetDomain(nsIURI* aDomain)
 {
   return NS_OK;
 }
 
-nsresult
-ExpandedPrincipal::GetOriginInternal(nsACString& aOrigin)
-{
-  aOrigin.AssignLiteral("[Expanded Principal [");
-  for (size_t i = 0; i < mPrincipals.Length(); ++i) {
-    if (i != 0) {
-      aOrigin.AppendLiteral(", ");
-    }
-
-    nsAutoCString subOrigin;
-    nsresult rv = mPrincipals.ElementAt(i)->GetOrigin(subOrigin);
-    NS_ENSURE_SUCCESS(rv, rv);
-    aOrigin.Append(subOrigin);
-  }
-
-  aOrigin.Append("]]");
-  return NS_OK;
-}
-
 bool
 ExpandedPrincipal::SubsumesInternal(nsIPrincipal* aOther,
                                     BasePrincipal::DocumentDomainConsideration aConsideration)
 {
   // If aOther is an ExpandedPrincipal too, we break it down into its component
   // nsIPrincipals, and check subsumes on each one.
   nsCOMPtr<nsIExpandedPrincipal> expanded = do_QueryInterface(aOther);
   if (expanded) {
--- a/caps/ExpandedPrincipal.h
+++ b/caps/ExpandedPrincipal.h
@@ -10,19 +10,16 @@
 #include "nsJSPrincipals.h"
 #include "nsTArray.h"
 #include "nsNetUtil.h"
 #include "mozilla/BasePrincipal.h"
 
 class ExpandedPrincipal : public nsIExpandedPrincipal
                         , public mozilla::BasePrincipal
 {
-  ExpandedPrincipal(nsTArray<nsCOMPtr<nsIPrincipal>> &aWhiteList,
-                    const mozilla::OriginAttributes& aAttrs);
-
 public:
   static already_AddRefed<ExpandedPrincipal>
   Create(nsTArray<nsCOMPtr<nsIPrincipal>>& aWhiteList,
          const mozilla::OriginAttributes& aAttrs);
 
   NS_DECL_NSIEXPANDEDPRINCIPAL
   NS_DECL_NSISERIALIZABLE
 
@@ -32,19 +29,20 @@ public:
   NS_IMETHOD GetHashValue(uint32_t* aHashValue) override;
   NS_IMETHOD GetURI(nsIURI** aURI) override;
   NS_IMETHOD GetDomain(nsIURI** aDomain) override;
   NS_IMETHOD SetDomain(nsIURI* aDomain) override;
   NS_IMETHOD GetBaseDomain(nsACString& aBaseDomain) override;
   NS_IMETHOD GetAddonId(nsAString& aAddonId) override;
   virtual bool AddonHasPermission(const nsAString& aPerm) override;
   virtual nsresult GetScriptLocation(nsACString &aStr) override;
-  nsresult GetOriginInternal(nsACString& aOrigin) override;
 
 protected:
+  explicit ExpandedPrincipal(nsTArray<nsCOMPtr<nsIPrincipal>> &aWhiteList);
+
   virtual ~ExpandedPrincipal();
 
   bool SubsumesInternal(nsIPrincipal* aOther,
                         DocumentDomainConsideration aConsideration) override;
 
   bool MayLoadInternal(nsIURI* aURI) override;
 
 private:
--- a/caps/NullPrincipal.cpp
+++ b/caps/NullPrincipal.cpp
@@ -65,33 +65,35 @@ NullPrincipal::Create(const OriginAttrib
   MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
 
   return nullPrin.forget();
 }
 
 nsresult
 NullPrincipal::Init(const OriginAttributes& aOriginAttributes, nsIURI* aURI)
 {
-  mOriginAttributes = aOriginAttributes;
-
   if (aURI) {
     nsAutoCString scheme;
     nsresult rv = aURI->GetScheme(scheme);
     NS_ENSURE_SUCCESS(rv, rv);
 
     NS_ENSURE_TRUE(scheme.EqualsLiteral(NS_NULLPRINCIPAL_SCHEME),
                    NS_ERROR_NOT_AVAILABLE);
 
     mURI = aURI;
   } else {
     mURI = NullPrincipalURI::Create();
     NS_ENSURE_TRUE(mURI, NS_ERROR_NOT_AVAILABLE);
   }
 
-  FinishInit();
+  nsAutoCString originNoSuffix;
+  DebugOnly<nsresult> rv = mURI->GetSpec(originNoSuffix);
+  MOZ_ASSERT(NS_SUCCEEDED(rv));
+
+  FinishInit(originNoSuffix, aOriginAttributes);
 
   return NS_OK;
 }
 
 nsresult
 NullPrincipal::GetScriptLocation(nsACString &aStr)
 {
   return mURI->GetSpec(aStr);
@@ -138,22 +140,16 @@ NullPrincipal::GetDomain(nsIURI** aDomai
 NS_IMETHODIMP
 NullPrincipal::SetDomain(nsIURI* aDomain)
 {
   // I think the right thing to do here is to just throw...  Silently failing
   // seems counterproductive.
   return NS_ERROR_NOT_AVAILABLE;
 }
 
-nsresult
-NullPrincipal::GetOriginInternal(nsACString& aOrigin)
-{
-  return mURI->GetSpec(aOrigin);
-}
-
 bool
 NullPrincipal::MayLoadInternal(nsIURI* aURI)
 {
   // Also allow the load if we are the principal of the URI being checked.
   nsCOMPtr<nsIURIWithPrincipal> uriPrinc = do_QueryInterface(aURI);
   if (uriPrinc) {
     nsCOMPtr<nsIPrincipal> principal;
     uriPrinc->GetPrincipal(getter_AddRefs(principal));
--- a/caps/NullPrincipal.h
+++ b/caps/NullPrincipal.h
@@ -46,17 +46,16 @@ public:
   NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override;
   NS_IMETHOD GetHashValue(uint32_t* aHashValue) override;
   NS_IMETHOD SetCsp(nsIContentSecurityPolicy* aCsp) override;
   NS_IMETHOD GetURI(nsIURI** aURI) override;
   NS_IMETHOD GetDomain(nsIURI** aDomain) override;
   NS_IMETHOD SetDomain(nsIURI* aDomain) override;
   NS_IMETHOD GetBaseDomain(nsACString& aBaseDomain) override;
   NS_IMETHOD GetAddonId(nsAString& aAddonId) override;
-  nsresult GetOriginInternal(nsACString& aOrigin) override;
 
   static already_AddRefed<NullPrincipal> CreateWithInheritedAttributes(nsIPrincipal* aInheritFrom);
 
   // Create NullPrincipal with origin attributes from docshell.
   // If aIsFirstParty is true, and the pref 'privacy.firstparty.isolate' is also
   // enabled, the mFirstPartyDomain value of the origin attributes will be set
   // to NULL_PRINCIPAL_FIRST_PARTY_DOMAIN.
   static already_AddRefed<NullPrincipal>
--- a/caps/SystemPrincipal.cpp
+++ b/caps/SystemPrincipal.cpp
@@ -30,17 +30,18 @@ NS_IMPL_CI_INTERFACE_GETTER(SystemPrinci
                             nsISerializable)
 
 #define SYSTEM_PRINCIPAL_SPEC "[System Principal]"
 
 already_AddRefed<SystemPrincipal>
 SystemPrincipal::Create()
 {
   RefPtr<SystemPrincipal> sp = new SystemPrincipal();
-  sp->FinishInit();
+  sp->FinishInit(NS_LITERAL_CSTRING(SYSTEM_PRINCIPAL_SPEC),
+                 OriginAttributes());
   return sp.forget();
 }
 
 nsresult
 SystemPrincipal::GetScriptLocation(nsACString &aStr)
 {
     aStr.AssignLiteral(SYSTEM_PRINCIPAL_SPEC);
     return NS_OK;
@@ -59,23 +60,16 @@ SystemPrincipal::GetHashValue(uint32_t *
 
 NS_IMETHODIMP
 SystemPrincipal::GetURI(nsIURI** aURI)
 {
     *aURI = nullptr;
     return NS_OK;
 }
 
-nsresult
-SystemPrincipal::GetOriginInternal(nsACString& aOrigin)
-{
-    aOrigin.AssignLiteral(SYSTEM_PRINCIPAL_SPEC);
-    return NS_OK;
-}
-
 NS_IMETHODIMP
 SystemPrincipal::GetCsp(nsIContentSecurityPolicy** aCsp)
 {
   *aCsp = nullptr;
   return NS_OK;
 }
 
 NS_IMETHODIMP
--- a/caps/SystemPrincipal.h
+++ b/caps/SystemPrincipal.h
@@ -38,17 +38,16 @@ public:
   NS_IMETHOD SetDomain(nsIURI* aDomain) override;
   NS_IMETHOD GetCsp(nsIContentSecurityPolicy** aCsp) override;
   NS_IMETHOD SetCsp(nsIContentSecurityPolicy* aCsp) override;
   NS_IMETHOD EnsureCSP(nsIDOMDocument* aDocument, nsIContentSecurityPolicy** aCSP) override;
   NS_IMETHOD GetPreloadCsp(nsIContentSecurityPolicy** aPreloadCSP) override;
   NS_IMETHOD EnsurePreloadCSP(nsIDOMDocument* aDocument, nsIContentSecurityPolicy** aCSP) override;
   NS_IMETHOD GetBaseDomain(nsACString& aBaseDomain) override;
   NS_IMETHOD GetAddonId(nsAString& aAddonId) override;
-  nsresult GetOriginInternal(nsACString& aOrigin) override;
 
   virtual nsresult GetScriptLocation(nsACString &aStr) override;
 
 protected:
   virtual ~SystemPrincipal(void) {}
 
   bool SubsumesInternal(nsIPrincipal *aOther,
                         DocumentDomainConsideration aConsideration) override
--- a/caps/tests/unit/test_origin.js
+++ b/caps/tests/unit/test_origin.js
@@ -295,17 +295,10 @@ function run_test() {
     Services.prefs.setBoolPref("security.fileuri.strict_origin_policy", t[0]);
     var filePrin = ssm.createCodebasePrincipal(fileURI, {});
     do_check_eq(filePrin.origin, t[1]);
   });
   Services.prefs.clearUserPref("security.fileuri.strict_origin_policy");
 
   var aboutBlankURI = makeURI('about:blank');
   var aboutBlankPrin = ssm.createCodebasePrincipal(aboutBlankURI, {});
-  var thrown = false;
-  try {
-    aboutBlankPrin.origin;
-  } catch (e) {
-    thrown = true;
-  }
-  do_check_true(thrown);
-
+  do_check_true(/^moz-nullprincipal:\{([0-9]|[a-z]|\-){36}\}$/.test(aboutBlankPrin.origin));
 }
--- a/devtools/client/shared/test/helper_inplace_editor.js
+++ b/devtools/client/shared/test/helper_inplace_editor.js
@@ -47,17 +47,17 @@ function createSpan(doc) {
   info("Creating a new span element");
   let div = doc.createElementNS(HTML_NS, "div");
   let span = doc.createElementNS(HTML_NS, "span");
   span.setAttribute("tabindex", "0");
   span.style.fontSize = "11px";
   span.style.display = "inline-block";
   span.style.width = "100px";
   span.style.border = "1px solid red";
-  span.style.fontFamily = "Courier New";
+  span.style.fontFamily = "monospace";
 
   div.style.height = "100%";
   div.style.position = "absolute";
   div.appendChild(span);
 
   let parent = doc.querySelector("window") || doc.body;
   parent.appendChild(div);
   return span;
--- a/dom/base/DocGroup.cpp
+++ b/dom/base/DocGroup.cpp
@@ -28,16 +28,17 @@ DocGroup::GetKey(nsIPrincipal* aPrincipa
   }
 
   return rv;
 }
 
 void
 DocGroup::RemoveDocument(nsIDocument* aDocument)
 {
+  MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mDocuments.Contains(aDocument));
   mDocuments.RemoveElement(aDocument);
 }
 
 DocGroup::DocGroup(TabGroup* aTabGroup, const nsACString& aKey)
   : mKey(aKey), mTabGroup(aTabGroup)
 {
   // This method does not add itself to mTabGroup->mDocGroups as the caller does it for us.
--- a/dom/base/DocGroup.h
+++ b/dom/base/DocGroup.h
@@ -55,31 +55,34 @@ public:
     return aKey == mKey;
   }
   TabGroup* GetTabGroup()
   {
     return mTabGroup;
   }
   mozilla::dom::CustomElementReactionsStack* CustomElementReactionsStack()
   {
+    MOZ_ASSERT(NS_IsMainThread());
     if (!mReactionsStack) {
       mReactionsStack = new mozilla::dom::CustomElementReactionsStack();
     }
 
     return mReactionsStack;
   }
   void RemoveDocument(nsIDocument* aWindow);
 
   // Iterators for iterating over every document within the DocGroup
   Iterator begin()
   {
+    MOZ_ASSERT(NS_IsMainThread());
     return mDocuments.begin();
   }
   Iterator end()
   {
+    MOZ_ASSERT(NS_IsMainThread());
     return mDocuments.end();
   }
 
   virtual nsresult Dispatch(const char* aName,
                             TaskCategory aCategory,
                             already_AddRefed<nsIRunnable>&& aRunnable) override;
 
   virtual nsIEventTarget* EventTargetFor(TaskCategory aCategory) const override;
--- a/dom/base/TabGroup.cpp
+++ b/dom/base/TabGroup.cpp
@@ -121,16 +121,17 @@ TabGroup::GetDocGroup(const nsACString& 
 {
   RefPtr<DocGroup> docGroup(mDocGroups.GetEntry(aKey)->mDocGroup);
   return docGroup.forget();
 }
 
 already_AddRefed<DocGroup>
 TabGroup::AddDocument(const nsACString& aKey, nsIDocument* aDocument)
 {
+  MOZ_ASSERT(NS_IsMainThread());
   HashEntry* entry = mDocGroups.PutEntry(aKey);
   RefPtr<DocGroup> docGroup;
   if (entry->mDocGroup) {
     docGroup = entry->mDocGroup;
   } else {
     docGroup = new DocGroup(this, aKey);
     entry->mDocGroup = docGroup;
   }
@@ -141,29 +142,31 @@ TabGroup::AddDocument(const nsACString& 
   docGroup->mDocuments.AppendElement(aDocument);
 
   return docGroup.forget();
 }
 
 /* static */ already_AddRefed<TabGroup>
 TabGroup::Join(nsPIDOMWindowOuter* aWindow, TabGroup* aTabGroup)
 {
+  MOZ_ASSERT(NS_IsMainThread());
   RefPtr<TabGroup> tabGroup = aTabGroup;
   if (!tabGroup) {
     tabGroup = new TabGroup();
   }
   MOZ_RELEASE_ASSERT(!tabGroup->mLastWindowLeft);
   MOZ_ASSERT(!tabGroup->mWindows.Contains(aWindow));
   tabGroup->mWindows.AppendElement(aWindow);
   return tabGroup.forget();
 }
 
 void
 TabGroup::Leave(nsPIDOMWindowOuter* aWindow)
 {
+  MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mWindows.Contains(aWindow));
   mWindows.RemoveElement(aWindow);
 
   // The Chrome TabGroup doesn't have cyclical references through mEventTargets
   // to itself, meaning that we don't have to worry about nulling mEventTargets
   // out after the last window leaves.
   if (!mIsChrome && mWindows.IsEmpty()) {
     mLastWindowLeft = true;
@@ -172,16 +175,17 @@ TabGroup::Leave(nsPIDOMWindowOuter* aWin
 }
 
 nsresult
 TabGroup::FindItemWithName(const nsAString& aName,
                            nsIDocShellTreeItem* aRequestor,
                            nsIDocShellTreeItem* aOriginalRequestor,
                            nsIDocShellTreeItem** aFoundItem)
 {
+  MOZ_ASSERT(NS_IsMainThread());
   NS_ENSURE_ARG_POINTER(aFoundItem);
   *aFoundItem = nullptr;
 
   MOZ_ASSERT(!aName.LowerCaseEqualsLiteral("_blank") &&
              !aName.LowerCaseEqualsLiteral("_top") &&
              !aName.LowerCaseEqualsLiteral("_parent") &&
              !aName.LowerCaseEqualsLiteral("_self"));
 
@@ -209,16 +213,17 @@ TabGroup::FindItemWithName(const nsAStri
   }
 
   return NS_OK;
 }
 
 nsTArray<nsPIDOMWindowOuter*>
 TabGroup::GetTopLevelWindows()
 {
+  MOZ_ASSERT(NS_IsMainThread());
   nsTArray<nsPIDOMWindowOuter*> array;
 
   for (nsPIDOMWindowOuter* outerWindow : mWindows) {
     if (outerWindow->GetDocShell() &&
         !outerWindow->GetScriptableParentOrNull()) {
       array.AppendElement(outerWindow);
     }
   }
--- a/dom/base/WebSocket.cpp
+++ b/dom/base/WebSocket.cpp
@@ -1629,23 +1629,22 @@ WebSocketImpl::Init(JSContext* aCx,
       nsCOMPtr<nsIGlobalObject> globalObject(GetEntryGlobal());
       if (globalObject) {
         principal = globalObject->PrincipalOrNull();
       }
 
       nsCOMPtr<nsPIDOMWindowInner> innerWindow;
 
       while (true) {
-        bool isNullPrincipal = true;
         if (principal) {
+          bool isNullPrincipal = true;
           isNullPrincipal = principal->GetIsNullPrincipal();
-        }
-
-        if (!isNullPrincipal) {
-          break;
+          if (isNullPrincipal || nsContentUtils::IsSystemPrincipal(principal)) {
+            break;
+          }
         }
 
         if (!innerWindow) {
           innerWindow = do_QueryInterface(globalObject);
           if (NS_WARN_IF(!innerWindow)) {
             return NS_ERROR_DOM_SECURITY_ERR;
           }
         }
--- a/dom/base/nsFrameMessageManager.cpp
+++ b/dom/base/nsFrameMessageManager.cpp
@@ -658,23 +658,35 @@ nsFrameMessageManager::SendMessage(const
 
   JS::Rooted<JSObject*> objects(aCx);
   if (aArgc >= 3 && aObjects.isObject()) {
     objects = &aObjects.toObject();
   }
 
   nsTArray<StructuredCloneData> retval;
 
+  TimeStamp start = TimeStamp::Now();
   sSendingSyncMessage |= aIsSync;
   bool ok = mCallback->DoSendBlockingMessage(aCx, aMessageName, data, objects,
                                              aPrincipal, &retval, aIsSync);
   if (aIsSync) {
     sSendingSyncMessage = false;
   }
 
+  uint32_t latencyMs = round((TimeStamp::Now() - start).ToMilliseconds());
+  if (latencyMs >= kMinTelemetrySyncMessageManagerLatencyMs) {
+    NS_ConvertUTF16toUTF8 messageName(aMessageName);
+    // NOTE: We need to strip digit characters from the message name in order to
+    // avoid a large number of buckets due to generated names from addons (such
+    // as "ublock:sb:{N}"). See bug 1348113 comment 10.
+    messageName.StripChars("0123456789");
+    Telemetry::Accumulate(Telemetry::IPC_SYNC_MESSAGE_MANAGER_LATENCY_MS,
+                          messageName, latencyMs);
+  }
+
   if (!ok) {
     return NS_OK;
   }
 
   uint32_t len = retval.Length();
   JS::Rooted<JSObject*> dataArray(aCx, JS_NewArrayObject(aCx, len));
   NS_ENSURE_TRUE(dataArray, NS_ERROR_OUT_OF_MEMORY);
 
--- a/dom/base/nsFrameMessageManager.h
+++ b/dom/base/nsFrameMessageManager.h
@@ -39,16 +39,20 @@ namespace dom {
 
 class nsIContentParent;
 class nsIContentChild;
 class ClonedMessageData;
 class MessageManagerReporter;
 
 namespace ipc {
 
+// Note: we round the time we spend to the nearest millisecond. So a min value
+// of 1 ms actually captures from 500us and above.
+static const uint32_t kMinTelemetrySyncMessageManagerLatencyMs = 1;
+
 enum MessageManagerFlags {
   MM_CHILD = 0,
   MM_CHROME = 1,
   MM_GLOBAL = 2,
   MM_PROCESSMANAGER = 4,
   MM_BROADCASTER = 8,
   MM_OWNSCALLBACK = 16
 };
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -2546,22 +2546,21 @@ nsGlobalWindow::SetInitialPrincipalToSub
     if (!mDoc->IsInitialDocument())
       return;
     // (b) already has the correct principal.
     if (mDoc->NodePrincipal() == newWindowPrincipal)
       return;
 
 #ifdef DEBUG
     // If we have a document loaded at this point, it had better be about:blank.
-    // Otherwise, something is really weird.
-    nsCOMPtr<nsIURI> uri;
-    mDoc->NodePrincipal()->GetURI(getter_AddRefs(uri));
-    NS_ASSERTION(uri && NS_IsAboutBlank(uri) &&
-                 NS_IsAboutBlank(mDoc->GetDocumentURI()),
-                 "Unexpected original document");
+    // Otherwise, something is really weird. An about:blank page has a
+    // NullPrincipal.
+    bool isNullPrincipal;
+    MOZ_ASSERT(NS_SUCCEEDED(mDoc->NodePrincipal()->GetIsNullPrincipal(&isNullPrincipal)) &&
+               isNullPrincipal);
 #endif
   }
 
   GetDocShell()->CreateAboutBlankContentViewer(newWindowPrincipal);
   mDoc->SetIsInitialDocument(true);
 
   nsCOMPtr<nsIPresShell> shell = GetDocShell()->GetPresShell();
 
--- a/dom/events/DataTransfer.cpp
+++ b/dom/events/DataTransfer.cpp
@@ -941,17 +941,24 @@ DataTransfer::GetTransferable(uint32_t a
   }
   transferable->Init(aLoadContext);
 
   nsCOMPtr<nsIStorageStream> storageStream;
   nsCOMPtr<nsIBinaryOutputStream> stream;
 
   bool added = false;
   bool handlingCustomFormats = true;
-  uint32_t totalCustomLength = 0;
+
+  // When writing the custom data, we need to ensure that there is sufficient
+  // space for a (uint32_t) data ending type, and the null byte character at
+  // the end of the nsCString. We claim that space upfront and store it in
+  // baseLength. This value will be set to zero if a write error occurs
+  // indicating that the data and length are no longer valid.
+  const uint32_t baseLength = sizeof(uint32_t) + 1;
+  uint32_t totalCustomLength = baseLength;
 
   const char* knownFormats[] = {
     kTextMime, kHTMLMime, kNativeHTMLMime, kRTFMime,
     kURLMime, kURLDataMime, kURLDescriptionMime, kURLPrivateMime,
     kPNGImageMime, kJPEGImageMime, kGIFImageMime, kNativeImageMime,
     kFileMime, kFilePromiseMime, kFilePromiseURLMime,
     kFilePromiseDestFilename, kFilePromiseDirectoryMime,
     kMozTextInternal, kHTMLContext, kHTMLInfo };
@@ -1003,18 +1010,19 @@ DataTransfer::GetTransferable(uint32_t a
 
       if (handlingCustomFormats) {
         if (!ConvertFromVariant(variant, getter_AddRefs(convertedData),
                                 &lengthInBytes)) {
           continue;
         }
 
         // When handling custom types, add the data to the stream if this is a
-        // custom type.
-        if (isCustomFormat) {
+        // custom type. If totalCustomLength is 0, then a write error occurred
+        // on a previous item, so ignore any others.
+        if (isCustomFormat && totalCustomLength > 0) {
           // If it isn't a string, just ignore it. The dataTransfer is cached in
           // the drag sesion during drag-and-drop, so non-strings will be
           // available when dragging locally.
           nsCOMPtr<nsISupportsString> str(do_QueryInterface(convertedData));
           if (str) {
             nsAutoString data;
             str->GetData(data);
 
@@ -1024,69 +1032,102 @@ DataTransfer::GetTransferable(uint32_t a
 
               nsCOMPtr<nsIOutputStream> outputStream;
               storageStream->GetOutputStream(0, getter_AddRefs(outputStream));
 
               stream = do_CreateInstance("@mozilla.org/binaryoutputstream;1");
               stream->SetOutputStream(outputStream);
             }
 
-            int32_t formatLength = type.Length() * sizeof(nsString::char_type);
-
-            stream->Write32(eCustomClipboardTypeId_String);
-            stream->Write32(formatLength);
-            stream->WriteBytes((const char *)type.get(),
-                               formatLength);
-            stream->Write32(lengthInBytes);
-            stream->WriteBytes((const char *)data.get(), lengthInBytes);
+            CheckedInt<uint32_t> formatLength =
+              CheckedInt<uint32_t>(type.Length()) * sizeof(nsString::char_type);
 
             // The total size of the stream is the format length, the data
-            // length, two integers to hold the lengths and one integer for the
-            // string flag.
-            totalCustomLength +=
-              formatLength + lengthInBytes + (sizeof(uint32_t) * 3);
+            // length, two integers to hold the lengths and one integer for
+            // the string flag. Guard against large data by ignoring any that
+            // don't fit.
+            CheckedInt<uint32_t> newSize = formatLength + totalCustomLength +
+                                           lengthInBytes + (sizeof(uint32_t) * 3);
+            if (newSize.isValid()) {
+              // If a write error occurs, set totalCustomLength to 0 so that
+              // further processing gets ignored.
+              nsresult rv = stream->Write32(eCustomClipboardTypeId_String);
+              if (NS_WARN_IF(NS_FAILED(rv))) {
+                totalCustomLength = 0;
+                continue;
+              }
+              rv = stream->Write32(formatLength.value());
+              if (NS_WARN_IF(NS_FAILED(rv))) {
+                totalCustomLength = 0;
+                continue;
+              }
+              rv = stream->WriteBytes((const char *)type.get(), formatLength.value());
+              if (NS_WARN_IF(NS_FAILED(rv))) {
+                totalCustomLength = 0;
+                continue;
+              }
+              rv = stream->Write32(lengthInBytes);
+              if (NS_WARN_IF(NS_FAILED(rv))) {
+                totalCustomLength = 0;
+                continue;
+              }
+              rv = stream->WriteBytes((const char *)data.get(), lengthInBytes);
+              if (NS_WARN_IF(NS_FAILED(rv))) {
+                totalCustomLength = 0;
+                continue;
+              }
+
+              totalCustomLength = newSize.value();
+            }
           }
         }
       } else if (isCustomFormat && stream) {
         // This is the second pass of the loop (handlingCustomFormats is false).
         // When encountering the first custom format, append all of the stream
-        // at this position.
-
-        // Write out a terminator.
-        totalCustomLength += sizeof(uint32_t);
-        stream->Write32(eCustomClipboardTypeId_None);
+        // at this position. If totalCustomLength is 0 indicating a write error
+        // occurred, or no data has been added to it, don't output anything,
+        if (totalCustomLength > baseLength) {
+          // Write out an end of data terminator.
+          nsresult rv = stream->Write32(eCustomClipboardTypeId_None);
+          if (NS_SUCCEEDED(rv)) {
+            nsCOMPtr<nsIInputStream> inputStream;
+            storageStream->NewInputStream(0, getter_AddRefs(inputStream));
 
-        nsCOMPtr<nsIInputStream> inputStream;
-        storageStream->NewInputStream(0, getter_AddRefs(inputStream));
+            RefPtr<nsStringBuffer> stringBuffer =
+              nsStringBuffer::Alloc(totalCustomLength);
 
-        RefPtr<nsStringBuffer> stringBuffer =
-          nsStringBuffer::Alloc(totalCustomLength + 1);
+            // Subtract off the null terminator when reading.
+            totalCustomLength--;
 
-        // Read the data from the string and add a null-terminator as ToString
-        // needs it.
-        uint32_t amountRead;
-        inputStream->Read(static_cast<char*>(stringBuffer->Data()),
-                          totalCustomLength, &amountRead);
-        static_cast<char*>(stringBuffer->Data())[amountRead] = 0;
+            // Read the data from the stream and add a null-terminator as
+            // ToString needs it.
+            uint32_t amountRead;
+            rv = inputStream->Read(static_cast<char*>(stringBuffer->Data()),
+                              totalCustomLength, &amountRead);
+            if (NS_SUCCEEDED(rv)) {
+              static_cast<char*>(stringBuffer->Data())[amountRead] = 0;
 
-        nsCString str;
-        stringBuffer->ToString(totalCustomLength, str);
-        nsCOMPtr<nsISupportsCString>
-          strSupports(do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID));
-        strSupports->SetData(str);
+              nsCString str;
+              stringBuffer->ToString(totalCustomLength, str);
+              nsCOMPtr<nsISupportsCString>
+                strSupports(do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID));
+              strSupports->SetData(str);
 
-        nsresult rv = transferable->SetTransferData(kCustomTypesMime,
-                                                    strSupports,
-                                                    totalCustomLength);
-        if (NS_FAILED(rv)) {
-          return nullptr;
+              nsresult rv = transferable->SetTransferData(kCustomTypesMime,
+                                                          strSupports,
+                                                          totalCustomLength);
+              if (NS_FAILED(rv)) {
+                return nullptr;
+              }
+
+              added = true;
+            }
+          }
         }
 
-        added = true;
-
         // Clear the stream so it doesn't get used again.
         stream = nullptr;
       } else {
         // This is the second pass of the loop and a known type is encountered.
         // Add it as is.
         if (!ConvertFromVariant(variant, getter_AddRefs(convertedData),
                                 &lengthInBytes)) {
           continue;
--- a/dom/events/test/test_continuous_wheel_events.html
+++ b/dom/events/test/test_continuous_wheel_events.html
@@ -4,17 +4,17 @@
   <title>Test for D3E WheelEvent</title>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
   <script type="application/javascript" src="/tests/SimpleTest/paint_listener.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 </head>
 <body>
 <p id="display"></p>
-<div id="scrollable" style="font-family:'Courier New'; font-size: 18px; line-height: 1; overflow: auto; width: 200px; height: 200px;">
+<div id="scrollable" style="font-family:monospace; font-size: 18px; line-height: 1; overflow: auto; width: 200px; height: 200px;">
   <div id="scrolled" style="font-size: 64px; width: 5000px; height: 5000px;">
     Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
     Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
     Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
     Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
     Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
     Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
     Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
@@ -39,17 +39,16 @@
     Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
   </div>
 </div>
 <div id="content" style="display: none">
 
 </div>
 <pre id="test">
 <script type="application/javascript">
-"use strict";
 
 SimpleTest.waitForExplicitFinish();
 SimpleTest.waitForFocus(runTests, window);
 
 var gScrollableElement = document.getElementById("scrollable");
 var gScrolledElement = document.getElementById("scrolled");
 
 var gLineHeight = 0;
--- a/dom/security/test/unit/test_isOriginPotentiallyTrustworthy.js
+++ b/dom/security/test/unit/test_isOriginPotentiallyTrustworthy.js
@@ -25,21 +25,19 @@ prefs.setCharPref("dom.securecontext.whi
 add_task(function* test_isOriginPotentiallyTrustworthy() {
   for (let [uriSpec, expectedResult] of [
     ["http://example.com/", false],
     ["https://example.com/", true],
     ["http://localhost/", true],
     ["http://127.0.0.1/", true],
     ["file:///", true],
     ["resource:///", true],
-    ["app://", true],
     ["moz-extension://", true],
     ["wss://example.com/", true],
     ["about:config", false],
-    ["urn:generic", false],
     ["http://example.net/", true],
     ["ws://example.org/", true],
     ["chrome://example.net/content/messenger.xul", false],
   ]) {
     let uri = NetUtil.newURI(uriSpec);
     let principal = gScriptSecurityManager.getCodebasePrincipal(uri);
     Assert.equal(gContentSecurityManager.isOriginPotentiallyTrustworthy(principal),
                  expectedResult);
--- a/dom/tests/mochitest/chrome/queryCaretRectWin.html
+++ b/dom/tests/mochitest/chrome/queryCaretRectWin.html
@@ -15,17 +15,17 @@
 -->
 
 <style>
   #text {
   position: absolute;
   left: 0em;
   top: 0em;
   font-size: 10pt;
-  font-family: 'Courier New';
+  font-family: monospace;
   line-height: 20px;
   letter-spacing: 0px;
   margin-top:-1px; /* nix the text area border */
   overflow: hidden;
   width:800px;
   height:400px;
   }
   #div-hor {
--- a/dom/tests/mochitest/chrome/selectAtPoint.html
+++ b/dom/tests/mochitest/chrome/selectAtPoint.html
@@ -1,18 +1,16 @@
 <!DOCTYPE HTML>
 <html>
 <head>
 <title>nsIDOMWindowUtils::selectAtPoint test</title>
 <script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
 <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
 
-<script>
-  "use strict";
-
+<script type="application/javascript">
   var SimpleTest = window.opener.SimpleTest;
   var Ci = Components.interfaces;
 
   function ok() { window.opener.ok.apply(window.opener, arguments); }
   function done() { window.opener.done.apply(window.opener, arguments); }
 
   function dumpLn() {
     for (let idx = 0; idx < arguments.length; idx++)
@@ -124,17 +122,23 @@
 
     // Separate character blocks in a word 't(te)s(ts)election1'
     targetPoint = { xPos: rect.left + (charDims.width + (charDims.width / 2)),
                     yPos: rect.top + (charDims.height / 2) };
     setStart(dwu, targetPoint.xPos, targetPoint.yPos, Ci.nsIDOMWindowUtils.SELECT_CHARACTER);
     targetPoint = { xPos: rect.left + ((charDims.width * 4) + (charDims.width / 2)),
                     yPos: rect.top + (charDims.height / 2) };
     setEnd(dwu, targetPoint.xPos, targetPoint.yPos, Ci.nsIDOMWindowUtils.SELECT_CHARACTER);
+    if (isLinux || isMac) {
+      // XXX I think this is a bug, the right hand selection is 4.5 characters over with a
+      // monspaced font. what we want: t(te)s(ts)election1 what we get: t(te)st(se)lection1
+      checkSelection(document, "split selection", "tese");
+    } else if (isWindows) {
       checkSelection(document, "split selection", "tets");
+    }
 
     // Trying to select where there's no text, should fail but not throw
     let result = dwu.selectAtPoint(rect.left - 20, rect.top - 20, Ci.nsIDOMWindowUtils.SELECT_CHARACTER, false);
     ok(result == false, "couldn't select?");
 
     // Second div in the main page
 
     div = document.getElementById("div2");
@@ -219,17 +223,17 @@
   }
 
   window.addEventListener("MozAfterPaint", onPaint);
 </script>
 
 <style type="text/css">
 
 body {
-  font-family: 'Courier New';
+  font-family: monospace;
   margin-left: 40px;
   margin-top: 40px;
   padding: 0;
 }
 
 #div1 {
   border: 1px solid red;
   width: 400px;
@@ -258,17 +262,17 @@ body {
 </style>
 </head>
 <body id="body" onload="onPageLoad();">
 
 <div id="div1">ttestselection1 Lorem ipsum dolor sit amet, at duo debet graeci, vivendum vulputate per ut. Ne labore incorrupte vix. Cu copiosae postulant tincidunt ius, in illud appetere contentiones eos. Ei munere officiis assentior pro, nibh decore ius at.</div>
 
 <br />
 
-<iframe id="frame1" src="data:text/html,<html><body style='margin: 0; padding: 0; font-family: \'Courier New\';' onload='window.parent.onFrameLoad();'><div id='sel2'>ttestselection2 Lorem ipsum dolor sit amet, at duo debet graeci, vivendum vulputate per ut.</div><br/><br/></body></html>"></iframe>
+<iframe id="frame1" src="data:text/html,<html><body style='margin: 0; padding: 0; font-family: monospace;' onload='window.parent.onFrameLoad();'><div id='sel2'>ttestselection2 Lorem ipsum dolor sit amet, at duo debet graeci, vivendum vulputate per ut.</div><br/><br/></body></html>"></iframe>
 
 <br/>
 
 <div id="div2">Lorem ipsum dolor sit amet, at duo debet graeci, vivendum vulputate per ut. Ne labore incorrupte vix. Cu copiosae postulant tincidunt ius, in illud appetere contentiones eos.</div>
 
 <br />
 
 <span id="measure">t</span>
--- a/editor/composer/nsEditorSpellCheck.cpp
+++ b/editor/composer/nsEditorSpellCheck.cpp
@@ -321,16 +321,21 @@ private:
 };
 
 NS_IMETHODIMP
 nsEditorSpellCheck::InitSpellChecker(nsIEditor* aEditor, bool aEnableSelectionChecking, nsIEditorSpellCheckCallback* aCallback)
 {
   NS_ENSURE_TRUE(aEditor, NS_ERROR_NULL_POINTER);
   mEditor = aEditor;
 
+  nsCOMPtr<nsIDOMDocument> domDoc;
+  mEditor->GetDocument(getter_AddRefs(domDoc));
+  nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
+  NS_ENSURE_STATE(doc);
+
   nsresult rv;
 
   // We can spell check with any editor type
   nsCOMPtr<nsITextServicesDocument>tsDoc =
      do_CreateInstance("@mozilla.org/textservices/textservicesdocument;1", &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   NS_ENSURE_TRUE(tsDoc, NS_ERROR_NULL_POINTER);
@@ -396,18 +401,18 @@ nsEditorSpellCheck::InitSpellChecker(nsI
   // do not fail if UpdateCurrentDictionary fails because this method may
   // succeed later.
   rv = UpdateCurrentDictionary(aCallback);
   if (NS_FAILED(rv) && aCallback) {
     // However, if it does fail, we still need to call the callback since we
     // discard the failure.  Do it asynchronously so that the caller is always
     // guaranteed async behavior.
     RefPtr<CallbackCaller> caller = new CallbackCaller(aCallback);
-    NS_ENSURE_STATE(caller);
-    rv = NS_DispatchToMainThread(caller);
+    rv = doc->Dispatch("nsEditorSpellCheck::CallbackCaller",
+                       TaskCategory::Other, caller.forget());
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsEditorSpellCheck::GetNextMisspelledWord(char16_t **aNextMisspelledWord)
--- a/editor/libeditor/EditorBase.cpp
+++ b/editor/libeditor/EditorBase.cpp
@@ -729,17 +729,18 @@ EditorBase::DoTransaction(nsITransaction
     // get the selection and start a batch change
     RefPtr<Selection> selection = GetSelection();
     NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
 
     selection->StartBatchChanges();
 
     nsresult rv;
     if (mTxnMgr) {
-      rv = mTxnMgr->DoTransaction(aTxn);
+      RefPtr<nsTransactionManager> txnMgr = mTxnMgr;
+      rv = txnMgr->DoTransaction(aTxn);
     } else {
       rv = aTxn->DoTransaction();
     }
     if (NS_SUCCEEDED(rv)) {
       DoAfterDoTransaction(aTxn);
     }
 
     // no need to check rv here, don't lose result of operation
@@ -804,18 +805,19 @@ EditorBase::Undo(uint32_t aCount)
   NS_ENSURE_TRUE(hasTransaction, NS_OK);
 
   AutoRules beginRulesSniffing(this, EditAction::undo, nsIEditor::eNone);
 
   if (!mTxnMgr) {
     return NS_OK;
   }
 
+  RefPtr<nsTransactionManager> txnMgr = mTxnMgr;
   for (uint32_t i = 0; i < aCount; ++i) {
-    nsresult rv = mTxnMgr->UndoTransaction();
+    nsresult rv = txnMgr->UndoTransaction();
     NS_ENSURE_SUCCESS(rv, rv);
 
     DoAfterUndoTransaction();
   }
 
   return NS_OK;
 }
 
@@ -843,18 +845,19 @@ EditorBase::Redo(uint32_t aCount)
   NS_ENSURE_TRUE(hasTransaction, NS_OK);
 
   AutoRules beginRulesSniffing(this, EditAction::redo, nsIEditor::eNone);
 
   if (!mTxnMgr) {
     return NS_OK;
   }
 
+  RefPtr<nsTransactionManager> txnMgr = mTxnMgr;
   for (uint32_t i = 0; i < aCount; ++i) {
-    nsresult rv = mTxnMgr->RedoTransaction();
+    nsresult rv = txnMgr->RedoTransaction();
     NS_ENSURE_SUCCESS(rv, rv);
 
     DoAfterRedoTransaction();
   }
 
   return NS_OK;
 }
 
@@ -875,27 +878,29 @@ EditorBase::CanRedo(bool* aIsEnabled, bo
 }
 
 NS_IMETHODIMP
 EditorBase::BeginTransaction()
 {
   BeginUpdateViewBatch();
 
   if (mTxnMgr) {
-    mTxnMgr->BeginBatch(nullptr);
+    RefPtr<nsTransactionManager> txnMgr = mTxnMgr;
+    txnMgr->BeginBatch(nullptr);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 EditorBase::EndTransaction()
 {
   if (mTxnMgr) {
-    mTxnMgr->EndBatch(false);
+    RefPtr<nsTransactionManager> txnMgr = mTxnMgr;
+    txnMgr->EndBatch(false);
   }
 
   EndUpdateViewBatch();
 
   return NS_OK;
 }
 
 
--- a/gfx/config/gfxVars.h
+++ b/gfx/config/gfxVars.h
@@ -30,16 +30,19 @@ class gfxVarReceiver;
   _(UseXRender,                 bool,             false)                \
   _(OffscreenFormat,            gfxImageFormat,   mozilla::gfx::SurfaceFormat::X8R8G8B8_UINT32) \
   _(RequiresAcceleratedGLContextForCompositorOGL, bool, false)          \
   _(CanUseHardwareVideoDecoding, bool,            false)                \
   _(PDMWMFDisableD3D11Dlls,     nsCString,        nsCString())          \
   _(PDMWMFDisableD3D9Dlls,      nsCString,        nsCString())          \
   _(DXInterop2Blocked,          bool,             false)                \
   _(UseWebRender,               bool,             false)                \
+  _(UseWebRenderANGLE,          bool,             false)                \
+  _(ScreenDepth,                int32_t,          0)                    \
+  _(GREDirectory,               nsCString,        nsCString())          \
 
   /* Add new entries above this line. */
 
 // Some graphics settings are computed on the UI process and must be
 // communicated to content and GPU processes. gfxVars helps facilitate
 // this. Its function is similar to gfxPrefs, except rather than hold
 // user preferences, it holds dynamically computed values.
 //
--- a/gfx/doc/README.webrender
+++ b/gfx/doc/README.webrender
@@ -74,9 +74,9 @@ there is another crate in m-c called moz
 the same folder to store its rust dependencies. If one of the libraries that is
 required by both mozjs_sys and webrender is updated without updating the other
 project's Cargo.lock file, that results in build bustage.
 This means that any time you do this sort of manual update of packages, you need
 to make sure that mozjs_sys also has its Cargo.lock file updated if needed, hence
 the need to run the cargo update command in js/src as well. Hopefully this will
 be resolved soon.
 
-Latest Commit: 0794911f97cae92496fca992d7430da696fa24eb
+Latest Commit: dafe3579e8dc886e6584116dc52a9362b543c169
--- a/gfx/gl/GLContextProviderEGL.cpp
+++ b/gfx/gl/GLContextProviderEGL.cpp
@@ -6,32 +6,36 @@
 #if defined(MOZ_WIDGET_GTK)
     #include <gdk/gdkx.h>
     // we're using default display for now
     #define GET_NATIVE_WINDOW_FROM_REAL_WIDGET(aWidget) ((EGLNativeWindowType)GDK_WINDOW_XID((GdkWindow*)aWidget->GetNativeData(NS_NATIVE_WINDOW)))
     #define GET_NATIVE_WINDOW_FROM_COMPOSITOR_WIDGET(aWidget) ((EGLNativeWindowType)GDK_WINDOW_XID((GdkWindow*)aWidget->RealWidget()->GetNativeData(NS_NATIVE_WINDOW)))
 #elif defined(MOZ_WIDGET_ANDROID)
     #define GET_NATIVE_WINDOW_FROM_REAL_WIDGET(aWidget) ((EGLNativeWindowType)aWidget->GetNativeData(NS_JAVA_SURFACE))
     #define GET_NATIVE_WINDOW_FROM_COMPOSITOR_WIDGET(aWidget) (aWidget->AsAndroid()->GetEGLNativeWindow())
+#elif defined(XP_WIN)
+    #define GET_NATIVE_WINDOW_FROM_REAL_WIDGET(aWidget) ((EGLNativeWindowType)aWidget->GetNativeData(NS_NATIVE_WINDOW))
+    #define GET_NATIVE_WINDOW_FROM_COMPOSITOR_WIDGET(aWidget) ((EGLNativeWindowType)aWidget->AsWindows()->GetHwnd())
 #else
     #define GET_NATIVE_WINDOW_FROM_REAL_WIDGET(aWidget) ((EGLNativeWindowType)aWidget->GetNativeData(NS_NATIVE_WINDOW))
     #define GET_NATIVE_WINDOW_FROM_COMPOSITOR_WIDGET(aWidget) ((EGLNativeWindowType)aWidget->RealWidget()->GetNativeData(NS_NATIVE_WINDOW))
 #endif
 
 #if defined(XP_UNIX)
     #ifdef MOZ_WIDGET_ANDROID
         #include <android/native_window.h>
         #include <android/native_window_jni.h>
         #include "mozilla/widget/AndroidCompositorWidget.h"
     #endif
 
     #define GLES2_LIB "libGLESv2.so"
     #define GLES2_LIB2 "libGLESv2.so.2"
 
 #elif defined(XP_WIN)
+    #include "mozilla/widget/WinCompositorWidget.h"
     #include "nsIFile.h"
 
     #define GLES2_LIB "libGLESv2.dll"
 
     #ifndef WIN32_LEAN_AND_MEAN
         #define WIN32_LEAN_AND_MEAN 1
     #endif
 
@@ -46,16 +50,17 @@
 #include "gfxPlatform.h"
 #include "gfxUtils.h"
 #include "GLBlitHelper.h"
 #include "GLContextEGL.h"
 #include "GLContextProvider.h"
 #include "GLLibraryEGL.h"
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Preferences.h"
+#include "mozilla/gfx/gfxVars.h"
 #include "mozilla/layers/CompositorOptions.h"
 #include "mozilla/widget/CompositorWidget.h"
 #include "nsDebug.h"
 #include "nsIWidget.h"
 #include "nsThreadUtils.h"
 #include "ScopedGLHelpers.h"
 #include "TextureImageEGL.h"
 
@@ -688,17 +693,17 @@ CreateConfig(EGLConfig* aConfig, int32_t
 // Return true if a suitable EGLConfig was found and pass it out
 // through aConfig.  Return false otherwise.
 //
 // NB: It's entirely legal for the returned EGLConfig to be valid yet
 // have the value null.
 static bool
 CreateConfig(EGLConfig* aConfig)
 {
-    int32_t depth = gfxPlatform::GetPlatform()->GetScreenDepth();
+    int32_t depth = gfxVars::ScreenDepth();
     if (!CreateConfig(aConfig, depth)) {
 #ifdef MOZ_WIDGET_ANDROID
         // Bug 736005
         // Android doesn't always support 16 bit so also try 24 bit
         if (depth == 16) {
             return CreateConfig(aConfig, 24);
         }
         // Bug 970096
--- a/gfx/gl/GLLibraryEGL.cpp
+++ b/gfx/gl/GLLibraryEGL.cpp
@@ -19,16 +19,17 @@
 #include "nsDirectoryServiceUtils.h"
 #include "nsIGfxInfo.h"
 #include "nsPrintfCString.h"
 #ifdef XP_WIN
 #include "nsWindowsHelpers.h"
 #endif
 #include "OGLShaderProgram.h"
 #include "prenv.h"
+#include "prsystem.h"
 #include "GLContext.h"
 #include "GLContextProvider.h"
 #include "gfxPrefs.h"
 #include "ScopedGLHelpers.h"
 
 namespace mozilla {
 namespace gl {
 
@@ -96,30 +97,24 @@ static PRLibrary* LoadApitraceLibrary()
 
 #endif // ANDROID
 
 #ifdef XP_WIN
 // see the comment in GLLibraryEGL::EnsureInitialized() for the rationale here.
 static PRLibrary*
 LoadLibraryForEGLOnWindows(const nsAString& filename)
 {
-    nsCOMPtr<nsIFile> file;
-    nsresult rv = NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(file));
-    if (NS_FAILED(rv))
-        return nullptr;
+    nsAutoCString path(gfx::gfxVars::GREDirectory());
+    path.Append(PR_GetDirectorySeparator());
+    path.Append(ToNewUTF8String(filename));
 
-    file->Append(filename);
-    PRLibrary* lib = nullptr;
-    rv = file->Load(&lib);
-    if (NS_FAILED(rv)) {
-        nsPrintfCString msg("Failed to load %s - Expect EGL initialization to fail",
-                            NS_LossyConvertUTF16toASCII(filename).get());
-        NS_WARNING(msg.get());
-    }
-    return lib;
+    PRLibSpec lspec;
+    lspec.type = PR_LibSpec_Pathname;
+    lspec.value.pathname = path.get();
+    return PR_LoadLibraryWithFlags(lspec, PR_LD_LAZY | PR_LD_LOCAL);
 }
 
 #endif // XP_WIN
 
 static EGLDisplay
 GetAndInitWARPDisplay(GLLibraryEGL& egl, void* displayType)
 {
     EGLint attrib_list[] = {  LOCAL_EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE,
@@ -236,16 +231,20 @@ private:
 
 AngleErrorReporting gAngleErrorReporter;
 
 static EGLDisplay
 GetAndInitDisplayForAccelANGLE(GLLibraryEGL& egl, nsACString* const out_failureId)
 {
     EGLDisplay ret = 0;
 
+    if (wr::RenderThread::IsInRenderThread()) {
+        return GetAndInitDisplay(egl, LOCAL_EGL_D3D11_ONLY_DISPLAY_ANGLE);
+    }
+
     FeatureState& d3d11ANGLE = gfxConfig::GetFeature(Feature::D3D11_HW_ANGLE);
 
     if (!gfxPrefs::WebGLANGLETryD3D11())
         d3d11ANGLE.UserDisable("User disabled D3D11 ANGLE by pref",
                                NS_LITERAL_CSTRING("FAILURE_ID_ANGLE_PREF"));
 
     if (gfxPrefs::WebGLANGLEForceD3D11())
         d3d11ANGLE.UserForceEnable("User force-enabled D3D11 ANGLE on disabled hardware");
--- a/gfx/ipc/GraphicsMessages.ipdlh
+++ b/gfx/ipc/GraphicsMessages.ipdlh
@@ -68,16 +68,17 @@ struct GPUDeviceData
 
 union GfxVarValue
 {
   BackendType;
   bool;
   gfxImageFormat;
   IntSize;
   nsCString;
+  int32_t;
 };
 
 struct GfxVarUpdate
 {
   size_t index;
   GfxVarValue value;
 };
 
--- a/gfx/layers/Layers.cpp
+++ b/gfx/layers/Layers.cpp
@@ -2439,16 +2439,32 @@ LayerManager::DumpPacket(layerscope::Lay
   // Add a new layer data (LayerManager)
   LayersPacket::Layer* layer = aPacket->add_layer();
   layer->set_type(LayersPacket::Layer::LayerManager);
   layer->set_ptr(reinterpret_cast<uint64_t>(this));
   // Layer Tree Root
   layer->set_parentptr(0);
 }
 
+void
+LayerManager::TrackDisplayItemLayer(RefPtr<DisplayItemLayer> aLayer)
+{
+  mDisplayItemLayers.AppendElement(aLayer);
+}
+
+void
+LayerManager::ClearDisplayItemLayers()
+{
+  for (uint32_t i = 0; i < mDisplayItemLayers.Length(); i++) {
+    mDisplayItemLayers[i]->EndTransaction();
+  }
+
+  mDisplayItemLayers.Clear();
+}
+
 /*static*/ bool
 LayerManager::IsLogEnabled()
 {
   return MOZ_LOG_TEST(GetLog(), LogLevel::Debug);
 }
 
 void
 LayerManager::SetPendingScrollUpdateForNextTransaction(FrameMetrics::ViewID aScrollId,
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -458,16 +458,25 @@ public:
    * layer transactions on the main thread or asynchronously using the ImageBridge IPDL protocol.
    * In the case of asynchronous, If the protocol is not available, the returned ImageContainer
    * will forward images within layer transactions.
    */
   static already_AddRefed<ImageContainer> CreateImageContainer(ImageContainer::Mode flag
                                                                 = ImageContainer::SYNCHRONOUS);
 
   /**
+   * Since the lifetimes of display items and display item layers are different,
+   * calling this tells the layer manager that the display item layer is valid for
+   * only one transaction. Users should call ClearDisplayItemLayers() to remove
+   * references to the dead display item at the end of a transaction.
+   */
+  virtual void TrackDisplayItemLayer(RefPtr<DisplayItemLayer> aLayer);
+  virtual void ClearDisplayItemLayers();
+
+  /**
    * Type of layer manager his is. This is to be used sparsely in order to
    * avoid a lot of Layers backend specific code. It should be used only when
    * Layers backend specific functionality is necessary.
    */
   virtual LayersBackend GetBackendType() = 0;
 
   /**
    * Type of layers backend that will be used to composite this layer tree.
@@ -770,16 +779,24 @@ public:
    * scroll position updates to the APZ code.
    */
   void SetPendingScrollUpdateForNextTransaction(FrameMetrics::ViewID aScrollId,
                                                 const ScrollUpdateInfo& aUpdateInfo);
   Maybe<ScrollUpdateInfo> GetPendingScrollInfoUpdate(FrameMetrics::ViewID aScrollId);
   void ClearPendingScrollInfoUpdate();
 private:
   std::map<FrameMetrics::ViewID,ScrollUpdateInfo> mPendingScrollUpdates;
+
+  // Display items are only valid during this transaction.
+  // At the end of the transaction, we have to go and clear out
+  // DisplayItemLayer's and null their display item. See comment
+  // above DisplayItemLayer declaration.
+  // Since layers are ref counted, we also have to stop holding
+  // a reference to the display item layer as well.
+  nsTArray<RefPtr<DisplayItemLayer>> mDisplayItemLayers;
 };
 
 /**
  * A Layer represents anything that can be rendered onto a destination
  * surface.
  */
 class Layer {
   NS_INLINE_DECL_REFCOUNTING(Layer)
--- a/gfx/layers/basic/BasicDisplayItemLayer.cpp
+++ b/gfx/layers/basic/BasicDisplayItemLayer.cpp
@@ -71,14 +71,13 @@ protected:
   }
 };
 
 already_AddRefed<DisplayItemLayer>
 BasicLayerManager::CreateDisplayItemLayer()
 {
   NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
   RefPtr<DisplayItemLayer> layer = new BasicDisplayItemLayer(this);
-  mDisplayItemLayers.AppendElement(layer);
   return layer.forget();
 }
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/basic/BasicLayerManager.cpp
+++ b/gfx/layers/basic/BasicLayerManager.cpp
@@ -541,28 +541,16 @@ ApplyDoubleBuffering(Layer* aLayer, cons
 void
 BasicLayerManager::EndTransaction(DrawPaintedLayerCallback aCallback,
                                   void* aCallbackData,
                                   EndTransactionFlags aFlags)
 {
   mInTransaction = false;
 
   EndTransactionInternal(aCallback, aCallbackData, aFlags);
-
-  ClearDisplayItemLayers();
-}
-
-void
-BasicLayerManager::ClearDisplayItemLayers()
-{
-  for (uint32_t i = 0; i < mDisplayItemLayers.Length(); i++) {
-    mDisplayItemLayers[i]->EndTransaction();
-  }
-
-  mDisplayItemLayers.Clear();
 }
 
 void
 BasicLayerManager::AbortTransaction()
 {
   NS_ASSERTION(InConstruction(), "Should be in construction phase");
   mPhase = PHASE_NONE;
   mUsingDefaultTarget = false;
@@ -667,16 +655,18 @@ BasicLayerManager::EndTransactionInterna
   if (!mTransactionIncomplete) {
     // This is still valid if the transaction was incomplete.
     mUsingDefaultTarget = false;
   }
 
   NS_ASSERTION(!aCallback || !mTransactionIncomplete,
                "If callback is not null, transaction must be complete");
 
+  ClearDisplayItemLayers();
+
   // XXX - We should probably assert here that for an incomplete transaction
   // out target is the default target.
 
   return !mTransactionIncomplete;
 }
 
 void
 BasicLayerManager::FlashWidgetUpdateArea(gfxContext *aContext)
--- a/gfx/layers/basic/BasicLayers.h
+++ b/gfx/layers/basic/BasicLayers.h
@@ -208,22 +208,14 @@ protected:
   // Image factory we use.
   RefPtr<ImageFactory> mFactory;
 
   BufferMode mDoubleBuffering;
   BasicLayerManagerType mType;
   bool mUsingDefaultTarget;
   bool mTransactionIncomplete;
   bool mCompositorMightResample;
-
-private:
-  // Display items are only valid during this transaction.
-  // At the end of the transaction, we have to go and clear out
-  // DisplayItemLayer's and null their display item. See comment
-  // above DisplayItemLayer declaration.
-  void ClearDisplayItemLayers();
-  nsTArray<RefPtr<DisplayItemLayer>> mDisplayItemLayers;
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif /* GFX_BASICLAYERS_H */
--- a/gfx/layers/wr/WebRenderLayerManager.cpp
+++ b/gfx/layers/wr/WebRenderLayerManager.cpp
@@ -309,16 +309,18 @@ WebRenderLayerManager::EndTransaction(Dr
 
   bool sync = mTarget != nullptr;
   mLatestTransactionId = mTransactionIdAllocator->GetTransactionId();
 
   WrBridge()->DPEnd(builder, size.ToUnknownSize(), sync, mLatestTransactionId);
 
   MakeSnapshotIfRequired(size);
 
+  ClearDisplayItemLayers();
+
   // this may result in Layers being deleted, which results in
   // PLayer::Send__delete__() and DeallocShmem()
   mKeepAlive.Clear();
 }
 
 void
 WebRenderLayerManager::MakeSnapshotIfRequired(LayoutDeviceIntSize aSize)
 {
--- a/gfx/skia/skia/src/ports/SkFontHost_cairo.cpp
+++ b/gfx/skia/skia/src/ports/SkFontHost_cairo.cpp
@@ -126,17 +126,18 @@ private:
     void resolvePattern(FcPattern* pattern);
 #endif
 
     cairo_scaled_font_t* fScaledFont;
     FT_Int32 fLoadGlyphFlags;
     FT_LcdFilter fLcdFilter;
     SkScalar fScaleX;
     SkScalar fScaleY;
-    FT_Matrix fShapeMatrix;
+    SkMatrix fShapeMatrix;
+    FT_Matrix fShapeMatrixFT;
     bool fHaveShape;
 };
 
 class CairoLockedFTFace {
 public:
     CairoLockedFTFace(cairo_scaled_font_t* scaledFont)
         : fScaledFont(scaledFont)
         , fFace(cairo_ft_scaled_font_lock_face(scaledFont))
@@ -587,22 +588,23 @@ bool SkScalerContext_CairoFT::computeSha
         fHaveShape = !m.isScaleTranslate();
     }
 
     fScaleX = SkDoubleToScalar(major);
     fScaleY = SkDoubleToScalar(minor);
 
     if (fHaveShape) {
         // Normalize the transform and convert to fixed-point.
-        double invScaleX = 65536.0 / major;
-        double invScaleY = 65536.0 / minor;
-        fShapeMatrix.xx = (FT_Fixed)(scaleX * invScaleX);
-        fShapeMatrix.yx = -(FT_Fixed)(skewY * invScaleX);
-        fShapeMatrix.xy = -(FT_Fixed)(skewX * invScaleY);
-        fShapeMatrix.yy = (FT_Fixed)(scaleY * invScaleY);
+        fShapeMatrix = m;
+        fShapeMatrix.preScale(SkDoubleToScalar(1.0 / major), SkDoubleToScalar(1.0 / minor));
+
+        fShapeMatrixFT.xx = SkScalarToFixed(fShapeMatrix.getScaleX());
+        fShapeMatrixFT.yx = SkScalarToFixed(-fShapeMatrix.getSkewY());
+        fShapeMatrixFT.xy = SkScalarToFixed(-fShapeMatrix.getSkewX());
+        fShapeMatrixFT.yy = SkScalarToFixed(fShapeMatrix.getScaleY());
     }
     return true;
 }
 
 unsigned SkScalerContext_CairoFT::generateGlyphCount()
 {
     CairoLockedFTFace faceLock(fScaledFont);
     return faceLock.getFace()->num_glyphs;
@@ -632,17 +634,17 @@ void SkScalerContext_CairoFT::prepareGly
 
 void SkScalerContext_CairoFT::fixVerticalLayoutBearing(FT_GlyphSlot glyph)
 {
     FT_Vector vector;
     vector.x = glyph->metrics.vertBearingX - glyph->metrics.horiBearingX;
     vector.y = -glyph->metrics.vertBearingY - glyph->metrics.horiBearingY;
     if (glyph->format == FT_GLYPH_FORMAT_OUTLINE) {
         if (fHaveShape) {
-            FT_Vector_Transform(&vector, &fShapeMatrix);
+            FT_Vector_Transform(&vector, &fShapeMatrixFT);
         }
         FT_Outline_Translate(&glyph->outline, vector.x, vector.y);
     } else if (glyph->format == FT_GLYPH_FORMAT_BITMAP) {
         glyph->bitmap_left += SkFDot6Floor(vector.x);
         glyph->bitmap_top  += SkFDot6Floor(vector.y);
     }
 }
 
@@ -697,27 +699,30 @@ void SkScalerContext_CairoFT::generateMe
             glyph->fMaskFormat = SkMask::kARGB32_Format;
         }
 
         if (isLCD(fRec)) {
             fRec.fMaskFormat = SkMask::kA8_Format;
         }
 
         if (fHaveShape) {
+            // Ensure filtering is preserved when the bitmap is transformed.
+            // Otherwise, the result will look horrifically aliased.
+            if (fRec.fMaskFormat == SkMask::kBW_Format) {
+                fRec.fMaskFormat = SkMask::kA8_Format;
+            }
+
             // Apply the shape matrix to the glyph's bounding box.
-            SkMatrix matrix;
-            fRec.getSingleMatrix(&matrix);
-            matrix.preScale(SkScalarInvert(fScaleX), SkScalarInvert(fScaleY));
             SkRect srcRect = SkRect::MakeXYWH(
                 SkIntToScalar(face->glyph->bitmap_left),
                 -SkIntToScalar(face->glyph->bitmap_top),
                 SkIntToScalar(face->glyph->bitmap.width),
                 SkIntToScalar(face->glyph->bitmap.rows));
             SkRect destRect;
-            matrix.mapRect(&destRect, srcRect);
+            fShapeMatrix.mapRect(&destRect, srcRect);
             SkIRect glyphRect = destRect.roundOut();
             glyph->fWidth  = SkToU16(glyphRect.width());
             glyph->fHeight = SkToU16(glyphRect.height());
             glyph->fTop    = SkToS16(SkScalarRoundToInt(destRect.fTop));
             glyph->fLeft   = SkToS16(SkScalarRoundToInt(destRect.fLeft));
         } else {
             glyph->fWidth  = SkToU16(face->glyph->bitmap.width);
             glyph->fHeight = SkToU16(face->glyph->bitmap.rows);
@@ -760,18 +765,17 @@ void SkScalerContext_CairoFT::generateIm
         gSetLcdFilter;
     if (useLcdFilter) {
         gSetLcdFilter(face->glyph->library, fLcdFilter);
     }
 
     SkMatrix matrix;
     if (face->glyph->format == FT_GLYPH_FORMAT_BITMAP &&
         fHaveShape) {
-        matrix.setScale(SkIntToScalar(glyph.fWidth) / SkIntToScalar(face->glyph->bitmap.width),
-                        SkIntToScalar(glyph.fHeight) / SkIntToScalar(face->glyph->bitmap.rows));
+        matrix = fShapeMatrix;
     } else {
         matrix.setIdentity();
     }
     generateGlyphImage(face, glyph, matrix);
 
     if (useLcdFilter) {
         gSetLcdFilter(face->glyph->library, FT_LCD_FILTER_NONE);
     }
--- a/gfx/thebes/gfxFcPlatformFontList.cpp
+++ b/gfx/thebes/gfxFcPlatformFontList.cpp
@@ -791,44 +791,70 @@ PreparePattern(FcPattern* aPattern, bool
         }
 #endif // MOZ_X11
 #endif // MOZ_WIDGET_GTK
     }
 
     FcDefaultSubstitute(aPattern);
 }
 
+static inline gfxFloat
+SizeForStyle(gfxFontconfigFontEntry* aEntry, const gfxFontStyle& aStyle)
+{
+    return aStyle.sizeAdjust >= 0.0 ?
+                aStyle.GetAdjustedSize(aEntry->GetAspect()) :
+                aStyle.size;
+}
+
+static double
+ChooseFontSize(gfxFontconfigFontEntry* aEntry,
+               const gfxFontStyle& aStyle)
+{
+    double requestedSize = SizeForStyle(aEntry, aStyle);
+    double bestDist = -1.0;
+    double bestSize = requestedSize;
+    double size;
+    int v = 0;
+    while (FcPatternGetDouble(aEntry->GetPattern(),
+                              FC_PIXEL_SIZE, v, &size) == FcResultMatch) {
+        ++v;
+        double dist = fabs(size - requestedSize);
+        if (bestDist < 0.0 || dist < bestDist) {
+            bestDist = dist;
+            bestSize = size;
+        }
+    }
+    return bestSize;
+}
+
 gfxFont*
 gfxFontconfigFontEntry::CreateFontInstance(const gfxFontStyle *aFontStyle,
                                            bool aNeedsBold)
 {
     nsAutoRef<FcPattern> pattern(FcPatternCreate());
     if (!pattern) {
         NS_WARNING("Failed to create Fontconfig pattern for font instance");
         return nullptr;
     }
-    FcPatternAddDouble(pattern, FC_PIXEL_SIZE, aFontStyle->size);
+
+    double size = ChooseFontSize(this, *aFontStyle);
+    FcPatternAddDouble(pattern, FC_PIXEL_SIZE, size);
 
     PreparePattern(pattern, aFontStyle->printerFont);
     nsAutoRef<FcPattern> renderPattern
         (FcFontRenderPrepare(nullptr, pattern, mFontPattern));
     if (!renderPattern) {
         NS_WARNING("Failed to prepare Fontconfig pattern for font instance");
         return nullptr;
     }
 
-    double adjustedSize = aFontStyle->size;
-    if (aFontStyle->sizeAdjust >= 0.0) {
-        adjustedSize = aFontStyle->GetAdjustedSize(GetAspect());
-    }
-
     cairo_scaled_font_t* scaledFont =
-        CreateScaledFont(renderPattern, adjustedSize, aFontStyle, aNeedsBold);
+        CreateScaledFont(renderPattern, size, aFontStyle, aNeedsBold);
     gfxFont* newFont =
-        new gfxFontconfigFont(scaledFont, renderPattern, adjustedSize,
+        new gfxFontconfigFont(scaledFont, renderPattern, size,
                               this, aFontStyle, aNeedsBold);
     cairo_scaled_font_destroy(scaledFont);
 
     return newFont;
 }
 
 nsresult
 gfxFontconfigFontEntry::CopyFontTable(uint32_t aTableTag,
@@ -926,20 +952,126 @@ gfxFontconfigFontFamily::FindStyleVariat
 }
 
 void
 gfxFontconfigFontFamily::AddFontPattern(FcPattern* aFontPattern)
 {
     NS_ASSERTION(!mHasStyles,
                  "font patterns must not be added to already enumerated families");
 
+    FcBool scalable;
+    if (FcPatternGetBool(aFontPattern, FC_SCALABLE, 0, &scalable) != FcResultMatch ||
+        !scalable) {
+        mHasNonScalableFaces = true;
+    }
+
     nsCountedRef<FcPattern> pattern(aFontPattern);
     mFontPatterns.AppendElement(pattern);
 }
 
+static const double kRejectDistance = 10000.0;
+
+// Calculate a distance score representing the size disparity between the
+// requested style's size and the font entry's size.
+static double
+SizeDistance(gfxFontconfigFontEntry* aEntry, const gfxFontStyle& aStyle)
+{
+    double requestedSize = SizeForStyle(aEntry, aStyle);
+    double bestDist = -1.0;
+    double size;
+    int v = 0;
+    while (FcPatternGetDouble(aEntry->GetPattern(),
+                              FC_PIXEL_SIZE, v, &size) == FcResultMatch) {
+        ++v;
+        double dist = fabs(size - requestedSize);
+        if (bestDist < 0.0 || dist < bestDist) {
+            bestDist = dist;
+        }
+    }
+    if (bestDist < 0.0) {
+        // No size means scalable
+        return -1.0;
+    } else if (5.0 * bestDist < requestedSize) {
+        // fontconfig prefers a matching family or lang to pixelsize of bitmap
+        // fonts. CSS suggests a tolerance of 20% on pixelsize.
+        return bestDist;
+    } else {
+        // Reject any non-scalable fonts that are not within tolerance.
+        return kRejectDistance;
+    }
+}
+
+void
+gfxFontconfigFontFamily::FindAllFontsForStyle(const gfxFontStyle& aFontStyle,
+                                              nsTArray<gfxFontEntry*>& aFontEntryList,
+                                              bool& aNeedsSyntheticBold)
+{
+    gfxFontFamily::FindAllFontsForStyle(aFontStyle,
+                                        aFontEntryList,
+                                        aNeedsSyntheticBold);
+
+    if (!mHasNonScalableFaces) {
+        return;
+    }
+
+    // Iterate over the the available fonts while compacting any groups
+    // of unscalable fonts with matching styles into a single entry
+    // corresponding to the closest available size. If the closest
+    // available size is rejected for being outside tolernace, then the
+    // entire group will be skipped.
+    size_t skipped = 0;
+    gfxFontconfigFontEntry* bestEntry = nullptr;
+    double bestDist = -1.0;
+    for (size_t i = 0; i < aFontEntryList.Length(); i++) {
+        gfxFontconfigFontEntry* entry =
+            static_cast<gfxFontconfigFontEntry*>(aFontEntryList[i]);
+        double dist = SizeDistance(entry, aFontStyle);
+        // If the entry is scalable or has a style that does not match
+        // the group of unscalable fonts, then start a new group.
+        if (dist < 0.0 ||
+            !bestEntry ||
+            bestEntry->Stretch() != entry->Stretch() ||
+            bestEntry->Weight() != entry->Weight() ||
+            bestEntry->mStyle != entry->mStyle) {
+            // If the best entry in this group is still outside the tolerance,
+            // then skip the entire group.
+            if (bestDist >= kRejectDistance) {
+                skipped++;
+            }
+            // Remove any compacted entries from the previous group.
+            if (skipped) {
+                i -= skipped;
+                aFontEntryList.RemoveElementsAt(i, skipped);
+                skipped = 0;
+            }
+            // Mark the start of the new group.
+            bestEntry = entry;
+            bestDist = dist;
+        } else {
+            // If this entry more closely matches the requested size than the
+            // current best in the group, then take this entry instead.
+            if (dist < bestDist) {
+                aFontEntryList[i-1-skipped] = entry;
+                bestEntry = entry;
+                bestDist = dist;
+            }
+            skipped++;
+        }
+    }
+    // If the best entry in this group is still outside the tolerance,
+    // then skip the entire group.
+    if (bestDist >= kRejectDistance) {
+        skipped++;
+    }
+    // Remove any compacted entries from the current group.
+    if (skipped) {
+        aFontEntryList.TruncateLength(aFontEntryList.Length() - skipped);
+    }
+}
+
 gfxFontconfigFont::gfxFontconfigFont(cairo_scaled_font_t *aScaledFont,
                                      FcPattern *aPattern,
                                      gfxFloat aAdjustedSize,
                                      gfxFontEntry *aFontEntry,
                                      const gfxFontStyle *aFontStyle,
                                      bool aNeedsBold) :
     gfxFontconfigFontBase(aScaledFont, aPattern, aFontEntry, aFontStyle)
 {
@@ -1001,23 +1133,16 @@ gfxFcPlatformFontList::AddFontSetFamilie
     }
 
     FcChar8* lastFamilyName = (FcChar8*)"";
     RefPtr<gfxFontconfigFontFamily> fontFamily;
     nsAutoString familyName;
     for (int f = 0; f < aFontSet->nfont; f++) {
         FcPattern* font = aFontSet->fonts[f];
 
-        // not scalable? skip...
-        FcBool scalable;
-        if (FcPatternGetBool(font, FC_SCALABLE, 0, &scalable) != FcResultMatch ||
-            !scalable) {
-            continue;
-        }
-
         // get canonical name
         uint32_t cIndex = FindCanonicalNameIndex(font, FC_FAMILYLANG);
         FcChar8* canonical = nullptr;
         FcPatternGetString(font, FC_FAMILY, cIndex, &canonical);
         if (!canonical) {
             continue;
         }
 
@@ -1121,19 +1246,16 @@ GetSystemFontList(nsTArray<nsString>& aL
     // add the lang to the pattern
     nsAutoCString fcLang;
     gfxFcPlatformFontList* pfl = gfxFcPlatformFontList::PlatformFontList();
     pfl->GetSampleLangForGroup(aLangGroup, fcLang);
     if (!fcLang.IsEmpty()) {
         FcPatternAddString(pat, FC_LANG, ToFcChar8Ptr(fcLang.get()));
     }
 
-    // ignore size-specific fonts
-    FcPatternAddBool(pat, FC_SCALABLE, FcTrue);
-
     nsAutoRef<FcFontSet> fs(FcFontList(nullptr, pat, os));
     if (!fs) {
         return;
     }
 
     for (int i = 0; i < fs->nfont; i++) {
         char *family;
 
@@ -1371,19 +1493,16 @@ gfxFcPlatformFontList::GetStandardFamily
         return true;
     }
 
     nsAutoRef<FcObjectSet> os(FcObjectSetBuild(FC_FAMILY, nullptr));
     if (!os) {
         return true;
     }
 
-    // ignore size-specific fonts
-    FcPatternAddBool(pat, FC_SCALABLE, FcTrue);
-
     // add the family name to the pattern
     NS_ConvertUTF16toUTF8 familyName(aFontName);
     FcPatternAddString(pat, FC_FAMILY, ToFcChar8Ptr(familyName.get()));
 
     nsAutoRef<FcFontSet> givenFS(FcFontList(nullptr, pat, os));
     if (!givenFS) {
         return true;
     }
@@ -1610,23 +1729,16 @@ gfxFcPlatformFontList::FindGenericFamili
     // -- select the fonts to be used for the generic
     prefFonts = new PrefFontList; // can be empty but in practice won't happen
     uint32_t limit = gfxPlatformGtk::GetPlatform()->MaxGenericSubstitions();
     bool foundFontWithLang = false;
     for (int i = 0; i < faces->nfont; i++) {
         FcPattern* font = faces->fonts[i];
         FcChar8* mappedGeneric = nullptr;
 
-        // not scalable? skip...
-        FcBool scalable;
-        if (FcPatternGetBool(font, FC_SCALABLE, 0, &scalable) != FcResultMatch ||
-            !scalable) {
-            continue;
-        }
-
         FcPatternGetString(font, FC_FAMILY, 0, &mappedGeneric);
         if (mappedGeneric) {
             NS_ConvertUTF8toUTF16 mappedGenericName(ToCharPtr(mappedGeneric));
             AutoTArray<gfxFontFamily*,1> genericFamilies;
             if (gfxPlatformFontList::FindAndAddFamilies(mappedGenericName,
                                                         &genericFamilies)) {
                 MOZ_ASSERT(genericFamilies.Length() == 1,
                            "expected a single family");
--- a/gfx/thebes/gfxFcPlatformFontList.h
+++ b/gfx/thebes/gfxFcPlatformFontList.h
@@ -119,16 +119,18 @@ public:
     nsresult ReadCMAP(FontInfoData *aFontInfoData = nullptr) override;
     bool TestCharacterMap(uint32_t aCh) override;
 
     hb_blob_t* GetFontTable(uint32_t aTableTag) override;
 
     void ForgetHBFace() override;
     void ReleaseGrFace(gr_face* aFace) override;
 
+    double GetAspect();
+
 protected:
     virtual ~gfxFontconfigFontEntry();
 
     gfxFont *CreateFontInstance(const gfxFontStyle *aFontStyle,
                                 bool aNeedsBold) override;
 
     // helper method for creating cairo font from pattern
     cairo_scaled_font_t*
@@ -140,18 +142,16 @@ protected:
     // override to pull data from FTFace
     virtual nsresult
     CopyFontTable(uint32_t aTableTag,
                   nsTArray<uint8_t>& aBuffer) override;
 
     // if HB or GR faces are gone, close down the FT_Face
     void MaybeReleaseFTFace();
 
-    double GetAspect();
-
     // pattern for a single face of a family
     nsCountedRef<FcPattern> mFontPattern;
 
     // user font data, when needed
     RefPtr<FTUserFontData> mUserFontData;
 
     // FTFace - initialized when needed
     FT_Face   mFTFace;
@@ -169,36 +169,43 @@ protected:
     // data font
     const uint8_t* mFontData;
 };
 
 class gfxFontconfigFontFamily : public gfxFontFamily {
 public:
     explicit gfxFontconfigFontFamily(const nsAString& aName) :
         gfxFontFamily(aName),
-        mContainsAppFonts(false)
+        mContainsAppFonts(false),
+        mHasNonScalableFaces(false)
     { }
 
     void FindStyleVariations(FontInfoData *aFontInfoData = nullptr) override;
 
     // Families are constructed initially with just references to patterns.
     // When necessary, these are enumerated within FindStyleVariations.
     void AddFontPattern(FcPattern* aFontPattern);
 
     void SetFamilyContainsAppFonts(bool aContainsAppFonts)
     {
         mContainsAppFonts = aContainsAppFonts;
     }
 
+    void
+    FindAllFontsForStyle(const gfxFontStyle& aFontStyle,
+                         nsTArray<gfxFontEntry*>& aFontEntryList,
+                         bool& aNeedsSyntheticBold) override;
+
 protected:
     virtual ~gfxFontconfigFontFamily() { }
 
     nsTArray<nsCountedRef<FcPattern> > mFontPatterns;
 
     bool      mContainsAppFonts;
+    bool      mHasNonScalableFaces;
 };
 
 class gfxFontconfigFont : public gfxFontconfigFontBase {
 public:
     gfxFontconfigFont(cairo_scaled_font_t *aScaledFont,
                       FcPattern *aPattern,
                       gfxFloat aAdjustedSize,
                       gfxFontEntry *aFontEntry,
--- a/gfx/thebes/gfxFontEntry.h
+++ b/gfx/thebes/gfxFontEntry.h
@@ -633,17 +633,17 @@ public:
     // choose a specific face to match a style using CSS font matching
     // rules (weight matching occurs here).  may return a face that doesn't
     // precisely match (e.g. normal face when no italic face exists).
     // aNeedsSyntheticBold is set to true when synthetic bolding is
     // needed, false otherwise
     gfxFontEntry *FindFontForStyle(const gfxFontStyle& aFontStyle, 
                                    bool& aNeedsSyntheticBold);
 
-    void
+    virtual void
     FindAllFontsForStyle(const gfxFontStyle& aFontStyle,
                          nsTArray<gfxFontEntry*>& aFontEntryList,
                          bool& aNeedsSyntheticBold);
 
     // checks for a matching font within the family
     // used as part of the font fallback process
     void FindFontForChar(GlobalFontMatch *aMatchData);
 
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -616,16 +616,26 @@ gfxPlatform::Init()
 
       if (Preferences::GetBool("media.wmf.skip-blacklist")) {
         gfxVars::SetPDMWMFDisableD3D11Dlls(nsCString());
         gfxVars::SetPDMWMFDisableD3D9Dlls(nsCString());
       } else {
         gfxVars::SetPDMWMFDisableD3D11Dlls(Preferences::GetCString("media.wmf.disable-d3d11-for-dlls"));
         gfxVars::SetPDMWMFDisableD3D9Dlls(Preferences::GetCString("media.wmf.disable-d3d9-for-dlls"));
       }
+
+      nsCOMPtr<nsIFile> file;
+      nsresult rv = NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(file));
+      if (NS_FAILED(rv)) {
+        gfxVars::SetGREDirectory(nsCString());
+      } else {
+        nsAutoCString nativePath;
+        file->GetNativePath(nativePath);
+        gfxVars::SetGREDirectory(nsCString(nativePath));
+      }
     }
 
     // Drop a note in the crash report if we end up forcing an option that could
     // destabilize things.  New items should be appended at the end (of an existing
     // or in a new section), so that we don't have to know the version to interpret
     // these cryptic strings.
     {
       nsAutoCString forcedPrefs;
@@ -1249,16 +1259,19 @@ gfxPlatform::PopulateScreenInfo()
   nsCOMPtr<nsIScreen> screen;
   manager->GetPrimaryScreen(getter_AddRefs(screen));
   if (!screen) {
     // This can happen in xpcshell, for instance
     return;
   }
 
   screen->GetColorDepth(&mScreenDepth);
+  if (XRE_IsParentProcess()) {
+    gfxVars::SetScreenDepth(mScreenDepth);
+  }
 
   int left, top;
   screen->GetRect(&left, &top, &mScreenSize.width, &mScreenSize.height);
 }
 
 bool
 gfxPlatform::SupportsAzureContentForDrawTarget(DrawTarget* aTarget)
 {
@@ -2323,16 +2336,29 @@ gfxPlatform::InitWebRenderConfig()
 
 #ifndef MOZ_BUILD_WEBRENDER
   featureWebRender.ForceDisable(
     FeatureStatus::Unavailable,
     "Build doesn't include WebRender",
     NS_LITERAL_CSTRING("FEATURE_FAILURE_NO_WEBRENDER"));
 #endif
 
+#ifdef XP_WIN
+  if (Preferences::GetBool("gfx.webrender.force-angle", false)) {
+    if (!gfxConfig::IsEnabled(Feature::D3D11_HW_ANGLE)) {
+      featureWebRender.ForceDisable(
+        FeatureStatus::Unavailable,
+        "ANGLE is disabled",
+        NS_LITERAL_CSTRING("FEATURE_FAILURE_ANGLE_DISABLED"));
+    } else {
+      gfxVars::SetUseWebRenderANGLE(gfxConfig::IsEnabled(Feature::WEBRENDER));
+    }
+  }
+#endif
+
   // gfxFeature is not usable in the GPU process, so we use gfxVars to transmit this feature
   if (gfxConfig::IsEnabled(Feature::WEBRENDER)) {
     gfxVars::SetUseWebRender(true);
     reporter.SetSuccessful();
   }
 }
 
 bool
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -480,16 +480,17 @@ private:
   DECL_GFX_PREF(Once, "image.mem.surfacecache.size_factor",    ImageMemSurfaceCacheSizeFactor, uint32_t, 64);
   DECL_GFX_PREF(Once, "image.multithreaded_decoding.limit",    ImageMTDecodingLimit, int32_t, -1);
 
   DECL_GFX_PREF(Once, "layers.acceleration.disabled",          LayersAccelerationDisabledDoNotUseDirectly, bool, false);
   DECL_GFX_PREF(Live, "layers.acceleration.draw-fps",          LayersDrawFPS, bool, false);
   DECL_GFX_PREF(Live, "layers.acceleration.draw-fps.print-histogram",  FPSPrintHistogram, bool, false);
   DECL_GFX_PREF(Live, "layers.acceleration.draw-fps.write-to-file", WriteFPSToFile, bool, false);
   DECL_GFX_PREF(Once, "layers.acceleration.force-enabled",     LayersAccelerationForceEnabledDoNotUseDirectly, bool, false);
+  DECL_GFX_PREF(Live, "layers.advanced.background-color",      LayersAllowBackgroundColorLayers, bool, false);
   DECL_OVERRIDE_PREF(Live, "layers.advanced.background-image", LayersAllowBackgroundImage, false);
   DECL_OVERRIDE_PREF(Live, "layers.advanced.border-layers",    LayersAllowBorderLayers, false);
   DECL_OVERRIDE_PREF(Live, "layers.advanced.boxshadow-inset-layers", LayersAllowInsetBoxShadow, gfxPrefs::OverrideBase_WebRender());
   DECL_OVERRIDE_PREF(Live, "layers.advanced.boxshadow-outer-layers", LayersAllowOuterBoxShadow, false);
   DECL_GFX_PREF(Live, "layers.advanced.bullet-layers",         LayersAllowBulletLayers, bool, false);
   DECL_GFX_PREF(Live, "layers.advanced.button-foreground-layers", LayersAllowButtonForegroundLayers, bool, false);
   DECL_GFX_PREF(Live, "layers.advanced.canvas-background-color", LayersAllowCanvasBackgroundColorLayers, bool, false);
   DECL_OVERRIDE_PREF(Live, "layers.advanced.caret-layers",     LayersAllowCaretLayers, gfxPrefs::OverrideBase_WebRender());
--- a/gfx/webrender/Cargo.toml
+++ b/gfx/webrender/Cargo.toml
@@ -1,33 +1,34 @@
 [package]
 name = "webrender"
-version = "0.25.0"
+version = "0.26.0"
 authors = ["Glenn Watson <gw@intuitionlibrary.com>"]
 license = "MPL-2.0"
 repository = "https://github.com/servo/webrender"
 build = "build.rs"
 
 [features]
-default = ["freetype-lib"]
+default = ["freetype-lib", "webgl"]
 freetype-lib = ["freetype/servo-freetype-sys"]
 profiler = ["thread_profiler/thread_profiler"]
+webgl = ["offscreen_gl_context", "webrender_traits/webgl"]
 
 [dependencies]
 app_units = "0.4"
 bincode = "1.0.0-alpha2"
 bit-set = "0.4"
 byteorder = "1.0"
 euclid = "0.11"
 fnv = "1.0"
 gleam = "0.4.1"
 lazy_static = "0.2"
 log = "0.3"
 num-traits = "0.1.32"
-offscreen_gl_context = {version = "0.8.0", features = ["serde", "osmesa"]}
+offscreen_gl_context = {version = "0.8.0", features = ["serde", "osmesa"], optional = true}
 time = "0.1"
 threadpool = "1.3.2"
 webrender_traits = {path = "../webrender_traits"}
 bitflags = "0.7"
 gamma-lut = "0.1"
 thread_profiler = "0.1.1"
 
 [dev-dependencies]
--- a/gfx/webrender/res/cs_blur.fs.glsl
+++ b/gfx/webrender/res/cs_blur.fs.glsl
@@ -10,31 +10,31 @@
 // TODO(gw): Make use of the bilinear sampling trick to reduce
 //           the number of texture fetches needed for a gaussian blur.
 
 float gauss(float x, float sigma) {
     return (1.0 / sqrt(6.283185307179586 * sigma * sigma)) * exp(-(x * x) / (2.0 * sigma * sigma));
 }
 
 void main(void) {
-    vec4 cache_sample = texture(sCache, vUv);
+    vec4 cache_sample = texture(sCacheRGBA8, vUv);
     vec4 color = vec4(cache_sample.rgb, 1.0) * (cache_sample.a * gauss(0.0, vSigma));
 
     for (int i=1 ; i < vBlurRadius ; ++i) {
         vec2 offset = vec2(float(i)) * vOffsetScale;
 
         vec2 st0 = clamp(vUv.xy + offset, vUvRect.xy, vUvRect.zw);
-        vec4 color0 = texture(sCache, vec3(st0, vUv.z));
+        vec4 color0 = texture(sCacheRGBA8, vec3(st0, vUv.z));
 
         vec2 st1 = clamp(vUv.xy - offset, vUvRect.xy, vUvRect.zw);
-        vec4 color1 = texture(sCache, vec3(st1, vUv.z));
+        vec4 color1 = texture(sCacheRGBA8, vec3(st1, vUv.z));
 
         // Alpha must be premultiplied in order to properly blur the alpha channel.
         float weight = gauss(float(i), vSigma);
         color += vec4(color0.rgb * color0.a, color0.a) * weight;
         color += vec4(color1.rgb * color1.a, color1.a) * weight;
     }
 
     // Unpremultiply the alpha.
     color.rgb /= color.a;
 
-    oFragColor = color;
+    oFragColor = dither(color);
 }
--- a/gfx/webrender/res/cs_blur.vs.glsl
+++ b/gfx/webrender/res/cs_blur.vs.glsl
@@ -35,17 +35,17 @@ void main(void) {
     RenderTaskData src_task = fetch_render_task(cmd.src_task_id);
 
     vec4 local_rect = task.data0;
 
     vec2 pos = mix(local_rect.xy,
                    local_rect.xy + local_rect.zw,
                    aPosition.xy);
 
-    vec2 texture_size = vec2(textureSize(sCache, 0).xy);
+    vec2 texture_size = vec2(textureSize(sCacheRGBA8, 0).xy);
     vUv.z = src_task.data1.x;
     vBlurRadius = int(task.data1.y);
     vSigma = task.data1.y * 0.5;
 
     switch (cmd.dir) {
         case DIR_HORIZONTAL:
             vOffsetScale = vec2(1.0 / texture_size.x, 0.0);
             break;
--- a/gfx/webrender/res/cs_box_shadow.fs.glsl
+++ b/gfx/webrender/res/cs_box_shadow.fs.glsl
@@ -139,10 +139,10 @@ float color(vec2 pos, vec2 p0Rect, vec2 
 void main(void) {
     vec2 pos = vPos.xy;
     vec2 p0Rect = vBoxShadowRect.xy, p1Rect = vBoxShadowRect.zw;
     vec2 radii = vBorderRadii.xy;
     float sigma = vBlurRadius / 2.0;
     float value = color(pos, p0Rect, p1Rect, radii, sigma);
 
     value = max(value, 0.0);
-    oFragColor = vec4(1.0, 1.0, 1.0, vInverted == 1.0 ? 1.0 - value : value);
+    oFragColor = dither(vec4(1.0, 1.0, 1.0, vInverted == 1.0 ? 1.0 - value : value));
 }
--- a/gfx/webrender/res/prim_shared.glsl
+++ b/gfx/webrender/res/prim_shared.glsl
@@ -28,17 +28,18 @@
 #define BORDER_BOTTOM    3
 
 #define UV_NORMALIZED    uint(0)
 #define UV_PIXEL         uint(1)
 
 #define EXTEND_MODE_CLAMP  0
 #define EXTEND_MODE_REPEAT 1
 
-uniform sampler2DArray sCache;
+uniform sampler2DArray sCacheA8;
+uniform sampler2DArray sCacheRGBA8;
 
 flat varying vec4 vClipMaskUvBounds;
 varying vec3 vClipMaskUv;
 
 #ifdef WR_VERTEX_SHADER
 
 #define VECS_PER_LAYER             13
 #define VECS_PER_RENDER_TASK        3
@@ -702,17 +703,17 @@ BoxShadow fetch_boxshadow(int index) {
     bs.bs_rect = texelFetchOffset(sData64, uv, 0, ivec2(1, 0));
     bs.color = texelFetchOffset(sData64, uv, 0, ivec2(2, 0));
     bs.border_radius_edge_size_blur_radius_inverted = texelFetchOffset(sData64, uv, 0, ivec2(3, 0));
 
     return bs;
 }
 
 void write_clip(vec2 global_pos, ClipArea area) {
-    vec2 texture_size = vec2(textureSize(sCache, 0).xy);
+    vec2 texture_size = vec2(textureSize(sCacheA8, 0).xy);
     vec2 uv = global_pos + area.task_bounds.xy - area.screen_origin_target_index.xy;
     vClipMaskUvBounds = area.task_bounds / texture_size.xyxy;
     vClipMaskUv = vec3(uv / texture_size, area.screen_origin_target_index.z);
 }
 #endif //WR_VERTEX_SHADER
 
 #ifdef WR_FRAGMENT_SHADER
 float signed_distance_rect(vec2 pos, vec2 p0, vec2 p1) {
@@ -750,11 +751,20 @@ vec2 init_transform_fs(vec3 local_pos, v
 
 float do_clip() {
     // anything outside of the mask is considered transparent
     bvec4 inside = lessThanEqual(
         vec4(vClipMaskUvBounds.xy, vClipMaskUv.xy),
         vec4(vClipMaskUv.xy, vClipMaskUvBounds.zw));
     // check for the dummy bounds, which are given to the opaque objects
     return vClipMaskUvBounds.xy == vClipMaskUvBounds.zw ? 1.0:
-        all(inside) ? textureLod(sCache, vClipMaskUv, 0.0).r : 0.0;
+        all(inside) ? textureLod(sCacheA8, vClipMaskUv, 0.0).r : 0.0;
+}
+
+vec4 dither(vec4 color) {
+    const int matrix_mask = 7;
+
+    ivec2 pos = ivec2(gl_FragCoord.xy) & ivec2(matrix_mask);
+    float noise_factor = 4.0 / 255.0;
+    float noise = texelFetch(sDither, pos, 0).r * noise_factor;
+    return color + vec4(noise, noise, noise, 0);
 }
 #endif //WR_FRAGMENT_SHADER
--- a/gfx/webrender/res/ps_angle_gradient.fs.glsl
+++ b/gfx/webrender/res/ps_angle_gradient.fs.glsl
@@ -6,16 +6,15 @@ uniform sampler2D sGradients;
 
 void main(void) {
     vec2 texture_size = vec2(textureSize(sGradients, 0));
 
     // Either saturate or modulo the offset depending on repeat mode, then scale to number of
     // gradient color entries (texture width / 2).
     float x = mix(clamp(vOffset, 0.0, 1.0), fract(vOffset), vGradientRepeat) * 0.5 * texture_size.x;
 
-    // Start at the center of first color in the nearest 2-color entry, then offset with the
-    // fractional remainder to interpolate between the colors. Rely on texture clamping when
-    // outside of valid range.
     x = 2.0 * floor(x) + 0.5 + fract(x);
 
-    // Normalize the texture coordates so we can use texture() for bilinear filtering.
-    oFragColor = texture(sGradients, vec2(x, vGradientIndex) / texture_size);
+    // Use linear filtering to mix in the low bits (vGradientIndex + 1) with the high
+    // bits (vGradientIndex)
+    float y = vGradientIndex * 2.0 + 0.5 + 1.0 / 256.0;
+    oFragColor = dither(texture(sGradients, vec2(x, y) / texture_size));
 }
--- a/gfx/webrender/res/ps_angle_gradient.vs.glsl
+++ b/gfx/webrender/res/ps_angle_gradient.vs.glsl
@@ -22,13 +22,13 @@ void main(void) {
     vec2 start_point = floor(0.5 + gradient.start_end_point.xy * uDevicePixelRatio) / uDevicePixelRatio;
     vec2 end_point = floor(0.5 + gradient.start_end_point.zw * uDevicePixelRatio) / uDevicePixelRatio;
 
     vec2 dir = end_point - start_point;
     // Normalized offset of this vertex within the gradient, before clamp/repeat.
     vOffset = dot(vi.local_pos - start_point, dir) / dot(dir, dir);
 
     // V coordinate of gradient row in lookup texture.
-    vGradientIndex = float(prim.sub_index) + 0.5;
+    vGradientIndex = float(prim.sub_index);
 
     // Whether to repeat the gradient instead of clamping.
     vGradientRepeat = float(int(gradient.extend_mode.x) == EXTEND_MODE_REPEAT);
 }
--- a/gfx/webrender/res/ps_blend.fs.glsl
+++ b/gfx/webrender/res/ps_blend.fs.glsl
@@ -94,17 +94,17 @@ vec4 Brightness(vec4 Cs, float amount) {
     return vec4(Cs.rgb * amount, Cs.a);
 }
 
 vec4 Opacity(vec4 Cs, float amount) {
     return vec4(Cs.rgb, Cs.a * amount);
 }
 
 void main(void) {
-    vec4 Cs = texture(sCache, vUv);
+    vec4 Cs = texture(sCacheRGBA8, vUv);
 
     if (Cs.a == 0.0) {
         discard;
     }
 
     switch (vOp) {
         case 0:
             // Gaussian blur is specially handled:
--- a/gfx/webrender/res/ps_blend.vs.glsl
+++ b/gfx/webrender/res/ps_blend.vs.glsl
@@ -11,17 +11,17 @@ void main(void) {
     vec2 dest_origin = dest_task.render_target_origin -
                        dest_task.screen_space_origin +
                        src_task.screen_space_origin;
 
     vec2 local_pos = mix(dest_origin,
                          dest_origin + src_task.size,
                          aPosition.xy);
 
-    vec2 texture_size = vec2(textureSize(sCache, 0));
+    vec2 texture_size = vec2(textureSize(sCacheRGBA8, 0));
     vec2 st0 = src_task.render_target_origin / texture_size;
     vec2 st1 = (src_task.render_target_origin + src_task.size) / texture_size;
     vUv = vec3(mix(st0, st1, aPosition.xy), src_task.render_target_layer_index);
 
     vOp = pi.sub_index;
     vAmount = float(pi.user_data.y) / 65535.0;
 
     gl_Position = uTransform * vec4(local_pos, pi.z, 1.0);
--- a/gfx/webrender/res/ps_border.fs.glsl
+++ b/gfx/webrender/res/ps_border.fs.glsl
@@ -361,20 +361,34 @@ void draw_mixed_border(float distanceFro
     case PST_TOP_LEFT:
     case PST_TOP_RIGHT:
     case PST_BOTTOM_LEFT:
     case PST_BOTTOM_RIGHT: {
       // This is the conversion factor for transformations and device pixel scaling.
       float pixelsPerFragment = length(fwidth(localPos.xy));
       vec4 color = get_fragment_color(distanceFromMixLine, pixelsPerFragment);
 
-      float distance = distance(vRefPoint, localPos) - vRadii.z;
-      float length = vRadii.x - vRadii.z;
-      if (distanceFromMiddle < 0.0) {
-        distance = length - distance;
+      if (vRadii.x > 0.0) {
+        float distance = distance(vRefPoint, localPos) - vRadii.z;
+        float length = vRadii.x - vRadii.z;
+        if (distanceFromMiddle < 0.0) {
+          distance = length - distance;
+        }
+
+        oFragColor = 0.0 <= distance && distance <= length ?
+          draw_mixed_edge(distance, length, color, brightness_mod) : vec4(0.0, 0.0, 0.0, 0.0);
+        break;
+      }
+
+      bool is_vertical = (vBorderPart == PST_TOP_LEFT) ? distanceFromMixLine < 0.0 :
+                                                         distanceFromMixLine >= 0.0;
+      float distance = is_vertical ? abs(localPos.x - vRefPoint.x) : abs(localPos.y - vRefPoint.y);
+      float length = is_vertical ? abs(vPieceRect.z) : abs(vPieceRect.w);
+      if (distanceFromMiddle > 0.0) {
+          distance = length - distance;
       }
 
       oFragColor = 0.0 <= distance && distance <= length ?
         draw_mixed_edge(distance, length, color, brightness_mod) : vec4(0.0, 0.0, 0.0, 0.0);
       break;
     }
     case PST_BOTTOM:
     case PST_TOP: {
--- a/gfx/webrender/res/ps_box_shadow.fs.glsl
+++ b/gfx/webrender/res/ps_box_shadow.fs.glsl
@@ -11,10 +11,10 @@ void main(void) {
     // shadow corner. This can happen, for example, when
     // drawing the outer parts of an inset box shadow.
     uv = clamp(uv, vec2(0.0), vec2(1.0));
 
     // Map the unit UV to the actual UV rect in the cache.
     uv = mix(vCacheUvRectCoords.xy, vCacheUvRectCoords.zw, uv);
 
     // Modulate the box shadow by the color.
-    oFragColor = vColor * texture(sCache, vec3(uv, vUv.z));
+    oFragColor = dither(vColor * texture(sCacheRGBA8, vec3(uv, vUv.z)));
 }
--- a/gfx/webrender/res/ps_box_shadow.vs.glsl
+++ b/gfx/webrender/res/ps_box_shadow.vs.glsl
@@ -20,13 +20,13 @@ void main(void) {
     // Constant offsets to inset from bilinear filtering border.
     vec2 patch_origin = child_task.data0.xy + vec2(1.0);
     vec2 patch_size_device_pixels = child_task.data0.zw - vec2(2.0);
     vec2 patch_size = patch_size_device_pixels / uDevicePixelRatio;
 
     vUv.xy = (vi.local_pos - prim.local_rect.p0) / patch_size;
     vMirrorPoint = 0.5 * prim.local_rect.size / patch_size;
 
-    vec2 texture_size = vec2(textureSize(sCache, 0));
+    vec2 texture_size = vec2(textureSize(sCacheRGBA8, 0));
     vCacheUvRectCoords = vec4(patch_origin, patch_origin + patch_size_device_pixels) / texture_size.xyxy;
 
     vColor = bs.color;
 }
--- a/gfx/webrender/res/ps_cache_image.fs.glsl
+++ b/gfx/webrender/res/ps_cache_image.fs.glsl
@@ -1,7 +1,7 @@
 /* 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/. */
 
 void main(void) {
-    oFragColor = texture(sCache, vUv);
+    oFragColor = texture(sCacheRGBA8, vUv);
 }
--- a/gfx/webrender/res/ps_cache_image.vs.glsl
+++ b/gfx/webrender/res/ps_cache_image.vs.glsl
@@ -13,16 +13,16 @@ void main(void) {
                                  prim.local_clip_rect,
                                  prim.z,
                                  prim.layer,
                                  prim.task);
 
     RenderTaskData child_task = fetch_render_task(prim.user_data.x);
     vUv.z = child_task.data1.x;
 
-    vec2 texture_size = vec2(textureSize(sCache, 0));
+    vec2 texture_size = vec2(textureSize(sCacheRGBA8, 0));
     vec2 uv0 = child_task.data0.xy / texture_size;
     vec2 uv1 = (child_task.data0.xy + child_task.data0.zw) / texture_size;
 
     vec2 f = (vi.local_pos - prim.local_rect.p0) / prim.local_rect.size;
 
     vUv.xy = mix(uv0, uv1, f);
 }
--- a/gfx/webrender/res/ps_composite.fs.glsl
+++ b/gfx/webrender/res/ps_composite.fs.glsl
@@ -163,18 +163,18 @@ const int MixBlendMode_SoftLight   = 9;
 const int MixBlendMode_Difference  = 10;
 const int MixBlendMode_Exclusion   = 11;
 const int MixBlendMode_Hue         = 12;
 const int MixBlendMode_Saturation  = 13;
 const int MixBlendMode_Color       = 14;
 const int MixBlendMode_Luminosity  = 15;
 
 void main(void) {
-    vec4 Cb = texture(sCache, vUv0);
-    vec4 Cs = texture(sCache, vUv1);
+    vec4 Cb = texture(sCacheRGBA8, vUv0);
+    vec4 Cs = texture(sCacheRGBA8, vUv1);
 
     // Return yellow if none of the branches match (shouldn't happen).
     vec4 result = vec4(1.0, 1.0, 0.0, 1.0);
 
     switch (vOp) {
         case MixBlendMode_Multiply:
             result.rgb = Multiply(Cb.rgb, Cs.rgb);
             break;
--- a/gfx/webrender/res/ps_composite.vs.glsl
+++ b/gfx/webrender/res/ps_composite.vs.glsl
@@ -12,17 +12,17 @@ void main(void) {
     vec2 dest_origin = dest_task.render_target_origin -
                        dest_task.screen_space_origin +
                        src_task.screen_space_origin;
 
     vec2 local_pos = mix(dest_origin,
                          dest_origin + src_task.size,
                          aPosition.xy);
 
-    vec2 texture_size = vec2(textureSize(sCache, 0));
+    vec2 texture_size = vec2(textureSize(sCacheRGBA8, 0));
 
     vec2 st0 = backdrop_task.render_target_origin / texture_size;
     vec2 st1 = (backdrop_task.render_target_origin + backdrop_task.size) / texture_size;
     vUv0 = vec3(mix(st0, st1, aPosition.xy), backdrop_task.render_target_layer_index);
 
     st0 = src_task.render_target_origin / texture_size;
     st1 = (src_task.render_target_origin + src_task.size) / texture_size;
     vUv1 = vec3(mix(st0, st1, aPosition.xy), src_task.render_target_layer_index);
--- a/gfx/webrender/res/ps_gradient.fs.glsl
+++ b/gfx/webrender/res/ps_gradient.fs.glsl
@@ -7,10 +7,10 @@ void main(void) {
     float alpha = 0.0;
     vec2 local_pos = init_transform_fs(vLocalPos, vLocalRect, alpha);
 #else
     float alpha = 1.0;
     vec2 local_pos = vPos;
 #endif
 
     alpha = min(alpha, do_clip());
-    oFragColor = vColor * vec4(1.0, 1.0, 1.0, alpha);
+    oFragColor = dither(vColor * vec4(1.0, 1.0, 1.0, alpha));
 }
--- a/gfx/webrender/res/ps_gradient.vs.glsl
+++ b/gfx/webrender/res/ps_gradient.vs.glsl
@@ -10,41 +10,53 @@ void main(void) {
     GradientStop g0 = fetch_gradient_stop(prim.sub_index + 0);
     GradientStop g1 = fetch_gradient_stop(prim.sub_index + 1);
 
     RectWithSize segment_rect;
     vec2 axis;
     vec4 adjusted_color_g0 = g0.color;
     vec4 adjusted_color_g1 = g1.color;
     if (gradient.start_end_point.y == gradient.start_end_point.w) {
-        vec2 x = mix(gradient.start_end_point.xx, gradient.start_end_point.zz,
-                     vec2(g0.offset.x, g1.offset.x));
+        // Calculate the x coord of the gradient stops
+        vec2 g01_x = mix(gradient.start_end_point.xx, gradient.start_end_point.zz,
+                         vec2(g0.offset.x, g1.offset.x));
+
         // The start and end point of gradient might exceed the geometry rect. So clamp
         // it to the geometry rect.
-        x = clamp(x, prim.local_rect.p0.xx, prim.local_rect.p0.xx + prim.local_rect.size.xx);
+        g01_x = clamp(g01_x, prim.local_rect.p0.xx, prim.local_rect.p0.xx + prim.local_rect.size.xx);
+
+        // Calculate the rect using the clamped coords
+        segment_rect.p0 = vec2(g01_x.x, prim.local_rect.p0.y);
+        segment_rect.size = vec2(g01_x.y - g01_x.x, prim.local_rect.size.y);
+        axis = vec2(1.0, 0.0);
+
+        // We need to adjust the colors of the stops because they may have been clamped
         vec2 adjusted_offset =
-            (x - gradient.start_end_point.xx) / (gradient.start_end_point.zz - gradient.start_end_point.xx);
+            (g01_x - segment_rect.p0.xx) / segment_rect.size.xx;
         adjusted_color_g0 = mix(g0.color, g1.color, adjusted_offset.x);
         adjusted_color_g1 = mix(g0.color, g1.color, adjusted_offset.y);
-        segment_rect.p0 = vec2(x.x, prim.local_rect.p0.y);
-        segment_rect.size = vec2(x.y - x.x, prim.local_rect.size.y);
-        axis = vec2(1.0, 0.0);
     } else {
-        vec2 y = mix(gradient.start_end_point.yy, gradient.start_end_point.ww,
-                     vec2(g0.offset.x, g1.offset.x));
+        // Calculate the y coord of the gradient stops
+        vec2 g01_y = mix(gradient.start_end_point.yy, gradient.start_end_point.ww,
+                         vec2(g0.offset.x, g1.offset.x));
+
         // The start and end point of gradient might exceed the geometry rect. So clamp
         // it to the geometry rect.
-        y = clamp(y, prim.local_rect.p0.yy, prim.local_rect.p0.yy + prim.local_rect.size.yy);
+        g01_y = clamp(g01_y, prim.local_rect.p0.yy, prim.local_rect.p0.yy + prim.local_rect.size.yy);
+
+        // Calculate the rect using the clamped coords
+        segment_rect.p0 = vec2(prim.local_rect.p0.x, g01_y.x);
+        segment_rect.size = vec2(prim.local_rect.size.x, g01_y.y - g01_y.x);
+        axis = vec2(0.0, 1.0);
+
+        // We need to adjust the colors of the stops because they may have been clamped
         vec2 adjusted_offset =
-            (y - gradient.start_end_point.yy) / (gradient.start_end_point.ww - gradient.start_end_point.yy);
+            (g01_y - segment_rect.p0.yy) / segment_rect.size.yy;
         adjusted_color_g0 = mix(g0.color, g1.color, adjusted_offset.x);
         adjusted_color_g1 = mix(g0.color, g1.color, adjusted_offset.y);
-        segment_rect.p0 = vec2(prim.local_rect.p0.x, y.x);
-        segment_rect.size = vec2(prim.local_rect.size.x, y.y - y.x);
-        axis = vec2(0.0, 1.0);
     }
 
 #ifdef WR_FEATURE_TRANSFORM
     TransformVertexInfo vi = write_transform_vertex(segment_rect,
                                                     prim.local_clip_rect,
                                                     prim.z,
                                                     prim.layer,
                                                     prim.task);
--- a/gfx/webrender/res/ps_hardware_composite.fs.glsl
+++ b/gfx/webrender/res/ps_hardware_composite.fs.glsl
@@ -1,7 +1,7 @@
 /* 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/. */
 
 void main(void) {
-    oFragColor = texture(sCache, vUv);
+    oFragColor = texture(sCacheRGBA8, vUv);
 }
--- a/gfx/webrender/res/ps_hardware_composite.vs.glsl
+++ b/gfx/webrender/res/ps_hardware_composite.vs.glsl
@@ -11,15 +11,15 @@ void main(void) {
     vec2 dest_origin = dest_task.render_target_origin -
                        dest_task.screen_space_origin +
                        src_task.screen_space_origin;
 
     vec2 local_pos = mix(dest_origin,
                          dest_origin + src_task.size,
                          aPosition.xy);
 
-    vec2 texture_size = vec2(textureSize(sCache, 0));
+    vec2 texture_size = vec2(textureSize(sCacheRGBA8, 0));
     vec2 st0 = src_task.render_target_origin / texture_size;
     vec2 st1 = (src_task.render_target_origin + src_task.size) / texture_size;
     vUv = vec3(mix(st0, st1, aPosition.xy), src_task.render_target_layer_index);
 
     gl_Position = uTransform * vec4(local_pos, pi.z, 1.0);
 }
--- a/gfx/webrender/res/ps_radial_gradient.fs.glsl
+++ b/gfx/webrender/res/ps_radial_gradient.fs.glsl
@@ -45,16 +45,15 @@ void main(void) {
     }
 
     vec2 texture_size = vec2(textureSize(sGradients, 0));
 
     // Either saturate or modulo the offset depending on repeat mode, then scale to number of
     // gradient color entries (texture width / 2).
     x = mix(clamp(x, 0.0, 1.0), fract(x), vGradientRepeat) * 0.5 * texture_size.x;
 
-    // Start at the center of first color in the nearest 2-color entry, then offset with the
-    // fractional remainder to interpolate between the colors. Rely on texture clamping when
-    // outside of valid range.
     x = 2.0 * floor(x) + 0.5 + fract(x);
 
-    // Normalize the texture coordates so we can use texture() for bilinear filtering.
-    oFragColor = texture(sGradients, vec2(x, vGradientIndex) / texture_size);
+    // Use linear filtering to mix in the low bits (vGradientIndex + 1) with the high
+    // bits (vGradientIndex)
+    float y = vGradientIndex * 2.0 + 0.5 + 1.0 / 256.0;
+    oFragColor = dither(texture(sGradients, vec2(x, y) / texture_size));
 }
--- a/gfx/webrender/res/ps_radial_gradient.vs.glsl
+++ b/gfx/webrender/res/ps_radial_gradient.vs.glsl
@@ -22,13 +22,13 @@ void main(void) {
     // be better to fix this higher up in DL construction
     // and not snap here?
     vStartCenter = floor(0.5 + gradient.start_end_center.xy * uDevicePixelRatio) / uDevicePixelRatio;
     vEndCenter = floor(0.5 + gradient.start_end_center.zw * uDevicePixelRatio) / uDevicePixelRatio;
     vStartRadius = gradient.start_end_radius_extend_mode.x;
     vEndRadius = gradient.start_end_radius_extend_mode.y;
 
     // V coordinate of gradient row in lookup texture.
-    vGradientIndex = float(prim.sub_index) + 0.5;
+    vGradientIndex = float(prim.sub_index);
 
     // Whether to repeat the gradient instead of clamping.
     vGradientRepeat = float(int(gradient.start_end_radius_extend_mode.z) == EXTEND_MODE_REPEAT);
 }
--- a/gfx/webrender/res/shared.glsl
+++ b/gfx/webrender/res/shared.glsl
@@ -31,16 +31,17 @@
 #endif
 
 //======================================================================================
 // Shared shader uniforms
 //======================================================================================
 uniform sampler2D sColor0;
 uniform sampler2D sColor1;
 uniform sampler2D sColor2;
+uniform sampler2D sDither;
 uniform sampler2D sMask;
 
 //======================================================================================
 // Interpolator definitions
 //======================================================================================
 
 //======================================================================================
 // VS only types and UBOs
--- a/gfx/webrender/src/clip_scroll_node.rs
+++ b/gfx/webrender/src/clip_scroll_node.rs
@@ -243,19 +243,23 @@ impl ClipScrollNode {
             inv_transform.pre_translated(-parent_accumulated_scroll_offset.x,
                                          -parent_accumulated_scroll_offset.y,
                                          0.0)
                          .transform_rect(parent_combined_viewport_rect);
 
         // Now that we have the combined viewport rectangle of the parent nodes in local space,
         // we do the intersection and get our combined viewport rect in the coordinate system
         // starting from our origin.
-        self.combined_local_viewport_rect =
-            parent_combined_viewport_in_local_space.intersection(&self.local_clip_rect)
-                                                    .unwrap_or(LayerRect::zero());
+        self.combined_local_viewport_rect = match self.node_type {
+            NodeType::Clip(_) => {
+                parent_combined_viewport_in_local_space.intersection(&self.local_clip_rect)
+                                                       .unwrap_or(LayerRect::zero())
+            }
+            NodeType::ReferenceFrame(_) => parent_combined_viewport_in_local_space,
+        };
 
         // The transformation for this viewport in world coordinates is the transformation for
         // our parent reference frame, plus any accumulated scrolling offsets from nodes
         // between our reference frame and this node. For reference frames, we also include
         // whatever local transformation this reference frame provides. This can be combined
         // with the local_viewport_rect to get its position in world space.
         self.world_viewport_transform =
             parent_reference_frame_transform
--- a/gfx/webrender/src/device.rs
+++ b/gfx/webrender/src/device.rs
@@ -1542,24 +1542,32 @@ impl Device {
         let u_color1 = self.gl.get_uniform_location(program.id, "sColor1");
         if u_color1 != -1 {
             self.gl.uniform_1i(u_color1, TextureSampler::Color1 as i32);
         }
         let u_color_2 = self.gl.get_uniform_location(program.id, "sColor2");
         if u_color_2 != -1 {
             self.gl.uniform_1i(u_color_2, TextureSampler::Color2 as i32);
         }
+        let u_noise = self.gl.get_uniform_location(program.id, "sDither");
+        if u_noise != -1 {
+            self.gl.uniform_1i(u_noise, TextureSampler::Dither as i32);
+        }
         let u_mask = self.gl.get_uniform_location(program.id, "sMask");
         if u_mask != -1 {
             self.gl.uniform_1i(u_mask, TextureSampler::Mask as i32);
         }
 
-        let u_cache = self.gl.get_uniform_location(program.id, "sCache");
-        if u_cache != -1 {
-            self.gl.uniform_1i(u_cache, TextureSampler::Cache as i32);
+        let u_cache_a8 = self.gl.get_uniform_location(program.id, "sCacheA8");
+        if u_cache_a8 != -1 {
+            self.gl.uniform_1i(u_cache_a8, TextureSampler::CacheA8 as i32);
+        }
+        let u_cache_rgba8 = self.gl.get_uniform_location(program.id, "sCacheRGBA8");
+        if u_cache_rgba8 != -1 {
+            self.gl.uniform_1i(u_cache_rgba8, TextureSampler::CacheRGBA8 as i32);
         }
 
         let u_layers = self.gl.get_uniform_location(program.id, "sLayers");
         if u_layers != -1 {
             self.gl.uniform_1i(u_layers, TextureSampler::Layers as i32);
         }
 
         let u_tasks = self.gl.get_uniform_location(program.id, "sRenderTasks");
--- a/gfx/webrender/src/frame.rs
+++ b/gfx/webrender/src/frame.rs
@@ -11,19 +11,20 @@ use internal_types::{RendererFrame};
 use frame_builder::{FrameBuilder, FrameBuilderConfig};
 use clip_scroll_tree::{ClipScrollTree, ScrollStates};
 use profiler::TextureCacheProfileCounters;
 use resource_cache::ResourceCache;
 use scene::{Scene, SceneProperties};
 use std::collections::HashMap;
 use std::hash::BuildHasherDefault;
 use tiling::{AuxiliaryListsMap, CompositeOps, PrimitiveFlags};
+use util::subtract_rect;
 use webrender_traits::{AuxiliaryLists, ClipDisplayItem, ClipRegion, ColorF, DeviceUintRect};
 use webrender_traits::{DeviceUintSize, DisplayItem, Epoch, FilterOp, ImageDisplayItem, LayerPoint};
-use webrender_traits::{LayerRect, LayerSize, LayerToScrollTransform, LayoutTransform};
+use webrender_traits::{LayerRect, LayerSize, LayerToScrollTransform, LayoutRect, LayoutTransform};
 use webrender_traits::{MixBlendMode, PipelineId, ScrollEventPhase, ScrollLayerId};
 use webrender_traits::{ScrollLayerState, ScrollLocation, ScrollPolicy, SpecificDisplayItem};
 use webrender_traits::{StackingContext, TileOffset, WorldPoint};
 
 #[derive(Copy, Clone, PartialEq, PartialOrd, Debug)]
 pub struct FrameId(pub u32);
 
 static DEFAULT_SCROLLBAR_COLOR: ColorF = ColorF { r: 0.3, g: 0.3, b: 0.3, a: 0.6 };
@@ -62,24 +63,24 @@ pub struct Frame {
     pub pipeline_epoch_map: HashMap<PipelineId, Epoch, BuildHasherDefault<FnvHasher>>,
     pub pipeline_auxiliary_lists: AuxiliaryListsMap,
     id: FrameId,
     frame_builder_config: FrameBuilderConfig,
     frame_builder: Option<FrameBuilder>,
 }
 
 trait DisplayListHelpers {
-    fn starting_stacking_context<'a>(&'a self) -> Option<(&'a StackingContext, &'a ClipRegion)>;
+    fn starting_stacking_context<'a>(&'a self) -> Option<(&'a StackingContext, &'a LayoutRect)>;
 }
 
 impl DisplayListHelpers for Vec<DisplayItem> {
-    fn starting_stacking_context<'a>(&'a self) -> Option<(&'a StackingContext, &'a ClipRegion)> {
+    fn starting_stacking_context<'a>(&'a self) -> Option<(&'a StackingContext, &'a LayoutRect)> {
         self.first().and_then(|item| match item.item {
             SpecificDisplayItem::PushStackingContext(ref specific_item) => {
-                Some((&specific_item.stacking_context, &item.clip))
+                Some((&specific_item.stacking_context, &item.rect))
             },
             _ => None,
         })
     }
 }
 
 trait StackingContextHelpers {
     fn mix_blend_mode_for_compositing(&self) -> Option<MixBlendMode>;
@@ -200,16 +201,32 @@ impl<'a> Iterator for DisplayListTravers
         }
 
         let item = &self.display_list[self.next_item_index];
         self.next_item_index += 1;
         Some(item)
     }
 }
 
+fn clip_intersection(original_rect: &LayerRect,
+                     region: &ClipRegion,
+                     aux_lists: &AuxiliaryLists)
+                     -> Option<LayerRect> {
+    if region.image_mask.is_some() {
+        return None;
+    }
+    let clips = aux_lists.complex_clip_regions(&region.complex);
+    let base_rect = region.main.intersection(original_rect);
+    clips.iter().fold(base_rect, |inner_combined, ccr| {
+        inner_combined.and_then(|combined| {
+            ccr.get_inner_rect().and_then(|ir| ir.intersection(&combined))
+        })
+    })
+}
+
 impl Frame {
     pub fn new(config: FrameBuilderConfig) -> Frame {
         Frame {
             pipeline_epoch_map: HashMap::with_hasher(Default::default()),
             pipeline_auxiliary_lists: HashMap::with_hasher(Default::default()),
             clip_scroll_tree: ClipScrollTree::new(),
             id: FrameId(0),
             frame_builder: None,
@@ -279,17 +296,17 @@ impl Frame {
             return;
         }
 
         let old_scrolling_states = self.reset();
         self.pipeline_auxiliary_lists = scene.pipeline_auxiliary_lists.clone();
 
         self.pipeline_epoch_map.insert(root_pipeline_id, root_pipeline.epoch);
 
-        let (root_stacking_context, root_clip) = match display_list.starting_stacking_context() {
+        let (root_stacking_context, root_bounds) = match display_list.starting_stacking_context() {
             Some(some) => some,
             None => {
                 warn!("Pipeline display list does not start with a stacking context.");
                 return;
             }
         };
 
         let background_color = root_pipeline.background_color.and_then(|color| {
@@ -304,33 +321,33 @@ impl Frame {
                                                   background_color,
                                                   self.frame_builder_config);
 
         {
             let mut context = FlattenContext::new(scene, &mut frame_builder, resource_cache);
 
             let scroll_layer_id = context.builder.push_root(root_pipeline_id,
                                                             &root_pipeline.viewport_size,
-                                                            &root_clip.main.size,
+                                                            &root_bounds.size,
                                                             &mut self.clip_scroll_tree);
 
             context.builder.setup_viewport_offset(window_size,
                                                   inner_rect,
                                                   device_pixel_ratio,
                                                   &mut self.clip_scroll_tree);
 
             let mut traversal = DisplayListTraversal::new_skipping_first(display_list);
             self.flatten_stacking_context(&mut traversal,
                                           root_pipeline_id,
                                           &mut context,
                                           scroll_layer_id,
                                           LayerPoint::zero(),
                                           0,
-                                          &root_stacking_context,
-                                          root_clip);
+                                          &root_bounds,
+                                          &root_stacking_context);
         }
 
         self.frame_builder = Some(frame_builder);
         self.clip_scroll_tree.finalize_and_apply_pending_scroll_offsets(old_scrolling_states);
     }
 
     fn flatten_clip<'a>(&mut self,
                         context: &mut FlattenContext,
@@ -352,18 +369,18 @@ impl Frame {
 
     fn flatten_stacking_context<'a>(&mut self,
                                     traversal: &mut DisplayListTraversal<'a>,
                                     pipeline_id: PipelineId,
                                     context: &mut FlattenContext,
                                     context_scroll_layer_id: ScrollLayerId,
                                     mut reference_frame_relative_offset: LayerPoint,
                                     level: i32,
-                                    stacking_context: &StackingContext,
-                                    clip_region: &ClipRegion) {
+                                    bounds: &LayerRect,
+                                    stacking_context: &StackingContext) {
         // Avoid doing unnecessary work for empty stacking contexts.
         if traversal.current_stacking_context_empty() {
             traversal.skip_current_stacking_context();
             return;
         }
 
         let composition_operations = {
             let auxiliary_lists = self.pipeline_auxiliary_lists
@@ -395,50 +412,48 @@ impl Frame {
             let transform = stacking_context.transform.as_ref();
             let transform = context.scene.properties.resolve_layout_transform(transform);
             let perspective =
                 stacking_context.perspective.unwrap_or_else(LayoutTransform::identity);
             let transform =
                 LayerToScrollTransform::create_translation(reference_frame_relative_offset.x,
                                                            reference_frame_relative_offset.y,
                                                            0.0)
-                                        .pre_translated(stacking_context.bounds.origin.x,
-                                                        stacking_context.bounds.origin.y,
-                                                        0.0)
+                                        .pre_translated(bounds.origin.x, bounds.origin.y, 0.0)
                                         .pre_mul(&transform)
                                         .pre_mul(&perspective);
 
+            let reference_frame_bounds = LayerRect::new(LayerPoint::zero(), bounds.size);
             scroll_layer_id = context.builder.push_reference_frame(Some(scroll_layer_id),
                                                                    pipeline_id,
-                                                                   &clip_region.main,
+                                                                   &reference_frame_bounds,
                                                                    &transform,
                                                                    &mut self.clip_scroll_tree);
             context.replacements.push((context_scroll_layer_id, scroll_layer_id));
             reference_frame_relative_offset = LayerPoint::zero();
         } else {
             reference_frame_relative_offset = LayerPoint::new(
-                reference_frame_relative_offset.x + stacking_context.bounds.origin.x,
-                reference_frame_relative_offset.y + stacking_context.bounds.origin.y);
+                reference_frame_relative_offset.x + bounds.origin.x,
+                reference_frame_relative_offset.y + bounds.origin.y);
         }
 
         // TODO(gw): Int with overflow etc
-        context.builder.push_stacking_context(reference_frame_relative_offset,
-                                              clip_region.main,
+        context.builder.push_stacking_context(&reference_frame_relative_offset,
                                               pipeline_id,
                                               level == 0,
                                               composition_operations);
 
         if level == 0 {
             if let Some(pipeline) = context.scene.pipeline_map.get(&pipeline_id) {
                 if let Some(bg_color) = pipeline.background_color {
                     // Note: we don't use the original clip region here,
                     // it's already processed by the node we just pushed.
-                    let background_rect = LayerRect::new(LayerPoint::zero(), clip_region.main.size);
+                    let background_rect = LayerRect::new(LayerPoint::zero(), bounds.size);
                     context.builder.add_solid_rectangle(scroll_layer_id,
-                                                        &clip_region.main,
+                                                        &bounds,
                                                         &ClipRegion::simple(&background_rect),
                                                         &bg_color,
                                                         PrimitiveFlags::None);
                 }
             }
         }
 
         self.flatten_items(traversal,
@@ -482,17 +497,18 @@ impl Frame {
         };
 
         let display_list = context.scene.display_lists.get(&pipeline_id);
         let display_list = match display_list {
             Some(display_list) => display_list,
             None => return,
         };
 
-        let (iframe_stacking_context, iframe_clip) = match display_list.starting_stacking_context() {
+        let (iframe_stacking_context,
+             iframe_stacking_context_bounds) = match display_list.starting_stacking_context() {
             Some(some) => some,
             None => {
                 warn!("Pipeline display list does not start with a stacking context.");
                 return;
             }
         };
 
         self.pipeline_epoch_map.insert(pipeline_id, pipeline.epoch);
@@ -511,29 +527,29 @@ impl Frame {
                                                  &mut self.clip_scroll_tree);
 
         let iframe_scroll_layer_id = ScrollLayerId::root_scroll_layer(pipeline_id);
         context.builder.add_clip_scroll_node(
             iframe_scroll_layer_id,
             iframe_reference_frame_id,
             pipeline_id,
             &LayerRect::new(LayerPoint::zero(), iframe_rect.size),
-            &iframe_clip.main.size,
-            iframe_clip,
+            &iframe_stacking_context_bounds.size,
+            &ClipRegion::simple(&iframe_stacking_context_bounds),
             &mut self.clip_scroll_tree);
 
         let mut traversal = DisplayListTraversal::new_skipping_first(display_list);
         self.flatten_stacking_context(&mut traversal,
                                       pipeline_id,
                                       context,
                                       iframe_scroll_layer_id,
                                       LayerPoint::zero(),
                                       0,
-                                      &iframe_stacking_context,
-                                      iframe_clip);
+                                      &iframe_stacking_context_bounds,
+                                      &iframe_stacking_context);
 
         context.builder.pop_reference_frame();
     }
 
     fn flatten_items<'a>(&mut self,
                          traversal: &mut DisplayListTraversal<'a>,
                          pipeline_id: PipelineId,
                          context: &mut FlattenContext,
@@ -589,21 +605,44 @@ impl Frame {
                                              text_info.font_key,
                                              text_info.size,
                                              text_info.blur_radius,
                                              &text_info.color,
                                              text_info.glyphs,
                                              text_info.glyph_options);
                 }
                 SpecificDisplayItem::Rectangle(ref info) => {
-                    context.builder.add_solid_rectangle(scroll_layer_id,
-                                                        &item.rect,
-                                                        &item.clip,
-                                                        &info.color,
-                                                        PrimitiveFlags::None);
+                    let auxiliary_lists = self.pipeline_auxiliary_lists
+                                              .get(&pipeline_id)
+                                              .expect("No auxiliary lists?!");
+                    // Try to extract the opaque inner rectangle out of the clipped primitive.
+                    if let Some(opaque_rect) = clip_intersection(&item.rect, &item.clip, &auxiliary_lists) {
+                        let mut results = Vec::new();
+                        subtract_rect(&item.rect, &opaque_rect, &mut results);
+                        // The inner rectangle is considered opaque within this layer.
+                        // It may still inherit some masking from the clip stack.
+                        context.builder.add_solid_rectangle(scroll_layer_id,
+                                                            &opaque_rect,
+                                                            &ClipRegion::simple(&item.clip.main),
+                                                            &info.color,
+                                                            PrimitiveFlags::None);
+                        for transparent_rect in &results {
+                            context.builder.add_solid_rectangle(scroll_layer_id,
+                                                                transparent_rect,
+                                                                &item.clip,
+                                                                &info.color,
+                                                                PrimitiveFlags::None);
+                        }
+                    } else {
+                        context.builder.add_solid_rectangle(scroll_layer_id,
+                                                            &item.rect,
+                                                            &item.clip,
+                                                            &info.color,
+                                                            PrimitiveFlags::None);
+                    }
                 }
                 SpecificDisplayItem::Gradient(ref info) => {
                     context.builder.add_gradient(scroll_layer_id,
                                                  item.rect,
                                                  &item.clip,
                                                  info.gradient.start_point,
                                                  info.gradient.end_point,
                                                  info.gradient.stops,
@@ -639,18 +678,18 @@ impl Frame {
                 }
                 SpecificDisplayItem::PushStackingContext(ref info) => {
                     self.flatten_stacking_context(traversal,
                                                   pipeline_id,
                                                   context,
                                                   item.scroll_layer_id,
                                                   reference_frame_relative_offset,
                                                   level + 1,
-                                                  &info.stacking_context,
-                                                  &item.clip);
+                                                  &item.rect,
+                                                  &info.stacking_context);
                 }
                 SpecificDisplayItem::Iframe(ref info) => {
                     self.flatten_iframe(info.pipeline_id,
                                         scroll_layer_id,
                                         &item.rect,
                                         context,
                                         reference_frame_relative_offset);
                 }
--- a/gfx/webrender/src/frame_builder.rs
+++ b/gfx/webrender/src/frame_builder.rs
@@ -206,36 +206,34 @@ impl FrameBuilder {
             packed_layer_index: packed_layer_index,
             xf_rect: None,
          });
 
         ClipScrollGroupIndex(self.clip_scroll_group_store.len() - 1, scroll_layer_id)
     }
 
     pub fn push_stacking_context(&mut self,
-                                 reference_frame_offset: LayerPoint,
-                                 rect: LayerRect,
+                                 reference_frame_offset: &LayerPoint,
                                  pipeline_id: PipelineId,
                                  is_page_root: bool,
                                  composite_ops: CompositeOps) {
         if let Some(parent_index) = self.stacking_context_stack.last() {
             let parent_is_root = self.stacking_context_store[parent_index.0].is_page_root;
 
             if composite_ops.mix_blend_mode.is_some() && !parent_is_root {
                 // the parent stacking context of a stacking context with mix-blend-mode
                 // must be drawn with a transparent background, unless the parent stacking context
                 // is the root of the page
                 self.stacking_context_store[parent_index.0].should_isolate = true;
             }
         }
 
         let stacking_context_index = StackingContextIndex(self.stacking_context_store.len());
         self.stacking_context_store.push(StackingContext::new(pipeline_id,
-                                                              reference_frame_offset,
-                                                              rect,
+                                                              *reference_frame_offset,
                                                               is_page_root,
                                                               composite_ops));
         self.cmds.push(PrimitiveRunCmd::PushStackingContext(stacking_context_index));
         self.stacking_context_stack.push(stacking_context_index);
     }
 
     pub fn pop_stacking_context(&mut self) {
         self.cmds.push(PrimitiveRunCmd::PopStackingContext);
@@ -1327,17 +1325,18 @@ impl FrameBuilder {
                 clip_scroll_group_store: &self.clip_scroll_group_store,
                 prim_store: &self.prim_store,
                 resource_cache: resource_cache,
             };
 
             pass.build(&ctx, &mut render_tasks);
 
             profile_counters.passes.inc();
-            profile_counters.targets.add(pass.targets.len());
+            profile_counters.color_targets.add(pass.color_targets.target_count());
+            profile_counters.alpha_targets.add(pass.alpha_targets.target_count());
         }
 
         resource_cache.end_frame();
 
         Frame {
             device_pixel_ratio: device_pixel_ratio,
             background_color: self.background_color,
             window_size: self.screen_size,
@@ -1441,17 +1440,17 @@ impl<'a> LayerRectCalculationAndCullingP
                                                 0.0);
             packed_layer.set_transform(transform);
 
             // Meanwhile, the combined viewport rect is relative to the reference frame, so
             // we move it into the local coordinate system of the node.
             let local_viewport_rect =
                 node.combined_local_viewport_rect.translate(&-node.local_viewport_rect.origin);
 
-            node_clip_info.xf_rect = packed_layer.set_rect(Some(local_viewport_rect),
+            node_clip_info.xf_rect = packed_layer.set_rect(&local_viewport_rect,
                                                            self.screen_rect,
                                                            self.device_pixel_ratio);
 
             let mask_info = match node_clip_info.mask_cache_info {
                 Some(ref mut mask_info) => mask_info,
                 _ => continue,
             };
 
@@ -1488,26 +1487,23 @@ impl<'a> LayerRectCalculationAndCullingP
                                                 stacking_context.reference_frame_offset.y,
                                                 0.0);
             packed_layer.set_transform(transform);
 
             if !stacking_context.can_contribute_to_scene() {
                 return;
             }
 
-            // Here we want to find the intersection between the clipping region and the
-            // stacking context content, so we move the viewport rectangle into the coordinate
-            // system of the stacking context content.
+            // Here we move the viewport rectangle into the coordinate system
+            // of the stacking context content.
             let viewport_rect =
                 &node.combined_local_viewport_rect
                      .translate(&-stacking_context.reference_frame_offset)
                      .translate(&-node.scrolling.offset);
-            let intersected_rect = stacking_context.local_rect.intersection(viewport_rect);
-
-            group.xf_rect = packed_layer.set_rect(intersected_rect,
+            group.xf_rect = packed_layer.set_rect(viewport_rect,
                                                   self.screen_rect,
                                                   self.device_pixel_ratio);
         }
     }
 
     fn compute_stacking_context_visibility(&mut self) {
         for context_index in 0..self.frame_builder.stacking_context_store.len() {
             let is_visible = {
--- a/gfx/webrender/src/gpu_store.rs
+++ b/gfx/webrender/src/gpu_store.rs
@@ -40,16 +40,20 @@ pub trait GpuStoreLayout {
         let texel_size = Self::texel_size();
         debug_assert!(item_size % texel_size == 0);
         item_size / texel_size
     }
 
     fn items_per_row<T>() -> usize {
         Self::texture_width::<T>() / Self::texels_per_item::<T>()
     }
+
+    fn rows_per_item<T>() -> usize {
+        Self::texels_per_item::<T>() / Self::texture_width::<T>()
+    }
 }
 
 /// A CPU-side buffer storing content to be uploaded to the GPU.
 pub struct GpuStore<T, L> {
     data: Vec<T>,
     layout: PhantomData<L>,
     // TODO(gw): Could store this intrusively inside
     // the data array free slots.
@@ -76,18 +80,20 @@ impl<T: Clone + Default, L: GpuStoreLayo
     pub fn build(&self) -> Vec<T> {
         let items_per_row = L::items_per_row::<T>();
 
         let mut items = self.data.clone();
 
         // Extend the data array to be a multiple of the row size.
         // This ensures memory safety when the array is passed to
         // OpenGL to upload to the GPU.
-        while items.len() % items_per_row != 0 {
-            items.push(T::default());
+        if items_per_row != 0 {
+            while items_per_row != 0 && items.len() % items_per_row != 0 {
+                items.push(T::default());
+            }
         }
 
         items
     }
 
     pub fn alloc(&mut self, count: usize) -> GpuStoreAddress {
         let address = self.get_next_address();
 
--- a/gfx/webrender/src/internal_types.rs
+++ b/gfx/webrender/src/internal_types.rs
@@ -1,33 +1,28 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use app_units::Au;
 use device::TextureFilter;
 use euclid::{TypedPoint2D, UnknownUnit};
 use fnv::FnvHasher;
-use gleam::gl;
-use offscreen_gl_context::{NativeGLContext, NativeGLContextHandle};
-use offscreen_gl_context::{GLContext, NativeGLContextMethods, GLContextDispatcher};
-use offscreen_gl_context::{OSMesaContext, OSMesaContextHandle};
-use offscreen_gl_context::{ColorAttachmentType, GLContextAttributes, GLLimits};
 use profiler::BackendProfileCounters;
 use std::collections::{HashMap, HashSet};
 use std::f32;
 use std::hash::BuildHasherDefault;
 use std::{i32, usize};
 use std::path::PathBuf;
 use std::sync::Arc;
 use tiling;
 use renderer::BlendMode;
-use webrender_traits::{Epoch, ColorF, PipelineId, DeviceIntSize};
+use webrender_traits::{Epoch, ColorF, PipelineId};
 use webrender_traits::{ImageFormat, NativeFontHandle};
-use webrender_traits::{ExternalImageId, ScrollLayerId, WebGLCommand};
+use webrender_traits::{ExternalImageId, ScrollLayerId};
 use webrender_traits::{ImageData};
 use webrender_traits::{DeviceUintRect};
 
 // An ID for a texture that is owned by the
 // texture cache module. This can include atlases
 // or standalone textures allocated via the
 // texture cache (e.g. if an image is too large
 // to be added to an atlas). The texture cache
@@ -43,138 +38,25 @@ pub struct CacheTextureId(pub usize);
 // pipeline until they reach the rendering
 // thread, where they are resolved to a
 // native texture ID.
 
 #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
 pub enum SourceTexture {
     Invalid,
     TextureCache(CacheTextureId),
-    WebGL(u32),                         // Is actually a gl::GLuint
     External(ExternalImageId),
-}
-
-pub enum GLContextHandleWrapper {
-    Native(NativeGLContextHandle),
-    OSMesa(OSMesaContextHandle),
-}
-
-impl GLContextHandleWrapper {
-    pub fn current_native_handle() -> Option<GLContextHandleWrapper> {
-        NativeGLContext::current_handle().map(GLContextHandleWrapper::Native)
-    }
-
-    pub fn current_osmesa_handle() -> Option<GLContextHandleWrapper> {
-        OSMesaContext::current_handle().map(GLContextHandleWrapper::OSMesa)
-    }
-
-    pub fn new_context(&self,
-                       size: DeviceIntSize,
-                       attributes: GLContextAttributes,
-                       dispatcher: Option<Box<GLContextDispatcher>>) -> Result<GLContextWrapper, &'static str> {
-        match *self {
-            GLContextHandleWrapper::Native(ref handle) => {
-                let ctx = GLContext::<NativeGLContext>::new_shared_with_dispatcher(size.to_untyped(),
-                                                                                   attributes,
-                                                                                   ColorAttachmentType::Texture,
-                                                                                   gl::GlType::default(),
-                                                                                   Some(handle),
-                                                                                   dispatcher);
-                ctx.map(GLContextWrapper::Native)
-            }
-            GLContextHandleWrapper::OSMesa(ref handle) => {
-                let ctx = GLContext::<OSMesaContext>::new_shared_with_dispatcher(size.to_untyped(),
-                                                                                 attributes,
-                                                                                 ColorAttachmentType::Texture,
-                                                                                 gl::GlType::default(),
-                                                                                 Some(handle),
-                                                                                 dispatcher);
-                ctx.map(GLContextWrapper::OSMesa)
-            }
-        }
-    }
-}
-
-pub enum GLContextWrapper {
-    Native(GLContext<NativeGLContext>),
-    OSMesa(GLContext<OSMesaContext>),
-}
-
-impl GLContextWrapper {
-    pub fn make_current(&self) {
-        match *self {
-            GLContextWrapper::Native(ref ctx) => {
-                ctx.make_current().unwrap();
-            }
-            GLContextWrapper::OSMesa(ref ctx) => {
-                ctx.make_current().unwrap();
-            }
-        }
-    }
-
-    pub fn unbind(&self) {
-        match *self {
-            GLContextWrapper::Native(ref ctx) => {
-                ctx.unbind().unwrap();
-            }
-            GLContextWrapper::OSMesa(ref ctx) => {
-                ctx.unbind().unwrap();
-            }
-        }
-    }
-
-    pub fn apply_command(&self, cmd: WebGLCommand) {
-        match *self {
-            GLContextWrapper::Native(ref ctx) => {
-                cmd.apply(ctx);
-            }
-            GLContextWrapper::OSMesa(ref ctx) => {
-                cmd.apply(ctx);
-            }
-        }
-    }
-
-    pub fn get_info(&self) -> (DeviceIntSize, u32, GLLimits) {
-        match *self {
-            GLContextWrapper::Native(ref ctx) => {
-                let (real_size, texture_id) = {
-                    let draw_buffer = ctx.borrow_draw_buffer().unwrap();
-                    (draw_buffer.size(), draw_buffer.get_bound_texture_id().unwrap())
-                };
-
-                let limits = ctx.borrow_limits().clone();
-
-                (DeviceIntSize::from_untyped(&real_size), texture_id, limits)
-            }
-            GLContextWrapper::OSMesa(ref ctx) => {
-                let (real_size, texture_id) = {
-                    let draw_buffer = ctx.borrow_draw_buffer().unwrap();
-                    (draw_buffer.size(), draw_buffer.get_bound_texture_id().unwrap())
-                };
-
-                let limits = ctx.borrow_limits().clone();
-
-                (DeviceIntSize::from_untyped(&real_size), texture_id, limits)
-            }
-        }
-    }
-
-    pub fn resize(&mut self, size: &DeviceIntSize) -> Result<(), &'static str> {
-        match *self {
-            GLContextWrapper::Native(ref mut ctx) => {
-                ctx.resize(size.to_untyped())
-            }
-            GLContextWrapper::OSMesa(ref mut ctx) => {
-                ctx.resize(size.to_untyped())
-            }
-        }
-    }
+    #[cfg_attr(not(feature = "webgl"), allow(dead_code))]
+    /// This is actually a gl::GLuint, with the shared texture id between the
+    /// main context and the WebGL context.
+    WebGL(u32),
 }
 
 const COLOR_FLOAT_TO_FIXED: f32 = 255.0;
+const COLOR_FLOAT_TO_FIXED_WIDE: f32 = 65535.0;
 pub const ANGLE_FLOAT_TO_FIXED: f32 = 65535.0;
 
 pub const ORTHO_NEAR_PLANE: f32 = -1000000.0;
 pub const ORTHO_FAR_PLANE: f32 = 1000000.0;
 
 #[derive(Clone)]
 pub enum FontTemplate {
     Raw(Arc<Vec<u8>>),
@@ -182,26 +64,28 @@ pub enum FontTemplate {
 }
 
 #[derive(Debug, PartialEq, Eq)]
 pub enum TextureSampler {
     Color0,
     Color1,
     Color2,
     Mask,
-    Cache,
+    CacheA8,
+    CacheRGBA8,
     Data16,
     Data32,
     Data64,
     Data128,
     Layers,
     RenderTasks,
     Geometry,
     ResourceRects,
     Gradients,
+    Dither,
 }
 
 impl TextureSampler {
     pub fn color(n: usize) -> TextureSampler {
         match n {
             0 => TextureSampler::Color0,
             1 => TextureSampler::Color1,
             2 => TextureSampler::Color2,
@@ -307,22 +191,30 @@ impl PackedColor {
 pub struct PackedTexel {
     pub b: u8,
     pub g: u8,
     pub r: u8,
     pub a: u8,
 }
 
 impl PackedTexel {
-    pub fn from_color(color: &ColorF) -> PackedTexel {
+    pub fn high_bytes(color: &ColorF) -> PackedTexel {
+        Self::extract_bytes(color, COLOR_FLOAT_TO_FIXED)
+    }
+
+    pub fn low_bytes(color: &ColorF) -> PackedTexel {
+        Self::extract_bytes(color, COLOR_FLOAT_TO_FIXED_WIDE)
+    }
+
+    fn extract_bytes(color: &ColorF, multiplier: f32) -> PackedTexel {
         PackedTexel {
-            b: (0.5 + color.b * COLOR_FLOAT_TO_FIXED).floor() as u8,
-            g: (0.5 + color.g * COLOR_FLOAT_TO_FIXED).floor() as u8,
-            r: (0.5 + color.r * COLOR_FLOAT_TO_FIXED).floor() as u8,
-            a: (0.5 + color.a * COLOR_FLOAT_TO_FIXED).floor() as u8,
+            b: ((0.5 + color.b * multiplier).floor() as u32 & 0xff) as u8,
+            g: ((0.5 + color.g * multiplier).floor() as u32 & 0xff) as u8,
+            r: ((0.5 + color.r * multiplier).floor() as u32 & 0xff) as u8,
+            a: ((0.5 + color.a * multiplier).floor() as u32 & 0xff) as u8,
         }
     }
 }
 
 #[derive(Debug, Clone, Copy)]
 #[repr(C)]
 pub struct PackedVertex {
     pub pos: [f32; 2],
--- a/gfx/webrender/src/lib.rs
+++ b/gfx/webrender/src/lib.rs
@@ -72,16 +72,23 @@ mod render_backend;
 mod render_task;
 mod resource_cache;
 mod scene;
 mod spring;
 mod texture_cache;
 mod tiling;
 mod util;
 
+#[cfg(feature = "webgl")]
+mod webgl_types;
+
+#[cfg(not(feature = "webgl"))]
+#[path = "webgl_stubs.rs"]
+mod webgl_types;
+
 mod shader_source {
     include!(concat!(env!("OUT_DIR"), "/shaders.rs"));
 }
 
 pub use record::{ApiRecordingReceiver, BinaryRecorder, WEBRENDER_RECORDING_HEADER};
 
 mod platform {
     #[cfg(target_os="macos")]
@@ -122,16 +129,17 @@ extern crate app_units;
 extern crate bincode;
 extern crate euclid;
 extern crate fnv;
 extern crate gleam;
 extern crate num_traits;
 //extern crate notify;
 extern crate time;
 extern crate webrender_traits;
+#[cfg(feature = "webgl")]
 extern crate offscreen_gl_context;
 extern crate byteorder;
 extern crate threadpool;
 
 #[cfg(any(target_os="macos", target_os="windows"))]
 extern crate gamma_lut;
 
 pub use renderer::{ExternalImage, ExternalImageSource, ExternalImageHandler};
--- a/gfx/webrender/src/prim_store.rs
+++ b/gfx/webrender/src/prim_store.rs
@@ -275,31 +275,34 @@ pub struct GradientDataEntry {
 // A table of gradient entries, with two colors per entry, that specify the start and end color
 // within the segment of the gradient space represented by that entry. To lookup a gradient result,
 // first the entry index is calculated to determine which two colors to interpolate between, then
 // the offset within that entry bucket is used to interpolate between the two colors in that entry.
 // This layout preserves hard stops, as the end color for a given entry can differ from the start
 // color for the following entry, despite them being adjacent. Colors are stored within in BGRA8
 // format for texture upload.
 pub struct GradientData {
-    pub colors: [GradientDataEntry; GRADIENT_DATA_RESOLUTION],
+    pub colors_high: [GradientDataEntry; GRADIENT_DATA_RESOLUTION],
+    pub colors_low: [GradientDataEntry; GRADIENT_DATA_RESOLUTION],
 }
 
 impl Default for GradientData {
     fn default() -> GradientData {
         GradientData {
-            colors: unsafe { mem::uninitialized() }
+            colors_high: unsafe { mem::uninitialized() },
+            colors_low: unsafe { mem::uninitialized() }
         }
     }
 }
 
 impl Clone for GradientData {
     fn clone(&self) -> GradientData {
         GradientData {
-            colors: self.colors,
+            colors_high: self.colors_high,
+            colors_low: self.colors_low,
         }
     }
 }
 
 impl GradientData {
     // Generate a color ramp between the start and end indexes from a start color to an end color.
     fn fill_colors(&mut self, start_idx: usize, end_idx: usize, start_color: &ColorF, end_color: &ColorF) -> usize {
         if start_idx >= end_idx {
@@ -309,28 +312,34 @@ impl GradientData {
         // Calculate the color difference for individual steps in the ramp.
         let inv_steps = 1.0 / (end_idx - start_idx) as f32;
         let step_r = (end_color.r - start_color.r) * inv_steps;
         let step_g = (end_color.g - start_color.g) * inv_steps;
         let step_b = (end_color.b - start_color.b) * inv_steps;
         let step_a = (end_color.a - start_color.a) * inv_steps;
 
         let mut cur_color = *start_color;
-        let mut cur_packed_color = PackedTexel::from_color(&cur_color);
+        let mut cur_color_high = PackedTexel::high_bytes(&cur_color);
+        let mut cur_color_low = PackedTexel::low_bytes(&cur_color);
 
         // Walk the ramp writing start and end colors for each entry.
-        for entry in &mut self.colors[start_idx..end_idx] {
-            entry.start_color = cur_packed_color;
+        for index in start_idx..end_idx {
+            let high_byte_entry = &mut self.colors_high[index];
+            let low_byte_entry = &mut self.colors_low[index];
 
+            high_byte_entry.start_color = cur_color_high;
+            low_byte_entry.start_color = cur_color_low;
             cur_color.r += step_r;
             cur_color.g += step_g;
             cur_color.b += step_b;
             cur_color.a += step_a;
-            cur_packed_color = PackedTexel::from_color(&cur_color);
-            entry.end_color = cur_packed_color;
+            cur_color_high = PackedTexel::high_bytes(&cur_color);
+            cur_color_low = PackedTexel::low_bytes(&cur_color);
+            high_byte_entry.end_color = cur_color_high;
+            low_byte_entry.end_color = cur_color_low;
         }
 
         end_idx
     }
 
     // Compute an entry index based on a gradient stop offset.
     #[inline]
     fn get_index(offset: f32) -> usize {
--- a/gfx/webrender/src/profiler.rs
+++ b/gfx/webrender/src/profiler.rs
@@ -245,26 +245,28 @@ impl ProfileCounter for AverageTimeProfi
         }
     }
 }
 
 pub struct FrameProfileCounters {
     pub total_primitives: IntProfileCounter,
     pub visible_primitives: IntProfileCounter,
     pub passes: IntProfileCounter,
-    pub targets: IntProfileCounter,
+    pub color_targets: IntProfileCounter,
+    pub alpha_targets: IntProfileCounter,
 }
 
 impl FrameProfileCounters {
     pub fn new() -> FrameProfileCounters {
         FrameProfileCounters {
             total_primitives: IntProfileCounter::new("Total Primitives"),
             visible_primitives: IntProfileCounter::new("Visible Primitives"),
             passes: IntProfileCounter::new("Passes"),
-            targets: IntProfileCounter::new("Render Targets"),
+            color_targets: IntProfileCounter::new("Color Targets"),
+            alpha_targets: IntProfileCounter::new("Alpha Targets"),
         }
     }
 }
 
 #[derive(Clone)]
 pub struct TextureCacheProfileCounters {
     pub pages_a8: ResourceProfileCounter,
     pub pages_rgb8: ResourceProfileCounter,
@@ -656,17 +658,18 @@ impl Profiler {
             &renderer_profile.frame_counter,
             &renderer_profile.frame_time,
         ], debug_renderer, true);
 
         self.draw_counters(&[
             &frame_profile.total_primitives,
             &frame_profile.visible_primitives,
             &frame_profile.passes,
-            &frame_profile.targets,
+            &frame_profile.color_targets,
+            &frame_profile.alpha_targets,
         ], debug_renderer, true);
 
         self.draw_counters(&[
             &backend_profile.font_templates,
             &backend_profile.image_templates,
         ], debug_renderer, true);
 
         self.draw_counters(&[
--- a/gfx/webrender/src/render_backend.rs
+++ b/gfx/webrender/src/render_backend.rs
@@ -1,34 +1,37 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use byteorder::{LittleEndian, ReadBytesExt};
 use frame::Frame;
 use frame_builder::FrameBuilderConfig;
-use internal_types::{FontTemplate, GLContextHandleWrapper, GLContextWrapper};
-use internal_types::{SourceTexture, ResultMsg, RendererFrame};
+use internal_types::{FontTemplate, SourceTexture, ResultMsg, RendererFrame};
 use profiler::{BackendProfileCounters, TextureCacheProfileCounters};
 use record::ApiRecordingReceiver;
 use resource_cache::ResourceCache;
 use scene::Scene;
 use std::collections::HashMap;
 use std::io::{Cursor, Read};
 use std::sync::{Arc, Mutex};
 use std::sync::mpsc::Sender;
 use texture_cache::TextureCache;
 use thread_profiler::register_thread_with_profiler;
 use threadpool::ThreadPool;
+use webgl_types::{GLContextHandleWrapper, GLContextWrapper};
 use webrender_traits::{DeviceIntPoint, DeviceUintPoint, DeviceUintRect, DeviceUintSize, LayerPoint};
 use webrender_traits::{ApiMsg, AuxiliaryLists, BuiltDisplayList, IdNamespace, ImageData};
 use webrender_traits::{PipelineId, RenderNotifier, RenderDispatcher, WebGLCommand, WebGLContextId};
 use webrender_traits::channel::{PayloadHelperMethods, PayloadReceiver, PayloadSender, MsgReceiver};
 use webrender_traits::{BlobImageRenderer, VRCompositorCommand, VRCompositorHandler};
+#[cfg(feature = "webgl")]
 use offscreen_gl_context::GLContextDispatcher;
+#[cfg(not(feature = "webgl"))]
+use webgl_types::GLContextDispatcher;
 
 /// The render backend is responsible for transforming high level display lists into
 /// GPU-friendly work which is then submitted to the renderer in the form of a frame::Frame.
 ///
 /// The render backend operates on its own thread.
 pub struct RenderBackend {
     api_rx: MsgReceiver<ApiMsg>,
     payload_rx: PayloadReceiver,
@@ -142,18 +145,18 @@ impl RenderBackend {
                             tx.send(glyph_dimensions).unwrap();
                         }
                         ApiMsg::AddImage(id, descriptor, data, tiling) => {
                             if let ImageData::Raw(ref bytes) = data {
                                 profile_counters.image_templates.inc(bytes.len());
                             }
                             self.resource_cache.add_image_template(id, descriptor, data, tiling);
                         }
-                        ApiMsg::UpdateImage(id, descriptor, bytes) => {
-                            self.resource_cache.update_image_template(id, descriptor, bytes);
+                        ApiMsg::UpdateImage(id, descriptor, bytes, dirty_rect) => {
+                            self.resource_cache.update_image_template(id, descriptor, bytes, dirty_rect);
                         }
                         ApiMsg::DeleteImage(id) => {
                             self.resource_cache.delete_image_template(id);
                         }
                         ApiMsg::SetPageZoom(factor) => {
                             self.page_zoom_factor = factor.get();
                         }
                         ApiMsg::SetPinchZoom(factor) => {
--- a/gfx/webrender/src/render_task.rs
+++ b/gfx/webrender/src/render_task.rs
@@ -2,17 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use internal_types::{HardwareCompositeOp, LowLevelFilterOp};
 use mask_cache::MaskCacheInfo;
 use prim_store::{PrimitiveCacheKey, PrimitiveIndex};
 use std::{cmp, f32, i32, mem, usize};
 use tiling::{ClipScrollGroupIndex, PackedLayerIndex, RenderPass, RenderTargetIndex};
-use tiling::{StackingContextIndex};
+use tiling::{RenderTargetKind, StackingContextIndex};
 use webrender_traits::{DeviceIntLength, DeviceIntPoint, DeviceIntRect, DeviceIntSize};
 use webrender_traits::{MixBlendMode, ScrollLayerId};
 
 const FLOATS_PER_RENDER_TASK_INFO: usize = 12;
 
 #[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)]
 pub struct RenderTaskIndex(pub usize);
 
@@ -434,9 +434,20 @@ impl RenderTask {
 
     pub fn max_depth(&self, depth: usize, max_depth: &mut usize) {
         let depth = depth + 1;
         *max_depth = cmp::max(*max_depth, depth);
         for child in &self.children {
             child.max_depth(depth, max_depth);
         }
     }
+
+    pub fn target_kind(&self) -> RenderTargetKind {
+        match self.kind {
+            RenderTaskKind::Alpha(..) |
+            RenderTaskKind::CachePrimitive(..) |
+            RenderTaskKind::VerticalBlur(..) |
+            RenderTaskKind::Readback(..) |
+            RenderTaskKind::HorizontalBlur(..) => RenderTargetKind::Color,
+            RenderTaskKind::CacheMask(..) => RenderTargetKind::Alpha,
+        }
+    }
 }
--- a/gfx/webrender/src/renderer.rs
+++ b/gfx/webrender/src/renderer.rs
@@ -16,17 +16,17 @@ use device::{GpuSample, TextureFilter, V
 use euclid::Matrix4D;
 use fnv::FnvHasher;
 use frame_builder::FrameBuilderConfig;
 use gleam::gl;
 use gpu_store::{GpuStore, GpuStoreLayout};
 use internal_types::{CacheTextureId, RendererFrame, ResultMsg, TextureUpdateOp};
 use internal_types::{ExternalImageUpdateList, TextureUpdateList, PackedVertex, RenderTargetMode};
 use internal_types::{ORTHO_NEAR_PLANE, ORTHO_FAR_PLANE, SourceTexture};
-use internal_types::{BatchTextures, TextureSampler, GLContextHandleWrapper};
+use internal_types::{BatchTextures, TextureSampler};
 use prim_store::GradientData;
 use profiler::{Profiler, BackendProfileCounters};
 use profiler::{GpuProfileTag, RendererProfileTimers, RendererProfileCounters};
 use record::ApiRecordingReceiver;
 use render_backend::RenderBackend;
 use render_task::RenderTaskData;
 use std;
 use std::cmp;
@@ -38,20 +38,21 @@ use std::mem;
 use std::path::PathBuf;
 use std::rc::Rc;
 use std::sync::{Arc, Mutex};
 use std::sync::mpsc::{channel, Receiver, Sender};
 use std::thread;
 use texture_cache::TextureCache;
 use threadpool::ThreadPool;
 use tiling::{AlphaBatchKind, BlurCommand, Frame, PrimitiveBatch, PrimitiveBatchData};
-use tiling::{CacheClipInstance, PrimitiveInstance, RenderTarget};
+use tiling::{AlphaRenderTarget, CacheClipInstance, PrimitiveInstance, ColorRenderTarget, RenderTargetKind};
 use time::precise_time_ns;
 use thread_profiler::{register_thread_with_profiler, write_profile};
 use util::TransformedRectKind;
+use webgl_types::GLContextHandleWrapper;
 use webrender_traits::{ColorF, Epoch, PipelineId, RenderNotifier, RenderDispatcher};
 use webrender_traits::{ExternalImageId, ImageData, ImageFormat, RenderApiSender};
 use webrender_traits::{DeviceIntRect, DevicePoint, DeviceIntPoint, DeviceIntSize, DeviceUintSize};
 use webrender_traits::{ImageDescriptor, BlobImageRenderer};
 use webrender_traits::channel;
 use webrender_traits::VRCompositorHandler;
 
 pub const GPU_DATA_TEXTURE_POOL: usize = 5;
@@ -149,25 +150,32 @@ impl<L: GpuStoreLayout> GpuDataTexture<L
     fn init<T: Default>(&mut self,
                         device: &mut Device,
                         data: &mut Vec<T>) {
         if data.is_empty() {
             return;
         }
 
         let items_per_row = L::items_per_row::<T>();
+        let rows_per_item = L::rows_per_item::<T>();
 
         // Extend the data array to be a multiple of the row size.
         // This ensures memory safety when the array is passed to
         // OpenGL to upload to the GPU.
-        while data.len() % items_per_row != 0 {
-            data.push(T::default());
+        if items_per_row != 0 {
+            while data.len() % items_per_row != 0 {
+                data.push(T::default());
+            }
         }
 
-        let height = data.len() / items_per_row;
+        let height = if items_per_row != 0 {
+            data.len() / items_per_row
+        } else {
+            data.len() * rows_per_item
+        };
 
         device.init_texture(self.id,
                             L::texture_width::<T>() as u32,
                             height as u32,
                             L::image_format(),
                             L::texture_filter(),
                             RenderTargetMode::None,
                             Some(unsafe { mem::transmute(data.as_slice()) } ));
@@ -196,17 +204,17 @@ pub type VertexDataStore<T> = GpuStore<T
 pub struct GradientDataTextureLayout {}
 
 impl GpuStoreLayout for GradientDataTextureLayout {
     fn image_format() -> ImageFormat {
         ImageFormat::RGBA8
     }
 
     fn texture_width<T>() -> usize {
-        mem::size_of::<GradientData>() / Self::texel_size()
+        mem::size_of::<GradientData>() / Self::texel_size() / 2
     }
 
     fn texture_filter() -> TextureFilter {
         TextureFilter::Linear
     }
 }
 
 type GradientDataTexture = GpuDataTexture<GradientDataTextureLayout>;
@@ -477,17 +485,18 @@ pub struct Renderer {
     clear_color: ColorF,
     debug: DebugRenderer,
     render_target_debug: bool,
     backend_profile_counters: BackendProfileCounters,
     profile_counters: RendererProfileCounters,
     profiler: Profiler,
     last_time: u64,
 
-    render_targets: Vec<TextureId>,
+    color_render_targets: Vec<TextureId>,
+    alpha_render_targets: Vec<TextureId>,
 
     gpu_profile: GpuProfiler<GpuProfileTag>,
     prim_vao_id: VAOId,
     blur_vao_id: VAOId,
     clip_vao_id: VAOId,
 
     gdt_index: usize,
     gpu_data_textures: [GpuDataTextures; GPU_DATA_TEXTURE_POOL],
@@ -507,16 +516,18 @@ pub struct Renderer {
     /// use a hashmap, and allows a flat vector for performance.
     cache_texture_id_map: Vec<TextureId>,
 
     /// A special 1x1 dummy cache texture used for shaders that expect to work
     /// with the cache but are actually running in the first pass
     /// when no target is yet provided as a cache texture input.
     dummy_cache_texture_id: TextureId,
 
+    dither_matrix_texture_id: TextureId,
+
     /// Optional trait object that allows the client
     /// application to provide external buffers for image data.
     external_image_handler: Option<Box<ExternalImageHandler>>,
 
     /// Map of external image IDs to native textures.
     external_images: HashMap<ExternalImageId, TextureId, BuildHasherDefault<FnvHasher>>,
 
     // Optional trait object that handles WebVR commands.
@@ -743,16 +754,28 @@ impl Renderer {
             0xff, 0xff, 0xff, 0xff,
             0xff, 0xff, 0xff, 0xff,
             0xff, 0xff, 0xff, 0xff,
         ];
         let mask_pixels: Vec<u8> = vec![
             0xff, 0xff,
             0xff, 0xff,
         ];
+
+        let dither_matrix: [u8; 64] = [
+            00, 48, 12, 60, 03, 51, 15, 63,
+            32, 16, 44, 28, 35, 19, 47, 31,
+            08, 56, 04, 52, 11, 59, 07, 55,
+            40, 24, 36, 20, 43, 27, 39, 23,
+            02, 50, 14, 62, 01, 49, 13, 61,
+            34, 18, 46, 30, 33, 17, 45, 29,
+            10, 58, 06, 54, 09, 57, 05, 53,
+            42, 26, 38, 22, 41, 25, 37, 21
+        ];
+
         // TODO: Ensure that the white texture can never get evicted when the cache supports LRU eviction!
         let white_image_id = texture_cache.new_item_id();
         texture_cache.insert(white_image_id,
                              ImageDescriptor::new(2, 2, ImageFormat::RGBA8, false),
                              TextureFilter::Linear,
                              ImageData::Raw(Arc::new(white_pixels)),
                              &mut backend_profile_counters.texture_cache);
 
@@ -767,16 +790,25 @@ impl Renderer {
         device.init_texture(dummy_cache_texture_id,
                             1,
                             1,
                             ImageFormat::RGBA8,
                             TextureFilter::Linear,
                             RenderTargetMode::LayerRenderTarget(1),
                             None);
 
+        let dither_matrix_texture_id = device.create_texture_ids(1, TextureTarget::Default)[0];
+        device.init_texture(dither_matrix_texture_id,
+                            8,
+                            8,
+                            ImageFormat::A8,
+                            TextureFilter::Nearest,
+                            RenderTargetMode::None,
+                            Some(&dither_matrix));
+
         let debug_renderer = DebugRenderer::new(&mut device);
 
         let gpu_data_textures = [
             GpuDataTextures::new(&mut device),
             GpuDataTextures::new(&mut device),
             GpuDataTextures::new(&mut device),
             GpuDataTextures::new(&mut device),
             GpuDataTextures::new(&mut device),
@@ -896,27 +928,29 @@ impl Renderer {
             backend_profile_counters: BackendProfileCounters::new(),
             profile_counters: RendererProfileCounters::new(),
             profiler: Profiler::new(),
             enable_profiler: options.enable_profiler,
             max_recorded_profiles: options.max_recorded_profiles,
             clear_framebuffer: options.clear_framebuffer,
             clear_color: options.clear_color,
             last_time: 0,
-            render_targets: Vec::new(),
+            color_render_targets: Vec::new(),
+            alpha_render_targets: Vec::new(),
             gpu_profile: gpu_profile,
             prim_vao_id: prim_vao_id,
             blur_vao_id: blur_vao_id,
             clip_vao_id: clip_vao_id,
             gdt_index: 0,
             gpu_data_textures: gpu_data_textures,
             pipeline_epoch_map: HashMap::with_hasher(Default::default()),
             main_thread_dispatcher: main_thread_dispatcher,
             cache_texture_id_map: Vec::new(),
             dummy_cache_texture_id: dummy_cache_texture_id,
+            dither_matrix_texture_id: dither_matrix_texture_id,
             external_image_handler: None,
             external_images: HashMap::with_hasher(Default::default()),
             vr_compositor_handler: vr_compositor,
             cpu_profiles: VecDeque::new(),
             gpu_profiles: VecDeque::new(),
         };
 
         let sender = RenderApiSender::new(api_tx, payload_tx);
@@ -1247,16 +1281,19 @@ impl Renderer {
         self.device.bind_vao(vao);
         self.device.bind_program(shader, projection);
 
         for i in 0..textures.colors.len() {
             let texture_id = self.resolve_source_texture(&textures.colors[i]);
             self.device.bind_texture(TextureSampler::color(i), texture_id);
         }
 
+        // TODO: this probably isn't the best place for this.
+        self.device.bind_texture(TextureSampler::Dither, self.dither_matrix_texture_id);
+
         self.device.update_vao_instances(vao, data, VertexUsageHint::Stream);
         self.device.draw_indexed_triangles_instanced_u16(6, data.len() as i32);
         self.profile_counters.vertices.add(6 * data.len());
         self.profile_counters.draw_calls.inc();
     }
 
     fn submit_batch(&mut self,
                     batch: &PrimitiveBatch,
@@ -1402,85 +1439,40 @@ impl Renderer {
                                           vao,
                                           shader,
                                           &batch.key.textures,
                                           projection);
             }
         }
     }
 
-    fn draw_target(&mut self,
-                   render_target: Option<(TextureId, i32)>,
-                   target: &RenderTarget,
-                   target_size: DeviceUintSize,
-                   cache_texture: TextureId,
-                   should_clear: bool,
-                   background_color: Option<ColorF>,
-                   render_task_data: &Vec<RenderTaskData>) {
-        self.device.disable_depth();
-        self.device.enable_depth_write();
-
-        let projection = {
+    fn draw_color_target(&mut self,
+                         render_target: Option<(TextureId, i32)>,
+                         target: &ColorRenderTarget,
+                         target_size: DeviceUintSize,
+                         color_cache_texture: TextureId,
+                         clear_color: Option<[f32; 4]>,
+                         render_task_data: &Vec<RenderTaskData>,
+                         projection: &Matrix4D<f32>) {
+        {
             let _gm = self.gpu_profile.add_marker(GPU_TAG_SETUP_TARGET);
             self.device.bind_draw_target(render_target, Some(target_size));
-
+            self.device.disable_depth();
+            self.device.enable_depth_write();
             self.device.set_blend(false);
             self.device.set_blend_mode_alpha();
-            self.device.bind_texture(TextureSampler::Cache, cache_texture);
-
-            let (color, projection) = match render_target {
-                Some(..) => (
-                    // The clear color here is chosen specifically such that:
-                    // - The red channel is cleared to 1, so that the clip mask
-                    //   generation (which reads/writes the red channel) can
-                    //   assume that each allocated rect is opaque / non-clipped
-                    //   initially.
-                    // - The alpha channel is cleared to 0, so that visual render
-                    //   tasks can assume that pixels are transparent if not
-                    //   rendered. (This is relied on by the compositing support
-                    //   for mix-blend-mode etc).
-                    [1.0, 1.0, 1.0, 0.0],
-                    Matrix4D::ortho(0.0,
-                                   target_size.width as f32,
-                                   0.0,
-                                   target_size.height as f32,
-                                   ORTHO_NEAR_PLANE,
-                                   ORTHO_FAR_PLANE)
-                ),
-                None => (
-                    background_color.map_or(self.clear_color.to_array(), |color| {
-                        color.to_array()
-                    }),
-                    Matrix4D::ortho(0.0,
-                                   target_size.width as f32,
-                                   target_size.height as f32,
-                                   0.0,
-                                   ORTHO_NEAR_PLANE,
-                                   ORTHO_FAR_PLANE)
-                ),
-            };
-
-            let clear_depth = Some(1.0);
-            let clear_color = if should_clear {
-                Some(color)
-            } else {
-                None
-            };
-
-            self.device.clear_target(clear_color, clear_depth);
+            self.device.clear_target(clear_color, Some(1.0));
 
             let isolate_clear_color = Some([0.0, 0.0, 0.0, 0.0]);
             for isolate_clear in &target.isolate_clears {
                 self.device.clear_target_rect(isolate_clear_color, None, *isolate_clear);
             }
 
-            projection
-        };
-
-        self.device.disable_depth_write();
+            self.device.disable_depth_write();
+        }
 
         // Draw any blurs for this target.
         // Blurs are rendered as a standard 2-pass
         // separable implementation.
         // TODO(gw): In the future, consider having
         //           fast path blur shaders for common
         //           blur radii with fixed weights.
         if !target.vertical_blurs.is_empty() || !target.horizontal_blurs.is_empty() {
@@ -1510,47 +1502,16 @@ impl Renderer {
             let shader = self.cs_box_shadow.get(&mut self.device).unwrap();
             self.draw_instanced_batch(&target.box_shadow_cache_prims,
                                       vao,
                                       shader,
                                       &BatchTextures::no_texture(),
                                       &projection);
         }
 
-        // Draw the clip items into the tiled alpha mask.
-        {
-            let _gm = self.gpu_profile.add_marker(GPU_TAG_CACHE_CLIP);
-            let vao = self.clip_vao_id;
-            // switch to multiplicative blending
-            self.device.set_blend(true);
-            self.device.set_blend_mode_multiply();
-            // draw rounded cornered rectangles
-            if !target.clip_batcher.rectangles.is_empty() {
-                let _gm2 = GpuMarker::new(self.device.rc_gl(), "clip rectangles");
-                let shader = self.cs_clip_rectangle.get(&mut self.device).unwrap();
-                self.draw_instanced_batch(&target.clip_batcher.rectangles,
-                                          vao,
-                                          shader,
-                                          &BatchTextures::no_texture(),
-                                          &projection);
-            }
-            // draw image masks
-            for (mask_texture_id, items) in target.clip_batcher.images.iter() {
-                let _gm2 = GpuMarker::new(self.device.rc_gl(), "clip images");
-                let texture_id = self.resolve_source_texture(mask_texture_id);
-                self.device.bind_texture(TextureSampler::Mask, texture_id);
-                let shader = self.cs_clip_image.get(&mut self.device).unwrap();
-                self.draw_instanced_batch(items,
-                                          vao,
-                                          shader,
-                                          &BatchTextures::no_texture(),
-                                          &projection);
-            }
-        }
-
         // Draw any textrun caches for this target. For now, this
         // is only used to cache text runs that are to be blurred
         // for text-shadow support. In the future it may be worth
         // considering using this for (some) other text runs, since
         // it removes the overhead of submitting many small glyphs
         // to multiple tiles in the normal text run case.
         if !target.text_run_cache_prims.is_empty() {
             self.device.set_blend(true);
@@ -1574,17 +1535,17 @@ impl Renderer {
         self.device.set_depth_func(DepthFunction::Less);
         self.device.enable_depth();
         self.device.enable_depth_write();
 
         for batch in &target.alpha_batcher.opaque_batches {
             self.submit_batch(batch,
                               &projection,
                               render_task_data,
-                              cache_texture,
+                              color_cache_texture,
                               render_target,
                               target_size);
         }
 
         self.device.disable_depth_write();
 
         for batch in &target.alpha_batcher.alpha_batches {
             if batch.key.blend_mode != prev_blend_mode {
@@ -1606,25 +1567,73 @@ impl Renderer {
                     }
                 }
                 prev_blend_mode = batch.key.blend_mode;
             }
 
             self.submit_batch(batch,
                               &projection,
                               render_task_data,
-                              cache_texture,
+                              color_cache_texture,
                               render_target,
                               target_size);
         }
 
         self.device.disable_depth();
         self.device.set_blend(false);
     }
 
+    fn draw_alpha_target(&mut self,
+                         render_target: (TextureId, i32),
+                         target: &AlphaRenderTarget,
+                         target_size: DeviceUintSize,
+                         projection: &Matrix4D<f32>) {
+        {
+            let _gm = self.gpu_profile.add_marker(GPU_TAG_SETUP_TARGET);
+            self.device.bind_draw_target(Some(render_target), Some(target_size));
+            self.device.disable_depth();
+            self.device.disable_depth_write();
+
+            let clear_color = [1.0, 1.0, 1.0, 0.0];
+            self.device.clear_target(Some(clear_color), None);
+        }
+
+        // Draw the clip items into the tiled alpha mask.
+        {
+            let _gm = self.gpu_profile.add_marker(GPU_TAG_CACHE_CLIP);
+            let vao = self.clip_vao_id;
+            // switch to multiplicative blending
+            self.device.set_blend(true);
+            self.device.set_blend_mode_multiply();
+
+            // draw rounded cornered rectangles
+            if !target.clip_batcher.rectangles.is_empty() {
+                let _gm2 = GpuMarker::new(self.device.rc_gl(), "clip rectangles");
+                let shader = self.cs_clip_rectangle.get(&mut self.device).unwrap();
+                self.draw_instanced_batch(&target.clip_batcher.rectangles,
+                                          vao,
+                                          shader,
+                                          &BatchTextures::no_texture(),
+                                          &projection);
+            }
+            // draw image masks
+            for (mask_texture_id, items) in target.clip_batcher.images.iter() {
+                let _gm2 = GpuMarker::new(self.device.rc_gl(), "clip images");
+                let texture_id = self.resolve_source_texture(mask_texture_id);
+                self.device.bind_texture(TextureSampler::Mask, texture_id);
+                let shader = self.cs_clip_image.get(&mut self.device).unwrap();
+                self.draw_instanced_batch(items,
+                                          vao,
+                                          shader,
+                                          &BatchTextures::no_texture(),
+                                          &projection);
+            }
+        }
+    }
+
     fn update_deferred_resolves(&mut self, frame: &mut Frame) {
         // The first thing we do is run through any pending deferred
         // resolves, and use a callback to get the UV rect for this
         // custom item. Then we patch the resource_rects structure
         // here before it's uploaded to the GPU.
         if !frame.deferred_resolves.is_empty() {
             let handler = self.external_image_handler
                               .as_mut()
@@ -1689,72 +1698,143 @@ impl Renderer {
 
         self.device.disable_depth_write();
         self.device.disable_stencil();
         self.device.set_blend(false);
 
         if frame.passes.is_empty() {
             self.device.clear_target(Some(self.clear_color.to_array()), Some(1.0));
         } else {
-            // Add new render targets to the pool if required.
-            let needed_targets = frame.passes.len() - 1;     // framebuffer doesn't need a target!
-            let current_target_count = self.render_targets.len();
-            if needed_targets > current_target_count {
-                let new_target_count = needed_targets - current_target_count;
-                let new_targets = self.device.create_texture_ids(new_target_count as i32,
-                                                                 TextureTarget::Array);
-                self.render_targets.extend_from_slice(&new_targets);
+            // Assign render targets to the passes.
+            for pass in &mut frame.passes {
+                debug_assert!(pass.color_texture_id.is_none());
+                debug_assert!(pass.alpha_texture_id.is_none());
+
+                if pass.needs_render_target_kind(RenderTargetKind::Color) {
+                    pass.color_texture_id = Some(self.color_render_targets
+                                                     .pop()
+                                                     .unwrap_or_else(|| {
+                                                         self.device
+                                                             .create_texture_ids(1, TextureTarget::Array)[0]
+                                                      }));
+                }
+
+                if pass.needs_render_target_kind(RenderTargetKind::Alpha) {
+                    pass.alpha_texture_id = Some(self.alpha_render_targets
+                                                     .pop()
+                                                     .unwrap_or_else(|| {
+                                                         self.device
+                                                             .create_texture_ids(1, TextureTarget::Array)[0]
+                                                      }));
+                }
             }
 
             // Init textures and render targets to match this scene.
-            for (pass, texture_id) in frame.passes.iter().zip(self.render_targets.iter()) {
-                self.device.init_texture(*texture_id,
-                                         frame.cache_size.width as u32,
-                                         frame.cache_size.height as u32,
-                                         ImageFormat::RGBA8,
-                                         TextureFilter::Linear,
-                                         RenderTargetMode::LayerRenderTarget(pass.targets.len() as i32),
-                                         None);
+            for pass in &frame.passes {
+                if let Some(texture_id) = pass.color_texture_id {
+                    let target_count = pass.required_target_count(RenderTargetKind::Color);
+                    self.device.init_texture(texture_id,
+                                             frame.cache_size.width as u32,
+                                             frame.cache_size.height as u32,
+                                             ImageFormat::RGBA8,
+                                             TextureFilter::Linear,
+                                             RenderTargetMode::LayerRenderTarget(target_count as i32),
+                                             None);
+                }
+                if let Some(texture_id) = pass.alpha_texture_id {
+                    let target_count = pass.required_target_count(RenderTargetKind::Alpha);
+                    self.device.init_texture(texture_id,
+                                             frame.cache_size.width as u32,
+                                             frame.cache_size.height as u32,
+                                             ImageFormat::A8,
+                                             TextureFilter::Nearest,
+                                             RenderTargetMode::LayerRenderTarget(target_count as i32),
+                                             None);
+                }
             }
 
             // TODO(gw): This is a hack / workaround for #728.
             // We should find a better way to implement these updates rather
             // than wasting this extra memory, but for now it removes a large
             // number of driver stalls.
             self.gpu_data_textures[self.gdt_index].init_frame(&mut self.device, frame);
             self.gdt_index = (self.gdt_index + 1) % GPU_DATA_TEXTURE_POOL;
 
-            let mut src_id = self.dummy_cache_texture_id;
+            let mut src_color_id = self.dummy_cache_texture_id;
+            let mut src_alpha_id = self.dummy_cache_texture_id;
+
+            for pass in &mut frame.passes {
+                let size;
+                let clear_color;
+                let projection;
 
-            for (pass_index, pass) in frame.passes.iter().enumerate() {
-                let (do_clear, size, target_id) = if pass.is_framebuffer {
-                    (self.clear_framebuffer || needs_clear,
-                     framebuffer_size,
-                     None)
+                if pass.is_framebuffer {
+                    clear_color = if self.clear_framebuffer || needs_clear {
+                        Some(frame.background_color.map_or(self.clear_color.to_array(), |color| {
+                            color.to_array()
+                        }))
+                    } else {
+                        None
+                    };
+                    size = framebuffer_size;
+                    projection = Matrix4D::ortho(0.0,
+                                                 size.width as f32,
+                                                 size.height as f32,
+                                                 0.0,
+                                                 ORTHO_NEAR_PLANE,
+                                                 ORTHO_FAR_PLANE)
                 } else {
-                    (true, &frame.cache_size, Some(self.render_targets[pass_index]))
-                };
+                    size = &frame.cache_size;
+                    clear_color = Some([1.0, 1.0, 1.0, 0.0]);
+                    projection = Matrix4D::ortho(0.0,
+                                                 size.width as f32,
+                                                 0.0,
+                                                 size.height as f32,
+                                                 ORTHO_NEAR_PLANE,
+                                                 ORTHO_FAR_PLANE);
+                }
 
-                for (target_index, target) in pass.targets.iter().enumerate() {
-                    let render_target = target_id.map(|texture_id| {
+                self.device.bind_texture(TextureSampler::CacheA8, src_alpha_id);
+                self.device.bind_texture(TextureSampler::CacheRGBA8, src_color_id);
+
+                for (target_index, target) in pass.alpha_targets.targets.iter().enumerate() {
+                    self.draw_alpha_target((pass.alpha_texture_id.unwrap(), target_index as i32),
+                                           target,
+                                           *size,
+                                           &projection);
+                }
+
+                for (target_index, target) in pass.color_targets.targets.iter().enumerate() {
+                    let render_target = pass.color_texture_id.map(|texture_id| {
                         (texture_id, target_index as i32)
                     });
-                    self.draw_target(render_target,
-                                     target,
-                                     *size,
-                                     src_id,
-                                     do_clear,
-                                     frame.background_color,
-                                     &frame.render_task_data);
+                    self.draw_color_target(render_target,
+                                           target,
+                                           *size,
+                                           src_color_id,
+                                           clear_color,
+                                           &frame.render_task_data,
+                                           &projection);
 
                 }
 
-                src_id = target_id.unwrap_or(self.dummy_cache_texture_id);
+                src_color_id = pass.color_texture_id.unwrap_or(self.dummy_cache_texture_id);
+                src_alpha_id = pass.alpha_texture_id.unwrap_or(self.dummy_cache_texture_id);
+
+                // Return the texture IDs to the pool for next frame.
+                if let Some(texture_id) = pass.color_texture_id.take() {
+                    self.color_render_targets.push(texture_id);
+                }
+                if let Some(texture_id) = pass.alpha_texture_id.take() {
+                    self.alpha_render_targets.push(texture_id);
+                }
             }
 
+            self.color_render_targets.reverse();
+            self.alpha_render_targets.reverse();
             self.draw_render_target_debug(framebuffer_size);
         }
 
         self.unlock_external_images();
     }
 
     pub fn debug_renderer<'a>(&'a mut self) -> &'a mut DebugRenderer {
         &mut self.debug
@@ -1779,17 +1859,17 @@ impl Renderer {
             // Right now, it just draws them in one row at the bottom of the screen,
             // with a fixed size.
             let rt_debug_x0 = 16;
             let rt_debug_y0 = 16;
             let rt_debug_spacing = 16;
             let rt_debug_size = 512;
             let mut current_target = 0;
 
-            for texture_id in &self.render_targets {
+            for texture_id in self.color_render_targets.iter().chain(self.alpha_render_targets.iter()) {
                 let layer_count = self.device.get_render_target_layer_count(*texture_id);
                 for layer_index in 0..layer_count {
                     let x0 = rt_debug_x0 + (rt_debug_spacing + rt_debug_size) * current_target;
                     let y0 = rt_debug_y0;
 
                     // If we have more targets than fit on one row in screen, just early exit.
                     if x0 > framebuffer_size.width as i32 {
                         return;
--- a/gfx/webrender/src/resource_cache.rs
+++ b/gfx/webrender/src/resource_cache.rs
@@ -18,17 +18,17 @@ use std::hash::Hash;
 use std::mem;
 use std::sync::{Arc, Barrier, Mutex};
 use std::sync::mpsc::{channel, Receiver, Sender};
 use std::thread;
 use texture_cache::{TextureCache, TextureCacheItemId};
 use thread_profiler::register_thread_with_profiler;
 use webrender_traits::{Epoch, FontKey, GlyphKey, ImageKey, ImageFormat, ImageRendering};
 use webrender_traits::{FontRenderMode, ImageData, GlyphDimensions, WebGLContextId};
-use webrender_traits::{DevicePoint, DeviceIntSize, ImageDescriptor, ColorF};
+use webrender_traits::{DevicePoint, DeviceIntSize, DeviceUintRect, ImageDescriptor, ColorF};
 use webrender_traits::{ExternalImageId, GlyphOptions, GlyphInstance, TileOffset, TileSize};
 use webrender_traits::{BlobImageRenderer, BlobImageDescriptor, BlobImageError};
 use threadpool::ThreadPool;
 use euclid::Point2D;
 
 thread_local!(pub static FONT_CONTEXT: RefCell<FontContext> = RefCell::new(FontContext::new()));
 
 type GlyphCache = ResourceClassCache<RenderedGlyphKey, Option<TextureCacheItemId>>;
@@ -105,16 +105,17 @@ enum State {
     QueryResources,
 }
 
 struct ImageResource {
     data: ImageData,
     descriptor: ImageDescriptor,
     epoch: Epoch,
     tiling: Option<TileSize>,
+    dirty_rect: Option<DeviceUintRect>
 }
 
 struct CachedImageInfo {
     texture_cache_id: TextureCacheItemId,
     epoch: Epoch,
 }
 
 pub struct ResourceClassCache<K,V> {
@@ -280,48 +281,55 @@ impl ResourceCache {
             tiling = Some(512);
         }
 
         let resource = ImageResource {
             descriptor: descriptor,
             data: data,
             epoch: Epoch(0),
             tiling: tiling,
+            dirty_rect: None,
         };
 
         self.image_templates.insert(image_key, resource);
     }
 
     pub fn update_image_template(&mut self,
                                  image_key: ImageKey,
                                  descriptor: ImageDescriptor,
-                                 bytes: Vec<u8>) {
-        let next_epoch = match self.image_templates.get(&image_key) {
+                                 bytes: Vec<u8>,
+                                 dirty_rect: Option<DeviceUintRect>) {
+        let (next_epoch, prev_dirty_rect) = match self.image_templates.get(&image_key) {
             Some(image) => {
                 // This image should not be an external image.
                 match image.data {
                     ImageData::ExternalHandle(id) => {
                         panic!("Update an external image with buffer, id={} image_key={:?}", id.0, image_key);
                     },
                     _ => {},
                 }
 
                 let Epoch(current_epoch) = image.epoch;
-                Epoch(current_epoch + 1)
+                (Epoch(current_epoch + 1), image.dirty_rect)
             }
             None => {
-                Epoch(0)
+                (Epoch(0), None)
             }
         };
 
         let resource = ImageResource {
             descriptor: descriptor,
             data: ImageData::new(bytes),
             epoch: next_epoch,
             tiling: None,
+            dirty_rect: match (dirty_rect, prev_dirty_rect) {
+                (Some(rect), Some(prev_rect)) => Some(rect.union(&prev_rect)),
+                (Some(rect), None) => Some(rect),
+                _ => None,
+            },
         };
 
         self.image_templates.insert(image_key, resource);
     }
 
     pub fn delete_image_template(&mut self, image_key: ImageKey) {
         let value = self.image_templates.remove(&image_key);
 
@@ -643,17 +651,17 @@ impl ResourceCache {
             }
         }
     }
 
     fn finalize_image_request(&mut self,
                               request: ImageRequest,
                               image_data: Option<ImageData>,
                               texture_cache_profile: &mut TextureCacheProfileCounters) {
-        let image_template = &self.image_templates[&request.key];
+        let image_template = self.image_templates.get_mut(&request.key).unwrap();
         let image_data = image_data.unwrap_or_else(||{
             image_template.data.clone()
         });
 
         match image_template.data {
             ImageData::ExternalHandle(..) => {
                 // external handle doesn't need to update the texture_cache.
             }
@@ -695,23 +703,25 @@ impl ResourceCache {
 
                 match self.cached_images.entry(request.clone(), self.current_frame_id) {
                     Occupied(entry) => {
                         let image_id = entry.get().texture_cache_id;
 
                         if entry.get().epoch != image_template.epoch {
                             self.texture_cache.update(image_id,
                                                       descriptor,
-                                                      image_data);
+                                                      image_data,
+                                                      image_template.dirty_rect);
 
                             // Update the cached epoch
                             *entry.into_mut() = CachedImageInfo {
                                 texture_cache_id: image_id,
                                 epoch: image_template.epoch,
                             };
+                            image_template.dirty_rect = None;
                         }
                     }
                     Vacant(entry) => {
                         let image_id = self.texture_cache.new_item_id();
 
                         let filter = match request.rendering {
                             ImageRendering::Pixelated => TextureFilter::Nearest,
                             ImageRendering::Auto | ImageRendering::CrispEdges => TextureFilter::Linear,
--- a/gfx/webrender/src/texture_cache.rs
+++ b/gfx/webrender/src/texture_cache.rs
@@ -701,39 +701,54 @@ impl TextureCache {
             item: cache_item,
             kind: AllocationKind::TexturePage,
         }
     }
 
     pub fn update(&mut self,
                   image_id: TextureCacheItemId,
                   descriptor: ImageDescriptor,
-                  data: ImageData) {
+                  data: ImageData,
+                  dirty_rect: Option<DeviceUintRect>) {
         let existing_item = self.items.get(image_id);
 
         // TODO(gw): Handle updates to size/format!
         debug_assert_eq!(existing_item.allocated_rect.size.width, descriptor.width);
         debug_assert_eq!(existing_item.allocated_rect.size.height, descriptor.height);
 
         let op = match data {
             ImageData::ExternalHandle(..) | ImageData::ExternalBuffer(..)=> {
                 panic!("Doesn't support Update() for external image.");
             }
             ImageData::Blob(..) => {
                 panic!("The vector image should have been rasterized into a raw image.");
             }
             ImageData::Raw(bytes) => {
-                TextureUpdateOp::Update {
-                    page_pos_x: existing_item.allocated_rect.origin.x,
-                    page_pos_y: existing_item.allocated_rect.origin.y,
-                    width: descriptor.width,
-                    height: descriptor.height,
-                    data: bytes,
-                    stride: descriptor.stride,
-                    offset: descriptor.offset,
+                if let Some(dirty) = dirty_rect {
+                    let stride = descriptor.compute_stride();
+                    let offset = descriptor.offset + dirty.origin.y * stride + dirty.origin.x;
+                    TextureUpdateOp::Update {
+                        page_pos_x: existing_item.allocated_rect.origin.x + dirty.origin.x,
+                        page_pos_y: existing_item.allocated_rect.origin.y + dirty.origin.y,
+                        width: dirty.size.width,
+                        height: dirty.size.height,
+                        data: bytes,
+                        stride: Some(stride),
+                        offset: offset,
+                    }
+                } else {
+                    TextureUpdateOp::Update {
+                        page_pos_x: existing_item.allocated_rect.origin.x,
+                        page_pos_y: existing_item.allocated_rect.origin.y,
+                        width: descriptor.width,
+                        height: descriptor.height,
+                        data: bytes,
+                        stride: descriptor.stride,
+                        offset: descriptor.offset,
+                    }
                 }
             }
         };
 
         let update_op = TextureUpdate {
             id: existing_item.texture_id,
             op: op,
         };
--- a/gfx/webrender/src/tiling.rs
+++ b/gfx/webrender/src/tiling.rs
@@ -1,13 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use app_units::Au;
+use device::TextureId;
 use fnv::FnvHasher;
 use gpu_store::GpuStoreAddress;
 use internal_types::{ANGLE_FLOAT_TO_FIXED, BatchTextures, CacheTextureId, LowLevelFilterOp};
 use internal_types::SourceTexture;
 use mask_cache::MaskCacheInfo;
 use prim_store::{CLIP_DATA_GPU_SIZE, DeferredResolve, GpuBlock128, GpuBlock16, GpuBlock32};
 use prim_store::{GpuBlock64, GradientData, PrimitiveCacheKey, PrimitiveGeometry, PrimitiveIndex};
 use prim_store::{PrimitiveKind, PrimitiveMetadata, PrimitiveStore, TexelRect};
@@ -123,17 +124,20 @@ impl AlphaBatchHelpers for PrimitiveStor
                         FontRenderMode::Subpixel => BlendMode::Subpixel(text_run_cpu.color),
                         FontRenderMode::Alpha | FontRenderMode::Mono => BlendMode::Alpha,
                     }
                 } else {
                     // Text runs drawn to blur never get drawn with subpixel AA.
                     BlendMode::Alpha
                 }
             }
-            PrimitiveKind::Image => {
+            PrimitiveKind::Image |
+            PrimitiveKind::AlignedGradient |
+            PrimitiveKind::AngleGradient |
+            PrimitiveKind::RadialGradient => {
                 if needs_blending {
                     BlendMode::PremultipliedAlpha
                 } else {
                     BlendMode::None
                 }
             }
             _ => {
                 if needs_blending {
@@ -408,28 +412,21 @@ pub enum PrimitiveRunCmd {
 }
 
 #[derive(Debug, Copy, Clone)]
 pub enum PrimitiveFlags {
     None,
     Scrollbar(ScrollLayerId, f32)
 }
 
-// TODO(gw): I've had to make several of these types below public
-//           with the changes for text-shadow. The proper solution
-//           is to split the render task and render target code into
-//           its own module. However, I'm avoiding that for now since
-//           this PR is large enough already, and other people are working
-//           on PRs that make use of render tasks.
-
 #[derive(Debug, Copy, Clone)]
 pub struct RenderTargetIndex(pub usize);
 
 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
-struct RenderPassIndex(isize);
+pub struct RenderPassIndex(isize);
 
 struct DynamicTaskInfo {
     index: RenderTaskIndex,
     rect: DeviceIntRect,
 }
 
 pub struct RenderTaskCollection {
     pub render_task_data: Vec<RenderTaskData>,
@@ -852,20 +849,99 @@ impl ClipBatcher {
 
 pub struct RenderTargetContext<'a> {
     pub stacking_context_store: &'a [StackingContext],
     pub clip_scroll_group_store: &'a [ClipScrollGroup],
     pub prim_store: &'a PrimitiveStore,
     pub resource_cache: &'a ResourceCache,
 }
 
+pub trait RenderTarget {
+    fn new(size: DeviceUintSize) -> Self;
+    fn allocate(&mut self, size: DeviceUintSize) -> Option<DeviceUintPoint>;
+    fn build(&mut self,
+             _ctx: &RenderTargetContext,
+             _render_tasks: &mut RenderTaskCollection,
+             _child_pass_index: RenderPassIndex) {}
+    fn add_task(&mut self,
+                task: RenderTask,
+                ctx: &RenderTargetContext,
+                render_tasks: &RenderTaskCollection,
+                pass_index: RenderPassIndex);
+}
+
+#[derive(Debug, Copy, Clone)]
+pub enum RenderTargetKind {
+    Color,   // RGBA32
+    Alpha,   // R8
+}
+
+pub struct RenderTargetList<T> {
+    target_size: DeviceUintSize,
+    pub targets: Vec<T>,
+}
+
+impl<T: RenderTarget> RenderTargetList<T> {
+    fn new(target_size: DeviceUintSize, create_initial_target: bool) -> RenderTargetList<T> {
+        let mut targets = Vec::new();
+        if create_initial_target {
+            targets.push(T::new(target_size));
+        }
+
+        RenderTargetList {
+            targets: targets,
+            target_size: target_size,
+        }
+    }
+
+    pub fn target_count(&self) -> usize {
+        self.targets.len()
+    }
+
+    fn build(&mut self,
+             ctx: &RenderTargetContext,
+             render_tasks: &mut RenderTaskCollection,
+             pass_index: RenderPassIndex) {
+        for target in &mut self.targets {
+            let child_pass_index = RenderPassIndex(pass_index.0 - 1);
+            target.build(ctx, render_tasks, child_pass_index);
+        }
+    }
+
+    fn add_task(&mut self,
+                task: RenderTask,
+                ctx: &RenderTargetContext,
+                render_tasks: &mut RenderTaskCollection,
+                pass_index: RenderPassIndex) {
+        self.targets.last_mut().unwrap().add_task(task, ctx, render_tasks, pass_index);
+    }
+
+    fn allocate(&mut self, alloc_size: DeviceUintSize) -> (DeviceUintPoint, RenderTargetIndex) {
+        let existing_origin = self.targets
+                                  .last_mut()
+                                  .and_then(|target| target.allocate(alloc_size));
+
+        let origin = match existing_origin {
+            Some(origin) => origin,
+            None => {
+                let mut new_target = T::new(self.target_size);
+                let origin = new_target.allocate(alloc_size)
+                                       .expect(&format!("Each render task must allocate <= size of one target! ({:?})", alloc_size));
+                self.targets.push(new_target);
+                origin
+            }
+        };
+
+        (origin, RenderTargetIndex(self.targets.len() - 1))
+    }
+}
+
 /// A render target represents a number of rendering operations on a surface.
-pub struct RenderTarget {
+pub struct ColorRenderTarget {
     pub alpha_batcher: AlphaBatcher,
-    pub clip_batcher: ClipBatcher,
     pub box_shadow_cache_prims: Vec<PrimitiveInstance>,
     // List of text runs to be cached to this render target.
     // TODO(gw): For now, assume that these all come from
     //           the same source texture id. This is almost
     //           always true except for pathological test
     //           cases with more than 4k x 4k of unique
     //           glyphs visible. Once the future glyph / texture
     //           cache changes land, this restriction will
@@ -875,21 +951,24 @@ pub struct RenderTarget {
     // List of blur operations to apply for this render target.
     pub vertical_blurs: Vec<BlurCommand>,
     pub horizontal_blurs: Vec<BlurCommand>,
     pub readbacks: Vec<DeviceIntRect>,
     pub isolate_clears: Vec<DeviceIntRect>,
     page_allocator: TexturePage,
 }
 
-impl RenderTarget {
-    fn new(size: DeviceUintSize) -> RenderTarget {
-        RenderTarget {
+impl RenderTarget for ColorRenderTarget {
+    fn allocate(&mut self, size: DeviceUintSize) -> Option<DeviceUintPoint> {
+        self.page_allocator.allocate(&size)
+    }
+
+    fn new(size: DeviceUintSize) -> ColorRenderTarget {
+        ColorRenderTarget {
             alpha_batcher: AlphaBatcher::new(),
-            clip_batcher: ClipBatcher::new(),
             box_shadow_cache_prims: Vec::new(),
             text_run_cache_prims: Vec::new(),
             text_run_textures: BatchTextures::no_texture(),
             vertical_blurs: Vec::new(),
             horizontal_blurs: Vec::new(),
             readbacks: Vec::new(),
             isolate_clears: Vec::new(),
             page_allocator: TexturePage::new(CacheTextureId(0), size),
@@ -1003,84 +1082,142 @@ impl RenderTarget {
                         }
                     }
                     _ => {
                         // No other primitives make use of primitive caching yet!
                         unreachable!()
                     }
                 }
             }
+            RenderTaskKind::CacheMask(..) => {
+                panic!("Should not be added to color target!");
+            }
+            RenderTaskKind::Readback(device_rect) => {
+                self.readbacks.push(device_rect);
+            }
+        }
+    }
+}
+
+pub struct AlphaRenderTarget {
+    pub clip_batcher: ClipBatcher,
+    page_allocator: TexturePage,
+}
+
+impl RenderTarget for AlphaRenderTarget {
+    fn allocate(&mut self, size: DeviceUintSize) -> Option<DeviceUintPoint> {
+        self.page_allocator.allocate(&size)
+    }
+
+    fn new(size: DeviceUintSize) -> AlphaRenderTarget {
+        AlphaRenderTarget {
+            clip_batcher: ClipBatcher::new(),
+            page_allocator: TexturePage::new(CacheTextureId(0), size),
+        }
+    }
+
+    fn add_task(&mut self,
+                task: RenderTask,
+                ctx: &RenderTargetContext,
+                render_tasks: &RenderTaskCollection,
+                pass_index: RenderPassIndex) {
+        match task.kind {
+            RenderTaskKind::Alpha(..) |
+            RenderTaskKind::VerticalBlur(..) |
+            RenderTaskKind::HorizontalBlur(..) |
+            RenderTaskKind::CachePrimitive(..) |
+            RenderTaskKind::Readback(..) => {
+                panic!("Should not be added to alpha target!");
+            }
             RenderTaskKind::CacheMask(ref task_info) => {
                 let task_index = render_tasks.get_task_index(&task.id, pass_index);
                 self.clip_batcher.add(task_index,
                                       &task_info.clips,
                                       &ctx.resource_cache,
                                       task_info.geometry_kind);
             }
-            RenderTaskKind::Readback(device_rect) => {
-                self.readbacks.push(device_rect);
-            }
         }
     }
 }
 
 /// A render pass represents a set of rendering operations that don't depend on one
 /// another.
 ///
 /// A render pass can have several render targets if there wasn't enough space in one
 /// target to do all of the rendering for that pass.
 pub struct RenderPass {
     pass_index: RenderPassIndex,
     pub is_framebuffer: bool,
     tasks: Vec<RenderTask>,
-    pub targets: Vec<RenderTarget>,
-    size: DeviceUintSize,
+    pub color_targets: RenderTargetList<ColorRenderTarget>,
+    pub alpha_targets: RenderTargetList<AlphaRenderTarget>,
+    pub color_texture_id: Option<TextureId>,
+    pub alpha_texture_id: Option<TextureId>,
 }
 
 impl RenderPass {
     pub fn new(pass_index: isize, is_framebuffer: bool, size: DeviceUintSize) -> RenderPass {
         RenderPass {
             pass_index: RenderPassIndex(pass_index),
             is_framebuffer: is_framebuffer,
-            targets: vec![ RenderTarget::new(size) ],
+            color_targets: RenderTargetList::new(size, is_framebuffer),
+            alpha_targets: RenderTargetList::new(size, false),
             tasks: vec![],
-            size: size,
+            color_texture_id: None,
+            alpha_texture_id: None,
         }
     }
 
     pub fn add_render_task(&mut self, task: RenderTask) {
         self.tasks.push(task);
     }
 
-    fn allocate_target(&mut self, alloc_size: DeviceUintSize) -> DeviceUintPoint {
-        let existing_origin = self.targets
-                                  .last_mut()
-                                  .unwrap()
-                                  .page_allocator
-                                  .allocate(&alloc_size);
-        match existing_origin {
-            Some(origin) => origin,
-            None => {
-                let mut new_target = RenderTarget::new(self.size);
-                let origin = new_target.page_allocator
-                                       .allocate(&alloc_size)
-                                       .expect(&format!("Each render task must allocate <= size of one target! ({:?})", alloc_size));
-                self.targets.push(new_target);
-                origin
-            }
+    fn add_task(&mut self,
+                task: RenderTask,
+                ctx: &RenderTargetContext,
+                render_tasks: &mut RenderTaskCollection) {
+        match task.target_kind() {
+            RenderTargetKind::Color => self.color_targets.add_task(task, ctx, render_tasks, self.pass_index),
+            RenderTargetKind::Alpha => self.alpha_targets.add_task(task, ctx, render_tasks, self.pass_index),
         }
     }
 
+    fn allocate_target(&mut self,
+                       kind: RenderTargetKind,
+                       alloc_size: DeviceUintSize) -> (DeviceUintPoint, RenderTargetIndex) {
+        match kind {
+            RenderTargetKind::Color => self.color_targets.allocate(alloc_size),
+            RenderTargetKind::Alpha => self.alpha_targets.allocate(alloc_size),
+        }
+    }
+
+    pub fn needs_render_target_kind(&self, kind: RenderTargetKind) -> bool {
+        if self.is_framebuffer {
+            false
+        } else {
+            self.required_target_count(kind) > 0
+        }
+    }
+
+    pub fn required_target_count(&self, kind: RenderTargetKind) -> usize {
+        debug_assert!(!self.is_framebuffer);        // framebuffer never needs targets
+        match kind {
+            RenderTargetKind::Color => self.color_targets.target_count(),
+            RenderTargetKind::Alpha => self.alpha_targets.target_count(),
+        }
+    }
 
     pub fn build(&mut self, ctx: &RenderTargetContext, render_tasks: &mut RenderTaskCollection) {
         profile_scope!("RenderPass::build");
 
         // Step through each task, adding to batches as appropriate.
         let tasks = mem::replace(&mut self.tasks, Vec::new());
         for mut task in tasks {
+            let target_kind = task.target_kind();
+
             // Find a target to assign this task to, or create a new
             // one if required.
             match task.location {
                 RenderTaskLocation::Fixed => {}
                 RenderTaskLocation::Dynamic(ref mut origin, ref size) => {
                     // See if this task is a duplicate.
                     // If so, just skip adding it!
                     match task.id {
@@ -1093,35 +1230,30 @@ impl RenderPass {
                             if let Some(rect) = render_tasks.get_dynamic_allocation(self.pass_index, key) {
                                 debug_assert_eq!(rect.size, *size);
                                 continue;
                             }
                         }
                     }
 
                     let alloc_size = DeviceUintSize::new(size.width as u32, size.height as u32);
-                    let alloc_origin = self.allocate_target(alloc_size);
+                    let (alloc_origin, target_index) = self.allocate_target(target_kind, alloc_size);
 
                     *origin = Some((DeviceIntPoint::new(alloc_origin.x as i32,
-                                                     alloc_origin.y as i32),
-                                    RenderTargetIndex(self.targets.len() - 1)));
+                                                        alloc_origin.y as i32),
+                                    target_index));
                 }
             }
 
             render_tasks.add(&task, self.pass_index);
-            self.targets.last_mut().unwrap().add_task(task,
-                                                      ctx,
-                                                      render_tasks,
-                                                      self.pass_index);
+            self.add_task(task, ctx, render_tasks);
         }
 
-        for target in &mut self.targets {
-            let child_pass_index = RenderPassIndex(self.pass_index.0 - 1);
-            target.build(ctx, render_tasks, child_pass_index);
-        }
+        self.color_targets.build(ctx, render_tasks, self.pass_index);
+        self.alpha_targets.build(ctx, render_tasks, self.pass_index);
     }
 }
 
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
 #[repr(u8)]
 pub enum AlphaBatchKind {
     Composite = 0,
     HardwareComposite,
@@ -1319,46 +1451,46 @@ pub struct StackingContextIndex(pub usiz
 #[derive(Debug)]
 pub struct StackingContext {
     pub pipeline_id: PipelineId,
 
     // Offset in the parent reference frame to the origin of this stacking
     // context's coordinate system.
     pub reference_frame_offset: LayerPoint,
 
-    // Bounds of this stacking context in its own coordinate system.
-    pub local_rect: LayerRect,
+    // Bounding rectangle for this stacking context calculated based on the size
+    // and position of all its children.
+    pub bounding_rect: DeviceIntRect,
 
-    pub bounding_rect: DeviceIntRect,
     pub composite_ops: CompositeOps,
     pub clip_scroll_groups: Vec<ClipScrollGroupIndex>,
 
     // Signifies that this stacking context should be drawn in a separate render pass
     // with a transparent background and then composited back to its parent. Used to
     // support mix-blend-mode in certain cases.
     pub should_isolate: bool,
 
     // Set for the root stacking context of a display list or an iframe. Used for determining
     // when to isolate a mix-blend-mode composite.
     pub is_page_root: bool,
 
+    // Wehther or not this stacking context has any visible components, calculated
+    // based on the size and position of all children and how they are clipped.
     pub is_visible: bool,
 }
 
 impl StackingContext {
     pub fn new(pipeline_id: PipelineId,
                reference_frame_offset: LayerPoint,
-               local_rect: LayerRect,
                is_page_root: bool,
                composite_ops: CompositeOps)
                -> StackingContext {
         StackingContext {
             pipeline_id: pipeline_id,
             reference_frame_offset: reference_frame_offset,
-            local_rect: local_rect,
             bounding_rect: DeviceIntRect::zero(),
             composite_ops: composite_ops,
             clip_scroll_groups: Vec::new(),
             should_isolate: false,
             is_page_root: is_page_root,
             is_visible: false,
         }
     }
@@ -1427,32 +1559,27 @@ impl PackedLayer {
     }
 
     pub fn set_transform(&mut self, transform: LayerToWorldTransform) {
         self.transform = transform;
         self.inv_transform = self.transform.inverse().unwrap();
     }
 
     pub fn set_rect(&mut self,
-                    local_rect: Option<LayerRect>,
+                    local_rect: &LayerRect,
                     screen_rect: &DeviceIntRect,
                     device_pixel_ratio: f32)
                     -> Option<TransformedRect> {
-        let local_rect = match local_rect {
-            Some(rect) if !rect.is_empty() => rect,
-            _ => return None,
-        };
-
         let xf_rect = TransformedRect::new(&local_rect, &self.transform, device_pixel_ratio);
         if !xf_rect.bounding_rect.intersects(screen_rect) {
             return None;
         }
 
         self.screen_vertices = xf_rect.vertices.clone();
-        self.local_clip_rect = local_rect;
+        self.local_clip_rect = *local_rect;
         Some(xf_rect)
     }
 }
 
 #[derive(Debug, Clone)]
 pub struct CompositeOps {
     // Requires only a single texture as input (e.g. most filters)
     pub filters: Vec<LowLevelFilterOp>,
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/src/webgl_stubs.rs
@@ -0,0 +1,59 @@
+/* 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/. */
+
+//! Stubs for the types contained in webgl_types.rs
+//!
+//! The API surface provided here should be roughly the same to the one provided
+//! in webgl_types, modulo completely compiled-out stuff.
+
+use webrender_traits::DeviceIntSize;
+use webrender_traits::{GLContextAttributes, GLLimits};
+use webrender_traits::WebGLCommand;
+
+pub struct GLContextHandleWrapper;
+
+impl GLContextHandleWrapper {
+    pub fn new_context(&self,
+                       _: DeviceIntSize,
+                       _: GLContextAttributes,
+                       _: Option<Box<GLContextDispatcher>>) -> Result<GLContextWrapper, &'static str> {
+        unreachable!()
+    }
+
+    pub fn current_native_handle() -> Option<GLContextHandleWrapper> {
+        None
+    }
+
+    pub fn current_osmesa_handle() -> Option<GLContextHandleWrapper> {
+        None
+    }
+}
+
+pub struct GLContextWrapper;
+
+impl GLContextWrapper {
+    pub fn make_current(&self) {
+        unreachable!()
+    }
+
+    pub fn unbind(&self) {
+        unreachable!()
+    }
+
+    pub fn apply_command(&self, _: WebGLCommand) {
+        unreachable!()
+    }
+
+    pub fn get_info(&self) -> (DeviceIntSize, u32, GLLimits) {
+        unreachable!()
+    }
+
+    pub fn resize(&mut self, _: &DeviceIntSize) -> Result<(), &'static str> {
+        unreachable!()
+    }
+}
+
+pub trait GLContextDispatcher {
+    fn dispatch(&self, Box<Fn() + Send>);
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/src/webgl_types.rs
@@ -0,0 +1,130 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+//! A set of WebGL-related types, in their own module so it's easy to
+//! compile it off.
+
+use gleam::gl;
+use offscreen_gl_context::{NativeGLContext, NativeGLContextHandle};
+use offscreen_gl_context::{GLContext, NativeGLContextMethods, GLContextDispatcher};
+use offscreen_gl_context::{OSMesaContext, OSMesaContextHandle};
+use offscreen_gl_context::{ColorAttachmentType, GLContextAttributes, GLLimits};
+use webrender_traits::{WebGLCommand, DeviceIntSize};
+
+pub enum GLContextHandleWrapper {
+    Native(NativeGLContextHandle),
+    OSMesa(OSMesaContextHandle),
+}
+
+impl GLContextHandleWrapper {
+    pub fn current_native_handle() -> Option<GLContextHandleWrapper> {
+        NativeGLContext::current_handle().map(GLContextHandleWrapper::Native)
+    }
+
+    pub fn current_osmesa_handle() -> Option<GLContextHandleWrapper> {
+        OSMesaContext::current_handle().map(GLContextHandleWrapper::OSMesa)
+    }
+
+    pub fn new_context(&self,
+                       size: DeviceIntSize,
+                       attributes: GLContextAttributes,
+                       dispatcher: Option<Box<GLContextDispatcher>>) -> Result<GLContextWrapper, &'static str> {
+        match *self {
+            GLContextHandleWrapper::Native(ref handle) => {
+                let ctx = GLContext::<NativeGLContext>::new_shared_with_dispatcher(size.to_untyped(),
+                                                                                   attributes,
+                                                                                   ColorAttachmentType::Texture,
+                                                                                   gl::GlType::default(),
+                                                                                   Some(handle),
+                                                                                   dispatcher);
+                ctx.map(GLContextWrapper::Native)
+            }
+            GLContextHandleWrapper::OSMesa(ref handle) => {
+                let ctx = GLContext::<OSMesaContext>::new_shared_with_dispatcher(size.to_untyped(),
+                                                                                 attributes,
+                                                                                 ColorAttachmentType::Texture,
+                                                                                 gl::GlType::default(),
+                                                                                 Some(handle),
+                                                                                 dispatcher);
+                ctx.map(GLContextWrapper::OSMesa)
+            }
+        }
+    }
+}
+
+pub enum GLContextWrapper {
+    Native(GLContext<NativeGLContext>),
+    OSMesa(GLContext<OSMesaContext>),
+}
+
+impl GLContextWrapper {
+    pub fn make_current(&self) {
+        match *self {
+            GLContextWrapper::Native(ref ctx) => {
+                ctx.make_current().unwrap();
+            }
+            GLContextWrapper::OSMesa(ref ctx) => {
+                ctx.make_current().unwrap();
+            }
+        }
+    }
+
+    pub fn unbind(&self) {
+        match *self {
+            GLContextWrapper::Native(ref ctx) => {
+                ctx.unbind().unwrap();
+            }
+            GLContextWrapper::OSMesa(ref ctx) => {
+                ctx.unbind().unwrap();
+            }
+        }
+    }
+
+    pub fn apply_command(&self, cmd: WebGLCommand) {
+        match *self {
+            GLContextWrapper::Native(ref ctx) => {
+                cmd.apply(ctx);
+            }
+            GLContextWrapper::OSMesa(ref ctx) => {
+                cmd.apply(ctx);
+            }
+        }
+    }
+
+    pub fn get_info(&self) -> (DeviceIntSize, u32, GLLimits) {
+        match *self {
+            GLContextWrapper::Native(ref ctx) => {
+                let (real_size, texture_id) = {
+                    let draw_buffer = ctx.borrow_draw_buffer().unwrap();
+                    (draw_buffer.size(), draw_buffer.get_bound_texture_id().unwrap())
+                };
+
+                let limits = ctx.borrow_limits().clone();
+
+                (DeviceIntSize::from_untyped(&real_size), texture_id, limits)
+            }
+            GLContextWrapper::OSMesa(ref ctx) => {
+                let (real_size, texture_id) = {
+                    let draw_buffer = ctx.borrow_draw_buffer().unwrap();
+                    (draw_buffer.size(), draw_buffer.get_bound_texture_id().unwrap())
+                };
+
+                let limits = ctx.borrow_limits().clone();
+
+                (DeviceIntSize::from_untyped(&real_size), texture_id, limits)
+            }
+        }
+    }
+
+    pub fn resize(&mut self, size: &DeviceIntSize) -> Result<(), &'static str> {
+        match *self {
+            GLContextWrapper::Native(ref mut ctx) => {
+                ctx.resize(size.to_untyped())
+            }
+            GLContextWrapper::OSMesa(ref mut ctx) => {
+                ctx.resize(size.to_untyped())
+            }
+        }
+    }
+}
--- a/gfx/webrender_bindings/Cargo.toml
+++ b/gfx/webrender_bindings/Cargo.toml
@@ -1,16 +1,16 @@
 [package]
 name = "webrender_bindings"
 version = "0.1.0"
 authors = ["The Mozilla Project Developers"]
 license = "MPL-2.0"
 
 [dependencies]
-webrender_traits = {path = "../webrender_traits", version = "0.26.0"}
+webrender_traits = {path = "../webrender_traits", version = "0.27.0"}
 euclid = "0.11"
 app_units = "0.4"
 gleam = "0.4"
 
 [dependencies.webrender]
 path = "../webrender"
-version = "0.25.0"
+version = "0.26.0"
 default-features = false
--- a/gfx/webrender_bindings/WebRenderAPI.cpp
+++ b/gfx/webrender_bindings/WebRenderAPI.cpp
@@ -1,15 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "WebRenderAPI.h"
 #include "mozilla/webrender/RendererOGL.h"
+#include "mozilla/gfx/gfxVars.h"
 #include "mozilla/layers/CompositorThread.h"
 #include "mozilla/widget/CompositorWidget.h"
 #include "mozilla/widget/CompositorWidget.h"
 #include "mozilla/layers/SynchronousTask.h"
 
 namespace mozilla {
 namespace wr {
 
@@ -39,17 +40,27 @@ public:
   {
     MOZ_COUNT_DTOR(NewRenderer);
   }
 
   virtual void Run(RenderThread& aRenderThread, WindowId aWindowId) override
   {
     layers::AutoCompleteTask complete(mTask);
 
-    RefPtr<gl::GLContext> gl = gl::GLContextProvider::CreateForCompositorWidget(mCompositorWidget, true);
+    RefPtr<gl::GLContext> gl;
+    if (gfxVars::UseWebRenderANGLE()) {
+      gl = gl::GLContextProviderEGL::CreateForCompositorWidget(mCompositorWidget, true);
+      if (!gl || !gl->IsANGLE()) {
+        gfxCriticalNote << "Failed ANGLE GL context creation for WebRender: " << hexa(gl.get());
+        return;
+      }
+    }
+    if (!gl) {
+      gl = gl::GLContextProvider::CreateForCompositorWidget(mCompositorWidget, true);
+    }
     if (!gl || !gl->MakeCurrent()) {
       gfxCriticalNote << "Failed GL context creation for WebRender: " << hexa(gl.get());
       return;
     }
 
     gl->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, mMaxTextureSize);
     *mUseANGLE = gl->IsANGLE();
 
--- a/gfx/webrender_bindings/src/bindings.rs
+++ b/gfx/webrender_bindings/src/bindings.rs
@@ -849,17 +849,17 @@ pub extern "C" fn wr_api_add_external_im
 #[no_mangle]
 pub extern "C" fn wr_api_update_image(api: &mut RenderApi,
                                       key: ImageKey,
                                       descriptor: &WrImageDescriptor,
                                       bytes: ByteSlice) {
     assert!(unsafe { is_in_compositor_thread() });
     let copied_bytes = bytes.as_slice().to_owned();
 
-    api.update_image(key, descriptor.to_descriptor(), copied_bytes);
+    api.update_image(key, descriptor.to_descriptor(), copied_bytes, None);
 }
 
 #[no_mangle]
 pub extern "C" fn wr_api_delete_image(api: &mut RenderApi, key: ImageKey) {
     assert!(unsafe { is_in_compositor_thread() });
     api.delete_image(key)
 }
 
@@ -1022,17 +1022,16 @@ pub extern "C" fn wr_dp_begin(state: &mu
 
     let bounds = LayoutRect::new(LayoutPoint::new(0.0, 0.0),
                                  LayoutSize::new(width as f32, height as f32));
 
     state.frame_builder
         .dl_builder
         .push_stacking_context(webrender_traits::ScrollPolicy::Scrollable,
                                bounds,
-                               ClipRegion::simple(&bounds),
                                0,
                                None,
                                None,
                                webrender_traits::MixBlendMode::Normal,
                                Vec::new());
 }
 
 #[no_mangle]
@@ -1083,29 +1082,27 @@ pub extern "C" fn wr_dp_push_stacking_co
             ImageMask {
                 image: image,
                 rect: rect.to_rect(),
                 repeat: repeat,
             }
         })
     };
 
-    let clip_region2 = state.frame_builder.dl_builder.new_clip_region(&overflow, vec![], None);
     let clip_region = state.frame_builder.dl_builder.new_clip_region(&overflow, vec![], mask);
 
     let mut filters: Vec<FilterOp> = Vec::new();
     if opacity < 1.0 {
         filters.push(FilterOp::Opacity(PropertyBinding::Value(opacity)));
     }
 
     state.frame_builder
         .dl_builder
         .push_stacking_context(webrender_traits::ScrollPolicy::Scrollable,
                                bounds,
-                               clip_region2,
                                state.z_index,
                                Some(PropertyBinding::Value(*transform)),
                                None,
                                mix_blend_mode,
                                filters);
     state.frame_builder.dl_builder.push_scroll_layer(clip_region, bounds.size, None);
 }
 
@@ -1336,21 +1333,23 @@ pub extern "C" fn wr_dp_push_box_shadow(
 pub unsafe extern "C" fn wr_api_finalize_builder(state: &mut WrState,
                                                  dl_descriptor: &mut BuiltDisplayListDescriptor,
                                                  dl_data: &mut WrVecU8,
                                                  aux_descriptor: &mut AuxiliaryListsDescriptor,
                                                  aux_data: &mut WrVecU8) {
     let frame_builder = mem::replace(&mut state.frame_builder,
                                      WebRenderFrameBuilder::new(state.pipeline_id));
     let (_, dl, aux) = frame_builder.dl_builder.finalize();
-    //XXX: get rid of the copies here
-    *dl_data = WrVecU8::from_vec(dl.data().to_owned());
-    *dl_descriptor = dl.descriptor().clone();
-    *aux_data = WrVecU8::from_vec(aux.data().to_owned());
-    *aux_descriptor = aux.descriptor().clone();
+    let (data, descriptor) = dl.into_data();
+    *dl_data = WrVecU8::from_vec(data);
+    *dl_descriptor = descriptor;
+
+    let (data, descriptor) = aux.into_data();
+    *aux_data = WrVecU8::from_vec(data);
+    *aux_descriptor = descriptor;
 }
 
 #[no_mangle]
 pub unsafe extern "C" fn wr_dp_push_built_display_list(state: &mut WrState,
                                                        dl_descriptor: BuiltDisplayListDescriptor,
                                                        dl_data: WrVecU8,
                                                        aux_descriptor: AuxiliaryListsDescriptor,
                                                        aux_data: WrVecU8) {
--- a/gfx/webrender_traits/Cargo.toml
+++ b/gfx/webrender_traits/Cargo.toml
@@ -1,27 +1,28 @@
 [package]
 name = "webrender_traits"
-version = "0.26.0"
+version = "0.27.0"
 authors = ["Glenn Watson <gw@intuitionlibrary.com>"]
 license = "MPL-2.0"
 repository = "https://github.com/servo/webrender"
 
 [features]
 nightly = ["euclid/unstable", "serde/unstable"]
 ipc = ["ipc-channel"]
+webgl = ["offscreen_gl_context"]
 
 [dependencies]
 app_units = "0.4"
 byteorder = "1.0"
 euclid = "0.11"
 gleam = "0.4"
 heapsize = "0.3.6"
 ipc-channel = {version = "0.7", optional = true}
-offscreen_gl_context = {version = "0.8", features = ["serde"]}
+offscreen_gl_context = {version = "0.8", features = ["serde"], optional = true}
 serde = "0.9"
 serde_derive = "0.9"
 
 [target.'cfg(target_os = "macos")'.dependencies]
 core-graphics = "0.7"
 
 [target.'cfg(target_os = "windows")'.dependencies]
 dwrote = "0.3"
--- a/gfx/webrender_traits/src/api.rs
+++ b/gfx/webrender_traits/src/api.rs
@@ -1,36 +1,39 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use byteorder::{LittleEndian, WriteBytesExt};
 use channel::{self, MsgSender, PayloadHelperMethods, PayloadSender};
+#[cfg(feature = "webgl")]
 use offscreen_gl_context::{GLContextAttributes, GLLimits};
 use std::cell::Cell;
 use std::fmt;
 use std::marker::PhantomData;
 use {AuxiliaryLists, AuxiliaryListsDescriptor, BuiltDisplayList, BuiltDisplayListDescriptor};
 use {ColorF, DeviceIntPoint, DeviceIntSize, DeviceUintRect, DeviceUintSize, FontKey};
 use {GlyphDimensions, GlyphKey, ImageData, ImageDescriptor, ImageKey, LayoutPoint, LayoutSize};
-use {LayoutTransform, NativeFontHandle, ScrollLayerId, WebGLCommand, WebGLContextId, WorldPoint};
+use {LayoutTransform, NativeFontHandle, ScrollLayerId, WorldPoint};
+#[cfg(feature = "webgl")]
+use {WebGLCommand, WebGLContextId};
 
 pub type TileSize = u16;
 
 #[derive(Clone, Deserialize, Serialize)]
 pub enum ApiMsg {
     AddRawFont(FontKey, Vec<u8>),
     AddNativeFont(FontKey, NativeFontHandle),
     DeleteFont(FontKey),
     /// Gets the glyph dimensions
     GetGlyphDimensions(Vec<GlyphKey>, MsgSender<Vec<Option<GlyphDimensions>>>),
     /// Adds an image from the resource cache.
     AddImage(ImageKey, ImageDescriptor, ImageData, Option<TileSize>),
     /// Updates the the resource cache with the new image data.
-    UpdateImage(ImageKey, ImageDescriptor, Vec<u8>),
+    UpdateImage(ImageKey, ImageDescriptor, Vec<u8>, Option<DeviceUintRect>),
     /// Drops an image from the resource cache.
     DeleteImage(ImageKey),
     CloneApi(MsgSender<IdNamespace>),
     /// Supplies a new frame to WebRender.
     ///
     /// After receiving this message, WebRender will read the display list, followed by the
     /// auxiliary lists, from the payload channel.
     SetRootDisplayList(Option<ColorF>,
@@ -95,16 +98,34 @@ impl fmt::Debug for ApiMsg {
         }
     }
 }
 
 #[repr(C)]
 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
 pub struct Epoch(pub u32);
 
+#[cfg(not(feature = "webgl"))]
+#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
+pub struct WebGLContextId(pub usize);
+
+#[cfg(not(feature = "webgl"))]
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct GLContextAttributes([u8; 0]);
+
+#[cfg(not(feature = "webgl"))]
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct GLLimits([u8; 0]);
+
+#[cfg(not(feature = "webgl"))]
+#[derive(Clone, Deserialize, Serialize)]
+pub enum WebGLCommand {
+    Flush,
+}
+
 #[repr(C)]
 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
 pub struct PipelineId(pub u32, pub u32);
 
 #[repr(C)]
 #[derive(Clone, Copy, Debug, Deserialize, Serialize)]
 pub struct IdNamespace(pub u32);
 
@@ -224,18 +245,19 @@ impl RenderApi {
 
     /// Updates a specific image.
     ///
     /// Currently doesn't support changing dimensions or format by updating.
     // TODO: Support changing dimensions (and format) during image update?
     pub fn update_image(&self,
                         key: ImageKey,
                         descriptor: ImageDescriptor,
-                        bytes: Vec<u8>) {
-        let msg = ApiMsg::UpdateImage(key, descriptor, bytes);
+                        bytes: Vec<u8>,
+                        dirty_rect: Option<DeviceUintRect>) {
+        let msg = ApiMsg::UpdateImage(key, descriptor, bytes, dirty_rect);
         self.api_sender.send(msg).unwrap();
     }
 
     /// Deletes the specific image.
     pub fn delete_image(&self, key: ImageKey) {
         let msg = ApiMsg::DeleteImage(key);
         self.api_sender.send(msg).unwrap();
     }
--- a/gfx/webrender_traits/src/display_item.rs
+++ b/gfx/webrender_traits/src/display_item.rs
@@ -239,17 +239,16 @@ pub struct RadialGradientDisplayItem {
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
 pub struct PushStackingContextDisplayItem {
     pub stacking_context: StackingContext,
 }
 
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
 pub struct StackingContext {
     pub scroll_policy: ScrollPolicy,
-    pub bounds: LayoutRect,
     pub z_index: i32,
     pub transform: Option<PropertyBinding<LayoutTransform>>,
     pub perspective: Option<LayoutTransform>,
     pub mix_blend_mode: MixBlendMode,
     pub filters: ItemRange,
 }
 
 #[repr(u32)]
@@ -351,27 +350,25 @@ pub struct ComplexClipRegion {
     /// The boundaries of the rectangle.
     pub rect: LayoutRect,
     /// Border radii of this rectangle.
     pub radii: BorderRadius,
 }
 
 impl StackingContext {
     pub fn new(scroll_policy: ScrollPolicy,
-               bounds: LayoutRect,
                z_index: i32,
                transform: Option<PropertyBinding<LayoutTransform>>,
                perspective: Option<LayoutTransform>,
                mix_blend_mode: MixBlendMode,
                filters: Vec<FilterOp>,
                auxiliary_lists_builder: &mut AuxiliaryListsBuilder)
                -> StackingContext {
         StackingContext {
             scroll_policy: scroll_policy,
-            bounds: bounds,
             z_index: z_index,
             transform: transform,
             perspective: perspective,
             mix_blend_mode: mix_blend_mode,
             filters: auxiliary_lists_builder.add_filters(&filters),
         }
     }
 }
--- a/gfx/webrender_traits/src/display_list.rs
+++ b/gfx/webrender_traits/src/display_list.rs
@@ -63,16 +63,20 @@ impl BuiltDisplayListDescriptor {
 impl BuiltDisplayList {
     pub fn from_data(data: Vec<u8>, descriptor: BuiltDisplayListDescriptor) -> BuiltDisplayList {
         BuiltDisplayList {
             data: data,
             descriptor: descriptor,
         }
     }
 
+    pub fn into_data(self) -> (Vec<u8>, BuiltDisplayListDescriptor) {
+        (self.data, self.descriptor)
+    }
+
     pub fn data(&self) -> &[u8] {
         &self.data[..]
     }
 
     pub fn descriptor(&self) -> &BuiltDisplayListDescriptor {
         &self.descriptor
     }
 
@@ -308,35 +312,33 @@ impl DisplayListBuilder {
         });
 
         self.push_item(item, rect, clip);
     }
 
     pub fn push_stacking_context(&mut self,
                                  scroll_policy: ScrollPolicy,
                                  bounds: LayoutRect,
-                                 clip: ClipRegion,
                                  z_index: i32,
                                  transform: Option<PropertyBinding<LayoutTransform>>,
                                  perspective: Option<LayoutTransform>,
                                  mix_blend_mode: MixBlendMode,
                                  filters: Vec<FilterOp>) {
         let item = SpecificDisplayItem::PushStackingContext(PushStackingContextDisplayItem {
             stacking_context: StackingContext {
                 scroll_policy: scroll_policy,
-                bounds: bounds,
                 z_index: z_index,
                 transform: transform,
                 perspective: perspective,
                 mix_blend_mode: mix_blend_mode,
                 filters: self.auxiliary_lists_builder.add_filters(&filters),
             }
         });
 
-        self.push_item(item, LayoutRect::zero(), clip);
+        self.push_item(item, bounds, ClipRegion::simple(&LayoutRect::zero()));
     }
 
     pub fn pop_stacking_context(&mut self) {
         self.push_new_empty_item(SpecificDisplayItem::PopStackingContext);
     }
 
     pub fn define_clip(&mut self,
                        clip: ClipRegion,
@@ -427,17 +429,17 @@ impl DisplayListBuilder {
                            complex: Vec<ComplexClipRegion>,
                            image_mask: Option<ImageMask>)
                            -> ClipRegion {
         ClipRegion::new(rect, complex, image_mask, &mut self.auxiliary_lists_builder)
     }
 
     pub fn finalize(self) -> (PipelineId, BuiltDisplayList, AuxiliaryLists) {
         unsafe {
-            let blob = convert_pod_to_blob(&self.list).to_vec();
+            let blob = convert_vec_pod_to_blob(self.list);
             let display_list_items_size = blob.len();
 
             (self.pipeline_id,
              BuiltDisplayList {
                  descriptor: BuiltDisplayListDescriptor {
                      display_list_items_size: display_list_items_size,
                  },
                  data: blob,
@@ -522,17 +524,17 @@ impl AuxiliaryListsBuilder {
     }
 
     pub fn glyph_instances(&self, glyph_instances_range: &ItemRange) -> &[GlyphInstance] {
         glyph_instances_range.get(&self.glyph_instances[..])
     }
 
     pub fn finalize(self) -> AuxiliaryLists {
         unsafe {
-            let mut blob = convert_pod_to_blob(&self.gradient_stops).to_vec();
+            let mut blob = convert_vec_pod_to_blob(self.gradient_stops);
             let gradient_stops_size = blob.len();
             blob.extend_from_slice(convert_pod_to_blob(&self.complex_clip_regions));
             let complex_clip_regions_size = blob.len() - gradient_stops_size;
             blob.extend_from_slice(convert_pod_to_blob(&self.filters));
             let filters_size = blob.len() - (complex_clip_regions_size + gradient_stops_size);
             blob.extend_from_slice(convert_pod_to_blob(&self.glyph_instances));
             let glyph_instances_size = blob.len() -
                 (complex_clip_regions_size + gradient_stops_size + filters_size);
@@ -561,16 +563,20 @@ impl AuxiliaryLists {
     /// Creates a new `AuxiliaryLists` instance from a descriptor and data received over a channel.
     pub fn from_data(data: Vec<u8>, descriptor: AuxiliaryListsDescriptor) -> AuxiliaryLists {
         AuxiliaryLists {
             data: data,
             descriptor: descriptor,
         }
     }
 
+    pub fn into_data(self) -> (Vec<u8>, AuxiliaryListsDescriptor) {
+        (self.data, self.descriptor)
+    }
+
     pub fn data(&self) -> &[u8] {
         &self.data[..]
     }
 
     pub fn descriptor(&self) -> &AuxiliaryListsDescriptor {
         &self.descriptor
     }
 
@@ -611,12 +617,19 @@ impl AuxiliaryLists {
         }
     }
 }
 
 unsafe fn convert_pod_to_blob<T>(data: &[T]) -> &[u8] where T: Copy + 'static {
     slice::from_raw_parts(data.as_ptr() as *const u8, data.len() * mem::size_of::<T>())
 }
 
+// this variant of the above lets us convert without needing to make a copy
+unsafe fn convert_vec_pod_to_blob<T>(mut data: Vec<T>) -> Vec<u8> where T: Copy + 'static {
+    let v = Vec::from_raw_parts(data.as_mut_ptr() as *mut u8, data.len() * mem::size_of::<T>(), data.capacity() * mem::size_of::<T>());
+    mem::forget(data);
+    v
+}
+
 unsafe fn convert_blob_to_pod<T>(blob: &[u8]) -> &[T] where T: Copy + 'static {
     slice::from_raw_parts(blob.as_ptr() as *const T, blob.len() / mem::size_of::<T>())
 }
 
--- a/gfx/webrender_traits/src/lib.rs
+++ b/gfx/webrender_traits/src/lib.rs
@@ -9,16 +9,17 @@ extern crate byteorder;
 #[cfg(feature = "nightly")]
 extern crate core;
 extern crate euclid;
 extern crate gleam;
 #[macro_use]
 extern crate heapsize;
 #[cfg(feature = "ipc")]
 extern crate ipc_channel;
+#[cfg(feature = "webgl")]
 extern crate offscreen_gl_context;
 extern crate serde;
 #[macro_use]
 extern crate serde_derive;
 
 #[cfg(target_os = "macos")]
 extern crate core_graphics;
 
@@ -28,18 +29,20 @@ extern crate dwrote;
 mod units;
 mod api;
 mod color;
 pub mod channel;
 mod display_item;
 mod display_list;
 mod font;
 mod image;
+#[cfg(feature = "webgl")]
 mod webgl;
 
 pub use api::*;
 pub use color::*;
 pub use display_item::*;
 pub use display_list::*;
 pub use font::*;
 pub use image::*;
 pub use units::*;
+#[cfg(feature = "webgl")]
 pub use webgl::*;
--- a/ipc/glue/BackgroundUtils.cpp
+++ b/ipc/glue/BackgroundUtils.cpp
@@ -84,18 +84,17 @@ PrincipalInfoToPrincipal(const Principal
         return nullptr;
       }
 
       OriginAttributes attrs;
       if (info.attrs().mAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID) {
         attrs = info.attrs();
       }
       principal = BasePrincipal::CreateCodebasePrincipal(uri, attrs);
-      rv = principal ? NS_OK : NS_ERROR_FAILURE;
-      if (NS_WARN_IF(NS_FAILED(rv))) {
+      if (NS_WARN_IF(!principal)) {
         return nullptr;
       }
 
       // When the principal is serialized, the origin is extract from it. This
       // can fail, and in case, here we will havea Tvoid_t. If we have a string,
       // it must match with what the_new_principal.getOrigin returns.
       if (info.originNoSuffix().type() == ContentPrincipalInfoOriginNoSuffix::TnsCString) {
         nsAutoCString originNoSuffix;
--- a/ipc/glue/PBackgroundSharedTypes.ipdlh
+++ b/ipc/glue/PBackgroundSharedTypes.ipdlh
@@ -13,19 +13,23 @@ union ContentPrincipalInfoOriginNoSuffix
   nsCString;
   void_t;
 };
 
 struct ContentPrincipalInfo
 {
   OriginAttributes attrs;
 
-  // nsIPrincipal.originNoSuffix can fail. In case this happens, this value
-  // will be set to void_t. So far, this is used only for dom/media.
-  // It will be removed in bug 1347817.
+  // Origin is not simply a part of the spec. Based on the scheme of the URI
+  // spec, we generate different kind of origins: for instance any file: URL
+  // shares the same origin, about: URLs have the full spec as origin and so
+  // on.
+  // Another important reason why we have this attribute is that
+  // ContentPrincipalInfo is used out of the main-thread. Having this value
+  // here allows us to retrive the origin without creating a full nsIPrincipal.
   ContentPrincipalInfoOriginNoSuffix originNoSuffix;
 
   nsCString spec;
 };
 
 struct SystemPrincipalInfo
 { };
 
--- a/js/src/jit-test/tests/wasm/profiling.js
+++ b/js/src/jit-test/tests/wasm/profiling.js
@@ -1,23 +1,27 @@
-// Single-step profiling currently only works in the ARM simulator
-if (!getBuildConfiguration()["arm-simulator"])
+try {
+    enableSingleStepProfiling();
+    disableSingleStepProfiling();
+} catch(e) {
+    // Single step profiling not supported here.
     quit();
+}
 
 const Module = WebAssembly.Module;
 const Instance = WebAssembly.Instance;
 const Table = WebAssembly.Table;
 
 function normalize(stack)
 {
     var wasmFrameTypes = [
-        {re:/^entry trampoline \(in asm.js\)$/,             sub:">"},
-        {re:/^wasm-function\[(\d+)\] \(.*\)$/,              sub:"$1"},
-        {re:/^(fast|slow) FFI trampoline \(in asm.js\)$/,   sub:"<"},
-        {re:/ \(in asm.js\)$/,                              sub:""}
+        {re:/^entry trampoline \(in wasm\)$/,             sub:">"},
+        {re:/^wasm-function\[(\d+)\] \(.*\)$/,            sub:"$1"},
+        {re:/^(fast|slow) FFI trampoline \(in wasm\)$/,   sub:"<"},
+        {re:/ \(in wasm\)$/,                              sub:""}
     ];
 
     var framesIn = stack.split(',');
     var framesOut = [];
     for (let frame of framesIn) {
         for (let {re, sub} of wasmFrameTypes) {
             if (re.test(frame)) {
                 framesOut.push(frame.replace(re, sub));
--- a/js/src/jit/MoveResolver.h
+++ b/js/src/jit/MoveResolver.h
@@ -278,17 +278,16 @@ class MoveResolver
             MOZ_ASSERT(!cycleEnd_);
             cycleEnd_ = true;
             cycleEndSlot_ = cycleSlot;
         }
     };
 
     typedef InlineList<MoveResolver::PendingMove>::iterator PendingMoveIterator;
 
-  private:
     js::Vector<MoveOp, 16, SystemAllocPolicy> orderedMoves_;
     int numCycles_;
     int curCycles_;
     TempObjectPool<PendingMove> movePool_;
 
     InlineList<PendingMove> pending_;
 
     PendingMove* findBlockingMove(const PendingMove* last);
--- a/js/src/jit/RegisterSets.h
+++ b/js/src/jit/RegisterSets.h
@@ -1354,18 +1354,24 @@ class ABIArg
     Register evenGpr() const {
         MOZ_ASSERT(isGeneralRegPair());
         return Register::FromCode(u.gpr_);
     }
     Register oddGpr() const {
         MOZ_ASSERT(isGeneralRegPair());
         return Register::FromCode(u.gpr_ + 1);
     }
-    FloatRegister fpu() const { MOZ_ASSERT(kind() == FPU); return FloatRegister::FromCode(u.fpu_); }
-    uint32_t offsetFromArgBase() const { MOZ_ASSERT(kind() == Stack); return u.offset_; }
+    FloatRegister fpu() const {
+        MOZ_ASSERT(kind() == FPU);
+        return FloatRegister::FromCode(u.fpu_);
+    }
+    uint32_t offsetFromArgBase() const {
+        MOZ_ASSERT(kind() == Stack);
+        return u.offset_;
+    }
 
     bool argInRegister() const { return kind() != Stack; }
     AnyRegister reg() const { return kind_ == GPR ? AnyRegister(gpr()) : AnyRegister(fpu()); }
 
     bool operator==(const ABIArg& rhs) const {
         if (kind_ != rhs.kind_)
             return false;
 
--- a/js/src/jit/arm/MacroAssembler-arm.cpp
+++ b/js/src/jit/arm/MacroAssembler-arm.cpp
@@ -5227,34 +5227,31 @@ MacroAssembler::callWithABIPre(uint32_t*
 }
 
 void
 MacroAssembler::callWithABIPost(uint32_t stackAdjust, MoveOp::Type result)
 {
     if (secondScratchReg_ != lr)
         ma_mov(secondScratchReg_, lr);
 
-    switch (result) {
-      case MoveOp::DOUBLE:
-        if (!UseHardFpABI()) {
+    if (!UseHardFpABI()) {
+        switch (result) {
+          case MoveOp::DOUBLE:
             // Move double from r0/r1 to ReturnFloatReg.
             ma_vxfer(r0, r1, ReturnDoubleReg);
-        }
-        break;
-      case MoveOp::FLOAT32:
-        if (!UseHardFpABI()) {
+            break;
+          case MoveOp::FLOAT32:
             // Move float32 from r0 to ReturnFloatReg.
-            ma_vxfer(r0, ReturnFloat32Reg.singleOverlay());
+            ma_vxfer(r0, ReturnFloat32Reg);
+            break;
+          case MoveOp::GENERAL:
+            break;
+          default:
+            MOZ_CRASH("unexpected callWithABI result");
         }
-        break;
-      case MoveOp::GENERAL:
-        break;
-
-      default:
-        MOZ_CRASH("unexpected callWithABI result");
     }
 
     freeStack(stackAdjust);
 
     if (dynamicAlignment_) {
         // While the x86 supports pop esp, on ARM that isn't well defined, so
         // just do it manually.
         as_dtr(IsLoad, 32, Offset, sp, DTRAddr(sp, DtrOffImm(0)));
--- a/js/src/jit/x86/Assembler-x86.cpp
+++ b/js/src/jit/x86/Assembler-x86.cpp
@@ -22,19 +22,16 @@ ABIArgGenerator::next(MIRType type)
     switch (type) {
       case MIRType::Int32:
       case MIRType::Float32:
       case MIRType::Pointer:
         current_ = ABIArg(stackOffset_);
         stackOffset_ += sizeof(uint32_t);
         break;
       case MIRType::Double:
-        current_ = ABIArg(stackOffset_);
-        stackOffset_ += sizeof(uint64_t);
-        break;
       case MIRType::Int64:
         current_ = ABIArg(stackOffset_);
         stackOffset_ += sizeof(uint64_t);
         break;
       case MIRType::Int8x16:
       case MIRType::Int16x8:
       case MIRType::Int32x4:
       case MIRType::Float32x4:
@@ -53,21 +50,18 @@ ABIArgGenerator::next(MIRType type)
     }
     return current_;
 }
 
 void
 Assembler::executableCopy(uint8_t* buffer, bool flushICache)
 {
     AssemblerX86Shared::executableCopy(buffer);
-
-    for (size_t i = 0; i < jumps_.length(); i++) {
-        RelativePatch& rp = jumps_[i];
+    for (RelativePatch& rp : jumps_)
         X86Encoding::SetRel32(buffer + rp.offset, rp.target);
-    }
 }
 
 class RelocationIterator
 {
     CompactBufferReader reader_;
     uint32_t offset_;
 
   public:
--- a/js/src/wasm/WasmFrameIterator.cpp
+++ b/js/src/wasm/WasmFrameIterator.cpp
@@ -73,17 +73,22 @@ FrameIterator::FrameIterator(WasmActivat
 {
     // When execution is interrupted, the embedding may capture a stack trace.
     // Since we've lost all the register state, we can't unwind the full stack
     // like ProfilingFrameIterator does. However, we can recover the interrupted
     // function via the resumePC and at least print that frame.
     if (void* resumePC = activation->resumePC()) {
         code_ = activation->compartment()->wasm.lookupCode(resumePC);
         codeRange_ = code_->lookupRange(resumePC);
-        MOZ_ASSERT(codeRange_->kind() == CodeRange::Function);
+        if (codeRange_->kind() != CodeRange::Function) {
+            // We might be in a stub inserted between functions, in which case
+            // we don't have a frame.
+            codeRange_ = nullptr;
+            missingFrameMessage_ = true;
+        }
         MOZ_ASSERT(!done());
         return;
     }
 
     fp_ = activation->exitFP();
 
     if (!fp_) {
         MOZ_ASSERT(done());
@@ -757,43 +762,43 @@ ProfilingFrameIterator::label() const
 {
     MOZ_ASSERT(!done());
 
     // Use the same string for both time inside and under so that the two
     // entries will be coalesced by the profiler.
     //
     // NB: these labels are parsed for location by
     //     devtools/client/performance/modules/logic/frame-utils.js
-    const char* importJitDescription = "fast FFI trampoline (in asm.js)";
-    const char* importInterpDescription = "slow FFI trampoline (in asm.js)";
-    const char* trapDescription = "trap handling (in asm.js)";
-    const char* debugTrapDescription = "debug trap handling (in asm.js)";
+    static const char* importJitDescription = "fast FFI trampoline (in wasm)";
+    static const char* importInterpDescription = "slow FFI trampoline (in wasm)";
+    static const char* trapDescription = "trap handling (in wasm)";
+    static const char* debugTrapDescription = "debug trap handling (in wasm)";
 
     switch (exitReason_) {
       case ExitReason::None:
         break;
       case ExitReason::ImportJit:
         return importJitDescription;
       case ExitReason::ImportInterp:
         return importInterpDescription;
       case ExitReason::Trap:
         return trapDescription;
       case ExitReason::DebugTrap:
         return debugTrapDescription;
     }
 
     switch (codeRange_->kind()) {
       case CodeRange::Function:         return code_->profilingLabel(codeRange_->funcIndex());
-      case CodeRange::Entry:            return "entry trampoline (in asm.js)";
+      case CodeRange::Entry:            return "entry trampoline (in wasm)";
       case CodeRange::ImportJitExit:    return importJitDescription;
       case CodeRange::ImportInterpExit: return importInterpDescription;
       case CodeRange::TrapExit:         return trapDescription;
       case CodeRange::DebugTrap:        return debugTrapDescription;
-      case CodeRange::Inline:           return "inline stub (in asm.js)";
-      case CodeRange::FarJumpIsland:    return "interstitial (in asm.js)";
+      case CodeRange::Inline:           return "inline stub (in wasm)";
+      case CodeRange::FarJumpIsland:    return "interstitial (in wasm)";
       case CodeRange::Throw:            MOZ_FALLTHROUGH;
       case CodeRange::Interrupt:        MOZ_CRASH("does not have a frame");
     }
 
     MOZ_CRASH("bad code range kind");
 }
 
 void
--- a/js/src/wasm/WasmGenerator.cpp
+++ b/js/src/wasm/WasmGenerator.cpp
@@ -644,17 +644,17 @@ ModuleGenerator::finishCodegen()
 
     // Code-generation is complete!
 
     masm_.finish();
     return !masm_.oom();
 }
 
 bool
-ModuleGenerator::finishLinkData(Bytes& code)
+ModuleGenerator::finishLinkData()
 {
     // Inflate the global bytes up to page size so that the total bytes are a
     // page size (as required by the allocator functions).
     linkData_.globalDataLength = AlignBytes(linkData_.globalDataLength, gc::SystemPageSize());
 
     // Add links to absolute addresses identified symbolically.
     for (size_t i = 0; i < masm_.numSymbolicAccesses(); i++) {
         SymbolicAccess src = masm_.symbolicAccess(i);
@@ -1176,17 +1176,17 @@ ModuleGenerator::finish(const ShareableB
 #ifdef DEBUG
     uint32_t lastOffset = 0;
     for (uint32_t debugTrapFarJumpOffset : metadata_->debugTrapFarJumpOffsets) {
         MOZ_ASSERT(debugTrapFarJumpOffset >= lastOffset);
         lastOffset = debugTrapFarJumpOffset;
     }
 #endif
 
-    if (!finishLinkData(code))
+    if (!finishLinkData())
         return nullptr;
 
     return SharedModule(js_new<Module>(Move(assumptions_),
                                        Move(code),
                                        Move(linkData_),
                                        Move(env_->imports),
                                        Move(env_->exports),
                                        Move(env_->dataSegments),
--- a/js/src/wasm/WasmGenerator.h
+++ b/js/src/wasm/WasmGenerator.h
@@ -258,17 +258,17 @@ class MOZ_STACK_CLASS ModuleGenerator
     const CodeRange& funcCodeRange(uint32_t funcIndex) const;
     uint32_t numFuncImports() const;
     MOZ_MUST_USE bool patchCallSites();
     MOZ_MUST_USE bool patchFarJumps(const TrapExitOffsetArray& trapExits, const Offsets& debugTrapStub);
     MOZ_MUST_USE bool finishTask(CompileTask* task);
     MOZ_MUST_USE bool finishOutstandingTask();
     MOZ_MUST_USE bool finishFuncExports();
     MOZ_MUST_USE bool finishCodegen();
-    MOZ_MUST_USE bool finishLinkData(Bytes& code);
+    MOZ_MUST_USE bool finishLinkData();
     MOZ_MUST_USE bool addFuncImport(const Sig& sig, uint32_t globalDataOffset);
     MOZ_MUST_USE bool allocateGlobalBytes(uint32_t bytes, uint32_t align, uint32_t* globalDataOff);
     MOZ_MUST_USE bool allocateGlobal(GlobalDesc* global);
 
     MOZ_MUST_USE bool launchBatchCompile();
 
     MOZ_MUST_USE bool initAsmJS(Metadata* asmJSMetadata);
     MOZ_MUST_USE bool initWasm(const CompileArgs& args);
--- a/js/src/wasm/WasmStubs.cpp
+++ b/js/src/wasm/WasmStubs.cpp
@@ -506,17 +506,17 @@ wasm::GenerateImportFunction(jit::MacroA
 // signature of the import and calls into an appropriate callImport C++
 // function, having boxed all the ABI arguments into a homogeneous Value array.
 CallableOffsets
 wasm::GenerateImportInterpExit(MacroAssembler& masm, const FuncImport& fi, uint32_t funcImportIndex,
                                Label* throwLabel)
 {
     masm.setFramePushed(0);
 
-    // Argument types for Module::callImport_*:
+    // Argument types for Instance::callImport_*:
     static const MIRType typeArray[] = { MIRType::Pointer,   // Instance*
                                          MIRType::Pointer,   // funcImportIndex
                                          MIRType::Int32,     // argc
                                          MIRType::Pointer }; // argv
     MIRTypeVector invokeArgTypes;
     MOZ_ALWAYS_TRUE(invokeArgTypes.append(typeArray, ArrayLength(typeArray)));
 
     // At the point of the call, the stack layout shall be (sp grows to the left):
@@ -530,17 +530,17 @@ wasm::GenerateImportInterpExit(MacroAsse
     CallableOffsets offsets;
     GenerateExitPrologue(masm, framePushed, ExitReason::ImportInterp, &offsets);
 
     // Fill the argument array.
     unsigned offsetToCallerStackArgs = sizeof(Frame) + masm.framePushed();
     Register scratch = ABINonArgReturnReg0;
     FillArgumentArray(masm, fi.sig().args(), argOffset, offsetToCallerStackArgs, scratch, ToValue(false));
 
-    // Prepare the arguments for the call to Module::callImport_*.
+    // Prepare the arguments for the call to Instance::callImport_*.
     ABIArgMIRTypeIter i(invokeArgTypes);
 
     // argument 0: Instance*
     Address instancePtr(WasmTlsReg, offsetof(TlsData, instance));
     if (i->kind() == ABIArg::GPR) {
         masm.loadPtr(instancePtr, i->gpr());
     } else {
         masm.loadPtr(instancePtr, scratch);
--- a/js/xpconnect/src/XPCJSContext.cpp
+++ b/js/xpconnect/src/XPCJSContext.cpp
@@ -1630,17 +1630,17 @@ XPCJSContext::~XPCJSContext()
     // Tell the profiler that the context is gone
     profiler_clear_js_context();
 #endif
 
     Preferences::UnregisterPrefixCallback(ReloadPrefsCallback,
                                           JS_OPTIONS_DOT_STR, this);
 
 #ifdef FUZZING
-    Preferences::UnRegisterCallback(ReloadPrefsCallback, "fuzzing.enabled", this);
+    Preferences::UnregisterCallback(ReloadPrefsCallback, "fuzzing.enabled", this);
 #endif
 }
 
 // If |*anonymizeID| is non-zero and this is a user compartment, the name will
 // be anonymized.
 static void
 GetCompartmentName(JSCompartment* c, nsCString& name, int* anonymizeID,
                    bool replaceSlashes)
--- a/layout/generic/crashtests/crashtests.list
+++ b/layout/generic/crashtests/crashtests.list
@@ -20,17 +20,17 @@ load 309322-1.html # bug 1338007
 load 309322-2.html # bug 1338007
 load 309322-3.html
 load 309322-4.html
 load 310556-1.xhtml
 load 321224.xul
 load 322780-1.xul
 load 323381-1.html
 load 323381-2.html
-asserts-if(gtkWidget,1) asserts-if(Android&&asyncPan,1) asserts-if(stylo,0) asserts-if(winWidget,1) load 323386-1.html # Bug 718883
+asserts-if(gtkWidget,1) asserts-if(Android&&asyncPan,1) asserts-if(stylo,0) load 323386-1.html # Bug 718883
 load 323389-1.html
 load 323389-2.html
 load 323493-1.html
 load 323495-1.html
 load 324318-1.html
 load 328946-1.html
 load 331284-1.xhtml
 load 331292.html
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -1305,21 +1305,26 @@ nsIFrame::GetMarginRectRelativeToSelf() 
 }
 
 bool
 nsIFrame::IsTransformed() const
 {
   return ((mState & NS_FRAME_MAY_BE_TRANSFORMED) &&
           (StyleDisplay()->HasTransform(this) ||
            IsSVGTransformed() ||
-           (mContent &&
-            nsLayoutUtils::HasAnimationOfProperty(this,
-                                                  eCSSProperty_transform) &&
-            IsFrameOfType(eSupportsCSSTransforms) &&
-            mContent->GetPrimaryFrame() == this)));
+           HasAnimationOfTransform()));
+}
+
+bool
+nsIFrame::HasAnimationOfTransform() const
+{
+  return mContent &&
+    nsLayoutUtils::HasAnimationOfProperty(this, eCSSProperty_transform) &&
+    IsFrameOfType(eSupportsCSSTransforms) &&
+    mContent->GetPrimaryFrame() == this;
 }
 
 bool
 nsIFrame::HasOpacityInternal(float aThreshold) const
 {
   MOZ_ASSERT(0.0 <= aThreshold && aThreshold <= 1.0, "Invalid argument");
   return StyleEffects()->mOpacity < aThreshold ||
          (StyleDisplay()->mWillChangeBitField & NS_STYLE_WILL_CHANGE_OPACITY) ||
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -1637,16 +1637,21 @@ public:
    * Returns true if this frame is transformed (e.g. has CSS or SVG transforms)
    * or if its parent is an SVG frame that has children-only transforms (e.g.
    * an SVG viewBox attribute) or if its transform-style is preserve-3d or
    * the frame has transform animations.
    */
   bool IsTransformed() const;
 
   /**
+   * True if this frame has any animation of transform in effect.
+   */
+  bool HasAnimationOfTransform() const;
+
+  /**
    * Returns true if the frame is translucent or the frame has opacity
    * animations for the purposes of creating a stacking context.
    */
   bool HasOpacity() const
   {
     return HasOpacityInternal(1.0f);
   }
   /**
--- a/layout/painting/FrameLayerBuilder.cpp
+++ b/layout/painting/FrameLayerBuilder.cpp
@@ -1540,16 +1540,21 @@ public:
   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.
   nsIntRegion mVisibilityComputedRegion;
+
+  /**
+   * This is set when the painted layer has no component alpha.
+   */
+  bool mDisabledAlpha;
 };
 
 /*
  * User data for layers which will be used as masks.
  */
 struct MaskLayerUserData : public LayerUserData
 {
   MaskLayerUserData()
@@ -2390,16 +2395,18 @@ ContainerState::CreatePaintedLayer(Paint
   // Create a new painted layer
   RefPtr<PaintedLayer> layer = mManager->CreatePaintedLayerWithHint(creationHint);
   if (!layer) {
     return nullptr;
   }
 
   // Mark this layer as being used for painting display items
   PaintedDisplayItemLayerUserData* userData = new PaintedDisplayItemLayerUserData();
+  userData->mDisabledAlpha =
+    mParameters.mDisableSubpixelAntialiasingInDescendants;
   layer->SetUserData(&gPaintedDisplayItemLayerUserData, userData);
   ResetScrollPositionForLayerPixelAlignment(aData->mAnimatedGeometryRoot);
 
   PreparePaintedLayerForUse(layer, userData, aData->mAnimatedGeometryRoot,
                             aData->mReferenceFrame,
                             aData->mAnimatedGeometryRootOffset, true);
 
   return layer.forget();
@@ -2488,21 +2495,30 @@ ContainerState::PreparePaintedLayerForUs
                        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));
 
   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;
+  const bool disableAlpha =
+    mParameters.mDisableSubpixelAntialiasingInDescendants;
+  if (aData->mDisabledAlpha != disableAlpha) {
+    aData->mAnimatedGeometryRootPosition = animatedGeometryRootTopLeft;
+    InvalidateEntirePaintedLayer(aLayer, aAnimatedGeometryRoot, "change of subpixel-AA");
+    aData->mDisabledAlpha = disableAlpha;
+    return;
+  }
+
+  // FIXME: Temporary workaround for bug 681192 and bug 724786.
+#ifndef MOZ_WIDGET_ANDROID
   // If it has changed, then we need to invalidate the entire layer since the
   // pixels in the layer buffer have the content at a (subpixel) offset
   // from what we need.
   if (!animatedGeometryRootTopLeft.WithinEpsilonOf(aData->mAnimatedGeometryRootPosition, SUBPIXEL_OFFSET_EPSILON)) {
     aData->mAnimatedGeometryRootPosition = animatedGeometryRootTopLeft;
     InvalidateEntirePaintedLayer(aLayer, aAnimatedGeometryRoot, "subpixel offset");
   } else if (didResetScrollPositionForLayerPixelAlignment) {
     aData->mAnimatedGeometryRootPosition = animatedGeometryRootTopLeft;
@@ -5520,17 +5536,20 @@ ChooseScaleAndSetTransform(FrameLayerBui
     if (ActiveLayerTracker::IsStyleAnimated(aDisplayListBuilder, aContainerFrame,
                                             eCSSProperty_transform)) {
       aOutgoingScale.mInActiveTransformedSubtree = true;
     }
   }
   if ((aLayerBuilder->IsBuildingRetainedLayers() &&
        (!canDraw2D || transform2d.HasNonIntegerTranslation())) ||
       aContainerFrame->Extend3DContext() ||
-      aContainerFrame->Combines3DTransformWithAncestors()) {
+      aContainerFrame->Combines3DTransformWithAncestors() ||
+      // For async transform animation, the value would be changed at
+      // any time, integer translation is not always true.
+      aContainerFrame->HasAnimationOfTransform()) {
     aOutgoingScale.mDisableSubpixelAntialiasingInDescendants = true;
   }
   return true;
 }
 
 already_AddRefed<ContainerLayer>
 FrameLayerBuilder::BuildContainerLayerFor(nsDisplayListBuilder* aBuilder,
                                           LayerManager* aManager,
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -2736,16 +2736,17 @@ nsDisplayItem::BuildDisplayItemLayer(nsD
   if (!layer) {
     layer = aManager->CreateDisplayItemLayer();
 
     if (!layer) {
       return nullptr;
     }
   }
 
+  aManager->TrackDisplayItemLayer(layer);
   layer->SetDisplayItem(this, aBuilder);
   layer->SetBaseTransform(gfx::Matrix4x4::Translation(aContainerParameters.mOffset.x,
                                                       aContainerParameters.mOffset.y, 0));
   return layer.forget();
 }
 
 nsRect
 nsDisplaySolidColor::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
@@ -3936,20 +3937,21 @@ nsDisplayBackgroundColor::CanApplyOpacit
 }
 
 LayerState
 nsDisplayBackgroundColor::GetLayerState(nsDisplayListBuilder* aBuilder,
                                         LayerManager* aManager,
                                         const ContainerLayerParameters& aParameters)
 {
   StyleGeometryBox clip = mBackgroundStyle->mImage.mLayers[0].mClip;
-  if (!ForceActiveLayers() || clip == StyleGeometryBox::Text) {
-    return LAYER_NONE;
-  }
-  return LAYER_ACTIVE;
+  if ((ForceActiveLayers() || gfxPrefs::LayersAllowBackgroundColorLayers()) &&
+      clip != StyleGeometryBox::Text) {
+    return LAYER_ACTIVE;
+  }
+  return LAYER_NONE;
 }
 
 already_AddRefed<Layer>
 nsDisplayBackgroundColor::BuildLayer(nsDisplayListBuilder* aBuilder,
                                      LayerManager* aManager,
                                      const ContainerLayerParameters& aContainerParameters)
 {
   if (mColor == Color()) {
--- a/layout/printing/nsPagePrintTimer.cpp
+++ b/layout/printing/nsPagePrintTimer.cpp
@@ -5,50 +5,47 @@
 
 #include "nsPagePrintTimer.h"
 
 #include "mozilla/Unused.h"
 #include "nsIContentViewer.h"
 #include "nsIServiceManager.h"
 #include "nsPrintEngine.h"
 
-using namespace mozilla;
-
 NS_IMPL_ISUPPORTS_INHERITED(nsPagePrintTimer, mozilla::Runnable, nsITimerCallback)
 
 nsPagePrintTimer::~nsPagePrintTimer()
 {
   // "Destroy" the document viewer; this normally doesn't actually
   // destroy it because of the IncrementDestroyRefCount call below
   // XXX This is messy; the document viewer should use a single approach
   // to keep itself alive during printing
   nsCOMPtr<nsIContentViewer> cv(do_QueryInterface(mDocViewerPrint));
   if (cv) {
     cv->Destroy();
   }
 }
 
-nsresult
+nsresult 
 nsPagePrintTimer::StartTimer(bool aUseDelay)
 {
   nsresult result;
   mTimer = do_CreateInstance("@mozilla.org/timer;1", &result);
   if (NS_FAILED(result)) {
     NS_WARNING("unable to start the timer");
   } else {
     uint32_t delay = 0;
     if (aUseDelay) {
       if (mFiringCount < 10) {
         // Longer delay for the few first pages.
         delay = mDelay + ((10 - mFiringCount) * 100);
       } else {
         delay = mDelay;
       }
     }
-    mTimer->SetTarget(mDocument->EventTargetFor(TaskCategory::Other));
     mTimer->InitWithCallback(this, delay, nsITimer::TYPE_ONE_SHOT);
   }
   return result;
 }
 
 nsresult
 nsPagePrintTimer::StartWatchDogTimer()
 {
@@ -57,17 +54,16 @@ nsPagePrintTimer::StartWatchDogTimer()
     mWatchDogTimer->Cancel();
   }
   mWatchDogTimer = do_CreateInstance("@mozilla.org/timer;1", &result);
   if (NS_FAILED(result)) {
     NS_WARNING("unable to start the timer");
   } else {
     // Instead of just doing one timer for a long period do multiple so we
     // can check if the user cancelled the printing.
-    mWatchDogTimer->SetTarget(mDocument->EventTargetFor(TaskCategory::Other));
     mWatchDogTimer->InitWithCallback(this, WATCH_DOG_INTERVAL,
                                      nsITimer::TYPE_ONE_SHOT);
   }
   return result;
 }
 
 void
 nsPagePrintTimer::StopWatchDogTimer()
@@ -157,18 +153,17 @@ nsPagePrintTimer::Notify(nsITimer *timer
   if (mDocViewerPrint) {
     bool donePrePrint = true;
     if (mPrintEngine) {
       donePrePrint = mPrintEngine->PrePrintPage();
     }
 
     if (donePrePrint && !mWaitingForRemotePrint) {
       StopWatchDogTimer();
-      // Pass nullptr here since name already was set in constructor.
-      mDocument->Dispatch(nullptr, TaskCategory::Other, do_AddRef(this));
+      NS_DispatchToMainThread(this);
     } else {
       // Start the watch dog if we're waiting for preprint to ensure that if any
       // mozPrintCallbacks take to long we error out.
       StartWatchDogTimer();
     }
 
   }
   return NS_OK;
@@ -188,32 +183,30 @@ nsPagePrintTimer::WaitForRemotePrint()
 
 void
 nsPagePrintTimer::RemotePrintFinished()
 {
   if (!mWaitingForRemotePrint) {
     return;
   }
 
-  mWaitingForRemotePrint->SetTarget(
-    mDocument->EventTargetFor(mozilla::TaskCategory::Other));
   mozilla::Unused <<
     mWaitingForRemotePrint->InitWithCallback(this, 0, nsITimer::TYPE_ONE_SHOT);
 }
 
-nsresult
+nsresult 
 nsPagePrintTimer::Start(nsPrintObject* aPO)
 {
   mPrintObj = aPO;
   mDone = false;
   return StartTimer(false);
 }
 
 
-void
+void  
 nsPagePrintTimer::Stop()
 {
   if (mTimer) {
     mTimer->Cancel();
     mTimer = nullptr;
   }
   StopWatchDogTimer();
 }
--- a/layout/printing/nsPagePrintTimer.h
+++ b/layout/printing/nsPagePrintTimer.h
@@ -9,43 +9,38 @@
 #include "nsITimer.h"
 
 #include "nsIDocumentViewerPrint.h"
 #include "nsPrintObject.h"
 #include "mozilla/Attributes.h"
 #include "nsThreadUtils.h"
 
 class nsPrintEngine;
-class nsIDocument;
 
 //---------------------------------------------------
 //-- Page Timer Class
 //---------------------------------------------------
 class nsPagePrintTimer final : public mozilla::Runnable,
                                public nsITimerCallback
 {
 public:
 
   NS_DECL_ISUPPORTS_INHERITED
 
   nsPagePrintTimer(nsPrintEngine* aPrintEngine,
                    nsIDocumentViewerPrint* aDocViewerPrint,
-                   nsIDocument* aDocument,
                    uint32_t aDelay)
-    : Runnable("nsPagePrintTimer")
-    , mPrintEngine(aPrintEngine)
+    : mPrintEngine(aPrintEngine)
     , mDocViewerPrint(aDocViewerPrint)
-    , mDocument(aDocument)
     , mDelay(aDelay)
     , mFiringCount(0)
     , mPrintObj(nullptr)
     , mWatchDogCount(0)
     , mDone(false)
   {
-    MOZ_ASSERT(aDocument);
     mDocViewerPrint->IncrementDestroyRefCount();
   }
 
   NS_DECL_NSITIMERCALLBACK
 
   nsresult Start(nsPrintObject* aPO);
 
   NS_IMETHOD Run() override;
@@ -62,17 +57,16 @@ private:
 
   nsresult StartTimer(bool aUseDelay);
   nsresult StartWatchDogTimer();
   void     StopWatchDogTimer();
   void     Fail();
 
   nsPrintEngine*             mPrintEngine;
   nsCOMPtr<nsIDocumentViewerPrint> mDocViewerPrint;
-  nsCOMPtr<nsIDocument>      mDocument;
   nsCOMPtr<nsITimer>         mTimer;
   nsCOMPtr<nsITimer>         mWatchDogTimer;
   nsCOMPtr<nsITimer>         mWaitingForRemotePrint;
   uint32_t                   mDelay;
   uint32_t                   mFiringCount;
   nsPrintObject *            mPrintObj;
   uint32_t                   mWatchDogCount;
   bool                       mDone;
--- a/layout/printing/nsPrintEngine.cpp
+++ b/layout/printing/nsPrintEngine.cpp
@@ -3490,25 +3490,21 @@ nsPrintEngine::FinishPrintPreview()
 
 /*=============== Timer Related Code ======================*/
 nsresult
 nsPrintEngine::StartPagePrintTimer(const UniquePtr<nsPrintObject>& aPO)
 {
   if (!mPagePrintTimer) {
     // Get the delay time in between the printing of each page
     // this gives the user more time to press cancel
-    if (!mDocument) {
-      MOZ_LOG(gPrintingLog, LogLevel::Error,("Error! mDocument is NULL"));
-      return NS_ERROR_FAILURE;
-    }
     int32_t printPageDelay = 50;
     mPrt->mPrintSettings->GetPrintPageDelay(&printPageDelay);
 
     RefPtr<nsPagePrintTimer> timer =
-      new nsPagePrintTimer(this, mDocViewerPrint, mDocument, printPageDelay);
+      new nsPagePrintTimer(this, mDocViewerPrint, printPageDelay);
     timer.forget(&mPagePrintTimer);
 
     nsCOMPtr<nsIPrintSession> printSession;
     nsresult rv = mPrt->mPrintSettings->GetPrintSession(getter_AddRefs(printSession));
     if (NS_SUCCEEDED(rv) && printSession) {
       RefPtr<mozilla::layout::RemotePrintJobChild> remotePrintJob;
       printSession->GetRemotePrintJob(getter_AddRefs(remotePrintJob));
       if (NS_SUCCEEDED(rv) && remotePrintJob) {
@@ -3555,22 +3551,19 @@ public:
 private:
   nsCOMPtr<nsIDocumentViewerPrint> mDocViewerPrint;
 };
 
 //-----------------------------------------------------------
 void
 nsPrintEngine::FirePrintCompletionEvent()
 {
-  MOZ_ASSERT(NS_IsMainThread());
   nsCOMPtr<nsIRunnable> event = new nsPrintCompletionEvent(mDocViewerPrint);
-  if (NS_FAILED(mDocument->Dispatch("nsPrintCompletionEvent",
-                                    TaskCategory::Other, event.forget()))) {
+  if (NS_FAILED(NS_DispatchToCurrentThread(event)))
     NS_WARNING("failed to dispatch print completion event");
-  }
 }
 
 void
 nsPrintEngine::DisconnectPagePrintTimer()
 {
   if (mPagePrintTimer) {
     mPagePrintTimer->Disconnect();
     NS_RELEASE(mPagePrintTimer);
--- a/layout/reftests/bidi/reftest.list
+++ b/layout/reftests/bidi/reftest.list
@@ -163,12 +163,12 @@ fuzzy-if(xulRuntime.widgetToolkit=="gtk3
 fuzzy-if(Android,254,557) == brackets-2a-rtl.html brackets-2a-rtl-ref.html
 == brackets-2b-ltr.html brackets-2b-ltr-ref.html
 == brackets-2b-rtl.html brackets-2b-rtl-ref.html
 == brackets-2c-ltr.html brackets-2c-ltr-ref.html
 fuzzy-if(Android,254,231) == brackets-2c-rtl.html brackets-2c-rtl-ref.html
 == brackets-3a-ltr.html brackets-3a-ltr-ref.html
 == brackets-3a-rtl.html brackets-3a-rtl-ref.html
 == brackets-3b-ltr.html brackets-3b-ltr-ref.html
-fuzzy-if(winWidget&&layersGPUAccelerated,49,233) fuzzy-if(winWidget&&!layersGPUAccelerated,56,75) == brackets-3b-rtl.html brackets-3b-rtl-ref.html
+== brackets-3b-rtl.html brackets-3b-rtl-ref.html
 == 1217833-1.html 1217833-1-ref.html
 == 1217833-2.html 1217833-2-ref.html
 == 1231175-1.html 1231175-1-ref.html
--- a/layout/reftests/box-shadow/reftest.list
+++ b/layout/reftests/box-shadow/reftest.list
@@ -27,21 +27,21 @@ fuzzy(2,440) == boxshadow-skiprect.html 
 == boxshadow-color-rounding-middle.html boxshadow-color-rounding-middle-ref.html
 fuzzy(3,500) fuzzy-if(d2d,2,1080) == boxshadow-border-radius-int.html boxshadow-border-radius-int-ref.html
 == boxshadow-inset-neg-spread.html about:blank
 == boxshadow-inset-neg-spread2.html boxshadow-inset-neg-spread2-ref.html
 fuzzy(26,3610) == boxshadow-rotated.html boxshadow-rotated-ref.html # Bug 1211264
 == boxshadow-inset-large-border-radius.html boxshadow-inset-large-border-radius-ref.html
 
 # fuzzy due to blur going inside, but as long as it's essentially black instead of a light gray its ok.
-fuzzy(13,9445) fuzzy-if(d2d,13,10926) fuzzy-if(webrender,13,13612) == boxshadow-inset-large-offset.html boxshadow-inset-large-offset-ref.html
+fuzzy(13,9445) fuzzy-if(d2d,13,10926) fuzzy-if(webrender,14,14307) == boxshadow-inset-large-offset.html boxshadow-inset-large-offset-ref.html
 
 == overflow-not-scrollable-1.html overflow-not-scrollable-1-ref.html
 == overflow-not-scrollable-1.html overflow-not-scrollable-1-ref2.html
 == overflow-not-scrollable-2.html overflow-not-scrollable-2-ref.html
-== 611574-1.html 611574-1-ref.html
+fuzzy-if(webrender,1,655) == 611574-1.html 611574-1-ref.html
 fuzzy-if(webrender,4,144) == 611574-2.html 611574-2-ref.html
 fuzzy-if(winWidget,5,30) fuzzy-if(skiaContent,16,10) == fieldset.html fieldset-ref.html # minor anti-aliasing problem on Windows
 fuzzy-if(winWidget,5,30) fuzzy-if(skiaContent,16,10) == fieldset-inset.html fieldset-inset-ref.html # minor anti-aliasing problem on Windows
 == 1178575.html 1178575-ref.html
 == 1178575-2.html 1178575-2-ref.html
 fuzzy(159,2) fails-if(!dwrite) == 1212823-1.html 1212823-1-ref.html
 == boxshadow-large-offset.html boxshadow-large-offset-ref.html
--- a/layout/reftests/css-break/reftest.list
+++ b/layout/reftests/css-break/reftest.list
@@ -1,13 +1,13 @@
 default-preferences pref(layout.css.box-decoration-break.enabled,true)
 
 == box-decoration-break-1.html box-decoration-break-1-ref.html
 fuzzy(1,20) fuzzy-if(skiaContent,1,700) == box-decoration-break-with-inset-box-shadow-1.html box-decoration-break-with-inset-box-shadow-1-ref.html
-fuzzy(16,460) fuzzy-if(Android,10,3673) fuzzy-if(skiaContent,32,254) fuzzy-if(winWidget,32,152) == box-decoration-break-with-outset-box-shadow-1.html box-decoration-break-with-outset-box-shadow-1-ref.html
+fuzzy(16,460) fuzzy-if(Android,10,3673) fuzzy-if(skiaContent,32,254) == box-decoration-break-with-outset-box-shadow-1.html box-decoration-break-with-outset-box-shadow-1-ref.html
 random-if(!gtkWidget) HTTP(..) == box-decoration-break-border-image.html box-decoration-break-border-image-ref.html
 == box-decoration-break-block-border-padding.html box-decoration-break-block-border-padding-ref.html
 == box-decoration-break-block-margin.html box-decoration-break-block-margin-ref.html
 fuzzy-if(!Android,1,62) fuzzy-if(Android,8,6627) == box-decoration-break-first-letter.html box-decoration-break-first-letter-ref.html #Bug 1313773
 == box-decoration-break-with-bidi.html box-decoration-break-with-bidi-ref.html
 == box-decoration-break-bug-1235152.html box-decoration-break-bug-1235152-ref.html
 == box-decoration-break-bug-1249913.html box-decoration-break-bug-1249913-ref.html
 == vertical-wm-001.html vertical-wm-001-ref.html
--- a/layout/reftests/forms/input/text/reftest.list
+++ b/layout/reftests/forms/input/text/reftest.list
@@ -1,10 +1,10 @@
 == bounds-1.html bounds-1-ref.html
-fuzzy-if(asyncPan&&!layersGPUAccelerated,140,111) fuzzy-if(winWidget&&layersGPUAccelerated,98,108) fuzzy-if(winWidget&&!layersGPUAccelerated,140,108) == size-1.html size-1-ref.html
+fuzzy-if(asyncPan&&!layersGPUAccelerated,140,111) == size-1.html size-1-ref.html
 == size-2.html size-2-ref.html
 HTTP(..) == baseline-1.html baseline-1-ref.html
 HTTP(..) == centering-1.xul centering-1-ref.xul
 == dynamic-height-1.xul dynamic-height-1-ref.xul
 fuzzy-if(skiaContent,1,500) needs-focus == select.html select-ref.html
 == intrinsic-size.html intrinsic-size-ref.html
 == line-height-0.5.html line-height-1.0.html
 != line-height-1.5.html line-height-1.0.html
--- a/layout/reftests/svg/svg-integration/reftest.list
+++ b/layout/reftests/svg/svg-integration/reftest.list
@@ -24,17 +24,17 @@ fuzzy-if(Android,255,30) == clipPath-htm
 == dynamic-conditions-outer-svg-02.xhtml ../pass.svg
 == dynamic-conditions-outer-svg-03.xhtml ../pass.svg
 == dynamic-conditions-outer-svg-04.xhtml ../pass.svg
 == filter-html-01.xhtml filter-html-01-ref.svg
 random-if(Android) == filter-html-01-extref.xhtml filter-html-01-ref.svg # Android: bug 1198380
 == filter-html-zoomed-01.xhtml filter-html-01-ref.svg
 == mask-html-01.xhtml mask-html-01-ref.svg
 == mask-html-01-extref-01.xhtml mask-html-01-ref.svg
-== mask-html-01-extref-02.xhtml mask-html-01-ref.svg
+random == mask-html-01-extref-02.xhtml mask-html-01-ref.svg # random due to bug 877661
 == mask-html-zoomed-01.xhtml mask-html-01-ref.svg
 == mask-html-xbl-bound-01.html mask-html-01-ref.svg
 == mask-transformed-html-01.xhtml ../pass.svg
 == mask-transformed-html-02.xhtml ../pass.svg
 fuzzy-if(skiaContent,1,5) == patterned-svg-under-transformed-html-01.xhtml ../pass.svg
 == patterned-svg-under-transformed-html-02.xhtml ../pass.svg
 
 fuzzy(1,5000) == mask-clipPath-opacity-01a.xhtml mask-clipPath-opacity-01-ref.xhtml
--- a/layout/reftests/w3c-css/submitted/writing-modes-3/reftest-stylo.list
+++ b/layout/reftests/w3c-css/submitted/writing-modes-3/reftest-stylo.list
@@ -1,13 +1,13 @@
 # DO NOT EDIT! This is a auto-generated temporary list for Stylo testing
 default-preferences pref(layout.css.text-combine-upright.enabled,true)
 
-== text-combine-upright-break-inside-001.html text-combine-upright-break-inside-001.html
-== text-combine-upright-break-inside-001a.html text-combine-upright-break-inside-001a.html
+fails == text-combine-upright-break-inside-001.html text-combine-upright-break-inside-001.html
+fails == text-combine-upright-break-inside-001a.html text-combine-upright-break-inside-001a.html
 fails == text-combine-upright-compression-001.html text-combine-upright-compression-001.html
 fails == text-combine-upright-compression-002.html text-combine-upright-compression-002.html
 fails == text-combine-upright-compression-003.html text-combine-upright-compression-003.html
 fails == text-combine-upright-compression-004.html text-combine-upright-compression-004.html
 fails == text-combine-upright-compression-005.html text-combine-upright-compression-005.html
 fails == text-combine-upright-compression-005a.html text-combine-upright-compression-005a.html
 fails == text-combine-upright-compression-006.html text-combine-upright-compression-006.html
 fails == text-combine-upright-compression-006a.html text-combine-upright-compression-006a.html
--- a/layout/xul/nsXULPopupManager.cpp
+++ b/layout/xul/nsXULPopupManager.cpp
@@ -1178,16 +1178,19 @@ nsXULPopupManager::HidePopupCallback(nsI
   // behaviour.
   nsEventStatus status = nsEventStatus_eIgnore;
   WidgetMouseEvent event(true, eXULPopupHidden, nullptr,
                          WidgetMouseEvent::eReal);
   EventDispatcher::Dispatch(aPopup, aPopupFrame->PresContext(),
                             &event, nullptr, &status);
   ENSURE_TRUE(weakFrame.IsAlive());
 
+  // Force any popups that might be anchored on elements within this popup to update.
+  UpdatePopupPositions(aPopupFrame->PresContext()->RefreshDriver());
+
   // if there are more popups to close, look for the next one
   if (aNextPopup && aPopup != aLastPopup) {
     nsMenuChainItem* foundMenu = nullptr;
     nsMenuChainItem* item = mPopups;
     while (item) {
       if (item->Content() == aNextPopup) {
         foundMenu = item;
         break;
--- a/mfbt/AlreadyAddRefed.h
+++ b/mfbt/AlreadyAddRefed.h
@@ -22,16 +22,24 @@ struct unused_t;
 /**
  * already_AddRefed cooperates with reference counting smart pointers to enable
  * you to assign in a pointer _without_ |AddRef|ing it.  You might want to use
  * this as a return type from a function that returns an already |AddRef|ed
  * pointer.
  *
  * TODO Move already_AddRefed to namespace mozilla.  This has not yet been done
  * because of the sheer number of usages of already_AddRefed.
+ *
+ * When should you use already_AddRefed<>?
+ * * Ensure a consumer takes ownership of a reference
+ * * Pass ownership without calling AddRef/Release (sometimes required in
+ *   off-main-thread code)
+ * * The ref pointer type you're using doesn't support move construction
+ *
+ * Otherwise, use Move(RefPtr/nsCOMPtr/etc).
  */
 template<class T>
 struct MOZ_MUST_USE_TYPE MOZ_NON_AUTOABLE already_AddRefed
 {
   /*
    * We want to allow returning nullptr from functions returning
    * already_AddRefed<T>, for simplicity.  But we also don't want to allow
    * returning raw T*, instead preferring creation of already_AddRefed<T> from
--- a/mobile/android/base/AndroidManifest.xml.in
+++ b/mobile/android/base/AndroidManifest.xml.in
@@ -312,16 +312,22 @@
 
 #ifdef MOZ_ANDROID_CUSTOM_TABS
         <activity android:name="org.mozilla.gecko.customtabs.CustomTabsActivity"
             android:theme="@style/GeckoCustomTabs" />
 #endif
         <activity android:name="org.mozilla.gecko.webapps.WebAppActivity"
             android:theme="@style/Theme.AppCompat.NoActionBar" />
 
+        <!-- Declare a predefined number of WebApp<num> activities. These are
+             used so that each web app can launch in its own activity. -->
+#define FRAGMENT WebAppManifestFragment.xml.frag.in
+#include WebAppFragmentRepeater.inc
+
+
         <!-- Service to handle requests from overlays. -->
         <service android:name="org.mozilla.gecko.overlays.service.OverlayActionService" />
 
         <!--
           Ensure that passwords provider runs in its own process. (Bug 718760.)
           Process name is per-application to avoid loading CPs from multiple
           Fennec versions into the same process. (Bug 749727.)
           Process name is a mangled version to avoid a Talos bug. (Bug 750548.)
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/WebAppFragmentRepeater.inc
@@ -0,0 +1,32 @@
+#define APPNUM 0
+#include @FRAGMENT@
+
+#define APPNUM 1
+#include @FRAGMENT@
+
+#define APPNUM 2
+#include @FRAGMENT@
+
+#define APPNUM 3
+#include @FRAGMENT@
+
+#define APPNUM 4
+#include @FRAGMENT@
+
+#define APPNUM 5
+#include @FRAGMENT@
+
+#define APPNUM 6
+#include @FRAGMENT@
+
+#define APPNUM 7
+#include @FRAGMENT@
+
+#define APPNUM 8
+#include @FRAGMENT@
+
+#define APPNUM 9
+#include @FRAGMENT@
+
+#undef APPNUM
+#undef FRAGMENT
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/WebAppManifestFragment.xml.frag.in
@@ -0,0 +1,9 @@
+        <activity android:name="org.mozilla.gecko.webapps.WebApps$WebApp@APPNUM@"
+                  android:label="WebApp"
+                  android:configChanges="keyboard|keyboardHidden|mcc|mnc|orientation|screenSize|locale|layoutDirection|smallestScreenSize|screenLayout"
+                  android:windowSoftInputMode="stateUnspecified|adjustResize"
+                  android:theme="@style/Gecko.App"
+                  android:taskAffinity="org.mozilla.gecko.webapps.WebApps@APPNUM@"
+                  android:launchMode="singleTask"
+                  android:exported="true"
+        />
--- a/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
@@ -2237,19 +2237,17 @@ public abstract class GeckoApp
             return;
         }
 
         foregrounded = true;
 
         GeckoAppShell.setGeckoInterface(this);
         GeckoAppShell.setScreenOrientationDelegate(this);
 
-        if (lastSelectedTabId >= 0 && (lastActiveGeckoApp == null || lastActiveGeckoApp.get() != this)) {
-            Tabs.getInstance().selectTab(lastSelectedTabId);
-        }
+        restoreLastSelectedTab();
 
         int newOrientation = getResources().getConfiguration().orientation;
         if (GeckoScreenOrientation.getInstance().update(newOrientation)) {
             refreshChrome();
         }
 
         if (mAppStateListeners != null) {
             for (GeckoAppShell.AppStateListener listener : mAppStateListeners) {
@@ -2291,16 +2289,22 @@ public abstract class GeckoApp
                     Log.w(LOGTAG, "Can't record session: rec is null.");
                 }
             }
         });
 
         Restrictions.update(this);
     }
 
+    protected void restoreLastSelectedTab() {
+        if (lastSelectedTabId >= 0 && (lastActiveGeckoApp == null || lastActiveGeckoApp.get() != this)) {
+            Tabs.getInstance().selectTab(lastSelectedTabId);
+        }
+    }
+
     @Override
     public void onWindowFocusChanged(boolean hasFocus) {
         super.onWindowFocusChanged(hasFocus);
 
         if (!mWindowFocusInitialized && hasFocus) {
             mWindowFocusInitialized = true;
             // XXX our editor tests require the GeckoView to have focus to pass, so we have to
             // manually shift focus to the GeckoView. requestFocus apparently doesn't work at
--- a/mobile/android/base/java/org/mozilla/gecko/LauncherActivity.java
+++ b/mobile/android/base/java/org/mozilla/gecko/LauncherActivity.java
@@ -1,22 +1,24 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
  * 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/. */
 
 package org.mozilla.gecko;
 
 import android.app.Activity;
+import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
 import android.support.annotation.NonNull;
 import android.support.customtabs.CustomTabsIntent;
 
 import org.mozilla.gecko.webapps.WebAppActivity;
+import org.mozilla.gecko.webapps.WebAppIndexer;
 import org.mozilla.gecko.customtabs.CustomTabsActivity;
 import org.mozilla.gecko.db.BrowserContract;
 import org.mozilla.gecko.mozglue.SafeIntent;
 import org.mozilla.gecko.preferences.GeckoPreferences;
 import org.mozilla.gecko.tabqueue.TabQueueHelper;
 import org.mozilla.gecko.tabqueue.TabQueueService;
 
 /**
@@ -84,21 +86,21 @@ public class LauncherActivity extends Ac
         intent.setClassName(getApplicationContext(), CustomTabsActivity.class.getName());
 
         filterFlags(intent);
 
         startActivity(intent);
     }
 
     private void dispatchWebAppIntent() {
-        Intent intent = new Intent(getIntent());
-        intent.setClassName(getApplicationContext(), WebAppActivity.class.getName());
-
-        filterFlags(intent);
-
+        final Intent intent = new Intent(getIntent());
+        final String manifestPath = getIntent().getStringExtra(WebAppActivity.MANIFEST_PATH);
+        final int index = WebAppIndexer.getInstance().getIndexForManifest(manifestPath, this);
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.setClassName(this, WebAppIndexer.WEBAPP_CLASS + index);
         startActivity(intent);
     }
 
     private static void filterFlags(Intent intent) {
         // Explicitly remove the new task and clear task flags (Our browser activity is a single
         // task activity and we never want to start a second task here). See bug 1280112.
         intent.setFlags(intent.getFlags() & ~Intent.FLAG_ACTIVITY_NEW_TASK);
         intent.setFlags(intent.getFlags() & ~Intent.FLAG_ACTIVITY_CLEAR_TASK);
--- a/mobile/android/base/java/org/mozilla/gecko/webapps/WebAppActivity.java
+++ b/mobile/android/base/java/org/mozilla/gecko/webapps/WebAppActivity.java
@@ -4,60 +4,89 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.webapps;
 
 import java.io.File;
 import java.io.IOException;
 
 import android.app.ActivityManager;
+import android.content.Intent;
 import android.graphics.Bitmap;
+import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
 import android.view.Window;
 import android.view.WindowManager;
 import android.util.Log;
 
 import org.json.JSONObject;
 import org.json.JSONException;
 
 import org.mozilla.gecko.AppConstants;
 import org.mozilla.gecko.EventDispatcher;
 import org.mozilla.gecko.GeckoApp;
 import org.mozilla.gecko.GeckoAppShell;
 import org.mozilla.gecko.GeckoProfile;
 import org.mozilla.gecko.icons.decoders.FaviconDecoder;
+import org.mozilla.gecko.mozglue.SafeIntent;
 import org.mozilla.gecko.R;
+import org.mozilla.gecko.Tabs;
 import org.mozilla.gecko.util.ColorUtil;
 import org.mozilla.gecko.util.EventCallback;
 import org.mozilla.gecko.util.FileUtils;
 import org.mozilla.gecko.util.GeckoBundle;
 
 public class WebAppActivity extends GeckoApp {
 
     public static final String INTENT_KEY = "IS_A_WEBAPP";
     public static final String MANIFEST_PATH = "MANIFEST_PATH";
 
     private static final String LOGTAG = "WebAppActivity";
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-
-        String manifestPath = getIntent().getStringExtra(WebAppActivity.MANIFEST_PATH);
-        if (manifestPath != null) {
-            updateFromManifest(manifestPath);
-        }
+        loadManifest(getIntent());
     }
 
     @Override
     public int getLayout() {
         return R.layout.webapp_activity;
     }
 
+    /**
+     * In case this activity is reused (the user has opened > 10 current web apps)
+     * we check that app launched is still within the same host as the
+     * shortcut has set, if not we reload the homescreens url
+     */
+    @Override
+    protected void onNewIntent(Intent externalIntent) {
+
+        restoreLastSelectedTab();
+
+        final SafeIntent intent = new SafeIntent(externalIntent);
+        final String launchUrl = intent.getDataString();
+        final String currentUrl = Tabs.getInstance().getSelectedTab().getURL();
+        final boolean isSameDomain = Uri.parse(currentUrl).getHost()
+            .equals(Uri.parse(launchUrl).getHost());
+
+        if (!isSameDomain) {
+            loadManifest(externalIntent);
+            Tabs.getInstance().loadUrl(launchUrl);
+        }
+    }
+
+    private void loadManifest(Intent intent) {
+        String manifestPath = intent.getStringExtra(WebAppActivity.MANIFEST_PATH);
+        if (manifestPath != null) {
+            updateFromManifest(manifestPath);
+        }
+    }
+
     private void updateFromManifest(String manifestPath) {
         try {
             final File manifestFile = new File(manifestPath);
             final JSONObject manifest = FileUtils.readJSONObjectFromFile(manifestFile);
             final JSONObject manifestField = (JSONObject) manifest.get("manifest");
             final Integer color = readColorFromManifest(manifestField);
             final String name = readNameFromManifest(manifestField);
             final Bitmap icon = readIconFromManifest(manifest);
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/java/org/mozilla/gecko/webapps/WebAppIndexer.java
@@ -0,0 +1,135 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
+ * 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/. */
+
+package org.mozilla.gecko.webapps;
+
+import java.util.ArrayList;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.support.annotation.UiThread;
+
+import org.mozilla.gecko.GeckoSharedPrefs;
+
+/**
+ * WebAppIndexer lets us create bookmarks that behave like android applications
+ * we create 10 slots of WebAppN in the manifest, when a bookmark is launched
+ * we take its manifest and assign it an index, subsequent launches of that
+ * bookmark are given the same index and therefore reopen the previous activity.
+ * We limit this to 10 spaces and recycle the least recently used index once
+ * we hit the limit, this means if the user can actively use 10 webapps at the same
+ * time, more than that and the last used will be replaced
+ **/
+
+public class WebAppIndexer {
+
+    public static final String WEBAPP_CLASS = "org.mozilla.gecko.webapps.WebApps$WebApp";
+
+    private final String mPrefNumSavedEntries = "WebAppIndexer.numActivities";
+    private final String mPrefActivityIndex = "WebAppIndexer.index";
+    private final String mPrefActivityId = "WebAppIndexer.manifest";
+
+    private static final int MAX_ACTIVITIES = 10;
+    private static final int INVALID_INDEX = -1;
+
+    private ArrayList<ActivityEntry> mActivityList = new ArrayList<ActivityEntry>();
+
+    private static class ActivityEntry {
+        public final int index;
+        public final String manifest;
+        ActivityEntry(int _index, String _manifest) {
+            index = _index;
+            manifest = _manifest;
+        }
+    }
+
+    private WebAppIndexer() { }
+    private final static WebAppIndexer INSTANCE = new WebAppIndexer();
+    public static WebAppIndexer getInstance() {
+        return INSTANCE;
+    }
+
+    public int getIndexForManifest(String manifest, Context context) {
+
+        if (mActivityList.size() == 0) {
+            loadActivityList(context);
+        }
+
+        int index = getManifestIndex(manifest);
+
+        // If we havent assigned this manifest an index then reassign the
+        // least recently used index
+        if (index == INVALID_INDEX) {
+            index = mActivityList.get(0).index;
+            final ActivityEntry newEntry = new ActivityEntry(index, manifest);
+            mActivityList.set(0, newEntry);
+        }
+
+        // Put the index at the back of the queue to be recycled
+        markActivityUsed(index, manifest, context);
+
+        return index;
+    }
+
+    private int getManifestIndex(String manifest) {
+        for (int i = mActivityList.size() - 1; i >= 0; i--) {
+            if (manifest.equals(mActivityList.get(i).manifest)) {
+                return mActivityList.get(i).index;
+            }
+        }
+        return INVALID_INDEX;
+    }
+
+    private void markActivityUsed(int index, String manifest, Context context) {
+        final int elementIndex = findActivityElement(index);
+        final ActivityEntry updatedEntry = new ActivityEntry(index, manifest);
+        mActivityList.remove(elementIndex);
+        mActivityList.add(updatedEntry);
+        storeActivityList(context);
+    }
+
+    private int findActivityElement(int index) {
+        for (int elementIndex = 0; elementIndex < mActivityList.size(); elementIndex++) {
+            if (mActivityList.get(elementIndex).index == index) {
+                return elementIndex;
+            }
+        }
+        return INVALID_INDEX;
+    }
+
+    // Store the list of assigned indexes in sharedPrefs because the LauncherActivity
+    // is likely to be killed and restarted between webapp launches
+    @UiThread
+    private void storeActivityList(Context context) {
+        final SharedPreferences prefs = GeckoSharedPrefs.forProfile(context);
+        final SharedPreferences.Editor editor = prefs.edit();
+        editor.clear();
+        editor.putInt(mPrefNumSavedEntries, mActivityList.size());
+        for (int i = 0; i < mActivityList.size(); ++i) {
+            editor.putInt(mPrefActivityIndex + i, mActivityList.get(i).index);
+            editor.putString(mPrefActivityId + i, mActivityList.get(i).manifest);
+        }
+        editor.apply();
+    }
+
+    @UiThread
+    private void loadActivityList(Context context) {
+        final SharedPreferences prefs = GeckoSharedPrefs.forProfile(context);
+        final int numSavedEntries = prefs.getInt(mPrefNumSavedEntries, 0);
+        for (int i = 0; i < numSavedEntries; ++i) {
+          int index = prefs.getInt(mPrefActivityIndex + i, i);
+          String manifest = prefs.getString(mPrefActivityId + i, null);
+          ActivityEntry entry = new ActivityEntry(index, manifest);
+          mActivityList.add(entry);
+        }
+
+        // Fill rest of the list with null spacers to be assigned
+        final int leftToFill = MAX_ACTIVITIES - mActivityList.size();
+        for (int i = 0; i < leftToFill; ++i) {
+            ActivityEntry entry = new ActivityEntry(i, null);
+            mActivityList.add(entry);
+        }
+    }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/java/org/mozilla/gecko/webapps/WebApps.java
@@ -0,0 +1,25 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
+ * 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/. */
+
+package org.mozilla.gecko.webapps;
+
+/**
+ * 10 predefined slots for homescreen webapps, in LauncherActivity
+ * launched webapps will be given an index (via WebAppIndexer) that
+ * points to one of these class names
+ **/
+