Bug 1317862 - Part 1: Add TextLayer class and basic support for them. r=mstange
authorMatt Woodrow <mwoodrow@mozilla.com>
Thu, 24 Nov 2016 18:11:29 +1300
changeset 324153 f2d4190eaaf8d0354f1c9aee3c940bc88e695bf5
parent 324152 880e9106f46dcb7d915358143e78574a7c0a1e3e
child 324154 7e55a4cc72d0f973b14676df25fecb12699565cd
push id24
push usermaklebus@msu.edu
push dateTue, 20 Dec 2016 03:11:33 +0000
reviewersmstange
bugs1317862
milestone53.0a1
Bug 1317862 - Part 1: Add TextLayer class and basic support for them. r=mstange
gfx/2d/2D.h
gfx/ipc/GfxMessageUtils.h
gfx/layers/LayerTreeInvalidation.cpp
gfx/layers/Layers.cpp
gfx/layers/Layers.h
gfx/layers/basic/BasicLayers.h
gfx/layers/basic/BasicTextLayer.cpp
gfx/layers/client/ClientLayerManager.h
gfx/layers/client/ClientTextLayer.cpp
gfx/layers/composite/LayerManagerComposite.cpp
gfx/layers/composite/LayerManagerComposite.h
gfx/layers/ipc/LayerTransactionParent.cpp
gfx/layers/ipc/LayersMessages.ipdlh
gfx/layers/ipc/ShadowLayerParent.cpp
gfx/layers/ipc/ShadowLayerParent.h
gfx/layers/ipc/ShadowLayers.cpp
gfx/layers/ipc/ShadowLayers.h
gfx/layers/moz.build
gfx/layers/protobuf/LayerScopePacket.pb.h
gfx/tests/gtest/TestLayers.cpp
--- a/gfx/2d/2D.h
+++ b/gfx/2d/2D.h
@@ -625,16 +625,20 @@ public:
 };
 
 struct Glyph
 {
   uint32_t mIndex;
   Point mPosition;
 };
 
+static inline bool operator==(const Glyph& aOne, const Glyph& aOther) {
+  return aOne.mIndex == aOther.mIndex && aOne.mPosition == aOther.mPosition;
+}
+
 /** This class functions as a glyph buffer that can be drawn to a DrawTarget.
  * @todo XXX - This should probably contain the guts of gfxTextRun in the future as
  * roc suggested. But for now it's a simple container for a glyph vector.
  */
 struct GlyphBuffer
 {
   const Glyph *mGlyphs; //!< A pointer to a buffer of glyphs. Managed by the caller.
   uint32_t mNumGlyphs;  //!< Number of glyphs mGlyphs points to.
@@ -659,17 +663,17 @@ struct GlyphMetrics
   // Height of the glyph's black box.
   Float mHeight;
 };
 
 /** This class is an abstraction of a backend/platform specific font object
  * at a particular size. It is passed into text drawing calls to describe
  * the font used for the drawing call.
  */
-class ScaledFont : public RefCounted<ScaledFont>
+class ScaledFont : public external::AtomicRefCounted<ScaledFont>
 {
 public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(ScaledFont)
   virtual ~ScaledFont() {}
 
   typedef void (*FontFileDataOutput)(const uint8_t *aData, uint32_t aLength, uint32_t aIndex, Float aGlyphSize, void *aBaton);
   typedef void (*FontDescriptorOutput)(const uint8_t *aData, uint32_t aLength, Float aFontSize, void *aBaton);
 
--- a/gfx/ipc/GfxMessageUtils.h
+++ b/gfx/ipc/GfxMessageUtils.h
@@ -1263,11 +1263,27 @@ struct ParamTraits<mozilla::layers::Asyn
             ReadParam(aMsg, aIter, &aResult->mPresShellId) &&
             ReadParam(aMsg, aIter, &aResult->mDragStartSequenceNumber) &&
             ReadParam(aMsg, aIter, &aResult->mScrollbarDragOffset) &&
             ReadParam(aMsg, aIter, &aResult->mScrollTrack) &&
             ReadParam(aMsg, aIter, &aResult->mDirection));
   }
 };
 
+template <>
+struct ParamTraits<mozilla::gfx::Glyph>
+{
+  typedef mozilla::gfx::Glyph paramType;
+  static void Write(Message* aMsg, const paramType& aParam) {
+    WriteParam(aMsg, aParam.mIndex);
+    WriteParam(aMsg, aParam.mPosition);
+  }
+
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult) {
+    return (ReadParam(aMsg, aIter, &aResult->mIndex) &&
+            ReadParam(aMsg, aIter, &aResult->mPosition)
+      );
+  }
+};
+
 } /* namespace IPC */
 
 #endif /* __GFXMESSAGEUTILS_H__ */
--- a/gfx/layers/LayerTreeInvalidation.cpp
+++ b/gfx/layers/LayerTreeInvalidation.cpp
@@ -604,16 +604,17 @@ CloneLayerTreePropertiesInternal(Layer* 
       return MakeUnique<ColorLayerProperties>(static_cast<ColorLayer*>(aRoot));
     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_READBACK:
     case Layer::TYPE_SHADOW:
     case Layer::TYPE_PAINTED:
+    case Layer::TYPE_TEXT:
       return MakeUnique<LayerPropertiesBase>(aRoot);
   }
 
   MOZ_ASSERT_UNREACHABLE("Unexpected root layer type");
   return MakeUnique<LayerPropertiesBase>(aRoot);
 }
 
 /* static */ UniquePtr<LayerProperties>
--- a/gfx/layers/Layers.cpp
+++ b/gfx/layers/Layers.cpp
@@ -2195,16 +2195,33 @@ ColorLayer::DumpPacket(layerscope::Layer
   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::ColorLayer);
   layer->set_color(mColor.ToABGR());
 }
 
+void
+TextLayer::PrintInfo(std::stringstream& aStream, const char* aPrefix)
+{
+  Layer::PrintInfo(aStream, aPrefix);
+  AppendToString(aStream, mBounds, " [bounds=", "]");
+}
+
+void
+TextLayer::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::TextLayer);
+}
+
 CanvasLayer::CanvasLayer(LayerManager* aManager, void* aImplData)
   : Layer(aManager, aImplData)
   , mPreTransCallback(nullptr)
   , mPreTransCallbackData(nullptr)
   , mPostTransCallback(nullptr)
   , mPostTransCallbackData(nullptr)
   , mSamplingFilter(gfx::SamplingFilter::GOOD)
   , mDirty(false)
@@ -2495,10 +2512,25 @@ SetAntialiasingFlags(Layer* aLayer, Draw
 }
 
 IntRect
 ToOutsideIntRect(const gfxRect &aRect)
 {
   return IntRect::RoundOut(aRect.x, aRect.y, aRect.width, aRect.height);
 }
 
+TextLayer::TextLayer(LayerManager* aManager, void* aImplData)
+  : Layer(aManager, aImplData)
+{}
+
+TextLayer::~TextLayer()
+{}
+
+void
+TextLayer::SetGlyphs(nsTArray<GlyphArray>&& aGlyphs)
+{
+  MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) Glyphs", this));
+  mGlyphs = Move(aGlyphs);
+  Mutated();
+}
+
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -80,28 +80,30 @@ class AsyncPanZoomController;
 class BasicLayerManager;
 class ClientLayerManager;
 class Layer;
 class LayerMetricsWrapper;
 class PaintedLayer;
 class ContainerLayer;
 class ImageLayer;
 class ColorLayer;
+class TextLayer;
 class CanvasLayer;
 class ReadbackLayer;
 class ReadbackProcessor;
 class RefLayer;
 class HostLayer;
 class ShadowableLayer;
 class ShadowLayerForwarder;
 class LayerManagerComposite;
 class SpecificLayerAttributes;
 class Compositor;
 class FrameUniformityData;
 class PersistentBufferProvider;
+class GlyphArray;
 
 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; }
@@ -397,16 +399,21 @@ public:
   virtual already_AddRefed<ImageLayer> CreateImageLayer() = 0;
   /**
    * CONSTRUCTION PHASE ONLY
    * Create a ColorLayer for this manager's layer tree.
    */
   virtual already_AddRefed<ColorLayer> CreateColorLayer() = 0;
   /**
    * CONSTRUCTION PHASE ONLY
+   * Create a TextLayer for this manager's layer tree.
+   */
+  virtual already_AddRefed<TextLayer> CreateTextLayer() = 0;
+  /**
+   * CONSTRUCTION PHASE ONLY
    * Create a CanvasLayer for this manager's layer tree.
    */
   virtual already_AddRefed<CanvasLayer> CreateCanvasLayer() = 0;
   /**
    * CONSTRUCTION PHASE ONLY
    * Create a ReadbackLayer for this manager's layer tree.
    */
   virtual already_AddRefed<ReadbackLayer> CreateReadbackLayer() { return nullptr; }
@@ -739,16 +746,17 @@ class Layer {
 
 public:
   // Keep these in alphabetical order
   enum LayerType {
     TYPE_CANVAS,
     TYPE_COLOR,
     TYPE_CONTAINER,
     TYPE_IMAGE,
+    TYPE_TEXT,
     TYPE_READBACK,
     TYPE_REF,
     TYPE_SHADOW,
     TYPE_PAINTED
   };
 
   /**
    * Returns the LayerManager this Layer belongs to. Note that the layer
@@ -1518,16 +1526,22 @@ public:
 
    /**
     * Dynamic cast to a Color. Returns null if this is not a
     * ColorLayer.
     */
   virtual ColorLayer* AsColorLayer() { return nullptr; }
 
   /**
+    * Dynamic cast to a TextLayer. Returns null if this is not a
+    * TextLayer.
+    */
+  virtual TextLayer* AsTextLayer() { return nullptr; }
+
+  /**
    * Dynamic cast to a LayerComposite.  Return null if this is not a
    * LayerComposite.  Can be used anytime.
    */
   virtual HostLayer* AsHostLayer() { return nullptr; }
 
   /**
    * Dynamic cast to a ShadowableLayer.  Return null if this is not a
    * ShadowableLayer.  Can be used anytime.
@@ -2318,16 +2332,71 @@ protected:
 
   virtual void DumpPacket(layerscope::LayersPacket* aPacket, const void* aParent) override;
 
   gfx::IntRect mBounds;
   gfx::Color mColor;
 };
 
 /**
+ * A Layer which renders Glyphs.
+ */
+class TextLayer : public Layer {
+public:
+  virtual TextLayer* AsTextLayer() override { return this; }
+
+  /**
+   * CONSTRUCTION PHASE ONLY
+   */
+  void SetBounds(const gfx::IntRect& aBounds)
+  {
+    if (!mBounds.IsEqualEdges(aBounds)) {
+      mBounds = aBounds;
+      Mutated();
+    }
+  }
+
+  const gfx::IntRect& GetBounds()
+  {
+    return mBounds;
+  }
+
+  void SetScaledFont(gfx::ScaledFont* aScaledFont) {
+    if (aScaledFont != mFont) {
+      mFont = aScaledFont;
+      Mutated();
+    }
+  }
+
+  gfx::ScaledFont* GetScaledFont() { return mFont; }
+
+  MOZ_LAYER_DECL_NAME("TextLayer", TYPE_TEXT)
+
+  virtual void ComputeEffectiveTransforms(const gfx::Matrix4x4& aTransformToSurface) override
+  {
+    gfx::Matrix4x4 idealTransform = GetLocalTransform() * aTransformToSurface;
+    mEffectiveTransform = SnapTransformTranslation(idealTransform, nullptr);
+    ComputeEffectiveTransformForMaskLayers(aTransformToSurface);
+  }
+
+  virtual void SetGlyphs(nsTArray<GlyphArray>&& aGlyphs);
+protected:
+  TextLayer(LayerManager* aManager, void* aImplData);
+  ~TextLayer();
+
+  virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) override;
+
+  virtual void DumpPacket(layerscope::LayersPacket* aPacket, const void* aParent) override;
+
+  gfx::IntRect mBounds;
+  nsTArray<GlyphArray> mGlyphs;
+  RefPtr<gfx::ScaledFont> mFont;
+};
+
+/**
  * A Layer for HTML Canvas elements.  It's backed by either a
  * gfxASurface or a GLContext (for WebGL layers), and has some control
  * for intelligent updating from the source if necessary (for example,
  * if hardware compositing is not available, for reading from the GL
  * buffer into an image surface that we can layer composite.)
  *
  * After Initialize is called, the underlying canvas Surface/GLContext
  * must not be modified during a layer transaction.
--- a/gfx/layers/basic/BasicLayers.h
+++ b/gfx/layers/basic/BasicLayers.h
@@ -109,16 +109,17 @@ public:
 
   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<ColorLayer> CreateColorLayer() override;
+  virtual already_AddRefed<TextLayer> CreateTextLayer() override;
   virtual already_AddRefed<ReadbackLayer> CreateReadbackLayer() 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
new file mode 100644
--- /dev/null
+++ b/gfx/layers/basic/BasicTextLayer.cpp
@@ -0,0 +1,86 @@
+/* -*- 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 ColorLayer, 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"
+
+using namespace mozilla::gfx;
+
+namespace mozilla {
+namespace layers {
+
+class BasicTextLayer : public TextLayer, public BasicImplData {
+public:
+  explicit BasicTextLayer(BasicLayerManager* aLayerManager) :
+    TextLayer(aLayerManager, static_cast<BasicImplData*>(this))
+  {
+    MOZ_COUNT_CTOR(BasicTextLayer);
+  }
+
+protected:
+  virtual ~BasicTextLayer()
+  {
+    MOZ_COUNT_DTOR(BasicTextLayer);
+  }
+
+public:
+  virtual void SetVisibleRegion(const LayerIntRegion& aRegion) override
+  {
+    NS_ASSERTION(BasicManager()->InConstruction(),
+                 "Can only set properties in construction phase");
+    TextLayer::SetVisibleRegion(aRegion);
+  }
+
+  virtual void Paint(DrawTarget* aDT,
+                     const gfx::Point& aDeviceOffset,
+                     Layer* aMaskLayer) override
+  {
+    if (IsHidden() || !mFont) {
+      return;
+    }
+
+    Rect snapped(mBounds.x, mBounds.y, mBounds.width, mBounds.height);
+    MaybeSnapToDevicePixels(snapped, *aDT, true);
+
+    // We don't currently support subpixel-AA in TextLayers since we
+    // don't check if there's an opaque background color behind them.
+    // We should fix this before using them in production.
+    aDT->SetPermitSubpixelAA(false);
+
+    for (GlyphArray& g : mGlyphs) {
+      GlyphBuffer buffer = { g.glyphs().Elements(), (uint32_t)g.glyphs().Length() };
+      aDT->FillGlyphs(mFont, buffer, ColorPattern(g.color().value()));
+    }
+  }
+
+protected:
+  BasicLayerManager* BasicManager()
+  {
+    return static_cast<BasicLayerManager*>(mManager);
+  }
+};
+
+already_AddRefed<TextLayer>
+BasicLayerManager::CreateTextLayer()
+{
+  NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
+  RefPtr<TextLayer> layer = new BasicTextLayer(this);
+  return layer.forget();
+}
+
+} // namespace layers
+} // namespace mozilla
--- a/gfx/layers/client/ClientLayerManager.h
+++ b/gfx/layers/client/ClientLayerManager.h
@@ -82,16 +82,17 @@ public:
 
   virtual already_AddRefed<PaintedLayer> CreatePaintedLayer() override;
   virtual already_AddRefed<PaintedLayer> CreatePaintedLayerWithHint(PaintedLayerCreationHint aHint) 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<TextLayer> CreateTextLayer() override;
   virtual already_AddRefed<RefLayer> CreateRefLayer() override;
 
   void UpdateTextureFactoryIdentifier(const TextureFactoryIdentifier& aNewIdentifier);
   TextureFactoryIdentifier GetTextureFactoryIdentifier()
   {
     return AsShadowForwarder()->GetTextureFactoryIdentifier();
   }
 
new file mode 100644
--- /dev/null
+++ b/gfx/layers/client/ClientTextLayer.cpp
@@ -0,0 +1,91 @@
+/* -*- 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 "ClientLayerManager.h"         // for ClientLayerManager, etc
+#include "Layers.h"                     // for ColorLayer, etc
+#include "mozilla/layers/LayersMessages.h"  // for ColorLayerAttributes, etc
+#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 "nsRegion.h"                   // for nsIntRegion
+
+namespace mozilla {
+namespace layers {
+
+using namespace mozilla::gfx;
+
+class ClientTextLayer : public TextLayer,
+                        public ClientLayer {
+public:
+  explicit ClientTextLayer(ClientLayerManager* aLayerManager) :
+    TextLayer(aLayerManager, static_cast<ClientLayer*>(this)),
+    mSwapped(false)
+  {
+    MOZ_COUNT_CTOR(ClientTextLayer);
+  }
+
+protected:
+  virtual ~ClientTextLayer()
+  {
+    MOZ_COUNT_DTOR(ClientTextLayer);
+  }
+
+public:
+  virtual void SetVisibleRegion(const LayerIntRegion& aRegion)
+  {
+    NS_ASSERTION(ClientManager()->InConstruction(),
+                 "Can only set properties in construction phase");
+    TextLayer::SetVisibleRegion(aRegion);
+  }
+
+  virtual void RenderLayer()
+  {
+    RenderMaskLayers(this);
+  }
+
+  virtual void FillSpecificAttributes(SpecificLayerAttributes& aAttrs)
+  {
+    NS_ASSERTION(!mSwapped, "Trying to access glyph array after it's been swapped!");
+    aAttrs = TextLayerAttributes(GetBounds(), nsTArray<GlyphArray>(), uintptr_t(mFont.get()));
+    aAttrs.get_TextLayerAttributes().glyphs().SwapElements(mGlyphs);
+    mSwapped = true;
+  }
+
+  virtual void SetGlyphs(nsTArray<GlyphArray>&& aGlyphs)
+  {
+    TextLayer::SetGlyphs(Move(aGlyphs));
+    mSwapped = false;
+  }
+
+  virtual Layer* AsLayer() { return this; }
+  virtual ShadowableLayer* AsShadowableLayer() { return this; }
+
+  virtual void Disconnect()
+  {
+    ClientLayer::Disconnect();
+  }
+
+protected:
+  ClientLayerManager* ClientManager()
+  {
+    return static_cast<ClientLayerManager*>(mManager);
+  }
+
+  bool mSwapped;
+};
+
+already_AddRefed<TextLayer>
+ClientLayerManager::CreateTextLayer()
+{
+  NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
+  RefPtr<ClientTextLayer> layer =
+    new ClientTextLayer(this);
+  CREATE_SHADOW(Text);
+  return layer.forget();
+}
+
+} // namespace layers
+} // namespace mozilla
--- a/gfx/layers/composite/LayerManagerComposite.cpp
+++ b/gfx/layers/composite/LayerManagerComposite.cpp
@@ -1116,16 +1116,59 @@ LayerManagerComposite::RenderToPresentat
 
   RootLayer()->Prepare(RenderTargetIntRect::FromUnknownRect(clipRect));
   RootLayer()->RenderLayer(clipRect);
 
   mCompositor->EndFrame();
 }
 #endif
 
+class TextLayerComposite : public TextLayer,
+                           public LayerComposite
+{
+public:
+  explicit TextLayerComposite(LayerManagerComposite *aManager)
+    : TextLayer(aManager, nullptr)
+    , LayerComposite(aManager)
+  {
+    MOZ_COUNT_CTOR(TextLayerComposite);
+    mImplData = static_cast<LayerComposite*>(this);
+  }
+
+protected:
+  ~TextLayerComposite()
+  {
+    MOZ_COUNT_DTOR(TextLayerComposite);
+    Destroy();
+  }
+
+public:
+  // LayerComposite Implementation
+  virtual Layer* GetLayer() override { return this; }
+
+  virtual void SetLayerManager(HostLayerManager* aManager) override
+  {
+    LayerComposite::SetLayerManager(aManager);
+    mManager = aManager;
+  }
+
+  virtual void Destroy() override { mDestroyed = true; }
+
+  virtual void RenderLayer(const gfx::IntRect& aClipRect) override {}
+  virtual void CleanupResources() override {};
+
+  virtual void GenEffectChain(EffectChain& aEffect) override {}
+
+  CompositableHost* GetCompositableHost() override { return nullptr; }
+
+  virtual HostLayer* AsHostLayer() override { return this; }
+
+  virtual const char* Name() const override { return "TextLayerComposite"; }
+};
+
 already_AddRefed<PaintedLayer>
 LayerManagerComposite::CreatePaintedLayer()
 {
   if (mDestroyed) {
     NS_WARNING("Call on destroyed layer manager");
     return nullptr;
   }
   return RefPtr<PaintedLayer>(new PaintedLayerComposite(this)).forget();
@@ -1176,16 +1219,26 @@ LayerManagerComposite::CreateRefLayer()
 {
   if (LayerManagerComposite::mDestroyed) {
     NS_WARNING("Call on destroyed layer manager");
     return nullptr;
   }
   return RefPtr<RefLayer>(new RefLayerComposite(this)).forget();
 }
 
+already_AddRefed<TextLayer>
+LayerManagerComposite::CreateTextLayer()
+{
+  if (LayerManagerComposite::mDestroyed) {
+    NS_WARNING("Call on destroyed layer manager");
+    return nullptr;
+  }
+  return RefPtr<TextLayer>(new TextLayerComposite(this)).forget();
+}
+
 LayerManagerComposite::AutoAddMaskEffect::AutoAddMaskEffect(Layer* aMaskLayer,
                                                             EffectChain& aEffects)
   : mCompositable(nullptr), mFailed(false)
 {
   if (!aMaskLayer) {
     return;
   }
 
--- a/gfx/layers/composite/LayerManagerComposite.h
+++ b/gfx/layers/composite/LayerManagerComposite.h
@@ -234,16 +234,17 @@ public:
   virtual bool CanUseCanvasLayerForSize(const gfx::IntSize &aSize) override;
 
   virtual void ClearCachedResources(Layer* aSubtree = nullptr) override;
 
   virtual already_AddRefed<PaintedLayer> CreatePaintedLayer() override;
   virtual already_AddRefed<ContainerLayer> CreateContainerLayer() override;
   virtual already_AddRefed<ImageLayer> CreateImageLayer() override;
   virtual already_AddRefed<ColorLayer> CreateColorLayer() override;
+  virtual already_AddRefed<TextLayer> CreateTextLayer() override;
   virtual already_AddRefed<CanvasLayer> CreateCanvasLayer() override;
   virtual already_AddRefed<RefLayer> CreateRefLayer() override;
 
   virtual bool AreComponentAlphaLayersEnabled() override;
 
   virtual already_AddRefed<DrawTarget>
     CreateOptimalMaskDrawTarget(const IntSize &aSize) override;
 
--- a/gfx/layers/ipc/LayerTransactionParent.cpp
+++ b/gfx/layers/ipc/LayerTransactionParent.cpp
@@ -281,17 +281,17 @@ LayerTransactionParent::RecvUpdate(Infal
     AutoResolveRefLayers resolve(mCompositorBridge->GetCompositionManager(this));
     layer_manager()->BeginTransaction();
   }
 
   // not all edits require an update to the hit testing tree
   bool updateHitTestingTree = false;
 
   for (EditArray::index_type i = 0; i < cset.Length(); ++i) {
-    const Edit& edit = cset[i];
+    Edit& edit = cset[i];
 
     switch (edit.type()) {
     // Create* ops
     case Edit::TOpCreatePaintedLayer: {
       MOZ_LAYERS_LOG(("[ParentSide] CreatePaintedLayer"));
 
       RefPtr<PaintedLayer> layer =
         layer_manager()->CreatePaintedLayer();
@@ -323,16 +323,25 @@ LayerTransactionParent::RecvUpdate(Infal
       MOZ_LAYERS_LOG(("[ParentSide] CreateColorLayer"));
 
       RefPtr<ColorLayer> layer = layer_manager()->CreateColorLayer();
       AsLayerComposite(edit.get_OpCreateColorLayer())->Bind(layer);
 
       updateHitTestingTree = true;
       break;
     }
+    case Edit::TOpCreateTextLayer: {
+      MOZ_LAYERS_LOG(("[ParentSide] CreateTextLayer"));
+
+      RefPtr<TextLayer> layer = layer_manager()->CreateTextLayer();
+      AsLayerComposite(edit.get_OpCreateTextLayer())->Bind(layer);
+
+      updateHitTestingTree = true;
+      break;
+    }
     case Edit::TOpCreateCanvasLayer: {
       MOZ_LAYERS_LOG(("[ParentSide] CreateCanvasLayer"));
 
       RefPtr<CanvasLayer> layer =
         layer_manager()->CreateCanvasLayer();
       AsLayerComposite(edit.get_OpCreateCanvasLayer())->Bind(layer);
 
       updateHitTestingTree = true;
@@ -348,23 +357,23 @@ LayerTransactionParent::RecvUpdate(Infal
       updateHitTestingTree = true;
       break;
     }
 
     // Attributes
     case Edit::TOpSetLayerAttributes: {
       MOZ_LAYERS_LOG(("[ParentSide] SetLayerAttributes"));
 
-      const OpSetLayerAttributes& osla = edit.get_OpSetLayerAttributes();
+      OpSetLayerAttributes& osla = edit.get_OpSetLayerAttributes();
       ShadowLayerParent* layerParent = AsLayerComposite(osla);
       Layer* layer = layerParent->AsLayer();
       if (!layer) {
         return IPC_FAIL_NO_REASON(this);
       }
-      const LayerAttributes& attrs = osla.attrs();
+      LayerAttributes& attrs = osla.attrs();
 
       const CommonLayerAttributes& common = attrs.common();
       layer->SetLayerBounds(common.layerBounds());
       layer->SetVisibleRegion(common.visibleRegion());
       layer->SetEventRegions(common.eventRegions());
       layer->SetContentFlags(common.contentFlags());
       layer->SetOpacity(common.opacity());
       layer->SetClipRect(common.useClipRect() ? Some(common.clipRect()) : Nothing());
@@ -407,17 +416,17 @@ LayerTransactionParent::RecvUpdate(Infal
       nsTArray<RefPtr<Layer>> maskLayers;
       for (size_t i = 0; i < common.ancestorMaskLayersParent().Length(); i++) {
         Layer* maskLayer = cast(common.ancestorMaskLayersParent().ElementAt(i))->AsLayer();
         maskLayers.AppendElement(maskLayer);
       }
       layer->SetAncestorMaskLayers(maskLayers);
 
       typedef SpecificLayerAttributes Specific;
-      const SpecificLayerAttributes& specific = attrs.specific();
+      SpecificLayerAttributes& specific = attrs.specific();
       switch (specific.type()) {
       case Specific::Tnull_t:
         break;
 
       case Specific::TPaintedLayerAttributes: {
         MOZ_LAYERS_LOG(("[ParentSide]   painted layer"));
 
         PaintedLayer* paintedLayer = layerParent->AsPaintedLayer();
@@ -454,16 +463,28 @@ LayerTransactionParent::RecvUpdate(Infal
         ColorLayer* colorLayer = layerParent->AsColorLayer();
         if (!colorLayer) {
           return IPC_FAIL_NO_REASON(this);
         }
         colorLayer->SetColor(specific.get_ColorLayerAttributes().color().value());
         colorLayer->SetBounds(specific.get_ColorLayerAttributes().bounds());
         break;
       }
+      case Specific::TTextLayerAttributes: {
+        MOZ_LAYERS_LOG(("[ParentSide]   text layer"));
+
+        TextLayer* textLayer = layerParent->AsTextLayer();
+        if (!textLayer) {
+          return IPC_FAIL_NO_REASON(this);
+        }
+        textLayer->SetBounds(specific.get_TextLayerAttributes().bounds());
+        textLayer->SetGlyphs(Move(specific.get_TextLayerAttributes().glyphs()));
+        textLayer->SetScaledFont(reinterpret_cast<gfx::ScaledFont*>(specific.get_TextLayerAttributes().scaledFont()));
+        break;
+      }
       case Specific::TCanvasLayerAttributes: {
         MOZ_LAYERS_LOG(("[ParentSide]   canvas layer"));
 
         CanvasLayer* canvasLayer = layerParent->AsCanvasLayer();
         if (!canvasLayer) {
           return IPC_FAIL_NO_REASON(this);
         }
         canvasLayer->SetSamplingFilter(specific.get_CanvasLayerAttributes().samplingFilter());
--- a/gfx/layers/ipc/LayersMessages.ipdlh
+++ b/gfx/layers/ipc/LayersMessages.ipdlh
@@ -40,32 +40,34 @@ using mozilla::LayoutDeviceIntRect from 
 using mozilla::layers::ScaleMode from "mozilla/layers/LayersTypes.h";
 using mozilla::layers::EventRegions from "mozilla/layers/LayersTypes.h";
 using mozilla::layers::EventRegionsOverride from "mozilla/layers/LayersTypes.h";
 using mozilla::layers::DiagnosticTypes from "mozilla/layers/CompositorTypes.h";
 using struct mozilla::layers::ScrollMetadata from "FrameMetrics.h";
 using mozilla::layers::FrameMetrics::ViewID from "FrameMetrics.h";
 using mozilla::layers::LayersBackend from "mozilla/layers/LayersTypes.h";
 using mozilla::layers::MaybeLayerClip from "FrameMetrics.h";
+using mozilla::gfx::Glyph from "Layers.h";
 
 namespace mozilla {
 namespace layers {
 
 struct TargetConfig {
   IntRect naturalBounds;
   ScreenRotation rotation;
   ScreenOrientationInternal orientation;
   nsIntRegion clearRegion;
 };
 
 // Create a shadow layer for |layer|
 struct OpCreatePaintedLayer    { PLayer layer; };
 struct OpCreateContainerLayer  { PLayer layer; };
 struct OpCreateImageLayer      { PLayer layer; };
 struct OpCreateColorLayer      { PLayer layer; };
+struct OpCreateTextLayer       { PLayer layer; };
 struct OpCreateCanvasLayer     { PLayer layer; };
 struct OpCreateRefLayer        { PLayer layer; };
 
 struct OpAttachCompositable {
   PLayer layer;
   PCompositable compositable;
 };
 
@@ -250,32 +252,43 @@ struct ContainerLayerAttributes {
   float preXScale;
   float preYScale;
   float inheritedXScale;
   float inheritedYScale;
   float presShellResolution;
   bool scaleToResolution;
   EventRegionsOverride eventRegionsOverride;
 };
+
+struct GlyphArray
+{
+  LayerColor color;
+  Glyph[] glyphs;
+};
+
+// XXX - Bas - Hack warning! This is using a raw pointer to a ScaledFont*
+// and won't work with e10s.
+struct TextLayerAttributes      { IntRect bounds; GlyphArray[] glyphs; uintptr_t scaledFont; };
 struct ColorLayerAttributes     { LayerColor color; IntRect bounds; };
 struct CanvasLayerAttributes    { SamplingFilter samplingFilter; IntRect bounds; };
 struct RefLayerAttributes {
   int64_t id;
   // TODO: Once bug 1132895 is fixed we shouldn't need to propagate the override
   // explicitly here.
   EventRegionsOverride eventRegionsOverride;
 };
 struct ImageLayerAttributes     { SamplingFilter samplingFilter; IntSize scaleToSize; ScaleMode scaleMode; };
 
 union SpecificLayerAttributes {
   null_t;
   PaintedLayerAttributes;
   ContainerLayerAttributes;
   ColorLayerAttributes;
   CanvasLayerAttributes;
+  TextLayerAttributes;
   RefLayerAttributes;
   ImageLayerAttributes;
 };
 
 struct LayerAttributes {
   CommonLayerAttributes common;
   SpecificLayerAttributes specific;
 };
@@ -434,16 +447,17 @@ struct CompositableOperation {
 // A unit of a changeset; a set of these comprise a changeset
 // If adding a new edit type that requires the hit testing tree to be updated,
 // set the updateHitTestingTree flag to true in RecvUpdate()
 union Edit {
   OpCreatePaintedLayer;
   OpCreateContainerLayer;
   OpCreateImageLayer;
   OpCreateColorLayer;
+  OpCreateTextLayer;
   OpCreateCanvasLayer;
   OpCreateRefLayer;
 
   OpSetLayerAttributes;
   OpSetDiagnosticTypes;
   OpWindowOverlayChanged;
 
   OpSetRoot;
--- a/gfx/layers/ipc/ShadowLayerParent.cpp
+++ b/gfx/layers/ipc/ShadowLayerParent.cpp
@@ -99,16 +99,24 @@ ShadowLayerParent::AsRefLayer() const
 PaintedLayer*
 ShadowLayerParent::AsPaintedLayer() const
 {
   return mLayer && mLayer->GetType() == Layer::TYPE_PAINTED
     ? static_cast<PaintedLayer*>(mLayer.get())
          : nullptr;
 }
 
+TextLayer*
+ShadowLayerParent::AsTextLayer() const
+{
+  return mLayer && mLayer->GetType() == Layer::TYPE_TEXT
+         ? static_cast<TextLayer*>(mLayer.get())
+         : nullptr;
+}
+
 void
 ShadowLayerParent::ActorDestroy(ActorDestroyReason why)
 {
   switch (why) {
   case AncestorDeletion:
     NS_RUNTIMEABORT("shadow layer deleted out of order!");
     return;                     // unreached
 
--- a/gfx/layers/ipc/ShadowLayerParent.h
+++ b/gfx/layers/ipc/ShadowLayerParent.h
@@ -15,16 +15,17 @@
 namespace mozilla {
 namespace layers {
 
 class ContainerLayer;
 class Layer;
 
 class CanvasLayer;
 class ColorLayer;
+class TextLayer;
 class ContainerLayer;
 class ImageLayer;
 class RefLayer;
 class PaintedLayer;
 
 class ShadowLayerParent : public PLayerParent
 {
 public:
@@ -35,16 +36,17 @@ public:
   void Bind(Layer* layer);
   void Destroy();
 
   Layer* AsLayer() const { return mLayer; }
 
   ContainerLayer* AsContainerLayer() const;
   CanvasLayer* AsCanvasLayer() const;
   ColorLayer* AsColorLayer() const;
+  TextLayer* AsTextLayer() const;
   ImageLayer* AsImageLayer() const;
   RefLayer* AsRefLayer() const;
   PaintedLayer* AsPaintedLayer() const;
 
 private:
   virtual void ActorDestroy(ActorDestroyReason why) override;
 
   void Disconnect();
--- a/gfx/layers/ipc/ShadowLayers.cpp
+++ b/gfx/layers/ipc/ShadowLayers.cpp
@@ -261,16 +261,21 @@ ShadowLayerForwarder::CreatedImageLayer(
   CreatedLayer<OpCreateImageLayer>(mTxn, aImage);
 }
 void
 ShadowLayerForwarder::CreatedColorLayer(ShadowableLayer* aColor)
 {
   CreatedLayer<OpCreateColorLayer>(mTxn, aColor);
 }
 void
+ShadowLayerForwarder::CreatedTextLayer(ShadowableLayer* aColor)
+{
+  CreatedLayer<OpCreateTextLayer>(mTxn, aColor);
+}
+void
 ShadowLayerForwarder::CreatedCanvasLayer(ShadowableLayer* aCanvas)
 {
   CreatedLayer<OpCreateCanvasLayer>(mTxn, aCanvas);
 }
 void
 ShadowLayerForwarder::CreatedRefLayer(ShadowableLayer* aRef)
 {
   CreatedLayer<OpCreateRefLayer>(mTxn, aRef);
--- a/gfx/layers/ipc/ShadowLayers.h
+++ b/gfx/layers/ipc/ShadowLayers.h
@@ -204,16 +204,17 @@ public:
    * the compositing process.
    */
   void CreatedPaintedLayer(ShadowableLayer* aThebes);
   void CreatedContainerLayer(ShadowableLayer* aContainer);
   void CreatedImageLayer(ShadowableLayer* aImage);
   void CreatedColorLayer(ShadowableLayer* aColor);
   void CreatedCanvasLayer(ShadowableLayer* aCanvas);
   void CreatedRefLayer(ShadowableLayer* aRef);
+  void CreatedTextLayer(ShadowableLayer* aRef);
 
   /**
    * At least one attribute of |aMutant| has changed, and |aMutant|
    * needs to sync to its shadow layer.  This initial implementation
    * forwards all attributes when any is mutated.
    */
   void Mutated(ShadowableLayer* aMutant);
 
--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -277,27 +277,29 @@ UNIFIED_SOURCES += [
     'basic/BasicCanvasLayer.cpp',
     'basic/BasicColorLayer.cpp',
     'basic/BasicCompositor.cpp',
     'basic/BasicContainerLayer.cpp',
     'basic/BasicImages.cpp',
     'basic/BasicLayerManager.cpp',
     'basic/BasicLayersImpl.cpp',
     'basic/BasicPaintedLayer.cpp',
+    'basic/BasicTextLayer.cpp',
     'basic/TextureHostBasic.cpp',
     'BSPTree.cpp',
     'BufferTexture.cpp',
     'BufferUnrotate.cpp',
     'client/CanvasClient.cpp',
     'client/ClientCanvasLayer.cpp',
     'client/ClientColorLayer.cpp',
     'client/ClientContainerLayer.cpp',
     'client/ClientImageLayer.cpp',
     'client/ClientLayerManager.cpp',
     'client/ClientPaintedLayer.cpp',
+    'client/ClientTextLayer.cpp',
     'client/ClientTiledPaintedLayer.cpp',
     'client/CompositableChild.cpp',
     'client/CompositableClient.cpp',
     'client/ContentClient.cpp',
     'client/GPUVideoTextureClient.cpp',
     'client/ImageClient.cpp',
     'client/SingleTiledContentClient.cpp',
     'client/TextureClient.cpp',
--- a/gfx/layers/protobuf/LayerScopePacket.pb.h
+++ b/gfx/layers/protobuf/LayerScopePacket.pb.h
@@ -67,18 +67,19 @@ const int TexturePacket_Filter_Filter_AR
 enum LayersPacket_Layer_LayerType {
   LayersPacket_Layer_LayerType_UnknownLayer = 0,
   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_RefLayer = 7,
-  LayersPacket_Layer_LayerType_ReadbackLayer = 8
+  LayersPacket_Layer_LayerType_TextLayer = 7,
+  LayersPacket_Layer_LayerType_RefLayer = 8,
+  LayersPacket_Layer_LayerType_ReadbackLayer = 9
 };
 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,
@@ -1668,16 +1669,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 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;
   static const LayerType LayerType_MAX =
--- a/gfx/tests/gtest/TestLayers.cpp
+++ b/gfx/tests/gtest/TestLayers.cpp
@@ -73,16 +73,20 @@ public:
   virtual already_AddRefed<PaintedLayer> CreatePaintedLayer() {
     RefPtr<PaintedLayer> layer = new TestPaintedLayer(this);
     return layer.forget();
   }
   virtual already_AddRefed<ColorLayer> CreateColorLayer() {
     NS_RUNTIMEABORT("Not implemented.");
     return nullptr;
   }
+  virtual already_AddRefed<TextLayer> CreateTextLayer() {
+    NS_RUNTIMEABORT("Not implemented.");
+    return nullptr;
+  }
   virtual void SetRoot(Layer* aLayer) {}
   virtual bool BeginTransactionWithTarget(gfxContext* aTarget) { return true; }
   virtual already_AddRefed<CanvasLayer> CreateCanvasLayer() {
     NS_RUNTIMEABORT("Not implemented.");
     return nullptr;
   }
   virtual void EndTransaction(DrawPaintedLayerCallback aCallback,
                               void* aCallbackData,