Merge inbound to mozilla-central a=merge on a CLOSED TREE
authorCoroiu Cristina <ccoroiu@mozilla.com>
Mon, 06 May 2019 00:38:28 +0300
changeset 472601 1e3244e602fc0373508049b6fe544332f800f033
parent 472600 647a90020b45dc8cdc45370bf3a91df815084b8c (current diff)
parent 472599 7aae4f23a5a189ffda85ab44342669b235c91c38 (diff)
child 472602 ad73e560441111bcc93c125674fe0e9bc61a53d7
child 472628 e86a75908fd3f530563496cee8777f0e64e3fd20
push id113027
push userccoroiu@mozilla.com
push dateSun, 05 May 2019 21:45:51 +0000
treeherdermozilla-inbound@1e3244e602fc [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone68.0a1
first release with
nightly linux32
1e3244e602fc / 68.0a1 / 20190505213908 / files
nightly linux64
1e3244e602fc / 68.0a1 / 20190505213908 / files
nightly mac
1e3244e602fc / 68.0a1 / 20190505213908 / files
nightly win32
1e3244e602fc / 68.0a1 / 20190505213908 / files
nightly win64
1e3244e602fc / 68.0a1 / 20190505213908 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to mozilla-central a=merge on a CLOSED TREE
gfx/wr/webrender/src/batch.rs
gfx/wr/webrender/src/picture.rs
gfx/wr/webrender/src/prim_store/mod.rs
testing/web-platform/meta/svg/render/reftests/blending-002.svg.ini
--- a/accessible/tests/browser/events/browser_test_focus_urlbar.js
+++ b/accessible/tests/browser/events/browser_test_focus_urlbar.js
@@ -77,17 +77,17 @@ async function runTests() {
   info("Ensuring no focus change on text selection and delete");
   EventUtils.synthesizeKey("KEY_ArrowLeft", {shiftKey: true});
   EventUtils.synthesizeKey("KEY_Delete");
   await waitForSearchFinish();
   // Wait a tick for a11y events to fire.
   await TestUtils.waitForTick();
   testStates(textBox, STATE_FOCUSED);
 
-  info("Ensuring autocomplete focus on down arrow");
+  info("Ensuring autocomplete focus on down arrow (1)");
   focused = waitForEvent(EVENT_FOCUS, isEventForAutocompleteItem);
   EventUtils.synthesizeKey("KEY_ArrowDown");
   event = await focused;
   testStates(event.accessible, STATE_FOCUSED);
 
   info("Ensuring focus of another autocomplete item on down arrow");
   focused = waitForEvent(EVENT_FOCUS, isEventForAutocompleteItem);
   EventUtils.synthesizeKey("KEY_ArrowDown");
@@ -121,43 +121,43 @@ async function runTests() {
   testStates(textBox, STATE_FOCUSED);
   if (UrlbarPrefs.get("quantumbar")) {
     gURLBar.view.close();
   }
   // On Mac, down arrow when not at the end of the field moves to the end.
   // Move back to the end so the next press of down arrow opens the popup.
   EventUtils.synthesizeKey("KEY_ArrowRight");
 
-  info("Ensuring autocomplete focus on down arrow");
+  info("Ensuring autocomplete focus on down arrow (2)");
   focused = waitForEvent(EVENT_FOCUS, isEventForAutocompleteItem);
   EventUtils.synthesizeKey("KEY_ArrowDown");
   event = await focused;
   testStates(event.accessible, STATE_FOCUSED);
 
   info("Ensuring text box focus when text is typed");
   focused = waitForEvent(EVENT_FOCUS, textBox);
   EventUtils.sendString("z");
   await focused;
   testStates(textBox, STATE_FOCUSED);
   EventUtils.synthesizeKey("KEY_Backspace");
   await waitForSearchFinish();
 
-  info("Ensuring autocomplete focus on down arrow");
+  info("Ensuring autocomplete focus on down arrow (3)");
   focused = waitForEvent(EVENT_FOCUS, isEventForAutocompleteItem);
   EventUtils.synthesizeKey("KEY_ArrowDown");
   event = await focused;
   testStates(event.accessible, STATE_FOCUSED);
 
   info("Ensuring text box focus on backspace");
   focused = waitForEvent(EVENT_FOCUS, textBox);
   EventUtils.synthesizeKey("KEY_Backspace");
   await focused;
   testStates(textBox, STATE_FOCUSED);
 
-  info("Ensuring autocomplete focus on down arrow");
+  info("Ensuring autocomplete focus on down arrow (4)");
   focused = waitForEvent(EVENT_FOCUS, isEventForAutocompleteItem);
   EventUtils.synthesizeKey("KEY_ArrowDown");
   event = await focused;
   testStates(event.accessible, STATE_FOCUSED);
 
   info("Ensuring text box focus on text selection");
   focused = waitForEvent(EVENT_FOCUS, textBox);
   EventUtils.synthesizeKey("KEY_ArrowLeft", {shiftKey: true});
--- a/browser/components/urlbar/UrlbarController.jsm
+++ b/browser/components/urlbar/UrlbarController.jsm
@@ -312,32 +312,39 @@ class UrlbarController {
               { reverse: event.keyCode == KeyEvent.DOM_VK_UP ||
                         event.keyCode == KeyEvent.DOM_VK_PAGE_UP });
           }
         } else {
           if (this.keyEventMovesCaret(event)) {
             break;
           }
           if (executeAction) {
+            this.userSelectionBehavior = "arrow";
             this.input.startQuery({ searchString: this.input.textValue });
           }
         }
         event.preventDefault();
         break;
       case KeyEvent.DOM_VK_LEFT:
       case KeyEvent.DOM_VK_RIGHT:
       case KeyEvent.DOM_VK_HOME:
       case KeyEvent.DOM_VK_END:
         this.view.removeAccessibleFocus();
         break;
       case KeyEvent.DOM_VK_DELETE:
       case KeyEvent.DOM_VK_BACK_SPACE:
-        if (event.shiftKey && this.view.isOpen &&
-            (!executeAction || this._handleDeleteEntry())) {
-          event.preventDefault();
+        if (!this.view.isOpen) {
+          break;
+        }
+        if (event.shiftKey) {
+          if (!executeAction || this._handleDeleteEntry()) {
+            event.preventDefault();
+          }
+        } else if (executeAction) {
+          this.view.removeAccessibleFocus();
         }
         break;
     }
   }
 
   /**
    * Tries to initialize a speculative connection on a result.
    * Speculative connections are only supported for a subset of all the results.
--- a/browser/components/urlbar/UrlbarView.jsm
+++ b/browser/components/urlbar/UrlbarView.jsm
@@ -210,17 +210,17 @@ class UrlbarView {
     this._updateResults(queryContext);
 
     let isFirstPreselectedResult = false;
     if (queryContext.lastResultCount == 0) {
       if (queryContext.preselected) {
         isFirstPreselectedResult = true;
         this._selectItem(this._rows.firstElementChild, {
           updateInput: false,
-          setAccessibleFocus: false,
+          setAccessibleFocus: this.controller._userSelectionBehavior == "arrow",
         });
       } else {
         // Clear the selection when we get a new set of results.
         this._selectItem(null);
       }
       // Hide the one-off search buttons if the input starts with a potential @
       // search alias or the search restriction character.
       let trimmedValue = this.input.textValue.trim();
--- a/browser/config/whats_new_page.yml
+++ b/browser/config/whats_new_page.yml
@@ -63,35 +63,39 @@
       release-types: [beta, release-rc]
       products: [firefox]
       update-channel: beta
       # e.g.: ["<61.0"]. {version.major_number} reflects the current version.
       # This is done by taskgraph.
       versions: ["<{version.major_number}.0"]
       locales:
           - be
-          - bs
           - cak
           - cs
           - cy
           - da
           - de
-          - el
+          - dsb
           - en-CA
           - en-GB
           - en-US
           - es-AR
+          - es-CL
           - es-ES
+          - es-MX
           - fr
           - fy-NL
+          - gn
+          - hsb
           - hu
           - ia
           - id
           - it
           - ka
+          - lij
           - nl
           - nn-NO
           - pl
           - pt-BR
           - pt-PT
           - rm
           - ro
           - ru
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -2054,17 +2054,18 @@ void nsJSContext::PokeShrinkingGC() {
 }
 
 // static
 void nsJSContext::MaybePokeCC() {
   if (sCCRunner || sICCRunner || !sHasRunGC || sShuttingDown) {
     return;
   }
 
-  if (!sLastCCEndTime.IsNull()) {
+  // Don't run consecutive CCs too often.
+  if (sCleanupsSinceLastGC && !sLastCCEndTime.IsNull()) {
     uint32_t sinceLastCCEnd = TimeUntilNow(sLastCCEndTime);
     if (sinceLastCCEnd < NS_CC_DELAY) {
       return;
     }
   }
 
   // If GC hasn't run recently and forget skippable only cycle was run,
   // don't start a new cycle too soon.
--- a/dom/base/test/browser_bug593387.js
+++ b/dom/base/test/browser_bug593387.js
@@ -3,17 +3,17 @@
  * Loads a chrome document in a content docshell and then inserts a
  * X-Frame-Options: DENY iframe into the document and verifies that the document
  * loads. The policy we are enforcing is outlined here:
  * https://bugzilla.mozilla.org/show_bug.cgi?id=593387#c17
 */
 
 add_task(async function test() {
   await BrowserTestUtils.withNewTab({ gBrowser,
-                                      url: "chrome://global/content/aboutProfiles.xhtml" },
+                                      url: "chrome://global/content/mozilla.xhtml" },
                                      async function(newBrowser) {
     // NB: We load the chrome:// page in the parent process.
     await testXFOFrameInChrome(newBrowser);
 
     // Run next test (try the same with a content top-level context)
     await BrowserTestUtils.loadURI(newBrowser, "http://example.com/");
     await BrowserTestUtils.browserLoaded(newBrowser);
 
--- a/dom/media/PeerConnection.jsm
+++ b/dom/media/PeerConnection.jsm
@@ -1636,16 +1636,29 @@ class RTCPeerConnection {
 
     if (maxPacketLifeTime === undefined) {
       maxPacketLifeTime = maxRetransmitTime;
     }
 
     if (maxRetransmitTime !== undefined) {
       this.logWarning("Use maxPacketLifeTime instead of deprecated maxRetransmitTime which will stop working soon in createDataChannel!");
     }
+
+    if (protocol.length > 32767) {
+      // At least 65536/2 UTF-16 characters. UTF-8 might be too long.
+      // Spec says to check how long |protocol| and |label| are in _bytes_. This
+      // is a little ambiguous. For now, examine the length of the utf-8 encoding.
+      const byteCounter = new TextEncoder("utf-8");
+
+      if (byteCounter.encode(protocol).length > 65535) {
+        throw new this._win.DOMException(
+            "protocol cannot be longer than 65535 bytes", "TypeError");
+      }
+    }
+
     if (!negotiated) {
       id = null;
     } else if (id === null) {
       throw new this._win.DOMException(
           "id is required when negotiated is true", "TypeError");
     }
     if (maxPacketLifeTime !== undefined && maxRetransmits !== undefined) {
       throw new this._win.DOMException(
--- a/gfx/layers/wr/WebRenderCommandBuilder.cpp
+++ b/gfx/layers/wr/WebRenderCommandBuilder.cpp
@@ -965,16 +965,31 @@ void Grouper::PaintContainerItem(DIGroup
       aGroup->PaintItemRange(this, aChildren->GetBottom(), nullptr, aContext,
                              aRecorder);
       aContext->GetDrawTarget()->PopLayer();
       GP("endGroup %s %p-%d\n", aItem->Name(), aItem->Frame(),
          aItem->GetPerFrameKey());
       aContext->GetDrawTarget()->FlushItem(aItemBounds);
       break;
     }
+    case DisplayItemType::TYPE_BLEND_CONTAINER: {
+      aContext->GetDrawTarget()->PushLayer(false, 1.0,
+                                           nullptr, mozilla::gfx::Matrix(),
+                                           aItemBounds);
+      GP("beginGroup %s %p-%d\n", aItem->Name(), aItem->Frame(),
+         aItem->GetPerFrameKey());
+      aContext->GetDrawTarget()->FlushItem(aItemBounds);
+      aGroup->PaintItemRange(this, aChildren->GetBottom(), nullptr, aContext,
+                             aRecorder);
+      aContext->GetDrawTarget()->PopLayer();
+      GP("endGroup %s %p-%d\n", aItem->Name(), aItem->Frame(),
+         aItem->GetPerFrameKey());
+      aContext->GetDrawTarget()->FlushItem(aItemBounds);
+      break;
+    }
     case DisplayItemType::TYPE_MASK: {
       GP("Paint Mask\n");
       auto maskItem = static_cast<nsDisplayMasksAndClipPaths*>(aItem);
       maskItem->SetPaintRect(maskItem->GetClippedBounds(mDisplayListBuilder));
       if (maskItem->IsValidMask()) {
         maskItem->PaintWithContentsPaintCallback(
             mDisplayListBuilder, aContext, [&] {
               GP("beginGroup %s %p-%d\n", aItem->Name(), aItem->Frame(),
--- a/gfx/wr/webrender/src/batch.rs
+++ b/gfx/wr/webrender/src/batch.rs
@@ -9,17 +9,17 @@ use clip::{ClipDataStore, ClipNodeFlags,
 use clip_scroll_tree::{ClipScrollTree, ROOT_SPATIAL_NODE_INDEX, SpatialNodeIndex, CoordinateSystemId};
 use glyph_rasterizer::GlyphFormat;
 use gpu_cache::{GpuBlockData, GpuCache, GpuCacheHandle, GpuCacheAddress};
 use gpu_types::{BrushFlags, BrushInstance, PrimitiveHeaders, ZBufferId, ZBufferIdGenerator};
 use gpu_types::{ClipMaskInstance, SplitCompositeInstance, SnapOffsets};
 use gpu_types::{PrimitiveInstanceData, RasterizationSpace, GlyphInstance};
 use gpu_types::{PrimitiveHeader, PrimitiveHeaderIndex, TransformPaletteId, TransformPalette};
 use internal_types::{FastHashMap, SavedTargetIndex, TextureSource};
-use picture::{Picture3DContext, PictureCompositeMode, PicturePrimitive, PictureSurface};
+use picture::{Picture3DContext, PictureCompositeMode, PicturePrimitive};
 use prim_store::{DeferredResolve, EdgeAaSegmentMask, PrimitiveInstanceKind, PrimitiveVisibilityIndex};
 use prim_store::{VisibleGradientTile, PrimitiveInstance, PrimitiveOpacity, SegmentInstanceIndex};
 use prim_store::{BrushSegment, ClipMaskKind, ClipTaskIndex, VECS_PER_SEGMENT};
 use prim_store::image::ImageSource;
 use render_backend::DataStores;
 use render_task::{RenderTaskAddress, RenderTaskId, RenderTaskTree, TileBlit};
 use renderer::{BlendMode, ImageBufferKind, ShaderColorMode};
 use renderer::{BLOCKS_PER_UV_RECT, MAX_VERTEX_TEXTURE_WIDTH};
@@ -1027,26 +1027,22 @@ impl AlphaBatchBuilder {
                                         ctx.clip_scroll_tree,
                                     ),
                             };
 
                             let raster_config = pic
                                 .raster_config
                                 .as_ref()
                                 .expect("BUG: 3d primitive was not assigned a surface");
-                            let (uv_rect_address, _) = ctx
-                                .surfaces[raster_config.surface_index.0]
-                                .surface
-                                .as_ref()
-                                .expect("BUG: no surface")
-                                .resolve(
-                                    render_tasks,
-                                    ctx.resource_cache,
-                                    gpu_cache,
-                                );
+                            let (uv_rect_address, _) = render_tasks.resolve_surface(
+                                ctx.surfaces[raster_config.surface_index.0]
+                                    .surface
+                                    .expect("BUG: no surface"),
+                                gpu_cache,
+                            );
 
                             let prim_header_index = prim_headers.push(&prim_header, z_id, [
                                 uv_rect_address.as_int(),
                                 if raster_config.establishes_raster_root { 1 } else { 0 },
                                 0,
                                 clip_task_address.0 as i32,
                             ]);
 
@@ -1094,19 +1090,17 @@ impl AlphaBatchBuilder {
                             brush_flags |= BrushFlags::PERSPECTIVE_INTERPOLATION;
                         };
 
                         let clip_task_address = ctx.get_prim_clip_task_address(
                             prim_info.clip_task_index,
                             render_tasks,
                         ).unwrap_or(OPAQUE_TASK_ADDRESS);
 
-                        let surface = ctx.surfaces[raster_config.surface_index.0]
-                            .surface
-                            .as_ref();
+                        let surface = ctx.surfaces[raster_config.surface_index.0].surface;
 
                         match raster_config.composite_mode {
                             PictureCompositeMode::TileCache { .. } => {
                                 let tile_cache = picture.tile_cache.as_ref().unwrap();
 
                                 // If the tile cache is disabled, just recurse into the
                                 // picture like a normal pass-through picture, adding
                                 // any child primitives into the parent surface batches.
@@ -1258,23 +1252,20 @@ impl AlphaBatchBuilder {
                             }
                             PictureCompositeMode::Filter(ref filter) => {
                                 assert!(filter.is_visible());
                                 match filter {
                                     FilterOp::Blur(..) => {
                                         let kind = BatchKind::Brush(
                                             BrushBatchKind::Image(ImageBufferKind::Texture2DArray)
                                         );
-                                        let (uv_rect_address, textures) = surface
-                                            .expect("bug: surface must be allocated by now")
-                                            .resolve(
-                                                render_tasks,
-                                                ctx.resource_cache,
-                                                gpu_cache,
-                                            );
+                                        let (uv_rect_address, textures) = render_tasks.resolve_surface(
+                                            surface.expect("bug: surface must be allocated by now"),
+                                            gpu_cache,
+                                        );
                                         let key = BatchKey::new(
                                             kind,
                                             non_segmented_blend_mode,
                                             textures,
                                         );
                                         let prim_header_index = prim_headers.push(&prim_header, z_id, [
                                             ShaderColorMode::Image as i32 | ((AlphaType::PremultipliedAlpha as i32) << 16),
                                             RasterizationSpace::Screen as i32,
@@ -1322,19 +1313,17 @@ impl AlphaBatchBuilder {
                                             ],
                                         };
 
                                         // Build batch keys for shadow/content
                                         let shadow_key = BatchKey::new(kind, non_segmented_blend_mode, shadow_textures);
                                         let content_key = BatchKey::new(kind, non_segmented_blend_mode, content_textures);
 
                                         // Retrieve the UV rect addresses for shadow/content.
-                                        let cache_task_id = surface
-                                            .expect("bug: surface must be allocated by now")
-                                            .resolve_render_task_id();
+                                        let cache_task_id = surface.expect("bug: surface must be allocated by now");
                                         let shadow_uv_rect_address = render_tasks[cache_task_id]
                                             .get_texture_address(gpu_cache)
                                             .as_int();
                                         let content_uv_rect_address = render_tasks[secondary_id]
                                             .get_texture_address(gpu_cache)
                                             .as_int();
 
                                         // Get the GPU cache address of the extra data handle.
@@ -1437,23 +1426,20 @@ impl AlphaBatchBuilder {
                                                 unreachable!();
                                             }
                                             FilterOp::ColorMatrix(_) => {
                                                 picture.extra_gpu_data_handle.as_int(gpu_cache)
                                             }
                                             FilterOp::ComponentTransfer => unreachable!(),
                                         };
 
-                                        let (uv_rect_address, textures) = surface
-                                            .expect("bug: surface must be allocated by now")
-                                            .resolve(
-                                                render_tasks,
-                                                ctx.resource_cache,
-                                                gpu_cache,
-                                            );
+                                        let (uv_rect_address, textures) = render_tasks.resolve_surface(
+                                            surface.expect("bug: surface must be allocated by now"),
+                                            gpu_cache,
+                                        );
 
                                         let key = BatchKey::new(
                                             BatchKind::Brush(BrushBatchKind::Blend),
                                             BlendMode::PremultipliedAlpha,
                                             textures,
                                         );
 
                                         let prim_header_index = prim_headers.push(&prim_header, z_id, [
@@ -1489,23 +1475,20 @@ impl AlphaBatchBuilder {
                                 let filter_mode : i32 = 13 |
                                     ((filter_data.data.r_func.to_int() << 28 |
                                       filter_data.data.g_func.to_int() << 24 |
                                       filter_data.data.b_func.to_int() << 20 |
                                       filter_data.data.a_func.to_int() << 16) as i32);
 
                                 let user_data = filter_data.gpu_cache_handle.as_int(gpu_cache);
 
-                                let (uv_rect_address, textures) = surface
-                                    .expect("bug: surface must be allocated by now")
-                                    .resolve(
-                                        render_tasks,
-                                        ctx.resource_cache,
-                                        gpu_cache,
-                                    );
+                                let (uv_rect_address, textures) = render_tasks.resolve_surface(
+                                    surface.expect("bug: surface must be allocated by now"),
+                                    gpu_cache,
+                                );
 
                                 let key = BatchKey::new(
                                     BatchKind::Brush(BrushBatchKind::Blend),
                                     BlendMode::PremultipliedAlpha,
                                     textures,
                                 );
 
                                 let prim_header_index = prim_headers.push(&prim_header, z_id, [
@@ -1527,23 +1510,20 @@ impl AlphaBatchBuilder {
                                 self.current_batch_list().push_single_instance(
                                     key,
                                     bounding_rect,
                                     z_id,
                                     PrimitiveInstanceData::from(instance),
                                 );
                             }
                             PictureCompositeMode::MixBlend(mode) if ctx.use_advanced_blending => {
-                                let (uv_rect_address, textures) = surface
-                                    .expect("bug: surface must be allocated by now")
-                                    .resolve(
-                                        render_tasks,
-                                        ctx.resource_cache,
-                                        gpu_cache,
-                                    );
+                                let (uv_rect_address, textures) = render_tasks.resolve_surface(
+                                    surface.expect("bug: surface must be allocated by now"),
+                                    gpu_cache,
+                                );
                                 let key = BatchKey::new(
                                     BatchKind::Brush(
                                         BrushBatchKind::Image(ImageBufferKind::Texture2DArray),
                                     ),
                                     BlendMode::Advanced(mode),
                                     textures,
                                 );
                                 let prim_header_index = prim_headers.push(&prim_header, z_id, [
@@ -1565,19 +1545,17 @@ impl AlphaBatchBuilder {
                                 self.current_batch_list().push_single_instance(
                                     key,
                                     bounding_rect,
                                     z_id,
                                     PrimitiveInstanceData::from(instance),
                                 );
                             }
                             PictureCompositeMode::MixBlend(mode) => {
-                                let cache_task_id = surface
-                                    .expect("bug: surface must be allocated by now")
-                                    .resolve_render_task_id();
+                                let cache_task_id = surface.expect("bug: surface must be allocated by now");
                                 let backdrop_id = picture.secondary_render_task_id.expect("no backdrop!?");
 
                                 let key = BatchKey::new(
                                     BatchKind::Brush(
                                         BrushBatchKind::MixBlend {
                                             task_id,
                                             source_id: cache_task_id,
                                             backdrop_id,
@@ -1607,19 +1585,17 @@ impl AlphaBatchBuilder {
                                 self.current_batch_list().push_single_instance(
                                     key,
                                     bounding_rect,
                                     z_id,
                                     PrimitiveInstanceData::from(instance),
                                 );
                             }
                             PictureCompositeMode::Blit(_) => {
-                                let cache_task_id = surface
-                                    .expect("bug: surface must be allocated by now")
-                                    .resolve_render_task_id();
+                                let cache_task_id = surface.expect("bug: surface must be allocated by now");
                                 let uv_rect_address = render_tasks[cache_task_id]
                                     .get_texture_address(gpu_cache)
                                     .as_int();
                                 let batch_params = BrushBatchParameters::shared(
                                     BrushBatchKind::Image(ImageBufferKind::Texture2DArray),
                                     BatchTextures::render_target_cache(),
                                     [
                                         ShaderColorMode::Image as i32 | ((AlphaType::PremultipliedAlpha as i32) << 16),
@@ -2648,57 +2624,26 @@ impl PrimitiveInstance {
             Some(ImageProperties { external_image: Some(_), .. }) => {
                 false
             }
             _ => true
         }
     }
 }
 
-impl PictureSurface {
-    // Retrieve the uv rect handle, and texture for a picture surface.
-    fn resolve(
+impl RenderTaskTree {
+    fn resolve_surface(
         &self,
-        render_tasks: &RenderTaskTree,
-        resource_cache: &ResourceCache,
+        task_id: RenderTaskId,
         gpu_cache: &GpuCache,
     ) -> (GpuCacheAddress, BatchTextures) {
-        match *self {
-            PictureSurface::TextureCache(ref handle) => {
-                let rt_cache_entry = resource_cache
-                    .get_cached_render_task(handle);
-                let cache_item = resource_cache
-                    .get_texture_cache_item(&rt_cache_entry.handle);
-
-                (
-                    gpu_cache.get_address(&cache_item.uv_rect_handle),
-                    BatchTextures::color(cache_item.texture_id),
-                )
-            }
-            PictureSurface::RenderTask(task_id) => {
-                (
-                    render_tasks[task_id].get_texture_address(gpu_cache),
-                    BatchTextures::render_target_cache(),
-                )
-            }
-        }
-    }
-
-    // Retrieve the render task id for a picture surface. Should only
-    // be used where it's known that this picture surface will never
-    // be persisted in the texture cache.
-    fn resolve_render_task_id(&self) -> RenderTaskId {
-        match *self {
-            PictureSurface::TextureCache(..) => {
-                panic!("BUG: unexpectedly cached render task");
-            }
-            PictureSurface::RenderTask(task_id) => {
-                task_id
-            }
-        }
+        (
+            self[task_id].get_texture_address(gpu_cache),
+            BatchTextures::render_target_cache(),
+        )
     }
 }
 
 pub fn resolve_image(
     request: ImageRequest,
     resource_cache: &ResourceCache,
     gpu_cache: &mut GpuCache,
     deferred_resolves: &mut Vec<DeferredResolve>,
--- a/gfx/wr/webrender/src/frame_builder.rs
+++ b/gfx/wr/webrender/src/frame_builder.rs
@@ -9,17 +9,17 @@ use clip::{ClipDataStore, ClipStore, Cli
 use clip_scroll_tree::{ClipScrollTree, ROOT_SPATIAL_NODE_INDEX, SpatialNodeIndex};
 use display_list_flattener::{DisplayListFlattener};
 use gpu_cache::{GpuCache, GpuCacheHandle};
 use gpu_types::{PrimitiveHeaders, TransformPalette, UvRectKind, ZBufferIdGenerator};
 use hit_test::{HitTester, HitTestingScene};
 #[cfg(feature = "replay")]
 use hit_test::HitTestingSceneStats;
 use internal_types::{FastHashMap, PlaneSplitter};
-use picture::{PictureSurface, PictureUpdateState, SurfaceInfo, ROOT_SURFACE_INDEX, SurfaceIndex};
+use picture::{PictureUpdateState, SurfaceInfo, ROOT_SURFACE_INDEX, SurfaceIndex};
 use picture::{RetainedTiles, TileCache, DirtyRegion};
 use prim_store::{PrimitiveStore, SpaceMapper, PictureIndex, PrimitiveDebugId, PrimitiveScratchBuffer};
 #[cfg(feature = "replay")]
 use prim_store::{PrimitiveStoreStats};
 use profiler::{FrameProfileCounters, GpuCacheProfileCounters, TextureCacheProfileCounters};
 use render_backend::{DataStores, FrameStamp};
 use render_task::{RenderTask, RenderTaskId, RenderTaskLocation, RenderTaskTree, RenderTaskTreeCounters};
 use resource_cache::{ResourceCache};
@@ -423,16 +423,34 @@ impl FrameBuilder {
             gpu_cache,
             transforms: transform_palette,
             segment_builder: SegmentBuilder::new(),
             surfaces,
             dirty_region_stack: Vec::new(),
             clip_chain_stack: ClipChainStack::new(),
         };
 
+        let root_render_task = RenderTask::new_picture(
+            RenderTaskLocation::Fixed(self.output_rect),
+            self.output_rect.size.to_f32(),
+            self.root_pic_index,
+            DeviceIntPoint::zero(),
+            Vec::new(),
+            UvRectKind::Rect,
+            root_spatial_node_index,
+            global_device_pixel_scale,
+        );
+
+        let root_render_task_id = frame_state.render_tasks.add(root_render_task);
+        frame_state
+            .surfaces
+            .first_mut()
+            .unwrap()
+            .surface = Some(root_render_task_id);
+
         // Push a default dirty region which culls primitives
         // against the screen world rect, in absence of any
         // other dirty regions.
         let mut default_dirty_region = DirtyRegion::new();
         default_dirty_region.push(
             frame_context.screen_world_rect,
         );
         frame_state.push_dirty_region(default_dirty_region);
@@ -473,34 +491,24 @@ impl FrameBuilder {
         );
 
         frame_state.pop_dirty_region();
 
         let child_tasks = frame_state
             .surfaces[ROOT_SURFACE_INDEX.0]
             .take_render_tasks();
 
-        let root_render_task = RenderTask::new_picture(
-            RenderTaskLocation::Fixed(self.output_rect),
-            self.output_rect.size.to_f32(),
-            self.root_pic_index,
-            DeviceIntPoint::zero(),
-            child_tasks,
-            UvRectKind::Rect,
-            root_spatial_node_index,
-            global_device_pixel_scale,
-        );
+        for child_task_id in child_tasks {
+            frame_state.render_tasks.add_dependency(
+                root_render_task_id,
+                child_task_id,
+            );
+        }
 
-        let render_task_id = frame_state.render_tasks.add(root_render_task);
-        frame_state
-            .surfaces
-            .first_mut()
-            .unwrap()
-            .surface = Some(PictureSurface::RenderTask(render_task_id));
-        Some(render_task_id)
+        Some(root_render_task_id)
     }
 
     pub fn build(
         &mut self,
         resource_cache: &mut ResourceCache,
         gpu_cache: &mut GpuCache,
         stamp: FrameStamp,
         clip_scroll_tree: &mut ClipScrollTree,
--- a/gfx/wr/webrender/src/picture.rs
+++ b/gfx/wr/webrender/src/picture.rs
@@ -22,17 +22,17 @@ use gpu_cache::{GpuCache, GpuCacheAddres
 use gpu_types::{TransformPalette, UvRectKind};
 use plane_split::{Clipper, Polygon, Splitter};
 use prim_store::{CoordinateSpaceMapping, SpaceMapper};
 use prim_store::{PictureIndex, PrimitiveInstance, PrimitiveInstanceKind};
 use prim_store::{get_raster_rects, PrimitiveScratchBuffer, VectorKey, PointKey};
 use prim_store::{OpacityBindingStorage, ImageInstanceStorage, OpacityBindingIndex, RectangleKey};
 use print_tree::PrintTreePrinter;
 use render_backend::DataStores;
-use render_task::{ClearMode, RenderTask, RenderTaskCacheEntryHandle, TileBlit};
+use render_task::{ClearMode, RenderTask, TileBlit};
 use render_task::{RenderTaskId, RenderTaskLocation};
 use resource_cache::ResourceCache;
 use scene::{FilterOpHelpers, SceneProperties};
 use scene_builder::Interners;
 use smallvec::SmallVec;
 use std::{mem, u16};
 use std::sync::atomic::{AtomicUsize, Ordering};
 use texture_cache::TextureCacheHandle;
@@ -1789,17 +1789,17 @@ pub struct SurfaceInfo {
     /// Helper structs for mapping local rects in different
     /// coordinate systems into the surface coordinates.
     pub map_local_to_surface: SpaceMapper<LayoutPixel, PicturePixel>,
     /// Defines the positioning node for the surface itself,
     /// and the rasterization root for this surface.
     pub raster_spatial_node_index: SpatialNodeIndex,
     pub surface_spatial_node_index: SpatialNodeIndex,
     /// This is set when the render task is created.
-    pub surface: Option<PictureSurface>,
+    pub surface: Option<RenderTaskId>,
     /// A list of render tasks that are dependencies of this surface.
     pub tasks: Vec<RenderTaskId>,
     /// How much the local surface rect should be inflated (for blur radii).
     pub inflation_factor: f32,
     /// The device pixel ratio specific to this surface.
     pub device_pixel_scale: DevicePixelScale,
     /// If true, subpixel AA rendering can be used on this surface.
     pub allow_subpixel_aa: bool,
@@ -1893,27 +1893,16 @@ pub enum PictureCompositeMode {
     /// is used for CSS isolation, and plane splitting.
     Blit(BlitReason),
     /// Used to cache a picture as a series of tiles.
     TileCache {
         clear_color: ColorF,
     },
 }
 
-// Stores the location of the picture if it is drawn to
-// an intermediate surface. This can be a render task if
-// it is not persisted, or a texture cache item if the
-// picture is cached in the texture cache.
-#[derive(Debug)]
-pub enum PictureSurface {
-    RenderTask(RenderTaskId),
-    #[allow(dead_code)]
-    TextureCache(RenderTaskCacheEntryHandle),
-}
-
 /// Enum value describing the place of a picture in a 3D context.
 #[derive(Clone, Debug)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 pub enum Picture3DContext<C> {
     /// The picture is not a part of 3D context sub-hierarchy.
     Out,
     /// The picture is a part of 3D context.
     In {
@@ -2492,24 +2481,24 @@ impl PicturePrimitive {
     }
 
     /// Add a primitive instance to the plane splitter. The function would generate
     /// an appropriate polygon, clip it against the frustum, and register with the
     /// given plane splitter.
     pub fn add_split_plane(
         splitter: &mut PlaneSplitter,
         transforms: &TransformPalette,
-        prim_instance: &PrimitiveInstance,
+        prim_spatial_node_index: SpatialNodeIndex,
         original_local_rect: LayoutRect,
         combined_local_clip_rect: &LayoutRect,
         world_rect: WorldRect,
         plane_split_anchor: usize,
     ) -> bool {
         let transform = transforms
-            .get_world_transform(prim_instance.spatial_node_index);
+            .get_world_transform(prim_spatial_node_index);
         let matrix = transform.cast();
 
         // Apply the local clip rect here, before splitting. This is
         // because the local clip rect can't be applied in the vertex
         // shader for split composites, since we are drawing polygons
         // rather that rectangles. The interpolation still works correctly
         // since we determine the UVs by doing a bilerp with a factor
         // from the original local rect.
@@ -2518,17 +2507,17 @@ impl PicturePrimitive {
         {
             Some(rect) => rect.cast(),
             None => return false,
         };
         let world_rect = world_rect.cast();
 
         if transform.is_simple_translation() {
             let inv_transform = transforms
-                .get_world_inv_transform(prim_instance.spatial_node_index);
+                .get_world_inv_transform(prim_spatial_node_index);
             let polygon = Polygon::from_transformed_rect_with_inverse(
                 local_rect,
                 &matrix,
                 &inv_transform.cast(),
                 plane_split_anchor,
             ).unwrap();
             splitter.add(polygon);
         } else {
@@ -2881,17 +2870,16 @@ impl PicturePrimitive {
                 parent_surface.rect = parent_surface.rect.union(&parent_surface_rect);
             }
         }
     }
 
     pub fn prepare_for_render(
         &mut self,
         pic_index: PictureIndex,
-        prim_instance: &PrimitiveInstance,
         clipped_prim_bounding_rect: WorldRect,
         surface_index: SurfaceIndex,
         frame_context: &FrameBuildingContext,
         frame_state: &mut FrameBuildingState,
         data_stores: &mut DataStores,
     ) -> bool {
         let (mut pic_state_for_children, pic_context) = self.take_state_and_context();
 
@@ -2911,17 +2899,17 @@ impl PicturePrimitive {
             (
                 surface_info.raster_spatial_node_index,
                 surface_info.take_render_tasks(),
                 surface_info.device_pixel_scale,
             )
         };
 
         let (map_raster_to_world, map_pic_to_raster) = create_raster_mappers(
-            prim_instance.spatial_node_index,
+            self.spatial_node_index,
             raster_spatial_node_index,
             frame_context.screen_world_rect,
             frame_context.clip_scroll_tree,
         );
 
         let pic_rect = PictureRect::from_untyped(&self.local_rect.to_untyped());
 
         let (clipped, unclipped) = match get_raster_rects(
@@ -3010,17 +2998,17 @@ impl PicturePrimitive {
                     RenderTargetKind::Color,
                     ClearMode::Transparent,
                 );
 
                 let render_task_id = frame_state.render_tasks.add(blur_render_task);
 
                 frame_state.surfaces[surface_index.0].tasks.push(render_task_id);
 
-                PictureSurface::RenderTask(render_task_id)
+                render_task_id
             }
             PictureCompositeMode::Filter(FilterOp::DropShadow(offset, blur_radius, color)) => {
                 let blur_std_deviation = blur_radius * device_pixel_scale.0;
                 let blur_range = (blur_std_deviation * BLUR_SAMPLE_SCALE).ceil() as i32;
                 let rounded_std_dev = blur_std_deviation.round();
                 let rounded_std_dev = DeviceSize::new(rounded_std_dev, rounded_std_dev);
                 // The clipped field is the part of the picture that is visible
                 // on screen. The unclipped field is the screen-space rect of
@@ -3096,17 +3084,17 @@ impl PicturePrimitive {
                         0.0,
                     ]);
 
                     // segment rect / extra data
                     request.push(shadow_rect);
                     request.push([0.0, 0.0, 0.0, 0.0]);
                 }
 
-                PictureSurface::RenderTask(render_task_id)
+                render_task_id
             }
             PictureCompositeMode::MixBlend(..) if !frame_context.fb_config.gpu_supports_advanced_blend => {
                 let uv_rect_kind = calculate_uv_rect_kind(
                     &pic_rect,
                     &transform,
                     &clipped,
                     device_pixel_scale,
                     true,
@@ -3127,17 +3115,17 @@ impl PicturePrimitive {
                     RenderTask::new_readback(clipped)
                 );
 
                 self.secondary_render_task_id = Some(readback_task_id);
                 frame_state.surfaces[surface_index.0].tasks.push(readback_task_id);
 
                 let render_task_id = frame_state.render_tasks.add(picture_task);
                 frame_state.surfaces[surface_index.0].tasks.push(render_task_id);
-                PictureSurface::RenderTask(render_task_id)
+                render_task_id
             }
             PictureCompositeMode::Filter(ref filter) => {
                 if let FilterOp::ColorMatrix(m) = *filter {
                     if let Some(mut request) = frame_state.gpu_cache.request(&mut self.extra_gpu_data_handle) {
                         for i in 0..5 {
                             request.push([m[i*4], m[i*4+1], m[i*4+2], m[i*4+3]]);
                         }
                     }
@@ -3159,17 +3147,17 @@ impl PicturePrimitive {
                     child_tasks,
                     uv_rect_kind,
                     pic_context.raster_spatial_node_index,
                     device_pixel_scale,
                 );
 
                 let render_task_id = frame_state.render_tasks.add(picture_task);
                 frame_state.surfaces[surface_index.0].tasks.push(render_task_id);
-                PictureSurface::RenderTask(render_task_id)
+                render_task_id
             }
             PictureCompositeMode::ComponentTransferFilter(handle) => {
                 let filter_data = &mut data_stores.filter_data[handle];
                 filter_data.update(frame_state);
 
                 let uv_rect_kind = calculate_uv_rect_kind(
                     &pic_rect,
                     &transform,
@@ -3186,17 +3174,17 @@ impl PicturePrimitive {
                     child_tasks,
                     uv_rect_kind,
                     pic_context.raster_spatial_node_index,
                     device_pixel_scale,
                 );
 
                 let render_task_id = frame_state.render_tasks.add(picture_task);
                 frame_state.surfaces[surface_index.0].tasks.push(render_task_id);
-                PictureSurface::RenderTask(render_task_id)
+                render_task_id
             }
             PictureCompositeMode::MixBlend(..) |
             PictureCompositeMode::Blit(_) => {
                 // The SplitComposite shader used for 3d contexts doesn't snap
                 // to pixels, so we shouldn't snap our uv coordinates either.
                 let supports_snapping = match self.context_3d {
                     Picture3DContext::In{ .. } => false,
                     _ => true,
@@ -3218,17 +3206,17 @@ impl PicturePrimitive {
                     child_tasks,
                     uv_rect_kind,
                     pic_context.raster_spatial_node_index,
                     device_pixel_scale,
                 );
 
                 let render_task_id = frame_state.render_tasks.add(picture_task);
                 frame_state.surfaces[surface_index.0].tasks.push(render_task_id);
-                PictureSurface::RenderTask(render_task_id)
+                render_task_id
             }
         };
 
         frame_state.surfaces[raster_config.surface_index.0].surface = Some(surface);
 
         true
     }
 }
--- a/gfx/wr/webrender/src/prim_store/mod.rs
+++ b/gfx/wr/webrender/src/prim_store/mod.rs
@@ -2437,88 +2437,26 @@ impl PrimitiveStore {
             }
         }
 
         #[cfg(debug_assertions)]
         {
             prim_instance.prepared_frame_id = frame_state.render_tasks.frame_id();
         }
 
-        match prim_instance.kind {
-            PrimitiveInstanceKind::Picture { pic_index, segment_instance_index, .. } => {
-                let pic = &mut self.pictures[pic_index.0];
-                let prim_info = &scratch.prim_info[prim_instance.visibility_info.0 as usize];
-                if pic.prepare_for_render(
-                    pic_index,
-                    prim_instance,
-                    prim_info.clipped_world_rect,
-                    pic_context.surface_index,
-                    frame_context,
-                    frame_state,
-                    data_stores,
-                ) {
-                    if let Some(ref mut splitter) = pic_state.plane_splitter {
-                        PicturePrimitive::add_split_plane(
-                            splitter,
-                            frame_state.transforms,
-                            prim_instance,
-                            pic.local_rect,
-                            &prim_info.combined_local_clip_rect,
-                            frame_context.screen_world_rect,
-                            plane_split_anchor,
-                        );
-                    }
-
-                    // If this picture uses segments, ensure the GPU cache is
-                    // up to date with segment local rects.
-                    // TODO(gw): This entire match statement above can now be
-                    //           refactored into prepare_interned_prim_for_render.
-                    if pic.can_use_segments() {
-                        write_segment(
-                            segment_instance_index,
-                            frame_state,
-                            &mut scratch.segments,
-                            &mut scratch.segment_instances,
-                            |request| {
-                                request.push(PremultipliedColorF::WHITE);
-                                request.push(PremultipliedColorF::WHITE);
-                                request.push([
-                                    -1.0,       // -ve means use prim rect for stretch size
-                                    0.0,
-                                    0.0,
-                                    0.0,
-                                ]);
-                            }
-                        );
-                    }
-                } else {
-                    prim_instance.visibility_info = PrimitiveVisibilityIndex::INVALID;
-                }
-            }
-            PrimitiveInstanceKind::TextRun { .. } |
-            PrimitiveInstanceKind::Clear { .. } |
-            PrimitiveInstanceKind::Rectangle { .. } |
-            PrimitiveInstanceKind::NormalBorder { .. } |
-            PrimitiveInstanceKind::ImageBorder { .. } |
-            PrimitiveInstanceKind::YuvImage { .. } |
-            PrimitiveInstanceKind::Image { .. } |
-            PrimitiveInstanceKind::LinearGradient { .. } |
-            PrimitiveInstanceKind::RadialGradient { .. } |
-            PrimitiveInstanceKind::LineDecoration { .. } => {
-                self.prepare_interned_prim_for_render(
-                    prim_instance,
-                    pic_context,
-                    pic_state,
-                    frame_context,
-                    frame_state,
-                    data_stores,
-                    scratch,
-                );
-            }
-        }
+        self.prepare_interned_prim_for_render(
+            prim_instance,
+            plane_split_anchor,
+            pic_context,
+            pic_state,
+            frame_context,
+            frame_state,
+            data_stores,
+            scratch,
+        );
 
         true
     }
 
     pub fn prepare_primitives(
         &mut self,
         prim_list: &mut PrimitiveList,
         pic_context: &PictureContext,
@@ -2597,18 +2535,19 @@ impl PrimitiveStore {
     }
 
     /// Prepare an interned primitive for rendering, by requesting
     /// resources, render tasks etc. This is equivalent to the
     /// prepare_prim_for_render_inner call for old style primitives.
     fn prepare_interned_prim_for_render(
         &mut self,
         prim_instance: &mut PrimitiveInstance,
+        plane_split_anchor: usize,
         pic_context: &PictureContext,
-        pic_state: &PictureState,
+        pic_state: &mut PictureState,
         frame_context: &FrameBuildingContext,
         frame_state: &mut FrameBuildingState,
         data_stores: &mut DataStores,
         scratch: &mut PrimitiveScratchBuffer,
     ) {
         let is_chased = prim_instance.is_chased();
         let device_pixel_scale = frame_state.surfaces[pic_context.surface_index.0].device_pixel_scale;
 
@@ -2988,18 +2927,64 @@ impl PrimitiveStore {
                     if visible_tiles_range.is_empty() {
                         prim_instance.visibility_info = PrimitiveVisibilityIndex::INVALID;
                     }
                 }
 
                 // TODO(gw): Consider whether it's worth doing segment building
                 //           for gradient primitives.
             }
-            _ => {
-                unreachable!();
+            PrimitiveInstanceKind::Picture { pic_index, segment_instance_index, .. } => {
+                let pic = &mut self.pictures[pic_index.0];
+                let prim_info = &scratch.prim_info[prim_instance.visibility_info.0 as usize];
+                if pic.prepare_for_render(
+                    *pic_index,
+                    prim_info.clipped_world_rect,
+                    pic_context.surface_index,
+                    frame_context,
+                    frame_state,
+                    data_stores,
+                ) {
+                    if let Some(ref mut splitter) = pic_state.plane_splitter {
+                        PicturePrimitive::add_split_plane(
+                            splitter,
+                            frame_state.transforms,
+                            prim_instance.spatial_node_index,
+                            pic.local_rect,
+                            &prim_info.combined_local_clip_rect,
+                            frame_context.screen_world_rect,
+                            plane_split_anchor,
+                        );
+                    }
+
+                    // If this picture uses segments, ensure the GPU cache is
+                    // up to date with segment local rects.
+                    // TODO(gw): This entire match statement above can now be
+                    //           refactored into prepare_interned_prim_for_render.
+                    if pic.can_use_segments() {
+                        write_segment(
+                            *segment_instance_index,
+                            frame_state,
+                            &mut scratch.segments,
+                            &mut scratch.segment_instances,
+                            |request| {
+                                request.push(PremultipliedColorF::WHITE);
+                                request.push(PremultipliedColorF::WHITE);
+                                request.push([
+                                    -1.0,       // -ve means use prim rect for stretch size
+                                    0.0,
+                                    0.0,
+                                    0.0,
+                                ]);
+                            }
+                        );
+                    }
+                } else {
+                    prim_instance.visibility_info = PrimitiveVisibilityIndex::INVALID;
+                }
             }
         };
     }
 }
 
 fn write_segment<F>(
     segment_instance_index: SegmentInstanceIndex,
     frame_state: &mut FrameBuildingState,
--- a/gfx/wr/webrender/src/render_task.rs
+++ b/gfx/wr/webrender/src/render_task.rs
@@ -134,16 +134,27 @@ impl RenderTaskTree {
         self.tasks.push(task);
         RenderTaskId {
             index,
             #[cfg(debug_assertions)]
             frame_id: self.frame_id,
         }
     }
 
+    /// Express a render task dependency between a parent and child task.
+    /// This is used to assign tasks to render passes.
+    pub fn add_dependency(
+        &mut self,
+        parent_id: RenderTaskId,
+        child_id: RenderTaskId,
+    ) {
+        let parent = &mut self[parent_id];
+        parent.children.push(child_id);
+    }
+
     /// Assign this frame's render tasks to render passes ordered so that passes appear
     /// earlier than the ones that depend on them.
     pub fn generate_passes(
         &self,
         main_render_task: Option<RenderTaskId>,
         screen_size: DeviceIntSize,
         gpu_supports_fast_clears: bool,
     ) -> Vec<RenderPass> {
--- a/mobile/android/base/java/org/mozilla/gecko/icons/IconTask.java
+++ b/mobile/android/base/java/org/mozilla/gecko/icons/IconTask.java
@@ -146,34 +146,34 @@ import java.util.concurrent.Callable;
 
             processor.process(request, response);
 
             logProcessor(processor);
         }
     }
 
     private void handleException(final Throwable t) {
-        if (AppConstants.NIGHTLY_BUILD) {
+        if (AppConstants.NIGHTLY_BUILD || AppConstants.FENNEC_NIGHTLY) {
             // We want to be aware of problems: Let's re-throw the exception on the main thread to
             // force an app crash. However we only do this in Nightly builds. Every other build
             // (especially release builds) should just carry on and log the error.
             ThreadUtils.postToUiThread(new Runnable() {
                 @Override
                 public void run() {
                     throw new RuntimeException("Icon task thread crashed", t);
                 }
             });
         } else {
             Log.e(LOGTAG, "Icon task crashed", t);
         }
     }
 
     private boolean shouldLog() {
         // Do not log anything if debugging is disabled and never log anything in a non-nightly build.
-        return DEBUG && AppConstants.NIGHTLY_BUILD;
+        return DEBUG && (AppConstants.NIGHTLY_BUILD || AppConstants.FENNEC_NIGHTLY);
     }
 
     private void logPreparer(IconRequest request, Preparer preparer) {
         if (!shouldLog()) {
             return;
         }
 
         Log.d(LOGTAG, String.format("  PREPARE %s" + " (%s)",
--- a/mobile/android/base/java/org/mozilla/gecko/media/MediaControlService.java
+++ b/mobile/android/base/java/org/mozilla/gecko/media/MediaControlService.java
@@ -35,19 +35,19 @@ public class MediaControlService extends
     }
 
     @Override
     public int onStartCommand(Intent intent, int flags, int startId) {
         Log.d(LOGTAG, "onStartCommand");
 
         if (intent.hasExtra(GeckoMediaControlAgent.EXTRA_NOTIFICATION_DATA)) {
             if (GeckoMediaControlAgent.getInstance().isAttachedToContext() ||
-                    /* bug 1516665 - If we are not attached to context but the build is not release or beta continue
+                    /* bug 1516665 - If we are not attached to context but the build is a Nightly, continue
                     in order to gather more information */
-                    !AppConstants.RELEASE_OR_BETA) {
+                    AppConstants.FENNEC_NIGHTLY) {
                     currentNotification = GeckoMediaControlAgent.getInstance().createNotification(
                             (MediaNotification) intent.getParcelableExtra(GeckoMediaControlAgent.EXTRA_NOTIFICATION_DATA));
             } else {
                 intent.setAction(GeckoMediaControlAgent.ACTION_SHUTDOWN);
             }
         }
 
         startForeground(R.id.mediaControlNotification, currentNotification);
--- a/mobile/android/chrome/content/about.xhtml
+++ b/mobile/android/chrome/content/about.xhtml
@@ -52,25 +52,29 @@
 
     <ul id="aboutLinks">
       <div class="top-border"></div>
       <li><a id="faqURL">&aboutPage.faq.label;</a></li>
       <li><a id="supportURL">&aboutPage.support.label;</a></li>
       <li><a id="privacyURL">&aboutPage.privacyPolicy.label;</a></li>
       <li><a href="about:rights">&aboutPage.rights.label;</a></li>
 #ifndef NIGHTLY_BUILD
+#ifndef FENNEC_NIGHTLY
       <li><a id="releaseNotesURL">&aboutPage.relNotes.label;</a></li>
 #endif
+#endif
       <li><a id="creditsURL">&aboutPage.credits.label;</a></li>
       <li><a href="about:license">&aboutPage.license.label;</a></li>
       <div class="bottom-border"></div>
     </ul>
 
 #ifdef RELEASE_OR_BETA
+#ifndef FENNEC_NIGHTLY
     <div id="aboutDetails">
       <p>&aboutPage.logoTrademark;</p>
     </div>
 #endif
+#endif
 
     <script type="application/javascript" src="chrome://browser/content/about.js" />
 
 </body>
 </html>
--- a/mobile/android/installer/Makefile.in
+++ b/mobile/android/installer/Makefile.in
@@ -62,20 +62,22 @@ MOZ_PACKAGER_MINIFY=1
 include $(topsrcdir)/toolkit/mozapps/installer/packager.mk
 
 # Note that JS_BINARY can be defined in packager.mk, so this test must come
 # after including that file. MOZ_PACKAGER_MINIFY_JS is used in packager.mk, but
 # since recipe evaluation is deferred, we can set it here after the inclusion.
 ifneq (,$(JS_BINARY))
 ifndef MOZ_DEBUG
 ifndef NIGHTLY_BUILD
+ifndef FENNEC_NIGHTLY
 MOZ_PACKAGER_MINIFY_JS=1
 endif
 endif
 endif
+endif
 
 ifeq (bundle, $(MOZ_FS_LAYOUT))
 BINPATH = $(_BINPATH)
 DEFINES += -DAPPNAME=$(_APPNAME)
 else
 # Every other platform just winds up in dist/bin
 BINPATH = bin
 endif
--- a/old-configure.in
+++ b/old-configure.in
@@ -3117,17 +3117,17 @@ fi
 AC_SUBST(MOZ_SOURCE_REPO)
 AC_SUBST(MOZ_SOURCE_CHANGESET)
 AC_SUBST(MOZ_INCLUDE_SOURCE_INFO)
 
 if test "$MOZ_TELEMETRY_REPORTING"; then
     AC_DEFINE(MOZ_TELEMETRY_REPORTING)
 
     # Enable Telemetry by default for nightly and aurora channels
-    if test -z "$RELEASE_OR_BETA"; then
+    if test -z "$RELEASE_OR_BETA" || test -n "$FENNEC_NIGHTLY"; then
       AC_DEFINE(MOZ_TELEMETRY_ON_BY_DEFAULT)
     fi
 fi
 
 dnl If we have any service that uploads data (and requires data submission
 dnl policy alert), set MOZ_DATA_REPORTING.
 dnl We need SUBST for build system and DEFINE for xul preprocessor.
 if test -n "$MOZ_TELEMETRY_REPORTING" || test -n "$MOZ_SERVICES_HEALTHREPORT" || test -n "$MOZ_CRASHREPORTER"; then
--- a/parser/expat/lib/xmlparse.c
+++ b/parser/expat/lib/xmlparse.c
@@ -1760,26 +1760,26 @@ XML_SetElementDeclHandler(XML_Parser par
 
 void XMLCALL
 XML_SetAttlistDeclHandler(XML_Parser parser,
                           XML_AttlistDeclHandler attdecl)
 {
   if (parser != NULL)
     attlistDeclHandler = attdecl;
 }
-#endif
-/* END MOZILLA CHANGE */
 
 void XMLCALL
 XML_SetEntityDeclHandler(XML_Parser parser,
                          XML_EntityDeclHandler handler)
 {
   if (parser != NULL)
     entityDeclHandler = handler;
 }
+#endif
+/* END MOZILLA CHANGE */
 
 void XMLCALL
 XML_SetXmlDeclHandler(XML_Parser parser,
                       XML_XmlDeclHandler handler) {
   if (parser != NULL)
     xmlDeclHandler = handler;
 }
 
--- a/parser/htmlparser/nsExpatDriver.cpp
+++ b/parser/htmlparser/nsExpatDriver.cpp
@@ -149,28 +149,16 @@ static int Driver_HandleExternalEntityRe
 
   nsExpatDriver* driver =
       static_cast<nsExpatDriver*>(aExternalEntityRefHandler);
 
   return driver->HandleExternalEntityRef(aOpenEntityNames, aBase, aSystemId,
                                          aPublicId);
 }
 
-static void Driver_HandleEntityDecl(
-    void* aUserData, const XML_Char* aEntityName, int aIsParameterEntity,
-    const XML_Char* aValue, int aValueLength, const XML_Char* aBase,
-    const XML_Char* aSystemId, const XML_Char* aPublicId,
-    const XML_Char* aNotationName) {
-  NS_ASSERTION(aUserData, "expat driver should exist");
-  if (aUserData) {
-    static_cast<nsExpatDriver*>(aUserData)->HandleEntityDecl(
-        aEntityName, aValue, aValueLength);
-  }
-}
-
 /***************************** END CALL BACKS ********************************/
 
 /***************************** CATALOG UTILS *********************************/
 
 // Initially added for bug 113400 to switch from the remote "XHTML 1.0 plus
 // MathML 2.0" DTD to the the lightweight customized version that Mozilla uses.
 // Since Mozilla is not validating, no need to fetch a *huge* file at each
 // click.
@@ -481,29 +469,16 @@ nsresult nsExpatDriver::HandleEndDoctype
     MaybeStopParser(rv);
   }
 
   mInternalSubset.Truncate();
 
   return NS_OK;
 }
 
-void nsExpatDriver::HandleEntityDecl(const char16_t* aEntityName,
-                                     const char16_t* aEntityValue,
-                                     const uint32_t aLength) {
-  MOZ_ASSERT(
-      mInInternalSubset || mInExternalDTD,
-      "Should only see entity declarations in the internal subset or in DTDs");
-  auto charLength = aLength / sizeof(char16_t);
-  nsDependentSubstring entityVal(aEntityValue, charLength);
-  if (entityVal.FindChar('<') != -1) {
-    MaybeStopParser(NS_ERROR_UNEXPECTED);
-  }
-}
-
 static nsresult ExternalDTDStreamReaderFunc(nsIUnicharInputStream* aIn,
                                             void* aClosure,
                                             const char16_t* aFromSegment,
                                             uint32_t aToOffset, uint32_t aCount,
                                             uint32_t* aWriteCount) {
   // Pass the buffer to expat for parsing.
   if (XML_Parse((XML_Parser)aClosure, (const char*)aFromSegment,
                 aCount * sizeof(char16_t), 0) == XML_STATUS_OK) {
@@ -1077,19 +1052,16 @@ nsExpatDriver::WillBuildModel(const CPar
       (XML_ExternalEntityRefHandler)Driver_HandleExternalEntityRef);
   XML_SetExternalEntityRefHandlerArg(mExpatParser, this);
   XML_SetCommentHandler(mExpatParser, Driver_HandleComment);
   XML_SetCdataSectionHandler(mExpatParser, Driver_HandleStartCdataSection,
                              Driver_HandleEndCdataSection);
 
   XML_SetParamEntityParsing(mExpatParser,
                             XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE);
-  if (doc && doc->NodePrincipal()->IsSystemPrincipal()) {
-    XML_SetEntityDeclHandler(mExpatParser, Driver_HandleEntityDecl);
-  }
   XML_SetDoctypeDeclHandler(mExpatParser, Driver_HandleStartDoctypeDecl,
                             Driver_HandleEndDoctypeDecl);
 
   // Set up the user data.
   XML_SetUserData(mExpatParser, this);
 
   return mInternalState;
 }
--- a/parser/htmlparser/nsExpatDriver.h
+++ b/parser/htmlparser/nsExpatDriver.h
@@ -44,18 +44,16 @@ class nsExpatDriver : public nsIDTD, pub
   nsresult HandleDefault(const char16_t* aData, const uint32_t aLength);
   nsresult HandleStartCdataSection();
   nsresult HandleEndCdataSection();
   nsresult HandleStartDoctypeDecl(const char16_t* aDoctypeName,
                                   const char16_t* aSysid,
                                   const char16_t* aPubid,
                                   bool aHasInternalSubset);
   nsresult HandleEndDoctypeDecl();
-  void HandleEntityDecl(const char16_t* aEntityName,
-                        const char16_t* aEntityValue, const uint32_t aLength);
 
  private:
   // Load up an external stream to get external entity information
   nsresult OpenInputStreamFromExternalDTD(const char16_t* aFPIStr,
                                           const char16_t* aURLStr,
                                           const char16_t* aBaseURL,
                                           nsIInputStream** aStream,
                                           nsAString& aAbsURL);
--- a/security/manager/ssl/ContentSignatureVerifier.cpp
+++ b/security/manager/ssl/ContentSignatureVerifier.cpp
@@ -2,79 +2,148 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ContentSignatureVerifier.h"
 
 #include "BRNameMatchingPolicy.h"
+#include "CryptoTask.h"
 #include "ScopedNSSTypes.h"
 #include "SharedCertVerifier.h"
 #include "cryptohi.h"
 #include "keyhi.h"
 #include "mozilla/Base64.h"
 #include "mozilla/Unused.h"
+#include "mozilla/dom/Promise.h"
 #include "nsCOMPtr.h"
 #include "nsPromiseFlatString.h"
 #include "nsSecurityHeaderParser.h"
 #include "nsWhitespaceTokenizer.h"
 #include "mozpkix/pkix.h"
 #include "mozpkix/pkixtypes.h"
 #include "secerr.h"
 
 NS_IMPL_ISUPPORTS(ContentSignatureVerifier, nsIContentSignatureVerifier)
 
 using namespace mozilla;
 using namespace mozilla::pkix;
 using namespace mozilla::psm;
+using dom::Promise;
 
 static LazyLogModule gCSVerifierPRLog("ContentSignatureVerifier");
 #define CSVerifier_LOG(args) MOZ_LOG(gCSVerifierPRLog, LogLevel::Debug, args)
 
 // Content-Signature prefix
 const unsigned char kPREFIX[] = {'C', 'o', 'n', 't', 'e', 'n', 't',
                                  '-', 'S', 'i', 'g', 'n', 'a', 't',
                                  'u', 'r', 'e', ':', 0};
 
+class VerifyContentSignatureTask : public CryptoTask {
+ public:
+  VerifyContentSignatureTask(const nsACString& aData,
+                             const nsACString& aCSHeader,
+                             const nsACString& aCertChain,
+                             const nsACString& aHostname,
+                             RefPtr<Promise>& aPromise)
+      : mData(aData),
+        mCSHeader(aCSHeader),
+        mCertChain(aCertChain),
+        mHostname(aHostname),
+        mSignatureVerified(false),
+        mPromise(aPromise) {}
+
+ private:
+  virtual nsresult CalculateResult() override;
+  virtual void CallCallback(nsresult rv) override;
+
+  nsCString mData;
+  nsCString mCSHeader;
+  nsCString mCertChain;
+  nsCString mHostname;
+  bool mSignatureVerified;
+  RefPtr<Promise> mPromise;
+};
+
 NS_IMETHODIMP
-ContentSignatureVerifier::VerifyContentSignature(const nsACString& aData,
-                                                 const nsACString& aCSHeader,
-                                                 const nsACString& aCertChain,
-                                                 const nsACString& aHostname,
-                                                 bool* _retval) {
-  NS_ENSURE_ARG(_retval);
-  *_retval = false;
+ContentSignatureVerifier::AsyncVerifyContentSignature(
+    const nsACString& aData, const nsACString& aCSHeader,
+    const nsACString& aCertChain, const nsACString& aHostname, JSContext* aCx,
+    Promise** aPromise) {
+  NS_ENSURE_ARG_POINTER(aCx);
+
+  nsIGlobalObject* globalObject = xpc::CurrentNativeGlobal(aCx);
+  if (NS_WARN_IF(!globalObject)) {
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  ErrorResult result;
+  RefPtr<Promise> promise = Promise::Create(globalObject, result);
+  if (NS_WARN_IF(result.Failed())) {
+    return result.StealNSResult();
+  }
 
+  RefPtr<VerifyContentSignatureTask> task(new VerifyContentSignatureTask(
+      aData, aCSHeader, aCertChain, aHostname, promise));
+  nsresult rv = task->Dispatch("ContentSig");
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  promise.forget(aPromise);
+  return NS_OK;
+}
+
+static nsresult VerifyContentSignatureInternal(
+    const nsACString& aData, const nsACString& aCSHeader,
+    const nsACString& aCertChain, const nsACString& aHostname,
+    /* out */
+    mozilla::Telemetry::LABELS_CONTENT_SIGNATURE_VERIFICATION_ERRORS&
+        aErrorLabel,
+    /* out */ nsACString& aCertFingerprint, /* out */ uint32_t& aErrorValue);
+static nsresult ParseContentSignatureHeader(
+    const nsACString& aContentSignatureHeader,
+    /* out */ nsCString& aSignature);
+
+nsresult VerifyContentSignatureTask::CalculateResult() {
   // 3 is the default, non-specific, "something failed" error.
   Telemetry::LABELS_CONTENT_SIGNATURE_VERIFICATION_ERRORS errorLabel =
       Telemetry::LABELS_CONTENT_SIGNATURE_VERIFICATION_ERRORS::err3;
   nsAutoCString certFingerprint;
   uint32_t errorValue = 3;
   nsresult rv =
-      VerifyContentSignatureInternal(aData, aCSHeader, aCertChain, aHostname,
+      VerifyContentSignatureInternal(mData, mCSHeader, mCertChain, mHostname,
                                      errorLabel, certFingerprint, errorValue);
   if (NS_FAILED(rv)) {
     CSVerifier_LOG(("CSVerifier: Signature verification failed"));
     if (certFingerprint.Length() > 0) {
       Telemetry::AccumulateCategoricalKeyed(certFingerprint, errorLabel);
     }
     Accumulate(Telemetry::CONTENT_SIGNATURE_VERIFICATION_STATUS, errorValue);
     if (rv == NS_ERROR_INVALID_SIGNATURE) {
       return NS_OK;
     }
     return rv;
   }
 
-  *_retval = true;
+  mSignatureVerified = true;
   Accumulate(Telemetry::CONTENT_SIGNATURE_VERIFICATION_STATUS, 0);
 
   return NS_OK;
 }
 
+void VerifyContentSignatureTask::CallCallback(nsresult rv) {
+  if (NS_FAILED(rv)) {
+    mPromise->MaybeReject(rv);
+  } else {
+    mPromise->MaybeResolve(mSignatureVerified);
+  }
+}
+
 bool IsNewLine(char16_t c) { return c == '\n' || c == '\r'; }
 
 nsresult ReadChainIntoCertList(const nsACString& aCertChain,
                                CERTCertList* aCertList) {
   bool inBlock = false;
   bool certFound = false;
 
   const nsCString header = NS_LITERAL_CSTRING("-----BEGIN CERTIFICATE-----");
@@ -133,17 +202,17 @@ nsresult ReadChainIntoCertList(const nsA
 
 // Given data to verify, a content signature header value, a string representing
 // a list of PEM-encoded certificates, and a hostname to validate the
 // certificates against, this function attempts to validate the certificate
 // chain, extract the signature from the header, and verify the data using the
 // key in the end-entity certificate from the chain. Returns NS_OK if everything
 // is satisfactory and a failing nsresult otherwise. The output parameters are
 // filled with telemetry data to report in the case of failures.
-nsresult ContentSignatureVerifier::VerifyContentSignatureInternal(
+static nsresult VerifyContentSignatureInternal(
     const nsACString& aData, const nsACString& aCSHeader,
     const nsACString& aCertChain, const nsACString& aHostname,
     /* out */
     Telemetry::LABELS_CONTENT_SIGNATURE_VERIFICATION_ERRORS& aErrorLabel,
     /* out */ nsACString& aCertFingerprint,
     /* out */ uint32_t& aErrorValue) {
   UniqueCERTCertList certCertList(CERT_NewCertList());
   if (!certCertList) {
@@ -311,17 +380,17 @@ nsresult ContentSignatureVerifier::Verif
     aErrorLabel = Telemetry::LABELS_CONTENT_SIGNATURE_VERIFICATION_ERRORS::err1;
     aErrorValue = 1;
     return NS_ERROR_INVALID_SIGNATURE;
   }
 
   return NS_OK;
 }
 
-nsresult ContentSignatureVerifier::ParseContentSignatureHeader(
+static nsresult ParseContentSignatureHeader(
     const nsACString& aContentSignatureHeader,
     /* out */ nsCString& aSignature) {
   // We only support p384 ecdsa.
   NS_NAMED_LITERAL_CSTRING(signature_var, "p384ecdsa");
 
   aSignature.Truncate();
 
   const nsCString& flatHeader = PromiseFlatCString(aContentSignatureHeader);
--- a/security/manager/ssl/ContentSignatureVerifier.h
+++ b/security/manager/ssl/ContentSignatureVerifier.h
@@ -22,22 +22,11 @@
 
 class ContentSignatureVerifier final : public nsIContentSignatureVerifier {
  public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSICONTENTSIGNATUREVERIFIER
 
  private:
   ~ContentSignatureVerifier() = default;
-
-  nsresult VerifyContentSignatureInternal(
-      const nsACString& aData, const nsACString& aCSHeader,
-      const nsACString& aCertChain, const nsACString& aHostname,
-      /* out */
-      mozilla::Telemetry::LABELS_CONTENT_SIGNATURE_VERIFICATION_ERRORS&
-          aErrorLabel,
-      /* out */ nsACString& aCertFingerprint, /* out */ uint32_t& aErrorValue);
-  nsresult ParseContentSignatureHeader(
-      const nsACString& aContentSignatureHeader,
-      /* out */ nsCString& aSignature);
 };
 
 #endif  // ContentSignatureVerifier_h
--- a/security/manager/ssl/nsIContentSignatureVerifier.idl
+++ b/security/manager/ssl/nsIContentSignatureVerifier.idl
@@ -22,17 +22,18 @@ interface nsIContentSignatureVerifier : 
    *
    * @param aData                   The data to be tested.
    * @param aContentSignatureHeader The content-signature header,
    *                                url-safe base64 encoded.
    * @param aCertificateChain       The certificate chain to use for verification.
    *                                PEM encoded string.
    * @param aHostname               The hostname for which the end entity must
                                     be valid.
-   * @returns true if the signature matches the data and aCertificateChain is
-   *          valid within aContext, false if not.
+   * @returns Promise that resolves with the value true if the signature
+   *          matches the data and aCertificateChain is valid within aContext,
+   *          and false if not. Rejects if another error occurred.
    */
-  [must_use]
-  boolean verifyContentSignature(in ACString aData,
-                                 in ACString aContentSignatureHeader,
-                                 in ACString aCertificateChain,
-                                 in ACString aHostname);
+  [implicit_jscontext, must_use]
+  Promise asyncVerifyContentSignature(in ACString aData,
+                                      in ACString aContentSignatureHeader,
+                                      in ACString aCertificateChain,
+                                      in ACString aHostname);
 };
--- a/security/manager/ssl/tests/unit/test_content_signing.js
+++ b/security/manager/ssl/tests/unit/test_content_signing.js
@@ -58,17 +58,17 @@ function check_telemetry(expected_index,
     equal(VERIFICATION_HISTOGRAM.snapshot().values[i] || 0, expected_value,
       "count " + i + ": " + VERIFICATION_HISTOGRAM.snapshot().values[i] +
       " expected " + expected_value);
   }
   VERIFICATION_HISTOGRAM.clear();
   ERROR_HISTOGRAM.clear();
 }
 
-function run_test() {
+add_task(async function run_test() {
   // set up some data
   const DATA = readFile(do_get_file(TEST_DATA_DIR + "test.txt"));
   const GOOD_SIGNATURE = "p384ecdsa=" +
       readFile(do_get_file(TEST_DATA_DIR + "test.txt.signature"))
       .trim();
 
   const BAD_SIGNATURE = "p384ecdsa=WqRXFQ7tnlVufpg7A-ZavXvWd2Zln0o4woHBy26C2r" +
                         "UWM4GJke4pE8ecHiXoi-7KnZXty6Pe3s4o3yAIyKDP9jUC52Ek1G" +
@@ -92,123 +92,123 @@ function run_test() {
   let notValidYetOneCRLChain = loadChain(TEST_DATA_DIR + "content_signing",
                                          ["onecrl_ee_not_valid_yet", "int",
                                           "root"]);
 
   // Check signature verification works without error before the root is set
   VERIFICATION_HISTOGRAM.clear();
   let chain1 = oneCRLChain.join("\n");
   let verifier = getSignatureVerifier();
-  ok(!verifier.verifyContentSignature(DATA, GOOD_SIGNATURE, chain1, ONECRL_NAME),
+  ok(!await verifier.asyncVerifyContentSignature(DATA, GOOD_SIGNATURE, chain1, ONECRL_NAME),
      "Before the root is set, signatures should fail to verify but not throw.");
   // Check for generic chain building error.
   check_telemetry(6, 1, getCertHash("content_signing_onecrl_ee"));
 
   setRoot(TEST_DATA_DIR + "content_signing_root.pem");
 
   // Check good signatures from good certificates with the correct SAN
-  ok(verifier.verifyContentSignature(DATA, GOOD_SIGNATURE, chain1, ONECRL_NAME),
+  ok(await verifier.asyncVerifyContentSignature(DATA, GOOD_SIGNATURE, chain1, ONECRL_NAME),
      "A OneCRL signature should verify with the OneCRL chain");
   let chain2 = remoteNewTabChain.join("\n");
-  ok(verifier.verifyContentSignature(DATA, GOOD_SIGNATURE, chain2,
-                                     ABOUT_NEWTAB_NAME),
+  ok(await verifier.asyncVerifyContentSignature(DATA, GOOD_SIGNATURE, chain2,
+                                                ABOUT_NEWTAB_NAME),
      "A newtab signature should verify with the newtab chain");
   // Check for valid signature
   check_telemetry(0, 2, getCertHash("content_signing_remote_newtab_ee"));
 
   // Check a bad signature when a good chain is provided
   chain1 = oneCRLChain.join("\n");
-  ok(!verifier.verifyContentSignature(DATA, BAD_SIGNATURE, chain1, ONECRL_NAME),
+  ok(!await verifier.asyncVerifyContentSignature(DATA, BAD_SIGNATURE, chain1, ONECRL_NAME),
      "A bad signature should not verify");
   // Check for invalid signature
   check_telemetry(1, 1, getCertHash("content_signing_onecrl_ee"));
 
   // Check a good signature from cert with good SAN but a different key than the
   // one used to create the signature
   let badKeyChain = oneCRLBadKeyChain.join("\n");
-  ok(!verifier.verifyContentSignature(DATA, GOOD_SIGNATURE, badKeyChain,
-                                      ONECRL_NAME),
+  ok(!await verifier.asyncVerifyContentSignature(DATA, GOOD_SIGNATURE, badKeyChain,
+                                                 ONECRL_NAME),
      "A signature should not verify if the signing key is wrong");
   // Check for wrong key in cert.
   check_telemetry(9, 1, getCertHash("content_signing_onecrl_wrong_key_ee"));
 
   // Check a good signature from cert with good SAN but a different key than the
   // one used to create the signature (this time, an RSA key)
   let rsaKeyChain = oneCRLBadKeyChain.join("\n");
-  ok(!verifier.verifyContentSignature(DATA, GOOD_SIGNATURE, rsaKeyChain,
-                                      ONECRL_NAME),
+  ok(!await verifier.asyncVerifyContentSignature(DATA, GOOD_SIGNATURE, rsaKeyChain,
+                                                 ONECRL_NAME),
      "A signature should not verify if the signing key is wrong (RSA)");
   // Check for wrong key in cert.
   check_telemetry(9, 1, getCertHash("content_signing_onecrl_wrong_key_ee"));
 
   // Check a good signature from cert with good SAN but with chain missing root
   let missingRoot = [oneCRLChain[0], oneCRLChain[1]].join("\n");
-  ok(!verifier.verifyContentSignature(DATA, GOOD_SIGNATURE, missingRoot,
-                                      ONECRL_NAME),
+  ok(!await verifier.asyncVerifyContentSignature(DATA, GOOD_SIGNATURE, missingRoot,
+                                                 ONECRL_NAME),
      "A signature should not verify if the chain is incomplete (missing root)");
   // Check for generic chain building error.
   check_telemetry(6, 1, getCertHash("content_signing_onecrl_ee"));
 
   // Check a good signature from cert with good SAN but with no path to root
   let missingInt = [oneCRLChain[0], oneCRLChain[2]].join("\n");
-  ok(!verifier.verifyContentSignature(DATA, GOOD_SIGNATURE, missingInt,
-                                      ONECRL_NAME),
+  ok(!await verifier.asyncVerifyContentSignature(DATA, GOOD_SIGNATURE, missingInt,
+                                                 ONECRL_NAME),
      "A signature should not verify if the chain is incomplete (missing int)");
   // Check for generic chain building error.
   check_telemetry(6, 1, getCertHash("content_signing_onecrl_ee"));
 
   // Check good signatures from good certificates with the wrong SANs
   chain1 = oneCRLChain.join("\n");
-  ok(!verifier.verifyContentSignature(DATA, GOOD_SIGNATURE, chain1,
-                                      ABOUT_NEWTAB_NAME),
+  ok(!await verifier.asyncVerifyContentSignature(DATA, GOOD_SIGNATURE, chain1,
+                                                 ABOUT_NEWTAB_NAME),
      "A OneCRL signature should not verify if we require the newtab SAN");
   // Check for invalid EE cert.
   check_telemetry(7, 1, getCertHash("content_signing_onecrl_ee"));
 
   chain2 = remoteNewTabChain.join("\n");
-  ok(!verifier.verifyContentSignature(DATA, GOOD_SIGNATURE, chain2,
-                                      ONECRL_NAME),
+  ok(!await verifier.asyncVerifyContentSignature(DATA, GOOD_SIGNATURE, chain2,
+                                                 ONECRL_NAME),
      "A newtab signature should not verify if we require the OneCRL SAN");
   // Check for invalid EE cert.
   check_telemetry(7, 1, getCertHash("content_signing_remote_newtab_ee"));
 
   // Check good signatures with good chains with some other invalid names
-  ok(!verifier.verifyContentSignature(DATA, GOOD_SIGNATURE, chain1, ""),
+  ok(!await verifier.asyncVerifyContentSignature(DATA, GOOD_SIGNATURE, chain1, ""),
      "A signature should not verify if the SANs do not match an empty name");
   // Check for invalid EE cert.
   check_telemetry(7, 1, getCertHash("content_signing_onecrl_ee"));
 
   // Test expired certificate.
   let chainExpired = expiredOneCRLChain.join("\n");
-  ok(!verifier.verifyContentSignature(DATA, GOOD_SIGNATURE, chainExpired, ""),
+  ok(!await verifier.asyncVerifyContentSignature(DATA, GOOD_SIGNATURE, chainExpired, ""),
      "A signature should not verify if the signing certificate is expired");
   // Check for expired cert.
   check_telemetry(4, 1, getCertHash("content_signing_onecrl_ee_expired"));
 
   // Test not valid yet certificate.
   let chainNotValidYet = notValidYetOneCRLChain.join("\n");
-  ok(!verifier.verifyContentSignature(DATA, GOOD_SIGNATURE, chainNotValidYet, ""),
+  ok(!await verifier.asyncVerifyContentSignature(DATA, GOOD_SIGNATURE, chainNotValidYet, ""),
      "A signature should not verify if the signing certificate is not valid yet");
   // Check for not yet valid cert.
   check_telemetry(5, 1, getCertHash("content_signing_onecrl_ee_not_valid_yet"));
 
   let relatedName = "subdomain." + ONECRL_NAME;
-  ok(!verifier.verifyContentSignature(DATA, GOOD_SIGNATURE, chain1,
-                                      relatedName),
+  ok(!await verifier.asyncVerifyContentSignature(DATA, GOOD_SIGNATURE, chain1,
+                                                 relatedName),
      "A signature should not verify if the SANs do not match a related name");
 
   let randomName = "\xb1\x9bU\x1c\xae\xaa3\x19H\xdb\xed\xa1\xa1\xe0\x81\xfb" +
                    "\xb2\x8f\x1cP\xe5\x8b\x9c\xc2s\xd3\x1f\x8e\xbbN";
-  ok(!verifier.verifyContentSignature(DATA, GOOD_SIGNATURE, chain1, randomName),
+  ok(!await verifier.asyncVerifyContentSignature(DATA, GOOD_SIGNATURE, chain1, randomName),
      "A signature should not verify if the SANs do not match a random name");
 
   // check good signatures with chains that have strange or missing SANs
   chain1 = noSANChain.join("\n");
-  ok(!verifier.verifyContentSignature(DATA, GOOD_SIGNATURE, chain1,
-                                      ONECRL_NAME),
+  ok(!await verifier.asyncVerifyContentSignature(DATA, GOOD_SIGNATURE, chain1,
+                                                 ONECRL_NAME),
      "A signature should not verify if the SANs do not match a supplied name");
 
   // Check malformed signature data
   chain1 = oneCRLChain.join("\n");
   let bad_signatures = [
     // wrong length
     "p384ecdsa=WqRXFQ7tnlVufpg7A-ZavXvWd2Zln0o4woHBy26C2rUWM4GJke4pE8ecHiXoi-" +
     "7KnZXty6Pe3s4o3yAIyKDP9jUC52Ek1Gq25j_X703nP5rk5gM1qz5Fe-qCWakPPl6L==",
@@ -221,19 +221,18 @@ function run_test() {
     // actually sha256 with RSA
     "p384ecdsa=XS_jiQsS5qlzQyUKaA1nAnQn_OvxhvDfKybflB8Xe5gNH1wNmPGK1qN-jpeTfK" +
     "6ob3l3gCTXrsMnOXMeht0kPP3wLfVgXbuuO135pQnsv0c-ltRMWLe56Cm4S4Z6E7WWKLPWaj" +
     "jhAcG5dZxjffP9g7tuPP4lTUJztyc4d1z_zQZakEG7R0vN7P5_CaX9MiMzP4R7nC3H4Ba6yi" +
     "yjlGvsZwJ_C5zDQzWWs95czUbMzbDScEZ_7AWnidw91jZn-fUK3xLb6m-Zb_b4GAqZ-vnXIf" +
     "LpLB1Nzal42BQZn7i4rhAldYdcVvy7rOMlsTUb5Zz6vpVW9LCT9lMJ7Sq1xbU-0g==",
     ];
   for (let badSig of bad_signatures) {
-    throws(() => {
-      verifier.verifyContentSignature(DATA, badSig, chain1, ONECRL_NAME);
-    }, /NS_ERROR/, `Bad or malformed signature "${badSig}" should be rejected`);
+    await Assert.rejects(verifier.asyncVerifyContentSignature(DATA, badSig, chain1, ONECRL_NAME),
+                         /NS_ERROR/, `Bad or malformed signature "${badSig}" should be rejected`);
   }
 
   // Check malformed and missing certificate chain data
   let chainSuffix = [oneCRLChain[1], oneCRLChain[2]].join("\n");
   let badChains = [
     // no data
     "",
     // completely wrong data
@@ -254,22 +253,25 @@ function run_test() {
   for (let badSection of badSections) {
     // ensure we test each bad section on its own...
     badChains.push(badSection);
     // ... and as part of a chain with good certificates
     badChains.push(badSection + "\n" + chainSuffix);
   }
 
   for (let badChain of badChains) {
-    throws(() => {
-      verifier.verifyContentSignature(DATA, GOOD_SIGNATURE, badChain,
-                                      ONECRL_NAME);
-    }, /NS_ERROR/, `Bad chain data starting "${badChain.substring(0, 80)}" ` +
-                   "should be rejected");
+    await Assert.rejects(verifier.asyncVerifyContentSignature(DATA, GOOD_SIGNATURE, badChain,
+                                                              ONECRL_NAME),
+                         /NS_ERROR/,
+                         `Bad chain data starting "${badChain.substring(0, 80)}" ` +
+                         "should be rejected");
   }
 
-  ok(!verifier.verifyContentSignature(DATA + "appended data", GOOD_SIGNATURE, chain1, ONECRL_NAME),
+  ok(!await verifier.asyncVerifyContentSignature(DATA + "appended data", GOOD_SIGNATURE, chain1,
+                                                 ONECRL_NAME),
      "A good signature should not verify if the data is tampered with (append)");
-  ok(!verifier.verifyContentSignature("prefixed data" + DATA, GOOD_SIGNATURE, chain1, ONECRL_NAME),
+  ok(!await verifier.asyncVerifyContentSignature("prefixed data" + DATA, GOOD_SIGNATURE, chain1,
+                                                 ONECRL_NAME),
      "A good signature should not verify if the data is tampered with (prefix)");
-  ok(!verifier.verifyContentSignature(DATA.replace(/e/g, "i"), GOOD_SIGNATURE, chain1, ONECRL_NAME),
+  ok(!await verifier.asyncVerifyContentSignature(DATA.replace(/e/g, "i"), GOOD_SIGNATURE, chain1,
+                                                 ONECRL_NAME),
      "A good signature should not verify if the data is tampered with (modify)");
-}
+});
--- a/services/common/tests/unit/test_blocklist_signatures.js
+++ b/services/common/tests/unit/test_blocklist_signatures.js
@@ -131,26 +131,24 @@ add_task(async function test_check_signa
   // First, perform a signature verification with known data and signature
   // to ensure things are working correctly
   let verifier = Cc["@mozilla.org/security/contentsignatureverifier;1"]
                    .createInstance(Ci.nsIContentSignatureVerifier);
 
   const emptyData = "[]";
   const emptySignature = "p384ecdsa=zbugm2FDitsHwk5-IWsas1PpWwY29f0Fg5ZHeqD8fzep7AVl2vfcaHA7LdmCZ28qZLOioGKvco3qT117Q4-HlqFTJM7COHzxGyU2MMJ0ZTnhJrPOC1fP3cVQjU1PTWi9";
   const name = "onecrl.content-signature.mozilla.org";
-  ok(verifier.verifyContentSignature(emptyData, emptySignature,
-                                     getCertChain(), name));
-
-  verifier = Cc["@mozilla.org/security/contentsignatureverifier;1"]
-               .createInstance(Ci.nsIContentSignatureVerifier);
+  ok(await verifier.asyncVerifyContentSignature(emptyData, emptySignature,
+                                                getCertChain(), name));
 
   const collectionData = '[{"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1155145","created":"2016-01-18T14:43:37Z","name":"GlobalSign certs","who":".","why":"."},"enabled":true,"id":"97fbf7c4-3ef2-f54f-0029-1ba6540c63ea","issuerName":"MHExKDAmBgNVBAMTH0dsb2JhbFNpZ24gUm9vdFNpZ24gUGFydG5lcnMgQ0ExHTAbBgNVBAsTFFJvb3RTaWduIFBhcnRuZXJzIENBMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMQswCQYDVQQGEwJCRQ==","last_modified":2000,"serialNumber":"BAAAAAABA/A35EU="},{"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1155145","created":"2016-01-18T14:48:11Z","name":"GlobalSign certs","who":".","why":"."},"enabled":true,"id":"e3bd531e-1ee4-7407-27ce-6fdc9cecbbdc","issuerName":"MIGBMQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTElMCMGA1UECxMcUHJpbWFyeSBPYmplY3QgUHVibGlzaGluZyBDQTEwMC4GA1UEAxMnR2xvYmFsU2lnbiBQcmltYXJ5IE9iamVjdCBQdWJsaXNoaW5nIENB","last_modified":3000,"serialNumber":"BAAAAAABI54PryQ="}]';
   const collectionSignature = "p384ecdsa=f4pA2tYM5jQgWY6YUmhUwQiBLj6QO5sHLD_5MqLePz95qv-7cNCuQoZnPQwxoptDtW8hcWH3kLb0quR7SB-r82gkpR9POVofsnWJRA-ETb0BcIz6VvI3pDT49ZLlNg3p";
 
-  ok(verifier.verifyContentSignature(collectionData, collectionSignature, getCertChain(), name));
+  ok(await verifier.asyncVerifyContentSignature(collectionData, collectionSignature,
+                                                getCertChain(), name));
 
   // set up prefs so the kinto updater talks to the test server
   Services.prefs.setCharPref(PREF_SETTINGS_SERVER,
     `http://localhost:${server.identity.primaryPort}/v1`);
 
   // These are records we'll use in the test collections
   const RECORD1 = {
     details: {
--- a/services/settings/RemoteSettingsClient.jsm
+++ b/services/settings/RemoteSettingsClient.jsm
@@ -448,20 +448,20 @@ class RemoteSettingsClient extends Event
       localRecords = data.map(r => kintoCollection.cleanLocalFields(r));
     }
 
     const serialized = await RemoteSettingsWorker.canonicalStringify(localRecords,
                                                                      remoteRecords,
                                                                      timestamp);
     const verifier = Cc["@mozilla.org/security/contentsignatureverifier;1"]
       .createInstance(Ci.nsIContentSignatureVerifier);
-    if (!verifier.verifyContentSignature(serialized,
-                                         "p384ecdsa=" + signature,
-                                         certChain,
-                                         this.signerName)) {
+    if (!await verifier.asyncVerifyContentSignature(serialized,
+                                                    "p384ecdsa=" + signature,
+                                                    certChain,
+                                                    this.signerName)) {
       throw new RemoteSettingsClient.InvalidSignatureError(`${bucket}/${collection}`);
     }
   }
 
   /**
    * Fetch the whole list of records from the server, verify the signature again
    * and then compute a synchronization result as if the diff-based sync happened.
    * And eventually, wipe out the local data.
deleted file mode 100644
--- a/testing/web-platform/meta/svg/render/reftests/blending-002.svg.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[blending-002.svg]
-  expected:
-    if webrender and (os == "linux"): FAIL
-    if webrender and (os == "win"): FAIL
--- a/testing/web-platform/meta/webrtc/RTCPeerConnection-createDataChannel.html.ini
+++ b/testing/web-platform/meta/webrtc/RTCPeerConnection-createDataChannel.html.ini
@@ -18,23 +18,19 @@
   [createDataChannel with invalid priority should throw TypeError]
     expected: FAIL
     bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1531100
 
   [createDataChannel with negotiated false and long label should throw TypeError]
     expected: FAIL
     bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1531908
 
-  [createDataChannel with negotiated false and long protocol should throw TypeError]
-    expected: FAIL
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1531910
-
   [createDataChannel with negotiated true and long label and long protocol should succeed]
     expected: FAIL
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1531908 and https://bugzilla.mozilla.org/show_bug.cgi?id=1531910
+    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1531908
 
   [Channels created after SCTP transport is established should have id assigned]
     expected: FAIL
     bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1526253
 
   [createDataChannel with negotiated false should succeed]
     expected: FAIL
 
@@ -60,17 +56,11 @@
     expected: FAIL
 
   [createDataChannel with negotiated true and id null should throw TypeError]
     expected: FAIL
 
   [createDataChannel with both maxPacketLifeTime and maxRetransmits null should succeed]
     expected: FAIL
 
-  [createDataChannel with too long protocol (2 byte unicode) should throw TypeError]
-    expected: FAIL
-
   [Channels created (after setRemoteDescription) should have id assigned]
     expected: FAIL
 
-  [createDataChannel with too long protocol should throw TypeError]
-    expected: FAIL
-
--- a/toolkit/components/corroborator/test/xpcshell/xpcshell.ini
+++ b/toolkit/components/corroborator/test/xpcshell/xpcshell.ini
@@ -1,6 +1,7 @@
 [DEFAULT]
 tags = corroborator
 support-files =
   data/**
 
 [test_verify_jar.js]
+skip-if = true # Bug 1549147 - Disable temporily until non-expired cert is available to sign test XPI.
--- a/toolkit/components/normandy/lib/NormandyApi.jsm
+++ b/toolkit/components/normandy/lib/NormandyApi.jsm
@@ -129,17 +129,17 @@ var NormandyApi = {
 
     const serialized = typeof data == "string" ? data : CanonicalJSON.stringify(data);
 
     const verifier = Cc["@mozilla.org/security/contentsignatureverifier;1"]
       .createInstance(Ci.nsIContentSignatureVerifier);
 
     let valid;
     try {
-      valid = verifier.verifyContentSignature(
+      valid = await verifier.asyncVerifyContentSignature(
         serialized,
         builtSignature,
         certChain,
         "normandy.content-signature.mozilla.org"
       );
     } catch (err) {
       throw new NormandyApi.InvalidSignatureError(`${type} signature validation failed: ${err}`);
     }
--- a/toolkit/modules/AppConstants.jsm
+++ b/toolkit/modules/AppConstants.jsm
@@ -17,16 +17,23 @@ this.AppConstants = Object.freeze({
   // defines: https://wiki.mozilla.org/Platform/Channel-specific_build_defines
   NIGHTLY_BUILD:
 #ifdef NIGHTLY_BUILD
   true,
 #else
   false,
 #endif
 
+  FENNEC_NIGHTLY:
+#ifdef FENNEC_NIGHTLY
+  true,
+#else
+  false,
+#endif
+
   RELEASE_OR_BETA:
 #ifdef RELEASE_OR_BETA
   true,
 #else
   false,
 #endif
 
   EARLY_BETA_OR_EARLIER:
--- a/toolkit/mozapps/extensions/internal/XPIDatabase.jsm
+++ b/toolkit/mozapps/extensions/internal/XPIDatabase.jsm
@@ -2405,19 +2405,17 @@ this.XPIDatabaseReconcile = {
       // Do not allow third party installs if xpinstall is disabled by policy
       if (isDetectedInstall && Services.policies &&
           !Services.policies.isAllowed("xpinstall")) {
         throw new Error("Extension installs are disabled by enterprise policy.");
       }
 
       if (!aNewAddon) {
         // Load the manifest from the add-on.
-        let file = new nsIFile(aAddonState.path);
-        aNewAddon = XPIInstall.syncLoadManifestFromFile(file, aLocation);
-        aNewAddon.rootURI = XPIInternal.getURIForResourceInFile(file, "").spec;
+        aNewAddon = XPIInstall.syncLoadManifest(aAddonState, aLocation);
       }
       // The add-on in the manifest should match the add-on ID.
       if (aNewAddon.id != aId) {
         throw new Error(`Invalid addon ID: expected addon ID ${aId}, found ${aNewAddon.id} in manifest`);
       }
 
       unsigned = XPIDatabase.mustSign(aNewAddon.type) && !aNewAddon.isCorrectlySigned;
       if (unsigned) {
@@ -2501,19 +2499,17 @@ this.XPIDatabaseReconcile = {
    *        changing this add-on
    */
   updateMetadata(aLocation, aOldAddon, aAddonState, aNewAddon) {
     logger.debug(`Add-on ${aOldAddon.id} modified in ${aLocation.name}`);
 
     try {
       // If there isn't an updated install manifest for this add-on then load it.
       if (!aNewAddon) {
-        let file = new nsIFile(aAddonState.path);
-        aNewAddon = XPIInstall.syncLoadManifestFromFile(file, aLocation, aOldAddon);
-        aNewAddon.rootURI = XPIInternal.getURIForResourceInFile(file, "").spec;
+        aNewAddon = XPIInstall.syncLoadManifest(aAddonState, aLocation, aOldAddon);
       } else {
         aNewAddon.rootURI = aOldAddon.rootURI;
       }
 
       // The ID in the manifest that was loaded must match the ID of the old
       // add-on.
       if (aNewAddon.id != aOldAddon.id)
         throw new Error(`Incorrect id in install manifest for existing add-on ${aOldAddon.id}`);
@@ -2581,19 +2577,17 @@ this.XPIDatabaseReconcile = {
     logger.debug(`Updating compatibility for add-on ${aOldAddon.id} in ${aLocation.name}`);
 
     let checkSigning = (aOldAddon.signedState === undefined &&
                         SIGNED_TYPES.has(aOldAddon.type));
 
     let manifest = null;
     if (checkSigning || aReloadMetadata) {
       try {
-        let file = new nsIFile(aAddonState.path);
-        manifest = XPIInstall.syncLoadManifestFromFile(file, aLocation);
-        manifest.rootURI = aOldAddon.rootURI;
+        manifest = XPIInstall.syncLoadManifest(aAddonState, aLocation);
       } catch (err) {
         // If we can no longer read the manifest, it is no longer compatible.
         aOldAddon.brokenManifest = true;
         aOldAddon.appDisabled = true;
         return aOldAddon;
       }
     }
 
@@ -2834,16 +2828,19 @@ this.XPIDatabaseReconcile = {
     }
 
     if (promises.some(p => p)) {
       XPIInternal.awaitPromise(Promise.all(promises));
     }
 
     for (let [id, addon] of previousVisible) {
       if (addon.location) {
+        if (addon.location.name == KEY_APP_BUILTINS) {
+          continue;
+        }
         if (addonExists(addon)) {
           XPIInternal.BootstrapScope.get(addon).uninstall();
         }
         addon.location.removeAddon(id);
         addon.visible = false;
         addon.active = false;
       }
 
@@ -2904,18 +2901,19 @@ this.XPIDatabaseReconcile = {
     let isActive = !currentAddon.disabled;
     let wasActive = previousAddon ? previousAddon.active : currentAddon.active;
 
     if (previousAddon) {
       if (previousAddon !== currentAddon) {
         AddonManagerPrivate.addStartupChange(AddonManager.STARTUP_CHANGE_CHANGED, id);
 
         if (previousAddon.location &&
-            previousAddon._sourceBundle.exists() &&
-            !previousAddon._sourceBundle.equals(currentAddon._sourceBundle)) {
+            (!previousAddon._sourceBundle ||
+             (previousAddon._sourceBundle.exists() &&
+              !previousAddon._sourceBundle.equals(currentAddon._sourceBundle)))) {
           promise = XPIInternal.BootstrapScope.get(previousAddon).update(
             currentAddon);
         } else if (this.isSystemAddonLocation(currentAddon.location) &&
                    previousAddon.version == currentAddon.version &&
                    previousAddon.userDisabled != currentAddon.userDisabled) {
           // A system addon change, no need for install or update events.
         } else {
           let reason = XPIInstall.newVersionReason(previousAddon.version, currentAddon.version);
--- a/toolkit/mozapps/extensions/internal/XPIInstall.jsm
+++ b/toolkit/mozapps/extensions/internal/XPIInstall.jsm
@@ -335,16 +335,46 @@ XPIPackage = class XPIPackage extends Pa
   }
 
   flushCache() {
     flushJarCache(this.file);
   }
 };
 
 /**
+ * Return an object that implements enough of the Package interface
+ * to allow loadManifest() to work for a built-in addon (ie, one loaded
+ * from a resource: url)
+ *
+ * @param {nsIURL} baseURL The URL for the root of the add-on.
+ * @returns {object}
+ */
+function builtinPackage(baseURL) {
+  return {
+    rootURI: baseURL,
+    filePath: baseURL.spec,
+    file: null,
+    verifySignedState() {
+      return {
+        signedState: AddonManager.SIGNEDSTATE_NOT_REQUIRED,
+        cert: null,
+      };
+    },
+    async hasResource(path) {
+      try {
+        let response = await fetch(this.rootURI.resolve(path));
+        return response.ok;
+      } catch (e) {
+        return false;
+      }
+    },
+  };
+}
+
+/**
  * Determine the reason to pass to an extension's bootstrap methods when
  * switch between versions.
  *
  * @param {string} oldVersion The version of the existing extension instance.
  * @param {string} newVersion The version of the extension being installed.
  *
  * @returns {integer}
  *        BOOSTRAP_REASONS.ADDON_UPGRADE or BOOSTRAP_REASONS.ADDON_DOWNGRADE
@@ -605,18 +635,33 @@ var loadManifestFromFile = async functio
     pkg.close();
   }
 };
 
 /*
  * A synchronous method for loading an add-on's manifest. Do not use
  * this.
  */
-function syncLoadManifestFromFile(aFile, aLocation, aOldAddon) {
-  return XPIInternal.awaitPromise(loadManifestFromFile(aFile, aLocation, aOldAddon));
+function syncLoadManifest(state, location, oldAddon) {
+  if (location.name == "app-builtin") {
+    let pkg = builtinPackage(Services.io.newURI(state.rootURI));
+    return XPIInternal.awaitPromise(loadManifest(pkg, location, oldAddon));
+  }
+
+  let file = new nsIFile(state.path);
+  let pkg = Package.get(file);
+  return XPIInternal.awaitPromise((async () => {
+    try {
+      let addon = await loadManifest(pkg, location, oldAddon);
+      addon.rootURI = getURIForResourceInFile(file, "").spec;
+      return addon;
+    } finally {
+      pkg.close();
+    }
+  })());
 }
 
 /**
  * Creates and returns a new unique temporary file. The caller should delete
  * the file when it is no longer needed.
  *
  * @returns {nsIFile}
  *       An nsIFile that points to a randomly named, initially empty file in
@@ -3221,17 +3266,17 @@ class SystemAddonInstaller extends Direc
 var XPIInstall = {
   // An array of currently active AddonInstalls
   installs: new Set(),
 
   createLocalInstall,
   flushJarCache,
   newVersionReason,
   recursiveRemove,
-  syncLoadManifestFromFile,
+  syncLoadManifest,
 
   // Keep track of in-progress operations that support cancel()
   _inProgress: [],
 
   doing(aCancellable) {
     this._inProgress.push(aCancellable);
   },
 
@@ -3690,37 +3735,17 @@ var XPIInstall = {
     // WebExtensions need to be able to iterate through the contents of
     // an extension (for localization).  It knows how to do this with
     // jar: and file: URLs, so translate the provided base URL to
     // something it can use.
     if (baseURL.scheme !== "resource") {
       throw new Error("Built-in addons must use resource: URLS");
     }
 
-    // Enough of the Package interface to allow loadManifest() to work.
-    let pkg = {
-      rootURI: baseURL,
-      filePath: baseURL.spec,
-      file: null,
-      verifySignedState() {
-        return {
-          signedState: AddonManager.SIGNEDSTATE_NOT_REQUIRED,
-          cert: null,
-        };
-      },
-      async hasResource(path) {
-        try {
-          let response = await fetch(this.rootURI.resolve(path));
-          return response.ok;
-        } catch (e) {
-          return false;
-        }
-      },
-    };
-
+    let pkg = builtinPackage(baseURL);
     let addon = await loadManifest(pkg, XPIInternal.BuiltInLocation);
     addon.rootURI = base;
 
     // If this is a theme, decide whether to enable it. Themes are
     // disabled by default. However:
     //
     // If a lightweight theme was selected in the last session, and this
     // theme has the same ID, then we clearly want to enable it.
--- a/toolkit/mozapps/extensions/internal/XPIProvider.jsm
+++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm
@@ -101,17 +101,17 @@ const STARTUP_MTIME_SCOPES = [KEY_APP_GL
                               KEY_APP_SYSTEM_SHARE,
                               KEY_APP_SYSTEM_USER];
 
 const NOTIFICATION_FLUSH_PERMISSIONS  = "flush-pending-permissions";
 const XPI_PERMISSION                  = "install";
 
 const XPI_SIGNATURE_CHECK_PERIOD      = 24 * 60 * 60;
 
-const DB_SCHEMA = 29;
+const DB_SCHEMA = 30;
 
 XPCOMUtils.defineLazyPreferenceGetter(this, "enabledScopesPref",
                                       PREF_EM_ENABLED_SCOPES,
                                       AddonManager.SCOPE_ALL);
 
 Object.defineProperty(this, "enabledScopes", {
   get() {
     // The profile location is always enabled
@@ -1982,16 +1982,39 @@ class BootstrapScope {
       await updateCallback();
     }
 
     this.addon = newAddon;
     return this._install(reason, callUpdate, startup, extraArgs);
   }
 }
 
+// https://bugzilla.mozilla.org/show_bug.cgi?id=1548973
+const MISSING_INTERMEDIATE_CERTIFICATE = "MIIHLTCCBRWgAwIBAgIDEAAIMA0GCSqGSIb3DQEBDAUAMH0xCzAJBgNVBAYTAlVTMRwwGgYDVQQKExNNb3ppbGxhIENvcnBvcmF0aW9uMS8wLQYDVQQLEyZNb3ppbGxhIEFNTyBQcm9kdWN0aW9uIFNpZ25pbmcgU2VydmljZTEfMB0GA1UEAxMWcm9vdC1jYS1wcm9kdWN0aW9uLWFtbzAeFw0xNTA0MDQwMDAwMDBaFw0yNTA0MDQwMDAwMDBaMIGnMQswCQYDVQQGEwJVUzEcMBoGA1UEChMTTW96aWxsYSBDb3Jwb3JhdGlvbjEvMC0GA1UECxMmTW96aWxsYSBBTU8gUHJvZHVjdGlvbiBTaWduaW5nIFNlcnZpY2UxJjAkBgNVBAMTHXNpZ25pbmdjYTEuYWRkb25zLm1vemlsbGEub3JnMSEwHwYJKoZIhvcNAQkBFhJmb3hzZWNAbW96aWxsYS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/qluiiI+wO6qGA4vH7cHvWvXpdju9JnvbwnrbYmxhtUpfS68LbdjGGtv7RP6F1XhHT4MU3v4GuMulH0E4Wfalm8evsb3tBJRMJPICJX5UCLi6VJ6J2vipXSWBf8xbcOB+PY5Kk6L+EZiWaepiM23CdaZjNOJCAB6wFHlGe+zUk87whpLa7GrtrHjTb8u9TSS+mwjhvgfP8ILZrWhzb5H/ybgmD7jYaJGIDY/WDmq1gVe03fShxD09Ml1P7H38o5kbFLnbbqpqC6n8SfUI31MiJAXAN2e6rAOM8EmocAY0EC5KUooXKRsYvHzhwwHkwIbbe6QpTUlIqvw1MPlQPs7Zu/MBnVmyGTSqJxtYoklr0MaEXnJNY3g3FDf1R0Opp2/BEY9Vh3Fc9Pq6qWIhGoMyWdueoSYa+GURqDbsuYnk7ZkysxK+yRoFJu4x3TUBmMKM14jQKLgxvuIzWVn6qg6cw7ye/DYNufc+DSPSTSakSsWJ9IPxiAU7xJ+GCMzaZ10Y3VGOybGLuPxDlSd6KALAoMcl9ghB2mvfB0N3wv6uWnbKuxihq/qDps+FjliNvr7C66mIVH+9rkyHIy6GgIUlwr7E88Qqw+SQeNeph6NIY85PL4p0Y8KivKP4J928tpp18wLuHNbIG+YaUk5WUDZ6/2621pi19UZQ8iiHxN/XKQIDAQABo4IBiTCCAYUwDAYDVR0TBAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwMwHQYDVR0OBBYEFBY++xz/DCuT+JsV1y2jwuZ4YdztMIGoBgNVHSMEgaAwgZ2AFLO86lh0q+FueCqyq5wjHqhjLJe3oYGBpH8wfTELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE01vemlsbGEgQ29ycG9yYXRpb24xLzAtBgNVBAsTJk1vemlsbGEgQU1PIFByb2R1Y3Rpb24gU2lnbmluZyBTZXJ2aWNlMR8wHQYDVQQDExZyb290LWNhLXByb2R1Y3Rpb24tYW1vggEBMDMGCWCGSAGG+EIBBAQmFiRodHRwOi8vYWRkb25zLm1vemlsbGEub3JnL2NhL2NybC5wZW0wTgYDVR0eBEcwRaFDMCCCHi5jb250ZW50LXNpZ25hdHVyZS5tb3ppbGxhLm9yZzAfgh1jb250ZW50LXNpZ25hdHVyZS5tb3ppbGxhLm9yZzANBgkqhkiG9w0BAQwFAAOCAgEAX1PNli/zErw3tK3S9Bv803RV4tHkrMa5xztxzlWja0VAUJKEQx7f1yM8vmcQJ9g5RE8WFc43IePwzbAoum5F4BTM7tqM//+e476F1YUgB7SnkDTVpBOnV5vRLz1Si4iJ/U0HUvMUvNJEweXvKg/DNbXuCreSvTEAawmRIxqNYoaigQD8x4hCzGcVtIi5Xk2aMCJW2K/6JqkN50pnLBNkPx6FeiYMJCP8z0FIz3fv53FHgu3oeDhi2u3VdONjK3aaFWTlKNiGeDU0/lr0suWfQLsNyphTMbYKyTqQYHxXYJno9PuNi7e1903PvM47fKB5bFmSLyzB1hB1YIVLj0/YqD4nz3lADDB91gMBB7vR2h5bRjFqLOxuOutNNcNRnv7UPqtVCtLF2jVb4/AmdJU78jpfDs+BgY/t2bnGBVFBuwqS2Kult/2kth4YMrL5DrURIM8oXWVQRBKxzr843yDmHo8+2rqxLnZcmWoe8yQ41srZ4IB+V3w2TIAd4gxZAB0Xa6KfnR4D8RgE5sgmgQoK7Y/hdvd9Ahu0WEZI8Eg+mDeCeojWcyjF+dt6c2oERiTmFTIFUoojEjJwLyIqHKt+eApEYpF7imaWcumFN1jR+iUjE4ZSUoVxGtZ/Jdnkf8VVQMhiBA+i7r5PsfrHq+lqTTGOg+GzYx7OmoeJAT0zo4c=";
+
+function addMissingIntermediateCertificate() {
+  const PREF_SIGNER_HOTFIXED = "extensions.signer.hotfixed";
+  let hotfixApplied = Services.prefs.getBoolPref(PREF_SIGNER_HOTFIXED, false);
+  if (hotfixApplied) {
+    return;
+  }
+  logger.debug("hotfix for addon signing cert has not been applied; applying");
+
+  try {
+    let certDB = Cc["@mozilla.org/security/x509certdb;1"].getService(Ci.nsIX509CertDB);
+    certDB.addCertFromBase64(MISSING_INTERMEDIATE_CERTIFICATE, ",,");
+    logger.debug("new intermediate certificate added");
+  } catch (e) {
+    logger.error("failed to add new intermediate certificate:", e);
+    return;
+  }
+
+  Services.prefs.setBoolPref(PREF_SIGNER_HOTFIXED, true);
+}
+
 let resolveDBReady;
 let dbReadyPromise = new Promise(resolve => {
   resolveDBReady = resolve;
 });
 let resolveProviderReady;
 let providerReadyPromise = new Promise(resolve => {
   resolveProviderReady = resolve;
 });
@@ -2227,16 +2250,21 @@ var XPIProvider = {
    * @param {string?} [aOldAppVersion]
    *        The version of the application last run with this profile or null
    *        if it is a new profile or the version is unknown
    * @param {string?} [aOldPlatformVersion]
    *        The version of the platform last run with this profile or null
    *        if it is a new profile or the version is unknown
    */
   startup(aAppChanged, aOldAppVersion, aOldPlatformVersion) {
+    // Add missing certificate (bug 1548973). Mistakenly disabled add-ons are
+    // going to be re-enabled because the schema version bump forces a new
+    // signature verification check.
+    addMissingIntermediateCertificate();
+
     try {
       AddonManagerPrivate.recordTimestamp("XPI_startup_begin");
 
       logger.debug("startup");
 
       this.builtInAddons = {};
       try {
         let url = Services.io.newURI(BUILT_IN_ADDONS_URI);
--- a/toolkit/mozapps/extensions/test/xpcshell/test_builtin_location.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_builtin_location.js
@@ -38,16 +38,39 @@ add_task(async function test_builtin_loc
   await wrapper.awaitStartup();
   await wrapper.awaitMessage("started");
   ok(true, "Extension in built-in location ran after restart");
 
   addon = await promiseAddonByID(id);
   notEqual(addon, null, "Addon is installed");
   ok(addon.isActive, "Addon is active");
 
+  // After a restart that causes a database rebuild, it should still work
+  await promiseRestartManager("2");
+  await wrapper.awaitStartup();
+  await wrapper.awaitMessage("started");
+  ok(true, "Extension in built-in location ran after restart");
+
+  addon = await promiseAddonByID(id);
+  notEqual(addon, null, "Addon is installed");
+  ok(addon.isActive, "Addon is active");
+
+  // After a restart that changes the schema version, it should still work
+  await promiseShutdownManager();
+  Services.prefs.setIntPref("extensions.databaseSchema", 0);
+  await promiseStartupManager();
+
+  await wrapper.awaitStartup();
+  await wrapper.awaitMessage("started");
+  ok(true, "Extension in built-in location ran after restart");
+
+  addon = await promiseAddonByID(id);
+  notEqual(addon, null, "Addon is installed");
+  ok(addon.isActive, "Addon is active");
+
   await wrapper.unload();
 
   addon = await promiseAddonByID(id);
   equal(addon, null, "Addon is gone after uninstall");
   await AddonTestUtils.promiseShutdownManager();
 });
 
 // Tests installing a hidden extension from the built-in location.
--- a/toolkit/mozapps/update/tests/browser/head.js
+++ b/toolkit/mozapps/update/tests/browser/head.js
@@ -574,16 +574,17 @@ function runDoorhangerUpdateTest(updateP
     })();
   }
 
   return (async function() {
     gEnv.set("MOZ_TEST_SKIP_UPDATE_STAGE", "1");
     await SpecialPowers.pushPrefEnv({
       set: [
         [PREF_APP_UPDATE_DISABLEDFORTESTING, false],
+        [PREF_APP_UPDATE_IDLETIME, 0],
         [PREF_APP_UPDATE_URL_MANUAL, URL_MANUAL_UPDATE],
         [PREF_APP_UPDATE_URL_DETAILS, gDetailsURL],
       ],
     });
 
     await setupTestUpdater();
 
     let updateURL = URL_HTTP_UPDATE_SJS + "?detailsURL=" + gDetailsURL +
@@ -598,18 +599,18 @@ function runDoorhangerUpdateTest(updateP
           for (var i = 0; i < checkAttempts - 1; i++) {
             await waitForEvent("update-error", "check-attempt-failed");
             gAUS.checkForBackgroundUpdates();
           }
         })();
       });
     } else {
       // Perform a startup processing doorhanger test.
+      writeStatusFile(STATE_FAILED_CRC_ERROR);
       reloadUpdateManagerData();
-      writeStatusFile(STATE_FAILED_CRC_ERROR);
       testPostUpdateProcessing();
     }
 
     for (let step of steps) {
       await processDoorhangerStep(step);
     }
   })();
 }
--- a/tools/tryselect/docs/tasks.rst
+++ b/tools/tryselect/docs/tasks.rst
@@ -53,17 +53,17 @@ skip the wait the next time you run ``ma
 
     Watchman triggers are persistent and don't need to be added more than once.
     See `Managing Triggers`_ for how to remove a trigger.
 
 You can test that everything is working by running these commands:
 
 .. code-block:: shell
 
-    $ statedir=`mach python -c "from mozboot.util import get_state_dir; get_state_dir(srcdir=True)"`
+    $ statedir=`mach python -c "from mozboot.util import get_state_dir; print(get_state_dir(srcdir=True))"`
     $ rm -rf $statedir/cache/taskgraph
     $ touch taskcluster/mach_commands.py
     # wait a minute for generation to trigger and finish
     $ ls $statedir/cache/taskgraph
 
 If the ``target_task_set`` file exists, you are good to go. If not you can look at the ``watchman``
 log to see if there were any errors. This typically lives somewhere like
 ``/usr/local/var/run/watchman/<user>-state/log``. In this case please file a bug under ``Firefox