Merge graphics to m-c a=merge while we IGNORE BAD COMMIT MESSAGES
authorWes Kocher <wkocher@mozilla.com>
Fri, 10 Feb 2017 12:32:41 -0800
changeset 342227 a288fe35e494cec3620717eab66eaff6f68a6369
parent 341818 511093a0d82882d4b20f91b0287ad4b610c5225f (current diff)
parent 342226 a5270cca9e2829e1ee9a2530e880fd98bee3f698 (diff)
child 342260 7b9d9e4a82a6eed63833171d38667313081641db
push id31345
push userkwierso@gmail.com
push dateFri, 10 Feb 2017 20:35:09 +0000
treeherdermozilla-central@a288fe35e494 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone54.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge graphics to m-c a=merge while we IGNORE BAD COMMIT MESSAGES
third_party/rust/gcc/appveyor.yml
third_party/rust/libc/.travis.yml
third_party/rust/libc/README.md
third_party/rust/libc/ci/docker/mips-unknown-linux-musl/Dockerfile
third_party/rust/libc/ci/docker/x86_64-unknown-freebsd/Dockerfile
third_party/rust/libc/ci/docker/x86_64-unknown-openbsd/Dockerfile
third_party/rust/libc/ci/run-docker.sh
third_party/rust/libc/ci/run.sh
third_party/rust/libc/src/unix/notbsd/linux/musl/b32/arm.rs
third_party/rust/libc/src/unix/notbsd/linux/musl/b32/asmjs.rs
third_party/rust/libc/src/unix/notbsd/linux/musl/b32/mips.rs
third_party/rust/libc/src/unix/notbsd/linux/musl/b32/x86.rs
third_party/rust/libc/src/windows.rs
third_party/rust/libz-sys/.travis.yml
third_party/rust/libz-sys/appveyor.yml
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -2325,17 +2325,17 @@ nsDOMWindowUtils::GetLayerManagerRemote(
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (!widget)
     return NS_ERROR_FAILURE;
 
   LayerManager *mgr = widget->GetLayerManager();
   if (!mgr)
     return NS_ERROR_FAILURE;
 
-  *retval = !!mgr->AsShadowForwarder();
+  *retval = !!mgr->AsKnowsCompositor();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::GetSupportsHardwareH264Decoding(JS::MutableHandle<JS::Value> aPromise)
 {
   nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
   NS_ENSURE_STATE(window);
@@ -2343,17 +2343,17 @@ nsDOMWindowUtils::GetSupportsHardwareH26
     do_QueryInterface(window->GetCurrentInnerWindow());
   NS_ENSURE_STATE(parentObject);
 #ifdef MOZ_FMP4
   nsCOMPtr<nsIWidget> widget = GetWidget();
   NS_ENSURE_STATE(widget);
   LayerManager *mgr = widget->GetLayerManager();
   NS_ENSURE_STATE(mgr);
   RefPtr<Promise> promise =
-    MP4Decoder::IsVideoAccelerated(mgr->AsShadowForwarder(), parentObject);
+    MP4Decoder::IsVideoAccelerated(mgr->AsKnowsCompositor(), parentObject);
   NS_ENSURE_STATE(promise);
   aPromise.setObject(*promise->PromiseObj());
 #else
   ErrorResult rv;
   RefPtr<Promise> promise = Promise::Create(parentObject, rv);
   if (rv.Failed()) {
     return rv.StealNSResult();
   }
--- a/dom/canvas/crashtests/crashtests.list
+++ b/dom/canvas/crashtests/crashtests.list
@@ -6,18 +6,18 @@ load 553938-1.html
 load 647480.html
 load 727547.html
 load 729116.html
 asserts-if(stylo,1) load 745699-1.html # bug 1324700
 load 746813-1.html
 load 743499-negative-size.html
 skip-if(Android) load 745818-large-source.html # Bug XXX - Crashes Android mid-run w/o a stack
 load 767337-1.html
-asserts-if(stylo,1) skip-if(Android) load 780392-1.html # bug 1324700
-skip-if(Android) skip-if(gtkWidget&&isDebugBuild) load 789933-1.html # bug 1155252 for linux
+asserts-if(stylo,1) skip-if(Android) skip-if(webrender) load 780392-1.html # bug 1324700. bug 1322816 for webrender
+skip-if(Android) skip-if(gtkWidget&&isDebugBuild) skip-if(webrender) load 789933-1.html # bug 1155252 for linux, bug 1322816 for webrender
 load 794463-1.html
 load 802926-1.html
 load 896047-1.html
 load 916128-1.html
 load 934939-1.html
 asserts-if(stylo,1) load 1099143-1.html # bug 1324700
 load 1161277-1.html
 load 1183363.html
--- a/dom/canvas/test/reftest/reftest.list
+++ b/dom/canvas/test/reftest/reftest.list
@@ -1,20 +1,20 @@
 # WebGL Reftests!
 default-preferences pref(webgl.force-enabled,true) pref(media.useAudioChannelAPI,true) pref(dom.audiochannel.mutedByDefault,false)
 
 # Check that disabling works:
 skip-if(Android)                           == webgl-disable-test.html?nogl wrapper.html?green.png
-pref(webgl.disabled,true) skip-if(Android)  == webgl-disable-test.html      wrapper.html?green.png
+pref(webgl.disabled,true) skip-if(Android) == webgl-disable-test.html      wrapper.html?green.png
 
 # Basic WebGL tests:
 # Do we get pixels to the screen at all?
 # Neither of these should ever break.
 skip-if(Android)                                        == webgl-clear-test.html wrapper.html?green.png
-pref(webgl.force-layers-readback,true) skip-if(Android)  == webgl-clear-test.html?readback wrapper.html?green.png
+pref(webgl.force-layers-readback,true) skip-if(Android) == webgl-clear-test.html?readback wrapper.html?green.png
 
 # Make sure that our choice of attribs doesn't break rendering.
 skip-if(Android) == webgl-clear-test.html?depth wrapper.html?green.png
 skip-if(Android) == webgl-clear-test.html?stencil wrapper.html?green.png
 skip-if(Android) == webgl-clear-test.html?depth&stencil wrapper.html?green.png
 
 # Check that resize works:
 skip-if(Android) == webgl-resize-test.html  wrapper.html?green.png
@@ -48,71 +48,71 @@ skip-if(Android)                        
 skip-if(Android)                                                                                                        == webgl-color-test.html?frame=1&__&________&premult&_____ wrapper.html?colors-no-alpha.png
 skip-if(Android)                                                                                                        == webgl-color-test.html?frame=1&aa&________&premult&_____ wrapper.html?colors-no-alpha.png
 skip-if(Android)                                                                                                        == webgl-color-test.html?frame=1&__&preserve&premult&_____ wrapper.html?colors-no-alpha.png
 skip-if(Android)                                                                                                        == webgl-color-test.html?frame=1&aa&preserve&premult&_____ wrapper.html?colors-no-alpha.png
 fuzzy(1,30000) fails-if(winWidget&&layersGPUAccelerated&&!d3d11) skip-if(Android)                                       == webgl-color-test.html?frame=1&__&________&_______&alpha wrapper.html?colors-non-premult.png
 fuzzy(1,30000) fails-if(winWidget&&layersGPUAccelerated&&!d3d11) skip-if(Android)                                       == webgl-color-test.html?frame=1&aa&________&_______&alpha wrapper.html?colors-non-premult.png
 fuzzy(1,30000) fails-if(winWidget&&layersGPUAccelerated&&!d3d11) skip-if(Android)                                       == webgl-color-test.html?frame=1&__&preserve&_______&alpha wrapper.html?colors-non-premult.png
 fuzzy(1,30000) fails-if(winWidget&&layersGPUAccelerated&&!d3d11) skip-if(Android)                                       == webgl-color-test.html?frame=1&aa&preserve&_______&alpha wrapper.html?colors-non-premult.png
-skip-if(Android)                                                                                                        == webgl-color-test.html?frame=1&__&________&premult&alpha wrapper.html?colors-premult.png
-skip-if(Android)                                                                                                        == webgl-color-test.html?frame=1&aa&________&premult&alpha wrapper.html?colors-premult.png
-skip-if(Android)                                                                                                        == webgl-color-test.html?frame=1&__&preserve&premult&alpha wrapper.html?colors-premult.png
-skip-if(Android)                                                                                                        == webgl-color-test.html?frame=1&aa&preserve&premult&alpha wrapper.html?colors-premult.png
+skip-if(Android)                                                                                                        fails-if(webrender) == webgl-color-test.html?frame=1&__&________&premult&alpha wrapper.html?colors-premult.png
+skip-if(Android)                                                                                                        fails-if(webrender) == webgl-color-test.html?frame=1&aa&________&premult&alpha wrapper.html?colors-premult.png
+skip-if(Android)                                                                                                        fails-if(webrender) == webgl-color-test.html?frame=1&__&preserve&premult&alpha wrapper.html?colors-premult.png
+skip-if(Android)                                                                                                        fails-if(webrender) == webgl-color-test.html?frame=1&aa&preserve&premult&alpha wrapper.html?colors-premult.png
 
 skip-if(Android)                                                                                                        == webgl-color-test.html?frame=6&__&________&_______&_____ wrapper.html?colors-no-alpha.png
 skip-if(Android)                                                                                                        == webgl-color-test.html?frame=6&aa&________&_______&_____ wrapper.html?colors-no-alpha.png
 skip-if(Android)                                                                                                        == webgl-color-test.html?frame=6&__&preserve&_______&_____ wrapper.html?colors-no-alpha.png
 skip-if(Android)                                                                                                        == webgl-color-test.html?frame=6&aa&preserve&_______&_____ wrapper.html?colors-no-alpha.png
 skip-if(Android)                                                                                                        == webgl-color-test.html?frame=6&__&________&premult&_____ wrapper.html?colors-no-alpha.png
 skip-if(Android)                                                                                                        == webgl-color-test.html?frame=6&aa&________&premult&_____ wrapper.html?colors-no-alpha.png
 skip-if(Android)                                                                                                        == webgl-color-test.html?frame=6&__&preserve&premult&_____ wrapper.html?colors-no-alpha.png
 skip-if(Android)                                                                                                        == webgl-color-test.html?frame=6&aa&preserve&premult&_____ wrapper.html?colors-no-alpha.png
 fuzzy(1,30000) fails-if(winWidget&&layersGPUAccelerated&&!d3d11) skip-if(Android)                                       == webgl-color-test.html?frame=6&__&________&_______&alpha wrapper.html?colors-non-premult.png
 fuzzy(1,30000) fails-if(winWidget&&layersGPUAccelerated&&!d3d11) skip-if(Android)                                       == webgl-color-test.html?frame=6&aa&________&_______&alpha wrapper.html?colors-non-premult.png
 fuzzy(1,30000) fails-if(winWidget&&layersGPUAccelerated&&!d3d11) skip-if(Android)                                       == webgl-color-test.html?frame=6&__&preserve&_______&alpha wrapper.html?colors-non-premult.png
 fuzzy(1,30000) fails-if(winWidget&&layersGPUAccelerated&&!d3d11) skip-if(Android)                                       == webgl-color-test.html?frame=6&aa&preserve&_______&alpha wrapper.html?colors-non-premult.png
-skip-if(Android)                                                                                                        == webgl-color-test.html?frame=6&__&________&premult&alpha wrapper.html?colors-premult.png
-skip-if(Android)                                                                                                        == webgl-color-test.html?frame=6&aa&________&premult&alpha wrapper.html?colors-premult.png
-skip-if(Android)                                                                                                        == webgl-color-test.html?frame=6&__&preserve&premult&alpha wrapper.html?colors-premult.png
-skip-if(Android)                                                                                                        == webgl-color-test.html?frame=6&aa&preserve&premult&alpha wrapper.html?colors-premult.png
+skip-if(Android)                                                                                                        fails-if(webrender) == webgl-color-test.html?frame=6&__&________&premult&alpha wrapper.html?colors-premult.png
+skip-if(Android)                                                                                                        fails-if(webrender) == webgl-color-test.html?frame=6&aa&________&premult&alpha wrapper.html?colors-premult.png
+skip-if(Android)                                                                                                        fails-if(webrender) == webgl-color-test.html?frame=6&__&preserve&premult&alpha wrapper.html?colors-premult.png
+skip-if(Android)                                                                                                        fails-if(webrender) == webgl-color-test.html?frame=6&aa&preserve&premult&alpha wrapper.html?colors-premult.png
 
 skip-if(Android)                                                                 pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=1&readback&__&________&_______&_____ wrapper.html?colors-no-alpha.png
 skip-if(Android)                                                                 pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=1&readback&aa&________&_______&_____ wrapper.html?colors-no-alpha.png
 skip-if(Android)                                                                 pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=1&readback&__&preserve&_______&_____ wrapper.html?colors-no-alpha.png
 skip-if(Android)                                                                 pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=1&readback&aa&preserve&_______&_____ wrapper.html?colors-no-alpha.png
 skip-if(Android)                                                                 pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=1&readback&__&________&premult&_____ wrapper.html?colors-no-alpha.png
 skip-if(Android)                                                                 pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=1&readback&aa&________&premult&_____ wrapper.html?colors-no-alpha.png
 skip-if(Android)                                                                 pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=1&readback&__&preserve&premult&_____ wrapper.html?colors-no-alpha.png
 skip-if(Android)                                                                 pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=1&readback&aa&preserve&premult&_____ wrapper.html?colors-no-alpha.png
 fuzzy(1,30000) fails-if(winWidget&&layersGPUAccelerated&&!d3d11) skip-if(Android) pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=1&readback&__&________&_______&alpha wrapper.html?colors-non-premult.png
 fuzzy(1,30000) fails-if(winWidget&&layersGPUAccelerated&&!d3d11) skip-if(Android) pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=1&readback&aa&________&_______&alpha wrapper.html?colors-non-premult.png
 fuzzy(1,30000) fails-if(winWidget&&layersGPUAccelerated&&!d3d11) skip-if(Android) pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=1&readback&__&preserve&_______&alpha wrapper.html?colors-non-premult.png
 fuzzy(1,30000) fails-if(winWidget&&layersGPUAccelerated&&!d3d11) skip-if(Android) pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=1&readback&aa&preserve&_______&alpha wrapper.html?colors-non-premult.png
-skip-if(Android)                                                                 pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=1&readback&__&________&premult&alpha wrapper.html?colors-premult.png
-skip-if(Android)                                                                 pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=1&readback&aa&________&premult&alpha wrapper.html?colors-premult.png
-skip-if(Android)                                                                 pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=1&readback&__&preserve&premult&alpha wrapper.html?colors-premult.png
-skip-if(Android)                                                                 pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=1&readback&aa&preserve&premult&alpha wrapper.html?colors-premult.png
+skip-if(Android)                                                                 pref(webgl.force-layers-readback,true) fails-if(webrender) == webgl-color-test.html?frame=1&readback&__&________&premult&alpha wrapper.html?colors-premult.png
+skip-if(Android)                                                                 pref(webgl.force-layers-readback,true) fails-if(webrender) == webgl-color-test.html?frame=1&readback&aa&________&premult&alpha wrapper.html?colors-premult.png
+skip-if(Android)                                                                 pref(webgl.force-layers-readback,true) fails-if(webrender) == webgl-color-test.html?frame=1&readback&__&preserve&premult&alpha wrapper.html?colors-premult.png
+skip-if(Android)                                                                 pref(webgl.force-layers-readback,true) fails-if(webrender) == webgl-color-test.html?frame=1&readback&aa&preserve&premult&alpha wrapper.html?colors-premult.png
 
 skip-if(Android)                                                                 pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=6&readback&__&________&_______&_____ wrapper.html?colors-no-alpha.png
 skip-if(Android)                                                                 pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=6&readback&aa&________&_______&_____ wrapper.html?colors-no-alpha.png
 skip-if(Android)                                                                 pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=6&readback&__&preserve&_______&_____ wrapper.html?colors-no-alpha.png
 skip-if(Android)                                                                 pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=6&readback&aa&preserve&_______&_____ wrapper.html?colors-no-alpha.png
 skip-if(Android)                                                                 pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=6&readback&__&________&premult&_____ wrapper.html?colors-no-alpha.png
 skip-if(Android)                                                                 pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=6&readback&aa&________&premult&_____ wrapper.html?colors-no-alpha.png
 skip-if(Android)                                                                 pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=6&readback&__&preserve&premult&_____ wrapper.html?colors-no-alpha.png
 skip-if(Android)                                                                 pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=6&readback&aa&preserve&premult&_____ wrapper.html?colors-no-alpha.png
 fuzzy(1,30000) fails-if(winWidget&&layersGPUAccelerated&&!d3d11) skip-if(Android) pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=6&readback&__&________&_______&alpha wrapper.html?colors-non-premult.png
 fuzzy(1,30000) fails-if(winWidget&&layersGPUAccelerated&&!d3d11) skip-if(Android) pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=6&readback&aa&________&_______&alpha wrapper.html?colors-non-premult.png
 fuzzy(1,30000) fails-if(winWidget&&layersGPUAccelerated&&!d3d11) skip-if(Android) pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=6&readback&__&preserve&_______&alpha wrapper.html?colors-non-premult.png
 fuzzy(1,30000) fails-if(winWidget&&layersGPUAccelerated&&!d3d11) skip-if(Android) pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=6&readback&aa&preserve&_______&alpha wrapper.html?colors-non-premult.png
-skip-if(Android)                                                                 pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=6&readback&__&________&premult&alpha wrapper.html?colors-premult.png
-skip-if(Android)                                                                 pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=6&readback&aa&________&premult&alpha wrapper.html?colors-premult.png
-skip-if(Android)                                                                 pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=6&readback&__&preserve&premult&alpha wrapper.html?colors-premult.png
-skip-if(Android)                                                                 pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=6&readback&aa&preserve&premult&alpha wrapper.html?colors-premult.png
+skip-if(Android)                                                                 pref(webgl.force-layers-readback,true) fails-if(webrender) == webgl-color-test.html?frame=6&readback&__&________&premult&alpha wrapper.html?colors-premult.png
+skip-if(Android)                                                                 pref(webgl.force-layers-readback,true) fails-if(webrender) == webgl-color-test.html?frame=6&readback&aa&________&premult&alpha wrapper.html?colors-premult.png
+skip-if(Android)                                                                 pref(webgl.force-layers-readback,true) fails-if(webrender) == webgl-color-test.html?frame=6&readback&__&preserve&premult&alpha wrapper.html?colors-premult.png
+skip-if(Android)                                                                 pref(webgl.force-layers-readback,true) fails-if(webrender) == webgl-color-test.html?frame=6&readback&aa&preserve&premult&alpha wrapper.html?colors-premult.png
 
 # Check for hanging bindings/state settings:
 skip-if(Android) == webgl-hanging-fb-test.html?__&________  wrapper.html?green.png
 skip-if(Android) == webgl-hanging-fb-test.html?aa&________  wrapper.html?green.png
 skip-if(Android) == webgl-hanging-fb-test.html?__&preserve  wrapper.html?green.png
 skip-if(Android) == webgl-hanging-fb-test.html?aa&preserve  wrapper.html?green.png
 skip-if(Android) pref(webgl.force-layers-readback,true)  == webgl-hanging-fb-test.html?readback&__&________  wrapper.html?green.png
 skip-if(Android) pref(webgl.force-layers-readback,true)  == webgl-hanging-fb-test.html?readback&aa&________  wrapper.html?green.png
@@ -152,22 +152,22 @@ skip-if(!winWidget) pref(webgl.disable-a
 # Bug 1255062
 == clip-multiple-move-1.html clip-multiple-move-1-ref.html
 == clip-multiple-move-2.html clip-multiple-move-2-ref.html
 
 # Bug 815648
 == stroketext-shadow.html stroketext-shadow-ref.html
 
 # focus rings
-pref(canvas.focusring.enabled,true) skip-if(cocoaWidget) skip-if(winWidget) needs-focus == drawFocusIfNeeded.html drawFocusIfNeeded-ref.html
+pref(canvas.focusring.enabled,true) skip-if(cocoaWidget) skip-if(winWidget) needs-focus fails-if(webrender) == drawFocusIfNeeded.html drawFocusIfNeeded-ref.html
 pref(canvas.customfocusring.enabled,true) skip-if(Android||cocoaWidget||winWidget) fuzzy-if(gtkWidget,64,410) needs-focus == drawCustomFocusRing.html drawCustomFocusRing-ref.html
 
 # Check that captureStream() displays in a local video element
 == capturestream.html wrapper.html?green.png
 
-fuzzy-if(azureSkia,16,2) fuzzy-if(Android,3,40) fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu),1,1) == 1177726-text-stroke-bounds.html 1177726-text-stroke-bounds-ref.html
+fuzzy-if(azureSkia,16,2) fuzzy-if(Android,3,40) fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu),1,1) fails-if(webrender) == 1177726-text-stroke-bounds.html 1177726-text-stroke-bounds-ref.html
 
 # Canvas Filter Reftests
 include filters/reftest.list
 
 # Bug 1305963
 == mozCurrentTransform.html mozCurrentTransform-ref.html
 == mozCurrentTransformInverse.html mozCurrentTransform-ref.html
--- a/dom/html/reftests/reftest.list
+++ b/dom/html/reftests/reftest.list
@@ -57,9 +57,9 @@ fuzzy(3,640) == bug917595-exif-rotated.j
 == table-border-2.html table-border-2-ref.html
 != table-border-2.html table-border-2-notref.html
 
 # Test imageset is using permissions.default.image
 pref(permissions.default.image,1) HTTP == bug1196784-with-srcset.html bug1196784-no-srcset.html
 pref(permissions.default.image,2) HTTP == bug1196784-with-srcset.html bug1196784-no-srcset.html
 
 # Test video with rotation information can be rotated.
-== bug1228601-video-rotation-90.html bug1228601-video-rotated-ref.html
+fails-if(webrender) == bug1228601-video-rotation-90.html bug1228601-video-rotated-ref.html
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -31,16 +31,17 @@
 #include "mozilla/layers/APZEventState.h"
 #include "mozilla/layers/ContentProcessController.h"
 #include "mozilla/layers/CompositorBridgeChild.h"
 #include "mozilla/layers/DoubleTapToZoom.h"
 #include "mozilla/layers/IAPZCTreeManager.h"
 #include "mozilla/layers/ImageBridgeChild.h"
 #include "mozilla/layers/InputAPZContext.h"
 #include "mozilla/layers/ShadowLayers.h"
+#include "mozilla/layers/WebRenderLayerManager.h"
 #include "mozilla/layout/RenderFrameChild.h"
 #include "mozilla/layout/RenderFrameParent.h"
 #include "mozilla/LookAndFeel.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/Move.h"
 #include "mozilla/PresShell.h"
 #include "mozilla/ProcessHangMonitor.h"
 #include "mozilla/ScopeExit.h"
@@ -421,16 +422,24 @@ TabChild::TabChild(nsIContentChild* aMan
     }
   }
 
   for (uint32_t idx = 0; idx < NUMBER_OF_AUDIO_CHANNELS; idx++) {
     mAudioChannelsActive.AppendElement(false);
   }
 }
 
+const CompositorOptions&
+TabChild::GetCompositorOptions() const
+{
+  // If you're calling this before mCompositorOptions is set, well.. don't.
+  MOZ_ASSERT(mCompositorOptions);
+  return mCompositorOptions.ref();
+}
+
 bool
 TabChild::AsyncPanZoomEnabled() const
 {
   // By the time anybody calls this, we must have had InitRenderingState called
   // already, and so mCompositorOptions should be populated.
   MOZ_RELEASE_ASSERT(mCompositorOptions);
   return mCompositorOptions->UseAPZ();
 }
@@ -2379,37 +2388,41 @@ TabChild::RecvSetDocShellIsActive(const 
   // channel and the PContent channel, we have an ordering problem. This code
   // ensures that we respect the order in which the requests were made and
   // ignore stale requests.
   if (mLayerObserverEpoch >= aLayerObserverEpoch) {
     return IPC_OK();
   }
   mLayerObserverEpoch = aLayerObserverEpoch;
 
-  MOZ_ASSERT(mPuppetWidget);
-  MOZ_ASSERT(mPuppetWidget->GetLayerManager());
-  MOZ_ASSERT(mPuppetWidget->GetLayerManager()->GetBackendType() ==
-             LayersBackend::LAYERS_CLIENT);
-
   auto clearForcePaint = MakeScopeExit([&] {
     // We might force a paint, or we might already have painted and this is a
     // no-op. In either case, once we exit this scope, we need to alert the
     // ProcessHangMonitor that we've finished responding to what might have
     // been a request to force paint. This is so that the BackgroundHangMonitor
     // for force painting can be made to wait again.
     if (aIsActive) {
       ProcessHangMonitor::ClearForcePaint();
     }
   });
 
-  // We send the current layer observer epoch to the compositor so that
-  // TabParent knows whether a layer update notification corresponds to the
-  // latest SetDocShellIsActive request that was made.
-  if (ClientLayerManager* clm = mPuppetWidget->GetLayerManager()->AsClientLayerManager()) {
-    clm->SetLayerObserverEpoch(aLayerObserverEpoch);
+  if (mCompositorOptions) {
+    // Note that |GetLayerManager()| has side-effects in that it creates a layer
+    // manager if one doesn't exist already. Calling it inside a debug-only
+    // assertion is generally bad but in this case we call it unconditionally
+    // just below so it's ok.
+    MOZ_ASSERT(mPuppetWidget);
+    MOZ_ASSERT(mPuppetWidget->GetLayerManager());
+    MOZ_ASSERT(mPuppetWidget->GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_CLIENT
+            || mPuppetWidget->GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_WR);
+
+    // We send the current layer observer epoch to the compositor so that
+    // TabParent knows whether a layer update notification corresponds to the
+    // latest SetDocShellIsActive request that was made.
+    mPuppetWidget->GetLayerManager()->SetLayerObserverEpoch(aLayerObserverEpoch);
   }
 
   // docshell is consider prerendered only if not active yet
   mIsPrerendered &= !aIsActive;
   nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
   if (docShell) {
     bool wasActive;
     docShell->GetIsActive(&wasActive);
@@ -2592,19 +2605,26 @@ TabChild::InitRenderingState(const Textu
       sTabChildren->Put(aLayersId, this);
       mLayersId = aLayersId;
     }
 
     ShadowLayerForwarder* lf =
         mPuppetWidget->GetLayerManager(
             nullptr, mTextureFactoryIdentifier.mParentBackend)
                 ->AsShadowForwarder();
-    // As long as we are creating a ClientLayerManager for the puppet widget,
-    // lf must be non-null here.
-    MOZ_ASSERT(lf);
+
+    LayerManager* lm = mPuppetWidget->GetLayerManager();
+    if (lm->AsWebRenderLayerManager()) {
+      lm->AsWebRenderLayerManager()->Initialize(compositorChild,
+                                                aLayersId,
+                                                &mTextureFactoryIdentifier);
+      ImageBridgeChild::IdentifyCompositorTextureHost(mTextureFactoryIdentifier);
+      gfx::VRManagerChild::IdentifyTextureHost(mTextureFactoryIdentifier);
+      InitAPZState();
+    }
 
     if (lf) {
       nsTArray<LayersBackend> backends;
       backends.AppendElement(mTextureFactoryIdentifier.mParentBackend);
       bool success;
       PLayerTransactionChild* shadowManager =
           compositorChild->SendPLayerTransactionConstructor(backends,
                                                             aLayersId, &mTextureFactoryIdentifier, &success);
@@ -2897,22 +2917,20 @@ TabChild::GetFrom(uint64_t aLayersId)
 
 void
 TabChild::DidComposite(uint64_t aTransactionId,
                        const TimeStamp& aCompositeStart,
                        const TimeStamp& aCompositeEnd)
 {
   MOZ_ASSERT(mPuppetWidget);
   MOZ_ASSERT(mPuppetWidget->GetLayerManager());
-  MOZ_ASSERT(mPuppetWidget->GetLayerManager()->GetBackendType() ==
-               LayersBackend::LAYERS_CLIENT);
-
-  RefPtr<ClientLayerManager> manager = mPuppetWidget->GetLayerManager()->AsClientLayerManager();
-
-  manager->DidComposite(aTransactionId, aCompositeStart, aCompositeEnd);
+  MOZ_ASSERT(mPuppetWidget->GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_CLIENT
+             || mPuppetWidget->GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_WR);
+
+  mPuppetWidget->GetLayerManager()->DidComposite(aTransactionId, aCompositeStart, aCompositeEnd);
 }
 
 void
 TabChild::DidRequestComposite(const TimeStamp& aCompositeReqStart,
                               const TimeStamp& aCompositeReqEnd)
 {
   nsCOMPtr<nsIDocShell> docShellComPtr = do_GetInterface(WebNavigation());
   if (!docShellComPtr) {
@@ -2936,30 +2954,29 @@ TabChild::DidRequestComposite(const Time
   }
 }
 
 void
 TabChild::ClearCachedResources()
 {
   MOZ_ASSERT(mPuppetWidget);
   MOZ_ASSERT(mPuppetWidget->GetLayerManager());
-  MOZ_ASSERT(mPuppetWidget->GetLayerManager()->GetBackendType() ==
-               LayersBackend::LAYERS_CLIENT);
-
-  ClientLayerManager *manager = mPuppetWidget->GetLayerManager()->AsClientLayerManager();
-  manager->ClearCachedResources();
+  MOZ_ASSERT(mPuppetWidget->GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_CLIENT
+             || mPuppetWidget->GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_WR);
+
+  mPuppetWidget->GetLayerManager()->ClearCachedResources();
 }
 
 void
 TabChild::InvalidateLayers()
 {
   MOZ_ASSERT(mPuppetWidget);
   MOZ_ASSERT(mPuppetWidget->GetLayerManager());
-  MOZ_ASSERT(mPuppetWidget->GetLayerManager()->GetBackendType() ==
-               LayersBackend::LAYERS_CLIENT);
+  MOZ_ASSERT(mPuppetWidget->GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_CLIENT
+             || mPuppetWidget->GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_WR);
 
   RefPtr<LayerManager> lm = mPuppetWidget->GetLayerManager();
   FrameLayerBuilder::InvalidateAllLayers(lm);
 }
 
 void
 TabChild::ReinitRendering()
 {
@@ -3008,23 +3025,24 @@ TabChild::ReinitRendering()
   nsCOMPtr<nsIDocument> doc(GetDocument());
   doc->NotifyLayerManagerRecreated();
 }
 
 void
 TabChild::CompositorUpdated(const TextureFactoryIdentifier& aNewIdentifier,
                             uint64_t aDeviceResetSeqNo)
 {
+  MOZ_ASSERT(mPuppetWidget->GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_CLIENT
+             || mPuppetWidget->GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_WR);
+
   RefPtr<LayerManager> lm = mPuppetWidget->GetLayerManager();
-  ClientLayerManager* clm = lm->AsClientLayerManager();
-  MOZ_ASSERT(clm);
 
   mTextureFactoryIdentifier = aNewIdentifier;
-  clm->UpdateTextureFactoryIdentifier(aNewIdentifier, aDeviceResetSeqNo);
-  FrameLayerBuilder::InvalidateAllLayers(clm);
+  lm->UpdateTextureFactoryIdentifier(aNewIdentifier, aDeviceResetSeqNo);
+  FrameLayerBuilder::InvalidateAllLayers(lm);
 }
 
 NS_IMETHODIMP
 TabChild::OnShowTooltip(int32_t aXCoords, int32_t aYCoords, const char16_t *aTipText,
                         const char16_t *aTipDir)
 {
     nsString str(aTipText);
     nsString dir(aTipDir);
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -616,16 +616,17 @@ public:
 
   bool IPCOpen() const { return mIPCOpen; }
 
   bool ParentIsActive() const
   {
     return mParentIsActive;
   }
 
+  const mozilla::layers::CompositorOptions& GetCompositorOptions() const;
   bool AsyncPanZoomEnabled() const;
 
   virtual ScreenIntSize GetInnerSize() override;
 
   // Call RecvShow(nsIntSize(0, 0)) and block future calls to RecvShow().
   void DoFakeShow(const TextureFactoryIdentifier& aTextureFactoryIdentifier,
                   const uint64_t& aLayersId,
                   PRenderFrameChild* aRenderFrame,
--- a/dom/media/test/crashtests/crashtests.list
+++ b/dom/media/test/crashtests/crashtests.list
@@ -5,17 +5,17 @@ load 466945-1.html
 load 468763-1.html
 load 474744-1.html
 asserts-if(stylo,8) HTTP load 481136-1.html # bug 1324671 # needs to be HTTP to recognize the ogg as an audio file?
 load 492286-1.xhtml
 load 493915-1.html
 load 495794-1.html
 load 576612-1.html
 load 752784-1.html
-load 789075-1.html
+skip-if(webrender) load 789075-1.html # bug 1322816 for webrender
 HTTP load 795892-1.html
 load 844563.html
 load 846612.html
 load 852838.html
 load 865537-1.html
 load 868504.html
 load 874869.html
 load 874915.html
--- a/dom/plugins/test/reftest/reftest.list
+++ b/dom/plugins/test/reftest/reftest.list
@@ -1,26 +1,27 @@
 # basic sanity checking
 random-if(!haveTestPlugin) != plugin-sanity.html about:blank
 fails-if(!haveTestPlugin) == plugin-sanity.html div-sanity.html
-fails-if(!haveTestPlugin) fuzzy-if(skiaContent&&haveTestPlugin,1,160000) == plugin-alpha-zindex.html div-alpha-zindex.html
-fails-if(!haveTestPlugin) fuzzy-if(skiaContent&&haveTestPlugin,1,164000) == plugin-alpha-opacity.html div-alpha-opacity.html
+fails-if(!haveTestPlugin) fuzzy-if(skiaContent&&haveTestPlugin,1,160000) fails-if(webrender) == plugin-alpha-zindex.html div-alpha-zindex.html
+fails-if(!haveTestPlugin) fuzzy-if(skiaContent&&haveTestPlugin,1,164000) fails-if(webrender) == plugin-alpha-opacity.html div-alpha-opacity.html
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) == windowless-clipping-1.html windowless-clipping-1-ref.html # bug 631832
 # fuzzy because of anti-aliasing in dashed border
-fuzzy(16,256) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) == border-padding-1.html border-padding-1-ref.html # bug 629430
+fuzzy(16,256) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) fails-if(webrender) == border-padding-1.html border-padding-1-ref.html # bug 629430
 fuzzy(16,256) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) == border-padding-2.html border-padding-2-ref.html # bug 629430
-fuzzy(16,256) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) skip-if(!haveTestPlugin||Android) == border-padding-3.html border-padding-3-ref.html # bug 629430 # bug 773482
+skip-if(!webrender) pref(layers.advanced.border-layers,true) fuzzy(16,256) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) == border-padding-2.html border-padding-2-ref.html
+fuzzy(16,256) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) skip-if(!haveTestPlugin||Android) fails-if(webrender) == border-padding-3.html border-padding-3-ref.html # bug 629430 # bug 773482
 # The following two "pluginproblemui-direction" tests are unreliable on all platforms. They should be re-written or replaced.
 #random-if(cocoaWidget||d2d||/^Windows\x20NT\x205\.1/.test(http.oscpu)) fails-if(!haveTestPlugin&&!Android) == pluginproblemui-direction-1.html pluginproblemui-direction-1-ref.html # bug 567367
 #random-if(cocoaWidget) fails-if(!haveTestPlugin&&!Android) == pluginproblemui-direction-2.html pluginproblemui-direction-2-ref.html
-fails-if(!haveTestPlugin) fuzzy-if(skiaContent&&haveTestPlugin,1,160000) == plugin-canvas-alpha-zindex.html div-alpha-zindex.html
-fails-if(!haveTestPlugin) fuzzy-if(skiaContent&&haveTestPlugin,1,160000) == plugin-transform-alpha-zindex.html div-alpha-zindex.html
-random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) fuzzy-if(skiaContent&&haveTestPlugin,1,160000) == plugin-busy-alpha-zindex.html div-alpha-zindex.html
-random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) fuzzy-if(skiaContent&&haveTestPlugin,1,32400) == plugin-background.html plugin-background-ref.html
-random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) fuzzy-if(skiaContent&&haveTestPlugin,1,32400) == plugin-background-1-step.html plugin-background-ref.html
-random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) fuzzy-if(skiaContent&&haveTestPlugin,1,32400) == plugin-background-2-step.html plugin-background-ref.html
-random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) fuzzy-if(skiaContent&&haveTestPlugin,1,32400) == plugin-background-5-step.html plugin-background-ref.html
-random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) fuzzy-if(skiaContent&&haveTestPlugin,1,32400) == plugin-background-10-step.html plugin-background-ref.html
+fails-if(!haveTestPlugin) fuzzy-if(skiaContent&&haveTestPlugin,1,160000) fails-if(webrender) == plugin-canvas-alpha-zindex.html div-alpha-zindex.html
+fails-if(!haveTestPlugin) fuzzy-if(skiaContent&&haveTestPlugin,1,160000) fails-if(webrender) == plugin-transform-alpha-zindex.html div-alpha-zindex.html
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) fuzzy-if(skiaContent&&haveTestPlugin,1,160000) fails-if(webrender) == plugin-busy-alpha-zindex.html div-alpha-zindex.html
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) fuzzy-if(skiaContent&&haveTestPlugin,1,32400) fails-if(webrender) == plugin-background.html plugin-background-ref.html
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) fuzzy-if(skiaContent&&haveTestPlugin,1,32400) fails-if(webrender) == plugin-background-1-step.html plugin-background-ref.html
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) fuzzy-if(skiaContent&&haveTestPlugin,1,32400) fails-if(webrender) == plugin-background-2-step.html plugin-background-ref.html
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) fuzzy-if(skiaContent&&haveTestPlugin,1,32400) fails-if(webrender) == plugin-background-5-step.html plugin-background-ref.html
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) fuzzy-if(skiaContent&&haveTestPlugin,1,32400) fails-if(webrender) == plugin-background-10-step.html plugin-background-ref.html
 random-if(!haveTestPlugin) == plugin-transform-1.html plugin-transform-1-ref.html
-fails-if(!haveTestPlugin) == plugin-transform-2.html plugin-transform-2-ref.html
+fails-if(!haveTestPlugin) fails-if(webrender) == plugin-transform-2.html plugin-transform-2-ref.html
 skip-if(!haveTestPlugin) == shrink-1.html shrink-1-ref.html
 skip-if(!haveTestPlugin) == update-1.html update-1-ref.html
 skip-if(!haveTestPlugin) == windowless-layers.html windowless-layers-ref.html
--- a/gfx/2d/2D.h
+++ b/gfx/2d/2D.h
@@ -746,16 +746,18 @@ public:
   virtual void GetGlyphDesignMetrics(const uint16_t* aGlyphIndices, uint32_t aNumGlyphs, GlyphMetrics* aGlyphMetrics) = 0;
 
   virtual bool GetFontFileData(FontFileDataOutput, void *) { return false; }
 
   virtual bool GetFontInstanceData(FontInstanceDataOutput, void *) { return false; }
 
   virtual bool GetFontDescriptor(FontDescriptorOutput, void *) { return false; }
 
+  virtual bool CanSerialize() { return false; }
+
   void AddUserData(UserDataKey *key, void *userData, void (*destroy)(void*)) {
     mUserData.Add(key, userData, destroy);
   }
   void *GetUserData(UserDataKey *key) {
     return mUserData.Get(key);
   }
 
 protected:
--- a/gfx/2d/ScaledFontDWrite.cpp
+++ b/gfx/2d/ScaledFontDWrite.cpp
@@ -223,16 +223,20 @@ ScaledFontDWrite::GetFontFileData(FontFi
   UINT32 fileCount = 0;
   mFontFace->GetFiles(&fileCount, nullptr);
 
   if (fileCount > 1) {
     MOZ_ASSERT(false);
     return false;
   }
 
+  if (!aDataCallback) {
+    return true;
+  }
+
   RefPtr<IDWriteFontFile> file;
   mFontFace->GetFiles(&fileCount, getter_AddRefs(file));
 
   const void *referenceKey;
   UINT32 refKeySize;
   // XXX - This can currently crash for webfonts, as when we get the reference
   // key out of the file, that can be an invalid reference key for the loader
   // we use it with. The fix to this is not obvious but it will probably 
--- a/gfx/2d/ScaledFontDWrite.h
+++ b/gfx/2d/ScaledFontDWrite.h
@@ -35,16 +35,18 @@ public:
   virtual void CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBuilder, const Matrix *aTransformHint);
 
   void CopyGlyphsToSink(const GlyphBuffer &aBuffer, ID2D1GeometrySink *aSink);
 
   virtual void GetGlyphDesignMetrics(const uint16_t* aGlyphIndices, uint32_t aNumGlyphs, GlyphMetrics* aGlyphMetrics);
 
   virtual bool GetFontFileData(FontFileDataOutput aDataCallback, void *aBaton);
 
+  virtual bool CanSerialize() override { return true; }
+
   virtual AntialiasMode GetDefaultAAMode() override;
 
   bool UseEmbeddedBitmaps() { return mUseEmbeddedBitmap; }
   bool ForceGDIMode() { return mForceGDIMode; }
 
 #ifdef USE_SKIA
   virtual SkTypeface* GetSkTypeface();
   SkFontStyle mStyle;
--- a/gfx/config/gfxFeature.h
+++ b/gfx/config/gfxFeature.h
@@ -20,16 +20,17 @@ namespace gfx {
   _(HW_COMPOSITING,               Feature,      "Compositing")                    \
   _(D3D11_COMPOSITING,            Feature,      "Direct3D11 Compositing")         \
   _(D3D9_COMPOSITING,             Feature,      "Direct3D9 Compositing")          \
   _(OPENGL_COMPOSITING,           Feature,      "OpenGL Compositing")             \
   _(DIRECT2D,                     Feature,      "Direct2D")                       \
   _(D3D11_HW_ANGLE,               Feature,      "Direct3D11 hardware ANGLE")      \
   _(DIRECT_DRAW,                  Feature,      "DirectDraw")                     \
   _(GPU_PROCESS,                  Feature,      "GPU Process")                    \
+  _(WEBRENDER,                    Feature,      "WebRender")                      \
   /* Add new entries above this comment */
 
 enum class Feature : uint32_t {
 #define MAKE_ENUM(name, type, desc) name,
   GFX_FEATURE_MAP(MAKE_ENUM)
 #undef MAKE_ENUM
   NumValues
 };
--- a/gfx/config/gfxVars.h
+++ b/gfx/config/gfxVars.h
@@ -28,16 +28,17 @@ class gfxVarReceiver;
   _(TileSize,                   IntSize,          IntSize(-1, -1))      \
   _(UseXRender,                 bool,             false)                \
   _(OffscreenFormat,            gfxImageFormat,   mozilla::gfx::SurfaceFormat::X8R8G8B8_UINT32) \
   _(RequiresAcceleratedGLContextForCompositorOGL, bool, false)          \
   _(CanUseHardwareVideoDecoding, bool,            false)                \
   _(PDMWMFDisableD3D11Dlls,     nsCString,        nsCString())          \
   _(PDMWMFDisableD3D9Dlls,      nsCString,        nsCString())          \
   _(DXInterop2Blocked,          bool,             false)                \
+  _(UseWebRender,               bool,             false)                \
 
   /* Add new entries above this line. */
 
 // Some graphics settings are computed on the UI process and must be
 // communicated to content and GPU processes. gfxVars helps facilitate
 // this. Its function is similar to gfxPrefs, except rather than hold
 // user preferences, it holds dynamically computed values.
 //
new file mode 100644
--- /dev/null
+++ b/gfx/doc/README.displayitem
@@ -0,0 +1,27 @@
+How to add a new WebRender display item from a Gecko Display item, the general flow is to:
+
+(1) Force layout to create a new active layer for the gecko display item.
+(2) Plumb the data needed for the display item from content through WebRenderBridgeParent on the parent side.
+(3) From WebRenderBridgeParent, call out into bindings.rs and implement the appropriate WR calls.
+
+More detailed steps are:
+
+1) Force layout to create an active layer for the gecko display item.
+See http://searchfox.org/mozilla-central/rev/0f254a30d684796bcc8b6e2a102a0095d25842bb/layout/generic/nsTextFrame.cpp#4983
+as an example for text layers. Ping Matt Woodrow or Markus Stange for help.
+
+The Active layer part comes from nsDisplayText::GetLayerState
+
+2) Create the new display item layer:
+
+See text layer:
+http://searchfox.org/mozilla-central/rev/0f254a30d684796bcc8b6e2a102a0095d25842bb/gfx/layers/Layers.h#2403
+
+The layer should have all the information to display the item.
+
+3) Create the WebRender equivalent layer. In YourLayerType::RenderLayer, serialize the data needed for the layer type.
+4) If you need to add a custom IPC serialization mechanism, do it in WebRenderMessageUtils.h
+5) Create a WebRender command to process the new layer type in WebRenderMessages.ipdlh. These are the struct OpDPPushYourLayerTypeHere
+6) Add a new function in WebRender.h that will call out into webrender to render your display item.
+7) In WebRenderBridgeParent::ProcessWebRenderCommands, call out to the new function in (6).
+8) Fill out the function in (6) in bindings.rs to make webrender do the right thing. Generally, it's just push a display item.
new file mode 100644
--- /dev/null
+++ b/gfx/doc/README.webrender
@@ -0,0 +1,82 @@
+Step 1: Install Rust if you don't have it already
+    If you are doing gecko builds already, you should already have Rust as it is a build requirement.
+    If not, you can install it using |mach bootstrap| (recommended) or from https://www.rust-lang.org/
+        Note: If installing manually, use the stable 64-bit release - on Windows make sure to use the MSVC ABI installer.
+    Ensure that rustc and cargo are in your $PATH (adding $HOME/.cargo/bin/ should be sufficient)
+
+Step 2: Set up mozconfig
+    Add the following line to your mozconfig:
+        ac_add_options --enable-webrender
+    The first time you do a build with this changes, you should also run |mach clobber|
+
+Step 3:
+    Build using |mach build|
+
+
+When making changes:
+    - Make the changes you want.
+    - Run |mach build| or |mach build binaries| as desired.
+
+
+For a debug webrender build:
+    Use a debug mozconfig (ac_add_options --enable-debug)
+    You can also use an opt build but make webrender less optimized by putting opt-level=0 in the [profile.release] section of your toolkit/library/rust/Cargo.toml file
+    See also https://groups.google.com/forum/#!topic/mozilla.dev.servo/MbeMcqqO1fs
+
+
+What if you have to pull in an update to webrender itself?
+
+1) Update your graphics branch checkout to the latest code on the
+   graphics branch
+2) Check out and update the webrender repo to the version you want
+3) Copy over the webrender and webrender_traits folders into gfx/. The best way
+   to do this is to simply delete the gfx/webrender and gfx/webrender_traits
+   folders and use |cp -R| to copy them in again from the webrender repo. Update
+   the "latest commit" information at the bottom of this file with the version.
+4) If you need to modify webrender_bindings/Cargo.toml to include or remove
+   features, do so now.
+4) Commit your changes to the graphics branch locally
+5) Run |mach vendor rust| to update the rust dependencies in third_party/rust
+6) Commit the vendored changes locally
+7) Build and test. You may need to make changes in bindings.rs or on
+   the C++ side depending on what changed in webrender. This can
+   potentially be quite tricky if you don't fully understand the API
+   changes on the webrender side. In this step, try to not use your new
+   features yet, just get the build working with the minimal changes.
+8) Commit the changes locally from step 7, and push everything to the
+   graphics branch.
+9) Now you have an update webrender with the new features you wanted,
+   so you can write gecko code against them.
+
+Yes, this is somewhat painful. It used to be worse. :)
+
+Note that when webrender is built as part of gecko, it may end up using slightly
+different versions of its dependencies than when it is built standalone from the
+webrender repo. The reason is that the Cargo.lock files in m-c and in the WR
+repo may reference different versions of the dependencies. Both builds will be
+compatible in terms of semantic versioning, but may produce different results -
+for example the standalone webrender might use euclid 0.10.4 while the
+one in gecko uses euclid 0.10.3. Although both choices are "valid" per
+the semantic versioning rules in webrender's Cargo.toml, the 0.2.3 may provide
+a bugfix that is needed for correct behaviour in webrender. If this is the case,
+the technically "correct" fix is to change the upstream webrender Cargo.toml
+file to require the correct version. Alternnatively, you can update the
+Cargo.lock files in m-c to pull in the new version. The way to do this is as
+follows:
+- Go to toolkit/library/rust and run |cargo update -p <package> --precise <version>|.
+  Repeat this for as many libraries as you need to update. Run the same commands
+  in toolkit/library/gtest/rust and js/src (ignore any errors about unmatched
+  packages). Commit all the changes locally.
+- Run |mach vendor rust|, which will update the corresponding libraries in
+  third_party/rust to the versions you specified.
+The reason we don't do this by default is to work around bug 1336528. Specifically,
+there is another crate in m-c called mozjs_sys which is built separately but uses
+the same folder to store its rust dependencies. If one of the libraries that is
+required by both mozjs_sys and webrender is updated without updating the other
+project's Cargo.lock file, that results in build bustage.
+This means that any time you do this sort of manual update of packages, you need
+to make sure that mozjs_sys also has its Cargo.lock file updated if needed, hence
+the need to run the cargo update command in js/src as well. Hopefully this will
+be resolved soon.
+
+Latest Commit: bcf3c371086894f5e1d098ee60f0592abf01f6b3
--- a/gfx/gl/GLContextGLX.h
+++ b/gfx/gl/GLContextGLX.h
@@ -29,17 +29,18 @@ public:
                     bool deleteDrawable,
                     gfxXlibSurface* pixmap = nullptr,
                     ContextProfile profile = ContextProfile::OpenGLCompatibility);
 
     // Finds a GLXFBConfig compatible with the provided window.
     static bool
     FindFBConfigForWindow(Display* display, int screen, Window window,
                           ScopedXFree<GLXFBConfig>* const out_scopedConfigArr,
-                          GLXFBConfig* const out_config, int* const out_visid);
+                          GLXFBConfig* const out_config, int* const out_visid,
+                          bool aWebRender);
 
     ~GLContextGLX();
 
     virtual GLContextType GetContextType() const override { return GLContextType::GLX; }
 
     static GLContextGLX* Cast(GLContext* gl) {
         MOZ_ASSERT(gl->GetContextType() == GLContextType::GLX);
         return static_cast<GLContextGLX*>(gl);
--- a/gfx/gl/GLContextProviderCGL.mm
+++ b/gfx/gl/GLContextProviderCGL.mm
@@ -8,16 +8,17 @@
 #include "nsDebug.h"
 #include "nsIWidget.h"
 #include <OpenGL/gl.h>
 #include "gfxFailure.h"
 #include "gfxPrefs.h"
 #include "prenv.h"
 #include "GeckoProfiler.h"
 #include "mozilla/gfx/MacIOSurface.h"
+#include "mozilla/layers/CompositorOptions.h"
 #include "mozilla/widget/CompositorWidget.h"
 
 #include <OpenGL/OpenGL.h>
 
 // When running inside a VM, creating an accelerated OpenGL context usually
 // fails. Uncomment this line to emulate that behavior.
 // #define EMULATE_VM
 
@@ -197,16 +198,26 @@ static const NSOpenGLPixelFormatAttribut
 
 static const NSOpenGLPixelFormatAttribute kAttribs_doubleBuffered_accel[] = {
     NSOpenGLPFAAccelerated,
     NSOpenGLPFAAllowOfflineRenderers,
     NSOpenGLPFADoubleBuffer,
     0
 };
 
+static const NSOpenGLPixelFormatAttribute kAttribs_doubleBuffered_accel_webrender[] = {
+    NSOpenGLPFAAccelerated,
+    NSOpenGLPFAAllowOfflineRenderers,
+    NSOpenGLPFADoubleBuffer,
+    NSOpenGLPFAOpenGLProfile,
+    NSOpenGLProfileVersion3_2Core,
+    NSOpenGLPFADepthSize, 24,
+    0
+};
+
 static const NSOpenGLPixelFormatAttribute kAttribs_offscreen[] = {
     0
 };
 
 static const NSOpenGLPixelFormatAttribute kAttribs_offscreen_allow_offline[] = {
     NSOpenGLPFAAllowOfflineRenderers,
     0
 };
@@ -238,35 +249,43 @@ CreateWithFormat(const NSOpenGLPixelForm
     [format release];
 
     return context;
 }
 
 already_AddRefed<GLContext>
 GLContextProviderCGL::CreateForCompositorWidget(CompositorWidget* aCompositorWidget, bool aForceAccelerated)
 {
-    return CreateForWindow(aCompositorWidget->RealWidget(), aForceAccelerated);
+    return CreateForWindow(aCompositorWidget->RealWidget(),
+                           aCompositorWidget->GetCompositorOptions().UseWebRender(),
+                           aForceAccelerated);
 }
 
 already_AddRefed<GLContext>
-GLContextProviderCGL::CreateForWindow(nsIWidget* aWidget, bool aForceAccelerated)
+GLContextProviderCGL::CreateForWindow(nsIWidget* aWidget,
+                                      bool aWebRender,
+                                      bool aForceAccelerated)
 {
     if (!sCGLLibrary.EnsureInitialized()) {
         return nullptr;
     }
 
 #ifdef EMULATE_VM
     if (aForceAccelerated) {
         return nullptr;
     }
 #endif
 
     const NSOpenGLPixelFormatAttribute* attribs;
     if (sCGLLibrary.UseDoubleBufferedWindows()) {
-        attribs = aForceAccelerated ? kAttribs_doubleBuffered_accel : kAttribs_doubleBuffered;
+        if (aWebRender) {
+            attribs = aForceAccelerated ? kAttribs_doubleBuffered_accel_webrender : kAttribs_doubleBuffered;
+        } else {
+            attribs = aForceAccelerated ? kAttribs_doubleBuffered_accel : kAttribs_doubleBuffered;
+        }
     } else {
         attribs = aForceAccelerated ? kAttribs_singleBuffered_accel : kAttribs_singleBuffered;
     }
     NSOpenGLContext* context = CreateWithFormat(attribs);
     if (!context) {
         return nullptr;
     }
 
--- a/gfx/gl/GLContextProviderEAGL.mm
+++ b/gfx/gl/GLContextProviderEAGL.mm
@@ -6,16 +6,17 @@
 #include "GLContextProvider.h"
 #include "GLContextEAGL.h"
 #include "nsDebug.h"
 #include "nsIWidget.h"
 #include "gfxPrefs.h"
 #include "gfxFailure.h"
 #include "prenv.h"
 #include "mozilla/Preferences.h"
+#include "mozilla/layers/CompositorOptions.h"
 #include "mozilla/widget/CompositorWidget.h"
 #include "GeckoProfiler.h"
 
 #import <UIKit/UIKit.h>
 
 namespace mozilla {
 namespace gl {
 
@@ -210,21 +211,25 @@ CreateEAGLContext(CreateContextFlags fla
     }
 
     return glContext.forget();
 }
 
 already_AddRefed<GLContext>
 GLContextProviderEAGL::CreateForCompositorWidget(CompositorWidget* aCompositorWidget, bool aForceAccelerated)
 {
-    return CreateForWindow(aCompositorWidget->RealWidget(), aForceAccelerated);
+    return CreateForWindow(aCompositorWidget->RealWidget(),
+                           aCompositorWidget->GetCompositorOptions().UseWebRender(),
+                           aForceAccelerated);
 }
 
 already_AddRefed<GLContext>
-GLContextProviderEAGL::CreateForWindow(nsIWidget* aWidget, bool aForceAccelerated)
+GLContextProviderEAGL::CreateForWindow(nsIWidget* aWidget,
+                                       bool aWebRender,
+                                       bool aForceAccelerated)
 {
     RefPtr<GLContext> glContext = CreateEAGLContext(CreateContextFlags::NONE, false,
                                                     GetGlobalContextEAGL());
     if (!glContext) {
         return nullptr;
     }
 
     if (!GLContextEAGL::Cast(glContext)->AttachToWindow(aWidget)) {
--- a/gfx/gl/GLContextProviderEGL.cpp
+++ b/gfx/gl/GLContextProviderEGL.cpp
@@ -46,16 +46,17 @@
 #include "gfxPlatform.h"
 #include "gfxUtils.h"
 #include "GLBlitHelper.h"
 #include "GLContextEGL.h"
 #include "GLContextProvider.h"
 #include "GLLibraryEGL.h"
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Preferences.h"
+#include "mozilla/layers/CompositorOptions.h"
 #include "mozilla/widget/CompositorWidget.h"
 #include "nsDebug.h"
 #include "nsIWidget.h"
 #include "nsThreadUtils.h"
 #include "ScopedGLHelpers.h"
 #include "TextureImageEGL.h"
 
 using namespace mozilla::gfx;
@@ -144,24 +145,26 @@ CreateSurfaceFromNativeWindow(EGLNativeW
 
 /* GLContextEGLFactory class was added as a friend of GLContextEGL
  * so that it could access  GLContextEGL::CreateGLContext. This was
  * done so that a new function would not need to be added to the shared
  * GLContextProvider interface.
  */
 class GLContextEGLFactory {
 public:
-    static already_AddRefed<GLContext> Create(EGLNativeWindowType aWindow);
+    static already_AddRefed<GLContext> Create(EGLNativeWindowType aWindow,
+                                              bool aWebRender);
 private:
     GLContextEGLFactory(){}
     ~GLContextEGLFactory(){}
 };
 
 already_AddRefed<GLContext>
-GLContextEGLFactory::Create(EGLNativeWindowType aWindow)
+GLContextEGLFactory::Create(EGLNativeWindowType aWindow,
+                            bool aWebRender)
 {
     MOZ_ASSERT(aWindow);
     nsCString discardFailureId;
     if (!sEGLLibrary.EnsureInitialized(false, &discardFailureId)) {
         MOZ_CRASH("GFX: Failed to load EGL library 3!\n");
         return nullptr;
     }
 
@@ -175,18 +178,22 @@ GLContextEGLFactory::Create(EGLNativeWin
 
     EGLSurface surface = mozilla::gl::CreateSurfaceFromNativeWindow(aWindow, config);
 
     if (!surface) {
         MOZ_CRASH("GFX: Failed to create EGLSurface!\n");
         return nullptr;
     }
 
+    CreateContextFlags flags = CreateContextFlags::NONE;
+    if (aWebRender) {
+        flags |= CreateContextFlags::PREFER_ES3;
+    }
     SurfaceCaps caps = SurfaceCaps::Any();
-    RefPtr<GLContextEGL> gl = GLContextEGL::CreateGLContext(CreateContextFlags::NONE,
+    RefPtr<GLContextEGL> gl = GLContextEGL::CreateGLContext(flags,
                                                             caps, nullptr, false, config,
                                                             surface, &discardFailureId);
     if (!gl) {
         MOZ_CRASH("GFX: Failed to create EGLContext!\n");
         mozilla::gl::DestroySurface(surface);
         return nullptr;
     }
 
@@ -706,24 +713,28 @@ GLContextProviderEGL::CreateWrappingExis
 
     return gl.forget();
 }
 
 already_AddRefed<GLContext>
 GLContextProviderEGL::CreateForCompositorWidget(CompositorWidget* aCompositorWidget, bool aForceAccelerated)
 {
     MOZ_ASSERT(aCompositorWidget);
-    return GLContextEGLFactory::Create(GET_NATIVE_WINDOW_FROM_COMPOSITOR_WIDGET(aCompositorWidget));
+    return GLContextEGLFactory::Create(GET_NATIVE_WINDOW_FROM_COMPOSITOR_WIDGET(aCompositorWidget),
+                                       aCompositorWidget->GetCompositorOptions().UseWebRender());
 }
 
 already_AddRefed<GLContext>
-GLContextProviderEGL::CreateForWindow(nsIWidget* aWidget, bool aForceAccelerated)
+GLContextProviderEGL::CreateForWindow(nsIWidget* aWidget,
+                                      bool aWebRender,
+                                      bool aForceAccelerated)
 {
     MOZ_ASSERT(aWidget);
-    return GLContextEGLFactory::Create(GET_NATIVE_WINDOW_FROM_REAL_WIDGET(aWidget));
+    return GLContextEGLFactory::Create(GET_NATIVE_WINDOW_FROM_REAL_WIDGET(aWidget),
+                                       aWebRender);
 }
 
 #if defined(ANDROID)
 EGLSurface
 GLContextProviderEGL::CreateEGLSurface(void* aWindow)
 {
     // NOTE: aWindow is an ANativeWindow
     nsCString discardFailureId;
--- a/gfx/gl/GLContextProviderGLX.cpp
+++ b/gfx/gl/GLContextProviderGLX.cpp
@@ -10,16 +10,17 @@
 #endif
 
 #include <X11/Xlib.h>
 #include <X11/Xutil.h>
 #include "X11UndefineNone.h"
 
 #include "mozilla/MathAlgorithms.h"
 #include "mozilla/StaticPtr.h"
+#include "mozilla/layers/CompositorOptions.h"
 #include "mozilla/widget/CompositorWidget.h"
 #include "mozilla/widget/X11CompositorWidget.h"
 #include "mozilla/Unused.h"
 
 #include "prenv.h"
 #include "GLContextProvider.h"
 #include "GLLibraryLoader.h"
 #include "nsDebug.h"
@@ -1115,17 +1116,19 @@ GLContextProviderGLX::CreateWrappingExis
 
         return glContext.forget();
     }
 
     return nullptr;
 }
 
 already_AddRefed<GLContext>
-CreateForWidget(Display* aXDisplay, Window aXWindow, bool aForceAccelerated)
+CreateForWidget(Display* aXDisplay, Window aXWindow,
+                bool aWebRender,
+                bool aForceAccelerated)
 {
     if (!sGLXLibrary.EnsureInitialized()) {
         return nullptr;
     }
 
     // Currently, we take whatever Visual the window already has, and
     // try to create an fbconfig for that visual.  This isn't
     // necessarily what we want in the long run; an fbconfig may not
@@ -1139,49 +1142,63 @@ CreateForWidget(Display* aXDisplay, Wind
     }
 
     int xscreen = DefaultScreen(aXDisplay);
 
     ScopedXFree<GLXFBConfig> cfgs;
     GLXFBConfig config;
     int visid;
     if (!GLContextGLX::FindFBConfigForWindow(aXDisplay, xscreen, aXWindow, &cfgs,
-                                             &config, &visid))
+                                             &config, &visid, aWebRender))
     {
         return nullptr;
     }
 
     SurfaceCaps caps = SurfaceCaps::Any();
     GLContextGLX* shareContext = GetGlobalContextGLX();
-    RefPtr<GLContextGLX> gl = GLContextGLX::CreateGLContext(CreateContextFlags::NONE,
-                                                            caps, shareContext, false,
-                                                            aXDisplay, aXWindow, config,
-                                                            false);
+    RefPtr<GLContextGLX> gl;
+    if (aWebRender) {
+      gl = GLContextGLX::CreateGLContext(CreateContextFlags::NONE,
+                                         caps, shareContext, false,
+                                         aXDisplay, aXWindow, config,
+                                         //TODO: we might want to pass an additional bool to select GL core/compat
+                                         false, nullptr, ContextProfile::OpenGLCore); //WR: required GL 3.2+
+    } else {
+      gl = GLContextGLX::CreateGLContext(CreateContextFlags::NONE,
+                                         caps, shareContext, false,
+                                         aXDisplay, aXWindow, config,
+                                         false);
+    }
+
     return gl.forget();
 }
 
 already_AddRefed<GLContext>
 GLContextProviderGLX::CreateForCompositorWidget(CompositorWidget* aCompositorWidget, bool aForceAccelerated)
 {
     X11CompositorWidget* compWidget = aCompositorWidget->AsX11();
     MOZ_ASSERT(compWidget);
 
     return CreateForWidget(compWidget->XDisplay(),
                            compWidget->XWindow(),
+                           compWidget->GetCompositorOptions().UseWebRender(),
                            aForceAccelerated);
 }
 
 already_AddRefed<GLContext>
-GLContextProviderGLX::CreateForWindow(nsIWidget* aWidget, bool aForceAccelerated)
+GLContextProviderGLX::CreateForWindow(nsIWidget* aWidget,
+                                      bool aWebRender,
+                                      bool aForceAccelerated)
 {
     Display* display = (Display*)aWidget->GetNativeData(NS_NATIVE_COMPOSITOR_DISPLAY);
     Window window = GET_NATIVE_WINDOW(aWidget);
 
     return CreateForWidget(display,
                            window,
+                           aWebRender,
                            aForceAccelerated);
 }
 
 static bool
 ChooseConfig(GLXLibrary* glx, Display* display, int screen, const SurfaceCaps& minCaps,
              ScopedXFree<GLXFBConfig>* const out_scopedConfigArr,
              GLXFBConfig* const out_config, int* const out_visid)
 {
@@ -1235,34 +1252,61 @@ ChooseConfig(GLXLibrary* glx, Display* d
     }
 
     return false;
 }
 
 bool
 GLContextGLX::FindFBConfigForWindow(Display* display, int screen, Window window,
                                     ScopedXFree<GLXFBConfig>* const out_scopedConfigArr,
-                                    GLXFBConfig* const out_config, int* const out_visid)
+                                    GLXFBConfig* const out_config, int* const out_visid,
+                                    bool aWebRender)
 {
     ScopedXFree<GLXFBConfig>& cfgs = *out_scopedConfigArr;
     int numConfigs;
     if (sGLXLibrary.IsATI() ||
         !sGLXLibrary.GLXVersionCheck(1, 3)) {
         const int attribs[] = {
             LOCAL_GLX_DOUBLEBUFFER, False,
             0
         };
-        cfgs = sGLXLibrary.xChooseFBConfig(display,
+        const int webrenderAttribs[] = {
+            LOCAL_GLX_DOUBLEBUFFER, False,
+            LOCAL_GLX_DEPTH_SIZE, 24,
+            0
+        };
+
+        if (aWebRender) {
+          cfgs = sGLXLibrary.xChooseFBConfig(display,
+                                             screen,
+                                             webrenderAttribs,
+                                             &numConfigs);
+        } else {
+          cfgs = sGLXLibrary.xChooseFBConfig(display,
+                                             screen,
+                                             attribs,
+                                             &numConfigs);
+        }
+    } else {
+        const int webrenderAttribs[] = {
+            LOCAL_GLX_DEPTH_SIZE, 24,
+            LOCAL_GLX_DOUBLEBUFFER, True,
+            0
+        };
+
+        if (aWebRender) {
+          cfgs = sGLXLibrary.xChooseFBConfig(display,
+                                             screen,
+                                             webrenderAttribs,
+                                             &numConfigs);
+        } else {
+          cfgs = sGLXLibrary.xGetFBConfigs(display,
                                            screen,
-                                           attribs,
                                            &numConfigs);
-    } else {
-        cfgs = sGLXLibrary.xGetFBConfigs(display,
-                                         screen,
-                                         &numConfigs);
+        }
     }
 
     if (!cfgs) {
         NS_WARNING("[GLX] glXGetFBConfigs() failed");
         return false;
     }
     NS_ASSERTION(numConfigs > 0, "No FBConfigs found!");
 
@@ -1274,37 +1318,57 @@ GLContextGLX::FindFBConfigForWindow(Disp
         NS_WARNING("[GLX] XGetWindowAttributes() failed");
         return false;
     }
     const VisualID windowVisualID = XVisualIDFromVisual(windowAttrs.visual);
 #ifdef DEBUG
     printf("[GLX] window %lx has VisualID 0x%lx\n", window, windowVisualID);
 #endif
 
-    for (int i = 0; i < numConfigs; i++) {
-        int visid = X11None;
-        sGLXLibrary.xGetFBConfigAttrib(display, cfgs[i], LOCAL_GLX_VISUAL_ID, &visid);
-        if (!visid) {
-            continue;
-        }
-        if (sGLXLibrary.IsATI()) {
+    if (aWebRender) {
+        for (int i = 0; i < numConfigs; i++) {
+            int visid = X11None;
+            sGLXLibrary.xGetFBConfigAttrib(display, cfgs[i], LOCAL_GLX_VISUAL_ID, &visid);
+            if (!visid) {
+                continue;
+            }
+
             int depth;
             Visual* visual;
             FindVisualAndDepth(display, visid, &visual, &depth);
             if (depth == windowAttrs.depth &&
                 AreCompatibleVisuals(windowAttrs.visual, visual)) {
                 *out_config = cfgs[i];
                 *out_visid = visid;
                 return true;
             }
-        } else {
-            if (windowVisualID == static_cast<VisualID>(visid)) {
-                *out_config = cfgs[i];
-                *out_visid = visid;
-                return true;
+        }
+    } else {
+        for (int i = 0; i < numConfigs; i++) {
+            int visid = X11None;
+            sGLXLibrary.xGetFBConfigAttrib(display, cfgs[i], LOCAL_GLX_VISUAL_ID, &visid);
+            if (!visid) {
+                continue;
+            }
+            if (sGLXLibrary.IsATI()) {
+                int depth;
+                Visual* visual;
+                FindVisualAndDepth(display, visid, &visual, &depth);
+                if (depth == windowAttrs.depth &&
+                    AreCompatibleVisuals(windowAttrs.visual, visual)) {
+                    *out_config = cfgs[i];
+                    *out_visid = visid;
+                    return true;
+                }
+            } else {
+                if (windowVisualID == static_cast<VisualID>(visid)) {
+                    *out_config = cfgs[i];
+                    *out_visid = visid;
+                    return true;
+                }
             }
         }
     }
 
     NS_WARNING("[GLX] Couldn't find a FBConfig matching window visual");
     return false;
 }
 
--- a/gfx/gl/GLContextProviderImpl.h
+++ b/gfx/gl/GLContextProviderImpl.h
@@ -56,22 +56,23 @@ public:
      * The GetSharedContext() method will return non-null if sharing
      * was successful.
      *
      * Note: a context created for a widget /must not/ hold a strong
      * reference to the widget; otherwise a cycle can be created through
      * a GL layer manager.
      *
      * @param aWidget Widget whose surface to create a context for
+     * @param aWebRender If the compositor is a WebRender compositor
      * @param aForceAccelerated true if only accelerated contexts are allowed
      *
      * @return Context to use for the window
      */
     static already_AddRefed<GLContext>
-    CreateForWindow(nsIWidget* aWidget, bool aForceAccelerated);
+    CreateForWindow(nsIWidget* aWidget, bool aWebRender, bool aForceAccelerated);
 
     /**
      * Create a context for offscreen rendering.  The target of this
      * context should be treated as opaque -- it might be a FBO, or a
      * pbuffer, or some other construct.  Users of this GLContext
      * should bind framebuffer 0 directly to use this offscreen buffer.
      *
      * The offscreen context returned by this method will always have
--- a/gfx/gl/GLContextProviderNull.cpp
+++ b/gfx/gl/GLContextProviderNull.cpp
@@ -12,17 +12,19 @@ using namespace mozilla::widget;
 
 already_AddRefed<GLContext>
 GLContextProviderNull::CreateForCompositorWidget(CompositorWidget* aCompositorWidget, bool aForceAccelerated)
 {
     return nullptr;
 }
 
 already_AddRefed<GLContext>
-GLContextProviderNull::CreateForWindow(nsIWidget* aWidget, bool aForceAccelerated)
+GLContextProviderNull::CreateForWindow(nsIWidget* aWidget,
+                                       bool aWebRender,
+                                       bool aForceAccelerated)
 {
     return nullptr;
 }
 
 already_AddRefed<GLContext>
 GLContextProviderNull::CreateWrappingExisting(void*, void*)
 {
     return nullptr;
--- a/gfx/gl/GLContextProviderWGL.cpp
+++ b/gfx/gl/GLContextProviderWGL.cpp
@@ -13,17 +13,19 @@
 
 #include "gfxCrashReporterUtils.h"
 
 #include "prenv.h"
 
 #include "mozilla/gfx/gfxVars.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/StaticPtr.h"
+#include "mozilla/layers/CompositorOptions.h"
 #include "mozilla/widget/CompositorWidget.h"
+#include "mozilla/widget/WinCompositorWidget.h"
 
 namespace mozilla {
 namespace gl {
 
 using namespace mozilla::gfx;
 using namespace mozilla::widget;
 
 WGLLibrary sWGLLib;
@@ -61,17 +63,17 @@ WGLLibrary::CreateDummyWindow(HDC* aWind
         pfd.nVersion = 1;
         pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
         pfd.iPixelType = PFD_TYPE_RGBA;
         pfd.cColorBits = 24;
         pfd.cRedBits = 8;
         pfd.cGreenBits = 8;
         pfd.cBlueBits = 8;
         pfd.cAlphaBits = 8;
-        pfd.cDepthBits = 0;
+        pfd.cDepthBits = gfxVars::UseWebRender() ? 24 : 0;
         pfd.iLayerType = PFD_MAIN_PLANE;
 
         mWindowPixelFormat = ChoosePixelFormat(dc, &pfd);
     }
 
     if (!mWindowPixelFormat ||
         !SetPixelFormat(dc, mWindowPixelFormat, nullptr))
     {
@@ -436,35 +438,31 @@ GetGlobalContextWGL()
 
 already_AddRefed<GLContext>
 GLContextProviderWGL::CreateWrappingExisting(void*, void*)
 {
     return nullptr;
 }
 
 already_AddRefed<GLContext>
-GLContextProviderWGL::CreateForCompositorWidget(CompositorWidget* aCompositorWidget, bool aForceAccelerated)
-{
-    return CreateForWindow(aCompositorWidget->RealWidget(), aForceAccelerated);
-}
-
-already_AddRefed<GLContext>
-GLContextProviderWGL::CreateForWindow(nsIWidget* aWidget, bool aForceAccelerated)
+CreateForWidget(HWND aHwnd,
+                bool aWebRender,
+                bool aForceAccelerated)
 {
     if (!sWGLLib.EnsureInitialized()) {
         return nullptr;
     }
 
     /**
        * We need to make sure we call SetPixelFormat -after- calling
        * EnsureInitialized, otherwise it can load/unload the dll and
        * wglCreateContext will fail.
        */
 
-    HDC dc = (HDC)aWidget->GetNativeData(NS_NATIVE_GRAPHIC);
+    HDC dc = ::GetDC(aHwnd);
 
     SetPixelFormat(dc, sWGLLib.GetWindowPixelFormat(), nullptr);
     HGLRC context;
 
     if (sWGLLib.HasRobustness()) {
         int attribs[] = {
             LOCAL_WGL_CONTEXT_FLAGS_ARB, LOCAL_WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB,
             LOCAL_WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, LOCAL_WGL_LOSE_CONTEXT_ON_RESET_ARB,
@@ -487,16 +485,30 @@ GLContextProviderWGL::CreateForWindow(ns
         return nullptr;
     }
 
     glContext->SetIsDoubleBuffered(true);
 
     return glContext.forget();
 }
 
+already_AddRefed<GLContext>
+GLContextProviderWGL::CreateForCompositorWidget(CompositorWidget* aCompositorWidget, bool aForceAccelerated)
+{
+    return CreateForWidget(aCompositorWidget->AsWindows()->GetHwnd(),
+                           aCompositorWidget->GetCompositorOptions().UseWebRender(),
+                           aForceAccelerated);
+}
+
+already_AddRefed<GLContext>
+GLContextProviderWGL::CreateForWindow(nsIWidget* aWidget, bool aWebRender, bool aForceAccelerated)
+{
+    return CreateForWidget((HWND)aWidget->GetNativeData(NS_NATIVE_WINDOW), aWebRender, aForceAccelerated);
+}
+
 static already_AddRefed<GLContextWGL>
 CreatePBufferOffscreenContext(CreateContextFlags flags, const IntSize& aSize)
 {
     WGLLibrary& wgl = sWGLLib;
 
     const int pfAttribs[] = {
         LOCAL_WGL_SUPPORT_OPENGL_ARB, LOCAL_GL_TRUE,
         LOCAL_WGL_ACCELERATION_ARB, LOCAL_WGL_FULL_ACCELERATION_ARB,
--- a/gfx/gl/GLLibraryEGL.cpp
+++ b/gfx/gl/GLLibraryEGL.cpp
@@ -3,16 +3,17 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "GLLibraryEGL.h"
 
 #include "angle/Platform.h"
 #include "gfxConfig.h"
 #include "gfxCrashReporterUtils.h"
 #include "gfxUtils.h"
+#include "mozilla/layers/CompositorThread.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/Tokenizer.h"
 #include "mozilla/ScopeExit.h"
 #include "mozilla/Unused.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsDirectoryServiceUtils.h"
@@ -143,16 +144,24 @@ GetAndInitWARPDisplay(GLLibraryEGL& egl,
 
     return display;
 }
 
 static bool
 IsAccelAngleSupported(const nsCOMPtr<nsIGfxInfo>& gfxInfo,
                       nsACString* const out_failureId)
 {
+    if (CompositorThreadHolder::IsInCompositorThread()) {
+        // We can only enter here with WebRender, so assert that this is a
+        // WebRender-enabled build.
+#ifndef MOZ_ENABLE_WEBRENDER
+        MOZ_ASSERT(false);
+#endif
+        return true;
+    }
     int32_t angleSupport;
     nsCString failureId;
     gfxUtils::ThreadSafeGetFeatureStatus(gfxInfo,
                                          nsIGfxInfo::FEATURE_WEBGL_ANGLE,
                                          failureId,
                                          &angleSupport);
     if (failureId.IsEmpty() && angleSupport != nsIGfxInfo::FEATURE_STATUS_OK) {
         // This shouldn't happen, if we see this it's because we've missed
--- a/gfx/gl/GLLibraryLoader.cpp
+++ b/gfx/gl/GLLibraryLoader.cpp
@@ -36,16 +36,22 @@ GLLibraryLoader::LoadSymbols(const SymLo
     return LoadSymbols(mLibrary,
                        firstStruct,
                        tryplatform ? mLookupFunc : nullptr,
                        prefix,
                        warnOnFailure);
 }
 
 PRFuncPtr
+GLLibraryLoader::LookupSymbol(const char* sym)
+{
+    return LookupSymbol(mLibrary, sym, mLookupFunc);
+}
+
+PRFuncPtr
 GLLibraryLoader::LookupSymbol(PRLibrary* lib,
                               const char* sym,
                               PlatformLookupFunction lookupFunction)
 {
     PRFuncPtr res = 0;
 
     // try finding it in the library directly, if we have one
     if (lib) {
--- a/gfx/gl/GLLibraryLoader.h
+++ b/gfx/gl/GLLibraryLoader.h
@@ -31,16 +31,18 @@ public:
         const char* symNames[MAX_SYMBOL_NAMES];
     } SymLoadStruct;
 
     bool LoadSymbols(const SymLoadStruct* firstStruct,
                      bool tryplatform = false,
                      const char* prefix = nullptr,
                      bool warnOnFailure = true);
 
+    PRFuncPtr LookupSymbol(const char* symname);
+
     /*
      * Static version of the functions in this class
      */
     static PRFuncPtr LookupSymbol(PRLibrary* lib,
                                   const char* symname,
                                   PlatformLookupFunction lookupFunction = nullptr);
     static bool LoadSymbols(PRLibrary* lib,
                             const SymLoadStruct* firstStruct,
--- a/gfx/ipc/CompositorOptions.h
+++ b/gfx/ipc/CompositorOptions.h
@@ -26,30 +26,35 @@ namespace layers {
  * and are accessible to content processes over PCompositorBridge as well.
  */
 class CompositorOptions
 {
 public:
   // This constructor needed for IPDL purposes, don't use it anywhere else.
   CompositorOptions()
     : mUseAPZ(false)
+    , mUseWebRender(false)
   {
   }
 
-  explicit CompositorOptions(bool aUseAPZ)
+  explicit CompositorOptions(bool aUseAPZ,
+                             bool aUseWebRender)
     : mUseAPZ(aUseAPZ)
+    , mUseWebRender(aUseWebRender)
   {
   }
 
   bool UseAPZ() const { return mUseAPZ; }
+  bool UseWebRender() const { return mUseWebRender; }
 
   friend struct IPC::ParamTraits<CompositorOptions>;
 
 private:
   bool mUseAPZ;
+  bool mUseWebRender;
 
   // Make sure to add new fields to the ParamTraits implementation
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif // _include_mozilla_gfx_ipc_CompositorOptions_h_
--- a/gfx/ipc/GPUParent.cpp
+++ b/gfx/ipc/GPUParent.cpp
@@ -23,16 +23,17 @@
 #include "mozilla/ipc/ProcessChild.h"
 #include "mozilla/layers/APZThreadUtils.h"
 #include "mozilla/layers/APZCTreeManager.h"
 #include "mozilla/layers/CompositorBridgeParent.h"
 #include "mozilla/layers/CompositorThread.h"
 #include "mozilla/layers/ImageBridgeParent.h"
 #include "mozilla/layers/LayerTreeOwnerTracker.h"
 #include "mozilla/layers/UiCompositorControllerParent.h"
+#include "mozilla/webrender/RenderThread.h"
 #include "nsDebugImpl.h"
 #include "nsExceptionHandler.h"
 #include "nsThreadManager.h"
 #include "prenv.h"
 #include "ProcessUtils.h"
 #include "VRManager.h"
 #include "VRManagerParent.h"
 #include "VsyncBridgeParent.h"
@@ -186,16 +187,21 @@ GPUParent::RecvInit(nsTArray<GfxPrefSett
     };
     char** argvp = argv;
     gtk_init(&argc, &argvp);
   } else {
     gtk_init(nullptr, nullptr);
   }
 #endif
 
+  // Make sure to do this *after* we update gfxVars above.
+  if (gfxVars::UseWebRender()) {
+    wr::RenderThread::Start();
+  }
+
   VRManager::ManagerInit();
   // Send a message to the UI process that we're done.
   GPUDeviceData data;
   RecvGetDeviceStatus(&data);
   Unused << SendInitComplete(data);
 
   Telemetry::AccumulateTimeDelta(Telemetry::GPU_PROCESS_INITIALIZATION_TIME_MS, mLaunchTime);
   return IPC_OK();
@@ -406,16 +412,19 @@ GPUParent::ActorDestroy(ActorDestroyReas
 #endif
 
   if (mVsyncBridge) {
     mVsyncBridge->Shutdown();
     mVsyncBridge = nullptr;
   }
   dom::VideoDecoderManagerParent::ShutdownVideoBridge();
   CompositorThreadHolder::Shutdown();
+  if (gfxVars::UseWebRender()) {
+    wr::RenderThread::ShutDown();
+  }
   Factory::ShutDown();
 #if defined(XP_WIN)
   DeviceManagerDx::Shutdown();
   DeviceManagerD3D9::Shutdown();
 #endif
   LayerTreeOwnerTracker::Shutdown();
   gfxVars::Shutdown();
   gfxConfig::Shutdown();
--- a/gfx/ipc/GPUProcessManager.cpp
+++ b/gfx/ipc/GPUProcessManager.cpp
@@ -149,16 +149,18 @@ GPUProcessManager::DisableGPUProcess(con
 {
   if (!gfxConfig::IsEnabled(Feature::GPU_PROCESS)) {
     return;
   }
 
   gfxConfig::SetFailed(Feature::GPU_PROCESS, FeatureStatus::Failed, aMessage);
   gfxCriticalNote << aMessage;
 
+  gfxPlatform::NotifyGPUProcessDisabled();
+
   DestroyProcess();
   ShutdownVsyncIOThread();
 }
 
 void
 GPUProcessManager::EnsureGPUReady()
 {
   if (mProcess && !mProcess->IsConnected()) {
--- a/gfx/ipc/GfxMessageUtils.h
+++ b/gfx/ipc/GfxMessageUtils.h
@@ -1335,20 +1335,22 @@ struct ParamTraits<mozilla::Array<T, Len
 
 template <>
 struct ParamTraits<mozilla::layers::CompositorOptions>
 {
   typedef mozilla::layers::CompositorOptions paramType;
 
   static void Write(Message* aMsg, const paramType& aParam) {
     WriteParam(aMsg, aParam.mUseAPZ);
+    WriteParam(aMsg, aParam.mUseWebRender);
   }
 
   static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult) {
-    return ReadParam(aMsg, aIter, &aResult->mUseAPZ);
+    return ReadParam(aMsg, aIter, &aResult->mUseAPZ)
+        && ReadParam(aMsg, aIter, &aResult->mUseWebRender);
   }
 };
 
 template <>
 struct ParamTraits<mozilla::layers::SimpleLayerAttributes>
 {
   typedef mozilla::layers::SimpleLayerAttributes paramType;
 
--- a/gfx/layers/Compositor.h
+++ b/gfx/layers/Compositor.h
@@ -130,16 +130,17 @@ class CompositingRenderTarget;
 class CompositorBridgeParent;
 class LayerManagerComposite;
 class CompositorOGL;
 class CompositorD3D9;
 class CompositorD3D11;
 class BasicCompositor;
 class TextureHost;
 class TextureReadLock;
+class WebRenderCompositorOGL;
 
 enum SurfaceInitMode
 {
   INIT_MODE_NONE,
   INIT_MODE_CLEAR
 };
 
 /**
@@ -468,16 +469,17 @@ public:
 #endif // MOZ_DUMP_PAINTING
 
   virtual LayersBackend GetBackendType() const = 0;
 
   virtual CompositorOGL* AsCompositorOGL() { return nullptr; }
   virtual CompositorD3D9* AsCompositorD3D9() { return nullptr; }
   virtual CompositorD3D11* AsCompositorD3D11() { return nullptr; }
   virtual BasicCompositor* AsBasicCompositor() { return nullptr; }
+  virtual WebRenderCompositorOGL* AsWebRenderCompositorOGL() { return nullptr; }
 
   /**
    * Each Compositor has a unique ID.
    * This ID is used to keep references to each Compositor in a map accessed
    * from the compositor thread only, so that async compositables can find
    * the right compositor parent and schedule compositing even if the compositor
    * changed.
    */
@@ -548,30 +550,30 @@ public:
   void SetCompositionTime(TimeStamp aTimeStamp) {
     mCompositionTime = aTimeStamp;
     if (!mCompositionTime.IsNull() && !mCompositeUntilTime.IsNull() &&
         mCompositionTime >= mCompositeUntilTime) {
       mCompositeUntilTime = TimeStamp();
     }
   }
 
-  void CompositeUntil(TimeStamp aTimeStamp) {
+  virtual void CompositeUntil(TimeStamp aTimeStamp) {
     if (mCompositeUntilTime.IsNull() ||
         mCompositeUntilTime < aTimeStamp) {
       mCompositeUntilTime = aTimeStamp;
     }
   }
   TimeStamp GetCompositeUntilTime() const {
     return mCompositeUntilTime;
   }
 
   // A stale Compositor has no CompositorBridgeParent; it will not process
   // frames and should not be used.
   void SetInvalid();
-  bool IsValid() const;
+  virtual bool IsValid() const;
   CompositorBridgeParent* GetCompositorBridgeParent() const {
     return mParent;
   }
 
   /// Most compositor backends operate asynchronously under the hood. This
   /// means that when a layer stops using a texture it is often desirable to
   /// wait for the end of the next composition before releasing the texture's
   /// ReadLock.
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -53,16 +53,17 @@
 #include "ImageContainer.h"
 
 class gfxContext;
 
 extern uint8_t gLayerManagerLayerBuilder;
 
 namespace mozilla {
 
+class ComputedTimingFunction;
 class FrameLayerBuilder;
 class StyleAnimationValue;
 
 namespace gl {
 class GLContext;
 } // namespace gl
 
 namespace gfx {
@@ -78,44 +79,53 @@ class AsyncPanZoomController;
 class BasicLayerManager;
 class ClientLayerManager;
 class Layer;
 class LayerMetricsWrapper;
 class PaintedLayer;
 class ContainerLayer;
 class ImageLayer;
 class ColorLayer;
+class CompositorBridgeChild;
 class TextLayer;
 class CanvasLayer;
 class BorderLayer;
 class ReadbackLayer;
 class ReadbackProcessor;
 class RefLayer;
 class HostLayer;
+class KnowsCompositor;
 class ShadowableLayer;
 class ShadowLayerForwarder;
 class LayerManagerComposite;
 class SpecificLayerAttributes;
+class TransactionIdAllocator;
 class Compositor;
 class FrameUniformityData;
 class PersistentBufferProvider;
 class GlyphArray;
+class WebRenderLayerManager;
 struct AnimData;
 
 namespace layerscope {
 class LayersPacket;
 } // namespace layerscope
 
 #define MOZ_LAYER_DECL_NAME(n, e)                              \
   virtual const char* Name() const override { return n; }  \
   virtual LayerType GetType() const override { return e; }
 
 // Defined in LayerUserData.h; please include that file instead.
 class LayerUserData;
 
+class DidCompositeObserver {
+  public:
+    virtual void DidComposite() = 0;
+};
+
 /*
  * Motivation: For truly smooth animation and video playback, we need to
  * be able to compose frames and render them on a dedicated thread (i.e.
  * off the main thread where DOM manipulation, script execution and layout
  * induce difficult-to-bound latency). This requires Gecko to construct
  * some kind of persistent scene structure (graph or tree) that can be
  * safely transmitted across threads. We have other scenarios (e.g. mobile
  * browsing) where retaining some rendered data between paints is desired
@@ -188,25 +198,31 @@ public:
     mUserData.Destroy();
     mRoot = nullptr;
   }
   bool IsDestroyed() { return mDestroyed; }
 
   virtual ShadowLayerForwarder* AsShadowForwarder()
   { return nullptr; }
 
+  virtual KnowsCompositor* AsKnowsCompositor()
+  { return nullptr; }
+
   virtual LayerManagerComposite* AsLayerManagerComposite()
   { return nullptr; }
 
   virtual ClientLayerManager* AsClientLayerManager()
   { return nullptr; }
 
   virtual BasicLayerManager* AsBasicLayerManager()
   { return nullptr; }
 
+  virtual WebRenderLayerManager* AsWebRenderLayerManager()
+  { return nullptr; }
+
   /**
    * Returns true if this LayerManager is owned by an nsIWidget,
    * and is used for drawing into the widget.
    */
   virtual bool IsWidgetLayerManager() { return true; }
   virtual bool IsInactiveLayerManager() { return false; }
 
   /**
@@ -661,16 +677,37 @@ public:
   }
 
   uint32_t GetAndClearPaintedPixelCount() {
     uint32_t count = mPaintedPixelCount;
     mPaintedPixelCount = 0;
     return count;
   }
 
+  virtual void SetLayerObserverEpoch(uint64_t aLayerObserverEpoch) {}
+
+  virtual void DidComposite(uint64_t aTransactionId,
+                            const mozilla::TimeStamp& aCompositeStart,
+                            const mozilla::TimeStamp& aCompositeEnd) {}
+
+  virtual void AddDidCompositeObserver(DidCompositeObserver* aObserver) { MOZ_CRASH("GFX: LayerManager"); }
+  virtual void RemoveDidCompositeObserver(DidCompositeObserver* aObserver) { MOZ_CRASH("GFX: LayerManager"); }
+
+  virtual void UpdateTextureFactoryIdentifier(const TextureFactoryIdentifier& aNewIdentifier,
+											  uint64_t aDeviceResetSeqNo) {}
+
+  virtual TextureFactoryIdentifier GetTextureFactoryIdentifier()
+  {
+    return TextureFactoryIdentifier();
+  }
+
+  virtual void SetTransactionIdAllocator(TransactionIdAllocator* aAllocator) {}
+
+  virtual CompositorBridgeChild* GetCompositorBridgeChild() { return nullptr; }
+
 protected:
   RefPtr<Layer> mRoot;
   gfx::UserData mUserData;
   bool mDestroyed;
   bool mSnapEffectiveTransforms;
 
   nsIntRegion mRegionToClear;
 
@@ -1737,16 +1774,18 @@ public:
   // and can be used anytime.
   // A layer has an APZC at index aIndex only-if GetFrameMetrics(aIndex).IsScrollable();
   // attempting to get an APZC for a non-scrollable metrics will return null.
   // The aIndex for these functions must be less than GetScrollMetadataCount().
   void SetAsyncPanZoomController(uint32_t aIndex, AsyncPanZoomController *controller);
   AsyncPanZoomController* GetAsyncPanZoomController(uint32_t aIndex) const;
   // The ScrollMetadataChanged function is used internally to ensure the APZC array length
   // matches the frame metrics array length.
+
+  virtual void ClearCachedResources() {}
 private:
   void ScrollMetadataChanged();
 public:
 
   void ApplyPendingUpdatesForThisTransaction();
 
 #ifdef DEBUG
   void SetDebugColorIndex(uint32_t aIndex) { mDebugColorIndex = aIndex; }
--- a/gfx/layers/LayersTypes.h
+++ b/gfx/layers/LayersTypes.h
@@ -44,16 +44,17 @@ class TextureHost;
 
 enum class LayersBackend : int8_t {
   LAYERS_NONE = 0,
   LAYERS_BASIC,
   LAYERS_OPENGL,
   LAYERS_D3D9,
   LAYERS_D3D11,
   LAYERS_CLIENT,
+  LAYERS_WR,
   LAYERS_LAST
 };
 
 enum class BufferMode : int8_t {
   BUFFER_NONE,
   BUFFERED
 };
 
--- a/gfx/layers/RotatedBuffer.cpp
+++ b/gfx/layers/RotatedBuffer.cpp
@@ -422,18 +422,20 @@ RotatedContentBuffer::FlushBuffers()
 
 RotatedContentBuffer::PaintState
 RotatedContentBuffer::BeginPaint(PaintedLayer* aLayer,
                                  uint32_t aFlags)
 {
   PaintState result;
   // We need to disable rotation if we're going to be resampled when
   // drawing, because we might sample across the rotation boundary.
+  // Also disable buffer rotation when using webrender.
   bool canHaveRotation = gfxPlatform::BufferRotationEnabled() &&
-                         !(aFlags & (PAINT_WILL_RESAMPLE | PAINT_NO_ROTATION));
+                         !(aFlags & (PAINT_WILL_RESAMPLE | PAINT_NO_ROTATION)) &&
+                         !(aLayer->Manager()->AsWebRenderLayerManager());
 
   nsIntRegion validRegion = aLayer->GetValidRegion();
 
   bool canUseOpaqueSurface = aLayer->CanUseOpaqueSurface();
   ContentType layerContentType =
     canUseOpaqueSurface ? gfxContentType::COLOR :
                           gfxContentType::COLOR_ALPHA;
 
--- a/gfx/layers/apz/src/GestureEventListener.cpp
+++ b/gfx/layers/apz/src/GestureEventListener.cpp
@@ -6,16 +6,17 @@
 
 #include "GestureEventListener.h"
 #include <math.h>                       // for fabsf
 #include <stddef.h>                     // for size_t
 #include "AsyncPanZoomController.h"     // for AsyncPanZoomController
 #include "InputBlockState.h"            // for TouchBlockState
 #include "base/task.h"                  // for CancelableTask, etc
 #include "gfxPrefs.h"                   // for gfxPrefs
+#include "InputBlockState.h"            // for TouchBlockState
 #include "mozilla/SizePrintfMacros.h"   // for PRIuSIZE
 #include "nsDebug.h"                    // for NS_WARNING
 #include "nsMathUtils.h"                // for NS_hypot
 
 #define GEL_LOG(...)
 // #define GEL_LOG(...) printf_stderr("GEL: " __VA_ARGS__)
 
 namespace mozilla {
--- a/gfx/layers/client/ClientLayerManager.cpp
+++ b/gfx/layers/client/ClientLayerManager.cpp
@@ -774,17 +774,17 @@ ClientLayerManager::HandleMemoryPressure
   if (GetCompositorBridgeChild()) {
     GetCompositorBridgeChild()->HandleMemoryPressure();
   }
 }
 
 void
 ClientLayerManager::ClearLayer(Layer* aLayer)
 {
-  ClientLayer::ToClientLayer(aLayer)->ClearCachedResources();
+  aLayer->ClearCachedResources();
   for (Layer* child = aLayer->GetFirstChild(); child;
        child = child->GetNextSibling()) {
     ClearLayer(child);
   }
 }
 
 void
 ClientLayerManager::HandleMemoryPressureLayer(Layer* aLayer)
--- a/gfx/layers/client/ClientLayerManager.h
+++ b/gfx/layers/client/ClientLayerManager.h
@@ -47,16 +47,21 @@ protected:
   virtual ~ClientLayerManager();
 
 public:
   virtual ShadowLayerForwarder* AsShadowForwarder() override
   {
     return mForwarder;
   }
 
+  virtual KnowsCompositor* AsKnowsCompositor() override
+  {
+    return mForwarder;
+  }
+
   virtual ClientLayerManager* AsClientLayerManager() override
   {
     return this;
   }
 
   virtual int32_t GetMaxTextureSize() const override;
 
   virtual void SetDefaultTargetConfiguration(BufferMode aDoubleBuffering, ScreenRotation aRotation);
@@ -86,19 +91,19 @@ public:
   virtual already_AddRefed<ImageLayer> CreateImageLayer() override;
   virtual already_AddRefed<CanvasLayer> CreateCanvasLayer() override;
   virtual already_AddRefed<ReadbackLayer> CreateReadbackLayer() override;
   virtual already_AddRefed<ColorLayer> CreateColorLayer() override;
   virtual already_AddRefed<TextLayer> CreateTextLayer() override;
   virtual already_AddRefed<BorderLayer> CreateBorderLayer() override;
   virtual already_AddRefed<RefLayer> CreateRefLayer() override;
 
-  void UpdateTextureFactoryIdentifier(const TextureFactoryIdentifier& aNewIdentifier,
-                                      uint64_t aDeviceResetSeqNo);
-  TextureFactoryIdentifier GetTextureFactoryIdentifier()
+  virtual void UpdateTextureFactoryIdentifier(const TextureFactoryIdentifier& aNewIdentifier,
+											  uint64_t aDeviceResetSeqNo) override;
+  virtual TextureFactoryIdentifier GetTextureFactoryIdentifier() override
   {
     return AsShadowForwarder()->GetTextureFactoryIdentifier();
   }
 
   virtual void FlushRendering() override;
   void SendInvalidRegion(const nsIntRegion& aRegion);
 
   virtual uint32_t StartFrameTimeRecording(int32_t aBufferSize) override;
@@ -148,17 +153,17 @@ public:
   DrawPaintedLayerCallback GetPaintedLayerCallback() const
   { return mPaintedLayerCallback; }
 
   void* GetPaintedLayerCallbackData() const
   { return mPaintedLayerCallbackData; }
 
   CompositorBridgeChild* GetRemoteRenderer();
 
-  CompositorBridgeChild* GetCompositorBridgeChild();
+  virtual CompositorBridgeChild* GetCompositorBridgeChild() override;
 
   // Disable component alpha layers with the software compositor.
   virtual bool ShouldAvoidComponentAlphaLayers() override { return !IsCompositingCheap(); }
 
   bool InConstruction() { return mPhase == PHASE_CONSTRUCTION; }
 #ifdef DEBUG
   bool InDrawing() { return mPhase == PHASE_DRAWING; }
   bool InForward() { return mPhase == PHASE_FORWARD; }
@@ -169,19 +174,19 @@ public:
   {
     mNeedsComposite = aNeedsComposite;
   }
   bool NeedsComposite() const { return mNeedsComposite; }
 
   virtual void Composite() override;
   virtual void GetFrameUniformity(FrameUniformityData* aFrameUniformityData) override;
 
-  void DidComposite(uint64_t aTransactionId,
-                    const mozilla::TimeStamp& aCompositeStart,
-                    const mozilla::TimeStamp& aCompositeEnd);
+  virtual void DidComposite(uint64_t aTransactionId,
+                            const mozilla::TimeStamp& aCompositeStart,
+                            const mozilla::TimeStamp& aCompositeEnd) override;
 
   virtual bool AreComponentAlphaLayersEnabled() override;
 
   // Log APZ test data for the current paint. We supply the paint sequence
   // number ourselves, and take care of calling APZTestData::StartNewPaint()
   // when a new paint is started.
   void LogTestDataForCurrentPaint(FrameMetrics::ViewID aScrollId,
                                   const std::string& aKey,
@@ -210,33 +215,31 @@ public:
   // LogTestData...() functions.
   const APZTestData& GetAPZTestData() const {
     return mApzTestData;
   }
 
   // Get a copy of the compositor-side APZ test data for our layers ID.
   void GetCompositorSideAPZTestData(APZTestData* aData) const;
 
-  void SetTransactionIdAllocator(TransactionIdAllocator* aAllocator) { mTransactionIdAllocator = aAllocator; }
+  virtual void SetTransactionIdAllocator(TransactionIdAllocator* aAllocator) override
+  {
+     mTransactionIdAllocator = aAllocator;
+  }
 
   float RequestProperty(const nsAString& aProperty) override;
 
   bool AsyncPanZoomEnabled() const override;
 
   void SetNextPaintSyncId(int32_t aSyncId);
 
-  void SetLayerObserverEpoch(uint64_t aLayerObserverEpoch);
+  virtual void SetLayerObserverEpoch(uint64_t aLayerObserverEpoch) override;
 
-  class DidCompositeObserver {
-  public:
-    virtual void DidComposite() = 0;
-  };
-
-  void AddDidCompositeObserver(DidCompositeObserver* aObserver);
-  void RemoveDidCompositeObserver(DidCompositeObserver* aObserver);
+  virtual void AddDidCompositeObserver(DidCompositeObserver* aObserver) override;
+  virtual void RemoveDidCompositeObserver(DidCompositeObserver* aObserver) override;
 
   virtual already_AddRefed<PersistentBufferProvider>
   CreatePersistentBufferProvider(const gfx::IntSize& aSize, gfx::SurfaceFormat aFormat) override;
 
 protected:
   enum TransactionPhase {
     PHASE_NONE, PHASE_CONSTRUCTION, PHASE_DRAWING, PHASE_FORWARD
   };
@@ -345,18 +348,16 @@ class ClientLayer : public ShadowableLay
 public:
   ClientLayer()
   {
     MOZ_COUNT_CTOR(ClientLayer);
   }
 
   ~ClientLayer();
 
-  virtual void ClearCachedResources() { }
-
   // Shrink memory usage.
   // Called when "memory-pressure" is observed.
   virtual void HandleMemoryPressure() { }
 
   virtual void RenderLayer() = 0;
   virtual void RenderLayerWithReadback(ReadbackProcessor *aReadback) { RenderLayer(); }
 
   virtual ClientPaintedLayer* AsThebes() { return nullptr; }
--- a/gfx/layers/client/ContentClient.cpp
+++ b/gfx/layers/client/ContentClient.cpp
@@ -58,16 +58,17 @@ static TextureFlags TextureFlagsForRotat
 
 /* static */ already_AddRefed<ContentClient>
 ContentClient::CreateContentClient(CompositableForwarder* aForwarder)
 {
   LayersBackend backend = aForwarder->GetCompositorBackendType();
   if (backend != LayersBackend::LAYERS_OPENGL &&
       backend != LayersBackend::LAYERS_D3D9 &&
       backend != LayersBackend::LAYERS_D3D11 &&
+      backend != LayersBackend::LAYERS_WR &&
       backend != LayersBackend::LAYERS_BASIC) {
     return nullptr;
   }
 
   bool useDoubleBuffering = false;
 
 #ifdef XP_WIN
   if (backend == LayersBackend::LAYERS_D3D11) {
--- a/gfx/layers/client/TextureClient.cpp
+++ b/gfx/layers/client/TextureClient.cpp
@@ -1047,17 +1047,18 @@ TextureClient::CreateForDrawing(TextureF
       aAllocator->IsSameProcess() &&
       aSize.width <= aMaxTextureSize &&
       aSize.height <= aMaxTextureSize &&
       NS_IsMainThread() &&
       DeviceManagerD3D9::GetDevice()) {
     data = D3D9TextureData::Create(aSize, aFormat, aAllocFlags);
   }
 
-  if (!data && aFormat == SurfaceFormat::B8G8R8X8 &&
+  if (aLayersBackend != LayersBackend::LAYERS_WR &&
+      !data && aFormat == SurfaceFormat::B8G8R8X8 &&
       moz2DBackend == gfx::BackendType::CAIRO &&
       NS_IsMainThread()) {
     data = DIBTextureData::Create(aSize, aFormat, aAllocator);
   }
 #endif
 
 #ifdef MOZ_X11
   gfxSurfaceType type =
--- a/gfx/layers/composite/CompositableHost.cpp
+++ b/gfx/layers/composite/CompositableHost.cpp
@@ -6,18 +6,20 @@
 #include "CompositableHost.h"
 #include <map>                          // for _Rb_tree_iterator, map, etc
 #include <utility>                      // for pair
 #include "ContentHost.h"                // for ContentHostDoubleBuffered, etc
 #include "Effects.h"                    // for EffectMask, Effect, etc
 #include "gfxUtils.h"
 #include "ImageHost.h"                  // for ImageHostBuffered, etc
 #include "TiledContentHost.h"           // for TiledContentHost
+#include "mozilla/gfx/gfxVars.h"
 #include "mozilla/layers/LayersSurfaces.h"  // for SurfaceDescriptor
 #include "mozilla/layers/TextureHost.h"  // for TextureHost, etc
+#include "mozilla/layers/WebRenderImageHost.h"
 #include "mozilla/RefPtr.h"                   // for nsRefPtr
 #include "nsDebug.h"                    // for NS_WARNING
 #include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "gfxPlatform.h"                // for gfxPlatform
 #include "IPDLActor.h"
 
 namespace mozilla {
 
@@ -123,17 +125,21 @@ CompositableHost::Create(const TextureIn
   switch (aTextureInfo.mCompositableType) {
   case CompositableType::IMAGE_BRIDGE:
     NS_ERROR("Cannot create an image bridge compositable this way");
     break;
   case CompositableType::CONTENT_TILED:
     result = new TiledContentHost(aTextureInfo);
     break;
   case CompositableType::IMAGE:
-    result = new ImageHost(aTextureInfo);
+    if (gfxVars::UseWebRender()) {
+      result = new WebRenderImageHost(aTextureInfo);
+    } else {
+      result = new ImageHost(aTextureInfo);
+    }
     break;
   case CompositableType::CONTENT_SINGLE:
     result = new ContentHostSingleBuffered(aTextureInfo);
     break;
   case CompositableType::CONTENT_DOUBLE:
     result = new ContentHostDoubleBuffered(aTextureInfo);
     break;
   default:
--- a/gfx/layers/composite/CompositableHost.h
+++ b/gfx/layers/composite/CompositableHost.h
@@ -40,16 +40,21 @@ namespace layers {
 class Layer;
 class LayerComposite;
 class Compositor;
 class ThebesBufferData;
 class TiledContentHost;
 class CompositableParentManager;
 struct EffectChain;
 
+struct ImageCompositeNotificationInfo {
+  base::ProcessId mImageBridgeProcessId;
+  ImageCompositeNotification mNotification;
+};
+
 struct AsyncCompositableRef
 {
   AsyncCompositableRef()
    : mProcessId(mozilla::ipc::kInvalidProcessId)
   {}
   AsyncCompositableRef(base::ProcessId aProcessId, const CompositableHandle& aHandle)
    : mProcessId(aProcessId), mHandle(aHandle)
   {}
@@ -228,16 +233,18 @@ public:
     return nullptr;
   }
 
   /// Called when shutting down the layer tree.
   /// This is a good place to clear all potential gpu resources before the widget
   /// is is destroyed.
   virtual void CleanupResources() {}
 
+  virtual void BindTextureSource() {}
+
 protected:
   TextureInfo mTextureInfo;
   AsyncCompositableRef mAsyncRef;
   uint64_t mCompositorID;
   RefPtr<Compositor> mCompositor;
   Layer* mLayer;
   uint32_t mFlashCounter; // used when the pref "layers.flash-borders" is true.
   bool mAttached;
copy from gfx/layers/composite/ImageHost.cpp
copy to gfx/layers/composite/ImageComposite.cpp
--- a/gfx/layers/composite/ImageHost.cpp
+++ b/gfx/layers/composite/ImageComposite.cpp
@@ -1,222 +1,95 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "ImageHost.h"
+#include "ImageComposite.h"
 
-#include "LayersLogging.h"              // for AppendToString
-#include "composite/CompositableHost.h"  // for CompositableHost, etc
-#include "ipc/IPCMessageUtils.h"        // for null_t
-#include "mozilla/layers/Compositor.h"  // for Compositor
-#include "mozilla/layers/Effects.h"     // for TexturedEffect, Effect, etc
-#include "mozilla/layers/LayerManagerComposite.h"     // for TexturedEffect, Effect, etc
-#include "nsAString.h"
-#include "nsDebug.h"                    // for NS_WARNING, NS_ASSERTION
-#include "nsPrintfCString.h"            // for nsPrintfCString
-#include "nsString.h"                   // for nsAutoCString
-
+// this is also defined in ImageHost.cpp
 #define BIAS_TIME_MS 1.0
 
 namespace mozilla {
 
 using namespace gfx;
 
 namespace layers {
 
-class ISurfaceAllocator;
-
-ImageHost::ImageHost(const TextureInfo& aTextureInfo)
-  : CompositableHost(aTextureInfo)
-  , mLastFrameID(-1)
+ImageComposite::ImageComposite()
+  : mLastFrameID(-1)
   , mLastProducerID(-1)
   , mBias(BIAS_NONE)
-  , mLocked(false)
 {}
 
-ImageHost::~ImageHost()
+ImageComposite::~ImageComposite()
 {
 }
 
-void
-ImageHost::UseTextureHost(const nsTArray<TimedTexture>& aTextures)
-{
-  MOZ_ASSERT(!mLocked);
-
-  CompositableHost::UseTextureHost(aTextures);
-  MOZ_ASSERT(aTextures.Length() >= 1);
-
-  nsTArray<TimedImage> newImages;
-
-  for (uint32_t i = 0; i < aTextures.Length(); ++i) {
-    const TimedTexture& t = aTextures[i];
-    MOZ_ASSERT(t.mTexture);
-    if (i + 1 < aTextures.Length() &&
-        t.mProducerID == mLastProducerID && t.mFrameID < mLastFrameID) {
-      // Ignore frames before a frame that we already composited. We don't
-      // ever want to display these frames. This could be important if
-      // the frame producer adjusts timestamps (e.g. to track the audio clock)
-      // and the new frame times are earlier.
-      continue;
-    }
-    TimedImage& img = *newImages.AppendElement();
-    img.mTextureHost = t.mTexture;
-    img.mTimeStamp = t.mTimeStamp;
-    img.mPictureRect = t.mPictureRect;
-    img.mFrameID = t.mFrameID;
-    img.mProducerID = t.mProducerID;
-    img.mTextureHost->SetCropRect(img.mPictureRect);
-    img.mTextureHost->Updated();
-  }
-
-  mImages.SwapElements(newImages);
-  newImages.Clear();
-
-  // If we only have one image we can upload it right away, otherwise we'll upload
-  // on-demand during composition after we have picked the proper timestamp.
-  if (mImages.Length() == 1) {
-    SetCurrentTextureHost(mImages[0].mTextureHost);
-  }
-
-  // Video producers generally send replacement images with the same frameID but
-  // slightly different timestamps in order to sync with the audio clock. This
-  // means that any CompositeUntil() call we made in Composite() may no longer
-  // guarantee that we'll composite until the next frame is ready. Fix that here.
-  if (GetCompositor() && mLastFrameID >= 0) {
-    for (size_t i = 0; i < mImages.Length(); ++i) {
-      bool frameComesAfter = mImages[i].mFrameID > mLastFrameID ||
-                             mImages[i].mProducerID != mLastProducerID;
-      if (frameComesAfter && !mImages[i].mTimeStamp.IsNull()) {
-        GetCompositor()->CompositeUntil(mImages[i].mTimeStamp +
-                                        TimeDuration::FromMilliseconds(BIAS_TIME_MS));
-        break;
-      }
-    }
-  }
-}
-
-void
-ImageHost::SetCurrentTextureHost(TextureHost* aTexture)
-{
-  if (aTexture == mCurrentTextureHost.get()) {
-    return;
-  }
-
-  bool swapTextureSources = !!mCurrentTextureHost && !!mCurrentTextureSource
-                            && mCurrentTextureHost->HasIntermediateBuffer();
-
-  if (swapTextureSources) {
-    auto dataSource = mCurrentTextureSource->AsDataTextureSource();
-    if (dataSource) {
-      // The current textureHost has an internal buffer in the form of the
-      // DataTextureSource. Removing the ownership of the texture source
-      // will enable the next texture host we bind to the texture source to
-      // acquire it instead of creating a new one. This is desirable in
-      // ImageHost because the current texture won't be used again with the
-      // same content. It wouldn't be desirable with ContentHost for instance,
-      // because the latter reuses the texture's valid regions.
-      dataSource->SetOwner(nullptr);
-    }
-
-    RefPtr<TextureSource> tmp = mExtraTextureSource;
-    mExtraTextureSource = mCurrentTextureSource.get();
-    mCurrentTextureSource = tmp;
-  } else {
-    mExtraTextureSource = nullptr;
-  }
-
-  mCurrentTextureHost = aTexture;
-  mCurrentTextureHost->PrepareTextureSource(mCurrentTextureSource);
-}
-
-void
-ImageHost::CleanupResources()
-{
-  mExtraTextureSource = nullptr;
-  mCurrentTextureSource = nullptr;
-  mCurrentTextureHost = nullptr;
-}
-
-void
-ImageHost::RemoveTextureHost(TextureHost* aTexture)
-{
-  MOZ_ASSERT(!mLocked);
-
-  CompositableHost::RemoveTextureHost(aTexture);
-
-  for (int32_t i = mImages.Length() - 1; i >= 0; --i) {
-    if (mImages[i].mTextureHost == aTexture) {
-      aTexture->UnbindTextureSource();
-      mImages.RemoveElementAt(i);
-    }
-  }
-}
-
 static TimeStamp
-GetBiasedTime(const TimeStamp& aInput, ImageHost::Bias aBias)
+GetBiasedTime(const TimeStamp& aInput, ImageComposite::Bias aBias)
 {
   switch (aBias) {
-  case ImageHost::BIAS_NEGATIVE:
+  case ImageComposite::BIAS_NEGATIVE:
     return aInput - TimeDuration::FromMilliseconds(BIAS_TIME_MS);
-  case ImageHost::BIAS_POSITIVE:
+  case ImageComposite::BIAS_POSITIVE:
     return aInput + TimeDuration::FromMilliseconds(BIAS_TIME_MS);
   default:
     return aInput;
   }
 }
 
-static ImageHost::Bias
-UpdateBias(const TimeStamp& aCompositionTime,
-           const TimeStamp& aCompositedImageTime,
-           const TimeStamp& aNextImageTime, // may be null
-           ImageHost::Bias aBias)
+/* static */ ImageComposite::Bias
+ImageComposite::UpdateBias(const TimeStamp& aCompositionTime,
+                           const TimeStamp& aCompositedImageTime,
+                           const TimeStamp& aNextImageTime, // may be null
+                           ImageComposite::Bias aBias)
 {
   if (aCompositedImageTime.IsNull()) {
-    return ImageHost::BIAS_NONE;
+    return ImageComposite::BIAS_NONE;
   }
   TimeDuration threshold = TimeDuration::FromMilliseconds(1.0);
   if (aCompositionTime - aCompositedImageTime < threshold &&
       aCompositionTime - aCompositedImageTime > -threshold) {
     // The chosen frame's time is very close to the composition time (probably
     // just before the current composition time, but due to previously set
     // negative bias, it could be just after the current composition time too).
     // If the inter-frame time is almost exactly equal to (a multiple of)
     // the inter-composition time, then we're in a dangerous situation because
     // jitter might cause frames to fall one side or the other of the
     // composition times, causing many frames to be skipped or duplicated.
     // Try to prevent that by adding a negative bias to the frame times during
     // the next composite; that should ensure the next frame's time is treated
     // as falling just before a composite time.
-    return ImageHost::BIAS_NEGATIVE;
+    return ImageComposite::BIAS_NEGATIVE;
   }
   if (!aNextImageTime.IsNull() &&
       aNextImageTime - aCompositionTime < threshold &&
       aNextImageTime - aCompositionTime > -threshold) {
     // The next frame's time is very close to our composition time (probably
     // just after the current composition time, but due to previously set
     // positive bias, it could be just before the current composition time too).
     // We're in a dangerous situation because jitter might cause frames to
     // fall one side or the other of the composition times, causing many frames
     // to be skipped or duplicated.
     // Try to prevent that by adding a negative bias to the frame times during
     // the next composite; that should ensure the next frame's time is treated
     // as falling just before a composite time.
-    return ImageHost::BIAS_POSITIVE;
+    return ImageComposite::BIAS_POSITIVE;
   }
-  return ImageHost::BIAS_NONE;
+  return ImageComposite::BIAS_NONE;
 }
 
-int ImageHost::ChooseImageIndex() const
+int
+ImageComposite::ChooseImageIndex() const
 {
-  if (!GetCompositor() || mImages.IsEmpty()) {
+  if (mImages.IsEmpty()) {
     return -1;
   }
-  TimeStamp now = GetCompositor()->GetCompositionTime();
+  TimeStamp now = GetCompositionTime();
 
   if (now.IsNull()) {
     // Not in a composition, so just return the last image we composited
     // (if it's one of the current images).
     for (uint32_t i = 0; i < mImages.Length(); ++i) {
       if (mImages[i].mFrameID == mLastFrameID &&
           mImages[i].mProducerID == mLastProducerID) {
         return i;
@@ -228,349 +101,24 @@ int ImageHost::ChooseImageIndex() const
   uint32_t result = 0;
   while (result + 1 < mImages.Length() &&
       GetBiasedTime(mImages[result + 1].mTimeStamp, mBias) <= now) {
     ++result;
   }
   return result;
 }
 
-const ImageHost::TimedImage* ImageHost::ChooseImage() const
-{
-  int index = ChooseImageIndex();
-  return index >= 0 ? &mImages[index] : nullptr;
-}
-
-ImageHost::TimedImage* ImageHost::ChooseImage()
+const ImageComposite::TimedImage* ImageComposite::ChooseImage() const
 {
   int index = ChooseImageIndex();
   return index >= 0 ? &mImages[index] : nullptr;
 }
 
-TextureHost*
-ImageHost::GetAsTextureHost(IntRect* aPictureRect)
-{
-  TimedImage* img = ChooseImage();
-  if (img) {
-    SetCurrentTextureHost(img->mTextureHost);
-  }
-  if (aPictureRect && img) {
-    *aPictureRect = img->mPictureRect;
-  }
-  return img ? img->mTextureHost.get() : nullptr;
-}
-
-void ImageHost::Attach(Layer* aLayer,
-                       Compositor* aCompositor,
-                       AttachFlags aFlags)
-{
-  CompositableHost::Attach(aLayer, aCompositor, aFlags);
-  for (auto& img : mImages) {
-    if (GetCompositor()) {
-      img.mTextureHost->SetCompositor(GetCompositor());
-    }
-    img.mTextureHost->Updated();
-  }
-}
-
-void
-ImageHost::Composite(LayerComposite* aLayer,
-                     EffectChain& aEffectChain,
-                     float aOpacity,
-                     const gfx::Matrix4x4& aTransform,
-                     const gfx::SamplingFilter aSamplingFilter,
-                     const gfx::IntRect& aClipRect,
-                     const nsIntRegion* aVisibleRegion,
-                     const Maybe<gfx::Polygon>& aGeometry)
+ImageComposite::TimedImage* ImageComposite::ChooseImage()
 {
-  if (!GetCompositor()) {
-    // should only happen when a tab is dragged to another window and
-    // async-video is still sending frames but we haven't attached the
-    // set the new compositor yet.
-    return;
-  }
-
-  int imageIndex = ChooseImageIndex();
-  if (imageIndex < 0) {
-    return;
-  }
-
-  if (uint32_t(imageIndex) + 1 < mImages.Length()) {
-    GetCompositor()->CompositeUntil(mImages[imageIndex + 1].mTimeStamp + TimeDuration::FromMilliseconds(BIAS_TIME_MS));
-  }
-
-  TimedImage* img = &mImages[imageIndex];
-  img->mTextureHost->SetCompositor(GetCompositor());
-  SetCurrentTextureHost(img->mTextureHost);
-
-  {
-    AutoLockCompositableHost autoLock(this);
-    if (autoLock.Failed()) {
-      NS_WARNING("failed to lock front buffer");
-      return;
-    }
-
-    if (!mCurrentTextureHost->BindTextureSource(mCurrentTextureSource)) {
-      return;
-    }
-
-    if (!mCurrentTextureSource) {
-      // BindTextureSource above should have returned false!
-      MOZ_ASSERT(false);
-      return;
-    }
-
-    bool isAlphaPremultiplied =
-        !(mCurrentTextureHost->GetFlags() & TextureFlags::NON_PREMULTIPLIED);
-    RefPtr<TexturedEffect> effect =
-        CreateTexturedEffect(mCurrentTextureHost,
-            mCurrentTextureSource.get(), aSamplingFilter, isAlphaPremultiplied,
-            GetRenderState());
-    if (!effect) {
-      return;
-    }
-
-    if (!GetCompositor()->SupportsEffect(effect->mType)) {
-      return;
-    }
-
-    DiagnosticFlags diagnosticFlags = DiagnosticFlags::IMAGE;
-    if (effect->mType == EffectTypes::NV12) {
-      diagnosticFlags |= DiagnosticFlags::NV12;
-    } else if (effect->mType == EffectTypes::YCBCR) {
-      diagnosticFlags |= DiagnosticFlags::YCBCR;
-    }
-
-    if (mLastFrameID != img->mFrameID || mLastProducerID != img->mProducerID) {
-      if (mAsyncRef) {
-        ImageCompositeNotificationInfo info;
-        info.mImageBridgeProcessId = mAsyncRef.mProcessId;
-        info.mNotification = ImageCompositeNotification(
-          mAsyncRef.mHandle,
-          img->mTimeStamp, GetCompositor()->GetCompositionTime(),
-          img->mFrameID, img->mProducerID);
-        static_cast<LayerManagerComposite*>(aLayer->GetLayerManager())->
-            AppendImageCompositeNotification(info);
-      }
-      mLastFrameID = img->mFrameID;
-      mLastProducerID = img->mProducerID;
-    }
-    aEffectChain.mPrimaryEffect = effect;
-    gfx::Rect pictureRect(0, 0, img->mPictureRect.width, img->mPictureRect.height);
-    BigImageIterator* it = mCurrentTextureSource->AsBigImageIterator();
-    if (it) {
-
-      // This iteration does not work if we have multiple texture sources here
-      // (e.g. 3 YCbCr textures). There's nothing preventing the different
-      // planes from having different resolutions or tile sizes. For example, a
-      // YCbCr frame could have Cb and Cr planes that are half the resolution of
-      // the Y plane, in such a way that the Y plane overflows the maximum
-      // texture size and the Cb and Cr planes do not. Then the Y plane would be
-      // split into multiple tiles and the Cb and Cr planes would just be one
-      // tile each.
-      // To handle the general case correctly, we'd have to create a grid of
-      // intersected tiles over all planes, and then draw each grid tile using
-      // the corresponding source tiles from all planes, with appropriate
-      // per-plane per-tile texture coords.
-      // DrawQuad currently assumes that all planes use the same texture coords.
-      MOZ_ASSERT(it->GetTileCount() == 1 || !mCurrentTextureSource->GetNextSibling(),
-                 "Can't handle multi-plane BigImages");
-
-      it->BeginBigImageIteration();
-      do {
-        IntRect tileRect = it->GetTileRect();
-        gfx::Rect rect(tileRect.x, tileRect.y, tileRect.width, tileRect.height);
-        rect = rect.Intersect(pictureRect);
-        effect->mTextureCoords = Rect(Float(rect.x - tileRect.x) / tileRect.width,
-                                      Float(rect.y - tileRect.y) / tileRect.height,
-                                      Float(rect.width) / tileRect.width,
-                                      Float(rect.height) / tileRect.height);
-        if (img->mTextureHost->GetFlags() & TextureFlags::ORIGIN_BOTTOM_LEFT) {
-          effect->mTextureCoords.y = effect->mTextureCoords.YMost();
-          effect->mTextureCoords.height = -effect->mTextureCoords.height;
-        }
-        GetCompositor()->DrawGeometry(rect, aClipRect, aEffectChain,
-                                      aOpacity, aTransform, aGeometry);
-        GetCompositor()->DrawDiagnostics(diagnosticFlags | DiagnosticFlags::BIGIMAGE,
-                                         rect, aClipRect, aTransform, mFlashCounter);
-      } while (it->NextTile());
-      it->EndBigImageIteration();
-      // layer border
-      GetCompositor()->DrawDiagnostics(diagnosticFlags, pictureRect,
-                                       aClipRect, aTransform, mFlashCounter);
-    } else {
-      IntSize textureSize = mCurrentTextureSource->GetSize();
-      effect->mTextureCoords = Rect(Float(img->mPictureRect.x) / textureSize.width,
-                                    Float(img->mPictureRect.y) / textureSize.height,
-                                    Float(img->mPictureRect.width) / textureSize.width,
-                                    Float(img->mPictureRect.height) / textureSize.height);
-
-      if (img->mTextureHost->GetFlags() & TextureFlags::ORIGIN_BOTTOM_LEFT) {
-        effect->mTextureCoords.y = effect->mTextureCoords.YMost();
-        effect->mTextureCoords.height = -effect->mTextureCoords.height;
-      }
-
-      GetCompositor()->DrawGeometry(pictureRect, aClipRect, aEffectChain,
-                                    aOpacity, aTransform, aGeometry);
-      GetCompositor()->DrawDiagnostics(diagnosticFlags,
-                                       pictureRect, aClipRect,
-                                       aTransform, mFlashCounter);
-    }
-  }
-
-  // Update mBias last. This can change which frame ChooseImage(Index) would
-  // return, and we don't want to do that until we've finished compositing
-  // since callers of ChooseImage(Index) assume the same image will be chosen
-  // during a given composition. This must happen after autoLock's
-  // destructor!
-  mBias = UpdateBias(
-      GetCompositor()->GetCompositionTime(), mImages[imageIndex].mTimeStamp,
-      uint32_t(imageIndex + 1) < mImages.Length() ?
-          mImages[imageIndex + 1].mTimeStamp : TimeStamp(),
-      mBias);
-}
-
-void
-ImageHost::SetCompositor(Compositor* aCompositor)
-{
-  if (mCompositor != aCompositor) {
-    for (auto& img : mImages) {
-      img.mTextureHost->SetCompositor(aCompositor);
-    }
-  }
-  CompositableHost::SetCompositor(aCompositor);
-}
-
-void
-ImageHost::PrintInfo(std::stringstream& aStream, const char* aPrefix)
-{
-  aStream << aPrefix;
-  aStream << nsPrintfCString("ImageHost (0x%p)", this).get();
-
-  nsAutoCString pfx(aPrefix);
-  pfx += "  ";
-  for (auto& img : mImages) {
-    aStream << "\n";
-    img.mTextureHost->PrintInfo(aStream, pfx.get());
-    AppendToString(aStream, img.mPictureRect, " [picture-rect=", "]");
-  }
-}
-
-void
-ImageHost::Dump(std::stringstream& aStream,
-                const char* aPrefix,
-                bool aDumpHtml)
-{
-  for (auto& img : mImages) {
-    aStream << aPrefix;
-    aStream << (aDumpHtml ? "<ul><li>TextureHost: "
-                             : "TextureHost: ");
-    DumpTextureHost(aStream, img.mTextureHost);
-    aStream << (aDumpHtml ? " </li></ul> " : " ");
-  }
-}
-
-LayerRenderState
-ImageHost::GetRenderState()
-{
-  TimedImage* img = ChooseImage();
-  if (img) {
-    SetCurrentTextureHost(img->mTextureHost);
-    return img->mTextureHost->GetRenderState();
-  }
-  return LayerRenderState();
-}
-
-already_AddRefed<gfx::DataSourceSurface>
-ImageHost::GetAsSurface()
-{
-  TimedImage* img = ChooseImage();
-  if (img) {
-    return img->mTextureHost->GetAsSurface();
-  }
-  return nullptr;
-}
-
-bool
-ImageHost::Lock()
-{
-  MOZ_ASSERT(!mLocked);
-  TimedImage* img = ChooseImage();
-  if (!img) {
-    return false;
-  }
-
-  SetCurrentTextureHost(img->mTextureHost);
-
-  if (!mCurrentTextureHost->Lock()) {
-    return false;
-  }
-  mLocked = true;
-  return true;
-}
-
-void
-ImageHost::Unlock()
-{
-  MOZ_ASSERT(mLocked);
-
-  if (mCurrentTextureHost) {
-    mCurrentTextureHost->Unlock();
-  }
-  mLocked = false;
-}
-
-IntSize
-ImageHost::GetImageSize() const
-{
-  const TimedImage* img = ChooseImage();
-  if (img) {
-    return IntSize(img->mPictureRect.width, img->mPictureRect.height);
-  }
-  return IntSize();
-}
-
-bool
-ImageHost::IsOpaque()
-{
-  const TimedImage* img = ChooseImage();
-  if (!img) {
-    return false;
-  }
-
-  if (img->mPictureRect.width == 0 ||
-      img->mPictureRect.height == 0 ||
-      !img->mTextureHost) {
-    return false;
-  }
-
-  gfx::SurfaceFormat format = img->mTextureHost->GetFormat();
-  if (gfx::IsOpaque(format)) {
-    return true;
-  }
-  return false;
-}
-
-already_AddRefed<TexturedEffect>
-ImageHost::GenEffect(const gfx::SamplingFilter aSamplingFilter)
-{
-  TimedImage* img = ChooseImage();
-  if (!img) {
-    return nullptr;
-  }
-  SetCurrentTextureHost(img->mTextureHost);
-  if (!mCurrentTextureHost->BindTextureSource(mCurrentTextureSource)) {
-    return nullptr;
-  }
-  bool isAlphaPremultiplied = true;
-  if (mCurrentTextureHost->GetFlags() & TextureFlags::NON_PREMULTIPLIED) {
-    isAlphaPremultiplied = false;
-  }
-
-  return CreateTexturedEffect(mCurrentTextureHost,
-                              mCurrentTextureSource,
-                              aSamplingFilter,
-                              isAlphaPremultiplied,
-                              GetRenderState());
+  int index = ChooseImageIndex();
+  return index >= 0 ? &mImages[index] : nullptr;
 }
 
 } // namespace layers
 } // namespace mozilla
+
+#undef BIAS_TIME_MS
copy from gfx/layers/composite/ImageHost.h
copy to gfx/layers/composite/ImageComposite.h
--- a/gfx/layers/composite/ImageHost.h
+++ b/gfx/layers/composite/ImageComposite.h
@@ -1,95 +1,32 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef MOZILLA_GFX_IMAGEHOST_H
-#define MOZILLA_GFX_IMAGEHOST_H
+#ifndef MOZILLA_GFX_IMAGECOMPOSITE_H
+#define MOZILLA_GFX_IMAGECOMPOSITE_H
 
-#include <stdio.h>                      // for FILE
-#include "CompositableHost.h"           // for CompositableHost
-#include "mozilla/Attributes.h"         // for override
-#include "mozilla/RefPtr.h"             // for RefPtr
-#include "mozilla/gfx/MatrixFwd.h"      // for Matrix4x4
-#include "mozilla/gfx/Point.h"          // for Point
-#include "mozilla/gfx/Polygon.h"        // for Polygon
-#include "mozilla/gfx/Rect.h"           // for Rect
-#include "mozilla/gfx/Types.h"          // for SamplingFilter
-#include "mozilla/layers/CompositorTypes.h"  // for TextureInfo, etc
-#include "mozilla/layers/LayersSurfaces.h"  // for SurfaceDescriptor
-#include "mozilla/layers/LayersTypes.h"  // for LayerRenderState, etc
-#include "mozilla/layers/TextureHost.h"  // for TextureHost, etc
-#include "mozilla/mozalloc.h"           // for operator delete
-#include "nsCOMPtr.h"                   // for already_AddRefed
-#include "nsRect.h"                     // for mozilla::gfx::IntRect
-#include "nsRegionFwd.h"                // for nsIntRegion
-#include "nscore.h"                     // for nsACString
+#include "CompositableHost.h"           // for CompositableTextureHostRef
+#include "mozilla/gfx/2D.h"
+#include "mozilla/TimeStamp.h"          // for TimeStamp
+#include "nsTArray.h"
 
 namespace mozilla {
 namespace layers {
 
-class Compositor;
-struct EffectChain;
-class ImageContainerParent;
-
 /**
- * ImageHost. Works with ImageClientSingle and ImageClientBuffered
+ * Implements Image selection logic.
  */
-class ImageHost : public CompositableHost
+class ImageComposite
 {
 public:
-  explicit ImageHost(const TextureInfo& aTextureInfo);
-  ~ImageHost();
-
-  virtual CompositableType GetType() override { return mTextureInfo.mCompositableType; }
-
-  virtual void Composite(LayerComposite* aLayer,
-                         EffectChain& aEffectChain,
-                         float aOpacity,
-                         const gfx::Matrix4x4& aTransform,
-                         const gfx::SamplingFilter aSamplingFilter,
-                         const gfx::IntRect& aClipRect,
-                         const nsIntRegion* aVisibleRegion = nullptr,
-                         const Maybe<gfx::Polygon>& aGeometry = Nothing()) override;
-
-  virtual void UseTextureHost(const nsTArray<TimedTexture>& aTextures) override;
-
-  virtual void RemoveTextureHost(TextureHost* aTexture) override;
-
-  virtual TextureHost* GetAsTextureHost(gfx::IntRect* aPictureRect = nullptr) override;
-
-  virtual void Attach(Layer* aLayer,
-                      Compositor* aCompositor,
-                      AttachFlags aFlags = NO_FLAGS) override;
-
-  virtual void SetCompositor(Compositor* aCompositor) override;
-
-  gfx::IntSize GetImageSize() const override;
-
-  virtual LayerRenderState GetRenderState() override;
-
-  virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) override;
-
-  virtual void Dump(std::stringstream& aStream,
-                    const char* aPrefix = "",
-                    bool aDumpHtml = false) override;
-
-  virtual already_AddRefed<gfx::DataSourceSurface> GetAsSurface() override;
-
-  virtual bool Lock() override;
-
-  virtual void Unlock() override;
-
-  virtual already_AddRefed<TexturedEffect> GenEffect(const gfx::SamplingFilter aSamplingFilter) override;
-
-  void SetCurrentTextureHost(TextureHost* aTexture);
-
-  virtual void CleanupResources() override;
+  explicit ImageComposite();
+  ~ImageComposite();
 
   int32_t GetFrameID()
   {
     const TimedImage* img = ChooseImage();
     return img ? img->mFrameID : -1;
   }
 
   int32_t GetProducerID()
@@ -105,37 +42,32 @@ public:
     // Don't apply bias to frame times
     BIAS_NONE,
     // Apply a negative bias to frame times to keep them before the vsync time
     BIAS_NEGATIVE,
     // Apply a positive bias to frame times to keep them after the vsync time
     BIAS_POSITIVE,
   };
 
-  bool IsOpaque();
+protected:
+  static Bias UpdateBias(const TimeStamp& aCompositionTime,
+                         const TimeStamp& aCompositedImageTime,
+                         const TimeStamp& aNextImageTime, // may be null
+                         ImageComposite::Bias aBias);
 
-protected:
+  virtual TimeStamp GetCompositionTime() const = 0;
+
   struct TimedImage {
     CompositableTextureHostRef mTextureHost;
     TimeStamp mTimeStamp;
     gfx::IntRect mPictureRect;
     int32_t mFrameID;
     int32_t mProducerID;
   };
 
-  // Use a simple RefPtr because the same texture is already held by a
-  // a CompositableTextureHostRef in the array of TimedImage.
-  // See the comment in CompositableTextureRef for more details.
-  RefPtr<TextureHost> mCurrentTextureHost;
-  CompositableTextureSourceRef mCurrentTextureSource;
-  // When doing texture uploads it's best to alternate between two (or three)
-  // texture sources so that the texture we upload to isn't being used by
-  // the GPU to composite the previous frame.
-  RefPtr<TextureSource> mExtraTextureSource;
-
   /**
    * ChooseImage is guaranteed to return the same TimedImage every time it's
    * called during the same composition, up to the end of Composite() ---
    * it depends only on mImages, mCompositor->GetCompositionTime(), and mBias.
    * mBias is updated at the end of Composite().
    */
   const TimedImage* ChooseImage() const;
   TimedImage* ChooseImage();
@@ -143,16 +75,14 @@ protected:
 
   nsTArray<TimedImage> mImages;
   int32_t mLastFrameID;
   int32_t mLastProducerID;
   /**
    * Bias to apply to the next frame.
    */
   Bias mBias;
-
-  bool mLocked;
 };
 
 } // namespace layers
 } // namespace mozilla
 
-#endif
+#endif // MOZILLA_GFX_IMAGECOMPOSITE_H
--- a/gfx/layers/composite/ImageHost.cpp
+++ b/gfx/layers/composite/ImageHost.cpp
@@ -11,31 +11,30 @@
 #include "mozilla/layers/Compositor.h"  // for Compositor
 #include "mozilla/layers/Effects.h"     // for TexturedEffect, Effect, etc
 #include "mozilla/layers/LayerManagerComposite.h"     // for TexturedEffect, Effect, etc
 #include "nsAString.h"
 #include "nsDebug.h"                    // for NS_WARNING, NS_ASSERTION
 #include "nsPrintfCString.h"            // for nsPrintfCString
 #include "nsString.h"                   // for nsAutoCString
 
+// this is also defined in ImageComposite.cpp
 #define BIAS_TIME_MS 1.0
 
 namespace mozilla {
 
 using namespace gfx;
 
 namespace layers {
 
 class ISurfaceAllocator;
 
 ImageHost::ImageHost(const TextureInfo& aTextureInfo)
   : CompositableHost(aTextureInfo)
-  , mLastFrameID(-1)
-  , mLastProducerID(-1)
-  , mBias(BIAS_NONE)
+  , ImageComposite()
   , mLocked(false)
 {}
 
 ImageHost::~ImageHost()
 {
 }
 
 void
@@ -147,107 +146,24 @@ ImageHost::RemoveTextureHost(TextureHost
   for (int32_t i = mImages.Length() - 1; i >= 0; --i) {
     if (mImages[i].mTextureHost == aTexture) {
       aTexture->UnbindTextureSource();
       mImages.RemoveElementAt(i);
     }
   }
 }
 
-static TimeStamp
-GetBiasedTime(const TimeStamp& aInput, ImageHost::Bias aBias)
+TimeStamp
+ImageHost::GetCompositionTime() const
 {
-  switch (aBias) {
-  case ImageHost::BIAS_NEGATIVE:
-    return aInput - TimeDuration::FromMilliseconds(BIAS_TIME_MS);
-  case ImageHost::BIAS_POSITIVE:
-    return aInput + TimeDuration::FromMilliseconds(BIAS_TIME_MS);
-  default:
-    return aInput;
-  }
-}
-
-static ImageHost::Bias
-UpdateBias(const TimeStamp& aCompositionTime,
-           const TimeStamp& aCompositedImageTime,
-           const TimeStamp& aNextImageTime, // may be null
-           ImageHost::Bias aBias)
-{
-  if (aCompositedImageTime.IsNull()) {
-    return ImageHost::BIAS_NONE;
-  }
-  TimeDuration threshold = TimeDuration::FromMilliseconds(1.0);
-  if (aCompositionTime - aCompositedImageTime < threshold &&
-      aCompositionTime - aCompositedImageTime > -threshold) {
-    // The chosen frame's time is very close to the composition time (probably
-    // just before the current composition time, but due to previously set
-    // negative bias, it could be just after the current composition time too).
-    // If the inter-frame time is almost exactly equal to (a multiple of)
-    // the inter-composition time, then we're in a dangerous situation because
-    // jitter might cause frames to fall one side or the other of the
-    // composition times, causing many frames to be skipped or duplicated.
-    // Try to prevent that by adding a negative bias to the frame times during
-    // the next composite; that should ensure the next frame's time is treated
-    // as falling just before a composite time.
-    return ImageHost::BIAS_NEGATIVE;
+  TimeStamp time;
+  if (GetCompositor()) {
+    time = GetCompositor()->GetCompositionTime();
   }
-  if (!aNextImageTime.IsNull() &&
-      aNextImageTime - aCompositionTime < threshold &&
-      aNextImageTime - aCompositionTime > -threshold) {
-    // The next frame's time is very close to our composition time (probably
-    // just after the current composition time, but due to previously set
-    // positive bias, it could be just before the current composition time too).
-    // We're in a dangerous situation because jitter might cause frames to
-    // fall one side or the other of the composition times, causing many frames
-    // to be skipped or duplicated.
-    // Try to prevent that by adding a negative bias to the frame times during
-    // the next composite; that should ensure the next frame's time is treated
-    // as falling just before a composite time.
-    return ImageHost::BIAS_POSITIVE;
-  }
-  return ImageHost::BIAS_NONE;
-}
-
-int ImageHost::ChooseImageIndex() const
-{
-  if (!GetCompositor() || mImages.IsEmpty()) {
-    return -1;
-  }
-  TimeStamp now = GetCompositor()->GetCompositionTime();
-
-  if (now.IsNull()) {
-    // Not in a composition, so just return the last image we composited
-    // (if it's one of the current images).
-    for (uint32_t i = 0; i < mImages.Length(); ++i) {
-      if (mImages[i].mFrameID == mLastFrameID &&
-          mImages[i].mProducerID == mLastProducerID) {
-        return i;
-      }
-    }
-    return -1;
-  }
-
-  uint32_t result = 0;
-  while (result + 1 < mImages.Length() &&
-      GetBiasedTime(mImages[result + 1].mTimeStamp, mBias) <= now) {
-    ++result;
-  }
-  return result;
-}
-
-const ImageHost::TimedImage* ImageHost::ChooseImage() const
-{
-  int index = ChooseImageIndex();
-  return index >= 0 ? &mImages[index] : nullptr;
-}
-
-ImageHost::TimedImage* ImageHost::ChooseImage()
-{
-  int index = ChooseImageIndex();
-  return index >= 0 ? &mImages[index] : nullptr;
+  return time;
 }
 
 TextureHost*
 ImageHost::GetAsTextureHost(IntRect* aPictureRect)
 {
   TimedImage* img = ChooseImage();
   if (img) {
     SetCurrentTextureHost(img->mTextureHost);
@@ -569,8 +485,10 @@ ImageHost::GenEffect(const gfx::Sampling
                               mCurrentTextureSource,
                               aSamplingFilter,
                               isAlphaPremultiplied,
                               GetRenderState());
 }
 
 } // namespace layers
 } // namespace mozilla
+
+#undef BIAS_TIME_MS
--- a/gfx/layers/composite/ImageHost.h
+++ b/gfx/layers/composite/ImageHost.h
@@ -11,36 +11,37 @@
 #include "mozilla/Attributes.h"         // for override
 #include "mozilla/RefPtr.h"             // for RefPtr
 #include "mozilla/gfx/MatrixFwd.h"      // for Matrix4x4
 #include "mozilla/gfx/Point.h"          // for Point
 #include "mozilla/gfx/Polygon.h"        // for Polygon
 #include "mozilla/gfx/Rect.h"           // for Rect
 #include "mozilla/gfx/Types.h"          // for SamplingFilter
 #include "mozilla/layers/CompositorTypes.h"  // for TextureInfo, etc
+#include "mozilla/layers/ImageComposite.h"  // for ImageComposite
 #include "mozilla/layers/LayersSurfaces.h"  // for SurfaceDescriptor
 #include "mozilla/layers/LayersTypes.h"  // for LayerRenderState, etc
 #include "mozilla/layers/TextureHost.h"  // for TextureHost, etc
 #include "mozilla/mozalloc.h"           // for operator delete
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsRect.h"                     // for mozilla::gfx::IntRect
 #include "nsRegionFwd.h"                // for nsIntRegion
 #include "nscore.h"                     // for nsACString
 
 namespace mozilla {
 namespace layers {
 
 class Compositor;
 struct EffectChain;
-class ImageContainerParent;
 
 /**
  * ImageHost. Works with ImageClientSingle and ImageClientBuffered
  */
-class ImageHost : public CompositableHost
+class ImageHost : public CompositableHost,
+                  public ImageComposite
 {
 public:
   explicit ImageHost(const TextureInfo& aTextureInfo);
   ~ImageHost();
 
   virtual CompositableType GetType() override { return mTextureInfo.mCompositableType; }
 
   virtual void Composite(LayerComposite* aLayer,
@@ -81,78 +82,31 @@ public:
   virtual void Unlock() override;
 
   virtual already_AddRefed<TexturedEffect> GenEffect(const gfx::SamplingFilter aSamplingFilter) override;
 
   void SetCurrentTextureHost(TextureHost* aTexture);
 
   virtual void CleanupResources() override;
 
-  int32_t GetFrameID()
-  {
-    const TimedImage* img = ChooseImage();
-    return img ? img->mFrameID : -1;
-  }
-
-  int32_t GetProducerID()
-  {
-    const TimedImage* img = ChooseImage();
-    return img ? img->mProducerID : -1;
-  }
-
-  int32_t GetLastFrameID() const { return mLastFrameID; }
-  int32_t GetLastProducerID() const { return mLastProducerID; }
-
-  enum Bias {
-    // Don't apply bias to frame times
-    BIAS_NONE,
-    // Apply a negative bias to frame times to keep them before the vsync time
-    BIAS_NEGATIVE,
-    // Apply a positive bias to frame times to keep them after the vsync time
-    BIAS_POSITIVE,
-  };
-
   bool IsOpaque();
 
 protected:
-  struct TimedImage {
-    CompositableTextureHostRef mTextureHost;
-    TimeStamp mTimeStamp;
-    gfx::IntRect mPictureRect;
-    int32_t mFrameID;
-    int32_t mProducerID;
-  };
+  // ImageComposite
+  virtual TimeStamp GetCompositionTime() const override;
 
   // Use a simple RefPtr because the same texture is already held by a
   // a CompositableTextureHostRef in the array of TimedImage.
   // See the comment in CompositableTextureRef for more details.
   RefPtr<TextureHost> mCurrentTextureHost;
   CompositableTextureSourceRef mCurrentTextureSource;
   // When doing texture uploads it's best to alternate between two (or three)
   // texture sources so that the texture we upload to isn't being used by
   // the GPU to composite the previous frame.
   RefPtr<TextureSource> mExtraTextureSource;
 
-  /**
-   * ChooseImage is guaranteed to return the same TimedImage every time it's
-   * called during the same composition, up to the end of Composite() ---
-   * it depends only on mImages, mCompositor->GetCompositionTime(), and mBias.
-   * mBias is updated at the end of Composite().
-   */
-  const TimedImage* ChooseImage() const;
-  TimedImage* ChooseImage();
-  int ChooseImageIndex() const;
-
-  nsTArray<TimedImage> mImages;
-  int32_t mLastFrameID;
-  int32_t mLastProducerID;
-  /**
-   * Bias to apply to the next frame.
-   */
-  Bias mBias;
-
   bool mLocked;
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif
--- a/gfx/layers/composite/LayerManagerComposite.cpp
+++ b/gfx/layers/composite/LayerManagerComposite.cpp
@@ -55,16 +55,17 @@
 #ifdef MOZ_WIDGET_ANDROID
 #include <android/log.h>
 #include <android/native_window.h>
 #endif
 #if defined(MOZ_WIDGET_ANDROID)
 #include "opengl/CompositorOGL.h"
 #include "GLContextEGL.h"
 #include "GLContextProvider.h"
+#include "mozilla/widget/AndroidCompositorWidget.h"
 #include "ScopedGLHelpers.h"
 #endif
 #include "GeckoProfiler.h"
 #include "TextRenderer.h"               // for TextRenderer
 #include "mozilla/layers/CompositorBridgeParent.h"
 #include "TreeTraversal.h"              // for ForEachNode
 
 #ifdef USE_SKIA
--- a/gfx/layers/composite/LayerManagerComposite.h
+++ b/gfx/layers/composite/LayerManagerComposite.h
@@ -2,16 +2,17 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFX_LayerManagerComposite_H
 #define GFX_LayerManagerComposite_H
 
 #include <stdint.h>                     // for int32_t, uint32_t
+#include "CompositableHost.h"           // for CompositableHost, ImageCompositeNotificationInfo
 #include "GLDefs.h"                     // for GLenum
 #include "Layers.h"
 #include "Units.h"                      // for ParentLayerIntRect
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
 #include "mozilla/Attributes.h"         // for override
 #include "mozilla/RefPtr.h"             // for RefPtr, already_AddRefed
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/Point.h"          // for IntSize
@@ -44,37 +45,31 @@ namespace mozilla {
 namespace gfx {
 class DrawTarget;
 } // namespace gfx
 
 namespace layers {
 
 class CanvasLayerComposite;
 class ColorLayerComposite;
-class CompositableHost;
 class Compositor;
 class ContainerLayerComposite;
 struct EffectChain;
 class ImageLayer;
 class ImageLayerComposite;
 class LayerComposite;
 class RefLayerComposite;
 class PaintedLayerComposite;
 class TextRenderer;
 class CompositingRenderTarget;
 struct FPSState;
 class PaintCounter;
 
 static const int kVisualWarningDuration = 150; // ms
 
-struct ImageCompositeNotificationInfo {
-  base::ProcessId mImageBridgeProcessId;
-  ImageCompositeNotification mNotification;
-};
-
 // An implementation of LayerManager that acts as a pair with ClientLayerManager
 // and is mirrored across IPDL. This gets managed/updated by LayerTransactionParent.
 class HostLayerManager : public LayerManager
 {
 public:
   HostLayerManager();
   ~HostLayerManager();
 
@@ -104,18 +99,16 @@ public:
   virtual LayersBackend GetBackendType() override
   {
     MOZ_CRASH("GFX: Shouldn't be called for composited layer manager");
   }
   virtual void GetBackendName(nsAString& name) override
   {
     MOZ_CRASH("GFX: Shouldn't be called for composited layer manager");
   }
-  virtual TextureFactoryIdentifier GetTextureFactoryIdentifier() = 0;
-
 
   virtual void ForcePresent() = 0;
   virtual void AddInvalidRegion(const nsIntRegion& aRegion) = 0;
   virtual void ClearApproximatelyVisibleRegions(uint64_t aLayersId,
                                                 const Maybe<uint32_t>& aPresShellId) = 0;
   virtual void UpdateApproximatelyVisibleRegion(const ScrollableLayerGuid& aGuid,
                                                 const CSSIntRegion& aRegion) = 0;
 
--- a/gfx/layers/composite/TextureHost.cpp
+++ b/gfx/layers/composite/TextureHost.cpp
@@ -197,17 +197,18 @@ TextureHost::Create(const SurfaceDescrip
       return CreateBackendIndependentTextureHost(aDesc, aDeallocator, aFlags);
 
     case SurfaceDescriptor::TEGLImageDescriptor:
     case SurfaceDescriptor::TSurfaceTextureDescriptor:
     case SurfaceDescriptor::TSurfaceDescriptorSharedGLTexture:
       return CreateTextureHostOGL(aDesc, aDeallocator, aFlags);
 
     case SurfaceDescriptor::TSurfaceDescriptorMacIOSurface:
-      if (aBackend == LayersBackend::LAYERS_OPENGL) {
+      if (aBackend == LayersBackend::LAYERS_OPENGL ||
+          aBackend == LayersBackend::LAYERS_WR) {
         return CreateTextureHostOGL(aDesc, aDeallocator, aFlags);
       } else {
         return CreateTextureHostBasic(aDesc, aDeallocator, aFlags);
       }
 
 #ifdef MOZ_X11
     case SurfaceDescriptor::TSurfaceDescriptorX11: {
       const SurfaceDescriptorX11& desc = aDesc.get_SurfaceDescriptorX11();
--- a/gfx/layers/ipc/CompositorBridgeChild.cpp
+++ b/gfx/layers/ipc/CompositorBridgeChild.cpp
@@ -15,16 +15,17 @@
 #include "mozilla/layers/ImageBridgeChild.h"
 #include "mozilla/layers/APZChild.h"
 #include "mozilla/layers/IAPZCTreeManager.h"
 #include "mozilla/layers/APZCTreeManagerChild.h"
 #include "mozilla/layers/LayerTransactionChild.h"
 #include "mozilla/layers/PLayerTransactionChild.h"
 #include "mozilla/layers/TextureClient.h"// for TextureClient
 #include "mozilla/layers/TextureClientPool.h"// for TextureClientPool
+#include "mozilla/layers/WebRenderBridgeChild.h"
 #include "mozilla/gfx/gfxVars.h"
 #include "mozilla/gfx/GPUProcessManager.h"
 #include "mozilla/gfx/Logging.h"
 #include "mozilla/mozalloc.h"           // for operator new, etc
 #include "nsAutoPtr.h"
 #include "nsDebug.h"                    // for NS_RUNTIMEABORT
 #include "nsIObserver.h"                // for nsIObserver
 #include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
@@ -140,16 +141,24 @@ CompositorBridgeChild::Destroy()
   AutoTArray<PLayerTransactionChild*, 16> transactions;
   ManagedPLayerTransactionChild(transactions);
   for (int i = transactions.Length() - 1; i >= 0; --i) {
     RefPtr<LayerTransactionChild> layers =
       static_cast<LayerTransactionChild*>(transactions[i]);
     layers->Destroy();
   }
 
+  AutoTArray<PWebRenderBridgeChild*, 16> wRBridges;
+  ManagedPWebRenderBridgeChild(wRBridges);
+  for (int i = wRBridges.Length() - 1; i >= 0; --i) {
+    RefPtr<WebRenderBridgeChild> wRBridge =
+      static_cast<WebRenderBridgeChild*>(wRBridges[i]);
+    wRBridge->Destroy();
+  }
+
   const ManagedContainer<PTextureChild>& textures = ManagedPTextureChild();
   for (auto iter = textures.ConstIter(); !iter.Done(); iter.Next()) {
     RefPtr<TextureClient> texture = TextureClient::AsTextureClient(iter.Get()->GetKey());
 
     if (texture) {
       texture->Destroy();
     }
   }
@@ -563,18 +572,20 @@ CompositorBridgeChild::RecvHideAllPlugin
 
 mozilla::ipc::IPCResult
 CompositorBridgeChild::RecvDidComposite(const uint64_t& aId, const uint64_t& aTransactionId,
                                         const TimeStamp& aCompositeStart,
                                         const TimeStamp& aCompositeEnd)
 {
   if (mLayerManager) {
     MOZ_ASSERT(aId == 0);
-    RefPtr<ClientLayerManager> m = mLayerManager->AsClientLayerManager();
-    MOZ_ASSERT(m);
+    MOZ_ASSERT(mLayerManager->GetBackendType() == LayersBackend::LAYERS_CLIENT ||
+               mLayerManager->GetBackendType() == LayersBackend::LAYERS_WR);
+    // Hold a reference to keep LayerManager alive. See Bug 1242668.
+    RefPtr<LayerManager> m = mLayerManager;
     m->DidComposite(aTransactionId, aCompositeStart, aCompositeEnd);
   } else if (aId != 0) {
     RefPtr<dom::TabChild> child = dom::TabChild::GetFrom(aId);
     if (child) {
       child->DidComposite(aTransactionId, aCompositeStart, aCompositeEnd);
     }
   }
 
@@ -1114,11 +1125,27 @@ CompositorBridgeChild::WillEndTransactio
 }
 
 void
 CompositorBridgeChild::HandleFatalError(const char* aName, const char* aMsg) const
 {
   dom::ContentChild::FatalErrorIfNotUsingGPUProcess(aName, aMsg, OtherPid());
 }
 
+PWebRenderBridgeChild*
+CompositorBridgeChild::AllocPWebRenderBridgeChild(const wr::PipelineId& aPipelineId, TextureFactoryIdentifier*)
+{
+  WebRenderBridgeChild* child = new WebRenderBridgeChild(aPipelineId);
+  child->AddIPDLReference();
+  return child;
+}
+
+bool
+CompositorBridgeChild::DeallocPWebRenderBridgeChild(PWebRenderBridgeChild* aActor)
+{
+  WebRenderBridgeChild* child = static_cast<WebRenderBridgeChild*>(aActor);
+  child->ReleaseIPDLReference();
+  return true;
+}
+
 } // namespace layers
 } // namespace mozilla
 
--- a/gfx/layers/ipc/CompositorBridgeChild.h
+++ b/gfx/layers/ipc/CompositorBridgeChild.h
@@ -99,17 +99,17 @@ public:
                    const TimeStamp& aCompositeEnd) override;
 
   virtual mozilla::ipc::IPCResult
   RecvInvalidateLayers(const uint64_t& aLayersId) override;
 
   virtual mozilla::ipc::IPCResult
   RecvCompositorUpdated(const uint64_t& aLayersId,
                         const TextureFactoryIdentifier& aNewIdentifier,
-                        const uint64_t& aSequenceNumber) override;
+                        const uint64_t& aSeqNo) override;
 
   virtual mozilla::ipc::IPCResult
   RecvUpdatePluginConfigurations(const LayoutDeviceIntPoint& aContentOffset,
                                  const LayoutDeviceIntRegion& aVisibleRegion,
                                  nsTArray<PluginWindowData>&& aPlugins) override;
 
   virtual mozilla::ipc::IPCResult
   RecvCaptureAllPlugins(const uintptr_t& aParentWidget) override;
@@ -218,16 +218,19 @@ public:
 
   PAPZChild* AllocPAPZChild(const uint64_t& aLayersId) override;
   bool DeallocPAPZChild(PAPZChild* aActor) override;
 
   void ProcessingError(Result aCode, const char* aReason) override;
 
   void WillEndTransaction();
 
+  PWebRenderBridgeChild* AllocPWebRenderBridgeChild(const wr::PipelineId& aPipelineId, TextureFactoryIdentifier*) override;
+  bool DeallocPWebRenderBridgeChild(PWebRenderBridgeChild* aActor) override;
+
   uint64_t DeviceResetSequenceNumber() const {
     return mDeviceResetSequenceNumber;
   }
 
 private:
   // Private destructor, to discourage deletion outside of Release():
   virtual ~CompositorBridgeChild();
 
--- a/gfx/layers/ipc/CompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CompositorBridgeParent.cpp
@@ -23,18 +23,20 @@
 #endif
 #include "gfxPrefs.h"                   // for gfxPrefs
 #include "mozilla/AutoRestore.h"        // for AutoRestore
 #include "mozilla/ClearOnShutdown.h"    // for ClearOnShutdown
 #include "mozilla/DebugOnly.h"          // for DebugOnly
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/TabParent.h"
 #include "mozilla/gfx/2D.h"          // for DrawTarget
+#include "mozilla/gfx/GPUChild.h"       // for GfxPrefValue
 #include "mozilla/gfx/Point.h"          // for IntSize
 #include "mozilla/gfx/Rect.h"          // for IntSize
+#include "mozilla/gfx/gfxVars.h"        // for gfxVars
 #include "VRManager.h"                  // for VRManager
 #include "mozilla/ipc/Transport.h"      // for Transport
 #include "mozilla/layers/APZCTreeManager.h"  // for APZCTreeManager
 #include "mozilla/layers/APZCTreeManagerParent.h"  // for APZCTreeManagerParent
 #include "mozilla/layers/APZThreadUtils.h"  // for APZCTreeManager
 #include "mozilla/layers/AsyncCompositionManager.h"
 #include "mozilla/layers/BasicCompositor.h"  // for BasicCompositor
 #include "mozilla/layers/Compositor.h"  // for Compositor
@@ -45,17 +47,21 @@
 #include "mozilla/layers/CrossProcessCompositorBridgeParent.h"
 #include "mozilla/layers/FrameUniformityData.h"
 #include "mozilla/layers/ImageBridgeParent.h"
 #include "mozilla/layers/LayerManagerComposite.h"
 #include "mozilla/layers/LayerTreeOwnerTracker.h"
 #include "mozilla/layers/LayersTypes.h"
 #include "mozilla/layers/PLayerTransactionParent.h"
 #include "mozilla/layers/RemoteContentController.h"
+#include "mozilla/layers/WebRenderBridgeParent.h"
+#include "mozilla/layers/WebRenderCompositableHolder.h"
+#include "mozilla/layers/WebRenderCompositorOGL.h"
 #include "mozilla/layout/RenderFrameParent.h"
+#include "mozilla/webrender/WebRenderAPI.h"
 #include "mozilla/media/MediaSystemResourceService.h" // for MediaSystemResourceService
 #include "mozilla/mozalloc.h"           // for operator new, etc
 #include "mozilla/Telemetry.h"
 #ifdef MOZ_WIDGET_GTK
 #include "basic/X11BasicCompositor.h" // for X11BasicCompositor
 #endif
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsDebug.h"                    // for NS_ASSERTION, etc
@@ -230,24 +236,30 @@ static StaticAutoPtr<CompositorMap> sCom
 
 void
 CompositorBridgeParent::Setup()
 {
   EnsureLayerTreeMapReady();
 
   MOZ_ASSERT(!sCompositorMap);
   sCompositorMap = new CompositorMap;
+
+  gfxPrefs::SetWebRenderProfilerEnabledChangeCallback(
+    [](const GfxPrefValue& aValue) -> void {
+      CompositorBridgeParent::SetWebRenderProfilerEnabled(aValue.get_bool());
+  });
 }
 
 void
 CompositorBridgeParent::Shutdown()
 {
   MOZ_ASSERT(sCompositorMap);
   MOZ_ASSERT(sCompositorMap->empty());
   sCompositorMap = nullptr;
+  gfxPrefs::SetWebRenderProfilerEnabledChangeCallback(nullptr);
 }
 
 void
 CompositorBridgeParent::FinishShutdown()
 {
   // TODO: this should be empty by now...
   sIndirectLayerTrees.clear();
 }
@@ -374,28 +386,30 @@ CompositorBridgeParent::Initialize()
 
   { // scope lock
     MonitorAutoLock lock(*sIndirectLayerTreesLock);
     sIndirectLayerTrees[mRootLayerTreeID].mParent = this;
   }
 
   LayerScope::SetPixelScale(mScale.scale);
 
-  mCompositorScheduler = new CompositorVsyncScheduler(this, mWidget);
+  if (!mOptions.UseWebRender()) {
+    mCompositorScheduler = new CompositorVsyncScheduler(this, mWidget);
+  }
 }
 
 mozilla::ipc::IPCResult
 CompositorBridgeParent::RecvReset(nsTArray<LayersBackend>&& aBackendHints,
                                   const uint64_t& aSeqNo,
                                   bool* aResult,
                                   TextureFactoryIdentifier* aOutIdentifier)
 {
   Maybe<TextureFactoryIdentifier> newIdentifier;
   ResetCompositorTask(aBackendHints, aSeqNo, &newIdentifier);
-  
+
   if (newIdentifier) {
     *aResult = true;
     *aOutIdentifier = newIdentifier.value();
   } else {
     *aResult = false;
   }
 
   return IPC_OK();
@@ -445,16 +459,29 @@ CompositorBridgeParent::StopAndClearReso
       lts->mLayerManager = nullptr;
       lts->mParent = nullptr;
     });
     mLayerManager->Destroy();
     mLayerManager = nullptr;
     mCompositionManager = nullptr;
   }
 
+  if (mWrBridge) {
+    MonitorAutoLock lock(*sIndirectLayerTreesLock);
+    ForEachIndirectLayerTree([this] (LayerTreeState* lts, uint64_t) -> void {
+      if (lts->mWrBridge) {
+        lts->mWrBridge->Destroy();
+        lts->mWrBridge = nullptr;
+      }
+      lts->mParent = nullptr;
+    });
+    mWrBridge->Destroy();
+    mWrBridge = nullptr;
+  }
+
   if (mCompositor) {
     mCompositor->DetachWidget();
     mCompositor->Destroy();
     mCompositor = nullptr;
   }
 
   // This must be destroyed now since it accesses the widget.
   if (mCompositorScheduler) {
@@ -975,24 +1002,28 @@ CompositorBridgeParent::CompositeToTarge
   mLayerManager->SetDebugOverlayWantsNextFrame(false);
   mLayerManager->EndTransaction(time);
 
   if (!aTarget) {
     TimeStamp end = TimeStamp::Now();
     DidComposite(start, end);
   }
 
-  // We're not really taking advantage of the stored composite-again-time here.
-  // We might be able to skip the next few composites altogether. However,
-  // that's a bit complex to implement and we'll get most of the advantage
-  // by skipping compositing when we detect there's nothing invalid. This is why
-  // we do "composite until" rather than "composite again at".
-  if (!mCompositor->GetCompositeUntilTime().IsNull() ||
-      mLayerManager->DebugOverlayWantsNextFrame()) {
-    ScheduleComposition();
+  if (mCompositor) {
+    // We're not really taking advantage of the stored composite-again-time here.
+    // We might be able to skip the next few composites altogether. However,
+    // that's a bit complex to implement and we'll get most of the advantage
+    // by skipping compositing when we detect there's nothing invalid. This is why
+    // we do "composite until" rather than "composite again at".
+    if (!mCompositor->GetCompositeUntilTime().IsNull() ||
+        mLayerManager->DebugOverlayWantsNextFrame()) {
+      ScheduleComposition();
+    }
+  } else {
+    // TODO(bug 1328602) Figure out what we should do here with the render thread.
   }
 
 #ifdef COMPOSITOR_PERFORMANCE_WARNING
   TimeDuration executionTime = TimeStamp::Now() - mCompositorScheduler->GetLastComposeTime();
   TimeDuration frameBudget = TimeDuration::FromMilliseconds(15);
   int32_t frameRate = CalculateCompositionFrameRate();
   if (frameRate > 0) {
     frameBudget = TimeDuration::FromSeconds(1.0 / frameRate);
@@ -1004,17 +1035,22 @@ CompositorBridgeParent::CompositeToTarge
 #endif
 
   // 0 -> Full-tilt composite
   if (gfxPrefs::LayersCompositionFrameRate() == 0
     || mLayerManager->GetCompositor()->GetDiagnosticTypes() & DiagnosticTypes::FLASH_BORDERS) {
     // Special full-tilt composite mode for performance testing
     ScheduleComposition();
   }
-  mCompositor->SetCompositionTime(TimeStamp());
+
+  if (mCompositor) {
+    mCompositor->SetCompositionTime(TimeStamp());
+  } else {
+    // TODO(bug 1328602) Need an equivalent that works with the rende thread.
+  }
 
   mozilla::Telemetry::AccumulateTimeDelta(mozilla::Telemetry::COMPOSITE_TIME, start);
 }
 
 mozilla::ipc::IPCResult
 CompositorBridgeParent::RecvRemotePluginsReady()
 {
 #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
@@ -1531,16 +1567,82 @@ CompositorBridgeParent::RecvAdoptChild(c
   }
 
   if (mApzcTreeManager && parent) {
     parent->ChildAdopted(mApzcTreeManager);
   }
   return IPC_OK();
 }
 
+PWebRenderBridgeParent*
+CompositorBridgeParent::AllocPWebRenderBridgeParent(const wr::PipelineId& aPipelineId,
+                                                    TextureFactoryIdentifier* aTextureFactoryIdentifier)
+{
+#ifndef MOZ_ENABLE_WEBRENDER
+  // Extra guard since this in the parent process and we don't want a malicious
+  // child process invoking this codepath before it's ready
+  MOZ_RELEASE_ASSERT(false);
+#endif
+  MOZ_ASSERT(aPipelineId.mHandle == mRootLayerTreeID);
+  MOZ_ASSERT(!mWrBridge);
+  MOZ_ASSERT(!mCompositor);
+  MOZ_ASSERT(!mCompositorScheduler);
+
+
+  MOZ_ASSERT(mWidget);
+  RefPtr<widget::CompositorWidget> widget = mWidget;
+  RefPtr<wr::WebRenderAPI> api = wr::WebRenderAPI::Create(gfxPrefs::WebRenderProfilerEnabled(), this, Move(widget));
+  RefPtr<WebRenderCompositableHolder> holder = new WebRenderCompositableHolder();
+  MOZ_ASSERT(api); // TODO have a fallback
+  api->SetRootPipeline(aPipelineId);
+  mWrBridge = new WebRenderBridgeParent(this, aPipelineId, mWidget, Move(api), Move(holder));
+
+  mCompositorScheduler = mWrBridge->CompositorScheduler();
+  MOZ_ASSERT(mCompositorScheduler);
+  mWrBridge.get()->AddRef(); // IPDL reference
+  MonitorAutoLock lock(*sIndirectLayerTreesLock);
+  auto pipelineHandle = aPipelineId.mHandle;
+  MOZ_ASSERT(sIndirectLayerTrees[pipelineHandle].mWrBridge == nullptr);
+  sIndirectLayerTrees[pipelineHandle].mWrBridge = mWrBridge;
+  *aTextureFactoryIdentifier = mWrBridge->GetTextureFactoryIdentifier();
+  return mWrBridge;
+}
+
+bool
+CompositorBridgeParent::DeallocPWebRenderBridgeParent(PWebRenderBridgeParent* aActor)
+{
+#ifndef MOZ_ENABLE_WEBRENDER
+  // Extra guard since this in the parent process and we don't want a malicious
+  // child process invoking this codepath before it's ready
+  MOZ_RELEASE_ASSERT(false);
+#endif
+  WebRenderBridgeParent* parent = static_cast<WebRenderBridgeParent*>(aActor);
+  {
+    MonitorAutoLock lock(*sIndirectLayerTreesLock);
+    auto it = sIndirectLayerTrees.find(parent->PipelineId().mHandle);
+    if (it != sIndirectLayerTrees.end()) {
+      it->second.mWrBridge = nullptr;
+    }
+  }
+  parent->Release(); // IPDL reference
+  return true;
+}
+
+void
+CompositorBridgeParent::SetWebRenderProfilerEnabled(bool aEnabled)
+{
+  MonitorAutoLock lock(*sIndirectLayerTreesLock);
+  for (auto it = sIndirectLayerTrees.begin(); it != sIndirectLayerTrees.end(); it++) {
+    LayerTreeState* state = &it->second;
+    if (state->mWrBridge) {
+      state->mWrBridge->SetWebRenderProfilerEnabled(aEnabled);
+    }
+  }
+}
+
 void
 EraseLayerState(uint64_t aId)
 {
   MonitorAutoLock lock(*sIndirectLayerTreesLock);
 
   auto iter = sIndirectLayerTrees.find(aId);
   if (iter != sIndirectLayerTrees.end()) {
     CompositorBridgeParent* parent = iter->second.mParent;
@@ -1711,27 +1813,41 @@ CompositorBridgeParent::LayerTreeState::
 {
   return mParent;
 }
 
 void
 CompositorBridgeParent::DidComposite(TimeStamp& aCompositeStart,
                                      TimeStamp& aCompositeEnd)
 {
-  Unused << SendDidComposite(0, mPendingTransaction, aCompositeStart, aCompositeEnd);
+  NotifyDidComposite(mPendingTransaction, aCompositeStart, aCompositeEnd);
   mPendingTransaction = 0;
+}
+
+void
+CompositorBridgeParent::NotifyDidComposite(uint64_t aTransactionId, TimeStamp& aCompositeStart, TimeStamp& aCompositeEnd)
+{
+  Unused << SendDidComposite(0, aTransactionId, aCompositeStart, aCompositeEnd);
 
   if (mLayerManager) {
     nsTArray<ImageCompositeNotificationInfo> notifications;
     mLayerManager->ExtractImageCompositeNotifications(&notifications);
     if (!notifications.IsEmpty()) {
       Unused << ImageBridgeParent::NotifyImageComposites(notifications);
     }
   }
 
+  if (mWrBridge) {
+    nsTArray<ImageCompositeNotificationInfo> notifications;
+    mWrBridge->ExtractImageCompositeNotifications(&notifications);
+    if (!notifications.IsEmpty()) {
+      Unused << ImageBridgeParent::NotifyImageComposites(notifications);
+    }
+  }
+
   MonitorAutoLock lock(*sIndirectLayerTreesLock);
   ForEachIndirectLayerTree([&] (LayerTreeState* lts, const uint64_t& aLayersId) -> void {
     if (lts->mCrossProcessParent) {
       CrossProcessCompositorBridgeParent* cpcp = lts->mCrossProcessParent;
       cpcp->DidComposite(aLayersId, aCompositeStart, aCompositeEnd);
     }
   });
 }
--- a/gfx/layers/ipc/CompositorBridgeParent.h
+++ b/gfx/layers/ipc/CompositorBridgeParent.h
@@ -66,16 +66,17 @@ class Compositor;
 class CompositorBridgeParent;
 class CompositorVsyncScheduler;
 class HostLayerManager;
 class LayerTransactionParent;
 class PAPZParent;
 class CrossProcessCompositorBridgeParent;
 class CompositorThreadHolder;
 class InProcessCompositorSession;
+class WebRenderBridgeParent;
 
 struct ScopedLayerTreeRegistration
 {
   ScopedLayerTreeRegistration(APZCTreeManager* aApzctm,
                               uint64_t aLayersId,
                               Layer* aRoot,
                               GeckoContentController* aController);
   ~ScopedLayerTreeRegistration();
@@ -110,16 +111,20 @@ public:
                                       const uint64_t& aInputBlockId,
                                       const nsTArray<ScrollableLayerGuid>& aTargets) = 0;
   virtual void UpdatePaintTime(LayerTransactionParent* aLayerTree, const TimeDuration& aPaintTime) {}
 
   virtual ShmemAllocator* AsShmemAllocator() override { return this; }
 
   virtual mozilla::ipc::IPCResult RecvSyncWithCompositor() override { return IPC_OK(); }
 
+  virtual void ObserveLayerUpdate(uint64_t aLayersId, uint64_t aEpoch, bool aActive) = 0;
+
+  virtual void NotifyDidComposite(uint64_t aTransactionId, TimeStamp& aCompositeStart, TimeStamp& aCompositeEnd) {}
+
   // HostIPCAllocator
   virtual base::ProcessId GetChildProcessId() override;
   virtual void NotifyNotUsed(PTextureParent* aTexture, uint64_t aTransactionId) override;
   virtual void SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage) override;
 
   // ShmemAllocator
   virtual bool AllocShmem(size_t aSize,
                           mozilla::ipc::SharedMemory::SharedMemoryType aType,
@@ -237,16 +242,18 @@ public:
   virtual bool DeallocPTextureParent(PTextureParent* actor) override;
 
   virtual bool IsSameProcess() const override;
 
 
   PCompositorWidgetParent* AllocPCompositorWidgetParent(const CompositorWidgetInitData& aInitData) override;
   bool DeallocPCompositorWidgetParent(PCompositorWidgetParent* aActor) override;
 
+  void ObserveLayerUpdate(uint64_t aLayersId, uint64_t aEpoch, bool aActive) override { }
+
   /**
    * Request that the compositor be recreated due to a shared device reset.
    * This must be called on the main thread, and blocks until a task posted
    * to the compositor thread has completed.
    *
    * Note that this posts a task directly, rather than using synchronous
    * IPDL, and waits on a monitor notification from the compositor thread.
    * We do this as a best-effort attempt to jump any IPDL messages that
@@ -341,16 +348,17 @@ public:
   struct LayerTreeState {
     LayerTreeState();
     ~LayerTreeState();
     RefPtr<Layer> mRoot;
     RefPtr<GeckoContentController> mController;
     APZCTreeManagerParent* mApzcTreeManagerParent;
     RefPtr<CompositorBridgeParent> mParent;
     HostLayerManager* mLayerManager;
+    RefPtr<WebRenderBridgeParent> mWrBridge;
     // Pointer to the CrossProcessCompositorBridgeParent. Used by APZCs to share
     // their FrameMetrics with the corresponding child process that holds
     // the PCompositorBridgeChild
     CrossProcessCompositorBridgeParent* mCrossProcessParent;
     TargetConfig mTargetConfig;
     APZTestData mApzTestData;
     LayerTransactionParent* mLayerTree;
     nsTArray<PluginWindowData> mPluginData;
@@ -437,16 +445,21 @@ public:
                                                    CompositorOptions* aOptions) override;
 
   RefPtr<APZCTreeManager> GetAPZCTreeManager();
 
   CompositorOptions GetOptions() const {
     return mOptions;
   }
 
+  PWebRenderBridgeParent* AllocPWebRenderBridgeParent(const wr::PipelineId& aPipelineId,
+                                                      TextureFactoryIdentifier* aTextureFactoryIdentifier) override;
+  bool DeallocPWebRenderBridgeParent(PWebRenderBridgeParent* aActor) override;
+  static void SetWebRenderProfilerEnabled(bool aEnabled);
+
   static CompositorBridgeParent* GetCompositorBridgeParentFromLayersId(const uint64_t& aLayersId);
 private:
 
   void Initialize();
 
   /**
    * Called during destruction in order to release resources as early as possible.
    */
@@ -531,24 +544,27 @@ protected:
   /**
    * Return true if current state allows compositing, that is
    * finishing a layers transaction.
    */
   bool CanComposite();
 
   void DidComposite(TimeStamp& aCompositeStart, TimeStamp& aCompositeEnd);
 
+  virtual void NotifyDidComposite(uint64_t aTransactionId, TimeStamp& aCompositeStart, TimeStamp& aCompositeEnd) override;
+
   // The indirect layer tree lock must be held before calling this function.
   // Callback should take (LayerTreeState* aState, const uint64_t& aLayersId)
   template <typename Lambda>
   inline void ForEachIndirectLayerTree(const Lambda& aCallback);
 
   RefPtr<HostLayerManager> mLayerManager;
   RefPtr<Compositor> mCompositor;
   RefPtr<AsyncCompositionManager> mCompositionManager;
+  RefPtr<WebRenderBridgeParent> mWrBridge;
   widget::CompositorWidget* mWidget;
   TimeStamp mTestTime;
   CSSToLayoutDeviceScale mScale;
   TimeDuration mVsyncRate;
   bool mIsTesting;
 
   uint64_t mPendingTransaction;
 
--- a/gfx/layers/ipc/CompositorVsyncScheduler.cpp
+++ b/gfx/layers/ipc/CompositorVsyncScheduler.cpp
@@ -79,17 +79,16 @@ CompositorVsyncScheduler::CompositorVsyn
   , mNeedsComposite(0)
   , mVsyncNotificationsSkipped(0)
   , mWidget(aWidget)
   , mCurrentCompositeTaskMonitor("CurrentCompositeTaskMonitor")
   , mCurrentCompositeTask(nullptr)
   , mSetNeedsCompositeMonitor("SetNeedsCompositeMonitor")
   , mSetNeedsCompositeTask(nullptr)
 {
-  MOZ_ASSERT(NS_IsMainThread() || XRE_GetProcessType() == GeckoProcessType_GPU);
   mVsyncObserver = new Observer(this);
 
   // mAsapScheduling is set on the main thread during init,
   // but is only accessed after on the compositor thread.
   mAsapScheduling = gfxPrefs::LayersCompositionFrameRate() == 0 ||
                     gfxPlatform::IsInLayoutAsapMode();
 }
 
--- a/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp
@@ -16,16 +16,18 @@
 #include "mozilla/layers/APZThreadUtils.h"  // for APZCTreeManager
 #include "mozilla/layers/AsyncCompositionManager.h"
 #include "mozilla/layers/CompositorOptions.h"
 #include "mozilla/layers/CompositorThread.h"
 #include "mozilla/layers/LayerManagerComposite.h"
 #include "mozilla/layers/LayerTreeOwnerTracker.h"
 #include "mozilla/layers/PLayerTransactionParent.h"
 #include "mozilla/layers/RemoteContentController.h"
+#include "mozilla/layers/WebRenderBridgeParent.h"
+#include "mozilla/layers/WebRenderCompositableHolder.h"
 #include "mozilla/mozalloc.h"           // for operator new, etc
 #include "nsDebug.h"                    // for NS_ASSERTION, etc
 #include "nsTArray.h"                   // for nsTArray
 #include "nsXULAppAPI.h"                // for XRE_GetIOMessageLoop
 #include "mozilla/Unused.h"
 #include "mozilla/StaticPtr.h"
 
 using namespace std;
@@ -189,16 +191,64 @@ CrossProcessCompositorBridgeParent::Allo
 bool
 CrossProcessCompositorBridgeParent::DeallocPAPZParent(PAPZParent* aActor)
 {
   RemoteContentController* controller = static_cast<RemoteContentController*>(aActor);
   controller->Release();
   return true;
 }
 
+PWebRenderBridgeParent*
+CrossProcessCompositorBridgeParent::AllocPWebRenderBridgeParent(const wr::PipelineId& aPipelineId,
+                                                                TextureFactoryIdentifier* aTextureFactoryIdentifier)
+{
+#ifndef MOZ_ENABLE_WEBRENDER
+  // Extra guard since this in the parent process and we don't want a malicious
+  // child process invoking this codepath before it's ready
+  MOZ_RELEASE_ASSERT(false);
+#endif
+  // Check to see if this child process has access to this layer tree.
+  if (!LayerTreeOwnerTracker::Get()->IsMapped(aPipelineId.mHandle, OtherPid())) {
+    NS_ERROR("Unexpected layers id in AllocPAPZCTreeManagerParent; dropping message...");
+    return nullptr;
+  }
+
+  auto pipelineHandle = aPipelineId.mHandle;
+  MonitorAutoLock lock(*sIndirectLayerTreesLock);
+  MOZ_ASSERT(sIndirectLayerTrees.find(pipelineHandle) != sIndirectLayerTrees.end());
+  MOZ_ASSERT(sIndirectLayerTrees[pipelineHandle].mWrBridge == nullptr);
+  CompositorBridgeParent* cbp = sIndirectLayerTrees[pipelineHandle].mParent;
+  WebRenderBridgeParent* root = sIndirectLayerTrees[cbp->RootLayerTreeId()].mWrBridge.get();
+
+  WebRenderBridgeParent* parent = nullptr;
+  RefPtr<wr::WebRenderAPI> api = root->GetWebRenderAPI();
+  RefPtr<WebRenderCompositableHolder> holder = root->CompositableHolder();
+  parent = new WebRenderBridgeParent(this, aPipelineId, nullptr, Move(api), Move(holder));
+
+  parent->AddRef(); // IPDL reference
+  sIndirectLayerTrees[pipelineHandle].mCrossProcessParent = this;
+  sIndirectLayerTrees[pipelineHandle].mWrBridge = parent;
+  *aTextureFactoryIdentifier = parent->GetTextureFactoryIdentifier();
+  return parent;
+}
+
+bool
+CrossProcessCompositorBridgeParent::DeallocPWebRenderBridgeParent(PWebRenderBridgeParent* aActor)
+{
+#ifndef MOZ_ENABLE_WEBRENDER
+  // Extra guard since this in the parent process and we don't want a malicious
+  // child process invoking this codepath before it's ready
+  MOZ_RELEASE_ASSERT(false);
+#endif
+  WebRenderBridgeParent* parent = static_cast<WebRenderBridgeParent*>(aActor);
+  EraseLayerState(parent->PipelineId().mHandle);
+  parent->Release(); // IPDL reference
+  return true;
+}
+
 mozilla::ipc::IPCResult
 CrossProcessCompositorBridgeParent::RecvNotifyChildCreated(const uint64_t& child)
 {
   MonitorAutoLock lock(*sIndirectLayerTreesLock);
   for (LayerTreeMap::iterator it = sIndirectLayerTrees.begin();
        it != sIndirectLayerTrees.end(); it++) {
     CompositorBridgeParent::LayerTreeState* lts = &it->second;
     if (lts->mParent && lts->mCrossProcessParent == this) {
@@ -267,16 +317,19 @@ CrossProcessCompositorBridgeParent::DidC
   uint64_t aId,
   TimeStamp& aCompositeStart,
   TimeStamp& aCompositeEnd)
 {
   sIndirectLayerTreesLock->AssertCurrentThreadOwns();
   if (LayerTransactionParent *layerTree = sIndirectLayerTrees[aId].mLayerTree) {
     Unused << SendDidComposite(aId, layerTree->GetPendingTransactionId(), aCompositeStart, aCompositeEnd);
     layerTree->SetPendingTransactionId(0);
+  } else if (WebRenderBridgeParent* wrbridge = sIndirectLayerTrees[aId].mWrBridge) {
+    Unused << SendDidComposite(aId, wrbridge->GetPendingTransactionId(), aCompositeStart, aCompositeEnd);
+    wrbridge->SetPendingTransactionId(0);
   }
 }
 
 void
 CrossProcessCompositorBridgeParent::ForceComposite(LayerTransactionParent* aLayerTree)
 {
   uint64_t id = aLayerTree->GetId();
   MOZ_ASSERT(id != 0);
@@ -524,10 +577,24 @@ CrossProcessCompositorBridgeParent::Upda
     CompositorBridgeParent::GetIndirectShadowTree(id);
   if (!state || !state->mParent) {
     return;
   }
 
   state->mParent->UpdatePaintTime(aLayerTree, aPaintTime);
 }
 
+void
+CrossProcessCompositorBridgeParent::ObserveLayerUpdate(uint64_t aLayersId, uint64_t aEpoch, bool aActive)
+{
+  MOZ_ASSERT(aLayersId != 0);
+
+  CompositorBridgeParent::LayerTreeState* state =
+    CompositorBridgeParent::GetIndirectShadowTree(aLayersId);
+  if (!state || !state->mParent) {
+    return;
+  }
+
+  Unused << state->mParent->SendObserveLayerUpdate(aLayersId, aEpoch, aActive);
+}
+
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/ipc/CrossProcessCompositorBridgeParent.h
+++ b/gfx/layers/ipc/CrossProcessCompositorBridgeParent.h
@@ -146,16 +146,22 @@ public:
   virtual PAPZCTreeManagerParent* AllocPAPZCTreeManagerParent(const uint64_t& aLayersId) override;
   virtual bool DeallocPAPZCTreeManagerParent(PAPZCTreeManagerParent* aActor) override;
 
   virtual PAPZParent* AllocPAPZParent(const uint64_t& aLayersId) override;
   virtual bool DeallocPAPZParent(PAPZParent* aActor) override;
 
   virtual void UpdatePaintTime(LayerTransactionParent* aLayerTree, const TimeDuration& aPaintTime) override;
 
+  PWebRenderBridgeParent* AllocPWebRenderBridgeParent(const wr::PipelineId& aPipelineId,
+                                                      TextureFactoryIdentifier* aTextureFactoryIdentifier) override;
+  bool DeallocPWebRenderBridgeParent(PWebRenderBridgeParent* aActor) override;
+
+  void ObserveLayerUpdate(uint64_t aLayersId, uint64_t aEpoch, bool aActive) override;
+
 protected:
   void OnChannelConnected(int32_t pid) override {
     mCompositorThreadHolder = CompositorThreadHolder::GetSingleton();
   }
 private:
   // Private destructor, to discourage deletion outside of Release():
   virtual ~CrossProcessCompositorBridgeParent();
 
--- a/gfx/layers/ipc/PCompositorBridge.ipdl
+++ b/gfx/layers/ipc/PCompositorBridge.ipdl
@@ -9,16 +9,17 @@ include LayersSurfaces;
 include LayersMessages;
 include PlatformWidgetTypes;
 include protocol PAPZ;
 include protocol PAPZCTreeManager;
 include protocol PBrowser;
 include protocol PCompositorWidget;
 include protocol PLayerTransaction;
 include protocol PTexture;
+include protocol PWebRenderBridge;
 include "mozilla/GfxMessageUtils.h";
 
 using struct mozilla::null_t from "ipc/IPCMessageUtils.h";
 using struct mozilla::layers::TextureFactoryIdentifier from "mozilla/layers/CompositorTypes.h";
 using struct mozilla::layers::FrameMetrics from "FrameMetrics.h";
 using mozilla::layers::FrameMetrics::ViewID from "FrameMetrics.h";
 using mozilla::layers::MaybeZoomConstraints from "FrameMetrics.h";
 using struct mozilla::layers::ScrollableLayerGuid from "FrameMetrics.h";
@@ -28,16 +29,17 @@ using mozilla::CrossProcessMutexHandle f
 using mozilla::ipc::SharedMemoryBasic::Handle from "mozilla/ipc/SharedMemoryBasic.h";
 using mozilla::CSSIntRegion from "Units.h";
 using mozilla::LayoutDeviceIntPoint from "Units.h";
 using mozilla::LayoutDeviceIntRegion from "Units.h";
 using class mozilla::TimeStamp from "mozilla/TimeStamp.h";
 using class mozilla::layers::FrameUniformityData from "mozilla/layers/FrameUniformityData.h";
 using mozilla::layers::TextureFlags from "mozilla/layers/CompositorTypes.h";
 using mozilla::layers::CompositorOptions from "mozilla/layers/CompositorOptions.h";
+using mozilla::wr::PipelineId from "mozilla/webrender/WebRenderTypes.h";
 
 namespace mozilla {
 namespace layers {
 
 
 /**
  * The PCompositorBridge protocol is a top-level protocol for the compositor.
  * There is an instance of the protocol for each compositor, plus one for each
@@ -66,16 +68,17 @@ namespace layers {
 sync protocol PCompositorBridge
 {
   manages PAPZ;
   manages PAPZCTreeManager;
   // A Compositor manages a single Layer Manager (PLayerTransaction)
   manages PLayerTransaction;
   manages PTexture;
   manages PCompositorWidget;
+  manages PWebRenderBridge;
 
 child:
   // The child should invalidate retained layers. This is used for local
   // compositor device resets, such as in CompositorD3D9, and ensures that
   // TextureSources are recreated.
   async InvalidateLayers(uint64_t layersId);
 
   // The compositor type or device has changed, and a new texture factory
@@ -233,16 +236,20 @@ parent:
    * Sent when the child has finished CaptureAllPlugins.
    */
   async AllPluginsCaptured();
 
   async PTexture(SurfaceDescriptor aSharedData, LayersBackend aBackend, TextureFlags aTextureFlags, uint64_t id, uint64_t aSerial);
 
   sync SyncWithCompositor();
 
+  // The pipelineId is the same as the layersId
+  sync PWebRenderBridge(PipelineId pipelineId)
+    returns (TextureFactoryIdentifier textureFactoryIdentifier);
+
 child:
   // Send back Compositor Frame Metrics from APZCs so tiled layers can
   // update progressively.
   async SharedCompositorFrameMetrics(Handle metrics, CrossProcessMutexHandle mutex, uint64_t aLayersId, uint32_t aAPZCId);
   async ReleaseSharedCompositorFrameMetrics(ViewID aId, uint32_t aAPZCId);
 };
 
 } // layers
new file mode 100644
--- /dev/null
+++ b/gfx/layers/ipc/PWebRenderBridge.ipdl
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: sw=2 ts=8 et :
+ */
+/* 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 LayersSurfaces;
+include LayersMessages;
+include "mozilla/GfxMessageUtils.h";
+include "mozilla/layers/WebRenderMessageUtils.h";
+
+include WebRenderMessages;
+include protocol PCompositorBridge;
+include protocol PTexture;
+
+using struct mozilla::layers::TextureInfo from "mozilla/layers/CompositorTypes.h";
+using mozilla::layers::CompositableHandle from "mozilla/layers/LayersTypes.h";
+using mozilla::wr::ByteBuffer from "mozilla/webrender/WebRenderTypes.h";
+using mozilla::wr::ImageKey from "mozilla/webrender/WebRenderTypes.h";
+
+namespace mozilla {
+namespace layers {
+
+sync protocol PWebRenderBridge
+{
+  manager PCompositorBridge;
+
+parent:
+  async NewCompositable(CompositableHandle handle, TextureInfo info);
+  async ReleaseCompositable(CompositableHandle compositable);
+
+  sync Create(IntSize aSize);
+  sync AddImage(IntSize aSize, uint32_t aStride,
+                SurfaceFormat aFormat, ByteBuffer aBytes)
+    returns (ImageKey aOutImageKey);
+  sync UpdateImage(ImageKey aImageKey, IntSize aSize,
+                   SurfaceFormat aFormat, ByteBuffer aBytes);
+  sync DeleteImage(ImageKey aImageKey);
+  sync DPBegin(IntSize aSize)
+    returns (bool aOutSuccess);
+  async DPEnd(WebRenderCommand[] commands, OpDestroy[] toDestroy, uint64_t fwdTransactionId, uint64_t transactionId);
+  sync DPSyncEnd(WebRenderCommand[] commands, OpDestroy[] toDestroy, uint64_t fwdTransactionId, uint64_t transactionId);
+  sync DPGetSnapshot(PTexture texture);
+  async AddExternalImageId(uint64_t aImageId, CompositableHandle aHandle);
+  async AddExternalImageIdForCompositable(uint64_t aImageId, CompositableHandle aHandle);
+  async RemoveExternalImageId(uint64_t aImageId);
+  async SetLayerObserverEpoch(uint64_t layerObserverEpoch);
+  async ClearCachedResources();
+
+  async Shutdown();
+child:
+  async __delete__();
+};
+
+} // layers
+} // mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/layers/ipc/WebRenderMessages.ipdlh
@@ -0,0 +1,105 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: sw=2 ts=8 et :
+ */
+/* 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 LayersSurfaces;
+include LayersMessages;
+include protocol PTexture;
+
+using WrBorderRadius from "mozilla/webrender/webrender_ffi.h";
+using WrBorderSide from "mozilla/webrender/webrender_ffi.h";
+using WrColor from "mozilla/webrender/webrender_ffi.h";
+using WrImageKey from "mozilla/webrender/webrender_ffi.h";
+using WrTextureFilter from "mozilla/webrender/webrender_ffi.h";
+using WrLayoutSize from "mozilla/webrender/webrender_ffi.h";
+using WrRect from "mozilla/webrender/webrender_ffi.h";
+using WrGlyphArray from "mozilla/webrender/webrender_ffi.h";
+using WrMixBlendMode from "mozilla/webrender/webrender_ffi.h";
+using MaybeImageMask from "mozilla/webrender/WebRenderTypes.h";
+using mozilla::gfx::Matrix4x4 from "mozilla/gfx/Matrix.h";
+using mozilla::wr::ByteBuffer from "mozilla/webrender/WebRenderTypes.h";
+using mozilla::wr::PipelineId from "mozilla/webrender/WebRenderTypes.h";
+using mozilla::LayerIntRegion from "Units.h";
+
+namespace mozilla {
+namespace layers {
+
+struct OpDPPushStackingContext {
+  WrRect bounds;
+  WrRect overflow;
+  MaybeImageMask mask;
+  float opacity;
+  Animation[] animations;
+  Matrix4x4 matrix;
+  WrMixBlendMode mixBlendMode;
+  uint64_t scrollid;
+};
+
+struct OpDPPopStackingContext { };
+
+struct OpDPPushRect {
+  WrRect bounds;
+  WrRect clip;
+  WrColor color;
+};
+
+struct OpDPPushBorder {
+  WrRect bounds;
+  WrRect clip;
+  WrBorderSide top;
+  WrBorderSide right;
+  WrBorderSide bottom;
+  WrBorderSide left;
+  WrBorderRadius radius;
+};
+
+struct OpDPPushImage {
+  WrRect bounds;
+  WrRect clip;
+  MaybeImageMask mask;
+  WrTextureFilter filter;
+  WrImageKey key;
+};
+
+struct OpDPPushExternalImageId {
+  LayerIntRegion validBufferRegion;
+  WrRect bounds;
+  WrRect clip;
+  MaybeImageMask mask;
+  WrTextureFilter filter;
+  uint64_t externalImageId;
+};
+
+struct OpDPPushIframe {
+  WrRect bounds;
+  WrRect clip;
+  PipelineId pipelineId;
+};
+
+struct OpDPPushText {
+  WrRect bounds;
+  WrRect clip;
+  WrGlyphArray[] glyph_array;
+  uint32_t font_index;
+  float glyph_size;
+  ByteBuffer font_buffer;
+  uint32_t font_buffer_length;
+};
+
+union WebRenderCommand {
+  OpDPPushStackingContext;
+  OpDPPopStackingContext;
+  OpDPPushRect;
+  OpDPPushBorder;
+  OpDPPushImage;
+  OpDPPushExternalImageId;
+  OpDPPushIframe;
+  OpDPPushText;
+  CompositableOperation;
+};
+
+} // namespace
+} // namespace
--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -145,16 +145,17 @@ EXPORTS.mozilla.layers += [
     'client/TiledContentClient.h',
     'composite/AsyncCompositionManager.h',
     'composite/CanvasLayerComposite.h',
     'composite/ColorLayerComposite.h',
     'composite/ContainerLayerComposite.h',
     'composite/ContentHost.h',
     'composite/FrameUniformityData.h',
     'composite/GPUVideoTextureHost.h',
+    'composite/ImageComposite.h',
     'composite/ImageHost.h',
     'composite/ImageLayerComposite.h',
     'composite/LayerManagerComposite.h',
     'composite/PaintedLayerComposite.h',
     'composite/TextureHost.h',
     'composite/TiledContentHost.h',
     'Compositor.h',
     'CompositorTypes.h',
@@ -201,16 +202,24 @@ EXPORTS.mozilla.layers += [
     'opengl/TextureClientOGL.h',
     'opengl/TextureHostOGL.h',
     'PersistentBufferProvider.h',
     'RenderTrace.h',
     'SourceSurfaceSharedData.h',
     'SourceSurfaceVolatileData.h',
     'TextureWrapperImage.h',
     'TransactionIdAllocator.h',
+    'wr/WebRenderBridgeChild.h',
+    'wr/WebRenderBridgeParent.h',
+    'wr/WebRenderCompositableHolder.h',
+    'wr/WebRenderCompositorOGL.h',
+    'wr/WebRenderImageHost.h',
+    'wr/WebRenderLayerManager.h',
+    'wr/WebRenderLayersLogging.h',
+    'wr/WebRenderMessageUtils.h',
 ]
 
 if CONFIG['MOZ_X11']:
     EXPORTS.mozilla.layers += [
         'basic/TextureClientX11.h',
         'basic/X11TextureSourceBasic.h',
         'composite/X11TextureHost.h',
         'ipc/ShadowLayerUtilsX11.h',
@@ -317,16 +326,17 @@ UNIFIED_SOURCES += [
     'composite/CanvasLayerComposite.cpp',
     'composite/ColorLayerComposite.cpp',
     'composite/CompositableHost.cpp',
     'composite/ContainerLayerComposite.cpp',
     'composite/ContentHost.cpp',
     'composite/FPSCounter.cpp',
     'composite/FrameUniformityData.cpp',
     'composite/GPUVideoTextureHost.cpp',
+    'composite/ImageComposite.cpp',
     'composite/ImageHost.cpp',
     'composite/ImageLayerComposite.cpp',
     'composite/LayerManagerComposite.cpp',
     'composite/PaintedLayerComposite.cpp',
     'composite/TextRenderer.cpp',
     'composite/TextureHost.cpp',
     'composite/TiledContentHost.cpp',
     'Compositor.cpp',
@@ -375,16 +385,30 @@ UNIFIED_SOURCES += [
     'protobuf/LayerScopePacket.pb.cc',
     'ReadbackProcessor.cpp',
     'RenderTrace.cpp',
     'RotatedBuffer.cpp',
     'ShareableCanvasLayer.cpp',
     'SourceSurfaceSharedData.cpp',
     'SourceSurfaceVolatileData.cpp',
     'TextureWrapperImage.cpp',
+    'wr/WebRenderBorderLayer.cpp',
+    'wr/WebRenderBridgeChild.cpp',
+    'wr/WebRenderBridgeParent.cpp',
+    'wr/WebRenderCanvasLayer.cpp',
+    'wr/WebRenderColorLayer.cpp',
+    'wr/WebRenderCompositableHolder.cpp',
+    'wr/WebRenderCompositorOGL.cpp',
+    'wr/WebRenderContainerLayer.cpp',
+    'wr/WebRenderImageHost.cpp',
+    'wr/WebRenderImageLayer.cpp',
+    'wr/WebRenderLayerManager.cpp',
+    'wr/WebRenderLayersLogging.cpp',
+    'wr/WebRenderPaintedLayer.cpp',
+    'wr/WebRenderTextLayer.cpp',
 ]
 
 SOURCES += [
     'basic/BasicImageLayer.cpp',
     'ImageContainer.cpp',
     'Layers.cpp',
     'LayerTreeInvalidation.cpp',
     'PersistentBufferProvider.cpp',
@@ -414,16 +438,18 @@ IPDL_SOURCES += [
     'ipc/PAPZ.ipdl',
     'ipc/PAPZCTreeManager.ipdl',
     'ipc/PCompositorBridge.ipdl',
     'ipc/PImageBridge.ipdl',
     'ipc/PLayerTransaction.ipdl',
     'ipc/PTexture.ipdl',
     'ipc/PUiCompositorController.ipdl',
     'ipc/PVideoBridge.ipdl',
+    'ipc/PWebRenderBridge.ipdl',
+    'ipc/WebRenderMessages.ipdlh',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 LOCAL_INCLUDES += [
     '/docshell/base',  # for nsDocShell.h
     '/layout/base',    # for TouchManager.h
     '/layout/generic', # for nsTextFrame.h
new file mode 100644
--- /dev/null
+++ b/gfx/layers/wr/WebRenderBorderLayer.cpp
@@ -0,0 +1,66 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "WebRenderBorderLayer.h"
+
+#include "WebRenderLayersLogging.h"
+#include "mozilla/gfx/Rect.h"
+#include "mozilla/webrender/webrender_ffi.h"
+#include "mozilla/layers/WebRenderBridgeChild.h"
+#include "mozilla/webrender/WebRenderTypes.h"
+
+namespace mozilla {
+namespace layers {
+
+using namespace mozilla::gfx;
+
+void
+WebRenderBorderLayer::RenderLayer()
+{
+  WrScrollFrameStackingContextGenerator scrollFrames(this);
+
+  Rect rect = RelativeToVisible(mRect.ToUnknownRect());
+  Rect clip;
+  if (GetClipRect().isSome()) {
+    clip = RelativeToTransformedVisible(IntRectToRect(GetClipRect().ref().ToUnknownRect()));
+  } else {
+    clip = rect;
+  }
+
+  Rect relBounds = TransformedVisibleBoundsRelativeToParent();
+  Rect overflow(0, 0, relBounds.width, relBounds.height);
+  Matrix4x4 transform;// = GetTransform();
+
+  if (gfxPrefs::LayersDump()) {
+    printf_stderr("BorderLayer %p using bounds=%s, overflow=%s, transform=%s, rect=%s, clip=%s\n",
+                  this->GetLayer(),
+                  Stringify(relBounds).c_str(),
+                  Stringify(overflow).c_str(),
+                  Stringify(transform).c_str(),
+                  Stringify(rect).c_str(),
+                  Stringify(clip).c_str());
+  }
+
+  WrBridge()->AddWebRenderCommand(
+      OpDPPushStackingContext(wr::ToWrRect(relBounds),
+                              wr::ToWrRect(overflow),
+                              Nothing(),
+                              1.0f,
+                              GetAnimations(),
+                              transform,
+                              WrMixBlendMode::Normal,
+                              FrameMetrics::NULL_SCROLL_ID));
+  WrBridge()->AddWebRenderCommand(
+    OpDPPushBorder(wr::ToWrRect(rect), wr::ToWrRect(clip),
+                   wr::ToWrBorderSide(mWidths[0], mColors[0], mBorderStyles[0]),
+                   wr::ToWrBorderSide(mWidths[1], mColors[1], mBorderStyles[1]),
+                   wr::ToWrBorderSide(mWidths[2], mColors[2], mBorderStyles[2]),
+                   wr::ToWrBorderSide(mWidths[3], mColors[3], mBorderStyles[3]),
+                   wr::ToWrBorderRadius(mCorners[0], mCorners[1], mCorners[3], mCorners[2])));
+  WrBridge()->AddWebRenderCommand(OpDPPopStackingContext());
+}
+
+} // namespace layers
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/layers/wr/WebRenderBorderLayer.h
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef GFX_WEBRENDERBORDERLAYER_H
+#define GFX_WEBRENDERBORDERLAYER_H
+
+#include "Layers.h"
+#include "WebRenderLayerManager.h"
+
+namespace mozilla {
+namespace layers {
+
+class WebRenderBorderLayer : public WebRenderLayer,
+                             public BorderLayer {
+public:
+  explicit WebRenderBorderLayer(WebRenderLayerManager* aLayerManager)
+    : BorderLayer(aLayerManager, static_cast<WebRenderLayer*>(this))
+  {
+    MOZ_COUNT_CTOR(WebRenderBorderLayer);
+  }
+
+protected:
+  virtual ~WebRenderBorderLayer()
+  {
+    MOZ_COUNT_DTOR(WebRenderBorderLayer);
+  }
+
+public:
+  Layer* GetLayer() override { return this; }
+  void RenderLayer() override;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // GFX_WEBRENDERBORDERLAYER_H
new file mode 100644
--- /dev/null
+++ b/gfx/layers/wr/WebRenderBridgeChild.cpp
@@ -0,0 +1,299 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=4 ts=8 et 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 "mozilla/layers/WebRenderBridgeChild.h"
+
+#include "gfxPlatform.h"
+#include "mozilla/layers/CompositableClient.h"
+#include "mozilla/layers/CompositorBridgeChild.h"
+#include "mozilla/layers/ImageDataSerializer.h"
+#include "mozilla/layers/PTextureChild.h"
+
+namespace mozilla {
+namespace layers {
+
+WebRenderBridgeChild::WebRenderBridgeChild(const wr::PipelineId& aPipelineId)
+  : mIsInTransaction(false)
+  , mSyncTransaction(false)
+  , mIPCOpen(false)
+  , mDestroyed(false)
+{
+}
+
+void
+WebRenderBridgeChild::Destroy()
+{
+  if (!IPCOpen()) {
+    return;
+  }
+  // mDestroyed is used to prevent calling Send__delete__() twice.
+  // When this function is called from CompositorBridgeChild::Destroy().
+  mDestroyed = true;
+
+  SendShutdown();
+}
+
+void
+WebRenderBridgeChild::ActorDestroy(ActorDestroyReason why)
+{
+  mDestroyed = true;
+}
+
+void
+WebRenderBridgeChild::AddWebRenderCommand(const WebRenderCommand& aCmd)
+{
+  MOZ_ASSERT(mIsInTransaction);
+  mCommands.AppendElement(aCmd);
+}
+
+bool
+WebRenderBridgeChild::DPBegin(const gfx::IntSize& aSize)
+{
+  MOZ_ASSERT(!mDestroyed);
+  MOZ_ASSERT(!mIsInTransaction);
+  bool success = false;
+  UpdateFwdTransactionId();
+  this->SendDPBegin(aSize, &success);
+  if (!success) {
+    return false;
+  }
+
+  mIsInTransaction = true;
+  return true;
+}
+
+void
+WebRenderBridgeChild::DPEnd(bool aIsSync, uint64_t aTransactionId)
+{
+  MOZ_ASSERT(!mDestroyed);
+  MOZ_ASSERT(mIsInTransaction);
+  if (aIsSync) {
+    this->SendDPSyncEnd(mCommands, mDestroyedActors, GetFwdTransactionId(), aTransactionId);
+  } else {
+    this->SendDPEnd(mCommands, mDestroyedActors, GetFwdTransactionId(), aTransactionId);
+  }
+
+  mCommands.Clear();
+  mDestroyedActors.Clear();
+  mIsInTransaction = false;
+  mSyncTransaction = false;
+}
+
+uint64_t
+WebRenderBridgeChild::GetNextExternalImageId()
+{
+  static uint32_t sNextID = 1;
+  ++sNextID;
+  MOZ_RELEASE_ASSERT(sNextID != UINT32_MAX);
+
+  // XXX replace external image id allocation with webrender's id allocation.
+  // Use proc id as IdNamespace for now.
+  uint32_t procId = static_cast<uint32_t>(base::GetCurrentProcId());
+  uint64_t imageId = procId;
+  imageId = imageId << 32 | sNextID;
+  return imageId;
+}
+
+uint64_t
+WebRenderBridgeChild::AllocExternalImageId(const CompositableHandle& aHandle)
+{
+  MOZ_ASSERT(!mDestroyed);
+
+  uint64_t imageId = GetNextExternalImageId();
+  SendAddExternalImageId(imageId, aHandle);
+  return imageId;
+}
+
+uint64_t
+WebRenderBridgeChild::AllocExternalImageIdForCompositable(CompositableClient* aCompositable)
+{
+  MOZ_ASSERT(!mDestroyed);
+  MOZ_ASSERT(aCompositable->IsConnected());
+
+  uint64_t imageId = GetNextExternalImageId();
+  SendAddExternalImageIdForCompositable(imageId, aCompositable->GetIPCHandle());
+  return imageId;
+}
+
+void
+WebRenderBridgeChild::DeallocExternalImageId(uint64_t aImageId)
+{
+  MOZ_ASSERT(!mDestroyed);
+  MOZ_ASSERT(aImageId);
+  SendRemoveExternalImageId(aImageId);
+}
+
+CompositorBridgeChild*
+WebRenderBridgeChild::GetCompositorBridgeChild()
+{
+  return static_cast<CompositorBridgeChild*>(Manager());
+}
+
+TextureForwarder*
+WebRenderBridgeChild::GetTextureForwarder()
+{
+  return static_cast<TextureForwarder*>(GetCompositorBridgeChild());
+}
+
+LayersIPCActor*
+WebRenderBridgeChild::GetLayersIPCActor()
+{
+  return static_cast<LayersIPCActor*>(GetCompositorBridgeChild());
+}
+
+void
+WebRenderBridgeChild::Connect(CompositableClient* aCompositable,
+                              ImageContainer* aImageContainer)
+{
+  MOZ_ASSERT(aCompositable);
+
+  static uint64_t sNextID = 1;
+  uint64_t id = sNextID++;
+
+  mCompositables.Put(id, aCompositable);
+
+  CompositableHandle handle(id);
+  aCompositable->InitIPDL(handle);
+  SendNewCompositable(handle, aCompositable->GetTextureInfo());
+}
+
+void
+WebRenderBridgeChild::UseTiledLayerBuffer(CompositableClient* aCompositable,
+                                          const SurfaceDescriptorTiles& aTiledDescriptor)
+{
+
+}
+
+void
+WebRenderBridgeChild::UpdateTextureRegion(CompositableClient* aCompositable,
+                                          const ThebesBufferData& aThebesBufferData,
+                                          const nsIntRegion& aUpdatedRegion)
+{
+
+}
+
+bool
+WebRenderBridgeChild::AddOpDestroy(const OpDestroy& aOp, bool aSynchronously)
+{
+  if (!mIsInTransaction) {
+    return false;
+  }
+
+  mDestroyedActors.AppendElement(aOp);
+  if (aSynchronously) {
+    MarkSyncTransaction();
+  }
+  return true;
+}
+
+void
+WebRenderBridgeChild::ReleaseCompositable(const CompositableHandle& aHandle)
+{
+  if (!DestroyInTransaction(aHandle)) {
+    SendReleaseCompositable(aHandle);
+  }
+  mCompositables.Remove(aHandle.Value());
+}
+
+bool
+WebRenderBridgeChild::DestroyInTransaction(PTextureChild* aTexture, bool aSynchronously)
+{
+  return AddOpDestroy(OpDestroy(aTexture), aSynchronously);
+}
+
+bool
+WebRenderBridgeChild::DestroyInTransaction(const CompositableHandle& aHandle)
+{
+  return AddOpDestroy(OpDestroy(aHandle), false);
+}
+
+void
+WebRenderBridgeChild::RemoveTextureFromCompositable(CompositableClient* aCompositable,
+                                                    TextureClient* aTexture)
+{
+  MOZ_ASSERT(aCompositable);
+  MOZ_ASSERT(aTexture);
+  MOZ_ASSERT(aTexture->GetIPDLActor());
+  MOZ_RELEASE_ASSERT(aTexture->GetIPDLActor()->GetIPCChannel() == GetIPCChannel());
+  if (!aCompositable->IsConnected() || !aTexture->GetIPDLActor()) {
+    // We don't have an actor anymore, don't try to use it!
+    return;
+  }
+
+  AddWebRenderCommand(
+    CompositableOperation(
+      aCompositable->GetIPCHandle(),
+      OpRemoveTexture(nullptr, aTexture->GetIPDLActor())));
+  if (aTexture->GetFlags() & TextureFlags::DEALLOCATE_CLIENT) {
+    MarkSyncTransaction();
+  }
+}
+
+void
+WebRenderBridgeChild::UseTextures(CompositableClient* aCompositable,
+                                  const nsTArray<TimedTextureClient>& aTextures)
+{
+  MOZ_ASSERT(aCompositable);
+
+  if (!aCompositable->IsConnected()) {
+    return;
+  }
+
+  AutoTArray<TimedTexture,4> textures;
+
+  for (auto& t : aTextures) {
+    MOZ_ASSERT(t.mTextureClient);
+    MOZ_ASSERT(t.mTextureClient->GetIPDLActor());
+    MOZ_RELEASE_ASSERT(t.mTextureClient->GetIPDLActor()->GetIPCChannel() == GetIPCChannel());
+    ReadLockDescriptor readLock;
+    t.mTextureClient->SerializeReadLock(readLock);
+    textures.AppendElement(TimedTexture(nullptr, t.mTextureClient->GetIPDLActor(),
+                                        readLock,
+                                        t.mTimeStamp, t.mPictureRect,
+                                        t.mFrameID, t.mProducerID));
+    if ((t.mTextureClient->GetFlags() & TextureFlags::IMMEDIATE_UPLOAD)
+        && t.mTextureClient->HasIntermediateBuffer()) {
+
+      // We use IMMEDIATE_UPLOAD when we want to be sure that the upload cannot
+      // race with updates on the main thread. In this case we want the transaction
+      // to be synchronous.
+
+      MarkSyncTransaction();
+    }
+    GetCompositorBridgeChild()->HoldUntilCompositableRefReleasedIfNecessary(t.mTextureClient);
+  }
+  AddWebRenderCommand(CompositableOperation(aCompositable->GetIPCHandle(),
+                                            OpUseTexture(textures)));
+}
+
+void
+WebRenderBridgeChild::UseComponentAlphaTextures(CompositableClient* aCompositable,
+                                                TextureClient* aClientOnBlack,
+                                                TextureClient* aClientOnWhite)
+{
+
+}
+
+void
+WebRenderBridgeChild::UpdateFwdTransactionId()
+{
+  GetCompositorBridgeChild()->UpdateFwdTransactionId();
+}
+
+uint64_t
+WebRenderBridgeChild::GetFwdTransactionId()
+{
+  return GetCompositorBridgeChild()->GetFwdTransactionId();
+}
+
+bool
+WebRenderBridgeChild::InForwarderThread()
+{
+  return NS_IsMainThread();
+}
+
+} // namespace layers
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/layers/wr/WebRenderBridgeChild.h
@@ -0,0 +1,118 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=4 ts=8 et tw=80 : */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_layers_WebRenderBridgeChild_h
+#define mozilla_layers_WebRenderBridgeChild_h
+
+#include "mozilla/layers/CompositableForwarder.h"
+#include "mozilla/layers/PWebRenderBridgeChild.h"
+
+namespace mozilla {
+
+namespace widget {
+class CompositorWidget;
+}
+
+namespace layers {
+
+class CompositableClient;
+class CompositorBridgeChild;
+class TextureForwarder;
+
+class WebRenderBridgeChild final : public PWebRenderBridgeChild
+                                 , public CompositableForwarder
+{
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WebRenderBridgeChild, override)
+
+public:
+  explicit WebRenderBridgeChild(const wr::PipelineId& aPipelineId);
+
+  void AddWebRenderCommand(const WebRenderCommand& aCmd);
+
+  bool DPBegin(const  gfx::IntSize& aSize);
+  void DPEnd(bool aIsSync, uint64_t aTransactionId);
+
+  CompositorBridgeChild* GetCompositorBridgeChild();
+
+  // KnowsCompositor
+  TextureForwarder* GetTextureForwarder() override;
+  LayersIPCActor* GetLayersIPCActor() override;
+
+  uint64_t AllocExternalImageId(const CompositableHandle& aHandle);
+  uint64_t AllocExternalImageIdForCompositable(CompositableClient* aCompositable);
+  void DeallocExternalImageId(uint64_t aImageId);
+
+  /**
+   * Clean this up, finishing with SendShutDown() which will cause __delete__
+   * to be sent from the parent side.
+   */
+  void Destroy();
+  bool IPCOpen() const { return mIPCOpen && !mDestroyed; }
+  bool IsDestroyed() const { return mDestroyed; }
+
+  void MarkSyncTransaction()
+  {
+    mSyncTransaction = true;
+  }
+
+private:
+  friend class CompositorBridgeChild;
+
+  ~WebRenderBridgeChild() {}
+
+  uint64_t GetNextExternalImageId();
+
+  // CompositableForwarder
+  void Connect(CompositableClient* aCompositable,
+               ImageContainer* aImageContainer = nullptr) override;
+  void UseTiledLayerBuffer(CompositableClient* aCompositable,
+                           const SurfaceDescriptorTiles& aTiledDescriptor) override;
+  void UpdateTextureRegion(CompositableClient* aCompositable,
+                           const ThebesBufferData& aThebesBufferData,
+                           const nsIntRegion& aUpdatedRegion) override;
+  void ReleaseCompositable(const CompositableHandle& aHandle) override;
+  bool DestroyInTransaction(PTextureChild* aTexture, bool aSynchronously) override;
+  bool DestroyInTransaction(const CompositableHandle& aHandle);
+  void RemoveTextureFromCompositable(CompositableClient* aCompositable,
+                                     TextureClient* aTexture) override;
+  void UseTextures(CompositableClient* aCompositable,
+                   const nsTArray<TimedTextureClient>& aTextures) override;
+  void UseComponentAlphaTextures(CompositableClient* aCompositable,
+                                 TextureClient* aClientOnBlack,
+                                 TextureClient* aClientOnWhite) override;
+  void UpdateFwdTransactionId() override;
+  uint64_t GetFwdTransactionId() override;
+  bool InForwarderThread() override;
+
+  void ActorDestroy(ActorDestroyReason why) override;
+
+  void AddIPDLReference() {
+    MOZ_ASSERT(mIPCOpen == false);
+    mIPCOpen = true;
+    AddRef();
+  }
+  void ReleaseIPDLReference() {
+    MOZ_ASSERT(mIPCOpen == true);
+    mIPCOpen = false;
+    Release();
+  }
+
+  bool AddOpDestroy(const OpDestroy& aOp, bool aSynchronously);
+
+  nsTArray<WebRenderCommand> mCommands;
+  nsTArray<OpDestroy> mDestroyedActors;
+  nsDataHashtable<nsUint64HashKey, CompositableClient*> mCompositables;
+  bool mIsInTransaction;
+  bool mSyncTransaction;
+
+  bool mIPCOpen;
+  bool mDestroyed;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // mozilla_layers_WebRenderBridgeChild_h
new file mode 100644
--- /dev/null
+++ b/gfx/layers/wr/WebRenderBridgeParent.cpp
@@ -0,0 +1,665 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=4 ts=8 et 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 "mozilla/layers/WebRenderBridgeParent.h"
+
+#include "CompositableHost.h"
+#include "GLContext.h"
+#include "GLContextProvider.h"
+#include "mozilla/Range.h"
+#include "mozilla/layers/Compositor.h"
+#include "mozilla/layers/CompositorBridgeParent.h"
+#include "mozilla/layers/CompositorThread.h"
+#include "mozilla/layers/CompositorVsyncScheduler.h"
+#include "mozilla/layers/ImageBridgeParent.h"
+#include "mozilla/layers/ImageDataSerializer.h"
+#include "mozilla/layers/TextureHost.h"
+#include "mozilla/layers/WebRenderCompositableHolder.h"
+#include "mozilla/layers/WebRenderCompositorOGL.h"
+#include "mozilla/webrender/RenderThread.h"
+#include "mozilla/widget/CompositorWidget.h"
+
+bool is_in_compositor_thread()
+{
+  return mozilla::layers::CompositorThreadHolder::IsInCompositorThread();
+}
+
+bool is_in_render_thread()
+{
+  return mozilla::wr::RenderThread::IsInRenderThread();
+}
+
+void* get_proc_address_from_glcontext(void* glcontext_ptr, const char* procname)
+{
+  MOZ_ASSERT(glcontext_ptr);
+
+  mozilla::gl::GLContext* glcontext = reinterpret_cast<mozilla::gl::GLContext*>(glcontext_ptr);
+  if (!glcontext) {
+    return nullptr;
+  }
+  PRFuncPtr p = glcontext->LookupSymbol(procname);
+  return reinterpret_cast<void*>(p);
+}
+
+namespace mozilla {
+namespace layers {
+
+using namespace mozilla::gfx;
+
+class MOZ_STACK_CLASS AutoWebRenderBridgeParentAsyncMessageSender
+{
+public:
+  explicit AutoWebRenderBridgeParentAsyncMessageSender(WebRenderBridgeParent* aWebRenderBridgeParent,
+                                                       InfallibleTArray<OpDestroy>* aDestroyActors = nullptr)
+    : mWebRenderBridgeParent(aWebRenderBridgeParent)
+    , mActorsToDestroy(aDestroyActors)
+  {
+    mWebRenderBridgeParent->SetAboutToSendAsyncMessages();
+  }
+
+  ~AutoWebRenderBridgeParentAsyncMessageSender()
+  {
+    mWebRenderBridgeParent->SendPendingAsyncMessages();
+    if (mActorsToDestroy) {
+      // Destroy the actors after sending the async messages because the latter may contain
+      // references to some actors.
+      for (const auto& op : *mActorsToDestroy) {
+        mWebRenderBridgeParent->DestroyActor(op);
+      }
+    }
+  }
+private:
+  WebRenderBridgeParent* mWebRenderBridgeParent;
+  InfallibleTArray<OpDestroy>* mActorsToDestroy;
+};
+
+WebRenderBridgeParent::WebRenderBridgeParent(CompositorBridgeParentBase* aCompositorBridge,
+                                             const wr::PipelineId& aPipelineId,
+                                             widget::CompositorWidget* aWidget,
+                                             RefPtr<wr::WebRenderAPI>&& aApi,
+                                             RefPtr<WebRenderCompositableHolder>&& aHolder)
+  : mCompositorBridge(aCompositorBridge)
+  , mPipelineId(aPipelineId)
+  , mWidget(aWidget)
+  , mBuilder(Nothing())
+  , mApi(aApi)
+  , mCompositableHolder(aHolder)
+  , mChildLayerObserverEpoch(0)
+  , mParentLayerObserverEpoch(0)
+  , mPendingTransactionId(0)
+  , mDestroyed(false)
+{
+  MOZ_ASSERT(mCompositableHolder);
+  if (mWidget) {
+    mCompositorScheduler = new CompositorVsyncScheduler(this, mWidget);
+  }
+}
+
+
+mozilla::ipc::IPCResult
+WebRenderBridgeParent::RecvCreate(const gfx::IntSize& aSize)
+{
+  if (mDestroyed) {
+    return IPC_OK();
+  }
+
+  if (mBuilder.isSome()) {
+    return IPC_OK();
+  }
+  MOZ_ASSERT(mApi);
+  mBuilder.emplace(LayerIntSize(aSize.width, aSize.height), mPipelineId);
+
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
+WebRenderBridgeParent::RecvShutdown()
+{
+  if (mDestroyed) {
+    return IPC_OK();
+  }
+  Destroy();
+  if (!Send__delete__(this)) {
+    return IPC_FAIL_NO_REASON(this);
+  }
+  return IPC_OK();
+}
+
+void
+WebRenderBridgeParent::Destroy()
+{
+  if (mDestroyed) {
+    return;
+  }
+  MOZ_ASSERT(mBuilder.isSome());
+  mDestroyed = true;
+  ClearResources();
+}
+
+mozilla::ipc::IPCResult
+WebRenderBridgeParent::RecvAddImage(const gfx::IntSize& aSize,
+                                    const uint32_t& aStride,
+                                    const gfx::SurfaceFormat& aFormat,
+                                    const ByteBuffer& aBuffer,
+                                    wr::ImageKey* aOutImageKey)
+{
+  if (mDestroyed) {
+    return IPC_OK();
+  }
+  MOZ_ASSERT(mApi);
+  *aOutImageKey = mApi->AddImageBuffer(aSize, aStride, aFormat,
+                                       aBuffer.AsSlice());
+
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
+WebRenderBridgeParent::RecvUpdateImage(const wr::ImageKey& aImageKey,
+                                       const gfx::IntSize& aSize,
+                                       const gfx::SurfaceFormat& aFormat,
+                                       const ByteBuffer& aBuffer)
+{
+  if (mDestroyed) {
+    return IPC_OK();
+  }
+  MOZ_ASSERT(mApi);
+  mApi->UpdateImageBuffer(aImageKey, aSize, aFormat, aBuffer.AsSlice());
+
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
+WebRenderBridgeParent::RecvDeleteImage(const wr::ImageKey& aImageKey)
+{
+  if (mDestroyed) {
+    return IPC_OK();
+  }
+  MOZ_ASSERT(mApi);
+  mKeysToDelete.push_back(aImageKey);
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
+WebRenderBridgeParent::RecvDPBegin(const gfx::IntSize& aSize,
+                                   bool* aOutSuccess)
+{
+  if (mDestroyed) {
+    return IPC_OK();
+  }
+  MOZ_ASSERT(mBuilder.isSome());
+  mBuilder.ref().Begin(LayerIntSize(aSize.width, aSize.height));
+  *aOutSuccess = true;
+
+  return IPC_OK();
+}
+
+void
+WebRenderBridgeParent::HandleDPEnd(InfallibleTArray<WebRenderCommand>&& aCommands,
+                                 InfallibleTArray<OpDestroy>&& aToDestroy,
+                                 const uint64_t& aFwdTransactionId,
+                                 const uint64_t& aTransactionId)
+{
+  UpdateFwdTransactionId(aFwdTransactionId);
+
+  if (mDestroyed) {
+    for (const auto& op : aToDestroy) {
+      DestroyActor(op);
+    }
+    return;
+  }
+  // This ensures that destroy operations are always processed. It is not safe
+  // to early-return from RecvDPEnd without doing so.
+  AutoWebRenderBridgeParentAsyncMessageSender autoAsyncMessageSender(this, &aToDestroy);
+
+  ProcessWebrenderCommands(aCommands, wr::Epoch(aTransactionId));
+
+  // The transaction ID might get reset to 1 if the page gets reloaded, see
+  // https://bugzilla.mozilla.org/show_bug.cgi?id=1145295#c41
+  // Otherwise, it should be continually increasing.
+  MOZ_ASSERT(aTransactionId == 1 || aTransactionId > mPendingTransactionId);
+  mPendingTransactionId = aTransactionId;
+}
+
+mozilla::ipc::IPCResult
+WebRenderBridgeParent::RecvDPEnd(InfallibleTArray<WebRenderCommand>&& aCommands,
+                                 InfallibleTArray<OpDestroy>&& aToDestroy,
+                                 const uint64_t& aFwdTransactionId,
+                                 const uint64_t& aTransactionId)
+{
+  HandleDPEnd(Move(aCommands), Move(aToDestroy), aFwdTransactionId, aTransactionId);
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
+WebRenderBridgeParent::RecvDPSyncEnd(InfallibleTArray<WebRenderCommand>&& aCommands,
+                                     InfallibleTArray<OpDestroy>&& aToDestroy,
+                                     const uint64_t& aFwdTransactionId,
+                                     const uint64_t& aTransactionId)
+{
+  HandleDPEnd(Move(aCommands), Move(aToDestroy), aFwdTransactionId, aTransactionId);
+  return IPC_OK();
+}
+
+void
+WebRenderBridgeParent::ProcessWebrenderCommands(InfallibleTArray<WebRenderCommand>& aCommands, const wr::Epoch& aEpoch)
+{
+  MOZ_ASSERT(mBuilder.isSome());
+  wr::DisplayListBuilder& builder = mBuilder.ref();
+  // XXX remove it when external image key is used.
+  std::vector<wr::ImageKey> keysToDelete;
+
+  for (InfallibleTArray<WebRenderCommand>::index_type i = 0; i < aCommands.Length(); ++i) {
+    const WebRenderCommand& cmd = aCommands[i];
+
+    switch (cmd.type()) {
+      case WebRenderCommand::TOpDPPushStackingContext: {
+        const OpDPPushStackingContext& op = cmd.get_OpDPPushStackingContext();
+        builder.PushStackingContext(op.bounds(), op.overflow(), op.mask().ptrOr(nullptr), op.opacity(), op.matrix(), op.mixBlendMode());
+        break;
+      }
+      case WebRenderCommand::TOpDPPopStackingContext: {
+        builder.PopStackingContext();
+        break;
+      }
+      case WebRenderCommand::TOpDPPushRect: {
+        const OpDPPushRect& op = cmd.get_OpDPPushRect();
+        builder.PushRect(op.bounds(), op.clip(), op.color());
+        break;
+      }
+      case WebRenderCommand::TOpDPPushBorder: {
+        const OpDPPushBorder& op = cmd.get_OpDPPushBorder();
+        builder.PushBorder(op.bounds(), op.clip(),
+                           op.top(), op.right(), op.bottom(), op.left(),
+                           op.radius());
+        break;
+      }
+      case WebRenderCommand::TOpDPPushImage: {
+        const OpDPPushImage& op = cmd.get_OpDPPushImage();
+        builder.PushImage(op.bounds(), op.clip(),
+                          op.mask().ptrOr(nullptr), op.filter(), wr::ImageKey(op.key()));
+        break;
+      }
+      case WebRenderCommand::TOpDPPushExternalImageId: {
+        const OpDPPushExternalImageId& op = cmd.get_OpDPPushExternalImageId();
+        MOZ_ASSERT(mExternalImageIds.Get(op.externalImageId()).get());
+
+        RefPtr<CompositableHost> host = mExternalImageIds.Get(op.externalImageId());
+        if (!host) {
+          break;
+        }
+        RefPtr<DataSourceSurface> dSurf = host->GetAsSurface();
+        if (!dSurf) {
+          break;
+        }
+
+        nsIntRegion validBufferRegion = op.validBufferRegion().ToUnknownRegion();
+        IntRect validRect = IntRect(IntPoint(0,0), dSurf->GetSize());
+        if (!validBufferRegion.IsEmpty()) {
+          IntPoint offset = validBufferRegion.GetBounds().TopLeft();
+          validBufferRegion.MoveBy(-offset);
+          validBufferRegion.AndWith(IntRect(IntPoint(0,0), dSurf->GetSize()));
+          validRect = validBufferRegion.GetBounds().ToUnknownRect();
+
+          // XXX Remove it when we can put subimage in WebRender.
+          RefPtr<DrawTarget> target =
+           gfx::Factory::CreateDrawTarget(gfx::BackendType::SKIA, validRect.Size(), SurfaceFormat::B8G8R8A8);
+          for (auto iter = validBufferRegion.RectIter(); !iter.Done(); iter.Next()) {
+            IntRect regionRect = iter.Get();
+            Rect srcRect(regionRect.x + offset.x, regionRect.y + offset.y, regionRect.width, regionRect.height);
+            Rect dstRect(regionRect.x, regionRect.y, regionRect.width, regionRect.height);
+            target->DrawSurface(dSurf, dstRect, srcRect);
+          }
+          RefPtr<SourceSurface> surf = target->Snapshot();
+          dSurf = surf->GetDataSurface();
+        }
+
+        DataSourceSurface::MappedSurface map;
+        if (!dSurf->Map(gfx::DataSourceSurface::MapType::READ, &map)) {
+          break;
+        }
+
+        wr::ImageKey key;
+        auto slice = Range<uint8_t>(map.mData, validRect.height * map.mStride);
+        key = mApi->AddImageBuffer(validRect.Size(), map.mStride, SurfaceFormat::B8G8R8A8, slice);
+
+        builder.PushImage(op.bounds(), op.clip(), op.mask().ptrOr(nullptr), op.filter(), key);
+        keysToDelete.push_back(key);
+        dSurf->Unmap();
+        break;
+      }
+      case WebRenderCommand::TOpDPPushIframe: {
+        const OpDPPushIframe& op = cmd.get_OpDPPushIframe();
+        builder.PushIFrame(op.bounds(), op.clip(), op.pipelineId());
+        break;
+      }
+      case WebRenderCommand::TCompositableOperation: {
+        EditReplyVector replyv;
+        if (!ReceiveCompositableUpdate(cmd.get_CompositableOperation(),
+                                       replyv)) {
+          NS_ERROR("ReceiveCompositableUpdate failed");
+        }
+        break;
+      }
+      case WebRenderCommand::TOpDPPushText: {
+        const OpDPPushText& op = cmd.get_OpDPPushText();
+        const nsTArray<WrGlyphArray>& glyph_array = op.glyph_array();
+
+        for (size_t i = 0; i < glyph_array.Length(); i++) {
+          const nsTArray<WrGlyphInstance>& glyphs = glyph_array[i].glyphs;
+
+          // TODO: We are leaking the key
+          wr::FontKey fontKey;
+          auto slice = Range<uint8_t>(op.font_buffer().mData, op.font_buffer_length());
+          fontKey = mApi->AddRawFont(slice);
+          builder.PushText(op.bounds(),
+                           op.clip(),
+                           glyph_array[i].color,
+                           fontKey,
+                           Range<const WrGlyphInstance>(glyphs.Elements(), glyphs.Length()),
+                           op.glyph_size());
+        }
+
+        break;
+      }
+      default:
+        NS_RUNTIMEABORT("not reached");
+    }
+  }
+  builder.End(*mApi, aEpoch);
+
+  ScheduleComposition();
+  DeleteOldImages();
+
+  // XXX remove it when external image key is used.
+  if (!keysToDelete.empty()) {
+    mKeysToDelete.swap(keysToDelete);
+  }
+
+  if (ShouldParentObserveEpoch()) {
+    mCompositorBridge->ObserveLayerUpdate(mPipelineId.mHandle, GetChildLayerObserverEpoch(), true);
+  }
+}
+
+mozilla::ipc::IPCResult
+WebRenderBridgeParent::RecvDPGetSnapshot(PTextureParent* aTexture)
+{
+  if (mDestroyed) {
+    return IPC_OK();
+  }
+
+  RefPtr<TextureHost> texture = TextureHost::AsTextureHost(aTexture);
+  if (!texture) {
+    // We kill the content process rather than have it continue with an invalid
+    // snapshot, that may be too harsh and we could decide to return some sort
+    // of error to the child process and let it deal with it...
+    return IPC_FAIL_NO_REASON(this);
+  }
+
+  // XXX Add other TextureHost supports.
+  // Only BufferTextureHost is supported now.
+  BufferTextureHost* bufferTexture = texture->AsBufferTextureHost();
+  if (!bufferTexture) {
+    // We kill the content process rather than have it continue with an invalid
+    // snapshot, that may be too harsh and we could decide to return some sort
+    // of error to the child process and let it deal with it...
+    return IPC_FAIL_NO_REASON(this);
+  }
+
+  MOZ_ASSERT(bufferTexture->GetBufferDescriptor().type() == BufferDescriptor::TRGBDescriptor);
+  DebugOnly<uint32_t> stride = ImageDataSerializer::GetRGBStride(bufferTexture->GetBufferDescriptor().get_RGBDescriptor());
+  uint8_t* buffer = bufferTexture->GetBuffer();
+  IntSize size = bufferTexture->GetSize();
+
+  // We only support B8G8R8A8 for now.
+  MOZ_ASSERT(buffer);
+  MOZ_ASSERT(bufferTexture->GetFormat() == SurfaceFormat::B8G8R8A8);
+  uint32_t buffer_size = size.width * size.height * 4;
+
+  // Assert the stride of the buffer is what webrender expects
+  MOZ_ASSERT((uint32_t)(size.width * 4) == stride);
+
+  MOZ_ASSERT(mBuilder.isSome());
+  mApi->Readback(size, buffer, buffer_size);
+
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
+WebRenderBridgeParent::RecvAddExternalImageId(const uint64_t& aImageId,
+                                              const CompositableHandle& aHandle)
+{
+  if (mDestroyed) {
+    return IPC_OK();
+  }
+
+  MOZ_ASSERT(!mExternalImageIds.Get(aImageId).get());
+
+  ImageBridgeParent* imageBridge = ImageBridgeParent::GetInstance(OtherPid());
+  if (!imageBridge) {
+     return IPC_FAIL_NO_REASON(this);
+  }
+  RefPtr<CompositableHost> host = imageBridge->FindCompositable(aHandle);
+  if (!host) {
+    NS_ERROR("CompositableHost not found in the map!");
+    return IPC_FAIL_NO_REASON(this);
+  }
+  if (host->GetType() != CompositableType::IMAGE &&
+      host->GetType() != CompositableType::CONTENT_SINGLE &&
+      host->GetType() != CompositableType::CONTENT_DOUBLE) {
+    NS_ERROR("Incompatible CompositableHost");
+    return IPC_OK();
+  }
+
+  mCompositableHolder->AddExternalImageId(aImageId, host);
+  mExternalImageIds.Put(aImageId, host);
+
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
+WebRenderBridgeParent::RecvAddExternalImageIdForCompositable(const uint64_t& aImageId,
+                                                             const CompositableHandle& aHandle)
+{
+  if (mDestroyed) {
+    return IPC_OK();
+  }
+  MOZ_ASSERT(!mExternalImageIds.Get(aImageId).get());
+
+  RefPtr<CompositableHost> host = FindCompositable(aHandle);
+  if (host->GetType() != CompositableType::IMAGE &&
+      host->GetType() != CompositableType::CONTENT_SINGLE &&
+      host->GetType() != CompositableType::CONTENT_DOUBLE) {
+    NS_ERROR("Incompatible CompositableHost");
+    return IPC_OK();
+  }
+
+  mCompositableHolder->AddExternalImageId(aImageId, host);
+  mExternalImageIds.Put(aImageId, host);
+
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
+WebRenderBridgeParent::RecvRemoveExternalImageId(const uint64_t& aImageId)
+{
+  if (mDestroyed) {
+    return IPC_OK();
+  }
+  MOZ_ASSERT(mExternalImageIds.Get(aImageId).get());
+  mExternalImageIds.Remove(aImageId);
+  mCompositableHolder->RemoveExternalImageId(aImageId);
+
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
+WebRenderBridgeParent::RecvSetLayerObserverEpoch(const uint64_t& aLayerObserverEpoch)
+{
+  mChildLayerObserverEpoch = aLayerObserverEpoch;
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
+WebRenderBridgeParent::RecvClearCachedResources()
+{
+  mCompositorBridge->ObserveLayerUpdate(mPipelineId.mHandle, GetChildLayerObserverEpoch(), false);
+  return IPC_OK();
+}
+
+void
+WebRenderBridgeParent::ActorDestroy(ActorDestroyReason aWhy)
+{
+  Destroy();
+}
+
+void
+WebRenderBridgeParent::CompositeToTarget(gfx::DrawTarget* aTarget, const gfx::IntRect* aRect)
+{
+  // TODO(bug 1328602) With the RenderThread, calling SetRootStackingContext
+  // should trigger the composition on the render thread.
+  MOZ_ASSERT_UNREACHABLE("unexpected to be called");
+}
+
+void
+WebRenderBridgeParent::DidComposite(uint64_t aTransactionId, TimeStamp aStart, TimeStamp aEnd)
+{
+  mCompositorBridge->NotifyDidComposite(aTransactionId, aStart, aEnd);
+}
+
+WebRenderBridgeParent::~WebRenderBridgeParent()
+{
+}
+
+void
+WebRenderBridgeParent::DeleteOldImages()
+{
+  for (wr::ImageKey key : mKeysToDelete) {
+    mApi->DeleteImage(key);
+  }
+  mKeysToDelete.clear();
+}
+
+void
+WebRenderBridgeParent::ScheduleComposition()
+{
+  MOZ_ASSERT(mApi);
+  // TODO(bug 1328602) should probably send a message to the render
+  // thread and force rendering, although in most cases where this is
+  // called, rendering should be triggered automatically already (maybe
+  // not in the ImageBridge case).
+}
+
+void
+WebRenderBridgeParent::ClearResources()
+{
+  DeleteOldImages();
+  if (mCompositableHolder) {
+    for (auto iter = mExternalImageIds.Iter(); !iter.Done(); iter.Next()) {
+      uint64_t externalImageId = iter.Key();
+      mCompositableHolder->RemoveExternalImageId(externalImageId);
+    }
+  }
+  mExternalImageIds.Clear();
+
+  if (mBuilder.isSome()) {
+    mBuilder.reset();
+  }
+  if (mCompositorScheduler) {
+    mCompositorScheduler->Destroy();
+    mCompositorScheduler = nullptr;
+  }
+
+  mApi = nullptr;
+  mCompositorBridge = nullptr;
+}
+
+bool
+WebRenderBridgeParent::ShouldParentObserveEpoch()
+{
+  if (mParentLayerObserverEpoch == mChildLayerObserverEpoch) {
+    return false;
+  }
+
+  mParentLayerObserverEpoch = mChildLayerObserverEpoch;
+  return true;
+}
+
+void
+WebRenderBridgeParent::SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage)
+{
+  MOZ_ASSERT_UNREACHABLE("unexpected to be called");
+}
+
+void
+WebRenderBridgeParent::SendPendingAsyncMessages()
+{
+  MOZ_ASSERT(mCompositorBridge);
+  mCompositorBridge->SendPendingAsyncMessages();
+}
+
+void
+WebRenderBridgeParent::SetAboutToSendAsyncMessages()
+{
+  MOZ_ASSERT(mCompositorBridge);
+  mCompositorBridge->SetAboutToSendAsyncMessages();
+}
+
+void
+WebRenderBridgeParent::NotifyNotUsed(PTextureParent* aTexture, uint64_t aTransactionId)
+{
+  MOZ_ASSERT_UNREACHABLE("unexpected to be called");
+}
+
+base::ProcessId
+WebRenderBridgeParent::GetChildProcessId()
+{
+  return OtherPid();
+}
+
+bool
+WebRenderBridgeParent::IsSameProcess() const
+{
+  return OtherPid() == base::GetCurrentProcId();
+}
+
+mozilla::ipc::IPCResult
+WebRenderBridgeParent::RecvNewCompositable(const CompositableHandle& aHandle,
+                                           const TextureInfo& aInfo)
+{
+  if (!AddCompositable(aHandle, aInfo)) {
+    return IPC_FAIL_NO_REASON(this);
+  }
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
+WebRenderBridgeParent::RecvReleaseCompositable(const CompositableHandle& aHandle)
+{
+  ReleaseCompositable(aHandle);
+  return IPC_OK();
+}
+
+void
+WebRenderBridgeParent::SetWebRenderProfilerEnabled(bool aEnabled)
+{
+  if (mWidget) {
+    // Only set the flag to "root" WebRenderBridgeParent.
+    mApi->SetProfilerEnabled(aEnabled);
+  }
+}
+
+TextureFactoryIdentifier
+WebRenderBridgeParent::GetTextureFactoryIdentifier()
+{
+  MOZ_ASSERT(mApi);
+
+  return TextureFactoryIdentifier(LayersBackend::LAYERS_WR,
+                                  XRE_GetProcessType(),
+                                  mApi->GetMaxTextureSize());
+}
+
+} // namespace layers
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/layers/wr/WebRenderBridgeParent.h
@@ -0,0 +1,172 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=4 ts=8 et tw=80 : */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_layers_WebRenderBridgeParent_h
+#define mozilla_layers_WebRenderBridgeParent_h
+
+#include "CompositableHost.h"           // for CompositableHost, ImageCompositeNotificationInfo
+#include "GLContextProvider.h"
+#include "mozilla/layers/CompositableTransactionParent.h"
+#include "mozilla/layers/CompositorVsyncSchedulerOwner.h"
+#include "mozilla/layers/PWebRenderBridgeParent.h"
+#include "mozilla/Maybe.h"
+#include "mozilla/webrender/WebRenderTypes.h"
+#include "mozilla/webrender/WebRenderAPI.h"
+#include "nsTArrayForwardDeclare.h"
+
+namespace mozilla {
+
+namespace gl {
+class GLContext;
+}
+
+namespace widget {
+class CompositorWidget;
+}
+
+namespace wr {
+class WebRenderAPI;
+}
+
+namespace layers {
+
+class Compositor;
+class CompositorBridgeParentBase;
+class CompositorVsyncScheduler;
+class WebRenderCompositableHolder;
+
+class WebRenderBridgeParent final : public PWebRenderBridgeParent
+                                  , public CompositorVsyncSchedulerOwner
+                                  , public CompositableParentManager
+{
+public:
+  WebRenderBridgeParent(CompositorBridgeParentBase* aCompositorBridge,
+                        const wr::PipelineId& aPipelineId,
+                        widget::CompositorWidget* aWidget,
+                        RefPtr<wr::WebRenderAPI>&& aApi,
+                        RefPtr<WebRenderCompositableHolder>&& aHolder);
+
+  wr::PipelineId PipelineId() { return mPipelineId; }
+  wr::WebRenderAPI* GetWebRenderAPI() { return mApi; }
+  WebRenderCompositableHolder* CompositableHolder() { return mCompositableHolder; }
+  CompositorVsyncScheduler* CompositorScheduler() { return mCompositorScheduler.get(); }
+
+  mozilla::ipc::IPCResult RecvNewCompositable(const CompositableHandle& aHandle,
+                                              const TextureInfo& aInfo) override;
+  mozilla::ipc::IPCResult RecvReleaseCompositable(const CompositableHandle& aHandle) override;
+
+  mozilla::ipc::IPCResult RecvCreate(const gfx::IntSize& aSize) override;
+  mozilla::ipc::IPCResult RecvShutdown() override;
+  mozilla::ipc::IPCResult RecvAddImage(const gfx::IntSize& aSize,
+                                       const uint32_t& aStride,
+                                       const gfx::SurfaceFormat& aFormat,
+                                       const ByteBuffer& aBuffer,
+                                       wr::ImageKey* aOutImageKey) override;
+  mozilla::ipc::IPCResult RecvUpdateImage(const wr::ImageKey& aImageKey,
+                                          const gfx::IntSize& aSize,
+                                          const gfx::SurfaceFormat& aFormat,
+                                          const ByteBuffer& aBuffer) override;
+  mozilla::ipc::IPCResult RecvDeleteImage(const wr::ImageKey& a1) override;
+  mozilla::ipc::IPCResult RecvDPBegin(const gfx::IntSize& aSize,
+                                      bool* aOutSuccess) override;
+  mozilla::ipc::IPCResult RecvDPEnd(InfallibleTArray<WebRenderCommand>&& aCommands,
+                                    InfallibleTArray<OpDestroy>&& aToDestroy,
+                                    const uint64_t& aFwdTransactionId,
+                                    const uint64_t& aTransactionId) override;
+  mozilla::ipc::IPCResult RecvDPSyncEnd(InfallibleTArray<WebRenderCommand>&& aCommands,
+                                        InfallibleTArray<OpDestroy>&& aToDestroy,
+                                        const uint64_t& aFwdTransactionId,
+                                        const uint64_t& aTransactionId) override;
+  mozilla::ipc::IPCResult RecvDPGetSnapshot(PTextureParent* aTexture) override;
+
+  mozilla::ipc::IPCResult RecvAddExternalImageId(const uint64_t& aImageId,
+                                                 const CompositableHandle& aHandle) override;
+  mozilla::ipc::IPCResult RecvAddExternalImageIdForCompositable(const uint64_t& aImageId,
+                                                                const CompositableHandle& aHandle) override;
+  mozilla::ipc::IPCResult RecvRemoveExternalImageId(const uint64_t& aImageId) override;
+  mozilla::ipc::IPCResult RecvSetLayerObserverEpoch(const uint64_t& aLayerObserverEpoch) override;
+
+  mozilla::ipc::IPCResult RecvClearCachedResources() override;
+
+  void ActorDestroy(ActorDestroyReason aWhy) override;
+  void SetWebRenderProfilerEnabled(bool aEnabled);
+
+  void Destroy();
+
+  const uint64_t& GetPendingTransactionId() { return mPendingTransactionId; }
+  void SetPendingTransactionId(uint64_t aId) { mPendingTransactionId = aId; }
+
+  // CompositorVsyncSchedulerOwner
+  bool IsPendingComposite() override { return false; }
+  void FinishPendingComposite() override { }
+  void CompositeToTarget(gfx::DrawTarget* aTarget, const gfx::IntRect* aRect = nullptr) override;
+
+  // CompositableParentManager
+  bool IsSameProcess() const override;
+  base::ProcessId GetChildProcessId() override;
+  void NotifyNotUsed(PTextureParent* aTexture, uint64_t aTransactionId) override;
+  void SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage) override;
+  void SendPendingAsyncMessages() override;
+  void SetAboutToSendAsyncMessages() override;
+
+  void DidComposite(uint64_t aTransactionId, TimeStamp aStart, TimeStamp aEnd);
+
+  TextureFactoryIdentifier GetTextureFactoryIdentifier();
+
+  void AppendImageCompositeNotification(const ImageCompositeNotificationInfo& aNotification)
+  {
+    MOZ_ASSERT(mWidget);
+    mImageCompositeNotifications.AppendElement(aNotification);
+  }
+
+  void ExtractImageCompositeNotifications(nsTArray<ImageCompositeNotificationInfo>* aNotifications)
+  {
+    MOZ_ASSERT(mWidget);
+    aNotifications->AppendElements(Move(mImageCompositeNotifications));
+  }
+
+private:
+  virtual ~WebRenderBridgeParent();
+
+  void DeleteOldImages();
+  void ProcessWebrenderCommands(InfallibleTArray<WebRenderCommand>& commands, const wr::Epoch& aEpoch);
+  void ScheduleComposition();
+  void ClearResources();
+  uint64_t GetChildLayerObserverEpoch() const { return mChildLayerObserverEpoch; }
+  bool ShouldParentObserveEpoch();
+  void HandleDPEnd(InfallibleTArray<WebRenderCommand>&& aCommands,
+                   InfallibleTArray<OpDestroy>&& aToDestroy,
+                   const uint64_t& aFwdTransactionId,
+                   const uint64_t& aTransactionId);
+
+private:
+  CompositorBridgeParentBase* MOZ_NON_OWNING_REF mCompositorBridge;
+  wr::PipelineId mPipelineId;
+  RefPtr<widget::CompositorWidget> mWidget;
+  Maybe<wr::DisplayListBuilder> mBuilder;
+  RefPtr<wr::WebRenderAPI> mApi;
+  RefPtr<WebRenderCompositableHolder> mCompositableHolder;
+  RefPtr<CompositorVsyncScheduler> mCompositorScheduler;
+  std::vector<wr::ImageKey> mKeysToDelete;
+  nsDataHashtable<nsUint64HashKey, RefPtr<CompositableHost>> mExternalImageIds;
+  nsTArray<ImageCompositeNotificationInfo> mImageCompositeNotifications;
+
+  // These fields keep track of the latest layer observer epoch values in the child and the
+  // parent. mChildLayerObserverEpoch is the latest epoch value received from the child.
+  // mParentLayerObserverEpoch is the latest epoch value that we have told TabParent about
+  // (via ObserveLayerUpdate).
+  uint64_t mChildLayerObserverEpoch;
+  uint64_t mParentLayerObserverEpoch;
+
+  uint64_t mPendingTransactionId;
+
+  bool mDestroyed;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // mozilla_layers_WebRenderBridgeParent_h
new file mode 100644
--- /dev/null
+++ b/gfx/layers/wr/WebRenderCanvasLayer.cpp
@@ -0,0 +1,111 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "WebRenderCanvasLayer.h"
+
+#include "AsyncCanvasRenderer.h"
+#include "gfxUtils.h"
+#include "GLContext.h"
+#include "GLScreenBuffer.h"
+#include "WebRenderLayersLogging.h"
+#include "mozilla/gfx/2D.h"
+#include "mozilla/layers/TextureClientSharedSurface.h"
+#include "mozilla/layers/WebRenderBridgeChild.h"
+#include "PersistentBufferProvider.h"
+#include "SharedSurface.h"
+#include "SharedSurfaceGL.h"
+#include "mozilla/webrender/WebRenderTypes.h"
+
+namespace mozilla {
+namespace layers {
+
+WebRenderCanvasLayer::~WebRenderCanvasLayer()
+{
+  MOZ_COUNT_DTOR(WebRenderCanvasLayer);
+
+  if (mExternalImageId) {
+    WrBridge()->DeallocExternalImageId(mExternalImageId);
+  }
+}
+
+void
+WebRenderCanvasLayer::Initialize(const Data& aData)
+{
+  ShareableCanvasLayer::Initialize(aData);
+
+  // XXX: Use basic surface factory until we support shared surface.
+  if (!mGLContext || mGLFrontbuffer)
+    return;
+
+  gl::GLScreenBuffer* screen = mGLContext->Screen();
+  auto factory = MakeUnique<gl::SurfaceFactory_Basic>(mGLContext, screen->mCaps, mFlags);
+  screen->Morph(Move(factory));
+}
+
+void
+WebRenderCanvasLayer::RenderLayer()
+{
+  UpdateCompositableClient();
+
+  if (!mExternalImageId) {
+    mExternalImageId = WrBridge()->AllocExternalImageIdForCompositable(mCanvasClient);
+  }
+
+  MOZ_ASSERT(mExternalImageId);
+
+  gfx::Matrix4x4 transform;// = GetTransform();
+  const bool needsYFlip = (mOriginPos == gl::OriginPos::BottomLeft);
+  if (needsYFlip) {
+    transform.PreTranslate(0, mBounds.height, 0).PreScale(1, -1, 1);
+  }
+  gfx::Rect rect(0, 0, mBounds.width, mBounds.height);
+  rect = RelativeToTransformedVisible(GetTransform().TransformBounds(rect));
+
+  gfx::Rect clip;
+  if (GetClipRect().isSome()) {
+      clip = RelativeToTransformedVisible(IntRectToRect(GetClipRect().ref().ToUnknownRect()));
+  } else {
+      clip = rect;
+  }
+
+  gfx::Rect relBounds = TransformedVisibleBoundsRelativeToParent();
+  gfx::Rect overflow(0, 0, relBounds.width, relBounds.height);
+  Maybe<WrImageMask> mask = buildMaskLayer();
+  WrTextureFilter filter = (mSamplingFilter == gfx::SamplingFilter::POINT) ? WrTextureFilter::Point : WrTextureFilter::Linear;
+  WrMixBlendMode mixBlendMode = wr::ToWrMixBlendMode(GetMixBlendMode());
+
+  if (gfxPrefs::LayersDump()) {
+    printf_stderr("CanvasLayer %p using bounds=%s, overflow=%s, transform=%s, rect=%s, clip=%s, texture-filter=%s, mix-blend-mode=%s\n",
+                  this->GetLayer(),
+                  Stringify(relBounds).c_str(),
+                  Stringify(overflow).c_str(),
+                  Stringify(transform).c_str(),
+                  Stringify(rect).c_str(),
+                  Stringify(clip).c_str(),
+                  Stringify(filter).c_str(),
+                  Stringify(mixBlendMode).c_str());
+  }
+
+  WrBridge()->AddWebRenderCommand(
+      OpDPPushStackingContext(wr::ToWrRect(relBounds),
+                              wr::ToWrRect(overflow),
+                              mask,
+                              1.0f,
+                              GetAnimations(),
+                              transform,
+                              mixBlendMode,
+                              FrameMetrics::NULL_SCROLL_ID));
+  WrBridge()->AddWebRenderCommand(OpDPPushExternalImageId(LayerIntRegion(), wr::ToWrRect(rect), wr::ToWrRect(clip), Nothing(), filter, mExternalImageId));
+  WrBridge()->AddWebRenderCommand(OpDPPopStackingContext());
+}
+
+void
+WebRenderCanvasLayer::AttachCompositable()
+{
+  mCanvasClient->Connect();
+}
+
+} // namespace layers
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/layers/wr/WebRenderCanvasLayer.h
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef GFX_WEBRENDERCANVASLAYER_H
+#define GFX_WEBRENDERCANVASLAYER_H
+
+#include "ShareableCanvasLayer.h"
+#include "WebRenderLayerManager.h"
+
+namespace mozilla {
+namespace gfx {
+class SourceSurface;
+}; // namespace gfx
+
+namespace layers {
+
+class WebRenderCanvasLayer : public WebRenderLayer,
+                             public ShareableCanvasLayer
+{
+public:
+  explicit WebRenderCanvasLayer(WebRenderLayerManager* aLayerManager)
+    : ShareableCanvasLayer(aLayerManager, static_cast<WebRenderLayer*>(this))
+    , mExternalImageId(0)
+  {
+    MOZ_COUNT_CTOR(WebRenderCanvasLayer);
+  }
+
+  virtual void Initialize(const Data& aData) override;
+
+  virtual CompositableForwarder* GetForwarder() override
+  {
+    return Manager()->WrBridge();
+  }
+
+  virtual void AttachCompositable() override;
+
+protected:
+  virtual ~WebRenderCanvasLayer();
+  WebRenderLayerManager* Manager()
+  {
+    return static_cast<WebRenderLayerManager*>(mManager);
+  }
+
+public:
+  Layer* GetLayer() override { return this; }
+  void RenderLayer() override;
+
+protected:
+  uint64_t mExternalImageId;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // GFX_WEBRENDERCANVASLAYER_H
new file mode 100644
--- /dev/null
+++ b/gfx/layers/wr/WebRenderColorLayer.cpp
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "WebRenderColorLayer.h"
+
+#include "WebRenderLayersLogging.h"
+#include "mozilla/webrender/webrender_ffi.h"
+#include "mozilla/webrender/WebRenderTypes.h"
+#include "mozilla/layers/WebRenderBridgeChild.h"
+
+namespace mozilla {
+namespace layers {
+
+void
+WebRenderColorLayer::RenderLayer()
+{
+  WrScrollFrameStackingContextGenerator scrollFrames(this);
+
+  LayerIntRegion visibleRegion = GetVisibleRegion();
+  LayerIntRect bounds = visibleRegion.GetBounds();
+  Rect rect = RelativeToVisible(IntRectToRect(bounds.ToUnknownRect()));
+  Rect clip;
+  if (GetClipRect().isSome()) {
+      clip = RelativeToTransformedVisible(IntRectToRect(GetClipRect().ref().ToUnknownRect()));
+  } else {
+      clip = rect;
+  }
+
+  gfx::Matrix4x4 transform;// = GetTransform();
+  gfx::Rect relBounds = TransformedVisibleBoundsRelativeToParent();
+  gfx::Rect overflow(0, 0, relBounds.width, relBounds.height);
+  WrMixBlendMode mixBlendMode = wr::ToWrMixBlendMode(GetMixBlendMode());
+
+  Maybe<WrImageMask> mask = buildMaskLayer();
+
+  if (gfxPrefs::LayersDump()) {
+    printf_stderr("ColorLayer %p using bounds=%s, overflow=%s, transform=%s, rect=%s, clip=%s, mix-blend-mode=%s\n",
+                  this->GetLayer(),
+                  Stringify(relBounds).c_str(),
+                  Stringify(overflow).c_str(),
+                  Stringify(transform).c_str(),
+                  Stringify(rect).c_str(),
+                  Stringify(clip).c_str(),
+                  Stringify(mixBlendMode).c_str());
+  }
+
+  WrBridge()->AddWebRenderCommand(
+      OpDPPushStackingContext(wr::ToWrRect(relBounds),
+                              wr::ToWrRect(overflow),
+                              mask,
+                              1.0f,
+                              GetAnimations(),
+                              transform,
+                              mixBlendMode,
+                              FrameMetrics::NULL_SCROLL_ID));
+  WrBridge()->AddWebRenderCommand(
+    OpDPPushRect(wr::ToWrRect(rect), wr::ToWrRect(clip), wr::ToWrColor(mColor)));
+  WrBridge()->AddWebRenderCommand(OpDPPopStackingContext());
+}
+
+} // namespace layers
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/layers/wr/WebRenderColorLayer.h
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef GFX_WEBRENDERCOLORLAYER_H
+#define GFX_WEBRENDERCOLORLAYER_H
+
+#include "Layers.h"
+#include "WebRenderLayerManager.h"
+
+namespace mozilla {
+namespace layers {
+
+class WebRenderColorLayer : public WebRenderLayer,
+                            public ColorLayer {
+public:
+  explicit WebRenderColorLayer(WebRenderLayerManager* aLayerManager)
+    : ColorLayer(aLayerManager, static_cast<WebRenderLayer*>(this))
+  {
+    MOZ_COUNT_CTOR(WebRenderColorLayer);
+  }
+
+protected:
+  virtual ~WebRenderColorLayer()
+  {
+    MOZ_COUNT_DTOR(WebRenderColorLayer);
+  }
+
+public:
+  Layer* GetLayer() override { return this; }
+  void RenderLayer() override;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // GFX_WEBRENDERCOLORLAYER_H
new file mode 100644
--- /dev/null
+++ b/gfx/layers/wr/WebRenderCompositableHolder.cpp
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "WebRenderCompositableHolder.h"
+
+#include "CompositableHost.h"
+//#include "mozilla/layers/CompositorBridgeParent.h"
+
+namespace mozilla {
+
+using namespace gfx;
+
+namespace layers {
+
+WebRenderCompositableHolder::WebRenderCompositableHolder()
+{
+  MOZ_COUNT_CTOR(WebRenderCompositableHolder);
+}
+
+WebRenderCompositableHolder::~WebRenderCompositableHolder()
+{
+  MOZ_COUNT_DTOR(WebRenderCompositableHolder);
+  Destroy();
+}
+
+void
+WebRenderCompositableHolder::Destroy()
+{
+  mCompositableHosts.Clear();
+}
+
+void
+WebRenderCompositableHolder::AddExternalImageId(uint64_t aExternalImageId, CompositableHost* aHost)
+{
+  MOZ_ASSERT(!mCompositableHosts.Get(aExternalImageId));
+  mCompositableHosts.Put(aExternalImageId, aHost);
+}
+
+void
+WebRenderCompositableHolder::RemoveExternalImageId(uint64_t aExternalImageId)
+{
+  MOZ_ASSERT(mCompositableHosts.Get(aExternalImageId));
+  mCompositableHosts.Remove(aExternalImageId);
+}
+
+void
+WebRenderCompositableHolder::UpdateExternalImages()
+{
+  for (auto iter = mCompositableHosts.Iter(); !iter.Done(); iter.Next()) {
+    RefPtr<CompositableHost>& host = iter.Data();
+    // XXX Change to correct TextrueSource handling here.
+    host->BindTextureSource();
+  }
+}
+
+} // namespace layers
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/layers/wr/WebRenderCompositableHolder.h
@@ -0,0 +1,43 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef MOZILLA_GFX_WEBRENDERCOMPOSITABLE_HOLDER_H
+#define MOZILLA_GFX_WEBRENDERCOMPOSITABLE_HOLDER_H
+
+#include "nsDataHashtable.h"
+
+namespace mozilla {
+namespace layers {
+
+class CompositableHost;
+
+class WebRenderCompositableHolder final
+{
+public:
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WebRenderCompositableHolder)
+
+  explicit WebRenderCompositableHolder();
+
+protected:
+  virtual ~WebRenderCompositableHolder();
+
+public:
+
+  virtual void Destroy();
+
+  void AddExternalImageId(uint64_t aExternalImageId, CompositableHost* aHost);
+  void RemoveExternalImageId(uint64_t aExternalImageId);
+  void UpdateExternalImages();
+
+private:
+
+  // Holds CompositableHosts that are bound to external image ids.
+  nsDataHashtable<nsUint64HashKey, RefPtr<CompositableHost> > mCompositableHosts;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif /* MOZILLA_GFX_WEBRENDERCOMPOSITABLE_HOLDER_H */
new file mode 100644
--- /dev/null
+++ b/gfx/layers/wr/WebRenderCompositorOGL.cpp
@@ -0,0 +1,152 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "WebRenderCompositorOGL.h"
+
+#include "CompositableHost.h"
+#include "GLContext.h"                  // for GLContext
+#include "GLUploadHelpers.h"
+#include "mozilla/layers/CompositorBridgeParent.h"
+#include "mozilla/layers/TextureHost.h"  // for TextureSource, etc
+#include "mozilla/layers/TextureHostOGL.h"  // for TextureSourceOGL, etc
+
+namespace mozilla {
+
+using namespace gfx;
+using namespace gl;
+
+namespace layers {
+
+WebRenderCompositorOGL::WebRenderCompositorOGL(CompositorBridgeParent* aCompositorBridge,
+                                               GLContext* aGLContext)
+  : Compositor(nullptr, nullptr)
+  , mCompositorBridge(aCompositorBridge)
+  , mGLContext(aGLContext)
+  , mDestroyed(false)
+{
+  MOZ_COUNT_CTOR(WebRenderCompositorOGL);
+}
+
+WebRenderCompositorOGL::~WebRenderCompositorOGL()
+{
+  MOZ_COUNT_DTOR(WebRenderCompositorOGL);
+  Destroy();
+}
+
+void
+WebRenderCompositorOGL::Destroy()
+{
+  Compositor::Destroy();
+
+  mCompositableHosts.Clear();
+  mCompositorBridge = nullptr;
+
+  if (!mDestroyed) {
+    mDestroyed = true;
+    CleanupResources();
+  }
+}
+
+void
+WebRenderCompositorOGL::CleanupResources()
+{
+  if (!mGLContext) {
+    return;
+  }
+
+  // On the main thread the Widget will be destroyed soon and calling MakeCurrent
+  // after that could cause a crash (at least with GLX, see bug 1059793), unless
+  // context is marked as destroyed.
+  // There may be some textures still alive that will try to call MakeCurrent on
+  // the context so let's make sure it is marked destroyed now.
+  mGLContext->MarkDestroyed();
+
+  mGLContext = nullptr;
+}
+
+bool
+WebRenderCompositorOGL::Initialize(nsCString* const out_failureReason)
+{
+  MOZ_ASSERT(mGLContext);
+  return true;
+}
+
+already_AddRefed<DataTextureSource>
+WebRenderCompositorOGL::CreateDataTextureSource(TextureFlags aFlags)
+{
+  return nullptr;
+}
+
+bool
+WebRenderCompositorOGL::SupportsPartialTextureUpdate()
+{
+  return CanUploadSubTextures(mGLContext);
+}
+
+int32_t
+WebRenderCompositorOGL::GetMaxTextureSize() const
+{
+  MOZ_ASSERT(mGLContext);
+  GLint texSize = 0;
+  mGLContext->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE,
+                            &texSize);
+  MOZ_ASSERT(texSize != 0);
+  return texSize;
+}
+
+void
+WebRenderCompositorOGL::MakeCurrent(MakeCurrentFlags aFlags) {
+  if (mDestroyed) {
+    NS_WARNING("Call on destroyed layer manager");
+    return;
+  }
+  mGLContext->MakeCurrent(aFlags & ForceMakeCurrent);
+}
+
+void
+WebRenderCompositorOGL::CompositeUntil(TimeStamp aTimeStamp)
+{
+  Compositor::CompositeUntil(aTimeStamp);
+  // We're not really taking advantage of the stored composite-again-time here.
+  // We might be able to skip the next few composites altogether. However,
+  // that's a bit complex to implement and we'll get most of the advantage
+  // by skipping compositing when we detect there's nothing invalid. This is why
+  // we do "composite until" rather than "composite again at".
+  ScheduleComposition();
+}
+
+void
+WebRenderCompositorOGL::AddExternalImageId(uint64_t aExternalImageId, CompositableHost* aHost)
+{
+  MOZ_ASSERT(!mCompositableHosts.Get(aExternalImageId));
+  mCompositableHosts.Put(aExternalImageId, aHost);
+}
+
+void
+WebRenderCompositorOGL::RemoveExternalImageId(uint64_t aExternalImageId)
+{
+  MOZ_ASSERT(mCompositableHosts.Get(aExternalImageId));
+  mCompositableHosts.Remove(aExternalImageId);
+}
+
+void
+WebRenderCompositorOGL::UpdateExternalImages()
+{
+  for (auto iter = mCompositableHosts.Iter(); !iter.Done(); iter.Next()) {
+    RefPtr<CompositableHost>& host = iter.Data();
+    // XXX Change to correct TextrueSource handling here.
+    host->BindTextureSource();
+  }
+}
+
+void
+WebRenderCompositorOGL::ScheduleComposition()
+{
+  MOZ_ASSERT(mCompositorBridge);
+  mCompositorBridge->ScheduleComposition();
+}
+
+} // namespace layers
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/layers/wr/WebRenderCompositorOGL.h
@@ -0,0 +1,138 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef MOZILLA_GFX_WEBRENDERCOMPOSITOROGL_H
+#define MOZILLA_GFX_WEBRENDERCOMPOSITOROGL_H
+
+#include "GLContextTypes.h"             // for GLContext, etc
+#include "GLDefs.h"                     // for GLuint, LOCAL_GL_TEXTURE_2D, etc
+#include "mozilla/layers/Compositor.h"  // for SurfaceInitMode, Compositor, etc
+#include "nsDataHashtable.h"
+
+namespace mozilla {
+namespace layers {
+
+class CompositableHost;
+class CompositorBridgeParent;
+
+class WebRenderCompositorOGL final : public Compositor
+{
+  typedef mozilla::gl::GLContext GLContext;
+
+public:
+  explicit WebRenderCompositorOGL(CompositorBridgeParent* aCompositorBridge, GLContext* aGLContext);
+
+protected:
+  virtual ~WebRenderCompositorOGL();
+
+public:
+  virtual WebRenderCompositorOGL* AsWebRenderCompositorOGL() override { return this; }
+
+  virtual already_AddRefed<DataTextureSource>
+  CreateDataTextureSource(TextureFlags aFlags = TextureFlags::NO_FLAGS) override;
+
+  virtual bool Initialize(nsCString* const out_failureReason) override;
+
+  virtual void Destroy() override;
+
+  virtual TextureFactoryIdentifier GetTextureFactoryIdentifier() override
+  {
+    TextureFactoryIdentifier result =
+      TextureFactoryIdentifier(LayersBackend::LAYERS_WR,
+                               XRE_GetProcessType(),
+                               GetMaxTextureSize(),
+                               true,
+                               SupportsPartialTextureUpdate());
+    return result;
+  }
+
+  virtual already_AddRefed<CompositingRenderTarget>
+  CreateRenderTarget(const gfx::IntRect &aRect, SurfaceInitMode aInit) override { return nullptr; }
+
+  virtual already_AddRefed<CompositingRenderTarget>
+  CreateRenderTargetFromSource(const gfx::IntRect &aRect,
+                               const CompositingRenderTarget *aSource,
+                               const gfx::IntPoint &aSourcePoint) override { return nullptr; }
+
+  virtual void SetRenderTarget(CompositingRenderTarget *aSurface) override { }
+
+  virtual CompositingRenderTarget* GetCurrentRenderTarget() const override { return nullptr; }
+
+  virtual void DrawQuad(const gfx::Rect& aRect,
+                        const gfx::IntRect& aClipRect,
+                        const EffectChain &aEffectChain,
+                        gfx::Float aOpacity,
+                        const gfx::Matrix4x4& aTransform,
+                        const gfx::Rect& aVisibleRect) override { }
+
+  virtual void DrawTriangle(const gfx::TexturedTriangle& aTriangle,
+                            const gfx::IntRect& aClipRect,
+                            const EffectChain& aEffectChain,
+                            gfx::Float aOpacity,
+                            const gfx::Matrix4x4& aTransform,
+                            const gfx::Rect& aVisibleRect) override { }
+
+  virtual void ClearRect(const gfx::Rect& aRect) override { }
+
+  virtual void BeginFrame(const nsIntRegion& aInvalidRegion,
+                          const gfx::IntRect *aClipRectIn,
+                          const gfx::IntRect& aRenderBounds,
+                          const nsIntRegion& aOpaqueRegion,
+                          gfx::IntRect *aClipRectOut = nullptr,
+                          gfx::IntRect *aRenderBoundsOut = nullptr) override { }
+
+  virtual void EndFrame() override { }
+
+  virtual bool SupportsPartialTextureUpdate() override;
+
+  virtual bool CanUseCanvasLayerForSize(const gfx::IntSize &aSize) override
+  {
+    if (!mGLContext)
+      return false;
+    int32_t maxSize = GetMaxTextureSize();
+    return aSize <= gfx::IntSize(maxSize, maxSize);
+  }
+
+  virtual int32_t GetMaxTextureSize() const override;
+
+  virtual void SetDestinationSurfaceSize(const gfx::IntSize& aSize) override { }
+  virtual void SetScreenRenderOffset(const ScreenPoint& aOffset) override { }
+
+  virtual void MakeCurrent(MakeCurrentFlags aFlags = 0) override;
+
+#ifdef MOZ_DUMP_PAINTING
+  virtual const char* Name() const override { return "WROGL"; }
+#endif // MOZ_DUMP_PAINTING
+
+  virtual LayersBackend GetBackendType() const override {
+    return LayersBackend::LAYERS_WR;
+  }
+
+  virtual bool IsValid() const override { return true; }
+
+  virtual void CompositeUntil(TimeStamp aTimeStamp) override;
+
+  GLContext* gl() const { return mGLContext; }
+
+  void AddExternalImageId(uint64_t aExternalImageId, CompositableHost* aHost);
+  void RemoveExternalImageId(uint64_t aExternalImageId);
+  void UpdateExternalImages();
+
+  void ScheduleComposition();
+private:
+  void CleanupResources();
+
+  CompositorBridgeParent* MOZ_NON_OWNING_REF mCompositorBridge;
+  RefPtr<GLContext> mGLContext;
+  // Holds CompositableHosts that are bound to external image ids.
+  nsDataHashtable<nsUint64HashKey, RefPtr<CompositableHost> > mCompositableHosts;
+
+  bool mDestroyed;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif /* MOZILLA_GFX_WEBRENDERCOMPOSITOROGL_H */
new file mode 100644
--- /dev/null
+++ b/gfx/layers/wr/WebRenderContainerLayer.cpp
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "WebRenderContainerLayer.h"
+
+#include <inttypes.h>
+#include "mozilla/layers/WebRenderBridgeChild.h"
+#include "mozilla/webrender/WebRenderTypes.h"
+#include "WebRenderLayersLogging.h"
+
+namespace mozilla {
+namespace layers {
+
+void
+WebRenderContainerLayer::RenderLayer()
+{
+  WrScrollFrameStackingContextGenerator scrollFrames(this);
+
+  nsTArray<LayerPolygon> children = SortChildrenBy3DZOrder(SortMode::WITHOUT_GEOMETRY);
+
+  gfx::Rect relBounds = TransformedVisibleBoundsRelativeToParent();
+  gfx::Rect overflow(0, 0, relBounds.width, relBounds.height);
+  gfx::Matrix4x4 transform;// = GetTransform();
+  WrMixBlendMode mixBlendMode = wr::ToWrMixBlendMode(GetMixBlendMode());
+  Maybe<WrImageMask> mask = buildMaskLayer();
+
+  if (gfxPrefs::LayersDump()) {
+    printf_stderr("ContainerLayer %p using bounds=%s, overflow=%s, transform=%s, mix-blend-mode=%s\n",
+                  this->GetLayer(),
+                  Stringify(relBounds).c_str(),
+                  Stringify(overflow).c_str(),
+                  Stringify(transform).c_str(),
+                  Stringify(mixBlendMode).c_str());
+  }
+
+  WrBridge()->AddWebRenderCommand(
+    OpDPPushStackingContext(wr::ToWrRect(relBounds),
+                            wr::ToWrRect(overflow),
+                            mask,
+                            GetLocalOpacity(),
+                            GetLayer()->GetAnimations(),
+                            transform,
+                            mixBlendMode,
+                            FrameMetrics::NULL_SCROLL_ID));
+  for (LayerPolygon& child : children) {
+    if (child.layer->IsBackfaceHidden()) {
+      continue;
+    }
+    ToWebRenderLayer(child.layer)->RenderLayer();
+  }
+  WrBridge()->AddWebRenderCommand(
+    OpDPPopStackingContext());
+}
+
+void
+WebRenderRefLayer::RenderLayer()
+{
+  WrScrollFrameStackingContextGenerator scrollFrames(this);
+
+  gfx::Rect relBounds = TransformedVisibleBoundsRelativeToParent();
+  gfx::Matrix4x4 transform;// = GetTransform();
+
+  if (gfxPrefs::LayersDump()) {
+    printf_stderr("RefLayer %p (%" PRIu64 ") using bounds/overflow=%s, transform=%s\n",
+                  this->GetLayer(),
+                  mId,
+                  Stringify(relBounds).c_str(),
+                  Stringify(transform).c_str());
+  }
+
+  WrBridge()->AddWebRenderCommand(OpDPPushIframe(wr::ToWrRect(relBounds), wr::ToWrRect(relBounds), wr::PipelineId(mId)));
+}
+
+} // namespace layers
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/layers/wr/WebRenderContainerLayer.h
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef GFX_WEBRENDERCONTAINERLAYER_H
+#define GFX_WEBRENDERCONTAINERLAYER_H
+
+#include "Layers.h"
+#include "WebRenderLayerManager.h"
+
+namespace mozilla {
+namespace layers {
+
+class WebRenderContainerLayer : public WebRenderLayer,
+                                public ContainerLayer
+{
+public:
+  explicit WebRenderContainerLayer(WebRenderLayerManager* aManager)
+    : ContainerLayer(aManager, static_cast<WebRenderLayer*>(this))
+  {
+    MOZ_COUNT_CTOR(WebRenderContainerLayer);
+  }
+
+protected:
+  virtual ~WebRenderContainerLayer()
+  {
+    ContainerLayer::RemoveAllChildren();
+    MOZ_COUNT_DTOR(WebRenderContainerLayer);
+  }
+
+public:
+  Layer* GetLayer() override { return this; }
+  void RenderLayer() override;
+
+  virtual void ComputeEffectiveTransforms(const gfx::Matrix4x4& aTransformToSurface) override
+  {
+    DefaultComputeEffectiveTransforms(aTransformToSurface);
+  }
+};
+
+class WebRenderRefLayer : public WebRenderLayer,
+                          public RefLayer {
+public:
+  explicit WebRenderRefLayer(WebRenderLayerManager* aManager) :
+    RefLayer(aManager, static_cast<WebRenderLayer*>(this))
+  {
+    MOZ_COUNT_CTOR(WebRenderRefLayer);
+  }
+
+protected:
+  virtual ~WebRenderRefLayer()
+  {
+    MOZ_COUNT_DTOR(WebRenderRefLayer);
+  }
+
+public:
+  Layer* GetLayer() override { return this; }
+  void RenderLayer() override;
+
+  virtual void ComputeEffectiveTransforms(const gfx::Matrix4x4& aTransformToSurface) override
+  {
+    DefaultComputeEffectiveTransforms(aTransformToSurface);
+  }
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // GFX_WEBRENDERCONTAINERLAYER_H
new file mode 100644
--- /dev/null
+++ b/gfx/layers/wr/WebRenderImageHost.cpp
@@ -0,0 +1,200 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "WebRenderImageHost.h"
+
+#include "LayersLogging.h"              // for AppendToString
+
+#include "mozilla/layers/Compositor.h"  // for Compositor
+#include "mozilla/layers/Effects.h"     // for TexturedEffect, Effect, etc
+#include "mozilla/layers/LayerManagerComposite.h"     // for TexturedEffect, Effect, etc
+#include "nsAString.h"
+#include "nsDebug.h"                    // for NS_WARNING, NS_ASSERTION
+#include "nsPrintfCString.h"            // for nsPrintfCString
+#include "nsString.h"                   // for nsAutoCString
+
+namespace mozilla {
+
+using namespace gfx;
+
+namespace layers {
+
+class ISurfaceAllocator;
+
+WebRenderImageHost::WebRenderImageHost(const TextureInfo& aTextureInfo)
+  : CompositableHost(aTextureInfo)
+  , ImageComposite()
+{}
+
+WebRenderImageHost::~WebRenderImageHost()
+{
+}
+
+void
+WebRenderImageHost::UseTextureHost(const nsTArray<TimedTexture>& aTextures)
+{
+  CompositableHost::UseTextureHost(aTextures);
+  MOZ_ASSERT(aTextures.Length() >= 1);
+
+  nsTArray<TimedImage> newImages;
+
+  for (uint32_t i = 0; i < aTextures.Length(); ++i) {
+    const TimedTexture& t = aTextures[i];
+    MOZ_ASSERT(t.mTexture);
+    if (i + 1 < aTextures.Length() &&
+        t.mProducerID == mLastProducerID && t.mFrameID < mLastFrameID) {
+      // Ignore frames before a frame that we already composited. We don't
+      // ever want to display these frames. This could be important if
+      // the frame producer adjusts timestamps (e.g. to track the audio clock)
+      // and the new frame times are earlier.
+      continue;
+    }
+    TimedImage& img = *newImages.AppendElement();
+    img.mTextureHost = t.mTexture;
+    img.mTimeStamp = t.mTimeStamp;
+    img.mPictureRect = t.mPictureRect;
+    img.mFrameID = t.mFrameID;
+    img.mProducerID = t.mProducerID;
+    img.mTextureHost->SetCropRect(img.mPictureRect);
+    img.mTextureHost->Updated();
+  }
+
+  mImages.SwapElements(newImages);
+  newImages.Clear();
+}
+
+void
+WebRenderImageHost::CleanupResources()
+{
+}
+
+void
+WebRenderImageHost::RemoveTextureHost(TextureHost* aTexture)
+{
+  CompositableHost::RemoveTextureHost(aTexture);
+
+  for (int32_t i = mImages.Length() - 1; i >= 0; --i) {
+    if (mImages[i].mTextureHost == aTexture) {
+      aTexture->UnbindTextureSource();
+      mImages.RemoveElementAt(i);
+    }
+  }
+}
+
+TimeStamp
+WebRenderImageHost::GetCompositionTime() const
+{
+  // XXX temporary workaround
+  return TimeStamp::Now();
+}
+
+TextureHost*
+WebRenderImageHost::GetAsTextureHost(IntRect* aPictureRect)
+{
+  MOZ_ASSERT_UNREACHABLE("unexpected to be called");
+  return nullptr;
+}
+
+void WebRenderImageHost::Attach(Layer* aLayer,
+                       Compositor* aCompositor,
+                       AttachFlags aFlags)
+{
+  MOZ_ASSERT_UNREACHABLE("unexpected to be called");
+}
+
+void
+WebRenderImageHost::Composite(LayerComposite* aLayer,
+                     EffectChain& aEffectChain,
+                     float aOpacity,
+                     const gfx::Matrix4x4& aTransform,
+                     const gfx::SamplingFilter aSamplingFilter,
+                     const gfx::IntRect& aClipRect,
+                     const nsIntRegion* aVisibleRegion,
+                     const Maybe<gfx::Polygon>& aGeometry)
+{
+  MOZ_ASSERT_UNREACHABLE("unexpected to be called");
+}
+
+void
+WebRenderImageHost::SetCompositor(Compositor* aCompositor)
+{
+  if (mCompositor != aCompositor) {
+    for (auto& img : mImages) {
+      img.mTextureHost->SetCompositor(aCompositor);
+    }
+  }
+  CompositableHost::SetCompositor(aCompositor);
+}
+
+void
+WebRenderImageHost::PrintInfo(std::stringstream& aStream, const char* aPrefix)
+{
+  aStream << aPrefix;
+  aStream << nsPrintfCString("WebRenderImageHost (0x%p)", this).get();
+
+  nsAutoCString pfx(aPrefix);
+  pfx += "  ";
+  for (auto& img : mImages) {
+    aStream << "\n";
+    img.mTextureHost->PrintInfo(aStream, pfx.get());
+    AppendToString(aStream, img.mPictureRect, " [picture-rect=", "]");
+  }
+}
+
+void
+WebRenderImageHost::Dump(std::stringstream& aStream,
+                const char* aPrefix,
+                bool aDumpHtml)
+{
+  for (auto& img : mImages) {
+    aStream << aPrefix;
+    aStream << (aDumpHtml ? "<ul><li>TextureHost: "
+                             : "TextureHost: ");
+    DumpTextureHost(aStream, img.mTextureHost);
+    aStream << (aDumpHtml ? " </li></ul> " : " ");
+  }
+}
+
+LayerRenderState
+WebRenderImageHost::GetRenderState()
+{
+  return LayerRenderState();
+}
+
+already_AddRefed<gfx::DataSourceSurface>
+WebRenderImageHost::GetAsSurface()
+{
+  TimedImage* img = ChooseImage();
+  if (img) {
+    return img->mTextureHost->GetAsSurface();
+  }
+  return nullptr;
+}
+
+bool
+WebRenderImageHost::Lock()
+{
+  MOZ_ASSERT_UNREACHABLE("unexpected to be called");
+  return false;
+}
+
+void
+WebRenderImageHost::Unlock()
+{
+  MOZ_ASSERT_UNREACHABLE("unexpected to be called");
+}
+
+IntSize
+WebRenderImageHost::GetImageSize() const
+{
+  const TimedImage* img = ChooseImage();
+  if (img) {
+    return IntSize(img->mPictureRect.width, img->mPictureRect.height);
+  }
+  return IntSize();
+}
+
+} // namespace layers
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/layers/wr/WebRenderImageHost.h
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef MOZILLA_GFX_WEBRENDERIMAGEHOST_H
+#define MOZILLA_GFX_WEBRENDERIMAGEHOST_H
+
+#include "CompositableHost.h"           // for CompositableHost
+#include "mozilla/layers/ImageComposite.h"  // for ImageComposite
+
+namespace mozilla {
+namespace layers {
+
+/**
+ * ImageHost. Works with ImageClientSingle and ImageClientBuffered
+ */
+class WebRenderImageHost : public CompositableHost,
+                           public ImageComposite
+{
+public:
+  explicit WebRenderImageHost(const TextureInfo& aTextureInfo);
+  ~WebRenderImageHost();
+
+  virtual CompositableType GetType() override { return mTextureInfo.mCompositableType; }
+
+  virtual void Composite(LayerComposite* aLayer,
+                         EffectChain& aEffectChain,
+                         float aOpacity,
+                         const gfx::Matrix4x4& aTransform,
+                         const gfx::SamplingFilter aSamplingFilter,
+                         const gfx::IntRect& aClipRect,
+                         const nsIntRegion* aVisibleRegion = nullptr,
+                         const Maybe<gfx::Polygon>& aGeometry = Nothing()) override;
+
+  virtual void UseTextureHost(const nsTArray<TimedTexture>& aTextures) override;
+
+  virtual void RemoveTextureHost(TextureHost* aTexture) override;
+
+  virtual TextureHost* GetAsTextureHost(gfx::IntRect* aPictureRect = nullptr) override;
+
+  virtual void Attach(Layer* aLayer,
+                      Compositor* aCompositor,
+                      AttachFlags aFlags = NO_FLAGS) override;
+
+  virtual void SetCompositor(Compositor* aCompositor) override;
+
+  gfx::IntSize GetImageSize() const override;
+
+  virtual LayerRenderState GetRenderState() override;
+
+  virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) override;
+
+  virtual void Dump(std::stringstream& aStream,
+                    const char* aPrefix = "",
+                    bool aDumpHtml = false) override;
+
+  virtual already_AddRefed<gfx::DataSourceSurface> GetAsSurface() override;
+
+  virtual bool Lock() override;
+
+  virtual void Unlock() override;
+
+  virtual void CleanupResources() override;
+
+protected:
+  // ImageComposite
+  virtual TimeStamp GetCompositionTime() const override;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // MOZILLA_GFX_WEBRENDERIMAGEHOST_H
new file mode 100644
--- /dev/null
+++ b/gfx/layers/wr/WebRenderImageLayer.cpp
@@ -0,0 +1,175 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "WebRenderImageLayer.h"
+
+#include "WebRenderLayersLogging.h"
+#include "mozilla/layers/ImageClient.h"
+#include "mozilla/layers/TextureClientRecycleAllocator.h"
+#include "mozilla/layers/TextureWrapperImage.h"
+#include "mozilla/layers/WebRenderBridgeChild.h"
+#include "mozilla/webrender/WebRenderTypes.h"
+
+namespace mozilla {
+namespace layers {
+
+using namespace gfx;
+
+WebRenderImageLayer::WebRenderImageLayer(WebRenderLayerManager* aLayerManager)
+  : ImageLayer(aLayerManager, static_cast<WebRenderLayer*>(this))
+  , mExternalImageId(0)
+  , mImageClientTypeContainer(CompositableType::UNKNOWN)
+{
+  MOZ_COUNT_CTOR(WebRenderImageLayer);
+}
+
+WebRenderImageLayer::~WebRenderImageLayer()
+{
+  MOZ_COUNT_DTOR(WebRenderImageLayer);
+  if (mExternalImageId) {
+    WrBridge()->DeallocExternalImageId(mExternalImageId);
+  }
+}
+
+CompositableType
+WebRenderImageLayer::GetImageClientType()
+{
+  if (mImageClientTypeContainer != CompositableType::UNKNOWN) {
+    return mImageClientTypeContainer;
+  }
+
+  if (mContainer->IsAsync()) {
+    mImageClientTypeContainer = CompositableType::IMAGE_BRIDGE;
+    return mImageClientTypeContainer;
+  }
+
+  AutoLockImage autoLock(mContainer);
+
+  mImageClientTypeContainer = autoLock.HasImage()
+    ? CompositableType::IMAGE : CompositableType::UNKNOWN;
+  return mImageClientTypeContainer;
+}
+
+already_AddRefed<gfx::SourceSurface>
+WebRenderImageLayer::GetAsSourceSurface()
+{
+  if (!mContainer) {
+    return nullptr;
+  }
+  AutoLockImage autoLock(mContainer);
+  Image *image = autoLock.GetImage();
+  if (!image) {
+    return nullptr;
+  }
+  RefPtr<gfx::SourceSurface> surface = image->GetAsSourceSurface();
+  if (!surface || !surface->IsValid()) {
+    return nullptr;
+  }
+  return surface.forget();
+}
+
+void
+WebRenderImageLayer::ClearCachedResources()
+{
+  if (mImageClient) {
+    mImageClient->ClearCachedResources();
+  }
+}
+
+void
+WebRenderImageLayer::RenderLayer()
+{
+  if (!mContainer) {
+     return;
+  }
+
+  CompositableType type = GetImageClientType();
+  if (type == CompositableType::UNKNOWN) {
+    return;
+  }
+
+  MOZ_ASSERT(GetImageClientType() != CompositableType::UNKNOWN);
+
+  if (GetImageClientType() == CompositableType::IMAGE && !mImageClient) {
+    mImageClient = ImageClient::CreateImageClient(CompositableType::IMAGE,
+                                                  WrBridge(),
+                                                  TextureFlags::DEFAULT);
+    if (!mImageClient) {
+      return;
+    }
+    mImageClient->Connect();
+  }
+
+  if (!mExternalImageId) {
+    if (GetImageClientType() == CompositableType::IMAGE_BRIDGE) {
+      MOZ_ASSERT(!mImageClient);
+      mExternalImageId = WrBridge()->AllocExternalImageId(mContainer->GetAsyncContainerHandle());
+    } else {
+      // Handle CompositableType::IMAGE case
+      MOZ_ASSERT(mImageClient);
+      mExternalImageId = WrBridge()->AllocExternalImageIdForCompositable(mImageClient);
+    }
+  }
+  MOZ_ASSERT(mExternalImageId);
+
+  // XXX Not good for async ImageContainer case.
+  AutoLockImage autoLock(mContainer);
+  Image* image = autoLock.GetImage();
+  if (!image) {
+    return;
+  }
+  gfx::IntSize size = image->GetSize();
+
+  if (mImageClient && !mImageClient->UpdateImage(mContainer, /* unused */0)) {
+    return;
+  }
+
+  WrScrollFrameStackingContextGenerator scrollFrames(this);
+
+  Rect rect(0, 0, size.width, size.height);
+
+  Rect clip;
+  if (GetClipRect().isSome()) {
+      clip = RelativeToTransformedVisible(IntRectToRect(GetClipRect().ref().ToUnknownRect()));
+  } else {
+      clip = rect;
+  }
+
+  Rect relBounds = TransformedVisibleBoundsRelativeToParent();
+  Rect overflow(0, 0, relBounds.width, relBounds.height);
+  Matrix4x4 transform;// = GetTransform();
+  Maybe<WrImageMask> mask = buildMaskLayer();
+  WrTextureFilter filter = (mSamplingFilter == gfx::SamplingFilter::POINT) ? WrTextureFilter::Point : WrTextureFilter::Linear;
+  WrMixBlendMode mixBlendMode = wr::ToWrMixBlendMode(GetMixBlendMode());
+
+  if (gfxPrefs::LayersDump()) {
+    printf_stderr("ImageLayer %p using bounds=%s, overflow=%s, transform=%s, rect=%s, clip=%s, texture-filter=%s, mix-blend-mode=%s\n",
+                  this->GetLayer(),
+                  Stringify(relBounds).c_str(),
+                  Stringify(overflow).c_str(),
+                  Stringify(transform).c_str(),
+                  Stringify(rect).c_str(),
+                  Stringify(clip).c_str(),
+                  Stringify(filter).c_str(),
+                  Stringify(mixBlendMode).c_str());
+  }
+
+  WrBridge()->AddWebRenderCommand(
+    OpDPPushStackingContext(wr::ToWrRect(relBounds),
+                            wr::ToWrRect(overflow),
+                            mask,
+                            1.0f,
+                            GetAnimations(),
+                            transform,
+                            mixBlendMode,
+                            FrameMetrics::NULL_SCROLL_ID));
+  WrBridge()->AddWebRenderCommand(OpDPPushExternalImageId(LayerIntRegion(), wr::ToWrRect(rect), wr::ToWrRect(clip), Nothing(), filter, mExternalImageId));
+  WrBridge()->AddWebRenderCommand(OpDPPopStackingContext());
+
+  //mContainer->SetImageFactory(originalIF);
+}
+
+} // namespace layers
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/layers/wr/WebRenderImageLayer.h
@@ -0,0 +1,48 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef GFX_WEBRENDERIMAGELAYER_H
+#define GFX_WEBRENDERIMAGELAYER_H
+
+#include "ImageLayers.h"
+#include "WebRenderLayerManager.h"
+
+namespace mozilla {
+namespace layers {
+
+class ImageClient;
+
+class WebRenderImageLayer : public WebRenderLayer,
+                            public ImageLayer {
+public:
+  explicit WebRenderImageLayer(WebRenderLayerManager* aLayerManager);
+
+  virtual already_AddRefed<gfx::SourceSurface> GetAsSourceSurface() override;
+
+  virtual void ClearCachedResources() override;
+protected:
+  virtual ~WebRenderImageLayer();
+
+  WebRenderLayerManager* Manager()
+  {
+    return static_cast<WebRenderLayerManager*>(mManager);
+  }
+
+public:
+  Layer* GetLayer() override { return this; }
+  void RenderLayer() override;
+
+protected:
+  CompositableType GetImageClientType();
+
+  uint64_t mExternalImageId;
+  RefPtr<ImageClient> mImageClient;
+  CompositableType mImageClientTypeContainer;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // GFX_WEBRENDERIMAGELAYER_H
new file mode 100644
--- /dev/null
+++ b/gfx/layers/wr/WebRenderLayerManager.cpp
@@ -0,0 +1,542 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "WebRenderLayerManager.h"
+
+#include "apz/src/AsyncPanZoomController.h"
+#include "WebRenderLayersLogging.h"
+#include "mozilla/dom/TabChild.h"
+#include "mozilla/layers/APZCTreeManager.h"
+#include "mozilla/layers/AsyncCompositionManager.h"
+#include "mozilla/layers/CompositorBridgeChild.h"
+#include "mozilla/layers/TextureClient.h"
+#include "mozilla/layers/WebRenderBridgeChild.h"
+#include "mozilla/widget/PlatformWidgetTypes.h"
+#include "nsThreadUtils.h"
+#include "TreeTraversal.h"
+#include "WebRenderBorderLayer.h"
+#include "WebRenderCanvasLayer.h"
+#include "WebRenderColorLayer.h"
+#include "WebRenderContainerLayer.h"
+#include "WebRenderImageLayer.h"
+#include "WebRenderPaintedLayer.h"
+#include "WebRenderTextLayer.h"
+
+namespace mozilla {
+
+using namespace gfx;
+
+namespace layers {
+
+WebRenderLayerManager*
+WebRenderLayer::WrManager()
+{
+  return static_cast<WebRenderLayerManager*>(GetLayer()->Manager());
+}
+
+WebRenderBridgeChild*
+WebRenderLayer::WrBridge()
+{
+  return WrManager()->WrBridge();
+}
+
+Rect
+WebRenderLayer::RelativeToVisible(Rect aRect)
+{
+  IntRect bounds = GetLayer()->GetVisibleRegion().GetBounds().ToUnknownRect();
+  aRect.MoveBy(-bounds.x, -bounds.y);
+  return aRect;
+}
+
+Rect
+WebRenderLayer::RelativeToTransformedVisible(Rect aRect)
+{
+  IntRect bounds = GetLayer()->GetVisibleRegion().GetBounds().ToUnknownRect();
+  Rect transformed = GetLayer()->GetTransform().TransformBounds(IntRectToRect(bounds));
+  aRect.MoveBy(-transformed.x, -transformed.y);
+  return aRect;
+}
+
+Rect
+WebRenderLayer::ParentStackingContextBounds(size_t aScrollMetadataIndex)
+{
+  // Walk up to find the parent stacking context. This will be created either
+  // by the nearest scrollable metrics, or by the parent layer which must be a
+  // ContainerLayer.
+  Layer* layer = GetLayer();
+  for (size_t i = aScrollMetadataIndex + 1; i < layer->GetScrollMetadataCount(); i++) {
+    if (layer->GetFrameMetrics(i).IsScrollable()) {
+      return layer->GetFrameMetrics(i).GetCompositionBounds().ToUnknownRect();
+    }
+  }
+  if (layer->GetParent()) {
+    return IntRectToRect(layer->GetParent()->GetVisibleRegion().GetBounds().ToUnknownRect());
+  }
+  return Rect();
+}
+
+Rect
+WebRenderLayer::RelativeToParent(Rect aRect)
+{
+  Rect parentBounds = ParentStackingContextBounds(-1);
+  aRect.MoveBy(-parentBounds.x, -parentBounds.y);
+  return aRect;
+}
+
+Rect
+WebRenderLayer::TransformedVisibleBoundsRelativeToParent()
+{
+  IntRect bounds = GetLayer()->GetVisibleRegion().GetBounds().ToUnknownRect();
+  Rect transformed = GetLayer()->GetTransform().TransformBounds(IntRectToRect(bounds));
+  return RelativeToParent(transformed);
+}
+
+Maybe<WrImageMask>
+WebRenderLayer::buildMaskLayer() {
+  Maybe<WrImageMask> mask = Nothing();
+  WrImageMask imageMask;
+  Layer* maskLayer = GetLayer()->GetMaskLayer();
+
+  if (maskLayer) {
+    RefPtr<SourceSurface> surface = WebRenderLayer::ToWebRenderLayer(maskLayer)->GetAsSourceSurface();
+    if (surface) {
+      Matrix transform;
+      Matrix4x4 effectiveTransform = maskLayer->GetEffectiveTransform();
+      DebugOnly<bool> maskIs2D = effectiveTransform.CanDraw2D(&transform);
+      NS_ASSERTION(maskIs2D, "How did we end up with a 3D transform here?!");
+      //XXX: let's assert that the mask transform is the same as the layer transform
+      //transform.PostTranslate(-aDeviceOffset.x, -aDeviceOffset.y);
+      {
+          RefPtr<DataSourceSurface> dataSurface = surface->GetDataSurface();
+          DataSourceSurface::ScopedMap map(dataSurface, DataSourceSurface::MapType::READ);
+          gfx::IntSize size = surface->GetSize();
+          MOZ_RELEASE_ASSERT(surface->GetFormat() == SurfaceFormat::A8, "bad format");
+          wr::ByteBuffer buf(size.height * map.GetStride(), map.GetData());
+          wr::ImageKey maskKey;
+          WrBridge()->SendAddImage(size, map.GetStride(), SurfaceFormat::A8, buf, &maskKey);
+
+          imageMask.image = maskKey.mHandle;
+          imageMask.rect = wr::ToWrRect(Rect(0, 0, size.width, size.height));
+          imageMask.repeat = false;
+          WrManager()->AddImageKeyForDiscard(maskKey);
+          mask = Some(imageMask);
+      }
+    }
+  }
+  return mask;
+}
+
+
+
+
+WrScrollFrameStackingContextGenerator::WrScrollFrameStackingContextGenerator(
+        WebRenderLayer* aLayer)
+  : mLayer(aLayer)
+{
+  Matrix4x4 identity;
+  Layer* layer = mLayer->GetLayer();
+  for (size_t i = layer->GetScrollMetadataCount(); i > 0; i--) {
+    const FrameMetrics& fm = layer->GetFrameMetrics(i - 1);
+    if (!fm.IsScrollable()) {
+      continue;
+    }
+    Rect bounds = fm.GetCompositionBounds().ToUnknownRect();
+    Rect overflow = (fm.GetExpandedScrollableRect() * fm.LayersPixelsPerCSSPixel()).ToUnknownRect();
+    Point scrollPos = (fm.GetScrollOffset() * fm.LayersPixelsPerCSSPixel()).ToUnknownPoint();
+    Rect parentBounds = mLayer->ParentStackingContextBounds(i);
+    bounds.MoveBy(-parentBounds.x, -parentBounds.y);
+    // Subtract the MT scroll position from the overflow here so that the WR
+    // scroll offset (which is the APZ async scroll component) always fits in
+    // the available overflow. If we didn't do this and WR did bounds checking
+    // on the scroll offset, we'd fail those checks.
+    overflow.MoveBy(bounds.x - scrollPos.x, bounds.y - scrollPos.y);
+    if (gfxPrefs::LayersDump()) {
+      printf_stderr("Pushing stacking context id %" PRIu64 " with bounds=%s, overflow=%s\n",
+        fm.GetScrollId(), Stringify(bounds).c_str(), Stringify(overflow).c_str());
+    }
+
+    mLayer->WrBridge()->AddWebRenderCommand(
+      OpDPPushStackingContext(wr::ToWrRect(bounds),
+                              wr::ToWrRect(overflow),
+                              Nothing(),
+                              1.0f,
+                              layer->GetAnimations(),
+                              identity,
+                              WrMixBlendMode::Normal,
+                              fm.GetScrollId()));
+  }
+}
+
+WrScrollFrameStackingContextGenerator::~WrScrollFrameStackingContextGenerator()
+{
+  Layer* layer = mLayer->GetLayer();
+  for (size_t i = 0; i < layer->GetScrollMetadataCount(); i++) {
+    const FrameMetrics& fm = layer->GetFrameMetrics(i);
+    if (!fm.IsScrollable()) {
+      continue;
+    }
+    if (gfxPrefs::LayersDump()) printf_stderr("Popping stacking context id %" PRIu64"\n", fm.GetScrollId());
+    mLayer->WrBridge()->AddWebRenderCommand(OpDPPopStackingContext());
+  }
+}
+
+
+WebRenderLayerManager::WebRenderLayerManager(nsIWidget* aWidget)
+  : mWidget(aWidget)
+  , mLatestTransactionId(0)
+  , mTarget(nullptr)
+{
+  MOZ_COUNT_CTOR(WebRenderLayerManager);
+}
+
+KnowsCompositor*
+WebRenderLayerManager::AsKnowsCompositor()
+{
+  return mWrChild;
+}
+
+void
+WebRenderLayerManager::Initialize(PCompositorBridgeChild* aCBChild,
+                                  uint64_t aLayersId,
+                                  TextureFactoryIdentifier* aTextureFactoryIdentifier)
+{
+  MOZ_ASSERT(mWrChild == nullptr);
+  MOZ_ASSERT(aTextureFactoryIdentifier);
+
+  TextureFactoryIdentifier textureFactoryIdentifier;
+  PWebRenderBridgeChild* bridge = aCBChild->SendPWebRenderBridgeConstructor(wr::PipelineId(aLayersId),
+                                                                            &textureFactoryIdentifier);
+  MOZ_ASSERT(bridge);
+  mWrChild = static_cast<WebRenderBridgeChild*>(bridge);
+  LayoutDeviceIntSize size = mWidget->GetClientSize();
+  WrBridge()->SendCreate(size.ToUnknownSize());
+  WrBridge()->IdentifyTextureHost(textureFactoryIdentifier);
+  *aTextureFactoryIdentifier = textureFactoryIdentifier;
+}
+
+void
+WebRenderLayerManager::Destroy()
+{
+  if (IsDestroyed()) {
+    return;
+  }
+
+  LayerManager::Destroy();
+  DiscardImages();
+  WrBridge()->Destroy();
+
+  if (mTransactionIdAllocator) {
+    // Make sure to notify the refresh driver just in case it's waiting on a
+    // pending transaction. Do this at the top of the event loop so we don't
+    // cause a paint to occur during compositor shutdown.
+    RefPtr<TransactionIdAllocator> allocator = mTransactionIdAllocator;
+    uint64_t id = mLatestTransactionId;
+
+    RefPtr<Runnable> task = NS_NewRunnableFunction([allocator, id] () -> void {
+      allocator->NotifyTransactionCompleted(id);
+    });
+    NS_DispatchToMainThread(task.forget());
+  }
+}
+
+WebRenderLayerManager::~WebRenderLayerManager()
+{
+  Destroy();
+  MOZ_COUNT_DTOR(WebRenderLayerManager);
+}
+
+CompositorBridgeChild*
+WebRenderLayerManager::GetCompositorBridgeChild()
+{
+  return mWidget ? mWidget->GetRemoteRenderer() : nullptr;
+}
+
+int32_t
+WebRenderLayerManager::GetMaxTextureSize() const
+{
+  return WrBridge()->GetMaxTextureSize();
+}
+
+bool
+WebRenderLayerManager::BeginTransactionWithTarget(gfxContext* aTarget)
+{
+  mTarget = aTarget;
+  return BeginTransaction();
+}
+
+bool
+WebRenderLayerManager::BeginTransaction()
+{
+  return true;
+}
+
+bool
+WebRenderLayerManager::EndEmptyTransaction(EndTransactionFlags aFlags)
+{
+  return false;
+}
+
+void
+WebRenderLayerManager::EndTransaction(DrawPaintedLayerCallback aCallback,
+                                      void* aCallbackData,
+                                      EndTransactionFlags aFlags)
+{
+  DiscardImages();
+
+  mPaintedLayerCallback = aCallback;
+  mPaintedLayerCallbackData = aCallbackData;
+
+  if (gfxPrefs::LayersDump()) {
+    this->Dump();
+  }
+
+  // Since we don't do repeat transactions right now, just set the time
+  mAnimationReadyTime = TimeStamp::Now();
+
+  LayoutDeviceIntSize size = mWidget->GetClientSize();
+  if (!WrBridge()->DPBegin(size.ToUnknownSize())) {
+    return;
+  }
+
+  WebRenderLayer::ToWebRenderLayer(mRoot)->RenderLayer();
+
+  bool sync = mTarget != nullptr;
+  mLatestTransactionId = mTransactionIdAllocator->GetTransactionId();
+
+  WrBridge()->DPEnd(sync, mLatestTransactionId);
+
+  MakeSnapshotIfRequired(size);
+
+  // this may result in Layers being deleted, which results in
+  // PLayer::Send__delete__() and DeallocShmem()
+  mKeepAlive.Clear();
+}
+
+void
+WebRenderLayerManager::MakeSnapshotIfRequired(LayoutDeviceIntSize aSize)
+{
+  if (!mTarget || aSize.IsEmpty()) {
+    return;
+  }
+
+  // XXX Add other TextureData supports.
+  // Only BufferTexture is supported now.
+
+  // TODO: fixup for proper surface format.
+  RefPtr<TextureClient> texture =
+    TextureClient::CreateForRawBufferAccess(WrBridge(),
+                                            SurfaceFormat::B8G8R8A8,
+                                            aSize.ToUnknownSize(),
+                                            BackendType::SKIA,
+                                            TextureFlags::DEFAULT);
+  if (!texture) {
+    return;
+  }
+
+  texture->InitIPDLActor(WrBridge());
+  if (!texture->GetIPDLActor()) {
+    return;
+  }
+
+  IntRect bounds = ToOutsideIntRect(mTarget->GetClipExtents());
+  if (!WrBridge()->SendDPGetSnapshot(texture->GetIPDLActor())) {
+    return;
+  }
+
+  TextureClientAutoLock autoLock(texture, OpenMode::OPEN_READ_ONLY);
+  if (!autoLock.Succeeded()) {
+    return;
+  }
+  RefPtr<DrawTarget> drawTarget = texture->BorrowDrawTarget();
+  if (!drawTarget || !drawTarget->IsValid()) {
+    return;
+  }
+  RefPtr<SourceSurface> snapshot = drawTarget->Snapshot();
+/*
+  static int count = 0;
+  char filename[100];
+  snprintf(filename, 100, "output%d.png", count++);
+  printf_stderr("Writing to :%s\n", filename);
+  gfxUtils::WriteAsPNG(snapshot, filename);
+  */
+
+  Rect dst(bounds.x, bounds.y, bounds.width, bounds.height);
+  Rect src(0, 0, bounds.width, bounds.height);
+
+  // The data we get from webrender is upside down. So flip and translate up so the image is rightside up.
+  // Webrender always does a full screen readback.
+  SurfacePattern pattern(snapshot, ExtendMode::CLAMP,
+                         Matrix::Scaling(1.0, -1.0).PostTranslate(0.0, aSize.height));
+  DrawTarget* dt = mTarget->GetDrawTarget();
+  MOZ_RELEASE_ASSERT(dt);
+  dt->FillRect(dst, pattern);
+
+  mTarget = nullptr;
+}
+
+void
+WebRenderLayerManager::AddImageKeyForDiscard(wr::ImageKey key)
+{
+  mImageKeys.push_back(key);
+}
+
+void
+WebRenderLayerManager::DiscardImages()
+{
+  for (auto key : mImageKeys) {
+      WrBridge()->SendDeleteImage(key);
+  }
+  mImageKeys.clear();
+}
+
+void
+WebRenderLayerManager::Hold(Layer* aLayer)
+{
+  mKeepAlive.AppendElement(aLayer);
+}
+
+void
+WebRenderLayerManager::SetLayerObserverEpoch(uint64_t aLayerObserverEpoch)
+{
+  WrBridge()->SendSetLayerObserverEpoch(aLayerObserverEpoch);
+}
+
+void
+WebRenderLayerManager::DidComposite(uint64_t aTransactionId,
+                                    const mozilla::TimeStamp& aCompositeStart,
+                                    const mozilla::TimeStamp& aCompositeEnd)
+{
+  MOZ_ASSERT(mWidget);
+
+  // |aTransactionId| will be > 0 if the compositor is acknowledging a shadow
+  // layers transaction.
+  if (aTransactionId) {
+    nsIWidgetListener *listener = mWidget->GetWidgetListener();
+    if (listener) {
+      listener->DidCompositeWindow(aTransactionId, aCompositeStart, aCompositeEnd);
+    }
+    listener = mWidget->GetAttachedWidgetListener();
+    if (listener) {
+      listener->DidCompositeWindow(aTransactionId, aCompositeStart, aCompositeEnd);
+    }
+    mTransactionIdAllocator->NotifyTransactionCompleted(aTransactionId);
+  }
+
+  // These observers fire whether or not we were in a transaction.
+  for (size_t i = 0; i < mDidCompositeObservers.Length(); i++) {
+    mDidCompositeObservers[i]->DidComposite();
+  }
+}
+
+void
+WebRenderLayerManager::ClearLayer(Layer* aLayer)
+{
+  aLayer->ClearCachedResources();
+  for (Layer* child = aLayer->GetFirstChild(); child;
+       child = child->GetNextSibling()) {
+    ClearLayer(child);
+  }
+}
+
+void
+WebRenderLayerManager::ClearCachedResources(Layer* aSubtree)
+{
+  WrBridge()->SendClearCachedResources();
+  if (aSubtree) {
+    ClearLayer(aSubtree);
+  } else if (mRoot) {
+    ClearLayer(mRoot);
+  }
+}
+
+void
+WebRenderLayerManager::UpdateTextureFactoryIdentifier(const TextureFactoryIdentifier& aNewIdentifier,
+                                                      uint64_t aDeviceResetSeqNo)
+{
+  WrBridge()->IdentifyTextureHost(aNewIdentifier);
+}
+
+TextureFactoryIdentifier
+WebRenderLayerManager::GetTextureFactoryIdentifier()
+{
+  return WrBridge()->GetTextureFactoryIdentifier();
+}
+
+void
+WebRenderLayerManager::AddDidCompositeObserver(DidCompositeObserver* aObserver)
+{
+  if (!mDidCompositeObservers.Contains(aObserver)) {
+    mDidCompositeObservers.AppendElement(aObserver);
+  }
+}
+
+void
+WebRenderLayerManager::RemoveDidCompositeObserver(DidCompositeObserver* aObserver)
+{
+  mDidCompositeObservers.RemoveElement(aObserver);
+}
+
+void
+WebRenderLayerManager::SetRoot(Layer* aLayer)
+{
+  mRoot = aLayer;
+}
+
+already_AddRefed<PaintedLayer>
+WebRenderLayerManager::CreatePaintedLayer()
+{
+  return MakeAndAddRef<WebRenderPaintedLayer>(this);
+}
+
+already_AddRefed<ContainerLayer>
+WebRenderLayerManager::CreateContainerLayer()
+{
+  return MakeAndAddRef<WebRenderContainerLayer>(this);
+}
+
+already_AddRefed<ImageLayer>
+WebRenderLayerManager::CreateImageLayer()
+{
+  return MakeAndAddRef<WebRenderImageLayer>(this);
+}
+
+already_AddRefed<CanvasLayer>
+WebRenderLayerManager::CreateCanvasLayer()
+{
+  return MakeAndAddRef<WebRenderCanvasLayer>(this);
+}
+
+already_AddRefed<ReadbackLayer>
+WebRenderLayerManager::CreateReadbackLayer()
+{
+  return nullptr;
+}
+
+already_AddRefed<ColorLayer>
+WebRenderLayerManager::CreateColorLayer()
+{
+  return MakeAndAddRef<WebRenderColorLayer>(this);
+}
+
+already_AddRefed<RefLayer>
+WebRenderLayerManager::CreateRefLayer()
+{
+  return MakeAndAddRef<WebRenderRefLayer>(this);
+}
+
+already_AddRefed<TextLayer>
+WebRenderLayerManager::CreateTextLayer()
+{
+  return MakeAndAddRef<WebRenderTextLayer>(this);
+}
+
+already_AddRefed<BorderLayer>
+WebRenderLayerManager::CreateBorderLayer()
+{
+  return MakeAndAddRef<WebRenderBorderLayer>(this);
+}
+
+} // namespace layers
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/layers/wr/WebRenderLayerManager.h
@@ -0,0 +1,179 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef GFX_WEBRENDERLAYERMANAGER_H
+#define GFX_WEBRENDERLAYERMANAGER_H
+
+#include "Layers.h"
+#include "mozilla/layers/CompositorController.h"
+#include "mozilla/layers/TransactionIdAllocator.h"
+#include "mozilla/webrender/webrender_ffi.h"
+#include "mozilla/webrender/WebRenderTypes.h"
+
+class nsIWidget;
+
+namespace mozilla {
+namespace layers {
+
+class CompositorBridgeChild;
+class KnowsCompositor;
+class PCompositorBridgeChild;
+class WebRenderBridgeChild;
+class WebRenderLayerManager;
+class APZCTreeManager;
+
+class WebRenderLayer
+{
+public:
+  virtual Layer* GetLayer() = 0;
+  virtual void RenderLayer() = 0;
+
+  virtual already_AddRefed<gfx::SourceSurface> GetAsSourceSurface() { return nullptr; }
+  static inline WebRenderLayer*
+  ToWebRenderLayer(Layer* aLayer)
+  {
+    return static_cast<WebRenderLayer*>(aLayer->ImplData());
+  }
+
+  WebRenderLayerManager* WrManager();
+  WebRenderBridgeChild* WrBridge();
+
+  gfx::Rect RelativeToVisible(gfx::Rect aRect);
+  gfx::Rect RelativeToTransformedVisible(gfx::Rect aRect);
+  gfx::Rect ParentStackingContextBounds(size_t aScrollMetadataIndex);
+  gfx::Rect RelativeToParent(gfx::Rect aRect);
+  gfx::Rect TransformedVisibleBoundsRelativeToParent();
+protected:
+  Maybe<WrImageMask> buildMaskLayer();
+
+};
+
+class MOZ_RAII WrScrollFrameStackingContextGenerator
+{
+public:
+  explicit WrScrollFrameStackingContextGenerator(WebRenderLayer* aLayer);
+  ~WrScrollFrameStackingContextGenerator();
+private:
+  WebRenderLayer* mLayer;
+};
+
+class WebRenderLayerManager final : public LayerManager
+{
+  typedef nsTArray<RefPtr<Layer> > LayerRefArray;
+
+public:
+  explicit WebRenderLayerManager(nsIWidget* aWidget);
+  void Initialize(PCompositorBridgeChild* aCBChild, uint64_t aLayersId, TextureFactoryIdentifier* aTextureFactoryIdentifier);
+
+  virtual void Destroy() override;
+
+protected:
+  virtual ~WebRenderLayerManager();
+
+public:
+  virtual KnowsCompositor* AsKnowsCompositor() override;
+  WebRenderLayerManager* AsWebRenderLayerManager() override { return this; }
+  virtual CompositorBridgeChild* GetCompositorBridgeChild() override;
+
+  virtual int32_t GetMaxTextureSize() const override;
+
+  virtual bool BeginTransactionWithTarget(gfxContext* aTarget) override;
+  virtual bool BeginTransaction() override;
+  virtual bool EndEmptyTransaction(EndTransactionFlags aFlags = END_DEFAULT) override;
+  virtual void EndTransaction(DrawPaintedLayerCallback aCallback,
+                              void* aCallbackData,
+                              EndTransactionFlags aFlags = END_DEFAULT) override;
+
+  virtual LayersBackend GetBackendType() override { return LayersBackend::LAYERS_WR; }
+  virtual void GetBackendName(nsAString& name) override { name.AssignLiteral("WebRender"); }
+  virtual const char* Name() const override { return "WebRender"; }
+
+  virtual void SetRoot(Layer* aLayer) override;
+
+  virtual already_AddRefed<PaintedLayer> CreatePaintedLayer() override;
+  virtual already_AddRefed<ContainerLayer> CreateContainerLayer() override;
+  virtual already_AddRefed<ImageLayer> CreateImageLayer() override;
+  virtual already_AddRefed<CanvasLayer> CreateCanvasLayer() override;
+  virtual already_AddRefed<ReadbackLayer> CreateReadbackLayer() override;
+  virtual already_AddRefed<ColorLayer> CreateColorLayer() override;
+  virtual already_AddRefed<RefLayer> CreateRefLayer() override;
+  virtual already_AddRefed<TextLayer> CreateTextLayer() override;
+  virtual already_AddRefed<BorderLayer> CreateBorderLayer() override;
+
+  virtual bool NeedsWidgetInvalidation() override { return true; }
+
+  virtual void SetLayerObserverEpoch(uint64_t aLayerObserverEpoch) override;
+
+  virtual void DidComposite(uint64_t aTransactionId,
+                            const mozilla::TimeStamp& aCompositeStart,
+                            const mozilla::TimeStamp& aCompositeEnd) override;
+
+  virtual void ClearCachedResources(Layer* aSubtree = nullptr) override;
+  virtual void UpdateTextureFactoryIdentifier(const TextureFactoryIdentifier& aNewIdentifier,
+                                              uint64_t aDeviceResetSeqNo) override;
+  virtual TextureFactoryIdentifier GetTextureFactoryIdentifier() override;
+
+  virtual void SetTransactionIdAllocator(TransactionIdAllocator* aAllocator) override
+  { mTransactionIdAllocator = aAllocator; }
+
+  virtual void AddDidCompositeObserver(DidCompositeObserver* aObserver) override;
+  virtual void RemoveDidCompositeObserver(DidCompositeObserver* aObserver) override;
+
+  DrawPaintedLayerCallback GetPaintedLayerCallback() const
+  { return mPaintedLayerCallback; }
+
+  void* GetPaintedLayerCallbackData() const
+  { return mPaintedLayerCallbackData; }
+
+  // adds an imagekey to a list of keys that will be discarded on the next
+  // transaction or destruction
+  void AddImageKeyForDiscard(wr::ImageKey);
+  void DiscardImages();
+
+  WebRenderBridgeChild* WrBridge() const { return mWrChild; }
+
+  void Hold(Layer* aLayer);
+
+private:
+  /**
+   * Take a snapshot of the parent context, and copy
+   * it into mTarget.
+   */
+  void MakeSnapshotIfRequired(LayoutDeviceIntSize aSize);
+
+  void ClearLayer(Layer* aLayer);
+
+private:
+  nsIWidget* MOZ_NON_OWNING_REF mWidget;
+  std::vector<wr::ImageKey> mImageKeys;
+
+  /* PaintedLayer callbacks; valid at the end of a transaciton,
+   * while rendering */
+  DrawPaintedLayerCallback mPaintedLayerCallback;
+  void *mPaintedLayerCallbackData;
+
+  RefPtr<WebRenderBridgeChild> mWrChild;
+
+  RefPtr<TransactionIdAllocator> mTransactionIdAllocator;
+  uint64_t mLatestTransactionId;
+
+  nsTArray<DidCompositeObserver*> mDidCompositeObservers;
+
+  LayerRefArray mKeepAlive;
+
+ // When we're doing a transaction in order to draw to a non-default
+ // target, the layers transaction is only performed in order to send
+ // a PLayers:Update.  We save the original non-default target to
+ // mTarget, and then perform the transaction. After the transaction ends,
+ // we send a message to our remote side to capture the actual pixels
+ // being drawn to the default target, and then copy those pixels
+ // back to mTarget.
+ RefPtr<gfxContext> mTarget;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif /* GFX_WEBRENDERLAYERMANAGER_H */
new file mode 100644
--- /dev/null
+++ b/gfx/layers/wr/WebRenderLayersLogging.cpp
@@ -0,0 +1,78 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: sw=2 ts=8 et :
+ */
+/* 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 "WebRenderLayersLogging.h"
+
+using namespace mozilla::gfx;
+
+namespace mozilla {
+namespace layers {
+
+void
+AppendToString(std::stringstream& aStream, WrMixBlendMode aMixBlendMode,
+               const char* pfx, const char* sfx)
+{
+  aStream << pfx;
+  switch (aMixBlendMode) {
+  case WrMixBlendMode::Normal:
+    aStream << "WrMixBlendMode::Normal"; break;
+  case WrMixBlendMode::Multiply:
+    aStream << "WrMixBlendMode::Multiply"; break;
+  case WrMixBlendMode::Screen:
+    aStream << "WrMixBlendMode::Screen"; break;
+  case WrMixBlendMode::Overlay:
+    aStream << "WrMixBlendMode::Overlay"; break;
+  case WrMixBlendMode::Darken:
+    aStream << "WrMixBlendMode::Darken"; break;
+  case WrMixBlendMode::Lighten:
+    aStream << "WrMixBlendMode::Lighten"; break;
+  case WrMixBlendMode::ColorDodge:
+    aStream << "WrMixBlendMode::ColorDodge"; break;
+  case WrMixBlendMode::ColorBurn:
+    aStream << "WrMixBlendMode::ColorBurn"; break;
+  case WrMixBlendMode::HardLight:
+    aStream << "WrMixBlendMode::HardLight"; break;
+  case WrMixBlendMode::SoftLight:
+    aStream << "WrMixBlendMode::SoftLight"; break;
+  case WrMixBlendMode::Difference:
+    aStream << "WrMixBlendMode::Difference"; break;
+  case WrMixBlendMode::Exclusion:
+    aStream << "WrMixBlendMode::Exclusion"; break;
+  case WrMixBlendMode::Hue:
+    aStream << "WrMixBlendMode::Hue"; break;
+  case WrMixBlendMode::Saturation:
+    aStream << "WrMixBlendMode::Saturation"; break;
+  case WrMixBlendMode::Color:
+    aStream << "WrMixBlendMode::Color"; break;
+  case WrMixBlendMode::Luminosity:
+    aStream << "WrMixBlendMode::Luminosity"; break;
+  case WrMixBlendMode::Sentinel:
+    NS_ERROR("unknown mix blend mode");
+    aStream << "???";
+  }
+  aStream << sfx;
+}
+
+void
+AppendToString(std::stringstream& aStream, WrTextureFilter aTextureFilter,
+               const char* pfx, const char* sfx)
+{
+  aStream << pfx;
+  switch (aTextureFilter) {
+  case WrTextureFilter::Linear:
+    aStream << "WrTextureFilter::Linear"; break;
+  case WrTextureFilter::Point:
+    aStream << "WrTextureFilter::Point"; break;
+  case WrTextureFilter::Sentinel:
+    NS_ERROR("unknown texture filter");
+    aStream << "???";
+  }
+  aStream << sfx;
+}
+
+} // namespace layers
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/layers/wr/WebRenderLayersLogging.h
@@ -0,0 +1,29 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+
+#ifndef GFX_WEBRENDERLAYERSLOGGING_H
+#define GFX_WEBRENDERLAYERSLOGGING_H
+
+#include "mozilla/webrender/WebRenderTypes.h"
+
+namespace mozilla {
+namespace layers {
+
+void
+AppendToString(std::stringstream& aStream, WrMixBlendMode aMixBlendMode,
+               const char* pfx="", const char* sfx="");
+
+void
+AppendToString(std::stringstream& aStream, WrTextureFilter aTextureFilter,
+               const char* pfx="", const char* sfx="");
+
+} // namespace layers
+} // namespace mozilla
+
+// this ensures that the WebRender AppendToString's are in scope for Stringify
+#include "LayersLogging.h"
+
+#endif // GFX_WEBRENDERLAYERSLOGGING_H
new file mode 100644
--- /dev/null
+++ b/gfx/layers/wr/WebRenderMessageUtils.h
@@ -0,0 +1,308 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef GFX_WEBRENDERMESSAGEUTILS_H
+#define GFX_WEBRENDERMESSAGEUTILS_H
+
+#include "chrome/common/ipc_message_utils.h"
+
+#include "mozilla/webrender/webrender_ffi.h"
+#include "mozilla/webrender/WebRenderTypes.h"
+
+namespace IPC {
+
+template<>
+struct ParamTraits<mozilla::wr::ByteBuffer>
+{
+  typedef mozilla::wr::ByteBuffer paramType;
+
+  static void
+  Write(Message* aMsg, const paramType& aParam)
+  {
+    WriteParam(aMsg, aParam.mLength);
+    aMsg->WriteBytes(aParam.mData, aParam.mLength);
+  }
+
+  static bool
+  Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
+  {
+    size_t length;
+    return ReadParam(aMsg, aIter, &length)
+        && aResult->Allocate(length)
+        && aMsg->ReadBytesInto(aIter, aResult->mData, length);
+  }
+};
+
+template<>
+struct ParamTraits<mozilla::wr::ImageKey>
+{
+  static void
+  Write(Message* aMsg, const mozilla::wr::ImageKey& aParam)
+  {
+    WriteParam(aMsg, aParam.mHandle);
+  }
+
+  static bool
+  Read(const Message* aMsg, PickleIterator* aIter, mozilla::wr::ImageKey* aResult)
+  {
+    return ReadParam(aMsg, aIter, &aResult->mHandle);
+  }
+};
+
+template<>
+struct ParamTraits<mozilla::wr::FontKey>
+{
+  static void
+  Write(Message* aMsg, const mozilla::wr::FontKey& aParam)
+  {
+    WriteParam(aMsg, aParam.mHandle);
+  }
+
+  static bool
+  Read(const Message* aMsg, PickleIterator* aIter, mozilla::wr::FontKey* aResult)
+  {
+    return ReadParam(aMsg, aIter, &aResult->mHandle);
+  }
+};
+
+template<>
+struct ParamTraits<mozilla::wr::PipelineId>
+{
+  static void
+  Write(Message* aMsg, const mozilla::wr::PipelineId& aParam)
+  {
+    WriteParam(aMsg, aParam.mHandle);
+  }
+
+  static bool
+  Read(const Message* aMsg, PickleIterator* aIter, mozilla::wr::PipelineId* aResult)
+  {
+    return ReadParam(aMsg, aIter, &aResult->mHandle);
+  }
+};
+
+template<>
+struct ParamTraits<WrImageFormat>
+  : public ContiguousEnumSerializer<
+        WrImageFormat,
+        WrImageFormat::Invalid,
+        WrImageFormat::Sentinel>
+{
+};
+
+template<>
+struct ParamTraits<WrBorderStyle>
+  : public ContiguousEnumSerializer<
+        WrBorderStyle,
+        WrBorderStyle::None,
+        WrBorderStyle::Sentinel>
+{
+};
+
+template<>
+struct ParamTraits<WrColor>
+{
+  static void
+  Write(Message* aMsg, const WrColor& aParam)
+  {
+    WriteParam(aMsg, aParam.r);
+    WriteParam(aMsg, aParam.g);
+    WriteParam(aMsg, aParam.b);
+    WriteParam(aMsg, aParam.a);
+  }
+
+  static bool
+  Read(const Message* aMsg, PickleIterator* aIter, WrColor* aResult)
+  {
+    return ReadParam(aMsg, aIter, &aResult->r)
+        && ReadParam(aMsg, aIter, &aResult->g)
+        && ReadParam(aMsg, aIter, &aResult->b)
+        && ReadParam(aMsg, aIter, &aResult->a);
+  }
+};
+
+template<>
+struct ParamTraits<WrGlyphInstance>
+{
+  static void
+  Write(Message* aMsg, const WrGlyphInstance& aParam)
+  {
+    WriteParam(aMsg, aParam.index);
+    WriteParam(aMsg, aParam.x);
+    WriteParam(aMsg, aParam.y);
+  }
+
+  static bool
+  Read(const Message* aMsg, PickleIterator* aIter, WrGlyphInstance* aResult)
+  {
+    return ReadParam(aMsg, aIter, &aResult->index)
+        && ReadParam(aMsg, aIter, &aResult->x)
+        && ReadParam(aMsg, aIter, &aResult->y);
+  }
+};
+
+template<>
+struct ParamTraits<WrGlyphArray>
+{
+  static void
+  Write(Message* aMsg, const WrGlyphArray& aParam)
+  {
+    WriteParam(aMsg, aParam.color);
+    size_t length = aParam.glyphs.Length();
+
+    WriteParam(aMsg, length);
+
+    for (size_t i = 0; i < length; i++) {
+      WriteParam(aMsg, aParam.glyphs[i]);
+    }
+  }
+
+  static bool
+  Read(const Message* aMsg, PickleIterator* aIter, WrGlyphArray* aResult)
+  {
+    if (!ReadParam(aMsg, aIter, &aResult->color)) {
+      return false;
+    }
+
+    size_t length;
+    if (!ReadParam(aMsg, aIter, &length)) {
+      return false;
+    }
+
+    aResult->glyphs.SetLength(length);
+
+    for (size_t i = 0; i < length; i++) {
+      if (!ReadParam(aMsg, aIter, &aResult->glyphs[i])) {
+        return false;
+      }
+    }
+
+    return true;
+  }
+};
+
+template<>
+struct ParamTraits<WrBorderSide>
+{
+  static void
+  Write(Message* aMsg, const WrBorderSide& aParam)
+  {
+    WriteParam(aMsg, aParam.width);
+    WriteParam(aMsg, aParam.color);
+    WriteParam(aMsg, aParam.style);
+  }
+
+  static bool
+  Read(const Message* aMsg, PickleIterator* aIter, WrBorderSide* aResult)
+  {
+    return ReadParam(aMsg, aIter, &aResult->width)
+        && ReadParam(aMsg, aIter, &aResult->color)
+        && ReadParam(aMsg, aIter, &aResult->style);
+  }
+};
+
+template<>
+struct ParamTraits<WrLayoutSize>
+{
+  static void
+  Write(Message* aMsg, const WrLayoutSize& aParam)
+  {
+    WriteParam(aMsg, aParam.width);
+    WriteParam(aMsg, aParam.height);
+  }
+
+  static bool
+  Read(const Message* aMsg, PickleIterator* aIter, WrLayoutSize* aResult)
+  {
+    return ReadParam(aMsg, aIter, &aResult->width)
+        && ReadParam(aMsg, aIter, &aResult->height);
+  }
+};
+
+template<>
+struct ParamTraits<WrBorderRadius>
+{
+  static void
+  Write(Message* aMsg, const WrBorderRadius& aParam)
+  {
+    WriteParam(aMsg, aParam.top_left);
+    WriteParam(aMsg, aParam.top_right);
+    WriteParam(aMsg, aParam.bottom_left);
+    WriteParam(aMsg, aParam.bottom_right);
+  }
+
+  static bool
+  Read(const Message* aMsg, PickleIterator* aIter, WrBorderRadius* aResult)
+  {
+    return ReadParam(aMsg, aIter, &aResult->top_left)
+        && ReadParam(aMsg, aIter, &aResult->top_right)
+        && ReadParam(aMsg, aIter, &aResult->bottom_left)
+        && ReadParam(aMsg, aIter, &aResult->bottom_right);
+  }
+};
+
+template<>
+struct ParamTraits<WrRect>
+{
+  static void
+  Write(Message* aMsg, const WrRect& aParam)
+  {
+    WriteParam(aMsg, aParam.x);
+    WriteParam(aMsg, aParam.y);
+    WriteParam(aMsg, aParam.width);
+    WriteParam(aMsg, aParam.height);
+  }
+
+  static bool
+  Read(const Message* aMsg, PickleIterator* aIter, WrRect* aResult)
+  {
+    return ReadParam(aMsg, aIter, &aResult->x)
+        && ReadParam(aMsg, aIter, &aResult->y)
+        && ReadParam(aMsg, aIter, &aResult->width)
+        && ReadParam(aMsg, aIter, &aResult->height);
+  }
+};
+
+template<>
+struct ParamTraits<WrImageMask>
+{
+  static void
+  Write(Message* aMsg, const WrImageMask& aParam)
+  {
+    WriteParam(aMsg, aParam.image);
+    WriteParam(aMsg, aParam.rect);
+    WriteParam(aMsg, aParam.repeat);
+  }
+
+  static bool
+  Read(const Message* aMsg, PickleIterator* aIter, WrImageMask* aResult)
+  {
+    return ReadParam(aMsg, aIter, &aResult->image)
+        && ReadParam(aMsg, aIter, &aResult->rect)
+        && ReadParam(aMsg, aIter, &aResult->repeat);
+  }
+};
+
+template<>
+struct ParamTraits<WrTextureFilter>
+  : public ContiguousEnumSerializer<
+        WrTextureFilter,
+        WrTextureFilter::Linear,
+        WrTextureFilter::Sentinel>
+{
+};
+
+template<>
+struct ParamTraits<WrMixBlendMode>
+  : public ContiguousEnumSerializer<
+        WrMixBlendMode,
+        WrMixBlendMode::Normal,
+        WrMixBlendMode::Sentinel>
+{
+};
+
+} // namespace IPC
+
+#endif // GFX_WEBRENDERMESSAGEUTILS_H
new file mode 100644
--- /dev/null
+++ b/gfx/layers/wr/WebRenderPaintedLayer.cpp
@@ -0,0 +1,175 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "WebRenderPaintedLayer.h"
+
+#include "WebRenderLayersLogging.h"
+#include "mozilla/ArrayUtils.h"
+#include "mozilla/layers/WebRenderBridgeChild.h"
+#include "mozilla/webrender/WebRenderTypes.h"
+#include "gfxUtils.h"
+
+namespace mozilla {
+namespace layers {
+
+using namespace mozilla::gfx;
+
+void
+WebRenderPaintedLayer::PaintThebes()
+{
+  PROFILER_LABEL("WebRenderPaintedLayer", "PaintThebes",
+    js::ProfileEntry::Category::GRAPHICS);
+
+  uint32_t flags = RotatedContentBuffer::PAINT_CAN_DRAW_ROTATED;
+
+  PaintState state =
+    mContentClient->BeginPaintBuffer(this, flags);
+  mValidRegion.Sub(mValidRegion, state.mRegionToInvalidate);
+
+  if (!state.mRegionToDraw.IsEmpty() && !Manager()->GetPaintedLayerCallback()) {
+    return;
+  }
+
+  // The area that became invalid and is visible needs to be repainted
+  // (this could be the whole visible area if our buffer switched
+  // from RGB to RGBA, because we might need to repaint with
+  // subpixel AA)
+  state.mRegionToInvalidate.And(state.mRegionToInvalidate,
+                                GetLocalVisibleRegion().ToUnknownRegion());
+
+  bool didUpdate = false;
+  RotatedContentBuffer::DrawIterator iter;
+  while (DrawTarget* target = mContentClient->BorrowDrawTargetForPainting(state, &iter)) {
+    if (!target || !target->IsValid()) {
+      if (target) {
+        mContentClient->ReturnDrawTargetToBuffer(target);
+      }
+      continue;
+    }
+
+    SetAntialiasingFlags(this, target);
+
+    RefPtr<gfxContext> ctx = gfxContext::CreatePreservingTransformOrNull(target);
+    MOZ_ASSERT(ctx); // already checked the target above
+    Manager()->GetPaintedLayerCallback()(this,
+                                              ctx,
+                                              iter.mDrawRegion,
+                                              iter.mDrawRegion,
+                                              state.mClip,
+                                              state.mRegionToInvalidate,
+                                              Manager()->GetPaintedLayerCallbackData());
+
+    ctx = nullptr;
+    mContentClient->ReturnDrawTargetToBuffer(target);
+    didUpdate = true;
+  }
+  if (didUpdate) {
+    Mutated();
+
+    ContentClientRemote* contentClientRemote = static_cast<ContentClientRemote*>(mContentClient.get());
+
+    // Hold(this) ensures this layer is kept alive through the current transaction
+    // The ContentClient assumes this layer is kept alive (e.g., in CreateBuffer),
+    // so deleting this Hold for whatever reason will break things.
+    Manager()->Hold(this);
+
+    contentClientRemote->Updated(state.mRegionToDraw,
+                                 mVisibleRegion.ToUnknownRegion(),
+                                 state.mDidSelfCopy);
+  }
+}
+
+void
+WebRenderPaintedLayer::RenderLayerWithReadback(ReadbackProcessor *aReadback)
+{
+  if (!mContentClient) {
+    mContentClient = ContentClient::CreateContentClient(Manager()->WrBridge());
+    if (!mContentClient) {
+      return;
+    }
+    mContentClient->Connect();
+    MOZ_ASSERT(mContentClient->GetForwarder());
+  }
+
+  nsTArray<ReadbackProcessor::Update> readbackUpdates;
+  nsIntRegion readbackRegion;
+  if (aReadback && UsedForReadback()) {
+    aReadback->GetPaintedLayerUpdates(this, &readbackUpdates);
+  }
+
+  IntPoint origin(mVisibleRegion.GetBounds().x, mVisibleRegion.GetBounds().y);
+  mContentClient->BeginPaint();
+  PaintThebes();
+  mContentClient->EndPaint(&readbackUpdates);
+}
+
+void
+WebRenderPaintedLayer::RenderLayer()
+{
+  RenderLayerWithReadback(nullptr);
+
+  if (!mExternalImageId) {
+    mExternalImageId = WrBridge()->AllocExternalImageIdForCompositable(mContentClient);
+    MOZ_ASSERT(mExternalImageId);
+  }
+
+  LayerIntRegion visibleRegion = GetVisibleRegion();
+  LayerIntRect bounds = visibleRegion.GetBounds();
+  LayerIntSize size = bounds.Size();
+  if (size.IsEmpty()) {
+      if (gfxPrefs::LayersDump()) {
+        printf_stderr("PaintedLayer %p skipping\n", this->GetLayer());
+      }
+      return;
+  }
+
+  WrScrollFrameStackingContextGenerator scrollFrames(this);
+
+  // Since we are creating a stacking context below using the visible region of
+  // this layer, we need to make sure the image display item has coordinates
+  // relative to the visible region.
+  Rect rect = RelativeToVisible(IntRectToRect(bounds.ToUnknownRect()));
+  Rect clip;
+  if (GetClipRect().isSome()) {
+      clip = RelativeToTransformedVisible(IntRectToRect(GetClipRect().ref().ToUnknownRect()));
+  } else {
+      clip = rect;
+  }
+
+  Maybe<WrImageMask> mask = buildMaskLayer();
+  Rect relBounds = TransformedVisibleBoundsRelativeToParent();
+  Rect overflow(0, 0, relBounds.width, relBounds.height);
+  Matrix4x4 transform;// = GetTransform();
+  WrMixBlendMode mixBlendMode = wr::ToWrMixBlendMode(GetMixBlendMode());
+
+  if (gfxPrefs::LayersDump()) {
+    printf_stderr("PaintedLayer %p using bounds=%s, overflow=%s, transform=%s, rect=%s, clip=%s, mix-blend-mode=%s\n",
+                  this->GetLayer(),
+                  Stringify(relBounds).c_str(),
+                  Stringify(overflow).c_str(),
+                  Stringify(transform).c_str(),
+                  Stringify(rect).c_str(),
+                  Stringify(clip).c_str(),
+                  Stringify(mixBlendMode).c_str());
+  }
+
+  ContentClientRemoteBuffer* contentClientRemote = static_cast<ContentClientRemoteBuffer*>(mContentClient.get());
+  visibleRegion.MoveBy(-contentClientRemote->BufferRect().x, -contentClientRemote->BufferRect().y);
+
+  WrBridge()->AddWebRenderCommand(
+      OpDPPushStackingContext(wr::ToWrRect(relBounds),
+                              wr::ToWrRect(overflow),
+                              mask,
+                              1.0f,
+                              GetAnimations(),
+                              transform,
+                              mixBlendMode,
+                              FrameMetrics::NULL_SCROLL_ID));
+  WrBridge()->AddWebRenderCommand(OpDPPushExternalImageId(visibleRegion, wr::ToWrRect(rect), wr::ToWrRect(clip), Nothing(), WrTextureFilter::Linear, mExternalImageId));
+  WrBridge()->AddWebRenderCommand(OpDPPopStackingContext());
+}
+
+} // namespace layers
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/layers/wr/WebRenderPaintedLayer.h
@@ -0,0 +1,63 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef GFX_WEBRENDERPAINTEDLAYER_H
+#define GFX_WEBRENDERPAINTEDLAYER_H
+
+#include "Layers.h"
+#include "mozilla/layers/ContentClient.h"
+#include "mozilla/layers/WebRenderBridgeChild.h"
+#include "WebRenderLayerManager.h"
+#include "mozilla/webrender/WebRenderTypes.h"
+
+namespace mozilla {
+namespace layers {
+
+class WebRenderPaintedLayer : public WebRenderLayer,
+                              public PaintedLayer {
+public:
+  typedef RotatedContentBuffer::PaintState PaintState;
+  typedef RotatedContentBuffer::ContentType ContentType;
+
+  explicit WebRenderPaintedLayer(WebRenderLayerManager* aLayerManager)
+    : PaintedLayer(aLayerManager, static_cast<WebRenderLayer*>(this), LayerManager::NONE),
+      mExternalImageId(0)
+  {
+    MOZ_COUNT_CTOR(WebRenderPaintedLayer);
+  }
+
+protected:
+  virtual ~WebRenderPaintedLayer()
+  {
+    MOZ_COUNT_DTOR(WebRenderPaintedLayer);
+    if (mExternalImageId) {
+      WrBridge()->DeallocExternalImageId(mExternalImageId);
+    }
+  }
+  WebRenderLayerManager* Manager()
+  {
+    return static_cast<WebRenderLayerManager*>(mManager);
+  }
+
+  uint64_t mExternalImageId;
+
+public:
+  virtual void InvalidateRegion(const nsIntRegion& aRegion) override
+  {
+    mInvalidRegion.Add(aRegion);
+    mValidRegion.Sub(mValidRegion, mInvalidRegion.GetRegion());
+  }
+
+  Layer* GetLayer() override { return this; }
+  void RenderLayer() override;
+  void PaintThebes();
+  void RenderLayerWithReadback(ReadbackProcessor *aReadback);
+  RefPtr<ContentClient> mContentClient;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // GFX_WEBRENDERPAINTEDLAYER_H
new file mode 100644
--- /dev/null
+++ b/gfx/layers/wr/WebRenderTextLayer.cpp
@@ -0,0 +1,90 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "WebRenderTextLayer.h"
+#include "WebRenderLayersLogging.h"
+#include "mozilla/webrender/WebRenderTypes.h"
+#include "mozilla/layers/WebRenderBridgeChild.h"
+
+#include "mozilla/gfx/2D.h"
+
+namespace mozilla {
+namespace layers {
+
+using namespace mozilla::gfx;
+
+static void
+DWriteFontFileData(const uint8_t* aData, uint32_t aLength, uint32_t aIndex,
+                   float aGlyphSize, uint32_t aVariationCount,
+                   const ScaledFont::VariationSetting* aVariations, void* aBaton)
+{
+    WebRenderTextLayer* layer = static_cast<WebRenderTextLayer*>(aBaton);
+
+    uint8_t* fontData = (uint8_t*)malloc(aLength * sizeof(uint8_t));
+    memcpy(fontData, aData, aLength * sizeof(uint8_t));
+
+    layer->mFontData = fontData;
+    layer->mFontDataLength = aLength;
+    layer->mIndex = aIndex;
+    layer->mGlyphSize = aGlyphSize;
+}
+
+void
+WebRenderTextLayer::RenderLayer()
+{
+    if (mBounds.IsEmpty()) {
+        return;
+    }
+
+    gfx::Rect rect = RelativeToParent(GetTransform().TransformBounds(IntRectToRect(mBounds)));
+    gfx::Rect clip;
+    if (GetClipRect().isSome()) {
+      clip = RelativeToParent(IntRectToRect(GetClipRect().ref().ToUnknownRect()));
+    } else {
+      clip = rect;
+    }
+
+    MOZ_ASSERT(mFont->GetType() == FontType::DWRITE);
+    mFont->GetFontFileData(&DWriteFontFileData, this);
+    wr::ByteBuffer fontBuffer(mFontDataLength, mFontData);
+
+    nsTArray<WrGlyphArray> wr_glyphs;
+    wr_glyphs.SetLength(mGlyphs.Length());
+
+    for (size_t i = 0; i < mGlyphs.Length(); i++) {
+        GlyphArray glyph_array = mGlyphs[i];
+        nsTArray<Glyph>& glyphs = glyph_array.glyphs();
+
+        nsTArray<WrGlyphInstance>& wr_glyph_instances = wr_glyphs[i].glyphs;
+        wr_glyph_instances.SetLength(glyphs.Length());
+        wr_glyphs[i].color = glyph_array.color().value();
+
+        for (size_t j = 0; j < glyphs.Length(); j++) {
+            wr_glyph_instances[j].index = glyphs[j].mIndex;
+            wr_glyph_instances[j].x = glyphs[j].mPosition.x;
+            wr_glyph_instances[j].y = glyphs[j].mPosition.y;
+        }
+    }
+
+    if (gfxPrefs::LayersDump()) {
+        printf_stderr("TextLayer %p using rect=%s, clip=%s\n",
+                      this->GetLayer(),
+                      Stringify(rect).c_str(),
+                      Stringify(clip).c_str());
+    }
+
+    WrBridge()->AddWebRenderCommand(OpDPPushText(
+        wr::ToWrRect(rect),
+        wr::ToWrRect(clip),
+        wr_glyphs,
+        mIndex,
+        mGlyphSize,
+        fontBuffer,
+        mFontDataLength
+    ));
+}
+
+} // namespace layers
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/layers/wr/WebRenderTextLayer.h
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+
+#ifndef GFX_WEBRENDERTEXTLAYER_H
+#define GFX_WEBRENDERTEXTLAYER_H
+
+#include "Layers.h"
+#include "WebRenderLayerManager.h"
+
+namespace mozilla {
+namespace layers {
+
+class WebRenderTextLayer : public WebRenderLayer,
+                           public TextLayer {
+public:
+    explicit WebRenderTextLayer(WebRenderLayerManager* aLayerManager)
+        : TextLayer(aLayerManager, static_cast<WebRenderLayer*>(this))
+        , mFontData(nullptr)
+        , mFontDataLength(0)
+        , mIndex(0)
+        , mGlyphSize(0.0)
+    {
+        MOZ_COUNT_CTOR(WebRenderTextLayer);
+    }
+
+protected:
+    virtual ~WebRenderTextLayer()
+    {
+        MOZ_COUNT_DTOR(WebRenderTextLayer);
+        if (mFontData) {
+            free(mFontData);
+        }
+    }
+
+public:
+  Layer* GetLayer() override { return this; }
+  void RenderLayer() override;
+
+  uint8_t* mFontData;
+  uint32_t mFontDataLength;
+  uint32_t mIndex;
+  float mGlyphSize;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // GFX_WEBRENDERTEXTLAYER_H
\ No newline at end of file
--- a/gfx/moz.build
+++ b/gfx/moz.build
@@ -20,16 +20,17 @@ DIRS += [
     'layers',
     'graphite2/src',
     'harfbuzz/src',
     'ots/src',
     'thebes',
     'ipc',
     'vr',
     'config',
+    'webrender_bindings',
 ]
 
 if CONFIG['MOZ_ENABLE_SKIA']:
     DIRS += ['skia']
 
 if CONFIG['MOZ_ENABLE_SKIA_PDF_SFNTLY'] and CONFIG['ENABLE_INTL_API']:
      DIRS += ['sfntly/cpp/src']
 
--- a/gfx/tests/browser/browser_windowless_troubleshoot_crash.js
+++ b/gfx/tests/browser/browser_windowless_troubleshoot_crash.js
@@ -23,18 +23,22 @@ add_task(function* test_windowlessBrowse
   });
   webNav.loadURI("about:blank", 0, null, null, null);
 
   yield onLoaded;
 
   let winUtils = webNav.document.defaultView.
                         QueryInterface(Ci.nsIInterfaceRequestor).
                         getInterface(Ci.nsIDOMWindowUtils);
-  is(winUtils.layerManagerType, "None", "windowless browser's layerManagerType should be 'None'");
-
+  try {
+    is(winUtils.layerManagerType, "None", "windowless browser's layerManagerType should be 'None'");
+  } catch (e) {
+    // The windowless browser may not have a layermanager at all yet, and that's ok.
+    // The troubleshooting code similarly skips over windows with no layer managers.
+  }
   ok(true, "not crashed");
 
   var Troubleshoot = Cu.import("resource://gre/modules/Troubleshoot.jsm", {}).Troubleshoot;
   var data = yield new Promise((resolve, reject) => {
     Troubleshoot.snapshot((data) => {
       resolve(data);
     });
   });
--- a/gfx/tests/reftest/reftest.list
+++ b/gfx/tests/reftest/reftest.list
@@ -1,9 +1,9 @@
 # 468496-1 will also detect bugs in video drivers.
 == 468496-1.html 468496-1-ref.html
 fuzzy(175,443) == 611498-1.html 611498-ref.html
 fuzzy-if(Android,8,1000) == 709477-1.html 709477-1-ref.html
 skip-if(!asyncPan) == 1086723.html 1086723-ref.html
 == 853889-1.html 853889-1-ref.html
 skip-if(Android) fuzzy-if(skiaContent,1,587) == 1143303-1.svg pass.svg
-fuzzy(100,30) == 1149923.html 1149923-ref.html # use fuzzy due to few distorted pixels caused by border-radius
+fuzzy(100,30) fails-if(webrender) == 1149923.html 1149923-ref.html # use fuzzy due to few distorted pixels caused by border-radius
 == 1131264-1.svg pass.svg
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -2,16 +2,17 @@
  * 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 "mozilla/layers/CompositorBridgeChild.h"
 #include "mozilla/layers/CompositorThread.h"
 #include "mozilla/layers/ImageBridgeChild.h"
 #include "mozilla/layers/ISurfaceAllocator.h"     // for GfxMemoryImageReporter
+#include "mozilla/webrender/RenderThread.h"
 #include "mozilla/gfx/gfxVars.h"
 #include "mozilla/gfx/GPUProcessManager.h"
 #include "mozilla/gfx/GraphicsMessages.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/Unused.h"
 
@@ -934,16 +935,19 @@ gfxPlatform::InitLayersIPC()
 {
     if (sLayersIPCIsUp) {
       return;
     }
     sLayersIPCIsUp = true;
 
     if (XRE_IsParentProcess())
     {
+        if (gfxVars::UseWebRender()) {
+            wr::RenderThread::Start();
+        }
         layers::CompositorThreadHolder::Start();
     }
 }
 
 /* static */ void
 gfxPlatform::ShutdownLayersIPC()
 {
     if (!sLayersIPCIsUp) {
@@ -962,16 +966,19 @@ gfxPlatform::ShutdownLayersIPC()
         gfx::VRManagerChild::ShutDown();
         layers::CompositorBridgeChild::ShutDown();
         layers::ImageBridgeChild::ShutDown();
 #if defined(MOZ_WIDGET_ANDROID)
         layers::UiCompositorControllerChild::Shutdown();
 #endif // defined(MOZ_WIDGET_ANDROID)
         // This has to happen after shutting down the child protocols.
         layers::CompositorThreadHolder::Shutdown();
+        if (gfxVars::UseWebRender()) {
+            wr::RenderThread::ShutDown();
+        }
     } else {
       // TODO: There are other kind of processes and we should make sure gfx
       // stuff is either not created there or shut down properly.
     }
 }
 
 void
 gfxPlatform::WillShutdown()
@@ -2201,16 +2208,17 @@ gfxPlatform::InitAcceleration()
   sLayersAccelerationPrefsInitialized = true;
 
   if (XRE_IsParentProcess()) {
     Preferences::RegisterCallbackAndCall(VideoDecodingFailedChangedCallback,
                                          "media.hardware-video-decoding.failed",
                                          nullptr,
                                          Preferences::ExactMatch);
     InitGPUProcessPrefs();
+    InitWebRenderConfig();
   }
 }
 
 void
 gfxPlatform::InitGPUProcessPrefs()
 {
   // We want to hide this from about:support, so only set a default if the
   // pref is known to be true.
@@ -2287,16 +2295,57 @@ gfxPlatform::InitCompositorAccelerationP
 
   // Safe mode trumps everything.
   if (InSafeMode()) {
     feature.ForceDisable(FeatureStatus::Blocked, "Acceleration blocked by safe-mode",
                          NS_LITERAL_CSTRING("FEATURE_FAILURE_COMP_SAFEMODE"));
   }
 }
 
+void
+gfxPlatform::InitWebRenderConfig()
+{
+  FeatureState& featureWebRender = gfxConfig::GetFeature(Feature::WEBRENDER);
+
+  featureWebRender.EnableByDefault();
+
+  if (!Preferences::GetBool("gfx.webrender.enabled", false)) {
+    featureWebRender.UserDisable(
+      "User disabled WebRender",
+      NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBRENDER_DISABLED"));
+  }
+
+  // WebRender relies on the GPU process when on Windows
+#ifdef XP_WIN
+  if (!gfxConfig::IsEnabled(Feature::GPU_PROCESS)) {
+    featureWebRender.ForceDisable(
+      FeatureStatus::Unavailable,
+      "GPU Process is disabled",
+      NS_LITERAL_CSTRING("FEATURE_FAILURE_GPU_PROCESS_DISABLED"));
+  }
+#endif
+
+  if (InSafeMode()) {
+    featureWebRender.ForceDisable(
+      FeatureStatus::Unavailable,
+      "Safe-mode is enabled",
+      NS_LITERAL_CSTRING("FEATURE_FAILURE_SAFE_MODE"));
+  }
+
+#ifndef MOZ_ENABLE_WEBRENDER
+  featureWebRender.ForceDisable(
+    FeatureStatus::Unavailable,
+    "Build doesn't include WebRender",
+    NS_LITERAL_CSTRING("FEATURE_FAILURE_NO_WEBRENDER"));
+#endif
+
+  // gfxFeature is not usable in the GPU process, so we use gfxVars to transmit this feature
+  gfxVars::SetUseWebRender(gfxConfig::IsEnabled(Feature::WEBRENDER));
+}
+
 bool
 gfxPlatform::CanUseHardwareVideoDecoding()
 {
   // this function is called from the compositor thread, so it is not
   // safe to init the prefs etc. from here.
   MOZ_ASSERT(sLayersAccelerationPrefsInitialized);
   return sLayersSupportsHardwareVideoDecoding && !sLayersHardwareVideoDecodingFailed;
 }
@@ -2537,16 +2586,28 @@ gfxPlatform::NotifyCompositorCreated(Lay
   // Notify that we created a compositor, so telemetry can update.
   NS_DispatchToMainThread(NS_NewRunnableFunction([] {
     if (nsCOMPtr<nsIObserverService> obsvc = services::GetObserverService()) {
       obsvc->NotifyObservers(nullptr, "compositor:created", nullptr);
     }
   }));
 }
 
+/* static */ void
+gfxPlatform::NotifyGPUProcessDisabled()
+{
+  if (gfxConfig::IsEnabled(Feature::WEBRENDER)) {
+    gfxConfig::GetFeature(Feature::WEBRENDER).ForceDisable(
+      FeatureStatus::Unavailable,
+      "GPU Process is disabled",
+      NS_LITERAL_CSTRING("FEATURE_FAILURE_GPU_PROCESS_DISABLED"));
+    gfxVars::SetUseWebRender(false);
+  }
+}
+
 void
 gfxPlatform::FetchAndImportContentDeviceData()
 {
   MOZ_ASSERT(XRE_IsContentProcess());
 
   mozilla::dom::ContentChild* cc = mozilla::dom::ContentChild::GetSingleton();
 
   mozilla::gfx::ContentDeviceData data;
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -647,16 +647,18 @@ public:
                                  mozilla::gfx::SurfaceFormat aFormat);
 
     /**
      * Wrapper around gfxPrefs::PerfWarnings().
      * Extracted into a function to avoid including gfxPrefs.h from this file.
      */
     static bool PerfWarnings();
 
+    static void NotifyGPUProcessDisabled();
+
     void NotifyCompositorCreated(mozilla::layers::LayersBackend aBackend);
     mozilla::layers::LayersBackend GetCompositorBackend() const {
       return mCompositorBackend;
     }
 
     virtual void CompositorUpdated() {}
 
     // Plugin async drawing support.
@@ -815,16 +817,17 @@ private:
 
     /**
      * This uses nsIScreenManager to determine the screen size and color depth
      */
     void PopulateScreenInfo();
 
     void InitCompositorAccelerationPrefs();
     void InitGPUProcessPrefs();
+    void InitWebRenderConfig();
 
     static bool IsDXInterop2Blocked();
 
     RefPtr<gfxASurface> mScreenReferenceSurface;
     nsCOMPtr<nsIObserver> mSRGBOverrideObserver;
     nsCOMPtr<nsIObserver> mFontPrefsObserver;
     nsCOMPtr<nsIObserver> mMemoryPressureObserver;
 
--- a/gfx/thebes/gfxPlatformGtk.cpp
+++ b/gfx/thebes/gfxPlatformGtk.cpp
@@ -730,18 +730,20 @@ public:
 
         // Most compositors wait for vsync events on the root window.
         Window root = DefaultRootWindow(mXDisplay);
         int screen = DefaultScreen(mXDisplay);
 
         ScopedXFree<GLXFBConfig> cfgs;
         GLXFBConfig config;
         int visid;
+        bool forWebRender = false;
         if (!gl::GLContextGLX::FindFBConfigForWindow(mXDisplay, screen, root,
-                                                     &cfgs, &config, &visid)) {
+                                                     &cfgs, &config, &visid,
+                                                     forWebRender)) {
           lock.NotifyAll();
           return;
         }
 
         mGLContext = gl::GLContextGLX::CreateGLContext(
             gl::CreateContextFlags::NONE,
             gl::SurfaceCaps::Any(),
             nullptr,
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -251,16 +251,17 @@ private:
 
   // This is where DECL_GFX_PREF for each of the preferences should go.
   // We will keep these in an alphabetical order to make it easier to see if
   // a method accessing a pref already exists. Just add yours in the list.
 
   // The apz prefs are explained in AsyncPanZoomController.cpp
   DECL_GFX_PREF(Live, "apz.allow_checkerboarding",             APZAllowCheckerboarding, bool, true);
   DECL_GFX_PREF(Live, "apz.allow_immediate_handoff",           APZAllowImmediateHandoff, bool, true);
+  DECL_GFX_PREF(Once, "apz.allow_with_webrender",              APZAllowWithWebRender, bool, false);
   DECL_GFX_PREF(Live, "apz.allow_zooming",                     APZAllowZooming, bool, false);
   DECL_GFX_PREF(Live, "apz.axis_lock.breakout_angle",          APZAxisBreakoutAngle, float, float(M_PI / 8.0) /* 22.5 degrees */);
   DECL_GFX_PREF(Live, "apz.axis_lock.breakout_threshold",      APZAxisBreakoutThreshold, float, 1.0f / 32.0f);
   DECL_GFX_PREF(Live, "apz.axis_lock.direct_pan_angle",        APZAllowedDirectPanAngle, float, float(M_PI / 3.0) /* 60 degrees */);
   DECL_GFX_PREF(Live, "apz.axis_lock.lock_angle",              APZAxisLockAngle, float, float(M_PI / 6.0) /* 30 degrees */);
   DECL_GFX_PREF(Live, "apz.axis_lock.mode",                    APZAxisLockMode, int32_t, 0);
   DECL_GFX_PREF(Live, "apz.content_response_timeout",          APZContentResponseTimeout, int32_t, 400);
   DECL_GFX_PREF(Live, "apz.danger_zone_x",                     APZDangerZoneX, int32_t, 50);
@@ -416,16 +417,17 @@ private:
   DECL_GFX_PREF(Once, "gfx.touch.resample.max-predict",        TouchResampleMaxPredict, int32_t, 8);
   DECL_GFX_PREF(Once, "gfx.touch.resample.min-delta",          TouchResampleMinDelta, int32_t, 2);
   DECL_GFX_PREF(Once, "gfx.touch.resample.old-touch-threshold",TouchResampleOldTouchThreshold, int32_t, 17);
   DECL_GFX_PREF(Once, "gfx.touch.resample.vsync-adjust",       TouchVsyncSampleAdjust, int32_t, 5);
 
   DECL_GFX_PREF(Once, "gfx.vr.openvr-runtime",                 VROpenVRRuntime, std::string, "");
   DECL_GFX_PREF(Live, "gfx.vsync.collect-scroll-transforms",   CollectScrollTransforms, bool, false);
   DECL_GFX_PREF(Once, "gfx.vsync.compositor.unobserve-count",  CompositorUnobserveCount, int32_t, 10);
+  DECL_GFX_PREF(Live, "gfx.webrender.profiler.enable",         WebRenderProfilerEnabled, bool, false);
   // Use vsync events generated by hardware
   DECL_GFX_PREF(Once, "gfx.work-around-driver-bugs",           WorkAroundDriverBugs, bool, true);
   DECL_GFX_PREF(Once, "gfx.screen-mirroring.enabled",          ScreenMirroringEnabled, bool, false);
 
   DECL_GFX_PREF(Live, "gl.ignore-dx-interop2-blacklist",       IgnoreDXInterop2Blacklist, bool, false);
   DECL_GFX_PREF(Live, "gl.msaa-level",                         MSAALevel, uint32_t, 2);
 #if defined(XP_MACOSX)
   DECL_GFX_PREF(Live, "gl.multithreaded",                      GLMultithreaded, bool, false);
new file mode 100644
--- /dev/null
+++ b/gfx/webrender_bindings/RenderThread.cpp
@@ -0,0 +1,247 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "RenderThread.h"
+#include "nsThreadUtils.h"
+#include "mozilla/webrender/RendererOGL.h"
+#include "mozilla/widget/CompositorWidget.h"
+#include "mozilla/layers/CompositorThread.h"
+#include "mozilla/layers/CompositorBridgeParent.h"
+#include "mozilla/StaticPtr.h"
+#include "base/task.h"
+
+namespace mozilla {
+namespace wr {
+
+static StaticRefPtr<RenderThread> sRenderThread;
+
+RenderThread::RenderThread(base::Thread* aThread)
+  : mThread(aThread)
+{
+
+}
+
+RenderThread::~RenderThread()
+{
+  delete mThread;
+}
+
+// static
+RenderThread*
+RenderThread::Get()
+{
+  return sRenderThread;
+}
+
+// static
+void
+RenderThread::Start()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(!sRenderThread);
+
+  base::Thread* thread = new base::Thread("Renderer");
+
+  base::Thread::Options options;
+  // TODO(nical): The compositor thread has a bunch of specific options, see
+  // which ones make sense here.
+  if (!thread->StartWithOptions(options)) {
+    delete thread;
+    return;
+  }
+
+  sRenderThread = new RenderThread(thread);
+}
+
+// static
+void
+RenderThread::ShutDown()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(sRenderThread);
+
+  // TODO(nical): sync with the render thread
+
+  sRenderThread = nullptr;
+}
+
+// static
+MessageLoop*
+RenderThread::Loop()
+{
+  return sRenderThread ? sRenderThread->mThread->message_loop() : nullptr;
+}
+
+// static
+bool
+RenderThread::IsInRenderThread()
+{
+  return sRenderThread && sRenderThread->mThread->thread_id() == PlatformThread::CurrentId();
+}
+
+void
+RenderThread::AddRenderer(wr::WindowId aWindowId, UniquePtr<RendererOGL> aRenderer)
+{
+  MOZ_ASSERT(IsInRenderThread());
+  mRenderers[aWindowId] = Move(aRenderer);
+}
+
+void
+RenderThread::RemoveRenderer(wr::WindowId aWindowId)
+{
+  MOZ_ASSERT(IsInRenderThread());
+  mRenderers.erase(aWindowId);
+}
+
+RendererOGL*
+RenderThread::GetRenderer(wr::WindowId aWindowId)
+{
+  MOZ_ASSERT(IsInRenderThread());
+
+  auto it = mRenderers.find(aWindowId);
+  MOZ_ASSERT(it != mRenderers.end());
+
+  if (it == mRenderers.end()) {
+    return nullptr;
+  }
+
+  return it->second.get();
+}
+
+void
+RenderThread::NewFrameReady(wr::WindowId aWindowId)
+{
+  if (!IsInRenderThread()) {
+    Loop()->PostTask(NewRunnableMethod<wr::WindowId>(
+      this, &RenderThread::NewFrameReady, aWindowId
+    ));
+    return;
+  }
+
+  UpdateAndRender(aWindowId);
+}
+
+void
+RenderThread::NewScrollFrameReady(wr::WindowId aWindowId, bool aCompositeNeeded)
+{
+  if (!IsInRenderThread()) {
+    Loop()->PostTask(NewRunnableMethod<wr::WindowId, bool>(
+      this, &RenderThread::NewScrollFrameReady, aWindowId, aCompositeNeeded
+    ));
+    return;
+  }
+
+  UpdateAndRender(aWindowId);
+}
+
+void
+RenderThread::PipelineSizeChanged(wr::WindowId aWindowId, uint64_t aPipelineId, float aWidth, float aHeight)
+{
+  if (!IsInRenderThread()) {
+    Loop()->PostTask(NewRunnableMethod<wr::WindowId, uint64_t, float, float>(
+      this, &RenderThread::PipelineSizeChanged,
+      aWindowId, aPipelineId, aWidth, aHeight
+    ));
+    return;
+  }
+
+  UpdateAndRender(aWindowId);
+}
+
+void
+RenderThread::RunEvent(wr::WindowId aWindowId, UniquePtr<RendererEvent> aEvent)
+{
+  if (!IsInRenderThread()) {
+    Loop()->PostTask(NewRunnableMethod<wr::WindowId, UniquePtr<RendererEvent>&&>(
+      this, &RenderThread::RunEvent,
+      aWindowId, Move(aEvent)
+    ));
+    return;
+  }
+
+  aEvent->Run(*this, aWindowId);
+  aEvent = nullptr;
+}
+
+static void
+NotifyDidRender(layers::CompositorBridgeParentBase* aBridge,
+                WrRenderedEpochs* aEpochs,
+                TimeStamp aStart,
+                TimeStamp aEnd)
+{
+  WrPipelineId pipeline;
+  WrEpoch epoch;
+  while (wr_rendered_epochs_next(aEpochs, &pipeline, &epoch)) {
+    // TODO - Currently each bridge seems to  only have one pipeline but at some
+    // point we should pass make sure we only notify bridges that have the
+    // corresponding pipeline id.
+    aBridge->NotifyDidComposite(epoch, aStart, aEnd);
+  }
+  wr_rendered_epochs_delete(aEpochs);
+}
+
+void
+RenderThread::UpdateAndRender(wr::WindowId aWindowId)
+{
+  MOZ_ASSERT(IsInRenderThread());
+
+  auto it = mRenderers.find(aWindowId);
+  MOZ_ASSERT(it != mRenderers.end());
+  if (it == mRenderers.end()) {
+    return;
+  }
+
+  auto& renderer = it->second;
+  renderer->Update();
+
+  TimeStamp start = TimeStamp::Now();
+
+  renderer->Render();
+
+  TimeStamp end = TimeStamp::Now();
+
+  auto epochs = renderer->FlushRenderedEpochs();
+  layers::CompositorThreadHolder::Loop()->PostTask(NewRunnableFunction(
+    &NotifyDidRender,
+    renderer->GetCompositorBridge(),
+    epochs,
+    start, end
+  ));
+}
+
+} // namespace wr
+} // namespace mozilla
+
+extern "C" {
+
+void wr_notifier_new_frame_ready(WrWindowId aWindowId)
+{
+  mozilla::wr::RenderThread::Get()->NewFrameReady(mozilla::wr::WindowId(aWindowId));
+}
+
+void wr_notifier_new_scroll_frame_ready(WrWindowId aWindowId, bool aCompositeNeeded)
+{
+  mozilla::wr::RenderThread::Get()->NewScrollFrameReady(mozilla::wr::WindowId(aWindowId),
+                                                        aCompositeNeeded);
+}
+
+void wr_notifier_pipeline_size_changed(WrWindowId aWindowId,
+                                       uint64_t aPipelineId,
+                                       float aWidth,
+                                       float aHeight)
+{
+  mozilla::wr::RenderThread::Get()->PipelineSizeChanged(mozilla::wr::WindowId(aWindowId),
+                                                        aPipelineId, aWidth, aHeight);
+}
+
+void wr_notifier_external_event(WrWindowId aWindowId, size_t aRawEvent)
+{
+  mozilla::UniquePtr<mozilla::wr::RendererEvent> evt(
+    reinterpret_cast<mozilla::wr::RendererEvent*>(aRawEvent));
+  mozilla::wr::RenderThread::Get()->RunEvent(mozilla::wr::WindowId(aWindowId),
+                                             mozilla::Move(evt));
+}
+
+} // extern C
new file mode 100644
--- /dev/null
+++ b/gfx/webrender_bindings/RenderThread.h
@@ -0,0 +1,116 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 sts=2 ts=8 et tw=99 : */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef MOZILLA_LAYERS_RENDERTHREAD_H
+#define MOZILLA_LAYERS_RENDERTHREAD_H
+
+#include "base/basictypes.h"            // for DISALLOW_EVIL_CONSTRUCTORS
+#include "base/platform_thread.h"       // for PlatformThreadId
+#include "base/thread.h"                // for Thread
+#include "base/message_loop.h"
+#include "nsISupportsImpl.h"
+#include "ThreadSafeRefcountingWithMainThreadDestruction.h"
+#include "mozilla/webrender/webrender_ffi.h"
+#include "mozilla/UniquePtr.h"
+#include "mozilla/webrender/WebRenderTypes.h"
+
+namespace mozilla {
+namespace wr {
+
+class RendererOGL;
+class RenderThread;
+
+/// Base class for an event that can be scheduled to run on the render thread.
+///
+/// The event can be passed through the same channels as regular WebRender messages
+/// to preserve ordering.
+class RendererEvent
+{
+public:
+  virtual ~RendererEvent() {}
+  virtual void Run(RenderThread& aRenderThread, wr::WindowId aWindow) = 0;
+};
+
+/// The render thread is where WebRender issues all of its GPU work, and as much
+/// as possible this thread should only serve this purpose.
+///
+/// The render thread owns the different RendererOGLs (one per window) and implements
+/// the RenderNotifier api exposed by the WebRender bindings.
+///
+/// We should generally avoid posting tasks to the render thread's event loop directly
+/// and instead use the RendererEvent mechanism which avoids races between the events
+/// and WebRender's own messages.
+///
+/// The GL context(s) should be created and used on this thread only.
+/// XXX - I've tried to organize code so that we can potentially avoid making
+/// this a singleton since this bad habit has a tendency to bite us later, but
+/// I haven't gotten all the way there either, in order to focus on the more
+/// important pieces first. So we are a bit in-between (this is totally a singleton
+/// but in some places we pretend it's not). Hopefully we can evolve this in a way
+/// that keeps the door open to removing the singleton bits.
+class RenderThread final
+{
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(RenderThread)
+
+public:
+  /// Can be called from any thread.
+  static RenderThread* Get();
+
+  /// Can only be called from the main thread.
+  static void Start();
+
+  /// Can only be called from the main thread.
+  static void ShutDown();
+
+  /// Can be called from any thread.
+  /// In most cases it is best to post RendererEvents through WebRenderAPI instead
+  /// of scheduling directly to this message loop (so as to preserve the ordering
+  /// of the messages).
+  static MessageLoop* Loop();
+
+  /// Can be called from any thread.
+  static bool IsInRenderThread();
+
+  /// Can only be called from the render thread.
+  void AddRenderer(wr::WindowId aWindowId, UniquePtr<RendererOGL> aRenderer);
+
+  /// Can only be called from the render thread.
+  void RemoveRenderer(wr::WindowId aWindowId);
+
+  /// Can only be called from the render thread.
+  RendererOGL* GetRenderer(wr::WindowId aWindowId);
+
+  // RenderNotifier implementation
+
+  /// Automatically forwarded to the render thread.
+  void NewFrameReady(wr::WindowId aWindowId);
+
+  /// Automatically forwarded to the render thread.
+  void NewScrollFrameReady(wr::WindowId aWindowId, bool aCompositeNeeded);
+
+  /// Automatically forwarded to the render thread.
+  void PipelineSizeChanged(wr::WindowId aWindowId, uint64_t aPipelineId, float aWidth, float aHeight);
+
+  /// Automatically forwarded to the render thread.
+  void RunEvent(wr::WindowId aWindowId, UniquePtr<RendererEvent> aCallBack);
+
+  /// Can only be called from the render thread.
+  void UpdateAndRender(wr::WindowId aWindowId);
+private:
+  explicit RenderThread(base::Thread* aThread);
+
+  ~RenderThread();
+
+
+  base::Thread* const mThread;
+
+  std::map<wr::WindowId, UniquePtr<RendererOGL>> mRenderers;
+};
+
+} // namespace wr
+} // namespace mozilla
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/webrender_bindings/RendererOGL.cpp
@@ -0,0 +1,100 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "RendererOGL.h"
+#include "GLContext.h"
+#include "GLContextProvider.h"
+#include "mozilla/gfx/Logging.h"
+#include "mozilla/layers/CompositorBridgeParent.h"
+#include "mozilla/layers/CompositorThread.h"
+#include "mozilla/widget/CompositorWidget.h"
+
+namespace mozilla {
+namespace wr {
+
+RendererOGL::RendererOGL(RefPtr<RenderThread>&& aThread,
+                         RefPtr<gl::GLContext>&& aGL,
+                         RefPtr<widget::CompositorWidget>&& aWidget,
+                         wr::WindowId aWindowId,
+                         WrRenderer* aWrRenderer,
+                         layers::CompositorBridgeParentBase* aBridge)
+  : mThread(aThread)
+  , mGL(aGL)
+  , mWidget(aWidget)
+  , mWrRenderer(aWrRenderer)
+  , mBridge(aBridge)
+  , mWindowId(aWindowId)
+{
+  MOZ_ASSERT(mThread);
+  MOZ_ASSERT(mGL);
+  MOZ_ASSERT(mWidget);
+  MOZ_ASSERT(mWrRenderer);
+  MOZ_ASSERT(mBridge);
+  MOZ_COUNT_CTOR(RendererOGL);
+}
+
+RendererOGL::~RendererOGL()
+{
+  MOZ_COUNT_DTOR(RendererOGL);
+  wr_renderer_delete(mWrRenderer);
+}
+
+void
+RendererOGL::Update()
+{
+  wr_renderer_update(mWrRenderer);
+}
+
+bool
+RendererOGL::Render()
+{
+  if (!mGL->MakeCurrent()) {
+    gfxCriticalNote << "Failed to make render context current, can't draw.";
+    return false;
+  }
+
+  mozilla::widget::WidgetRenderingContext widgetContext;
+
+#if defined(XP_MACOSX)
+  widgetContext.mGL = mGL;
+// TODO: we don't have a notion of compositor here.
+//#elif defined(MOZ_WIDGET_ANDROID)
+//  widgetContext.mCompositor = mCompositor;
+#endif
+
+  if (!mWidget->PreRender(&widgetContext)) {
+    return false;
+  }
+  // XXX set clear color if MOZ_WIDGET_ANDROID is defined.
+  // XXX pass the actual render bounds instead of an empty rect.
+  mWidget->DrawWindowUnderlay(&widgetContext, LayoutDeviceIntRect());
+
+  auto size = mWidget->GetClientSize();
+  wr_renderer_render(mWrRenderer, size.width, size.height);
+
+  mGL->SwapBuffers();
+  mWidget->DrawWindowOverlay(&widgetContext, LayoutDeviceIntRect());
+  mWidget->PostRender(&widgetContext);
+
+  // TODO: Flush pending actions such as texture deletions/unlocks and
+  //       textureHosts recycling.
+
+  return true;
+}
+
+void
+RendererOGL::SetProfilerEnabled(bool aEnabled)
+{
+  wr_renderer_set_profiler_enabled(mWrRenderer, aEnabled);
+}
+
+WrRenderedEpochs*
+RendererOGL::FlushRenderedEpochs()
+{
+  return wr_renderer_flush_rendered_epochs(mWrRenderer);
+}
+
+} // namespace wr
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/webrender_bindings/RendererOGL.h
@@ -0,0 +1,82 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 sts=2 ts=8 et tw=99 : */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef MOZILLA_LAYERS_RENDEREROGL_H
+#define MOZILLA_LAYERS_RENDEREROGL_H
+
+#include "mozilla/webrender/RenderThread.h"
+#include "mozilla/webrender/WebRenderTypes.h"
+#include "mozilla/webrender/webrender_ffi.h"
+
+namespace mozilla {
+
+namespace gfx {
+class DrawTarget;
+}
+
+namespace gl {
+class GLContext;
+}
+
+namespace layers {
+class CompositorBridgeParentBase;
+}
+
+namespace widget {
+class CompositorWidget;
+}
+
+namespace wr {
+
+/// Owns the WebRender renderer and GL context.
+///
+/// There is one renderer per window, all owned by the render thread.
+/// This class is a similar abstraction to CompositorOGL except that it is used
+/// on the render thread instead of the compositor thread.
+class RendererOGL
+{
+public:
+  /// This can be called on the render thread only.
+  void Update();
+
+  /// This can be called on the render thread only.
+  bool Render();
+
+  /// This can be called on the render thread only.
+  bool RenderToTarget(gfx::DrawTarget& aTarget);
+
+  /// This can be called on the render thread only.
+  void SetProfilerEnabled(bool aEnabled);
+
+  /// This can be called on the render thread only.
+  ~RendererOGL();
+
+  /// This can be called on the render thread only.
+  RendererOGL(RefPtr<RenderThread>&& aThread,
+              RefPtr<gl::GLContext>&& aGL,
+              RefPtr<widget::CompositorWidget>&&,
+              wr::WindowId aWindowId,
+              WrRenderer* aWrRenderer,
+              layers::CompositorBridgeParentBase* aBridge);
+
+  layers::CompositorBridgeParentBase* GetCompositorBridge() { return mBridge; }
+
+  WrRenderedEpochs* FlushRenderedEpochs();
+
+protected:
+
+  RefPtr<RenderThread> mThread;
+  RefPtr<gl::GLContext> mGL;
+  RefPtr<widget::CompositorWidget> mWidget;
+  WrRenderer* mWrRenderer;
+  layers::CompositorBridgeParentBase* mBridge;
+  wr::WindowId mWindowId;
+};
+
+} // namespace wr
+} // namespace mozilla
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/webrender_bindings/WebRenderAPI.cpp
@@ -0,0 +1,415 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "WebRenderAPI.h"
+#include "mozilla/webrender/RendererOGL.h"
+#include "mozilla/layers/CompositorThread.h"
+#include "mozilla/widget/CompositorWidget.h"
+#include "mozilla/widget/CompositorWidget.h"
+#include "mozilla/layers/SynchronousTask.h"
+
+namespace mozilla {
+namespace wr {
+
+Maybe<WrImageFormat>
+SurfaceFormatToWrImageFormat(gfx::SurfaceFormat aFormat) {
+  switch (aFormat) {
+    case gfx::SurfaceFormat::B8G8R8X8:
+      // TODO: WebRender will have a BGRA + opaque flag for this but does not
+      // have it yet (cf. issue #732).
+    case gfx::SurfaceFormat::B8G8R8A8:
+      return Some(WrImageFormat::RGBA8);
+    case gfx::SurfaceFormat::B8G8R8:
+      return Some(WrImageFormat::RGB8);
+    case gfx::SurfaceFormat::A8:
+      return Some(WrImageFormat::A8);
+    case gfx::SurfaceFormat::UNKNOWN:
+      return Some(WrImageFormat::Invalid);
+    default:
+      return Nothing();
+  }
+}
+
+class NewRenderer : public RendererEvent
+{
+public:
+  NewRenderer(WrAPI** aApi, layers::CompositorBridgeParentBase* aBridge,
+              GLint* aMaxTextureSize,
+              RefPtr<widget::CompositorWidget>&& aWidget,
+              layers::SynchronousTask* aTask,
+              bool aEnableProfiler)
+    : mWrApi(aApi)
+    , mMaxTextureSize(aMaxTextureSize)
+    , mBridge(aBridge)
+    , mCompositorWidget(Move(aWidget))
+    , mTask(aTask)
+    , mEnableProfiler(aEnableProfiler)
+  {
+    MOZ_COUNT_CTOR(NewRenderer);
+  }
+
+  ~NewRenderer()
+  {
+    MOZ_COUNT_DTOR(NewRenderer);
+  }
+
+  virtual void Run(RenderThread& aRenderThread, WindowId aWindowId) override
+  {
+    layers::AutoCompleteTask complete(mTask);
+
+    RefPtr<gl::GLContext> gl = gl::GLContextProvider::CreateForCompositorWidget(mCompositorWidget, true);
+    if (!gl || !gl->MakeCurrent()) {
+      return;
+    }
+
+    gl->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, mMaxTextureSize);
+
+    wr_gl_init(gl.get());
+
+    WrRenderer* wrRenderer = nullptr;
+    wr_window_new(aWindowId.mHandle, this->mEnableProfiler, mWrApi, &wrRenderer);
+    MOZ_ASSERT(wrRenderer);
+
+    RefPtr<RenderThread> thread = &aRenderThread;
+    auto renderer = MakeUnique<RendererOGL>(Move(thread),
+                                            Move(gl),
+                                            Move(mCompositorWidget),
+                                            aWindowId,
+                                            wrRenderer,
+                                            mBridge);
+
+    aRenderThread.AddRenderer(aWindowId, Move(renderer));
+  }
+
+private:
+  WrAPI** mWrApi;
+  GLint* mMaxTextureSize;
+  layers::CompositorBridgeParentBase* mBridge;
+  RefPtr<widget::CompositorWidget> mCompositorWidget;
+  layers::SynchronousTask* mTask;
+  bool mEnableProfiler;
+};
+
+class RemoveRenderer : public RendererEvent
+{
+public:
+  explicit RemoveRenderer(layers::SynchronousTask* aTask)
+    : mTask(aTask)
+  {
+    MOZ_COUNT_CTOR(RemoveRenderer);
+  }
+
+  ~RemoveRenderer()
+  {
+    MOZ_COUNT_DTOR(RemoveRenderer);
+  }
+
+  virtual void Run(RenderThread& aRenderThread, WindowId aWindowId) override
+  {
+    aRenderThread.RemoveRenderer(aWindowId);
+    layers::AutoCompleteTask complete(mTask);
+  }
+
+private:
+  layers::SynchronousTask* mTask;
+};
+
+
+//static
+already_AddRefed<WebRenderAPI>
+WebRenderAPI::Create(bool aEnableProfiler,
+                     layers::CompositorBridgeParentBase* aBridge,
+                     RefPtr<widget::CompositorWidget>&& aWidget)
+{
+  MOZ_ASSERT(aBridge);
+  MOZ_ASSERT(aWidget);
+
+  static uint64_t sNextId = 1;
+  WindowId id(sNextId++);
+
+  WrAPI* wrApi = nullptr;
+  GLint maxTextureSize = 0;
+
+  // Dispatch a synchronous task because the WrApi object needs to be created
+  // on the render thread. If need be we could delay waiting on this task until
+  // the next time we need to access the WrApi object.
+  layers::SynchronousTask task("Create Renderer");
+  auto event = MakeUnique<NewRenderer>(&wrApi, aBridge, &maxTextureSize,
+                                       Move(aWidget), &task, aEnableProfiler);
+  RenderThread::Get()->RunEvent(id, Move(event));
+
+  task.Wait();
+
+  if (!wrApi) {
+    return nullptr;
+  }
+
+  return RefPtr<WebRenderAPI>(new WebRenderAPI(wrApi, id, maxTextureSize)).forget();
+}
+
+WebRenderAPI::~WebRenderAPI()
+{
+  layers::SynchronousTask task("Destroy WebRenderAPI");
+  auto event = MakeUnique<RemoveRenderer>(&task);
+  RunOnRenderThread(Move(event));
+  task.Wait();
+
+  wr_api_delete(mWrApi);
+}
+
+void
+WebRenderAPI::SetRootDisplayList(gfx::Color aBgColor,
+                                 Epoch aEpoch,
+                                 LayerSize aViewportSize,
+                                 DisplayListBuilder& aBuilder)
+{
+  wr_api_set_root_display_list(mWrApi, aBuilder.mWrState,
+                               aEpoch.mHandle,
+                               aViewportSize.width, aViewportSize.height);
+}
+
+void
+WebRenderAPI::Readback(gfx::IntSize size,
+                       uint8_t *buffer,
+                       uint32_t buffer_size)
+{
+    class Readback : public RendererEvent
+    {
+        public:
+            explicit Readback(layers::SynchronousTask* aTask,
+                              gfx::IntSize aSize, uint8_t *aBuffer, uint32_t aBufferSize)
+                : mTask(aTask)
+                , mSize(aSize)
+                , mBuffer(aBuffer)
+                , mBufferSize(aBufferSize)
+            {
+                MOZ_COUNT_CTOR(Readback);
+            }
+
+            ~Readback()
+            {
+                MOZ_COUNT_DTOR(Readback);
+            }
+
+            virtual void Run(RenderThread& aRenderThread, WindowId aWindowId) override
+            {
+                aRenderThread.UpdateAndRender(aWindowId);
+                wr_renderer_readback(mSize.width, mSize.height, mBuffer, mBufferSize);
+                layers::AutoCompleteTask complete(mTask);
+            }
+
+            layers::SynchronousTask* mTask;
+            gfx::IntSize mSize;
+            uint8_t *mBuffer;
+            uint32_t mBufferSize;
+    };
+
+    layers::SynchronousTask task("Readback");
+    auto event = MakeUnique<Readback>(&task, size, buffer, buffer_size);
+    RunOnRenderThread(Move(event));
+
+    task.Wait();
+}
+
+void
+WebRenderAPI::SetRootPipeline(PipelineId aPipeline)
+{
+  wr_api_set_root_pipeline(mWrApi, aPipeline.mHandle);
+}
+
+ImageKey
+WebRenderAPI::AddImageBuffer(gfx::IntSize aSize,
+                             uint32_t aStride,
+                             gfx::SurfaceFormat aFormat,
+                             Range<uint8_t> aBytes)
+{
+  auto format = SurfaceFormatToWrImageFormat(aFormat).value();
+  return ImageKey(wr_api_add_image(mWrApi,
+                                   aSize.width, aSize.height,
+                                   aStride, format,
+                                   &aBytes[0], aBytes.length()));
+}
+
+ImageKey
+WebRenderAPI::AddExternalImageHandle(gfx::IntSize aSize,
+                                     gfx::SurfaceFormat aFormat,
+                                     uint64_t aHandle)
+{
+  auto format = SurfaceFormatToWrImageFormat(aFormat).value();
+  return ImageKey(wr_api_add_external_image_texture(mWrApi,
+                                                    aSize.width, aSize.height, format,
+                                                    aHandle));
+}
+
+void
+WebRenderAPI::UpdateImageBuffer(ImageKey aKey,
+                                gfx::IntSize aSize,
+                                gfx::SurfaceFormat aFormat,
+                                Range<uint8_t> aBytes)
+{
+  auto format = SurfaceFormatToWrImageFormat(aFormat).value();
+  wr_api_update_image(mWrApi,
+                      aKey.mHandle,
+                      aSize.width, aSize.height, format,
+                      &aBytes[0], aBytes.length());
+}
+
+void
+WebRenderAPI::DeleteImage(ImageKey aKey)
+{
+  wr_api_delete_image(mWrApi, aKey.mHandle);
+}
+
+wr::FontKey
+WebRenderAPI::AddRawFont(Range<uint8_t> aBytes)
+{
+  return wr::FontKey(wr_api_add_raw_font(mWrApi, &aBytes[0], aBytes.length()));
+}
+
+void
+WebRenderAPI::DeleteFont(wr::FontKey aKey)
+{
+  printf("XXX - WebRender does not seem to implement deleting a font! Leaking it...\n");
+}
+
+class EnableProfiler : public RendererEvent
+{
+public:
+  explicit EnableProfiler(bool aEnabled)
+    : mEnabled(aEnabled)
+  {
+    MOZ_COUNT_CTOR(EnableProfiler);
+  }
+
+  ~EnableProfiler()
+  {
+    MOZ_COUNT_DTOR(EnableProfiler);
+  }
+
+  virtual void Run(RenderThread& aRenderThread, WindowId aWindowId) override
+  {
+    auto renderer = aRenderThread.GetRenderer(aWindowId);
+    if (renderer) {
+      renderer->SetProfilerEnabled(mEnabled);
+    }
+  }
+
+private:
+  bool mEnabled;
+};
+
+void
+WebRenderAPI::SetProfilerEnabled(bool aEnabled)
+{
+  auto event = MakeUnique<EnableProfiler>(aEnabled);
+  RunOnRenderThread(Move(event));
+}
+
+void
+WebRenderAPI::RunOnRenderThread(UniquePtr<RendererEvent> aEvent)
+{
+  auto event = reinterpret_cast<uintptr_t>(aEvent.release());
+  wr_api_send_external_event(mWrApi, event);
+}
+
+DisplayListBuilder::DisplayListBuilder(const LayerIntSize& aSize, PipelineId aId)
+{
+  MOZ_COUNT_CTOR(DisplayListBuilder);
+  mWrState = wr_state_new(aSize.width, aSize.height, aId.mHandle);
+}
+
+DisplayListBuilder::~DisplayListBuilder()
+{
+  MOZ_COUNT_DTOR(DisplayListBuilder);
+  wr_state_delete(mWrState);
+}
+
+void
+DisplayListBuilder::Begin(const LayerIntSize& aSize)
+{
+  wr_dp_begin(mWrState, aSize.width, aSize.height);
+}
+
+void
+DisplayListBuilder::End(WebRenderAPI& aApi, Epoch aEpoch)
+{
+  wr_dp_end(mWrState, aApi.mWrApi, aEpoch.mHandle);
+}
+
+void
+DisplayListBuilder::PushStackingContext(const WrRect& aBounds,
+                                        const WrRect& aOverflow,
+                                        const WrImageMask* aMask,
+                                        const float aOpacity,
+                                        const gfx::Matrix4x4& aTransform,
+                                        const WrMixBlendMode& aMi