Bug 1337130 - Create a DisplayItemLayer type. r=mattwoodrow
authorMason Chang <mchang@mozilla.com>
Tue, 14 Feb 2017 13:49:27 -0800
changeset 344051 48b29a84e4e507b596e92e106a8ef03d644cff2a
parent 344050 501ad90b7bb0f6217d08448e422dee1c3edb50f5
child 344052 b242c7944db3f3f7527924b71a49ebffdbe26690
push id87277
push userkwierso@gmail.com
push dateWed, 22 Feb 2017 01:41:20 +0000
treeherdermozilla-inbound@988dd3817ad4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow
bugs1337130
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
Bug 1337130 - Create a DisplayItemLayer type. r=mattwoodrow
gfx/layers/LayerTreeInvalidation.cpp
gfx/layers/Layers.cpp
gfx/layers/Layers.h
gfx/layers/basic/BasicDisplayItemLayer.cpp
gfx/layers/basic/BasicLayerManager.cpp
gfx/layers/basic/BasicLayers.h
gfx/layers/client/ClientLayerManager.h
gfx/layers/ipc/CompositorBridgeParent.cpp
gfx/layers/moz.build
gfx/layers/protobuf/LayerScopePacket.pb.h
gfx/layers/wr/WebRenderImageHost.cpp
gfx/layers/wr/WebRenderImageLayer.cpp
gfx/thebes/gfxPrefs.h
layout/base/nsCaret.cpp
layout/base/nsCaret.h
layout/painting/nsDisplayList.cpp
layout/painting/nsDisplayList.h
--- a/gfx/layers/LayerTreeInvalidation.cpp
+++ b/gfx/layers/LayerTreeInvalidation.cpp
@@ -732,16 +732,17 @@ CloneLayerTreePropertiesInternal(Layer* 
     case Layer::TYPE_IMAGE:
       return MakeUnique<ImageLayerProperties>(static_cast<ImageLayer*>(aRoot), aIsMask);
     case Layer::TYPE_CANVAS:
       return MakeUnique<CanvasLayerProperties>(static_cast<CanvasLayer*>(aRoot));
     case Layer::TYPE_BORDER:
       return MakeUnique<BorderLayerProperties>(static_cast<BorderLayer*>(aRoot));
     case Layer::TYPE_TEXT:
       return MakeUnique<TextLayerProperties>(static_cast<TextLayer*>(aRoot));
+    case Layer::TYPE_DISPLAYITEM:
     case Layer::TYPE_READBACK:
     case Layer::TYPE_SHADOW:
     case Layer::TYPE_PAINTED:
       return MakeUnique<LayerPropertiesBase>(aRoot);
   }
 
   MOZ_ASSERT_UNREACHABLE("Unexpected root layer type");
   return MakeUnique<LayerPropertiesBase>(aRoot);
--- a/gfx/layers/Layers.cpp
+++ b/gfx/layers/Layers.cpp
@@ -37,16 +37,17 @@
 #include "mozilla/layers/LayerManagerComposite.h"  // for LayerComposite
 #include "mozilla/layers/LayerMetricsWrapper.h" // for LayerMetricsWrapper
 #include "mozilla/layers/LayersMessages.h"  // for TransformFunction, etc
 #include "mozilla/layers/LayersTypes.h"  // for TextureDumpMode
 #include "mozilla/layers/PersistentBufferProvider.h"
 #include "mozilla/layers/ShadowLayers.h"  // for ShadowableLayer
 #include "nsAString.h"
 #include "nsCSSValue.h"                 // for nsCSSValue::Array, etc
+#include "nsDisplayList.h"              // for nsDisplayItem
 #include "nsPrintfCString.h"            // for nsPrintfCString
 #include "nsStyleStruct.h"              // for nsTimingFunction, etc
 #include "protobuf/LayerScopePacket.pb.h"
 #include "mozilla/Compression.h"
 #include "TreeTraversal.h"              // for ForEachNode
 
 #include <deque>
 #include <set>
@@ -2117,16 +2118,44 @@ ContainerLayer::DumpPacket(layerscope::L
   Layer::DumpPacket(aPacket, aParent);
   // Get this layer data
   using namespace layerscope;
   LayersPacket::Layer* layer = aPacket->mutable_layer(aPacket->layer_size()-1);
   layer->set_type(LayersPacket::Layer::ContainerLayer);
 }
 
 void
+DisplayItemLayer::EndTransaction() {
+  mItem = nullptr;
+  mBuilder = nullptr;
+}
+
+void
+DisplayItemLayer::PrintInfo(std::stringstream& aStream, const char* aPrefix)
+{
+  Layer::PrintInfo(aStream, aPrefix);
+  const char* type = "TYPE_UNKNOWN";
+  if (mItem) {
+    type = mItem->Name();
+  }
+
+  aStream << " [itype type=" << type << "]";
+}
+
+void
+DisplayItemLayer::DumpPacket(layerscope::LayersPacket* aPacket, const void* aParent)
+{
+  Layer::DumpPacket(aPacket, aParent);
+  // Get this layer data
+  using namespace layerscope;
+  LayersPacket::Layer* layer = aPacket->mutable_layer(aPacket->layer_size()-1);
+  layer->set_type(LayersPacket::Layer::DisplayItemLayer);
+}
+
+void
 ColorLayer::PrintInfo(std::stringstream& aStream, const char* aPrefix)
 {
   Layer::PrintInfo(aStream, aPrefix);
   AppendToString(aStream, mColor, " [color=", "]");
   AppendToString(aStream, mBounds, " [bounds=", "]");
 }
 
 void
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -48,16 +48,18 @@
 #include "nsTArray.h"                   // for nsTArray
 #include "nsTArrayForwardDeclare.h"     // for InfallibleTArray
 #include "nscore.h"                     // for nsACString, nsAString
 #include "mozilla/Logging.h"                      // for PRLogModuleInfo
 #include "nsIWidget.h"                  // For plugin window configuration information structs
 #include "ImageContainer.h"
 
 class gfxContext;
+class nsDisplayListBuilder;
+class nsDisplayItem;
 
 extern uint8_t gLayerManagerLayerBuilder;
 
 namespace mozilla {
 
 class ComputedTimingFunction;
 class FrameLayerBuilder;
 class StyleAnimationValue;
@@ -78,16 +80,17 @@ class AsyncCanvasRenderer;
 class AsyncPanZoomController;
 class BasicLayerManager;
 class ClientLayerManager;
 class Layer;
 class LayerMetricsWrapper;
 class PaintedLayer;
 class ContainerLayer;
 class ImageLayer;
+class DisplayItemLayer;
 class ColorLayer;
 class CompositorBridgeChild;
 class TextLayer;
 class CanvasLayer;
 class BorderLayer;
 class ReadbackLayer;
 class ReadbackProcessor;
 class RefLayer;
@@ -434,18 +437,21 @@ public:
    * Create a ReadbackLayer for this manager's layer tree.
    */
   virtual already_AddRefed<ReadbackLayer> CreateReadbackLayer() { return nullptr; }
   /**
    * CONSTRUCTION PHASE ONLY
    * Create a RefLayer for this manager's layer tree.
    */
   virtual already_AddRefed<RefLayer> CreateRefLayer() { return nullptr; }
-
-
+  /**
+   * CONSTRUCTION PHASE ONLY
+   * Create a DisplayItemLayer for this manager's layer tree.
+   */
+  virtual already_AddRefed<DisplayItemLayer> CreateDisplayItemLayer() { return nullptr; }
   /**
    * Can be called anytime, from any thread.
    *
    * Creates an Image container which forwards its images to the compositor within
    * layer transactions on the main thread or asynchronously using the ImageBridge IPDL protocol.
    * In the case of asynchronous, If the protocol is not available, the returned ImageContainer
    * will forward images within layer transactions.
    */
@@ -775,16 +781,17 @@ class Layer {
   typedef InfallibleTArray<Animation> AnimationArray;
 
 public:
   // Keep these in alphabetical order
   enum LayerType {
     TYPE_CANVAS,
     TYPE_COLOR,
     TYPE_CONTAINER,
+    TYPE_DISPLAYITEM,
     TYPE_IMAGE,
     TYPE_TEXT,
     TYPE_BORDER,
     TYPE_READBACK,
     TYPE_REF,
     TYPE_SHADOW,
     TYPE_PAINTED
   };
@@ -1564,16 +1571,22 @@ public:
   virtual HostLayer* AsHostLayer() { return nullptr; }
 
   /**
    * Dynamic cast to a ShadowableLayer.  Return null if this is not a
    * ShadowableLayer.  Can be used anytime.
    */
   virtual ShadowableLayer* AsShadowableLayer() { return nullptr; }
 
+  /**
+   * Dynamic cast as a DisplayItemLayer. Return null if not a
+   * DisplayItemLayer. Can be used anytime.
+   */
+  virtual DisplayItemLayer* AsDisplayItemLayer() { return nullptr; }
+
   // These getters can be used anytime.  They return the effective
   // values that should be used when drawing this layer to screen,
   // accounting for this layer possibly being a shadow.
   const Maybe<ParentLayerIntRect>& GetLocalClipRect();
   const LayerIntRegion& GetLocalVisibleRegion();
 
   bool Extend3DContext() {
     return GetContentFlags() & CONTENT_EXTEND_3D_CONTEXT;
@@ -2301,16 +2314,71 @@ protected:
   bool mMayHaveReadbackChild;
   // This is updated by ComputeDifferences. This will be true if we need to invalidate
   // the intermediate surface.
   bool mChildrenChanged;
   EventRegionsOverride mEventRegionsOverride;
 };
 
 /**
+ * A generic layer that references back to its display item.
+ *
+ * In order to not throw away information early in the pipeline from layout -> webrender,
+ * we'd like a generic layer type that can represent all the nsDisplayItems instead of
+ * creating a new layer type for each nsDisplayItem for Webrender. Another option
+ * is to break down nsDisplayItems into smaller nsDisplayItems early in the pipeline.
+ * The problem with this is that the whole pipeline would have to deal with more
+ * display items, which is slower.
+ *
+ * An alternative is to create a DisplayItemLayer, but the wrinkle with this is that
+ * it has a pointer to its nsDisplayItem. Managing the lifetime is key as display items
+ * only live as long as their display list builder, which goes away at the end of a paint.
+ * Layers however, are retained between paints.
+ * It's ok to recycle a DisplayItemLayer for a different display item since its just a pointer.
+ * Instead, when a layer transaction is completed, it is up to the layer manager to tell
+ * DisplayItemLayers that the display item pointer is no longer valid.
+ */
+class DisplayItemLayer : public Layer {
+  public:
+    virtual DisplayItemLayer* AsDisplayItemLayer() override { return this; }
+    void EndTransaction();
+
+    MOZ_LAYER_DECL_NAME("DisplayItemLayer", TYPE_DISPLAYITEM)
+
+    void SetDisplayItem(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder) {
+      mItem = aItem;
+      mBuilder = aBuilder;
+    }
+
+    nsDisplayItem* GetDisplayItem() { return mItem; }
+    nsDisplayListBuilder* GetDisplayListBuilder() { return mBuilder; }
+
+    virtual void ComputeEffectiveTransforms(const gfx::Matrix4x4& aTransformToSurface) override
+    {
+      gfx::Matrix4x4 idealTransform = GetLocalTransform() * aTransformToSurface;
+      mEffectiveTransform = SnapTransformTranslation(idealTransform, nullptr);
+      ComputeEffectiveTransformForMaskLayers(aTransformToSurface);
+    }
+
+  protected:
+    DisplayItemLayer(LayerManager* aManager, void* aImplData)
+      : Layer(aManager, aImplData)
+      , mItem(nullptr)
+  {}
+
+  virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) override;
+
+  virtual void DumpPacket(layerscope::LayersPacket* aPacket, const void* aParent) override;
+
+  // READ COMMENT ABOVE TO ENSURE WE DON'T HAVE A DANGLING POINTER
+  nsDisplayItem* mItem;
+  nsDisplayListBuilder* mBuilder;
+};
+
+/**
  * A Layer which just renders a solid color in its visible region. It actually
  * can fill any area that contains the visible region, so if you need to
  * restrict the area filled, set a clip region on this layer.
  */
 class ColorLayer : public Layer {
 public:
   virtual ColorLayer* AsColorLayer() override { return this; }
 
new file mode 100644
--- /dev/null
+++ b/gfx/layers/basic/BasicDisplayItemLayer.cpp
@@ -0,0 +1,84 @@
+/* -*- 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 "BasicLayersImpl.h"            // for FillRectWithMask, etc
+#include "Layers.h"                     // for Layer, etc
+#include "BasicImplData.h"              // for BasicImplData
+#include "BasicLayers.h"                // for BasicLayerManager
+#include "gfxContext.h"                 // for gfxContext, etc
+#include "gfxRect.h"                    // for gfxRect
+#include "gfx2DGlue.h"
+#include "mozilla/mozalloc.h"           // for operator new
+#include "nsCOMPtr.h"                   // for already_AddRefed
+#include "nsDebug.h"                    // for NS_ASSERTION
+#include "nsISupportsImpl.h"            // for Layer::AddRef, etc
+#include "nsRect.h"                     // for mozilla::gfx::IntRect
+#include "nsRegion.h"                   // for nsIntRegion
+#include "mozilla/gfx/PathHelpers.h"
+#include "nsDisplayList.h"              // for nsDisplayItem
+#include "nsCaret.h"
+
+using namespace mozilla::gfx;
+
+namespace mozilla {
+namespace layers {
+
+class BasicDisplayItemLayer : public DisplayItemLayer, public BasicImplData {
+public:
+  explicit BasicDisplayItemLayer(BasicLayerManager* aLayerManager) :
+    DisplayItemLayer(aLayerManager, static_cast<BasicImplData*>(this))
+  {
+    MOZ_COUNT_CTOR(BasicDisplayItemLayer);
+  }
+
+protected:
+  virtual ~BasicDisplayItemLayer()
+  {
+    MOZ_COUNT_DTOR(BasicDisplayItemLayer);
+  }
+
+public:
+  virtual void SetVisibleRegion(const LayerIntRegion& aRegion) override
+  {
+    NS_ASSERTION(BasicManager()->InConstruction(),
+                 "Can only set properties in construction phase");
+    DisplayItemLayer::SetVisibleRegion(aRegion);
+  }
+
+  virtual void Paint(DrawTarget* aDT,
+                     const gfx::Point& aDeviceOffset,
+                     Layer* aMaskLayer) override
+  {
+    if (IsHidden() || !mItem || !mBuilder) {
+      return;
+    }
+
+    AutoRestoreTransform autoRestoreTransform(aDT);
+    Matrix transform = aDT->GetTransform();
+    RefPtr<gfxContext> context = gfxContext::CreateOrNull(aDT, aDeviceOffset);
+    context->SetMatrix(ThebesMatrix(transform));
+
+    nsRenderingContext ctx(context);
+    mItem->Paint(mBuilder, &ctx);
+  }
+
+protected:
+  BasicLayerManager* BasicManager()
+  {
+    return static_cast<BasicLayerManager*>(mManager);
+  }
+};
+
+already_AddRefed<DisplayItemLayer>
+BasicLayerManager::CreateDisplayItemLayer()
+{
+  NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
+  RefPtr<DisplayItemLayer> layer = new BasicDisplayItemLayer(this);
+  mDisplayItemLayers.AppendElement(layer);
+  return layer.forget();
+}
+
+} // namespace layers
+} // namespace mozilla
--- a/gfx/layers/basic/BasicLayerManager.cpp
+++ b/gfx/layers/basic/BasicLayerManager.cpp
@@ -541,16 +541,28 @@ ApplyDoubleBuffering(Layer* aLayer, cons
 void
 BasicLayerManager::EndTransaction(DrawPaintedLayerCallback aCallback,
                                   void* aCallbackData,
                                   EndTransactionFlags aFlags)
 {
   mInTransaction = false;
 
   EndTransactionInternal(aCallback, aCallbackData, aFlags);
+
+  ClearDisplayItemLayers();
+}
+
+void
+BasicLayerManager::ClearDisplayItemLayers()
+{
+  for (uint32_t i = 0; i < mDisplayItemLayers.Length(); i++) {
+    mDisplayItemLayers[i]->EndTransaction();
+  }
+
+  mDisplayItemLayers.Clear();
 }
 
 void
 BasicLayerManager::AbortTransaction()
 {
   NS_ASSERTION(InConstruction(), "Should be in construction phase");
   mPhase = PHASE_NONE;
   mUsingDefaultTarget = false;
@@ -729,17 +741,17 @@ BasicLayerManager::PaintSelfOrChildren(P
       if (layer->IsBackfaceHidden()) {
         continue;
       }
       if (!layer->AsContainerLayer() && !layer->IsVisible()) {
         continue;
       }
 
       PaintLayer(aGroupTarget, layer, aPaintContext.mCallback,
-          aPaintContext.mCallbackData);
+                aPaintContext.mCallbackData);
       if (mTransactionIncomplete)
         break;
     }
   }
 }
 
 void
 BasicLayerManager::FlushGroup(PaintLayerContext& aPaintContext, bool aNeedsClipToVisibleRegion)
@@ -811,17 +823,18 @@ BasicLayerManager::PaintLayer(gfxContext
                               DrawPaintedLayerCallback aCallback,
                               void* aCallbackData)
 {
   MOZ_ASSERT(aTarget);
 
   PROFILER_LABEL("BasicLayerManager", "PaintLayer",
     js::ProfileEntry::Category::GRAPHICS);
 
-  PaintLayerContext paintLayerContext(aTarget, aLayer, aCallback, aCallbackData);
+  PaintLayerContext paintLayerContext(aTarget, aLayer,
+                                      aCallback, aCallbackData);
 
   // Don't attempt to paint layers with a singular transform, cairo will
   // just throw an error.
   if (aLayer->GetEffectiveTransform().IsSingular()) {
     return;
   }
 
   RenderTraceScope trace("BasicLayerManager::PaintLayer", "707070");
--- a/gfx/layers/basic/BasicLayers.h
+++ b/gfx/layers/basic/BasicLayers.h
@@ -19,16 +19,17 @@
 #include "nsRegion.h"                   // for nsIntRegion
 #include "nscore.h"                     // for nsAString, etc
 
 class nsIWidget;
 
 namespace mozilla {
 namespace layers {
 
+class DisplayItemLayer;
 class ImageFactory;
 class ImageLayer;
 class PaintLayerContext;
 class ReadbackLayer;
 
 /**
  * This is a cairo/Thebes-only, main-thread-only implementation of layers.
  * 
@@ -112,16 +113,17 @@ public:
   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<ColorLayer> CreateColorLayer() override;
   virtual already_AddRefed<TextLayer> CreateTextLayer() override;
   virtual already_AddRefed<BorderLayer> CreateBorderLayer() override;
   virtual already_AddRefed<ReadbackLayer> CreateReadbackLayer() override;
+  virtual already_AddRefed<DisplayItemLayer> CreateDisplayItemLayer() override;
   virtual ImageFactory *GetImageFactory();
 
   virtual LayersBackend GetBackendType() override { return LayersBackend::LAYERS_BASIC; }
   virtual void GetBackendName(nsAString& name) override { name.AssignLiteral("Basic"); }
 
   bool InConstruction() { return mPhase == PHASE_CONSTRUCTION; }
 #ifdef DEBUG
   bool InDrawing() { return mPhase == PHASE_DRAWING; }
@@ -206,14 +208,22 @@ protected:
   // Image factory we use.
   RefPtr<ImageFactory> mFactory;
 
   BufferMode mDoubleBuffering;
   BasicLayerManagerType mType;
   bool mUsingDefaultTarget;
   bool mTransactionIncomplete;
   bool mCompositorMightResample;
+
+private:
+  // Display items are only valid during this transaction.
+  // At the end of the transaction, we have to go and clear out
+  // DisplayItemLayer's and null their display item. See comment
+  // above DisplayItemLayer declaration.
+  void ClearDisplayItemLayers();
+  nsTArray<RefPtr<DisplayItemLayer>> mDisplayItemLayers;
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif /* GFX_BASICLAYERS_H */
--- a/gfx/layers/client/ClientLayerManager.h
+++ b/gfx/layers/client/ClientLayerManager.h
@@ -21,16 +21,18 @@
 #include "nsIObserver.h"                // for nsIObserver
 #include "nsISupportsImpl.h"            // for Layer::Release, etc
 #include "nsRect.h"                     // for mozilla::gfx::IntRect
 #include "nsTArray.h"                   // for nsTArray
 #include "nscore.h"                     // for nsAString
 #include "mozilla/layers/TransactionIdAllocator.h"
 #include "nsIWidget.h"                  // For plugin window configuration information structs
 
+class nsDisplayListBuilder;
+
 namespace mozilla {
 namespace layers {
 
 class ClientPaintedLayer;
 class CompositorBridgeChild;
 class ImageLayer;
 class FrameUniformityData;
 
--- a/gfx/layers/ipc/CompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CompositorBridgeParent.cpp
@@ -29,16 +29,17 @@
 #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/gfx/gfxVars.h"
 #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
 #include "mozilla/layers/CompositorOGL.h"  // for CompositorOGL
 #include "mozilla/layers/CompositorThread.h"
--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -288,16 +288,17 @@ UNIFIED_SOURCES += [
     'AsyncCanvasRenderer.cpp',
     'AxisPhysicsModel.cpp',
     'AxisPhysicsMSDModel.cpp',
     'basic/BasicBorderLayer.cpp',
     'basic/BasicCanvasLayer.cpp',
     'basic/BasicColorLayer.cpp',
     'basic/BasicCompositor.cpp',
     'basic/BasicContainerLayer.cpp',
+    'basic/BasicDisplayItemLayer.cpp',
     'basic/BasicImages.cpp',
     'basic/BasicLayerManager.cpp',
     'basic/BasicLayersImpl.cpp',
     'basic/BasicPaintedLayer.cpp',
     'basic/BasicTextLayer.cpp',
     'basic/TextureHostBasic.cpp',
     'BSPTree.cpp',
     'BufferTexture.cpp',
--- a/gfx/layers/protobuf/LayerScopePacket.pb.h
+++ b/gfx/layers/protobuf/LayerScopePacket.pb.h
@@ -69,17 +69,18 @@ enum LayersPacket_Layer_LayerType {
   LayersPacket_Layer_LayerType_LayerManager = 1,
   LayersPacket_Layer_LayerType_ContainerLayer = 2,
   LayersPacket_Layer_LayerType_PaintedLayer = 3,
   LayersPacket_Layer_LayerType_CanvasLayer = 4,
   LayersPacket_Layer_LayerType_ImageLayer = 5,
   LayersPacket_Layer_LayerType_ColorLayer = 6,
   LayersPacket_Layer_LayerType_TextLayer = 7,
   LayersPacket_Layer_LayerType_RefLayer = 8,
-  LayersPacket_Layer_LayerType_ReadbackLayer = 9
+  LayersPacket_Layer_LayerType_ReadbackLayer = 9,
+  LayersPacket_Layer_LayerType_DisplayItemLayer = 10
 };
 bool LayersPacket_Layer_LayerType_IsValid(int value);
 const LayersPacket_Layer_LayerType LayersPacket_Layer_LayerType_LayerType_MIN = LayersPacket_Layer_LayerType_UnknownLayer;
 const LayersPacket_Layer_LayerType LayersPacket_Layer_LayerType_LayerType_MAX = LayersPacket_Layer_LayerType_ReadbackLayer;
 const int LayersPacket_Layer_LayerType_LayerType_ARRAYSIZE = LayersPacket_Layer_LayerType_LayerType_MAX + 1;
 
 enum LayersPacket_Layer_ScrollingDirect {
   LayersPacket_Layer_ScrollingDirect_VERTICAL = 1,
@@ -1669,16 +1670,17 @@ class LayersPacket_Layer : public ::goog
   typedef LayersPacket_Layer_LayerType LayerType;
   static const LayerType UnknownLayer = LayersPacket_Layer_LayerType_UnknownLayer;
   static const LayerType LayerManager = LayersPacket_Layer_LayerType_LayerManager;
   static const LayerType ContainerLayer = LayersPacket_Layer_LayerType_ContainerLayer;
   static const LayerType PaintedLayer = LayersPacket_Layer_LayerType_PaintedLayer;
   static const LayerType CanvasLayer = LayersPacket_Layer_LayerType_CanvasLayer;
   static const LayerType ImageLayer = LayersPacket_Layer_LayerType_ImageLayer;
   static const LayerType ColorLayer = LayersPacket_Layer_LayerType_ColorLayer;
+  static const LayerType DisplayItemLayer = LayersPacket_Layer_LayerType_DisplayItemLayer;
   static const LayerType TextLayer = LayersPacket_Layer_LayerType_TextLayer;
   static const LayerType RefLayer = LayersPacket_Layer_LayerType_RefLayer;
   static const LayerType ReadbackLayer = LayersPacket_Layer_LayerType_ReadbackLayer;
   static inline bool LayerType_IsValid(int value) {
     return LayersPacket_Layer_LayerType_IsValid(value);
   }
   static const LayerType LayerType_MIN =
     LayersPacket_Layer_LayerType_LayerType_MIN;
--- a/gfx/layers/wr/WebRenderImageHost.cpp
+++ b/gfx/layers/wr/WebRenderImageHost.cpp
@@ -1,16 +1,15 @@
 /* -*- 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 "WebRenderLayersLogging.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
--- a/gfx/layers/wr/WebRenderImageLayer.cpp
+++ b/gfx/layers/wr/WebRenderImageLayer.cpp
@@ -1,16 +1,15 @@
 /* -*- 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 "WebRenderLayersLogging.h"
 #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 {
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -450,16 +450,17 @@ private:
   DECL_GFX_PREF(Once, "layers.acceleration.disabled",          LayersAccelerationDisabledDoNotUseDirectly, bool, false);
   DECL_GFX_PREF(Live, "layers.acceleration.draw-fps",          LayersDrawFPS, bool, false);
   DECL_GFX_PREF(Live, "layers.acceleration.draw-fps.print-histogram",  FPSPrintHistogram, bool, false);
   DECL_GFX_PREF(Live, "layers.acceleration.draw-fps.write-to-file", WriteFPSToFile, bool, false);
   DECL_GFX_PREF(Once, "layers.acceleration.force-enabled",     LayersAccelerationForceEnabledDoNotUseDirectly, bool, false);
   DECL_GFX_PREF(Live, "layers.advanced.border-layers",         LayersAllowBorderLayers, bool, false);
   DECL_GFX_PREF(Live, "layers.advanced.text-layers",           LayersAllowTextLayers, bool, false);
   DECL_GFX_PREF(Live, "layers.advanced.bullet-layers",         LayersAllowBulletLayers, bool, false);
+  DECL_GFX_PREF(Live, "layers.advanced.caret-layers",          LayersAllowCaretLayers, bool, false);
   DECL_GFX_PREF(Once, "layers.allow-d3d9-fallback",            LayersAllowD3D9Fallback, bool, false);
   DECL_GFX_PREF(Once, "layers.amd-switchable-gfx.enabled",     LayersAMDSwitchableGfxEnabled, bool, false);
   DECL_GFX_PREF(Once, "layers.async-pan-zoom.enabled",         AsyncPanZoomEnabledDoNotUseDirectly, bool, true);
   DECL_GFX_PREF(Once, "layers.async-pan-zoom.separate-event-thread", AsyncPanZoomSeparateEventThread, bool, false);
   DECL_GFX_PREF(Live, "layers.bench.enabled",                  LayersBenchEnabled, bool, false);
   DECL_GFX_PREF(Once, "layers.bufferrotation.enabled",         BufferRotationEnabled, bool, true);
   DECL_GFX_PREF(Live, "layers.child-process-shutdown",         ChildProcessShutdown, bool, true);
 #ifdef MOZ_GFX_OPTIMIZE_MOBILE
--- a/layout/base/nsCaret.cpp
+++ b/layout/base/nsCaret.cpp
@@ -532,23 +532,30 @@ nsCaret::GetPaintGeometry(nsRect* aRect)
   nsRect caretRect;
   nsRect hookRect;
   ComputeCaretRects(frame, frameOffset, &caretRect, &hookRect);
 
   aRect->UnionRect(caretRect, hookRect);
   return frame;
 }
 
+nsIFrame*
+nsCaret::GetFrame(int32_t* aContentOffset) {
+  return GetFrameAndOffset(GetSelectionInternal(),
+                           mOverrideContent,
+                           mOverrideOffset,
+                           aContentOffset);
+}
+
 void nsCaret::PaintCaret(DrawTarget& aDrawTarget,
                          nsIFrame* aForFrame,
                          const nsPoint &aOffset)
 {
   int32_t contentOffset;
-  nsIFrame* frame = GetFrameAndOffset(GetSelectionInternal(),
-    mOverrideContent, mOverrideOffset, &contentOffset);
+  nsIFrame* frame = GetFrame(&contentOffset);
   if (!frame) {
     return;
   }
   NS_ASSERTION(frame == aForFrame, "We're referring different frame");
 
   int32_t appUnitsPerDevPixel = frame->PresContext()->AppUnitsPerDevPixel();
 
   nsRect caretRect;
--- a/layout/base/nsCaret.h
+++ b/layout/base/nsCaret.h
@@ -174,16 +174,20 @@ class nsCaret final : public nsISelectio
     // @return the frame of the focus node.
     static nsIFrame* GetFrameAndOffset(mozilla::dom::Selection* aSelection,
                                        nsINode* aOverrideNode,
                                        int32_t aOverrideOffset,
                                        int32_t* aFrameOffset);
 
     size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
 
+    nsIFrame*     GetFrame(int32_t* aContentOffset);
+    void          ComputeCaretRects(nsIFrame* aFrame, int32_t aFrameOffset,
+                                    nsRect* aCaretRect, nsRect* aHookRect);
+
 protected:
     static void   CaretBlinkCallback(nsITimer *aTimer, void *aClosure);
 
     void          CheckSelectionLanguageChange();
 
     void          ResetBlinking();
     void          StopBlinking();
 
@@ -191,19 +195,16 @@ protected:
 
     struct Metrics {
       nscoord mBidiIndicatorSize; // width and height of bidi indicator
       nscoord mCaretWidth;        // full caret width including bidi indicator
     };
     static Metrics ComputeMetrics(nsIFrame* aFrame, int32_t aOffset,
                                   nscoord aCaretHeight);
 
-    void          ComputeCaretRects(nsIFrame* aFrame, int32_t aFrameOffset,
-                                    nsRect* aCaretRect, nsRect* aHookRect);
-
     // Returns true if we should not draw the caret because of XUL menu popups.
     // The caret should be hidden if:
     // 1. An open popup contains the caret, but a menu popup exists before the
     //    caret-owning popup in the popup list (i.e. a menu is in front of the
     //    popup with the caret). If the menu itself contains the caret we don't
     //    hide it.
     // 2. A menu popup is open, but there is no caret present in any popup.
     // 3. The caret selection is empty.
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -76,16 +76,18 @@
 #include "mozilla/RestyleManager.h"
 #include "nsCaret.h"
 #include "nsISelection.h"
 #include "nsDOMTokenList.h"
 #include "mozilla/RuleNodeCacheConditions.h"
 #include "nsCSSProps.h"
 #include "nsPluginFrame.h"
 #include "nsSVGMaskFrame.h"
+#include "mozilla/layers/WebrenderLayerManager.h"
+#include "mozilla/layers/WebrenderMessages.h"
 
 // GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
 // GetTickCount().
 #ifdef GetCurrentTime
 #undef GetCurrentTime
 #endif
 
 using namespace mozilla;
@@ -2723,16 +2725,37 @@ nsDisplayItem::IntersectClip(nsDisplayLi
 nsRect
 nsDisplayItem::GetClippedBounds(nsDisplayListBuilder* aBuilder)
 {
   bool snap;
   nsRect r = GetBounds(aBuilder, &snap);
   return GetClip().ApplyNonRoundedIntersection(r);
 }
 
+already_AddRefed<Layer>
+nsDisplayItem::BuildDisplayItemLayer(nsDisplayListBuilder* aBuilder,
+                                     LayerManager* aManager,
+                                     const ContainerLayerParameters& aContainerParameters)
+{
+  RefPtr<DisplayItemLayer> layer = static_cast<DisplayItemLayer*>
+    (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, this));
+  if (!layer) {
+    layer = aManager->CreateDisplayItemLayer();
+
+    if (!layer) {
+      return nullptr;
+    }
+  }
+
+  layer->SetDisplayItem(this, aBuilder);
+  layer->SetBaseTransform(gfx::Matrix4x4::Translation(aContainerParameters.mOffset.x,
+                                                      aContainerParameters.mOffset.y, 0));
+  return layer.forget();
+}
+
 nsRect
 nsDisplaySolidColor::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
 {
   *aSnap = true;
   return mBounds;
 }
 
 void
@@ -4316,16 +4339,79 @@ nsDisplayCaret::GetBounds(nsDisplayListB
 void
 nsDisplayCaret::Paint(nsDisplayListBuilder* aBuilder,
                       nsRenderingContext* aCtx) {
   // Note: Because we exist, we know that the caret is visible, so we don't
   // need to check for the caret's visibility.
   mCaret->PaintCaret(*aCtx->GetDrawTarget(), mFrame, ToReferenceFrame());
 }
 
+void
+nsDisplayCaret::CreateWebRenderCommands(nsTArray<WebRenderCommand>& aCommands,
+                                        WebRenderLayer* aLayer) {
+  using namespace mozilla::layers;
+  int32_t contentOffset;
+  nsIFrame* frame = mCaret->GetFrame(&contentOffset);
+  if (!frame) {
+    return;
+  }
+  NS_ASSERTION(frame == mFrame, "We're referring different frame");
+
+  int32_t appUnitsPerDevPixel = frame->PresContext()->AppUnitsPerDevPixel();
+
+  nsRect caretRect;
+  nsRect hookRect;
+  mCaret->ComputeCaretRects(frame, contentOffset, &caretRect, &hookRect);
+
+  gfx::Color color = ToDeviceColor(frame->GetCaretColorAt(contentOffset));
+  Rect devCaretRect =
+    NSRectToRect(caretRect + ToReferenceFrame(), appUnitsPerDevPixel);
+  Rect devHookRect =
+    NSRectToRect(hookRect + ToReferenceFrame(), appUnitsPerDevPixel);
+
+  Rect caretTransformedRect = aLayer->RelativeToParent(devCaretRect);
+  Rect hookTransformedRect = aLayer->RelativeToParent(devHookRect);
+
+  IntRect caret = RoundedToInt(caretTransformedRect);
+  IntRect hook = RoundedToInt(hookTransformedRect);
+
+  // Note, WR will pixel snap anything that is layout aligned.
+  aCommands.AppendElement(OpDPPushRect(
+                          wr::ToWrRect(caret),
+                          wr::ToWrRect(caret),
+                          wr::ToWrColor(color)));
+
+  if (!devHookRect.IsEmpty()) {
+    aCommands.AppendElement(OpDPPushRect(
+                            wr::ToWrRect(hook),
+                            wr::ToWrRect(hook),
+                            wr::ToWrColor(color)));
+  }
+}
+
+LayerState
+nsDisplayCaret::GetLayerState(nsDisplayListBuilder* aBuilder,
+                              LayerManager* aManager,
+                              const ContainerLayerParameters& aParameters)
+{
+  if (gfxPrefs::LayersAllowCaretLayers()) {
+    return LAYER_ACTIVE;
+  }
+
+  return LAYER_INACTIVE;
+}
+
+already_AddRefed<Layer>
+nsDisplayCaret::BuildLayer(nsDisplayListBuilder* aBuilder,
+                           LayerManager* aManager,
+                           const ContainerLayerParameters& aContainerParameters)
+{
+  return BuildDisplayItemLayer(aBuilder, aManager, aContainerParameters);
+}
+
 nsDisplayBorder::nsDisplayBorder(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
   : nsDisplayItem(aBuilder, aFrame)
 {
   MOZ_COUNT_CTOR(nsDisplayBorder);
 
   mBounds = CalculateBounds(*mFrame->StyleBorder()).GetBounds();
 }
 
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -52,16 +52,18 @@ class nsDisplayScrollInfoLayer;
 class nsCaret;
 
 namespace mozilla {
 class FrameLayerBuilder;
 namespace layers {
 class Layer;
 class ImageLayer;
 class ImageContainer;
+class WebRenderCommand;
+class WebRenderLayer;
 } // namespace layers
 } // namespace mozilla
 
 // A set of blend modes, that never includes OP_OVER (since it's
 // considered the default, rather than a specific blend mode).
 typedef mozilla::EnumSet<mozilla::gfx::CompositionOp> BlendModeSet;
 
 /*
@@ -1579,17 +1581,20 @@ public:
   typedef mozilla::DisplayItemClip DisplayItemClip;
   typedef mozilla::DisplayItemClipChain DisplayItemClipChain;
   typedef mozilla::ActiveScrolledRoot ActiveScrolledRoot;
   typedef mozilla::layers::FrameMetrics FrameMetrics;
   typedef mozilla::layers::ScrollMetadata ScrollMetadata;
   typedef mozilla::layers::FrameMetrics::ViewID ViewID;
   typedef mozilla::layers::Layer Layer;
   typedef mozilla::layers::LayerManager LayerManager;
+  typedef mozilla::layers::WebRenderCommand WebRenderCommand;
+  typedef mozilla::layers::WebRenderLayer WebRenderLayer;
   typedef mozilla::LayerState LayerState;
+  typedef class mozilla::gfx::DrawTarget DrawTarget;
 
   // This is never instantiated directly (it has pure virtual methods), so no
   // need to count constructors and destructors.
   nsDisplayItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame);
   nsDisplayItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                 const ActiveScrolledRoot* aActiveScrolledRoot);
   /**
    * This constructor is only used in rare cases when we need to construct
@@ -1913,16 +1918,31 @@ public:
    * constructed.
    */
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager,
                                              const ContainerLayerParameters& aContainerParameters)
   { return nullptr; }
 
   /**
+    * Create the WebRenderCommands required to paint this display item.
+    * The layer this item is in is passed in as rects must be relative
+    * to their parent.
+    */
+   virtual void CreateWebRenderCommands(nsTArray<WebRenderCommand>& aCommands,
+                                        WebRenderLayer* aLayer) {}
+  /**
+   * Builds a DisplayItemLayer and sets the display item to this.
+   */
+   already_AddRefed<Layer>
+   BuildDisplayItemLayer(nsDisplayListBuilder* aBuilder,
+                         LayerManager* aManager,
+                         const ContainerLayerParameters& aContainerParameters);
+
+  /**
    * On entry, aVisibleRegion contains the region (relative to ReferenceFrame())
    * which may be visible. If the display item opaquely covers an area, it
    * can remove that area from aVisibleRegion before returning.
    * nsDisplayList::ComputeVisibility automatically subtracts the region
    * returned by GetOpaqueRegion, and automatically removes items whose bounds
    * do not intersect the visible area, so implementations of
    * nsDisplayItem::ComputeVisibility do not need to do these things.
    * nsDisplayList::ComputeVisibility will already have set mVisibleRect on
@@ -2612,18 +2632,16 @@ public:
  * 
  * This should not be used for display items which are created frequently,
  * because each item is one or two pointers bigger than an item from a
  * custom display item class could be, and fractionally slower. However it does
  * save code size. We use this for infrequently-used item types.
  */
 class nsDisplayGeneric : public nsDisplayItem {
 public:
-  typedef class mozilla::gfx::DrawTarget DrawTarget;
-
   typedef void (* PaintCallback)(nsIFrame* aFrame, DrawTarget* aDrawTarget,
                                  const nsRect& aDirtyRect, nsPoint aFramePt);
 
   // XXX: should be removed eventually
   typedef void (* OldPaintCallback)(nsIFrame* aFrame, nsRenderingContext* aCtx,
                                     const nsRect& aDirtyRect, nsPoint aFramePt);
 
   nsDisplayGeneric(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
@@ -2794,16 +2812,25 @@ public:
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayCaret();
 #endif
 
   virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) override;
   virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) override;
   NS_DISPLAY_DECL_NAME("Caret", TYPE_CARET)
 
+  virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
+                                   LayerManager* aManager,
+                                   const ContainerLayerParameters& aParameters) override;
+  virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
+                                             LayerManager* aManager,
+                                             const ContainerLayerParameters& aContainerParameters) override;
+  virtual void CreateWebRenderCommands(nsTArray<WebRenderCommand>& aCommands,
+                                        WebRenderLayer* aLayer) override;
+
 protected:
   RefPtr<nsCaret> mCaret;
   nsRect mBounds;
 };
 
 /**
  * The standard display item to paint the CSS borders of a frame.
  */
@@ -4189,17 +4216,16 @@ protected:
 
 /**
  * A display item to paint a stacking context with mask and clip effects
  * set by the stacking context root frame's style.
  */
 class nsDisplayMask : public nsDisplaySVGEffects {
 public:
   typedef mozilla::layers::ImageLayer ImageLayer;
-  typedef class mozilla::gfx::DrawTarget DrawTarget;
 
   nsDisplayMask(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                 nsDisplayList* aList, bool aHandleOpacity,
                 const ActiveScrolledRoot* aActiveScrolledRoot);
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayMask();
 #endif