Merge mozilla-central to mozilla-inbound. a=merge CLOSED TREE
authorCiure Andrei <aciure@mozilla.com>
Sat, 15 Dec 2018 00:03:24 +0200
changeset 507911 df705aed115f7abd3fe6d173b9d1c7b6d8224322
parent 507910 8ea9cbbd44eb9c236e7323046e203a86cb2da40c (current diff)
parent 507655 d02d14a3dd6e172c4cc8efb5c749752d3893fc90 (diff)
child 507912 b37f33f2be2d164e3de71d8f17d89c967135a14c
push id10547
push userffxbld-merge
push dateMon, 21 Jan 2019 13:03:58 +0000
treeherdermozilla-beta@24ec1916bffe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone66.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to mozilla-inbound. a=merge CLOSED TREE
js/src/shell/js.cpp
--- a/.clang-format-ignore
+++ b/.clang-format-ignore
@@ -1,21 +1,13 @@
 # Uses the LLVM coding style
 build/clang-plugin/.*
 # The two templates cannot be formatted
 config/gcc-stl-wrapper.template.h
 config/msvc-stl-wrapper.template.h
-dom/base/test/.*
-dom/bindings/test/.*
-dom/media/gtest/.*
-gfx/testsd/.*
-.*/gtest/ExampleStylesheet.h
-image/test/.*
-ipc/ipdl/test/.*
-ipc/testshell/.*
 # Generated code
 js/src/builtin/intl/TimeZoneDataGenerated.h
 
 # Don't want to reformat irregexp. bug 1510128
 js/src/irregexp/.*
 
 # Generated by js/src/util/make_unicode.py
 # Note: the irregexp files are already excluded with the rest of js/src/irregexp
@@ -30,26 +22,16 @@ layout/style/nsCSSAnonBoxList.h
 layout/style/nsCSSCounterDescList.h
 layout/style/nsCSSFontDescList.h
 layout/style/nsCSSKeywordList.h
 layout/style/nsCSSPseudoElementList.h
 layout/style/nsCSSVisitedDependentPropList.h
 layout/style/nsDOMCSSValueList.h
 layout/style/nsStyleStructList.h
 
-media/mtransport/test/.*
-mfbt/tests/.*
-storage/test/.*
-testing/gtest/.*
-tools/profiler/tests/.*
-uriloader/exthandler/tests/.*
-widget/tests/.*
-xpcom/glue/tests/.*
-xpcom/tests/.*
-
 # Generated by protobuf
 .*/.*.pb.h
 .*/.*.pb.cc
 
 # Autogenerated file
 gfx/gl/GLConsts.h
 gfx/webrender_bindings/webrender_ffi_generated.h
 intl/unicharutil/util/nsUnicodePropertyData.cpp
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -767,17 +767,17 @@ dependencies = [
 name = "dump_syms_rust_demangle"
 version = "0.1.0"
 dependencies = [
  "rustc-demangle 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "dwrote"
-version = "0.6.2"
+version = "0.6.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 1.0.80 (git+https://github.com/servo/serde?branch=deserialize_from_enums9)",
  "winapi 0.3.6 (git+https://github.com/froydnj/winapi-rs?branch=aarch64)",
 ]
@@ -2928,17 +2928,17 @@ dependencies = [
  "app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "bincode 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-foundation 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-graphics 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-text 13.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "dwrote 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "dwrote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "freetype 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "gleam 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "plane-split 0.13.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "rayon 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2956,33 +2956,33 @@ name = "webrender_api"
 version = "0.57.2"
 dependencies = [
  "app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "bincode 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-foundation 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-graphics 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "dwrote 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "dwrote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_bytes 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 1.0.80 (git+https://github.com/servo/serde?branch=deserialize_from_enums9)",
  "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "webrender_bindings"
 version = "0.1.0"
 dependencies = [
  "app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "bincode 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-foundation 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-graphics 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "dwrote 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "dwrote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "foreign-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "gleam 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "nsstring 0.1.0",
  "rayon 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "thread_profiler 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -3178,17 +3178,17 @@ dependencies = [
 "checksum darling_macro 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "99c4eff4bcbeaf6a22578012ff79c95910338668278d1901e528bd34a22f575d"
 "checksum devd-rs 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e7c9ac481c38baf400d3b732e4a06850dfaa491d1b6379a249d9d40d14c2434c"
 "checksum diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3c2b69f912779fbb121ceb775d74d51e915af17aaebc38d28a592843a2dd0a3a"
 "checksum digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "03b072242a8cbaf9c145665af9d250c59af3b958f83ed6824e13533cf76d5b90"
 "checksum dirs 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "88972de891f6118092b643d85a0b28e0678e0f948d7f879aa32f2d5aafe97d2a"
 "checksum docopt 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d8acd393692c503b168471874953a2531df0e9ab77d0b6bbc582395743300a4a"
 "checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
 "checksum dtoa-short 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "068d4026697c1a18f0b0bb8cfcad1b0c151b90d8edb9bf4c235ad68128920d1d"
-"checksum dwrote 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7b46afd0d0bbbea88fc083ea293e40865e26a75ec9d38cf5d05a23ac3e2ffe02"
+"checksum dwrote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f0beca78470f26189a662e72afe7a54c625b4feb06b2d36c207ac15319bd57c5"
 "checksum either 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18785c1ba806c258137c937e44ada9ee7e69a37e3c72077542cd2f069d78562a"
 "checksum ena 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "88dc8393b3c7352f94092497f6b52019643e493b6b890eb417cdb7c46117e621"
 "checksum encoding_c 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "769ecb8b33323998e482b218c0d13cd64c267609023b4b7ec3ee740714c318ee"
 "checksum encoding_rs 0.8.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1a8fa54e6689eb2549c4efed8d00d7f3b2b994a064555b0e8df4ae3764bcc4be"
 "checksum env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0561146661ae44c579e993456bc76d11ce1e0c7d745e57b2fa7146b6e49fa2ad"
 "checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3"
 "checksum euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)" = "dbbf962bb6f877239a34491f2e0a12c6b824f389bc789eb90f1d70d4780b0727"
 "checksum failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6dd377bcc1b1b7ce911967e3ec24fa19c3224394ec05b54aa7b083d498341ac7"
--- a/caps/nsScriptSecurityManager.cpp
+++ b/caps/nsScriptSecurityManager.cpp
@@ -433,26 +433,69 @@ nsScriptSecurityManager::IsSystemPrincip
 NS_IMPL_ISUPPORTS(nsScriptSecurityManager, nsIScriptSecurityManager)
 
 ///////////////////////////////////////////////////
 // Methods implementing nsIScriptSecurityManager //
 ///////////////////////////////////////////////////
 
 ///////////////// Security Checks /////////////////
 
+#if defined(DEBUG) && !defined(ANDROID)
+static void AssertEvalNotUsingSystemPrincipal(nsIPrincipal* subjectPrincipal,
+                                              JSContext* cx) {
+  if (!nsContentUtils::IsSystemPrincipal(subjectPrincipal)) {
+    return;
+  }
+
+  if (Preferences::GetBool("security.allow_eval_with_system_principal")) {
+    return;
+  }
+
+  static StaticAutoPtr<nsTArray<nsCString>> sUrisAllowEval;
+  JS::AutoFilename scriptFilename;
+  if (JS::DescribeScriptedCaller(cx, &scriptFilename)) {
+    if (!sUrisAllowEval) {
+      sUrisAllowEval = new nsTArray<nsCString>();
+      nsAutoCString urisAllowEval;
+      Preferences::GetCString("security.uris_using_eval_with_system_principal",
+                              urisAllowEval);
+      for (const nsACString& filenameString : urisAllowEval.Split(',')) {
+        sUrisAllowEval->AppendElement(filenameString);
+      }
+      ClearOnShutdown(&sUrisAllowEval);
+    }
+
+    nsAutoCString fileName;
+    fileName = nsAutoCString(scriptFilename.get());
+    // Extract file name alone if scriptFilename contains line number
+    // separated by multiple space delimiters in few cases.
+    int32_t fileNameIndex = fileName.FindChar(' ');
+    if (fileNameIndex != -1) {
+      fileName = Substring(fileName, 0, fileNameIndex);
+    }
+    ToLowerCase(fileName);
+
+    for (auto& uriEntry : *sUrisAllowEval) {
+      if (StringEndsWith(fileName, uriEntry)) {
+        return;
+      }
+    }
+  }
+
+  MOZ_ASSERT(false, "do not use eval with system privileges");
+}
+#endif
+
 bool nsScriptSecurityManager::ContentSecurityPolicyPermitsJSAction(
     JSContext* cx, JS::HandleValue aValue) {
   MOZ_ASSERT(cx == nsContentUtils::GetCurrentJSContext());
   nsCOMPtr<nsIPrincipal> subjectPrincipal = nsContentUtils::SubjectPrincipal();
 
 #if defined(DEBUG) && !defined(ANDROID)
-  if (!(Preferences::GetBool("security.allow_eval_with_system_principal"))) {
-    MOZ_ASSERT(!nsContentUtils::IsSystemPrincipal(subjectPrincipal),
-               "do not use eval with system privileges");
-  }
+  AssertEvalNotUsingSystemPrincipal(subjectPrincipal, cx);
 #endif
 
   nsCOMPtr<nsIContentSecurityPolicy> csp;
   nsresult rv = subjectPrincipal->GetCsp(getter_AddRefs(csp));
   NS_ASSERTION(NS_SUCCEEDED(rv), "CSP: Failed to get CSP from principal.");
 
   // don't do anything unless there's a CSP
   if (!csp) return true;
--- a/devtools/server/actors/highlighters.css
+++ b/devtools/server/actors/highlighters.css
@@ -32,16 +32,18 @@
   --highlighter-bubble-text-color: hsl(216, 33%, 97%);
   --highlighter-bubble-background-color: hsl(214, 13%, 24%);
   --highlighter-bubble-border-color: rgba(255, 255, 255, 0.2);
   --highlighter-bubble-arrow-size: 8px;
   --highlighter-font-family: message-box;
   --highlighter-font-size: 11px;
   --highlighter-infobar-color: hsl(210, 30%, 85%);
   --highlighter-marker-color: #000;
+
+  --grey-40: #b1b1b3;
 }
 
 /**
  * Highlighters are asbolute positioned in the page by default.
  * A single highlighter can have fixed position in its css class if needed (see below the
  * eye dropper or rulers highlighter, for example); but if it has to handle the
  * document's scrolling (as rulers does), it would lag a bit behind due the APZ (Async
  * Pan/Zoom module), that performs asynchronously panning and zooming on the compositor
@@ -637,25 +639,62 @@
 }
 
 :-moz-native-anonymous .shapes-marker-hover {
   fill: var(--highlighter-guide-color);
 }
 
 /* Accessible highlighter */
 
+:-moz-native-anonymous .accessible-infobar {
+  min-width: unset;
+}
+
+:-moz-native-anonymous .accessible-infobar-text {
+  display: grid;
+  grid-template-areas:
+    "role name"
+    "audit audit";
+  grid-template-columns: min-content 1fr;
+}
+
+:-moz-native-anonymous .accessible-infobar-role {
+  grid-area: role;
+  color: #9CDCFE;
+}
+
+:-moz-native-anonymous .accessible-infobar-name {
+  grid-area: name;
+}
+
+:-moz-native-anonymous .accessible-infobar-audit {
+  grid-area: audit;
+  padding-top: 5px;
+  padding-bottom: 2px;
+}
+
 :-moz-native-anonymous .accessible-bounds {
   opacity: 0.6;
   fill: #6a5acd;
 }
 
 :-moz-native-anonymous .accessible-infobar-name,
 :-moz-native-anonymous .accessible-infobar-audit {
   color: var(--highlighter-infobar-color);
-  max-width: 90%;
+}
+
+:-moz-native-anonymous .accessible-infobar-audit .accessible-contrast-ratio:not(:empty):before {
+  content: "";
+  height: 8px;
+  width: 8px;
+  display: inline-flex;
+  background-color: var(--accessibility-highlighter-contrast-ratio-color);
+  box-shadow: 0 0 0 1px var(--grey-40), 4px 3px var(--accessibility-highlighter-contrast-ratio-bg), 4px 3px 0 1px var(--grey-40);
+  margin-inline-start: 3px;
+  margin-inline-end: 9px;
 }
 
 :-moz-native-anonymous .accessible-infobar-audit .accessible-contrast-ratio:not(:empty):after {
   margin-inline-start: 2px;
 }
 
 :-moz-native-anonymous .accessible-infobar-audit .accessible-contrast-ratio:not(:empty).AA:after,
 :-moz-native-anonymous .accessible-infobar-audit .accessible-contrast-ratio:not(:empty).AAA:after {
@@ -671,30 +710,22 @@
   content: "AA\2713";
 }
 
 :-moz-native-anonymous .accessible-infobar-audit .accessible-contrast-ratio:not(:empty).AAA:after {
   content: "AAA\2713";
 }
 
 :-moz-native-anonymous .accessible-infobar-audit .accessible-contrast-ratio-label,
-:-moz-native-anonymous .accessible-infobar-audit #accessible-contrast-ratio-max:not(:empty):before {
+:-moz-native-anonymous .accessible-infobar-audit .accessible-contrast-ratio-separator:before {
   margin-inline-end: 3px;
 }
 
-:-moz-native-anonymous .accessible-infobar-audit #accessible-contrast-ratio-max {
+:-moz-native-anonymous .accessible-infobar-audit .accessible-contrast-ratio-separator:before {
+  content: "-";
   margin-inline-start: 3px;
 }
 
-:-moz-native-anonymous .accessible-infobar-audit #accessible-contrast-ratio-max:not(:empty):before {
-  content: "-";
-}
-
-:-moz-native-anonymous .accessible-infobar-name:not(:empty),
-:-moz-native-anonymous .accessible-infobar-audit:not(:empty) {
+:-moz-native-anonymous .accessible-infobar-name:not(:empty) {
   border-inline-start: 1px solid #5a6169;
   margin-inline-start: 6px;
   padding-inline-start: 6px;
 }
-
-:-moz-native-anonymous .accessible-infobar-role {
-  color: #9CDCFE;
-}
--- a/devtools/server/actors/highlighters/utils/accessibility.js
+++ b/devtools/server/actors/highlighters/utils/accessibility.js
@@ -474,24 +474,23 @@ class ContrastRatio extends AuditReport 
     createNode(this.win, {
       nodeType: "span",
       parent: root,
       attributes: {
         "class": "contrast-ratio-label",
         "id": "contrast-ratio-label",
       },
       prefix: this.prefix,
-      text: L10N.getStr("accessibility.contrast.ratio.label"),
     });
 
     createNode(this.win, {
       nodeType: "span",
       parent: root,
       attributes: {
-        "class": "contrast-ratio",
+        "class": "contrast-ratio-error",
         "id": "contrast-ratio-error",
       },
       prefix: this.prefix,
       text: L10N.getStr("accessibility.contrast.ratio.error"),
     });
 
     createNode(this.win, {
       nodeType: "span",
@@ -502,69 +501,92 @@ class ContrastRatio extends AuditReport 
       },
       prefix: this.prefix,
     });
 
     createNode(this.win, {
       nodeType: "span",
       parent: root,
       attributes: {
+        "class": "contrast-ratio-separator",
+        "id": "contrast-ratio-separator",
+      },
+      prefix: this.prefix,
+    });
+
+    createNode(this.win, {
+      nodeType: "span",
+      parent: root,
+      attributes: {
         "class": "contrast-ratio",
         "id": "contrast-ratio-max",
       },
       prefix: this.prefix,
     });
   }
 
-  _fillAndStyleContrastValue(el, value, isLargeText, stringName) {
+  _fillAndStyleContrastValue(el, { value, isLargeText, color, backgroundColor }) {
     value = value.toFixed(2);
     const style = getContrastRatioScoreStyle(value, isLargeText);
-    this.setTextContent(el, stringName ? L10N.getFormatStr(stringName, value) : value);
+    this.setTextContent(el, value);
     el.classList.add(style);
+    el.setAttribute("style",
+      `--accessibility-highlighter-contrast-ratio-color: rgba(${color});` +
+      `--accessibility-highlighter-contrast-ratio-bg: rgba(${backgroundColor});`);
     el.removeAttribute("hidden");
   }
 
   /**
    * Update contrast ratio score infobar markup.
    * @param  {Number}
    *         Contrast ratio for an accessible object being highlighted.
    * @return {Boolean}
    *         True if the contrast ratio markup was updated correctly and infobar audit
    *         block should be visible.
    */
   update({ contrastRatio }) {
     const els = {};
-    for (const key of ["label", "min", "max", "error"]) {
+    for (const key of ["label", "min", "max", "error", "separator"]) {
       const el = els[key] = this.getElement(`contrast-ratio-${key}`);
       if (["min", "max"].includes(key)) {
         ["fail", "AA", "AAA"].forEach(className => el.classList.remove(className));
         this.setTextContent(el, "");
       }
 
       el.setAttribute("hidden", true);
+      el.removeAttribute("style");
     }
 
     if (!contrastRatio) {
       return false;
     }
 
     const { isLargeText, error } = contrastRatio;
+    this.setTextContent(els.label,
+      L10N.getFormatStr("accessibility.contrast.ratio.label2",
+        isLargeText ? L10N.getStr("accessibility.contrast.ratio.large") : ""));
     els.label.removeAttribute("hidden");
     if (error) {
       els.error.removeAttribute("hidden");
       return true;
     }
 
     if (contrastRatio.value) {
-      this._fillAndStyleContrastValue(els.min, contrastRatio.value, isLargeText);
+      const { value, color, backgroundColor } = contrastRatio;
+      this._fillAndStyleContrastValue(els.min,
+        { value, isLargeText, color, backgroundColor });
       return true;
     }
 
-    this._fillAndStyleContrastValue(els.min, contrastRatio.min, isLargeText);
-    this._fillAndStyleContrastValue(els.max, contrastRatio.max, isLargeText);
+    const { min, max, color, backgroundColorMin, backgroundColorMax } = contrastRatio;
+    this._fillAndStyleContrastValue(els.min,
+      { value: min, isLargeText, color, backgroundColor: backgroundColorMin });
+    els.separator.removeAttribute("hidden");
+    this._fillAndStyleContrastValue(els.max,
+      { value: max, isLargeText, color, backgroundColor: backgroundColorMax });
 
     return true;
   }
 }
 
 /**
  * A helper function that calculate accessible object bounds and positioning to
  * be used for highlighting.
--- a/devtools/server/actors/highlighters/xul-accessible.js
+++ b/devtools/server/actors/highlighters/xul-accessible.js
@@ -13,16 +13,18 @@ const { TEXT_NODE } = require("devtools/
  * Stylesheet used for highlighter styling of accessible objects in chrome. It
  * is consistent with the styling of an in-content accessible highlighter.
  */
 const ACCESSIBLE_BOUNDS_SHEET = "data:text/css;charset=utf-8," + encodeURIComponent(`
   .highlighter-container {
     --highlighter-bubble-background-color: hsl(214, 13%, 24%);
     --highlighter-bubble-border-color: rgba(255, 255, 255, 0.2);
     --highlighter-bubble-arrow-size: 8px;
+
+    --grey-40: #b1b1b3;
   }
 
   .accessible-bounds {
     position: fixed;
     pointer-events: none;
     z-index: 10;
     display: block;
     background-color: #6a5acd!important;
@@ -34,17 +36,16 @@ const ACCESSIBLE_BOUNDS_SHEET = "data:te
     max-width: 90%;
     z-index: 11;
   }
 
   .accessible-infobar {
     position: relative;
     left: -50%;
     background-color: var(--highlighter-bubble-background-color);
-    min-width: 75px;
     border: 1px solid var(--highlighter-bubble-border-color);
     border-radius: 3px;
     padding: 5px;
   }
 
   .accessible-arrow {
     position: absolute;
     width: 0;
@@ -62,26 +63,57 @@ const ACCESSIBLE_BOUNDS_SHEET = "data:te
 
   .bottom {
     border-top: var(--highlighter-bubble-arrow-size) solid
       var(--highlighter-bubble-background-color);
     bottom: calc(-1 * var(--highlighter-bubble-arrow-size));
   }
 
   .accessible-infobar-text {
+    display: grid;
+    grid-template-areas:
+      "role name"
+      "audit audit";
+    grid-template-columns: min-content 1fr;
     overflow: hidden;
     white-space: nowrap;
-    display: flex;
     justify-content: center;
   }
 
+  .accessible-infobar-role {
+    color: #9CDCFE;
+    grid-area: role;
+  }
+
+  .accessible-infobar-name {
+    grid-area: name;
+  }
+
+  .accessible-infobar-audit {
+    grid-area: audit;
+    padding-top: 5px;
+    padding-bottom: 2px;
+  }
+
   .accessible-infobar-name,
   .accessible-infobar-audit {
     color: hsl(210, 30%, 85%);
-    max-width: 90%;
+  }
+
+  .accessible-infobar-audit .accessible-contrast-ratio:not(:empty):before {
+    content: "";
+    height: 8px;
+    width: 8px;
+    display: inline-flex;
+    background-color: var(--accessibility-highlighter-contrast-ratio-color);
+    box-shadow: 0 0 0 1px var(--grey-40),
+                4px 3px var(--accessibility-highlighter-contrast-ratio-bg),
+                4px 3px 0 1px var(--grey-40);
+    margin-inline-start: 3px;
+    margin-inline-end: 9px;
   }
 
   .accessible-infobar-audit .accessible-contrast-ratio:not(:empty):after {
     margin-inline-start: 2px;
   }
 
   .accessible-infobar-audit .accessible-contrast-ratio:not(:empty).AA:after,
   .accessible-infobar-audit .accessible-contrast-ratio:not(:empty).AAA:after {
@@ -97,37 +129,29 @@ const ACCESSIBLE_BOUNDS_SHEET = "data:te
     content: "AA\u2713";
   }
 
   .accessible-infobar-audit .accessible-contrast-ratio:not(:empty).AAA:after {
     content: "AAA\u2713";
   }
 
   .accessible-infobar-audit .accessible-contrast-ratio-label,
-  .accessible-infobar-audit #accessible-contrast-ratio-max:not(:empty):before {
+  .accessible-infobar-audit .accessible-contrast-ratio-separator:before {
     margin-inline-end: 3px;
   }
 
-  .accessible-infobar-audit #accessible-contrast-ratio-max {
+  .accessible-infobar-audit .accessible-contrast-ratio-separator:before {
+    content: "-";
     margin-inline-start: 3px;
   }
 
-  .accessible-infobar-audit #accessible-contrast-ratio-max:not(:empty):before {
-    content: "-";
-  }
-
-  .accessible-infobar-name:not(:empty),
-  .accessible-infobar-audit:not(:empty) {
+  .accessible-infobar-name:not(:empty) {
     border-inline-start: 1px solid #5a6169;
     margin-inline-start: 6px;
     padding-inline-start: 6px;
-  }
-
-  .accessible-infobar-role {
-    color: #9CDCFE;
   }`);
 
 /**
  * The XULWindowAccessibleHighlighter is a class that has the same API as the
  * AccessibleHighlighter, and by extension other highlighters that implement
  * auto-refresh highlighter, but instead of drawing in canvas frame anonymous
  * content (that is not available for chrome accessible highlighting) it adds a
  * transparrent inactionable element with the same position and bounds as the
--- a/devtools/server/actors/source.js
+++ b/devtools/server/actors/source.js
@@ -558,18 +558,18 @@ const SourceActor = ActorClassWithSpec(s
    *        A condition which must be true for breakpoint to be hit.
    * @param Boolean noSliding
    *        If true, disables breakpoint sliding.
    *
    * @returns Promise
    *          A promise that resolves to a JSON object representing the
    *          response.
    */
-  setBreakpoint: function(line, column, condition, noSliding) {
-    if (this.threadActor.state !== "paused") {
+  setBreakpoint: function(line, column, condition, noSliding, inNestedLoop) {
+    if (!inNestedLoop && this.threadActor.state !== "paused") {
       const errorObject = {
         error: "wrongState",
         message: "Cannot set breakpoint while debuggee is running.",
       };
       throw errorObject;
     }
 
     const location = new OriginalLocation(this, line, column);
--- a/devtools/server/actors/thread.js
+++ b/devtools/server/actors/thread.js
@@ -75,35 +75,42 @@ const ThreadActor = ActorClassWithSpec(t
     this.sourceActorStore = new SourceActorStore();
 
     this._debuggerSourcesSeen = null;
 
     // A map of actorID -> actor for breakpoints created and managed by the
     // server.
     this._hiddenBreakpoints = new Map();
 
+    // A Set of URLs string to watch for when new sources are found by
+    // the debugger instance.
+    this._onLoadBreakpointURLs = new Set();
+
     this.global = global;
 
     this._allEventsListener = this._allEventsListener.bind(this);
     this.onNewSourceEvent = this.onNewSourceEvent.bind(this);
     this.onUpdatedSourceEvent = this.onUpdatedSourceEvent.bind(this);
 
     this.uncaughtExceptionHook = this.uncaughtExceptionHook.bind(this);
     this.createCompletionGrip = this.createCompletionGrip.bind(this);
     this.onDebuggerStatement = this.onDebuggerStatement.bind(this);
     this.onNewScript = this.onNewScript.bind(this);
     this.objectGrip = this.objectGrip.bind(this);
     this.pauseObjectGrip = this.pauseObjectGrip.bind(this);
     this._onWindowReady = this._onWindowReady.bind(this);
     this._onOpeningRequest = this._onOpeningRequest.bind(this);
     EventEmitter.on(this._parent, "window-ready", this._onWindowReady);
 
-    // Set a wrappedJSObject property so |this| can be sent via the observer svc
-    // for the xpcshell harness.
-    this.wrappedJSObject = this;
+    if (Services.obs) {
+      // Set a wrappedJSObject property so |this| can be sent via the observer svc
+      // for the xpcshell harness.
+      this.wrappedJSObject = this;
+      Services.obs.notifyObservers(this, "devtools-thread-instantiated");
+    }
   },
 
   // Used by the ObjectActor to keep track of the depth of grip() calls.
   _gripDepth: null,
 
   get dbg() {
     if (!this._dbg) {
       this._dbg = this._parent.makeDebugger();
@@ -301,16 +308,27 @@ const ThreadActor = ActorClassWithSpec(t
       // now.
       return null;
     } catch (e) {
       reportError(e);
       return { error: "notAttached", message: e.toString() };
     }
   },
 
+  /**
+   * Tell the thread to automatically add a breakpoint on the first line of
+   * a given file, when it is first loaded.
+   *
+   * This is currently only used by the xpcshell test harness, and unless
+   * we decide to expand the scope of this feature, we should keep it that way.
+   */
+  setBreakpointOnLoad(urls) {
+    this._onLoadBreakpointURLs = new Set(urls);
+  },
+
   _findXHRBreakpointIndex(p, m) {
     return this._xhrBreakpoints.findIndex(
       ({ path, method }) => path === p && method === m);
   },
 
   removeXHRBreakpoint: function(path, method) {
     const index = this._findXHRBreakpointIndex(path, method);
 
@@ -2012,16 +2030,22 @@ const ThreadActor = ActorClassWithSpec(t
         } else {
           actor.originalLocation.originalSourceActor._setBreakpointAtGeneratedLocation(
             actor, GeneratedLocation.fromOriginalLocation(actor.originalLocation)
           );
         }
       }
     }
 
+    if (this._onLoadBreakpointURLs.has(source.url)) {
+      this.unsafeSynchronize(
+        sourceActor.setBreakpoint(1, undefined, undefined, undefined, true)
+      );
+    }
+
     this._debuggerSourcesSeen.add(source);
     return true;
   },
 
   /**
    * Get prototypes and properties of multiple objects.
    */
   onPrototypesAndProperties: function(request) {
--- a/devtools/server/actors/utils/accessibility.js
+++ b/devtools/server/actors/utils/accessibility.js
@@ -191,28 +191,37 @@ function getContrastRatioFor(node, optio
       error: true,
     };
   }
 
   const { color, isLargeText } = props;
   if (rgba.value) {
     return {
       value: colorUtils.calculateContrastRatio(rgba.value, color),
+      color,
+      backgroundColor: rgba.value,
       isLargeText,
     };
   }
 
-  // calculateContrastRatio modifies the array, since we need to use color array twice,
-  // pass its copy to the method.
-  const min = colorUtils.calculateContrastRatio(rgba.min, Array.from(color));
-  const max = colorUtils.calculateContrastRatio(rgba.max, Array.from(color));
+  let min = colorUtils.calculateContrastRatio(rgba.min, color);
+  let max = colorUtils.calculateContrastRatio(rgba.max, color);
+
+  // Flip minimum and maximum contrast ratios if necessary.
+  if (min > max) {
+    [min, max] = [max, min];
+    [rgba.min, rgba.max] = [rgba.max, rgba.min];
+  }
 
   return {
-    min: min < max ? min : max,
-    max: min < max ? max : min,
+    min,
+    max,
+    color,
+    backgroundColorMin: rgba.min,
+    backgroundColorMax: rgba.max,
     isLargeText,
   };
 }
 
 /**
  * Helper function that determines if nsIAccessible object is in defunct state.
  *
  * @param  {nsIAccessible}  accessible
--- a/devtools/shared/css/color.js
+++ b/devtools/shared/css/color.js
@@ -1192,16 +1192,20 @@ function blendColors(foregroundColor, ba
  *
  * @param {Array} backgroundColor An array with [r,g,b,a] values containing
  * the background color.
  * @param {Array} textColor An array with [r,g,b,a] values containing
  * the text color.
  * @return {Number} The calculated luminance.
  */
 function calculateContrastRatio(backgroundColor, textColor) {
+  // Do not modify given colors.
+  backgroundColor = Array.from(backgroundColor);
+  textColor = Array.from(textColor);
+
   backgroundColor = blendColors(backgroundColor);
   textColor = blendColors(textColor, backgroundColor);
 
   const backgroundLuminance = calculateLuminance(backgroundColor);
   const textLuminance = calculateLuminance(textColor);
   const ratio = (textLuminance + 0.05) / (backgroundLuminance + 0.05);
 
   return (ratio > 1.0) ? ratio : (1 / ratio);
--- a/devtools/shared/locales/en-US/accessibility.properties
+++ b/devtools/shared/locales/en-US/accessibility.properties
@@ -6,11 +6,18 @@
 # ratio description, used by the accessibility highlighter to display the value. %S in the
 # content will be replaced by the contrast ratio numerical value.
 accessibility.contrast.ratio=Contrast: %S
 
 # LOCALIZATION NOTE (accessibility.contrast.ratio.error): A title text for the color
 # contrast ratio, used when the tool is unable to calculate the contrast ratio value.
 accessibility.contrast.ratio.error=Unable to calculate
 
-# LOCALIZATION NOTE (accessibility.contrast.ratio.label): A title text for the color
-# contrast ratio description, used together with the actual values.
-accessibility.contrast.ratio.label=Contrast:
+# LOCALIZATION NOTE (accessibility.contrast.ratio.label2): A title text for the color
+# contrast ratio description, used together with the actual values. %S in the
+# content will optionally be replaced by the text that indicates that large text is being
+# analyzed (see accessibility.contrast.ratio.large).
+accessibility.contrast.ratio.label2=Contrast%S:
+
+# LOCALIZATION NOTE (accessibility.contrast.ratio.large): A title text for the color
+# contrast ratio that specifies that the color contrast criteria used is if for large
+# text.
+accessibility.contrast.ratio.large=\u0020(large text)
--- a/gfx/webrender_bindings/Cargo.toml
+++ b/gfx/webrender_bindings/Cargo.toml
@@ -18,15 +18,15 @@ fxhash = "0.2.1"
 
 [dependencies.webrender]
 path = "../wr/webrender"
 version = "0.57.2"
 default-features = false
 features = ["capture", "serialize_program"]
 
 [target.'cfg(target_os = "windows")'.dependencies]
-dwrote = "0.6.2"
+dwrote = "0.6.3"
 
 [target.'cfg(target_os = "macos")'.dependencies]
 core-foundation = "0.6"
 core-graphics = "0.17.1"
 foreign-types = "0.3.0"
 
--- a/gfx/webrender_bindings/revision.txt
+++ b/gfx/webrender_bindings/revision.txt
@@ -1,1 +1,1 @@
-22f3f356ea1a9fe2760cd4a609cba78614e428c4
+d2c673ada607f29846c3d1ac8ca7d2b272ba1b2d
--- a/gfx/wr/Cargo.lock
+++ b/gfx/wr/Cargo.lock
@@ -357,17 +357,17 @@ source = "registry+https://github.com/ru
 
 [[package]]
 name = "dtoa"
 version = "0.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "dwrote"
-version = "0.6.2"
+version = "0.6.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 1.0.80 (git+https://github.com/servo/serde?branch=deserialize_from_enums9)",
  "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -1536,17 +1536,17 @@ dependencies = [
  "base64 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "bincode 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-foundation 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-graphics 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-text 13.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "dwrote 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "dwrote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "freetype 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "gleam 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "image 0.20.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "mozangle 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1588,17 +1588,17 @@ name = "webrender_api"
 version = "0.57.2"
 dependencies = [
  "app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "bincode 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-foundation 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-graphics 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "dwrote 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "dwrote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_bytes 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 1.0.80 (git+https://github.com/servo/serde?branch=deserialize_from_enums9)",
  "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -1667,17 +1667,17 @@ dependencies = [
  "app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "base64 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "bincode 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-foundation 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-graphics 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "crossbeam 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
- "dwrote 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "dwrote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "font-loader 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "gleam 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "glutin 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "image 0.20.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1795,17 +1795,17 @@ dependencies = [
 "checksum crossbeam-epoch 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "30fecfcac6abfef8771151f8be4abc9e4edc112c2bcb233314cafde2680536e9"
 "checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9"
 "checksum crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "677d453a17e8bd2b913fa38e8b9cf04bcdbb5be790aa294f2389661d72036015"
 "checksum deflate 0.7.18 (registry+https://github.com/rust-lang/crates.io-index)" = "32c8120d981901a9970a3a1c97cf8b630e0fa8c3ca31e75b6fd6fd5f9f427b31"
 "checksum digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "03b072242a8cbaf9c145665af9d250c59af3b958f83ed6824e13533cf76d5b90"
 "checksum dlib 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "77e51249a9d823a4cb79e3eca6dcd756153e8ed0157b6c04775d04bf1b13b76a"
 "checksum downcast-rs 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "18df8ce4470c189d18aa926022da57544f31e154631eb4cfe796aea97051fe6c"
 "checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
-"checksum dwrote 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7b46afd0d0bbbea88fc083ea293e40865e26a75ec9d38cf5d05a23ac3e2ffe02"
+"checksum dwrote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f0beca78470f26189a662e72afe7a54c625b4feb06b2d36c207ac15319bd57c5"
 "checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0"
 "checksum env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0e6e40ebb0e66918a37b38c7acab4e10d299e0463fe2af5d29b9cc86710cfd2a"
 "checksum euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)" = "dbbf962bb6f877239a34491f2e0a12c6b824f389bc789eb90f1d70d4780b0727"
 "checksum expat-sys 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c470ccb972f2088549b023db8029ed9da9426f5affbf9b62efff7009ab8ed5b1"
 "checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
 "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
 "checksum font-loader 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fd330f40acb3016432cbfa4c54b3d6e6e893a538df79d8df8fd8c26e21c36aaa"
 "checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
--- a/gfx/wr/webrender/Cargo.toml
+++ b/gfx/wr/webrender/Cargo.toml
@@ -69,14 +69,14 @@ optional = true
 [dev-dependencies]
 mozangle = "0.1"
 rand = "0.4"
 
 [target.'cfg(any(target_os = "android", all(unix, not(target_os = "macos"))))'.dependencies]
 freetype = { version = "0.4", default-features = false }
 
 [target.'cfg(target_os = "windows")'.dependencies]
-dwrote = "0.6.2"
+dwrote = "0.6.3"
 
 [target.'cfg(target_os = "macos")'.dependencies]
 core-foundation = "0.6"
 core-graphics = "0.17.1"
 core-text = { version = "13", default-features = false }
--- a/gfx/wr/webrender/src/display_list_flattener.rs
+++ b/gfx/wr/webrender/src/display_list_flattener.rs
@@ -151,27 +151,16 @@ pub struct DisplayListFlattener<'a> {
 
     /// Reference to the document resources, which contains
     /// shared (interned) data between display lists.
     resources: &'a mut DocumentResources,
 
     /// The root picture index for this flattener. This is the picture
     /// to start the culling phase from.
     pub root_pic_index: PictureIndex,
-
-    /// TODO(gw): This is a complete hack that relies on knowledge of
-    ///           what the Gecko display list looks like. It's used
-    ///           for now to work out which scroll root to use to
-    ///           create the picture cache for the content. It's only
-    ///           ever used if picture caching is enabled in the
-    ///           RendererOptions struct. We will need to work out
-    ///           a better API to avoid this, before we enable it
-    ///           for all users. Another alternative is that this
-    ///           will disappear itself when document splitting is used.
-    picture_cache_scroll_root: Option<SpatialNodeIndex>,
 }
 
 impl<'a> DisplayListFlattener<'a> {
     pub fn create_frame_builder(
         scene: &Scene,
         clip_scroll_tree: &mut ClipScrollTree,
         font_instances: FontInstanceMap,
         view: &DocumentView,
@@ -199,38 +188,31 @@ impl<'a> DisplayListFlattener<'a> {
             hit_testing_runs: Vec::new(),
             pending_shadow_items: VecDeque::new(),
             sc_stack: Vec::new(),
             pipeline_clip_chain_stack: vec![ClipChainId::NONE],
             prim_store: PrimitiveStore::new(&prim_store_stats),
             clip_store: ClipStore::new(),
             resources,
             root_pic_index: PictureIndex(0),
-            picture_cache_scroll_root: None,
         };
 
         flattener.push_root(
             root_pipeline_id,
             &root_pipeline.viewport_size,
             &root_pipeline.content_size,
         );
 
         flattener.flatten_root(
             root_pipeline,
             &root_pipeline.viewport_size,
         );
 
         debug_assert!(flattener.sc_stack.is_empty());
 
-        // If picture caching is enabled, splice up the root
-        // stacking context to enable correct surface caching.
-        flattener.setup_picture_caching(
-            root_pipeline_id,
-        );
-
         new_scene.root_pipeline_id = Some(root_pipeline_id);
         new_scene.pipeline_epochs = scene.pipeline_epochs.clone();
         new_scene.pipelines = scene.pipelines.clone();
 
         FrameBuilder::with_display_list_flattener(
             view.inner_rect,
             background_color,
             view.window_size,
@@ -240,17 +222,17 @@ impl<'a> DisplayListFlattener<'a> {
 
     /// Cut the primitives in the root stacking context based on the picture
     /// caching scroll root. This is a temporary solution for the initial
     /// implementation of picture caching. We need to work out the specifics
     /// of how WR should decide (or Gecko should communicate) where the main
     /// content frame is that should get surface caching.
     fn setup_picture_caching(
         &mut self,
-        root_pipeline_id: PipelineId,
+        primitives: &mut Vec<PrimitiveInstance>,
     ) {
         if !self.config.enable_picture_caching {
             return;
         }
 
         // This method is basically a hack to set up picture caching in a minimal
         // way without having to check the public API (yet). The intent is to
         // work out a good API for this and switch to using it. In the mean
@@ -271,108 +253,112 @@ impl<'a> DisplayListFlattener<'a> {
         //     [primitives attached to cached scroll root]
         //  [trailing root primitives]
         //
         // This step is typically very quick, because there are only
         // a small number of items in the root stacking context, since
         // most of the content is embedded in its own picture.
         //
 
-        // See if we found a scroll root for the cached surface root.
-        if let Some(picture_cache_scroll_root) = self.picture_cache_scroll_root {
-            // Get the list of existing primitives in the main stacking context.
-            let mut old_prim_list = mem::replace(
-                &mut self.prim_store.pictures[self.root_pic_index.0].prim_list,
-                PrimitiveList::empty(),
+        // Find the first primitive which has the desired scroll root.
+        let mut main_scroll_root = None;
+
+        let first_index = primitives.iter().position(|instance| {
+            let scroll_root = self.find_scroll_root(
+                instance.spatial_node_index,
             );
 
-            // Find the first primitive which has the desired scroll root.
-            let first_index = old_prim_list.prim_instances.iter().position(|instance| {
-                let scroll_root = self.find_scroll_root(
-                    instance.spatial_node_index,
-                );
-
-                scroll_root == picture_cache_scroll_root
-            }).unwrap_or(old_prim_list.prim_instances.len());
+            if scroll_root == ROOT_SPATIAL_NODE_INDEX {
+                false
+            } else {
+                debug_assert!(main_scroll_root.is_none());
+                main_scroll_root = Some(scroll_root);
+                true
+            }
+        }).unwrap_or(primitives.len());
 
-            // Split off the preceding primtives.
-            let mut remaining_prims = old_prim_list.prim_instances.split_off(first_index);
-
-            // Find the first primitive in reverse order that is not the root scroll node.
-            let last_index = remaining_prims.iter().rposition(|instance| {
-                let scroll_root = self.find_scroll_root(
-                    instance.spatial_node_index,
-                );
+        let main_scroll_root = match main_scroll_root {
+            Some(main_scroll_root) => main_scroll_root,
+            None => ROOT_SPATIAL_NODE_INDEX,
+        };
 
-                scroll_root != ROOT_SPATIAL_NODE_INDEX
-            }).unwrap_or(remaining_prims.len() - 1);
-
-            let preceding_prims = old_prim_list.prim_instances;
-            let trailing_prims = remaining_prims.split_off(last_index + 1);
+        // Get the list of existing primitives in the main stacking context.
+        let mut old_prim_list = mem::replace(
+            primitives,
+            Vec::new(),
+        );
 
-            let prim_list = PrimitiveList::new(
-                remaining_prims,
-                &self.resources,
-            );
+        // Split off the preceding primtives.
+        let mut remaining_prims = old_prim_list.split_off(first_index);
 
-            // Now, create a picture with tile caching enabled that will hold all
-            // of the primitives selected as belonging to the main scroll root.
-            let prim_key = PrimitiveKey::new(
-                true,
-                LayoutSize::zero(),
-                LayoutRect::max_rect(),
-                PrimitiveKeyKind::Unused,
+        // Find the first primitive in reverse order that is not the root scroll node.
+        let last_index = remaining_prims.iter().rposition(|instance| {
+            let scroll_root = self.find_scroll_root(
+                instance.spatial_node_index,
             );
 
-            let primitive_data_handle = self.resources
-                .prim_interner
-                .intern(&prim_key, || {
-                    PrimitiveSceneData {
-                        prim_relative_clip_rect: LayoutRect::max_rect(),
-                        prim_size: LayoutSize::zero(),
-                        is_backface_visible: true,
-                    }
-                }
-            );
+            scroll_root != ROOT_SPATIAL_NODE_INDEX
+        }).unwrap_or(remaining_prims.len() - 1);
+
+        let preceding_prims = old_prim_list;
+        let trailing_prims = remaining_prims.split_off(last_index + 1);
+
+        let prim_list = PrimitiveList::new(
+            remaining_prims,
+            &self.resources,
+        );
+
+        // Now, create a picture with tile caching enabled that will hold all
+        // of the primitives selected as belonging to the main scroll root.
+        let prim_key = PrimitiveKey::new(
+            true,
+            LayoutSize::zero(),
+            LayoutRect::max_rect(),
+            PrimitiveKeyKind::Unused,
+        );
 
-            let pic_index = self.prim_store.pictures.alloc().init(PicturePrimitive::new_image(
-                Some(PictureCompositeMode::TileCache { clear_color: ColorF::new(1.0, 1.0, 1.0, 1.0) }),
-                Picture3DContext::Out,
-                root_pipeline_id,
-                None,
-                true,
-                RasterSpace::Screen,
-                prim_list,
-                picture_cache_scroll_root,
-                LayoutRect::max_rect(),
-                &self.clip_store,
-            ));
+        let primitive_data_handle = self.resources
+            .prim_interner
+            .intern(&prim_key, || {
+                PrimitiveSceneData {
+                    prim_relative_clip_rect: LayoutRect::max_rect(),
+                    prim_size: LayoutSize::zero(),
+                    is_backface_visible: true,
+                }
+            }
+        );
 
-            let instance = PrimitiveInstance::new(
-                LayoutPoint::zero(),
-                PrimitiveInstanceKind::Picture {
-                    data_handle: primitive_data_handle,
-                    pic_index: PictureIndex(pic_index)
-                },
-                ClipChainId::NONE,
-                picture_cache_scroll_root,
-            );
+        let pic_index = self.prim_store.pictures.alloc().init(PicturePrimitive::new_image(
+            Some(PictureCompositeMode::TileCache { clear_color: ColorF::new(1.0, 1.0, 1.0, 1.0) }),
+            Picture3DContext::Out,
+            self.scene.root_pipeline_id.unwrap(),
+            None,
+            true,
+            RasterSpace::Screen,
+            prim_list,
+            main_scroll_root,
+            LayoutRect::max_rect(),
+            &self.clip_store,
+        ));
 
-            // This contains the tile caching picture, with preceding and
-            // trailing primitives outside the main scroll root.
-            let mut new_prim_list = preceding_prims;
-            new_prim_list.push(instance);
-            new_prim_list.extend(trailing_prims);
+        let instance = PrimitiveInstance::new(
+            LayoutPoint::zero(),
+            PrimitiveInstanceKind::Picture {
+                data_handle: primitive_data_handle,
+                pic_index: PictureIndex(pic_index)
+            },
+            ClipChainId::NONE,
+            main_scroll_root,
+        );
 
-            // Finally, store the sliced primitive list in the root picture.
-            self.prim_store.pictures[self.root_pic_index.0].prim_list = PrimitiveList::new(
-                new_prim_list,
-                &self.resources,
-            );
-        }
+        // This contains the tile caching picture, with preceding and
+        // trailing primitives outside the main scroll root.
+        primitives.extend(preceding_prims);
+        primitives.push(instance);
+        primitives.extend(trailing_prims);
     }
 
     /// Find the spatial node that is the scroll root for a given
     /// spatial node.
     fn find_scroll_root(
         &self,
         spatial_node_index: SpatialNodeIndex,
     ) -> SpatialNodeIndex {
@@ -551,34 +537,26 @@ impl<'a> DisplayListFlattener<'a> {
         // positioning offsets.
         let frame_rect = item.clip_rect().translate(reference_frame_relative_offset);
         let content_rect = item.rect().translate(reference_frame_relative_offset);
 
         debug_assert!(info.clip_id != info.scroll_frame_id);
 
         self.add_clip_node(info.clip_id, clip_and_scroll_ids, clip_region);
 
-        let node_index = self.add_scroll_frame(
+        self.add_scroll_frame(
             info.scroll_frame_id,
             info.clip_id,
             info.external_id,
             pipeline_id,
             &frame_rect,
             &content_rect.size,
             info.scroll_sensitivity,
             ScrollFrameKind::Explicit,
         );
-
-        // TODO(gw): See description of picture_cache_scroll_root field for information
-        //           about this temporary hack. What it's trying to identify is the first
-        //           scroll root within the first iframe that we encounter in the display
-        //           list.
-        if self.picture_cache_scroll_root.is_none() && pipeline_id != self.scene.root_pipeline_id.unwrap() {
-            self.picture_cache_scroll_root = Some(node_index);
-        }
     }
 
     fn flatten_reference_frame(
         &mut self,
         traversal: &mut BuiltDisplayListIter<'a>,
         pipeline_id: PipelineId,
         item: &DisplayItemRef,
         reference_frame: &ReferenceFrame,
@@ -1223,16 +1201,19 @@ impl<'a> DisplayListFlattener<'a> {
         // Check if this stacking context is the root of a pipeline, and the caller
         // has requested it as an output frame.
         let frame_output_pipeline_id = if is_pipeline_root && self.output_pipelines.contains(&pipeline_id) {
             Some(pipeline_id)
         } else {
             None
         };
 
+        let create_tile_cache = is_pipeline_root &&
+                                self.sc_stack.len() == 2;
+
         // Get the transform-style of the parent stacking context,
         // which determines if we *might* need to draw this on
         // an intermediate surface for plane splitting purposes.
         let (parent_is_3d, extra_3d_instance) = match self.sc_stack.last_mut() {
             Some(sc) => {
                 // Cut the sequence of flat children before starting a child stacking context,
                 // so that the relative order between them and our current SC is preserved.
                 let extra_instance = sc.cut_flat_item_sequence(
@@ -1312,21 +1293,22 @@ impl<'a> DisplayListFlattener<'a> {
             requested_raster_space,
             spatial_node_index,
             clip_chain_id,
             frame_output_pipeline_id,
             composite_ops,
             should_isolate,
             transform_style,
             context_3d,
+            create_tile_cache,
         });
     }
 
     pub fn pop_stacking_context(&mut self) {
-        let stacking_context = self.sc_stack.pop().unwrap();
+        let mut stacking_context = self.sc_stack.pop().unwrap();
 
         // If we encounter a stacking context that is effectively a no-op, then instead
         // of creating a picture, just append the primitive list to the parent stacking
         // context as a short cut. This serves two purposes:
         // (a) It's an optimization to reduce picture count and allocations, as display lists
         //     often contain a lot of these stacking contexts that don't require pictures or
         //     off-screen surfaces.
         // (b) It's useful for the initial version of picture caching in gecko, by enabling
@@ -1337,16 +1319,22 @@ impl<'a> DisplayListFlattener<'a> {
                 parent_sc,
                 self.clip_scroll_tree,
             ) {
                 parent_sc.primitives.extend(stacking_context.primitives);
                 return;
             }
         }
 
+        if stacking_context.create_tile_cache {
+            self.setup_picture_caching(
+                &mut stacking_context.primitives,
+            );
+        }
+
         // An arbitrary large clip rect. For now, we don't
         // specify a clip specific to the stacking context.
         // However, now that they are represented as Picture
         // primitives, we can apply any kind of clip mask
         // to them, as for a normal primitive. This is needed
         // to correctly handle some CSS cases (see #1957).
         let max_clip = LayoutRect::max_rect();
 
@@ -2528,16 +2516,19 @@ struct FlattenedStackingContext {
     /// Pipeline this stacking context belongs to.
     pipeline_id: PipelineId,
 
     /// CSS transform-style property.
     transform_style: TransformStyle,
 
     /// Defines the relationship to a preserve-3D hiearachy.
     context_3d: Picture3DContext<PrimitiveInstance>,
+
+    /// If true, create a tile cache for this stacking context.
+    create_tile_cache: bool,
 }
 
 impl FlattenedStackingContext {
     /// Return true if the stacking context has a valid preserve-3d property
     pub fn is_3d(&self) -> bool {
         self.transform_style == TransformStyle::Preserve3D && self.composite_ops.is_empty()
     }
 
@@ -2577,16 +2568,21 @@ impl FlattenedStackingContext {
             return false;
         }
 
         // If represents a transform, it may affect backface visibility of children
         if !clip_scroll_tree.node_is_identity(self.spatial_node_index) {
             return false;
         }
 
+        // If the pipelines are different, we care for purposes of selecting tile caches
+        if self.pipeline_id != parent.pipeline_id {
+            return false;
+        }
+
         // It is redundant!
         true
     }
 
     /// For a Preserve3D context, cut the sequence of the immediate flat children
     /// recorded so far and generate a picture from them.
     pub fn cut_flat_item_sequence(
         &mut self,
--- a/gfx/wr/webrender/src/glyph_rasterizer/mod.rs
+++ b/gfx/wr/webrender/src/glyph_rasterizer/mod.rs
@@ -155,17 +155,19 @@ impl FontTransform {
 }
 
 impl<'a> From<&'a LayoutToWorldTransform> for FontTransform {
     fn from(xform: &'a LayoutToWorldTransform) -> Self {
         FontTransform::new(xform.m11, xform.m21, xform.m12, xform.m22)
     }
 }
 
-pub const FONT_SIZE_LIMIT: f64 = 1024.0;
+// Some platforms (i.e. Windows) may have trouble rasterizing glyphs above this size.
+// Ensure glyph sizes are reasonably limited to avoid that scenario.
+pub const FONT_SIZE_LIMIT: f64 = 512.0;
 
 #[derive(Clone, Hash, PartialEq, Eq, Debug, Ord, PartialOrd)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct FontInstance {
     pub font_key: FontKey,
     // The font size is in *device* pixels, not logical pixels.
     // It is stored as an Au since we need sub-pixel sizes, but
--- a/gfx/wr/webrender/src/picture.rs
+++ b/gfx/wr/webrender/src/picture.rs
@@ -15,17 +15,17 @@ use euclid::approxeq::ApproxEq;
 use intern::ItemUid;
 use internal_types::{FastHashMap, PlaneSplitter};
 use frame_builder::{FrameBuildingContext, FrameBuildingState, PictureState, PictureContext};
 use gpu_cache::{GpuCache, GpuCacheAddress, GpuCacheHandle};
 use gpu_types::{TransformPalette, TransformPaletteId, UvRectKind};
 use internal_types::FastHashSet;
 use plane_split::{Clipper, Polygon, Splitter};
 use prim_store::{PictureIndex, PrimitiveInstance, SpaceMapper, VisibleFace, PrimitiveInstanceKind};
-use prim_store::{get_raster_rects, CoordinateSpaceMapping};
+use prim_store::{get_raster_rects, CoordinateSpaceMapping, PointKey};
 use prim_store::{OpacityBindingStorage, PrimitiveTemplateKind, ImageInstanceStorage, OpacityBindingIndex, SizeKey};
 use render_backend::FrameResources;
 use render_task::{ClearMode, RenderTask, RenderTaskCacheEntryHandle, TileBlit};
 use render_task::{RenderTaskCacheKey, RenderTaskCacheKeyKind, RenderTaskId, RenderTaskLocation};
 use resource_cache::ResourceCache;
 use scene::{FilterOpHelpers, SceneProperties};
 use scene_builder::DocumentResources;
 use smallvec::SmallVec;
@@ -73,17 +73,18 @@ pub struct TileCoordinate;
 // Geometry types for tile coordinates.
 pub type TileOffset = TypedPoint2D<i32, TileCoordinate>;
 pub type TileSize = TypedSize2D<i32, TileCoordinate>;
 pub type TileRect = TypedRect<i32, TileCoordinate>;
 
 /// The size in device pixels of a cached tile. The currently chosen
 /// size is arbitrary. We should do some profiling to find the best
 /// size for real world pages.
-pub const TILE_SIZE_DP: i32 = 512;
+pub const TILE_SIZE_WIDTH: i32 = 1024;
+pub const TILE_SIZE_HEIGHT: i32 = 256;
 
 /// Information about the state of a transform dependency.
 #[derive(Debug)]
 pub struct TileTransformInfo {
     /// The spatial node in the current clip-scroll tree that
     /// this transform maps to.
     spatial_node_index: SpatialNodeIndex,
     /// Tiles check this to see if the dependencies have changed.
@@ -242,23 +243,37 @@ impl Tile {
         }
     }
 }
 
 /// Index of a transform array local to the tile.
 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
 pub struct TileTransformIndex(u32);
 
+/// Defines a key that uniquely identifies a primitive instance.
+#[derive(Debug, Eq, PartialEq, Hash)]
+pub struct PrimitiveDescriptor {
+    /// Uniquely identifies the content of the primitive template.
+    prim_uid: ItemUid,
+    /// The origin in local space of this primitive.
+    origin: PointKey,
+    /// The first clip in the clip_uids array of clips that affect this tile.
+    first_clip: u16,
+    /// The number of clips that affect this primitive instance.
+    clip_count: u16,
+}
+
 /// Uniquely describes the content of this tile, in a way that can be
 /// (reasonably) efficiently hashed and compared.
 #[derive(Debug, Eq, PartialEq, Hash)]
 pub struct TileDescriptor {
-    /// List of primitive unique identifiers. The uid is guaranteed
-    /// to uniquely describe the content of the primitive.
-    pub prim_uids: Vec<ItemUid>,
+    /// List of primitive instance unique identifiers. The uid is guaranteed
+    /// to uniquely describe the content of the primitive template, while
+    /// the other parameters describe the clip chain and instance params.
+    pub prims: Vec<PrimitiveDescriptor>,
 
     /// List of clip node unique identifiers. The uid is guaranteed
     /// to uniquely describe the content of the clip node.
     pub clip_uids: Vec<ItemUid>,
 
     /// List of local tile transform ids that are used to position
     /// the primitive and clip items above.
     pub transform_ids: Vec<TileTransformIndex>,
@@ -283,31 +298,31 @@ pub struct TileDescriptor {
 
 impl TileDescriptor {
     fn new(
         tile_offset: TileOffset,
         local_tile_size: SizeKey,
         raster_transform: TransformKey,
     ) -> Self {
         TileDescriptor {
-            prim_uids: Vec::new(),
+            prims: Vec::new(),
             clip_uids: Vec::new(),
             transform_ids: Vec::new(),
             opacity_bindings: Vec::new(),
             transforms: Vec::new(),
             tile_offset,
             raster_transform,
             local_tile_size,
         }
     }
 
     /// Clear the dependency information for a tile, when the dependencies
     /// are being rebuilt.
     fn clear(&mut self) {
-        self.prim_uids.clear();
+        self.prims.clear();
         self.clip_uids.clear();
         self.transform_ids.clear();
         self.transforms.clear();
         self.opacity_bindings.clear();
     }
 }
 
 /// Represents the dirty region of a tile cache picture.
@@ -411,18 +426,18 @@ impl TileCache {
         );
 
         // Work out the local space size of each tile, based on the
         // device pixel size of tiles.
         // TODO(gw): Perhaps add a map_point API to SpaceMapper.
         let world_tile_rect = WorldRect::from_floats(
             0.0,
             0.0,
-            TILE_SIZE_DP as f32 / frame_context.device_pixel_scale.0,
-            TILE_SIZE_DP as f32 / frame_context.device_pixel_scale.0,
+            TILE_SIZE_WIDTH as f32 / frame_context.device_pixel_scale.0,
+            TILE_SIZE_HEIGHT as f32 / frame_context.device_pixel_scale.0,
         );
         let local_tile_rect = world_mapper
             .unmap(&world_tile_rect)
             .expect("bug: unable to get local tile size");
         self.local_tile_size = local_tile_rect.size;
         self.local_origin = pic_rect.origin;
 
         // Walk the transforms and see if we need to rebuild the primitive
@@ -551,25 +566,42 @@ impl TileCache {
             }
 
             // Reset the size of the tile grid.
             self.tile_rect = TileRect::zero();
         }
 
         // Get the tile coordinates in the picture space.
         let pic_rect = TypedRect::from_untyped(&pic_rect.to_untyped());
-        let local_pic_rect = pic_rect.translate(&-self.local_origin.to_vector());
-
-        let x0 = (local_pic_rect.origin.x / self.local_tile_size.width).floor() as i32;
-        let y0 = (local_pic_rect.origin.y / self.local_tile_size.height).floor() as i32;
-        let x1 = ((local_pic_rect.origin.x + local_pic_rect.size.width) / self.local_tile_size.width).ceil() as i32;
-        let y1 = ((local_pic_rect.origin.y + local_pic_rect.size.height) / self.local_tile_size.height).ceil() as i32;
+        let (p0, p1) = self.get_tile_coords_for_rect(&pic_rect);
 
         // Update the tile array allocation if needed.
-        self.reconfigure_tiles_if_required(x0, y0, x1, y1);
+        self.reconfigure_tiles_if_required(p0.x, p0.y, p1.x, p1.y);
+    }
+
+    /// Get the tile coordinates for a given rectangle.
+    fn get_tile_coords_for_rect(
+        &self,
+        rect: &LayoutRect,
+    ) -> (TileOffset, TileOffset) {
+        // Translate the rectangle into the virtual tile space
+        let origin = rect.origin - self.local_origin;
+
+        // Get the tile coordinates in the picture space.
+        let p0 = TileOffset::new(
+            (origin.x / self.local_tile_size.width).floor() as i32,
+            (origin.y / self.local_tile_size.height).floor() as i32,
+        );
+
+        let p1 = TileOffset::new(
+            ((origin.x + rect.size.width) / self.local_tile_size.width).ceil() as i32,
+            ((origin.y + rect.size.height) / self.local_tile_size.height).ceil() as i32,
+        );
+
+        (p0, p1)
     }
 
     /// Resize the 2D tiles array if needed in order to fit dependencies
     /// for a given primitive.
     fn reconfigure_tiles_if_required(
         &mut self,
         mut x0: i32,
         mut y0: i32,
@@ -687,24 +719,18 @@ impl TileCache {
         };
 
         // If the rect is invalid, no need to create dependencies.
         // TODO(gw): Need to handle pictures with filters here.
         if rect.size.width <= 0.0 || rect.size.height <= 0.0 {
             return;
         }
 
-        // Translate the rectangle into the virtual tile space
-        let origin = rect.origin - self.local_origin;
-
         // Get the tile coordinates in the picture space.
-        let x0 = (origin.x / self.local_tile_size.width).floor() as i32;
-        let y0 = (origin.y / self.local_tile_size.height).floor() as i32;
-        let x1 = ((origin.x + rect.size.width) / self.local_tile_size.width).ceil() as i32;
-        let y1 = ((origin.y + rect.size.height) / self.local_tile_size.height).ceil() as i32;
+        let (p0, p1) = self.get_tile_coords_for_rect(&rect);
 
         // Build the list of resources that this primitive has dependencies on.
         let mut opacity_bindings: SmallVec<[PropertyBindingId; 4]> = SmallVec::new();
         let mut clip_chain_spatial_nodes: SmallVec<[SpatialNodeIndex; 8]> = SmallVec::new();
         let mut clip_chain_uids: SmallVec<[ItemUid; 8]> = SmallVec::new();
         let mut image_keys: SmallVec<[ImageKey; 8]> = SmallVec::new();
         let mut current_clip_chain_id = prim_instance.clip_chain_id;
 
@@ -790,18 +816,18 @@ impl TileCache {
                 clip_chain_spatial_nodes.push(clip_chain_node.spatial_node_index);
                 clip_chain_uids.push(clip_chain_node.handle.uid());
             }
             current_clip_chain_id = clip_chain_node.parent_clip_chain_id;
         }
 
         // Normalize the tile coordinates before adding to tile dependencies.
         // For each affected tile, mark any of the primitive dependencies.
-        for y in y0 - self.tile_rect.origin.y .. y1 - self.tile_rect.origin.y {
-            for x in x0 - self.tile_rect.origin.x .. x1 - self.tile_rect.origin.x {
+        for y in p0.y - self.tile_rect.origin.y .. p1.y - self.tile_rect.origin.y {
+            for x in p0.x - self.tile_rect.origin.x .. p1.x - self.tile_rect.origin.x {
                 let index = (y * self.tile_rect.size.width + x) as usize;
                 let tile = &mut self.tiles[index];
 
                 // Mark if the tile is cacheable at all.
                 tile.is_cacheable &= is_cacheable;
                 tile.in_use = true;
 
                 // Include any image keys this tile depends on.
@@ -830,17 +856,22 @@ impl TileCache {
                 // Include any opacity bindings this primitive depends on.
                 for id in &opacity_bindings {
                     if tile.opacity_bindings.insert(*id) {
                         tile.descriptor.opacity_bindings.push(*id);
                     }
                 }
 
                 // Update the tile descriptor, used for tile comparison during scene swaps.
-                tile.descriptor.prim_uids.push(prim_instance.uid());
+                tile.descriptor.prims.push(PrimitiveDescriptor {
+                    prim_uid: prim_instance.uid(),
+                    origin: prim_instance.prim_origin.into(),
+                    first_clip: tile.descriptor.clip_uids.len() as u16,
+                    clip_count: clip_chain_uids.len() as u16,
+                });
                 tile.descriptor.clip_uids.extend_from_slice(&clip_chain_uids);
             }
         }
     }
 
     /// Get a local space rectangle for a given tile coordinate.
     pub fn get_tile_rect(&self, x: i32, y: i32) -> LayoutRect {
         LayoutRect::new(
@@ -2179,18 +2210,18 @@ impl PicturePrimitive {
                 match tile_cache.dirty_region {
                     Some(ref dirty_region) => {
                         // Texture cache descriptor for each tile.
                         // TODO(gw): If / when we start to use tile caches with
                         //           clip masks and/or transparent backgrounds,
                         //           we will need to correctly select an opacity
                         //           here and a blend mode in batch.rs.
                         let descriptor = ImageDescriptor::new(
-                            TILE_SIZE_DP,
-                            TILE_SIZE_DP,
+                            TILE_SIZE_WIDTH,
+                            TILE_SIZE_HEIGHT,
                             ImageFormat::BGRA8,
                             true,
                             false,
                         );
 
                         // Get a picture rect, expanded to tile boundaries.
                         let p0 = pic_rect.origin;
                         let p1 = pic_rect.bottom_right();
@@ -2230,18 +2261,18 @@ impl PicturePrimitive {
 
                                     let cache_item = frame_state
                                         .resource_cache
                                         .get_texture_cache_item(&tile.handle);
 
                                     // Set up the blit command now that we know where the dest
                                     // rect is in the texture cache.
                                     let offset = DeviceIntPoint::new(
-                                        (x - dirty_region.tile_offset.x) * TILE_SIZE_DP,
-                                        (y - dirty_region.tile_offset.y) * TILE_SIZE_DP,
+                                        (x - dirty_region.tile_offset.x) * TILE_SIZE_WIDTH,
+                                        (y - dirty_region.tile_offset.y) * TILE_SIZE_HEIGHT,
                                     );
 
                                     blits.push(TileBlit {
                                         target: cache_item,
                                         offset,
                                     });
 
                                     tile.is_valid = true;
--- a/gfx/wr/webrender/src/platform/windows/font.rs
+++ b/gfx/wr/webrender/src/platform/windows/font.rs
@@ -248,17 +248,17 @@ impl FontContext {
 
     fn create_glyph_analysis(
         &mut self,
         font: &FontInstance,
         key: &GlyphKey,
         size: f32,
         transform: Option<dwrote::DWRITE_MATRIX>,
         bitmaps: bool,
-    ) -> dwrote::GlyphRunAnalysis {
+    ) -> (dwrote::GlyphRunAnalysis, dwrote::DWRITE_TEXTURE_TYPE, dwrote::RECT) {
         let face = self.get_font_face(font);
         let glyph = key.index() as u16;
         let advance = 0.0f32;
         let offset = dwrote::GlyphOffset {
             advanceOffset: 0.0,
             ascenderOffset: 0.0,
         };
 
@@ -277,25 +277,46 @@ impl FontContext {
         let dwrite_render_mode = dwrite_render_mode(
             face,
             font,
             size,
             dwrite_measure_mode,
             bitmaps,
         );
 
-        dwrote::GlyphRunAnalysis::create(
+        let analysis = dwrote::GlyphRunAnalysis::create(
             &glyph_run,
             1.0,
             transform,
             dwrite_render_mode,
             dwrite_measure_mode,
             0.0,
             0.0,
-        )
+        );
+        let texture_type = dwrite_texture_type(font.render_mode);
+        let bounds = analysis.get_alpha_texture_bounds(texture_type);
+        // If the bounds are empty, then we might not be able to render the glyph with cleartype.
+        // Try again with aliased rendering to check if that works instead.
+        if font.render_mode != FontRenderMode::Mono &&
+           (bounds.left == bounds.right || bounds.top == bounds.bottom) {
+            let analysis2 = dwrote::GlyphRunAnalysis::create(
+                &glyph_run,
+                1.0,
+                transform,
+                dwrote::DWRITE_RENDERING_MODE_ALIASED,
+                dwrite_measure_mode,
+                0.0,
+                0.0,
+            );
+            let bounds2 = analysis2.get_alpha_texture_bounds(dwrote::DWRITE_TEXTURE_ALIASED_1x1);
+            if bounds2.left != bounds2.right && bounds2.top != bounds2.bottom {
+                return (analysis2, dwrote::DWRITE_TEXTURE_ALIASED_1x1, bounds2);
+            }
+        }
+        (analysis, texture_type, bounds)
     }
 
     pub fn get_glyph_index(&mut self, font_key: FontKey, ch: char) -> Option<u32> {
         let face = self.fonts.get(&font_key).unwrap();
         let indices = face.get_glyph_indices(&[ch as u32]);
         indices.first().map(|idx| *idx as u32)
     }
 
@@ -329,21 +350,17 @@ impl FontContext {
                 m21: shape.skew_x,
                 m22: shape.scale_y,
                 dx: 0.0,
                 dy: 0.0,
             })
         } else {
             None
         };
-        let analysis = self.create_glyph_analysis(font, key, size, transform, bitmaps);
-
-        let texture_type = dwrite_texture_type(font.render_mode);
-
-        let bounds = analysis.get_alpha_texture_bounds(texture_type);
+        let (_, _, bounds) = self.create_glyph_analysis(font, key, size, transform, bitmaps);
 
         let width = (bounds.right - bounds.left) as i32;
         let height = (bounds.bottom - bounds.top) as i32;
 
         // Alpha texture bounds can sometimes return an empty rect
         // Such as for spaces
         if width == 0 || height == 0 {
             return None;
@@ -368,55 +385,56 @@ impl FontContext {
             })
     }
 
     // DWrite ClearType gives us values in RGB, but WR expects BGRA.
     #[cfg(not(feature = "pathfinder"))]
     fn convert_to_bgra(
         &self,
         pixels: &[u8],
+        texture_type: dwrote::DWRITE_TEXTURE_TYPE,
         render_mode: FontRenderMode,
         bitmaps: bool,
     ) -> Vec<u8> {
-        match (render_mode, bitmaps) {
-            (FontRenderMode::Mono, _) => {
+        match (texture_type, render_mode, bitmaps) {
+            (dwrote::DWRITE_TEXTURE_ALIASED_1x1, _, _) => {
                 let mut bgra_pixels: Vec<u8> = vec![0; pixels.len() * 4];
                 for i in 0 .. pixels.len() {
                     let alpha = pixels[i];
                     bgra_pixels[i * 4 + 0] = alpha;
                     bgra_pixels[i * 4 + 1] = alpha;
                     bgra_pixels[i * 4 + 2] = alpha;
                     bgra_pixels[i * 4 + 3] = alpha;
                 }
                 bgra_pixels
             }
-            (FontRenderMode::Alpha, _) | (_, true) => {
+            (_, FontRenderMode::Subpixel, false) => {
+                let length = pixels.len() / 3;
+                let mut bgra_pixels: Vec<u8> = vec![0; length * 4];
+                for i in 0 .. length {
+                    bgra_pixels[i * 4 + 0] = pixels[i * 3 + 2];
+                    bgra_pixels[i * 4 + 1] = pixels[i * 3 + 1];
+                    bgra_pixels[i * 4 + 2] = pixels[i * 3 + 0];
+                    bgra_pixels[i * 4 + 3] = 0xff;
+                }
+                bgra_pixels
+            }
+            _ => {
                 let length = pixels.len() / 3;
                 let mut bgra_pixels: Vec<u8> = vec![0; length * 4];
                 for i in 0 .. length {
                     // Only take the G channel, as its closest to D2D
                     let alpha = pixels[i * 3 + 1] as u8;
                     bgra_pixels[i * 4 + 0] = alpha;
                     bgra_pixels[i * 4 + 1] = alpha;
                     bgra_pixels[i * 4 + 2] = alpha;
                     bgra_pixels[i * 4 + 3] = alpha;
                 }
                 bgra_pixels
             }
-            (FontRenderMode::Subpixel, false) => {
-                let length = pixels.len() / 3;
-                let mut bgra_pixels: Vec<u8> = vec![0; length * 4];
-                for i in 0 .. length {
-                    bgra_pixels[i * 4 + 0] = pixels[i * 3 + 2];
-                    bgra_pixels[i * 4 + 1] = pixels[i * 3 + 1];
-                    bgra_pixels[i * 4 + 2] = pixels[i * 3 + 0];
-                    bgra_pixels[i * 4 + 3] = 0xff;
-                }
-                bgra_pixels
-            }
         }
     }
 
     pub fn prepare_font(font: &mut FontInstance) {
         match font.render_mode {
             FontRenderMode::Mono => {
                 // In mono mode the color of the font is irrelevant.
                 font.color = ColorU::new(255, 255, 255, 255);
@@ -463,31 +481,28 @@ impl FontContext {
                 m22: shape.scale_y,
                 dx: (x_offset / scale) as f32,
                 dy: (y_offset / scale) as f32,
             })
         } else {
             None
         };
 
-        let analysis = self.create_glyph_analysis(font, key, size, transform, bitmaps);
-        let texture_type = dwrite_texture_type(font.render_mode);
+        let (analysis, texture_type, bounds) = self.create_glyph_analysis(font, key, size, transform, bitmaps);
 
-        let bounds = analysis.get_alpha_texture_bounds(texture_type);
         let width = (bounds.right - bounds.left) as i32;
         let height = (bounds.bottom - bounds.top) as i32;
-
         // Alpha texture bounds can sometimes return an empty rect
         // Such as for spaces
         if width == 0 || height == 0 {
             return GlyphRasterResult::LoadFailed;
         }
 
         let pixels = analysis.create_alpha_texture(texture_type, bounds);
-        let mut bgra_pixels = self.convert_to_bgra(&pixels, font.render_mode, bitmaps);
+        let mut bgra_pixels = self.convert_to_bgra(&pixels, texture_type, font.render_mode, bitmaps);
 
         // These are the default values we use in Gecko.
         // We use a gamma value of 2.3 for gdi fonts
         const GDI_GAMMA: u16 = 230;
 
         let FontInstancePlatformOptions { gamma, contrast, .. } = font.platform_options.unwrap_or_default();
         let gdi_gamma = match font.render_mode {
             FontRenderMode::Mono => GDI_GAMMA,
@@ -504,23 +519,31 @@ impl FontContext {
             .or_insert_with(||
                 GammaLut::new(
                     contrast as f32 / 100.0,
                     gdi_gamma as f32 / 100.0,
                     gdi_gamma as f32 / 100.0,
                 ));
         gamma_lut.preblend(&mut bgra_pixels, font.color);
 
+        let format = if bitmaps {
+            GlyphFormat::Bitmap
+        } else if texture_type == dwrote::DWRITE_TEXTURE_ALIASED_1x1 {
+            font.get_alpha_glyph_format()
+        } else {
+            font.get_glyph_format()
+        };
+
         GlyphRasterResult::Bitmap(RasterizedGlyph {
             left: bounds.left as f32,
             top: -bounds.top as f32,
             width,
             height,
             scale: (if bitmaps { scale / y_scale } else { scale }) as f32,
-            format: if bitmaps { GlyphFormat::Bitmap } else { font.get_glyph_format() },
+            format,
             bytes: bgra_pixels,
         })
     }
 }
 
 #[cfg(feature = "pathfinder")]
 impl<'a> From<NativeFontHandleWrapper<'a>> for PathfinderComPtr<IDWriteFontFace> {
     fn from(font_handle: NativeFontHandleWrapper<'a>) -> Self {
--- a/gfx/wr/webrender_api/Cargo.toml
+++ b/gfx/wr/webrender_api/Cargo.toml
@@ -24,9 +24,9 @@ serde_derive = { version = "=1.0.80", fe
 serde_bytes = "0.10"
 time = "0.1"
 
 [target.'cfg(target_os = "macos")'.dependencies]
 core-foundation = "0.6"
 core-graphics = "0.17.1"
 
 [target.'cfg(target_os = "windows")'.dependencies]
-dwrote = "0.6.2"
+dwrote = "0.6.3"
--- a/gfx/wr/wrench/Cargo.toml
+++ b/gfx/wr/wrench/Cargo.toml
@@ -34,13 +34,13 @@ serde = {version = "1.0", features = ["d
 core-graphics = "0.17.1"
 core-foundation = "0.6"
 
 [features]
 headless = [ "osmesa-sys", "osmesa-src" ]
 pathfinder = [ "webrender/pathfinder" ]
 
 [target.'cfg(target_os = "windows")'.dependencies]
-dwrote = "0.6.2"
+dwrote = "0.6.3"
 mozangle = {version = "0.1.5", features = ["egl"]}
 
 [target.'cfg(all(unix, not(target_os = "android")))'.dependencies]
 font-loader = "0.7"
--- a/gfx/wr/wrench/reftests/text/reftest.list
+++ b/gfx/wr/wrench/reftests/text/reftest.list
@@ -11,17 +11,17 @@
 != shadow-cover-1.yaml shadow-cover-2.yaml
 != shadow-many.yaml shadow.yaml
 != shadow-complex.yaml shadow-many.yaml
 != shadow-clipped-text.yaml blank.yaml
 != non-opaque.yaml non-opaque-notref.yaml
 == decorations.yaml decorations-ref.yaml
 fuzzy(1,173) == decorations-suite.yaml decorations-suite.png
 == 1658.yaml 1658-ref.yaml
-== split-batch.yaml split-batch-ref.yaml
+fuzzy(1,5) == split-batch.yaml split-batch-ref.yaml
 == shadow-red.yaml shadow-red-ref.yaml
 fuzzy(1,735) == shadow-grey.yaml shadow-grey-ref.yaml
 fuzzy(1,663) == shadow-grey-transparent.yaml shadow-grey-ref.yaml
 == subtle-shadow.yaml subtle-shadow-ref.yaml
 == shadow-atomic.yaml shadow-atomic-ref.yaml
 == shadow-clip-rect.yaml shadow-atomic-ref.yaml
 fuzzy(1,1) platform(linux) == shadow-ordering.yaml shadow-ordering-ref.yaml
 != synthetic-bold.yaml synthetic-bold-not-ref.yaml
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -47,16 +47,19 @@
 #include <thread>
 #include <utility>
 #ifdef XP_UNIX
 #include <sys/mman.h>
 #include <sys/stat.h>
 #include <sys/wait.h>
 #include <unistd.h>
 #endif
+#ifdef XP_LINUX
+#include <sys/prctl.h>
+#endif
 
 #include "jsapi.h"
 #include "jsfriendapi.h"
 #include "jstypes.h"
 #include "jsutil.h"
 #ifndef JS_POSIX_NSPR
 #include "prerror.h"
 #include "prlink.h"
@@ -10930,16 +10933,26 @@ int main(int argc, char** argv, char** e
     case OptionParser::Okay:
       break;
   }
 
   if (op.getHelpOption()) {
     return EXIT_SUCCESS;
   }
 
+  /*
+   * Allow dumping on Linux with the fuzzing flag set, even when running with
+   * the suid/sgid flag set on the shell.
+   */
+#ifdef XP_LINUX
+  if (op.getBoolOption("fuzzing-safe")) {
+    prctl(PR_SET_DUMPABLE, 1);
+  }
+#endif
+
 #ifdef DEBUG
   /*
    * Process OOM options as early as possible so that we can observe as many
    * allocations as possible.
    */
   OOM_printAllocationCount = op.getBoolOption('O');
 #endif
 
--- a/layout/tools/reftest/selftest/conftest.py
+++ b/layout/tools/reftest/selftest/conftest.py
@@ -11,70 +11,104 @@ import mozinfo
 import pytest
 from manifestparser import expression
 from moztest.selftest.fixtures import binary, setup_test_harness  # noqa
 
 here = os.path.abspath(os.path.dirname(__file__))
 setup_args = [False, 'reftest', 'reftest']
 
 
+@pytest.fixture(scope='module')
+def normalize():
+    """A function that can take a relative path and append it to the 'files'
+    directory which contains the data necessary to run these tests.
+    """
+
+    def inner(path):
+        if os.path.isabs(path):
+            return path
+        return os.path.join(here, 'files', path)
+
+    return inner
+
+
 @pytest.fixture  # noqa: F811
 def parser(setup_test_harness):
     setup_test_harness(*setup_args)
     cmdline = pytest.importorskip('reftestcommandline')
     return cmdline.DesktopArgumentsParser()
 
 
 @pytest.fixture  # noqa: F811
-def runtests(setup_test_harness, binary, parser):
+def get_reftest(setup_test_harness, binary, parser):
     setup_test_harness(*setup_args)
     runreftest = pytest.importorskip('runreftest')
     harness_root = runreftest.SCRIPT_DIRECTORY
 
-    buf = StringIO()
     build = parser.build_obj
     options = vars(parser.parse_args([]))
     options.update({
         'app': binary,
         'focusFilterMode': 'non-needs-focus',
-        'log_raw': [buf],
         'suite': 'reftest',
-        'specialPowersExtensionPath': os.path.join(harness_root, 'specialpowers'),
     })
 
     if not os.path.isdir(build.bindir):
         package_root = os.path.dirname(harness_root)
         options.update({
             'extraProfileFiles': [os.path.join(package_root, 'bin', 'plugins')],
             'reftestExtensionPath': os.path.join(harness_root, 'reftest'),
             'sandboxReadWhitelist': [here, os.environ['PYTHON_TEST_TMP']],
             'utilityPath': os.path.join(package_root, 'bin'),
+            'specialPowersExtensionPath': os.path.join(harness_root, 'specialpowers'),
         })
 
         if 'MOZ_FETCHES_DIR' in os.environ:
             options['sandboxReadWhitelist'].append(os.environ['MOZ_FETCHES_DIR'])
     else:
         options.update({
             'extraProfileFiles': [os.path.join(build.topobjdir, 'dist', 'plugins')],
             'sandboxReadWhitelist': [build.topobjdir, build.topsrcdir],
+            'specialPowersExtensionPath': os.path.join(
+                build.distdir, 'xpi-stage', 'specialpowers'),
         })
 
-    def normalize(test):
-        if os.path.isabs(test):
-            return test
-        return os.path.join(here, 'files', test)
+    def inner(**opts):
+        options.update(opts)
+        config = Namespace(**options)
+
+        # This is pulled from `runreftest.run_test_harness` minus some error
+        # checking that isn't necessary in this context. It should stay roughly
+        # in sync.
+        reftest = runreftest.RefTest(config.suite)
+        parser.validate(config, reftest)
+
+        config.app = reftest.getFullPath(config.app)
+        assert os.path.exists(config.app)
+
+        if config.xrePath is None:
+            config.xrePath = os.path.dirname(config.app)
+
+        return reftest, config
+    return inner
+
+
+@pytest.fixture  # noqa: F811
+def runtests(get_reftest, normalize):
 
     def inner(*tests, **opts):
         assert len(tests) > 0
-        tests = map(normalize, tests)
+        opts['tests'] = map(normalize, tests)
 
-        options['tests'] = tests
-        options.update(opts)
+        buf = StringIO()
+        opts['log_raw'] = [buf]
 
-        result = runreftest.run_test_harness(parser, Namespace(**options))
+        reftest, options = get_reftest(**opts)
+        result = reftest.runTests(options.tests, options)
+
         out = json.loads('[' + ','.join(buf.getvalue().splitlines()) + ']')
         buf.close()
         return result, out
     return inner
 
 
 @pytest.fixture(autouse=True)  # noqa: F811
 def skip_using_mozinfo(request, setup_test_harness):
copy from layout/reftests/reftest-sanity/scripttest-pass.html
copy to layout/tools/reftest/selftest/files/scripttest-pass.html
new file mode 100644
--- /dev/null
+++ b/layout/tools/reftest/selftest/files/types.list
@@ -0,0 +1,5 @@
+== green.html green.html
+!= green.html red.html
+load green.html
+script scripttest-pass.html
+print green.html green.html
--- a/layout/tools/reftest/selftest/python.ini
+++ b/layout/tools/reftest/selftest/python.ini
@@ -1,6 +1,7 @@
 [DEFAULT]
 subsuite=reftest
 sequential=true
 skip-if = python == 3
 
+[test_reftest_manifest_parser.py]
 [test_reftest_output.py]
new file mode 100644
--- /dev/null
+++ b/layout/tools/reftest/selftest/test_reftest_manifest_parser.py
@@ -0,0 +1,40 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+import mozunit
+import pytest
+
+
+@pytest.fixture
+def parse(get_reftest, normalize):
+    output = pytest.importorskip("output")
+
+    reftest, options = get_reftest(tests=["dummy"])
+    reftest._populate_logger(options)
+    reftest.outputHandler = output.OutputHandler(
+        reftest.log, options.utilityPath, options.symbolsPath)
+
+    def resolve(path):
+        path = normalize(path)
+        return "file://{}".format(path)
+
+    def inner(*manifests):
+        assert len(manifests) > 0
+        manifests = {m: None for m in map(resolve, manifests)}
+        return reftest.getActiveTests(manifests, options)
+
+    return inner
+
+
+def test_parse_test_types(parse):
+    tests = parse('types.list')
+    assert tests[0]['type'] == '=='
+    assert tests[1]['type'] == '!='
+    assert tests[2]['type'] == 'load'
+    assert tests[3]['type'] == 'script'
+    assert tests[4]['type'] == 'print'
+
+
+if __name__ == '__main__':
+    mozunit.main()
--- a/media/webrtc/signaling/src/media-conduit/VideoStreamFactory.cpp
+++ b/media/webrtc/signaling/src/media-conduit/VideoStreamFactory.cpp
@@ -238,12 +238,14 @@ std::vector<webrtc::VideoStream> VideoSt
       if (mCodecConfig.mEncodingConstraints.maxMbps > 0) {
         // Not supported yet!
         CSFLogError(LOGTAG, "%s H.264 max_mbps not supported yet",
                     __FUNCTION__);
       }
     }
     streams.push_back(video_stream);
   }
+
+  MOZ_RELEASE_ASSERT(streams.size(), "Should configure at least one stream");
   return streams;
 }
 
 }  // namespace mozilla
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -2651,16 +2651,17 @@ pref("security.notification_enable_delay
 
 #if defined(DEBUG) && !defined(ANDROID)
 pref("csp.about_uris_without_csp", "blank,printpreview,srcdoc,about,addons,cache-entry,config,crashes,debugging,devtools,downloads,home,memory,networking,newtab,performance,plugins,policies,profiles,restartrequired,searchreset,serviceworkers,sessionrestore,support,sync-log,telemetry,url-classifier,webrtc,welcomeback");
 // the following prefs are for testing purposes only.
 pref("csp.overrule_about_uris_without_csp_whitelist", false);
 pref("csp.skip_about_page_has_csp_assert", false);
 // assertion flag will be set to false after fixing Bug 1473549
 pref("security.allow_eval_with_system_principal", true);
+pref("security.uris_using_eval_with_system_principal", "autocomplete.xml,redux.js,react-redux.js,content-task.js,content-task.js,tree.xml,dialog.xml,preferencesbindings.js,wizard.xml,lodash.js,jszip.js,ajv-4.1.1.js,updates.js,setup,jsol.js");
 #endif
 
 // Default Content Security Policy to apply to signed contents.
 pref("security.signed_content.CSP.default", "script-src 'self'; style-src 'self'");
 
 // Mixed content blocking
 pref("security.mixed_content.block_active_content", false);
 pref("security.mixed_content.block_display_content", false);
--- a/parser/html/javasrc/ElementName.java
+++ b/parser/html/javasrc/ElementName.java
@@ -954,20 +954,20 @@ TreeBuilder.IMAGE);
 public static final ElementName IFRAME = new ElementName("iframe", "iframe", 
 // CPPONLY: NS_NewHTMLIFrameElement,
 // CPPONLY: NS_NewSVGUnknownElement, 
 TreeBuilder.IFRAME | SPECIAL);
 public static final ElementName LINE = new ElementName("line", "line", 
 // CPPONLY: NS_NewHTMLUnknownElement,
 // CPPONLY: NS_NewSVGLineElement, 
 TreeBuilder.OTHER);
-public static final ElementName MARQUEE = new ElementName("marquee", "marquee", 
-// CPPONLY: NS_NewHTMLDivElement,
-// CPPONLY: NS_NewSVGUnknownElement, 
-TreeBuilder.MARQUEE_OR_APPLET | SPECIAL | SCOPING);
+public static final ElementName MARQUEE = new ElementName("marquee", "marquee",
+    // CPPONLY: NS_NewHTMLMarqueeElement,
+    // CPPONLY: NS_NewSVGUnknownElement,
+    TreeBuilder.MARQUEE_OR_APPLET | SPECIAL | SCOPING);
 public static final ElementName POLYLINE = new ElementName("polyline", "polyline", 
 // CPPONLY: NS_NewHTMLUnknownElement,
 // CPPONLY: NS_NewSVGPolylineElement, 
 TreeBuilder.OTHER);
 public static final ElementName PICTURE = new ElementName("picture", "picture", 
 // CPPONLY: NS_NewHTMLPictureElement,
 // CPPONLY: NS_NewSVGUnknownElement, 
 TreeBuilder.OTHER);
--- a/parser/html/javasrc/TreeBuilder.java
+++ b/parser/html/javasrc/TreeBuilder.java
@@ -3293,27 +3293,29 @@ public abstract class TreeBuilder<T> imp
                         case ';':
                             end = i;
                             break charsetloop;
                         default:
                             continue;
                     }
             }
         }
-        String charset = null;
         if (start != -1) {
             if (end == -1) {
+              if (charsetState == CHARSET_UNQUOTED) {
                 end = buffer.length;
+              } else {
+                return null;
+              }
             }
-            charset = Portability.newStringFromBuffer(buffer, start, end
-                    - start
+            return Portability.newStringFromBuffer(buffer, start, end - start
                 // CPPONLY: , tb, false
             );
         }
-        return charset;
+        return null;
     }
 
     private void checkMetaCharset(HtmlAttributes attributes)
             throws SAXException {
         String charset = attributes.getValue(AttributeName.CHARSET);
         if (charset != null) {
             if (tokenizer.internalEncodingDeclaration(charset)) {
                 requestSuspension();
--- a/parser/html/nsHtml5TreeBuilder.cpp
+++ b/parser/html/nsHtml5TreeBuilder.cpp
@@ -2284,25 +2284,28 @@ nsHtml5String nsHtml5TreeBuilder::extrac
             NS_HTML5_BREAK(charsetloop);
           }
           default: { continue; }
         }
       }
     }
   }
 charsetloop_end:;
-  nsHtml5String charset = nullptr;
   if (start != -1) {
     if (end == -1) {
-      end = buffer.length;
+      if (charsetState == CHARSET_UNQUOTED) {
+        end = buffer.length;
+      } else {
+        return nullptr;
+      }
     }
-    charset = nsHtml5Portability::newStringFromBuffer(buffer, start,
-                                                      end - start, tb, false);
+    return nsHtml5Portability::newStringFromBuffer(buffer, start, end - start,
+                                                   tb, false);
   }
-  return charset;
+  return nullptr;
 }
 
 void nsHtml5TreeBuilder::checkMetaCharset(nsHtml5HtmlAttributes* attributes) {
   nsHtml5String charset =
       attributes->getValue(nsHtml5AttributeName::ATTR_CHARSET);
   if (charset) {
     if (tokenizer->internalEncodingDeclaration(charset)) {
       requestSuspension();
--- a/testing/raptor/raptor/playback/__init__.py
+++ b/testing/raptor/raptor/playback/__init__.py
@@ -5,19 +5,19 @@ from .mitmproxy import Mitmproxy
 
 LOG = get_proxy_logger(component='mitmproxy')
 
 playback_cls = {
     'mitmproxy': Mitmproxy,
 }
 
 
-def get_playback(config):
+def get_playback(config, android_device=None):
     tool_name = config.get('playback_tool', None)
     if tool_name is None:
         LOG.critical("playback_tool name not found in config")
         return
     if playback_cls.get(tool_name, None) is None:
         LOG.critical("specified playback tool is unsupported: %s" % tool_name)
         return None
 
     cls = playback_cls.get(tool_name)
-    return cls(config)
+    return cls(config, android_device)
--- a/testing/raptor/raptor/playback/base.py
+++ b/testing/raptor/raptor/playback/base.py
@@ -6,18 +6,19 @@
 from __future__ import absolute_import
 
 from abc import ABCMeta, abstractmethod
 
 
 class Playback(object):
     __metaclass__ = ABCMeta
 
-    def __init__(self, config):
+    def __init__(self, config, android_device=None):
         self.config = config
+        self.android_device = android_device
 
     @abstractmethod
     def download(self):
         pass
 
     @abstractmethod
     def setup(self):
         pass
--- a/testing/raptor/raptor/playback/mitmproxy.py
+++ b/testing/raptor/raptor/playback/mitmproxy.py
@@ -85,22 +85,23 @@ POLICIES_CONTENT_OFF = '''{
       "Locked": false
     }
   }
 }'''
 
 
 class Mitmproxy(Playback, Python3Virtualenv, TestingMixin, MercurialScript):
 
-    def __init__(self, config):
+    def __init__(self, config, android_device=None):
         self.config = config
         self.mitmproxy_proc = None
         self.mitmdump_path = None
         self.recordings = config.get('playback_recordings', None)
         self.browser_path = config.get('binary', None)
+        self.android_device = android_device
 
         # raptor_dir is where we will download all mitmproxy required files
         # when running locally it comes from obj_path via mozharness/mach
         if self.config.get("obj_path", None) is not None:
             self.raptor_dir = self.config.get("obj_path")
         else:
             # in production it is ../tasks/task_N/build/, in production that dir
             # is not available as an envvar, however MOZ_UPLOAD_DIR is set as
@@ -197,19 +198,25 @@ class Mitmproxy(Playback, Python3Virtual
         self.py3_install_modules(modules=['mitmproxy'])
         self.mitmdump_path = os.path.join(self.py3_path_to_executables(), 'mitmdump')
 
     def setup(self):
         # for firefox we need to install the generated mitmproxy CA cert
         # for google chromium this is not necessary as chromium will be
         # started with --ignore-certificate-errors cmd line arg
         if self.config['app'] == "firefox":
-            # install the generated CA certificate into Firefox
-            self.install_mitmproxy_cert(self.mitmproxy_proc,
-                                        self.browser_path)
+            # install the generated CA certificate into Firefox desktop
+            self.install_mitmproxy_cert_desktop(self.mitmproxy_proc,
+                                                self.browser_path)
+        elif self.config['app'] == "geckoview":
+            # install the generated CA certificate into android geckoview
+            self.install_mitmproxy_cert_android(self.mitmproxy_proc,
+                                                self.browser_path)
+        else:
+            return
 
     def start(self):
         # if on windows, the mitmdump_path was already set when creating py3 env
         if self.mitmdump_path is None:
             self.mitmdump_path = os.path.join(self.raptor_dir, 'mitmdump')
 
         recordings_list = self.recordings.split()
         self.mitmproxy_proc = self.start_mitmproxy_playback(self.mitmdump_path,
@@ -218,29 +225,24 @@ class Mitmproxy(Playback, Python3Virtual
                                                             self.browser_path)
         return
 
     def stop(self):
         self.stop_mitmproxy_playback()
         self.turn_off_browser_proxy()
         return
 
-    def install_mitmproxy_cert(self, mitmproxy_proc, browser_path):
+    def install_mitmproxy_cert_desktop(self, mitmproxy_proc, browser_path):
         """Install the CA certificate generated by mitmproxy, into Firefox
-        1. Create a directory called distribution in the same directory as the Firefox executable
-        2. Create a file called policies.json with:
-        {
-          "policies": {
-            "certificates": {
-              "Install": ["FULL_PATH_TO_CERT"]
-            }
-          }
-        }
+        1. Create a dir called 'distribution' in the same directory as the Firefox executable
+        2. Create the policies.json file inside that folder; which points to the certificate
+           location, and turns on the the browser proxy settings
         """
         LOG.info("Installing mitmproxy CA certficate into Firefox")
+
         # browser_path is the exe, we want the folder
         self.policies_dir = os.path.dirname(browser_path)
         # on macosx we need to remove the last folders 'MacOS'
         # and the policies json needs to go in ../Content/Resources/
         if 'mac' in self.config['platform']:
             self.policies_dir = os.path.join(self.policies_dir[:-6], "Resources")
         # for all platforms the policies json goes in a 'distribution' dir
         self.policies_dir = os.path.join(self.policies_dir, "distribution")
@@ -257,36 +259,93 @@ class Mitmproxy(Playback, Python3Virtual
             LOG.info("folder already exists: %s" % self.policies_dir)
 
         self.write_policies_json(self.policies_dir,
                                  policies_content=POLICIES_CONTENT_ON %
                                  {'cert': self.cert_path,
                                   'host': self.config['host']})
 
         # cannot continue if failed to add CA cert to Firefox, need to check
-        if not self.is_mitmproxy_cert_installed():
-            LOG.error('Aborting: failed to install mitmproxy CA cert into Firefox')
+        if not self.is_mitmproxy_cert_installed_desktop():
+            LOG.error('Aborting: failed to install mitmproxy CA cert into Firefox desktop')
             self.stop_mitmproxy_playback()
             sys.exit()
 
+    def install_mitmproxy_cert_android(self, mitmproxy_proc, browser_path):
+        """Install the CA certificate generated by mitmproxy, into geckoview android
+        1. Get the `certutil` tool.
+        2. Create an NSS certificate database in the geckoview browser profile dir.
+           `certutil -N -d sql:<path to profile> --empty-password`
+        3. Import the mitmproxy certificate into the database.
+           `certutil -A -d sql:<path to profile> -n "some nickname" -t TC,, -a -i <path to CA.pem>`
+        """
+        # get the certutil tool
+        if self.config.get("obj_path", None) is not None:
+            # when running locally, it is found in the Firefox desktop build (..obj../dist/bin)
+            self.certutil = os.path.join(self.config['obj_path'], 'dist', 'bin')
+        else:
+            # in production it is already downloaded on the host automation machines via hostutils
+            # self.certutil = TODO
+            LOG.info("TODO: where is the path in production to certutil/hostutils?")
+
+        bin_suffix = mozinfo.info.get('bin_suffix', '')
+        self.certutil = os.path.join(self.certutil, "certutil" + bin_suffix)
+
+        if os.path.isfile(self.certutil):
+            LOG.info("certutil is found at: %s" % self.certutil)
+        else:
+            LOG.critical("unable to find certutil at %s" % self.certutil)
+
+        # DEFAULT_CERT_PATH has local path and name of mitmproxy cert i.e.
+        # /home/cltbld/.mitmproxy/mitmproxy-ca-cert.cer
+        self.local_cert_path = DEFAULT_CERT_PATH
+
+        # create cert db
+        param1 = "sql:%s/" % self.config['local_profile_dir']
+        command = [self.certutil, '-N', '-d', param1, '--empty-password']
+
+        LOG.info("creating nss cert database using command: %s" % ' '.join(command))
+        cmd_proc = subprocess.Popen(command, env=os.environ.copy())
+        time.sleep(3)
+        cmd_terminated = cmd_proc.poll()
+        if cmd_terminated is None:  # None value indicates process hasn't terminated
+            LOG.critical("nss cert db creation command failed to complete")
+
+        # import mitmproxy cert into the db
+        command = [self.certutil, '-A', '-d', param1, '-n',
+                   'mitmproxy-cert', '-t', 'TC,,', '-a', '-i', self.local_cert_path]
+
+        LOG.info("importing mitmproxy cert into db using command: %s" % ' '.join(command))
+        cmd_proc = subprocess.Popen(command, env=os.environ.copy())
+        time.sleep(3)
+        cmd_terminated = cmd_proc.poll()
+        if cmd_terminated is None:  # None value indicates process hasn't terminated
+            LOG.critical("command to import mitmproxy cert into cert db failed to complete")
+
+        # cannot continue if failed to add CA cert to Firefox, need to check
+        # if not self.is_mitmproxy_cert_installed_android():
+        #    LOG.error('Aborting: failed to install mitmproxy CA cert into Firefox')
+        #    self.stop_mitmproxy_playback()
+        #    sys.exit()
+
     def write_policies_json(self, location, policies_content):
         policies_file = os.path.join(location, "policies.json")
         LOG.info("writing: %s" % policies_file)
 
         with open(policies_file, 'w') as fd:
             fd.write(policies_content)
 
     def read_policies_json(self, location):
         policies_file = os.path.join(location, "policies.json")
         LOG.info("reading: %s" % policies_file)
 
         with open(policies_file, 'r') as fd:
             return fd.read()
 
-    def is_mitmproxy_cert_installed(self):
+    def is_mitmproxy_cert_installed_desktop(self):
         """Verify mitmxproy CA cert was added to Firefox"""
         try:
             # read autoconfig file, confirm mitmproxy cert is in there
             contents = self.read_policies_json(self.policies_dir)
             LOG.info("Firefox policies file contents:")
             LOG.info(contents)
             if (POLICIES_CONTENT_ON % {
                     'cert': self.cert_path,
@@ -295,16 +354,21 @@ class Mitmproxy(Playback, Python3Virtual
             else:
 
                 return False
         except Exception as e:
             LOG.info("failed to read Firefox policies file, exeption: %s" % e)
             return False
         return True
 
+    def is_mitmproxy_cert_installed_android(self):
+        """Verify mitmxproy CA cert was added to Firefox"""
+        LOG.info("* TODO: verify cert is installed on android")
+        return False
+
     def start_mitmproxy_playback(self,
                                  mitmdump_path,
                                  mitmproxy_recording_path,
                                  mitmproxy_recordings_list,
                                  browser_path):
         """Startup mitmproxy and replay the specified flow file"""
 
         LOG.info("mitmdump path: %s" % mitmdump_path)
--- a/testing/raptor/raptor/raptor.py
+++ b/testing/raptor/raptor/raptor.py
@@ -23,18 +23,16 @@ here = os.path.abspath(os.path.dirname(_
 if os.environ.get('SCRIPTSPATH', None) is not None:
     # in production it is env SCRIPTS_PATH
     mozharness_dir = os.environ['SCRIPTSPATH']
 else:
     # locally it's in source tree
     mozharness_dir = os.path.join(here, '../../../mozharness')
 sys.path.insert(0, mozharness_dir)
 
-from mozharness.mozilla.firefox.autoconfig import _cfg_file_path, _autoconfig_path
-
 webext_dir = os.path.join(os.path.dirname(here), 'webext')
 sys.path.insert(0, here)
 
 try:
     from mozbuild.base import MozbuildObject
     build = MozbuildObject.from_environment(cwd=here)
 except ImportError:
     build = None
@@ -45,26 +43,16 @@ from control_server import RaptorControl
 from gen_test_config import gen_test_config
 from outputhandler import OutputHandler
 from manifest import get_raptor_test_list
 from playback import get_playback
 from results import RaptorResultsHandler
 from gecko_profile import GeckoProfile
 
 
-def remove_autoconfig(binary):
-    bindir = os.path.dirname(binary)
-    mozillacfg = _cfg_file_path(bindir)
-    if os.path.isfile(mozillacfg):
-        os.unlink(mozillacfg)
-    autoconfig = _autoconfig_path(bindir)
-    if os.path.isfile(autoconfig):
-        os.unlink(autoconfig)
-
-
 class Raptor(object):
     """Container class for Raptor"""
 
     def __init__(self, app, binary, run_local=False, obj_path=None,
                  gecko_profile=False, gecko_profile_interval=None, gecko_profile_entries=None,
                  symbols_path=None, host=None, is_release_build=False, debug_mode=False):
         self.config = {}
         self.config['app'] = app
@@ -81,44 +69,45 @@ class Raptor(object):
         self.config['is_release_build'] = is_release_build
         self.raptor_venv = os.path.join(os.getcwd(), 'raptor-venv')
         self.log = get_default_logger(component='raptor-main')
         self.control_server = None
         self.playback = None
         self.benchmark = None
         self.gecko_profiler = None
         self.post_startup_delay = 30000
+        self.device = None
 
         # debug mode is currently only supported when running locally
         self.debug_mode = debug_mode if self.config['run_local'] else False
 
         # if running debug-mode reduce the pause after browser startup
         if self.debug_mode:
             self.post_startup_delay = 3000
             self.log.info("debug-mode enabled, reducing post-browser startup pause to %d ms"
                           % self.post_startup_delay)
 
         # Create the profile; for geckoview we want a firefox profile type
         if self.config['app'] == 'geckoview':
             self.profile = create_profile('firefox')
         else:
             self.profile = create_profile(self.config['app'])
-            # Clear any existing mozilla.cfg file to prevent earlier
-            # runs using mitmproxy from interfering with settings.
-            remove_autoconfig(binary)
 
         # Merge in base profiles
         with open(os.path.join(self.profile_data_dir, 'profiles.json'), 'r') as fh:
             base_profiles = json.load(fh)['raptor']
 
         for name in base_profiles:
             path = os.path.join(self.profile_data_dir, name)
             self.log.info("Merging profile: {}".format(path))
             self.profile.merge(path)
 
+        # add profile dir to our config
+        self.config['local_profile_dir'] = self.profile.profile
+
         # create results holder
         self.results_handler = RaptorResultsHandler()
 
         # when testing desktop browsers we use mozrunner to start the browser; when
         # testing on android (i.e. geckoview) we use mozdevice to control the device app
 
         if self.config['app'] == "geckoview":
             # create the android device handler; it gets initiated and sets up adb etc
@@ -172,33 +161,34 @@ class Raptor(object):
         self.log.info("starting raptor test: %s" % test['name'])
         self.log.info("test settings: %s" % str(test))
         self.log.info("raptor config: %s" % str(self.config))
 
         # benchmark-type tests require the benchmark test to be served out
         if test.get('type') == "benchmark":
             self.benchmark = Benchmark(self.config, test)
             benchmark_port = int(self.benchmark.port)
+
+            # for android we must make the benchmarks server available to the device
+            if self.config['app'] == "geckoview" and self.config['host'] \
+                    in ('localhost', '127.0.0.1'):
+                self.log.info("making the raptor benchmarks server port available to device")
+                _tcp_port = "tcp:%s" % benchmark_port
+                self.device.create_socket_connection('reverse', _tcp_port, _tcp_port)
         else:
             benchmark_port = 0
 
         gen_test_config(self.config['app'],
                         test['name'],
                         self.control_server.port,
                         self.post_startup_delay,
                         host=self.config['host'],
                         b_port=benchmark_port,
                         debug_mode=1 if self.debug_mode else 0)
 
-        # for android we must make the benchmarks server available to the device
-        if self.config['app'] == "geckoview" and self.config['host'] in ('localhost', '127.0.0.1'):
-            self.log.info("making the raptor benchmarks server port available to device")
-            _tcp_port = "tcp:%s" % benchmark_port
-            self.device.create_socket_connection('reverse', _tcp_port, _tcp_port)
-
         # must intall raptor addon each time because we dynamically update some content
         # note: for chrome the addon is just a list of paths that ultimately are added
         # to the chromium command line '--load-extension' argument
         raptor_webext = os.path.join(webext_dir, 'raptor')
         self.log.info("installing webext %s" % raptor_webext)
         self.profile.addons.install(raptor_webext)
 
         # add test specific preferences
@@ -208,46 +198,82 @@ class Raptor(object):
             else:
                 self.log.info("preferences were configured for the test, \
                               but we do not install them on non Firefox browsers.")
 
         # on firefox we can get an addon id; chrome addon actually is just cmd line arg
         if self.config['app'] in ["firefox", "geckoview"]:
             webext_id = self.profile.addons.addon_details(raptor_webext)['id']
 
+        # for android/geckoview, create a top-level raptor folder on the device
+        # sdcard; if it already exists remove it so we start fresh each time
+        if self.config['app'] == "geckoview":
+            self.device_raptor_dir = "/sdcard/raptor"
+            self.config['device_raptor_dir'] = self.device_raptor_dir
+            if self.device.is_dir(self.device_raptor_dir):
+                self.log.info("deleting existing device raptor dir: %s" % self.device_raptor_dir)
+                self.device.rm(self.device_raptor_dir, recursive=True)
+            self.log.info("creating raptor folder on sdcard: %s" % self.device_raptor_dir)
+            self.device.mkdir(self.device_raptor_dir)
+            self.device.chmod(self.device_raptor_dir, recursive=True)
+
         # some tests require tools to playback the test pages
         if test.get('playback', None) is not None:
             self.get_playback_config(test)
             # startup the playback tool
-            self.playback = get_playback(self.config)
+            self.playback = get_playback(self.config, self.device)
+
+            # for android we must make the playback server available to the device
+            if self.config['app'] == "geckoview" and self.config['host'] \
+                    in ('localhost', '127.0.0.1'):
+                self.log.info("making the raptor playback server port available to device")
+                _tcp_port = "tcp:8080"
+                self.device.create_socket_connection('reverse', _tcp_port, _tcp_port)
 
         if self.config['app'] in ("geckoview", "firefox") and \
            self.config['host'] not in ('localhost', '127.0.0.1'):
             # Must delete the proxy settings from the profile if running
             # the test with a host different from localhost.
             userjspath = os.path.join(self.profile.profile, 'user.js')
             with open(userjspath) as userjsfile:
                 prefs = userjsfile.readlines()
             prefs = [pref for pref in prefs if 'network.proxy' not in pref]
             with open(userjspath, 'w') as userjsfile:
                 userjsfile.writelines(prefs)
 
-        # for geckoview we must copy the profile onto the device and set perms
+        # for geckoview/android pageload playback we can't use a policy to turn on the
+        # proxy; we need to set prefs instead; note that the 'host' may be different
+        # than '127.0.0.1' so we must set the prefs accordingly
+        if self.config['app'] == "geckoview" and test.get('playback', None) is not None:
+            self.log.info("setting profile prefs to turn on the geckoview browser proxy")
+            no_proxies_on = "localhost, 127.0.0.1, %s" % self.config['host']
+            proxy_prefs = {}
+            proxy_prefs["network.proxy.type"] = 1
+            proxy_prefs["network.proxy.http"] = self.config['host']
+            proxy_prefs["network.proxy.http_port"] = 8080
+            proxy_prefs["network.proxy.ssl"] = self.config['host']
+            proxy_prefs["network.proxy.ssl_port"] = 8080
+            proxy_prefs["network.proxy.no_proxies_on"] = no_proxies_on
+            self.profile.set_preferences(proxy_prefs)
+
+        # now some final settings, and then startup of the browser under test
         if self.config['app'] == "geckoview":
+            # for android/geckoview we must copy the profile onto the device and set perms
             if not self.device.is_app_installed(self.config['binary']):
                 raise Exception('%s is not installed' % self.config['binary'])
-
-            self.log.info("copying firefox profile onto the android device")
-            self.device_profile = "/sdcard/raptor-profile"
+            self.device_profile = os.path.join(self.device_raptor_dir, "profile")
             if self.device.is_dir(self.device_profile):
+                self.log.info("deleting existing device profile folder: %s" % self.device_profile)
                 self.device.rm(self.device_profile, recursive=True)
+            self.log.info("creating profile folder on device: %s" % self.device_profile)
             self.device.mkdir(self.device_profile)
+            self.log.info("copying firefox profile onto the device")
+            self.log.info("note: the profile folder being copied is: %s" % self.profile.profile)
+            self.log.info('the adb push cmd copies that profile dir to a new temp dir before copy')
             self.device.push(self.profile.profile, self.device_profile)
-
-            self.log.info("setting permisions to profile dir on the device")
             self.device.chmod(self.device_profile, recursive=True)
 
             # now start the geckoview app
             self.log.info("starting %s" % self.config['app'])
 
             extra_args = ["-profile", self.device_profile,
                           "--es", "env0", "LOG_VERBOSE=1",
                           "--es", "env1", "R_LOG_LEVEL=6"]
@@ -420,17 +446,16 @@ class Raptor(object):
         self.control_server.stop()
         if self.config['app'] != "geckoview":
             self.runner.stop()
         elif self.config['app'] == 'geckoview':
             self.log.info('removing reverse socket connections')
             self.device.remove_socket_connections('reverse')
         else:
             pass
-        remove_autoconfig(self.config['binary'])
         self.log.info("finished")
 
 
 def view_gecko_profile(ffox_bin):
     # automatically load the latest talos gecko-profile archive in perf-html.io
     LOG = get_default_logger(component='raptor-view-gecko-profile')
 
     if sys.platform.startswith('win') and not ffox_bin.endswith(".exe"):
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/html/syntax/parsing/quotes-in-meta.html
@@ -0,0 +1,12 @@
+<!doctype html>
+<meta http-equiv="Content-Type" content='charset="windows-1251'>
+<meta charset=windows-1250>
+<title></title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<link rel=help href="https://html.spec.whatwg.org/#algorithm-for-extracting-a-character-encoding-from-a-meta-element">
+<script>
+test(function() {
+    assert_equals(document.characterSet, "windows-1250");
+});
+</script>
--- a/testing/xpcshell/head.js
+++ b/testing/xpcshell/head.js
@@ -392,48 +392,32 @@ function _setupDebuggerServer(breakpoint
                     "  firefox-appdir = browser\n" +
                     "to the xpcshell.ini manifest.\n" +
                     "It is possible for this to alter test behevior by " +
                     "triggering additional browser code to run, so check " +
                     "test behavior after making this change.\n" +
                     "See also https://bugzil.la/1215378.");
   }
   let { DebuggerServer } = require("devtools/server/main");
-  let { OriginalLocation } = require("devtools/server/actors/common");
   DebuggerServer.init();
   DebuggerServer.registerAllActors();
   let { createRootActor } = require("resource://testing-common/dbg-actors.js");
   DebuggerServer.setRootActor(createRootActor);
   DebuggerServer.allowChromeProcess = true;
 
   // An observer notification that tells us when we can "resume" script
   // execution.
-  const TOPICS = ["devtools-thread-resumed", "xpcshell-test-devtools-shutdown"];
+  const TOPICS = ["devtools-thread-instantiated", "devtools-thread-resumed", "xpcshell-test-devtools-shutdown"];
   let observe = function(subject, topic, data) {
-    switch (topic) {
-      case "devtools-thread-resumed":
-        // Exceptions in here aren't reported and block the debugger from
-        // resuming, so...
-        try {
-          // Add a breakpoint for the first line in our test files.
-          let threadActor = subject.wrappedJSObject;
-          for (let file of breakpointFiles) {
-            // Pass an empty `source` object to workaround `source` function assertion
-            let sourceActor = threadActor.sources.source({originalUrl: file, source: {}});
-            sourceActor._getOrCreateBreakpointActor(new OriginalLocation(sourceActor, 1));
-          }
-        } catch (ex) {
-          info("Failed to initialize breakpoints: " + ex + "\n" + ex.stack);
-        }
-        break;
-      case "xpcshell-test-devtools-shutdown":
-        // the debugger has shutdown before we got a resume event - nothing
-        // special to do here.
-        break;
+    if (topic === "devtools-thread-instantiated") {
+      const threadActor = subject.wrappedJSObject;
+      threadActor.setBreakpointOnLoad(breakpointFiles);
+      return;
     }
+
     for (let topicToRemove of TOPICS) {
       _Services.obs.removeObserver(observe, topicToRemove);
     }
     callback();
   };
 
   for (let topic of TOPICS) {
     _Services.obs.addObserver(observe, topic);
--- a/third_party/rust/dwrote/.cargo-checksum.json
+++ b/third_party/rust/dwrote/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{"Cargo.toml":"7e1fc76f204e32123bd7c8964377fa5b5231187f312683210393360ead036908","README.md":"d69d75705e2582721cbfb2d3b4b2af052c71679057a0b2ac53a22c03f1755bba","appveyor.yml":"7c1e0718a363d3567cecd1ef772d4e17c2a17f18906dc464dce8a2411adff6be","src/bitmap_render_target.rs":"fc13525d7459515e4bf9769c8a8961b046b4d1ba4042591aaf0925dd5edebf64","src/com_helpers.rs":"02535b27bfb0cee6e4d8db3abd22f2d2e8137a4ce3ab3504beaf4fa3ca9370df","src/comptr.rs":"84794cf04b772398e75fdb5d55fd8fa015abf26c61b1f9c761a597133682b2e1","src/font.rs":"a79b944f2f5125bbef9e24921355dc6996f073e3742ddd410b8efaa0df3a3ee2","src/font_collection.rs":"67cd566714f4c0a20cba24dd064ba471e75016fa2672b2153a19878e6b71f24d","src/font_collection_impl.rs":"a585a6ce62083b3346d67619ea47fec46423a7fb04cc11372828389ab26c5a05","src/font_face.rs":"7f78c4132df39857d8118ac3eacbb57e11bca1d69f9d7f8e1c1c24b7a2b69749","src/font_family.rs":"4e948542dba0c158187d0cb2d72343c443380480cacd12894070d0ef1351dd0a","src/font_file.rs":"1c012d0b436c2831d31cd76f77a59dab1edc5d63881c495eb486cd4febe23031","src/font_file_loader_impl.rs":"71c4153971dbfc21d42ba2e33f159fcb145f7dcfbd17e856e9fd75f0571d41e0","src/gdi_interop.rs":"04dbef7c34bb0fe62c4f2c2ceca62ca94c75a964d744b29b3322a6c3bbb4eabd","src/geometry_sink_impl.rs":"d615de212e55b8b8d95c8d605fc5d78044b4ae4dfd846f706911a16cc3afc049","src/glyph_run_analysis.rs":"3b2a351422098a19e8f490421e5b19227fc14a41a0df97d488c536fd1d4b552c","src/helpers.rs":"2f3c57642b24b80c45bbd012e7d6ca1fc524b1b42a8be004cb9b52ea13f4166d","src/lib.rs":"b634e62dd088d804429f451ba9f14aaab0b6a1179042d70fed825f3253ffacfb","src/outline_builder.rs":"0f5c842b2ffe75e21d68f93be6a3834c120bd43303d4e490fdfee9f4f964cdc4","src/rendering_params.rs":"850a51143790f5d29422dc49cbceddc232d814ecd0e6933434ad644e6eec539b","src/test.rs":"158aa4d03655f4efef00327fe72a03dfb504659176aa0eef976ca2485b2c1d74","src/types.rs":"587aea2e50720e85b28efe237c8ea10bc45b52049ca724447a0fc9b0e6672b11"},"package":"7b46afd0d0bbbea88fc083ea293e40865e26a75ec9d38cf5d05a23ac3e2ffe02"}
\ No newline at end of file
+{"files":{"Cargo.toml":"5f9a26a7a0f3fffc7093b0ac9e2fd84db133ba5516a9bfb53ed4f842b350564f","README.md":"d69d75705e2582721cbfb2d3b4b2af052c71679057a0b2ac53a22c03f1755bba","appveyor.yml":"7c1e0718a363d3567cecd1ef772d4e17c2a17f18906dc464dce8a2411adff6be","src/bitmap_render_target.rs":"fc13525d7459515e4bf9769c8a8961b046b4d1ba4042591aaf0925dd5edebf64","src/com_helpers.rs":"02535b27bfb0cee6e4d8db3abd22f2d2e8137a4ce3ab3504beaf4fa3ca9370df","src/comptr.rs":"84794cf04b772398e75fdb5d55fd8fa015abf26c61b1f9c761a597133682b2e1","src/font.rs":"a79b944f2f5125bbef9e24921355dc6996f073e3742ddd410b8efaa0df3a3ee2","src/font_collection.rs":"67cd566714f4c0a20cba24dd064ba471e75016fa2672b2153a19878e6b71f24d","src/font_collection_impl.rs":"a585a6ce62083b3346d67619ea47fec46423a7fb04cc11372828389ab26c5a05","src/font_face.rs":"7f78c4132df39857d8118ac3eacbb57e11bca1d69f9d7f8e1c1c24b7a2b69749","src/font_family.rs":"4e948542dba0c158187d0cb2d72343c443380480cacd12894070d0ef1351dd0a","src/font_file.rs":"1c012d0b436c2831d31cd76f77a59dab1edc5d63881c495eb486cd4febe23031","src/font_file_loader_impl.rs":"71c4153971dbfc21d42ba2e33f159fcb145f7dcfbd17e856e9fd75f0571d41e0","src/gdi_interop.rs":"04dbef7c34bb0fe62c4f2c2ceca62ca94c75a964d744b29b3322a6c3bbb4eabd","src/geometry_sink_impl.rs":"d615de212e55b8b8d95c8d605fc5d78044b4ae4dfd846f706911a16cc3afc049","src/glyph_run_analysis.rs":"3b2a351422098a19e8f490421e5b19227fc14a41a0df97d488c536fd1d4b552c","src/helpers.rs":"2f3c57642b24b80c45bbd012e7d6ca1fc524b1b42a8be004cb9b52ea13f4166d","src/lib.rs":"d6a109158cb69cf4a113722169ba8b339d9d38eccb2c9d6b2fe68dd40da22814","src/outline_builder.rs":"0f5c842b2ffe75e21d68f93be6a3834c120bd43303d4e490fdfee9f4f964cdc4","src/rendering_params.rs":"850a51143790f5d29422dc49cbceddc232d814ecd0e6933434ad644e6eec539b","src/test.rs":"158aa4d03655f4efef00327fe72a03dfb504659176aa0eef976ca2485b2c1d74","src/types.rs":"587aea2e50720e85b28efe237c8ea10bc45b52049ca724447a0fc9b0e6672b11"},"package":"f0beca78470f26189a662e72afe7a54c625b4feb06b2d36c207ac15319bd57c5"}
\ No newline at end of file
--- a/third_party/rust/dwrote/Cargo.toml
+++ b/third_party/rust/dwrote/Cargo.toml
@@ -7,17 +7,17 @@
 #
 # If you believe there's an error in this file please file an
 # issue against the rust-lang/cargo repository. If you're
 # editing this file be aware that the upstream Cargo.toml
 # will likely look very different (and much more reasonable)
 
 [package]
 name = "dwrote"
-version = "0.6.2"
+version = "0.6.3"
 authors = ["Vladimir Vukicevic <vladimir@pobox.com>"]
 description = "Lightweight binding to DirectWrite."
 license = "MPL-2.0"
 repository = "https://github.com/servo/dwrote-rs"
 
 [lib]
 name = "dwrote"
 [dependencies.lazy_static]
--- a/third_party/rust/dwrote/src/lib.rs
+++ b/third_party/rust/dwrote/src/lib.rs
@@ -60,16 +60,17 @@ pub use winapi::um::dwrite::{DWRITE_FONT
                  DWRITE_FONT_SIMULATIONS_BOLD,
                  DWRITE_FONT_SIMULATIONS_OBLIQUE};
 pub use winapi::um::dwrite::{DWRITE_TEXTURE_ALIASED_1x1, DWRITE_TEXTURE_CLEARTYPE_3x1};
 pub use winapi::um::dwrite::{DWRITE_FONT_SIMULATIONS};
 pub use winapi::um::dwrite::{DWRITE_RENDERING_MODE};
 pub use winapi::um::dwrite::{DWRITE_TEXTURE_TYPE};
 pub use winapi::um::dwrite_3::{DWRITE_FONT_AXIS_VALUE};
 pub use winapi::um::dcommon::{DWRITE_MEASURING_MODE};
+pub use winapi::shared::windef::RECT;
 use winapi::um::libloaderapi::{GetProcAddress, LoadLibraryW};
 
 #[macro_use] mod com_helpers;
 
 mod bitmap_render_target; pub use bitmap_render_target::BitmapRenderTarget;
 mod font; pub use font::{Font, InformationalStringId};
 mod font_collection; pub use font_collection::FontCollection;
 mod font_face; pub use font_face::{FontFace, FontFaceType};
--- a/toolkit/modules/Promise-backend.js
+++ b/toolkit/modules/Promise-backend.js
@@ -61,20 +61,16 @@ if (Cu) {
   // If we're in a devtools module environment, ChromeUtils won't exist.
   /* eslint "mozilla/use-chromeutils-import": ["error", {allowCu: true}] */
   Cu.import("resource://gre/modules/Services.jsm", this);
   Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
 
   XPCOMUtils.defineLazyServiceGetter(this, "FinalizationWitnessService",
                                      "@mozilla.org/toolkit/finalizationwitness;1",
                                      "nsIFinalizationWitnessService");
-
-  // For now, we're worried about add-ons using Promises with CPOWs, so we'll
-  // permit them in this scope, but this support will go away soon.
-  Cu.permitCPOWsInScope(this);
 }
 
 const STATUS_PENDING = 0;
 const STATUS_RESOLVED = 1;
 const STATUS_REJECTED = 2;
 
 // This N_INTERNALS name allow internal properties of the Promise to be
 // accessed only by this module, while still being visible on the object
--- a/toolkit/modules/Task.jsm
+++ b/toolkit/modules/Task.jsm
@@ -82,20 +82,16 @@ var EXPORTED_SYMBOLS = [
  *   task.  This makes it possible to call an externally provided function and
  *   spawn a task from it, regardless of whether it is an asynchronous generator
  *   or a synchronous function.  This comes in handy when iterating over
  *   function lists where some items have been converted to tasks and some not.
  */
 
 // Globals
 
-// For now, we're worried about add-ons using Tasks with CPOWs, so we'll
-// permit them in this scope, but this support will go away soon.
-Cu.permitCPOWsInScope(this);
-
 // The following error types are considered programmer errors, which should be
 // reported (possibly redundantly) so as to let programmers fix their code.
 const ERRORS_TO_REPORT = ["EvalError", "RangeError", "ReferenceError", "TypeError"];
 
 /**
  * The Task currently being executed
  */
 var gCurrentTask = null;