Bug 1061393 - Export display list info to layer scope viewer. r=kamidphish
authorCJ Ku <cku@mozilla.com>
Mon, 03 Aug 2015 02:11:00 -0400
changeset 287535 006e8f78affed61e48b8bd0346d6e6d3efc06e7e
parent 287534 10bdc996eb3cea12229f2ed22a932b134bc8aa3f
child 287536 6160dbecbceb4d8673c1731802e0939e4764ef6f
push id5067
push userraliiev@mozilla.com
push dateMon, 21 Sep 2015 14:04:52 +0000
treeherdermozilla-beta@14221ffe5b2f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskamidphish
bugs1061393
milestone42.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 1061393 - Export display list info to layer scope viewer. r=kamidphish
gfx/layers/LayerScope.cpp
gfx/layers/LayerScope.h
gfx/layers/Layers.cpp
gfx/layers/Layers.h
gfx/layers/ipc/CompositorParent.cpp
gfx/layers/ipc/LayerTransactionParent.cpp
gfx/layers/ipc/LayersMessages.ipdlh
gfx/layers/ipc/ShadowLayers.cpp
gfx/layers/opengl/CompositorOGL.cpp
gfx/layers/protobuf/LayerScopePacket.pb.cc
gfx/layers/protobuf/LayerScopePacket.pb.h
gfx/layers/protobuf/LayerScopePacket.proto
layout/base/nsLayoutDebugger.cpp
layout/base/nsLayoutUtils.cpp
layout/generic/nsFrame.h
layout/generic/nsTextFrame.cpp
--- a/gfx/layers/LayerScope.cpp
+++ b/gfx/layers/LayerScope.cpp
@@ -186,16 +186,18 @@ public:
       , mRects(0)
     { }
 
     float mOffsetX;
     float mOffsetY;
     gfx::Matrix4x4 mMVMatrix;
     size_t mRects;
     gfx::Rect mLayerRects[4];
+    gfx::Rect mTextureRects[4];
+    std::list<GLuint> mTexIDs;
 };
 
 class ContentMonitor {
 public:
     using THArray = nsTArray<const TextureHost *>;
 
     // Notify the content of a TextureHost was changed.
     void SetChangedHost(const TextureHost* host) {
@@ -284,16 +286,28 @@ public:
     void NewDrawSession() {
         mSession = mozilla::MakeUnique<DrawSession>();
     }
 
     DrawSession& CurrentSession() {
         return *mSession;
     }
 
+    void SetPixelScale(double scale) {
+        mScale = scale;
+    }
+
+    double GetPixelScale() const {
+        return mScale;
+    }
+
+    LayerScopeManager()
+        : mScale(1.0)
+    {
+    }
 private:
     friend class CreateServerSocketRunnable;
     class CreateServerSocketRunnable : public nsRunnable
     {
     public:
         explicit CreateServerSocketRunnable(LayerScopeManager *aLayerScopeManager)
             : mLayerScopeManager(aLayerScopeManager)
         {
@@ -305,16 +319,17 @@ private:
         }
     private:
         LayerScopeManager* mLayerScopeManager;
     };
 
     mozilla::UniquePtr<LayerScopeWebSocketManager> mWebSocketManager;
     mozilla::UniquePtr<DrawSession> mSession;
     mozilla::UniquePtr<ContentMonitor> mContentMonitor;
+    double mScale;
 };
 
 LayerScopeManager gLayerScopeManager;
 
 /*
  * DebugGLData is the base class of
  * 1. DebugGLFrameStatusData (Frame start/end packet)
  * 2. DebugGLColorData (Color data packet)
@@ -362,16 +377,18 @@ public:
 
     virtual bool Write() override {
         Packet packet;
         packet.set_type(mDataType);
 
         FramePacket* fp = packet.mutable_frame();
         fp->set_value(static_cast<uint64_t>(mFrameStamp));
 
+        fp->set_scale(gLayerScopeManager.GetPixelScale());
+
         return WriteToStream(packet);
     }
 
 protected:
     int64_t mFrameStamp;
 };
 
 #ifdef MOZ_WIDGET_GONK
@@ -618,26 +635,30 @@ protected:
 
 class DebugGLDrawData final: public DebugGLData {
 public:
     DebugGLDrawData(float aOffsetX,
                     float aOffsetY,
                     const gfx::Matrix4x4& aMVMatrix,
                     size_t aRects,
                     const gfx::Rect* aLayerRects,
+                    const gfx::Rect* aTextureRects,
+                    const std::list<GLuint> aTexIDs,
                     void* aLayerRef)
         : DebugGLData(Packet::DRAW),
           mOffsetX(aOffsetX),
           mOffsetY(aOffsetY),
           mMVMatrix(aMVMatrix),
           mRects(aRects),
+          mTexIDs(aTexIDs),
           mLayerRef(reinterpret_cast<uint64_t>(aLayerRef))
     {
         for (size_t i = 0; i < mRects; i++){
             mLayerRects[i] = aLayerRects[i];
+            mTextureRects[i] = aTextureRects[i];
         }
     }
 
     virtual bool Write() override {
         Packet packet;
         packet.set_type(mDataType);
 
         DrawPacket* dp = packet.mutable_draw();
@@ -649,32 +670,46 @@ public:
         auto element = reinterpret_cast<Float *>(&mMVMatrix);
         for (int i = 0; i < 16; i++) {
           dp->add_mvmatrix(*element++);
         }
         dp->set_totalrects(mRects);
 
         MOZ_ASSERT(mRects > 0 && mRects < 4);
         for (size_t i = 0; i < mRects; i++) {
+            // Vertex
             layerscope::DrawPacket::Rect* pRect = dp->add_layerrect();
             pRect->set_x(mLayerRects[i].x);
             pRect->set_y(mLayerRects[i].y);
             pRect->set_w(mLayerRects[i].width);
             pRect->set_h(mLayerRects[i].height);
+
+            // UV
+            pRect = dp->add_texturerect();
+            pRect->set_x(mTextureRects[i].x);
+            pRect->set_y(mTextureRects[i].y);
+            pRect->set_w(mTextureRects[i].width);
+            pRect->set_h(mTextureRects[i].height);
+        }
+
+        for (GLuint texId: mTexIDs) {
+            dp->add_texids(texId);
         }
 
         return WriteToStream(packet);
     }
 
 protected:
     float mOffsetX;
     float mOffsetY;
     gfx::Matrix4x4 mMVMatrix;
     size_t mRects;
     gfx::Rect mLayerRects[4];
+    gfx::Rect mTextureRects[4];
+    std::list<GLuint> mTexIDs;
     uint64_t mLayerRef;
 };
 
 class DebugListener : public nsIServerSocketListener
 {
     virtual ~DebugListener() { }
 
 public:
@@ -950,16 +985,18 @@ SenderHelper::SendTextureSource(GLContex
         aGLContext->ReadTexImageHelper()->ReadTexImage(0, textureTarget,
                                                          size,
                                                          shaderConfig, aFlipY);
     gLayerScopeManager.GetSocketManager()->AppendDebugData(
         new DebugGLTextureData(aGLContext, aLayerRef, textureTarget,
                                aTexID, img));
 
     sTextureIdList.push_back(aTexID);
+    gLayerScopeManager.CurrentSession().mTexIDs.push_back(aTexID);
+
 }
 
 #ifdef MOZ_WIDGET_GONK
 bool
 SenderHelper::SendGraphicBuffer(void* aLayerRef,
                                 TextureSourceOGL* aSource,
                                 GLuint aTexID,
                                 const TexturedEffect* aEffect) {
@@ -978,16 +1015,18 @@ SenderHelper::SendGraphicBuffer(void* aL
     if (!package->TryPack(changed)) {
         return false;
     }
 
     // Transfer ownership to SocketManager.
     gLayerScopeManager.GetSocketManager()->AppendDebugData(package.release());
     sTextureIdList.push_back(aTexID);
 
+    gLayerScopeManager.CurrentSession().mTexIDs.push_back(aTexID);
+
     gLayerScopeManager.GetContentMonitor()->ClearChangedHost(aEffect->mState.mTexture);
     return true;
 }
 #endif
 
 void
 SenderHelper::SendTexturedEffect(GLContext* aGLContext,
                                  void* aLayerRef,
@@ -1580,73 +1619,82 @@ LayerScope::DrawBegin()
 {
     if (!CheckSendable()) {
         return;
     }
 
     gLayerScopeManager.NewDrawSession();
 }
 
-void LayerScope::SetRenderOffset(float aX, float aY)
+void
+LayerScope::SetRenderOffset(float aX, float aY)
 {
     if (!CheckSendable()) {
         return;
     }
 
     gLayerScopeManager.CurrentSession().mOffsetX = aX;
     gLayerScopeManager.CurrentSession().mOffsetY = aY;
 }
 
-void LayerScope::SetLayerTransform(const gfx::Matrix4x4& aMatrix)
+void
+LayerScope::SetLayerTransform(const gfx::Matrix4x4& aMatrix)
 {
     if (!CheckSendable()) {
         return;
     }
 
     gLayerScopeManager.CurrentSession().mMVMatrix = aMatrix;
 }
 
-void LayerScope::SetLayerRects(size_t aRects, const gfx::Rect* aLayerRects)
+void
+LayerScope::SetDrawRects(size_t aRects,
+                         const gfx::Rect* aLayerRects,
+                         const gfx::Rect* aTextureRects)
 {
     if (!CheckSendable()) {
         return;
     }
 
     MOZ_ASSERT(aRects > 0 && aRects <= 4);
     MOZ_ASSERT(aLayerRects);
 
     gLayerScopeManager.CurrentSession().mRects = aRects;
 
     for (size_t i = 0; i < aRects; i++){
         gLayerScopeManager.CurrentSession().mLayerRects[i] = aLayerRects[i];
+        gLayerScopeManager.CurrentSession().mTextureRects[i] = aTextureRects[i];
     }
 }
 
 void
 LayerScope::DrawEnd(gl::GLContext* aGLContext,
                     const EffectChain& aEffectChain,
                     int aWidth,
                     int aHeight)
 {
     // Protect this public function
     if (!CheckSendable()) {
         return;
     }
 
-    // 1. Send parameters of draw call, such as uniforms and attributes of
+    // 1. Send textures.
+    SenderHelper::SendEffectChain(aGLContext, aEffectChain, aWidth, aHeight);
+
+    // 2. Send parameters of draw call, such as uniforms and attributes of
     // vertex adnd fragment shader.
     DrawSession& draws = gLayerScopeManager.CurrentSession();
     gLayerScopeManager.GetSocketManager()->AppendDebugData(
         new DebugGLDrawData(draws.mOffsetX, draws.mOffsetY,
                             draws.mMVMatrix, draws.mRects,
                             draws.mLayerRects,
+                            draws.mTextureRects,
+                            draws.mTexIDs,
                             aEffectChain.mLayerRef));
 
-    // 2. Send textures.
-    SenderHelper::SendEffectChain(aGLContext, aEffectChain, aWidth, aHeight);
 }
 
 void
 LayerScope::SendLayer(LayerComposite* aLayer,
                       int aWidth,
                       int aHeight)
 {
     // Protect this public function
@@ -1698,16 +1746,21 @@ void
 LayerScope::SetHWComposed()
 {
     if (CheckSendable()) {
         gLayerScopeManager.GetSocketManager()->AppendDebugData(
             new DebugGLMetaData(Packet::META, true));
     }
 }
 
+void
+LayerScope::SetPixelScale(double devPixelsPerCSSPixel)
+{
+    gLayerScopeManager.SetPixelScale(devPixelsPerCSSPixel);
+}
 // ----------------------------------------------
 // LayerScopeAutoFrame implementation
 // ----------------------------------------------
 LayerScopeAutoFrame::LayerScopeAutoFrame(int64_t aFrameStamp)
 {
     // Do Begin Frame
     BeginFrame(aFrameStamp);
 }
@@ -1716,21 +1769,20 @@ LayerScopeAutoFrame::~LayerScopeAutoFram
 {
     // Do End Frame
     EndFrame();
 }
 
 void
 LayerScopeAutoFrame::BeginFrame(int64_t aFrameStamp)
 {
-    SenderHelper::ClearTextureIdList();
-
     if (!LayerScope::CheckSendable()) {
         return;
     }
+    SenderHelper::ClearTextureIdList();
 
     gLayerScopeManager.GetSocketManager()->AppendDebugData(
         new DebugGLFrameStatusData(Packet::FRAMESTART, aFrameStamp));
 }
 
 void
 LayerScopeAutoFrame::EndFrame()
 {
--- a/gfx/layers/LayerScope.h
+++ b/gfx/layers/LayerScope.h
@@ -21,30 +21,33 @@ namespace layerscope { class Packet; }
 struct EffectChain;
 class LayerComposite;
 
 class LayerScope {
 public:
     static void DrawBegin();
     static void SetRenderOffset(float aX, float aY);
     static void SetLayerTransform(const gfx::Matrix4x4& aMatrix);
-    static void SetLayerRects(size_t aRects, const gfx::Rect* aLayerRects);
+    static void SetDrawRects(size_t aRects,
+                             const gfx::Rect* aLayerRects,
+                             const gfx::Rect* aTextureRects);
     static void DrawEnd(gl::GLContext* aGLContext,
                         const EffectChain& aEffectChain,
                         int aWidth,
                         int aHeight);
 
     static void SendLayer(LayerComposite* aLayer,
                           int aWidth,
                           int aHeight);
     static void SendLayerDump(UniquePtr<layerscope::Packet> aPacket);
     static bool CheckSendable();
     static void CleanLayer();
     static void SetHWComposed();
 
+    static void SetPixelScale(double devPixelsPerCSSPixel);
     static void ContentChanged(TextureHost *host);
 private:
     static void Init();
 };
 
 // Perform BeginFrame and EndFrame automatically
 class LayerScopeAutoFrame {
 public:
--- a/gfx/layers/Layers.cpp
+++ b/gfx/layers/Layers.cpp
@@ -31,31 +31,33 @@
 #include "mozilla/layers/LayerMetricsWrapper.h" // for LayerMetricsWrapper
 #include "mozilla/layers/LayersMessages.h"  // for TransformFunction, etc
 #include "mozilla/layers/PersistentBufferProvider.h"
 #include "nsAString.h"
 #include "nsCSSValue.h"                 // for nsCSSValue::Array, etc
 #include "nsPrintfCString.h"            // for nsPrintfCString
 #include "nsStyleStruct.h"              // for nsTimingFunction, etc
 #include "protobuf/LayerScopePacket.pb.h"
+#include "mozilla/Compression.h"
 
 uint8_t gLayerManagerLayerBuilder;
 
 namespace mozilla {
 namespace layers {
 
 FILE*
 FILEOrDefault(FILE* aFile)
 {
   return aFile ? aFile : stderr;
 }
 
 typedef FrameMetrics::ViewID ViewID;
 
 using namespace mozilla::gfx;
+using namespace mozilla::Compression;
 
 //--------------------------------------------------
 // LayerManager
 FrameMetrics::ViewID
 LayerManager::GetRootScrollableLayerId()
 {
   if (!mRoot) {
     return FrameMetrics::NULL_SCROLL_ID;
@@ -1587,16 +1589,45 @@ Layer::Dump(layerscope::LayersPacket* aP
   }
 
   if (Layer* next = GetNextSibling()) {
     next->Dump(aPacket, aParent);
   }
 }
 
 void
+Layer::SetDisplayListLog(const char* log)
+{
+  if (gfxUtils::DumpDisplayList()) {
+    mDisplayListLog = log;
+  }
+}
+
+void
+Layer::GetDisplayListLog(nsCString& log)
+{
+  log.SetLength(0);
+
+  if (gfxUtils::DumpDisplayList()) {
+    // This function returns a plain text string which consists of two things
+    //   1. DisplayList log.
+    //   2. Memory address of this layer.
+    // We know the target layer of each display item by information in #1.
+    // Here is an example of a Text display item line log in #1
+    //   Text p=0xa9850c00 f=0x0xaa405b00(.....
+    // f keeps the address of the target client layer of a display item.
+    // For LayerScope, display-item-to-client-layer mapping is not enough since
+    // LayerScope, which lives in the chrome process, knows only composite layers.
+    // As so, we need display-item-to-client-layer-to-layer-composite
+    // mapping. That's the reason we insert #2 into the log
+    log.AppendPrintf("0x%p\n%s",(void*) this, mDisplayListLog.get());
+  }
+}
+
+void
 Layer::Log(const char* aPrefix)
 {
   if (!IsLogEnabled())
     return;
 
   LogSelf(aPrefix);
 
   if (Layer* kid = GetFirstChild()) {
@@ -1802,20 +1833,32 @@ Layer::DumpPacket(layerscope::LayersPack
   layer->set_calpha(static_cast<bool>(GetContentFlags() & CONTENT_COMPONENT_ALPHA));
   // Vertical or horizontal bar
   if (GetScrollbarDirection() != NONE) {
     layer->set_direct(GetScrollbarDirection() == VERTICAL ?
                       LayersPacket::Layer::VERTICAL :
                       LayersPacket::Layer::HORIZONTAL);
     layer->set_barid(GetScrollbarTargetContainerId());
   }
+
   // Mask layer
   if (mMaskLayer) {
     layer->set_mask(reinterpret_cast<uint64_t>(mMaskLayer.get()));
   }
+
+  // DisplayList log.
+  if (mDisplayListLog.Length() > 0) {
+    layer->set_displaylistloglength(mDisplayListLog.Length());
+    auto compressedData =
+      MakeUnique<char[]>(LZ4::maxCompressedSize(mDisplayListLog.Length()));
+    int compressedSize = LZ4::compress((char*)mDisplayListLog.get(),
+                                       mDisplayListLog.Length(),
+                                       compressedData.get());
+    layer->set_displaylistlog(compressedData.get(), compressedSize);
+  }
 }
 
 void
 PaintedLayer::PrintInfo(std::stringstream& aStream, const char* aPrefix)
 {
   Layer::PrintInfo(aStream, aPrefix);
   if (!mValidRegion.IsEmpty()) {
     AppendToString(aStream, mValidRegion, " [valid=", "]");
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -1578,16 +1578,26 @@ public:
   // an implementation that first calls the base implementation then
   // appends additional info to aTo.
   virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix);
 
   // Just like PrintInfo, but this function dump information into layerscope packet,
   // instead of a StringStream. It is also internally used to implement Dump();
   virtual void DumpPacket(layerscope::LayersPacket* aPacket, const void* aParent);
 
+  /**
+   * Store display list log.
+   */
+  void SetDisplayListLog(const char *log);
+
+  /**
+   * Return display list log.
+   */
+  void GetDisplayListLog(nsCString& log);
+
   static bool IsLogEnabled() { return LayerManager::IsLogEnabled(); }
 
   /**
    * Returns the current area of the layer (in layer-space coordinates)
    * marked as needed to be recomposited.
    */
   const nsIntRegion& GetInvalidRegion() { return mInvalidRegion; }
   const void SetInvalidRegion(const nsIntRegion& aRect) { mInvalidRegion = aRect; }
@@ -1780,16 +1790,18 @@ protected:
   bool mIsScrollbarContainer;
   DebugOnly<uint32_t> mDebugColorIndex;
   // If this layer is used for OMTA, then this counter is used to ensure we
   // stay in sync with the animation manager
   uint64_t mAnimationGeneration;
 #ifdef MOZ_DUMP_PAINTING
   nsTArray<nsCString> mExtraDumpInfo;
 #endif
+  // Store display list log.
+  nsCString mDisplayListLog;
 };
 
 /**
  * A Layer which we can paint into. It is a conceptually
  * infinite surface, but each PaintedLayer has an associated "valid region"
  * of contents that it is currently storing, which is finite. PaintedLayer
  * implementations can store content between paints.
  *
--- a/gfx/layers/ipc/CompositorParent.cpp
+++ b/gfx/layers/ipc/CompositorParent.cpp
@@ -70,16 +70,18 @@
 #include "ProfilerMarkers.h"
 #endif
 #include "mozilla/VsyncDispatcher.h"
 
 #ifdef MOZ_WIDGET_GONK
 #include "GeckoTouchDispatcher.h"
 #endif
 
+#include "LayerScope.h"
+
 namespace mozilla {
 namespace layers {
 
 using namespace mozilla::ipc;
 using namespace mozilla::gfx;
 using namespace std;
 
 using base::ProcessId;
@@ -676,16 +678,18 @@ CompositorParent::CompositorParent(nsIWi
   if (UseVsyncComposition()) {
     gfxDebugOnce() << "Enabling vsync compositor";
     mCompositorScheduler = new CompositorVsyncScheduler(this, aWidget);
   } else {
     mCompositorScheduler = new CompositorSoftwareTimerScheduler(this);
   }
 
   gfxPlatform::GetPlatform()->ComputeTileSize();
+
+  LayerScope::SetPixelScale(mWidget->GetDefaultScale().scale);
 }
 
 bool
 CompositorParent::IsInCompositorThread()
 {
   return CompositorThread() && CompositorThread()->thread_id() == PlatformThread::CurrentId();
 }
 
--- a/gfx/layers/ipc/LayerTransactionParent.cpp
+++ b/gfx/layers/ipc/LayerTransactionParent.cpp
@@ -342,16 +342,17 @@ LayerTransactionParent::RecvUpdate(Infal
       if (PLayerParent* maskLayer = common.maskLayerParent()) {
         layer->SetMaskLayer(cast(maskLayer)->AsLayer());
       } else {
         layer->SetMaskLayer(nullptr);
       }
       layer->SetAnimations(common.animations());
       layer->SetInvalidRegion(common.invalidRegion());
       layer->SetFrameMetrics(common.metrics());
+      layer->SetDisplayListLog(common.displayListLog().get());
 
       nsTArray<nsRefPtr<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);
 
--- a/gfx/layers/ipc/LayersMessages.ipdlh
+++ b/gfx/layers/ipc/LayersMessages.ipdlh
@@ -228,16 +228,17 @@ struct CommonLayerAttributes {
   bool forceIsolatedGroup;
   nullable PLayer maskLayer;
   PLayer[] ancestorMaskLayers;
   // Animated colors will only honored for ColorLayers.
   Animation[] animations;
   nsIntRegion invalidRegion;
   FrameMetrics[] metrics;
   string contentDescription;
+  nsCString displayListLog;
 };
 
 struct PaintedLayerAttributes {
   nsIntRegion validRegion;
 };
 struct ContainerLayerAttributes {
   float preXScale;
   float preYScale;
--- a/gfx/layers/ipc/ShadowLayers.cpp
+++ b/gfx/layers/ipc/ShadowLayers.cpp
@@ -608,16 +608,20 @@ ShadowLayerForwarder::EndTransaction(Inf
     common.maskLayerParent() = nullptr;
     common.animations() = mutant->GetAnimations();
     common.invalidRegion() = mutant->GetInvalidRegion();
     common.metrics() = mutant->GetAllFrameMetrics();
     for (size_t i = 0; i < mutant->GetAncestorMaskLayerCount(); i++) {
       auto layer = Shadow(mutant->GetAncestorMaskLayerAt(i)->AsShadowableLayer());
       common.ancestorMaskLayersChild().AppendElement(layer);
     }
+    nsCString log;
+    mutant->GetDisplayListLog(log);
+    common.displayListLog() = log;
+
     attrs.specific() = null_t();
     mutant->FillSpecificAttributes(attrs.specific());
 
     MOZ_LAYERS_LOG(("[LayersForwarder] OpSetLayerAttributes(%p)\n", mutant));
 
     mTxn->AddEdit(OpSetLayerAttributes(nullptr, Shadow(shadow), attrs));
   }
 
--- a/gfx/layers/opengl/CompositorOGL.cpp
+++ b/gfx/layers/opengl/CompositorOGL.cpp
@@ -1622,17 +1622,17 @@ CompositorOGL::BindAndDrawQuads(ShaderPr
   aProg->SetLayerRects(aLayerRects);
   if (aProg->GetTextureCount() > 0) {
     aProg->SetTextureRects(aTextureRects);
   }
 
   // We are using GL_TRIANGLES here because the Mac Intel drivers fail to properly
   // process uniform arrays with GL_TRIANGLE_STRIP. Go figure.
   mGLContext->fDrawArrays(LOCAL_GL_TRIANGLES, 0, 6 * aQuads);
-  LayerScope::SetLayerRects(aQuads, aLayerRects);
+  LayerScope::SetDrawRects(aQuads, aLayerRects, aTextureRects);
 }
 
 GLBlitTextureImageHelper*
 CompositorOGL::BlitTextureImageHelper()
 {
     if (!mBlitTextureImageHelper) {
         mBlitTextureImageHelper = MakeUnique<GLBlitTextureImageHelper>(this);
     }
--- a/gfx/layers/protobuf/LayerScopePacket.pb.cc
+++ b/gfx/layers/protobuf/LayerScopePacket.pb.cc
@@ -94,16 +94,17 @@ struct StaticDescriptorInitializer_Layer
   }
 } static_descriptor_initializer_LayerScopePacket_2eproto_;
 #endif
 
 // ===================================================================
 
 #ifndef _MSC_VER
 const int FramePacket::kValueFieldNumber;
+const int FramePacket::kScaleFieldNumber;
 #endif  // !_MSC_VER
 
 FramePacket::FramePacket()
   : ::google::protobuf::MessageLite() {
   SharedCtor();
   // @@protoc_insertion_point(constructor:mozilla.layers.layerscope.FramePacket)
 }
 
@@ -115,16 +116,17 @@ FramePacket::FramePacket(const FramePack
   SharedCtor();
   MergeFrom(from);
   // @@protoc_insertion_point(copy_constructor:mozilla.layers.layerscope.FramePacket)
 }
 
 void FramePacket::SharedCtor() {
   _cached_size_ = 0;
   value_ = GOOGLE_ULONGLONG(0);
+  scale_ = 0;
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
 }
 
 FramePacket::~FramePacket() {
   // @@protoc_insertion_point(destructor:mozilla.layers.layerscope.FramePacket)
   SharedDtor();
 }
 
@@ -153,17 +155,31 @@ const FramePacket& FramePacket::default_
 
 FramePacket* FramePacket::default_instance_ = NULL;
 
 FramePacket* FramePacket::New() const {
   return new FramePacket;
 }
 
 void FramePacket::Clear() {
-  value_ = GOOGLE_ULONGLONG(0);
+#define OFFSET_OF_FIELD_(f) (reinterpret_cast<char*>(      \
+  &reinterpret_cast<FramePacket*>(16)->f) - \
+   reinterpret_cast<char*>(16))
+
+#define ZR_(first, last) do {                              \
+    size_t f = OFFSET_OF_FIELD_(first);                    \
+    size_t n = OFFSET_OF_FIELD_(last) - f + sizeof(last);  \
+    ::memset(&first, 0, n);                                \
+  } while (0)
+
+  ZR_(value_, scale_);
+
+#undef OFFSET_OF_FIELD_
+#undef ZR_
+
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
   mutable_unknown_fields()->clear();
 }
 
 bool FramePacket::MergePartialFromCodedStream(
     ::google::protobuf::io::CodedInputStream* input) {
 #define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
   ::google::protobuf::uint32 tag;
@@ -182,16 +198,31 @@ bool FramePacket::MergePartialFromCodedS
         if (tag == 8) {
           DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
                    ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>(
                  input, &value_)));
           set_has_value();
         } else {
           goto handle_unusual;
         }
+        if (input->ExpectTag(21)) goto parse_scale;
+        break;
+      }
+
+      // optional float scale = 2;
+      case 2: {
+        if (tag == 21) {
+         parse_scale:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &scale_)));
+          set_has_scale();
+        } else {
+          goto handle_unusual;
+        }
         if (input->ExpectAtEnd()) goto success;
         break;
       }
 
       default: {
       handle_unusual:
         if (tag == 0 ||
             ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -216,32 +247,42 @@ failure:
 void FramePacket::SerializeWithCachedSizes(
     ::google::protobuf::io::CodedOutputStream* output) const {
   // @@protoc_insertion_point(serialize_start:mozilla.layers.layerscope.FramePacket)
   // optional uint64 value = 1;
   if (has_value()) {
     ::google::protobuf::internal::WireFormatLite::WriteUInt64(1, this->value(), output);
   }
 
+  // optional float scale = 2;
+  if (has_scale()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(2, this->scale(), output);
+  }
+
   output->WriteRaw(unknown_fields().data(),
                    unknown_fields().size());
   // @@protoc_insertion_point(serialize_end:mozilla.layers.layerscope.FramePacket)
 }
 
 int FramePacket::ByteSize() const {
   int total_size = 0;
 
   if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
     // optional uint64 value = 1;
     if (has_value()) {
       total_size += 1 +
         ::google::protobuf::internal::WireFormatLite::UInt64Size(
           this->value());
     }
 
+    // optional float scale = 2;
+    if (has_scale()) {
+      total_size += 1 + 4;
+    }
+
   }
   total_size += unknown_fields().size();
 
   GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
   _cached_size_ = total_size;
   GOOGLE_SAFE_CONCURRENT_WRITES_END();
   return total_size;
 }
@@ -252,16 +293,19 @@ void FramePacket::CheckTypeAndMergeFrom(
 }
 
 void FramePacket::MergeFrom(const FramePacket& from) {
   GOOGLE_CHECK_NE(&from, this);
   if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
     if (from.has_value()) {
       set_value(from.value());
     }
+    if (from.has_scale()) {
+      set_scale(from.scale());
+    }
   }
   mutable_unknown_fields()->append(from.unknown_fields());
 }
 
 void FramePacket::CopyFrom(const FramePacket& from) {
   if (&from == this) return;
   Clear();
   MergeFrom(from);
@@ -270,16 +314,17 @@ void FramePacket::CopyFrom(const FramePa
 bool FramePacket::IsInitialized() const {
 
   return true;
 }
 
 void FramePacket::Swap(FramePacket* other) {
   if (other != this) {
     std::swap(value_, other->value_);
+    std::swap(scale_, other->scale_);
     std::swap(_has_bits_[0], other->_has_bits_[0]);
     _unknown_fields_.swap(other->_unknown_fields_);
     std::swap(_cached_size_, other->_cached_size_);
   }
 }
 
 ::std::string FramePacket::GetTypeName() const {
   return "mozilla.layers.layerscope.FramePacket";
@@ -2454,16 +2499,18 @@ const int LayersPacket_Layer::kDispatchR
 const int LayersPacket_Layer::kNoActionRegionFieldNumber;
 const int LayersPacket_Layer::kHPanRegionFieldNumber;
 const int LayersPacket_Layer::kVPanRegionFieldNumber;
 const int LayersPacket_Layer::kValidFieldNumber;
 const int LayersPacket_Layer::kColorFieldNumber;
 const int LayersPacket_Layer::kFilterFieldNumber;
 const int LayersPacket_Layer::kRefIDFieldNumber;
 const int LayersPacket_Layer::kSizeFieldNumber;
+const int LayersPacket_Layer::kDisplayListLogLengthFieldNumber;
+const int LayersPacket_Layer::kDisplayListLogFieldNumber;
 #endif  // !_MSC_VER
 
 LayersPacket_Layer::LayersPacket_Layer()
   : ::google::protobuf::MessageLite() {
   SharedCtor();
   // @@protoc_insertion_point(constructor:mozilla.layers.layerscope.LayersPacket.Layer)
 }
 
@@ -2539,16 +2586,17 @@ void LayersPacket_Layer::InitAsDefaultIn
 LayersPacket_Layer::LayersPacket_Layer(const LayersPacket_Layer& from)
   : ::google::protobuf::MessageLite() {
   SharedCtor();
   MergeFrom(from);
   // @@protoc_insertion_point(copy_constructor:mozilla.layers.layerscope.LayersPacket.Layer)
 }
 
 void LayersPacket_Layer::SharedCtor() {
+  ::google::protobuf::internal::GetEmptyString();
   _cached_size_ = 0;
   type_ = 0;
   ptr_ = GOOGLE_ULONGLONG(0);
   parentptr_ = GOOGLE_ULONGLONG(0);
   clip_ = NULL;
   transform_ = NULL;
   vregion_ = NULL;
   shadow_ = NULL;
@@ -2563,25 +2611,30 @@ void LayersPacket_Layer::SharedCtor() {
   noactionregion_ = NULL;
   hpanregion_ = NULL;
   vpanregion_ = NULL;
   valid_ = NULL;
   color_ = 0u;
   filter_ = 0;
   refid_ = GOOGLE_ULONGLONG(0);
   size_ = NULL;
+  displaylistloglength_ = 0u;
+  displaylistlog_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
 }
 
 LayersPacket_Layer::~LayersPacket_Layer() {
   // @@protoc_insertion_point(destructor:mozilla.layers.layerscope.LayersPacket.Layer)
   SharedDtor();
 }
 
 void LayersPacket_Layer::SharedDtor() {
+  if (displaylistlog_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
+    delete displaylistlog_;
+  }
   #ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
   if (this != &default_instance()) {
   #else
   if (this != default_instance_) {
   #endif
     delete clip_;
     delete transform_;
     delete vregion_;
@@ -2652,30 +2705,36 @@ void LayersPacket_Layer::Clear() {
     }
     if (has_dispatchregion()) {
       if (dispatchregion_ != NULL) dispatchregion_->::mozilla::layers::layerscope::LayersPacket_Layer_Region::Clear();
     }
     if (has_noactionregion()) {
       if (noactionregion_ != NULL) noactionregion_->::mozilla::layers::layerscope::LayersPacket_Layer_Region::Clear();
     }
   }
-  if (_has_bits_[16 / 32] & 8323072) {
+  if (_has_bits_[16 / 32] & 16711680) {
     ZR_(color_, refid_);
     if (has_hpanregion()) {
       if (hpanregion_ != NULL) hpanregion_->::mozilla::layers::layerscope::LayersPacket_Layer_Region::Clear();
     }
     if (has_vpanregion()) {
       if (vpanregion_ != NULL) vpanregion_->::mozilla::layers::layerscope::LayersPacket_Layer_Region::Clear();
     }
     if (has_valid()) {
       if (valid_ != NULL) valid_->::mozilla::layers::layerscope::LayersPacket_Layer_Region::Clear();
     }
     if (has_size()) {
       if (size_ != NULL) size_->::mozilla::layers::layerscope::LayersPacket_Layer_Size::Clear();
     }
+    displaylistloglength_ = 0u;
+  }
+  if (has_displaylistlog()) {
+    if (displaylistlog_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
+      displaylistlog_->clear();
+    }
   }
 
 #undef OFFSET_OF_FIELD_
 #undef ZR_
 
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
   mutable_unknown_fields()->clear();
 }
@@ -3025,16 +3084,44 @@ bool LayersPacket_Layer::MergePartialFro
       case 104: {
         if (tag == 834) {
          parse_size:
           DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
                input, mutable_size()));
         } else {
           goto handle_unusual;
         }
+        if (input->ExpectTag(840)) goto parse_displayListLogLength;
+        break;
+      }
+
+      // optional uint32 displayListLogLength = 105;
+      case 105: {
+        if (tag == 840) {
+         parse_displayListLogLength:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &displaylistloglength_)));
+          set_has_displaylistloglength();
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(850)) goto parse_displayListLog;
+        break;
+      }
+
+      // optional bytes displayListLog = 106;
+      case 106: {
+        if (tag == 850) {
+         parse_displayListLog:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadBytes(
+                input, this->mutable_displaylistlog()));
+        } else {
+          goto handle_unusual;
+        }
         if (input->ExpectAtEnd()) goto success;
         break;
       }
 
       default: {
       handle_unusual:
         if (tag == 0 ||
             ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -3183,16 +3270,27 @@ void LayersPacket_Layer::SerializeWithCa
   }
 
   // optional .mozilla.layers.layerscope.LayersPacket.Layer.Size size = 104;
   if (has_size()) {
     ::google::protobuf::internal::WireFormatLite::WriteMessage(
       104, this->size(), output);
   }
 
+  // optional uint32 displayListLogLength = 105;
+  if (has_displaylistloglength()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(105, this->displaylistloglength(), output);
+  }
+
+  // optional bytes displayListLog = 106;
+  if (has_displaylistlog()) {
+    ::google::protobuf::internal::WireFormatLite::WriteBytesMaybeAliased(
+      106, this->displaylistlog(), output);
+  }
+
   output->WriteRaw(unknown_fields().data(),
                    unknown_fields().size());
   // @@protoc_insertion_point(serialize_end:mozilla.layers.layerscope.LayersPacket.Layer)
 }
 
 int LayersPacket_Layer::ByteSize() const {
   int total_size = 0;
 
@@ -3348,16 +3446,32 @@ int LayersPacket_Layer::ByteSize() const
 
     // optional .mozilla.layers.layerscope.LayersPacket.Layer.Size size = 104;
     if (has_size()) {
       total_size += 2 +
         ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
           this->size());
     }
 
+    // optional uint32 displayListLogLength = 105;
+    if (has_displaylistloglength()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->displaylistloglength());
+    }
+
+  }
+  if (_has_bits_[24 / 32] & (0xffu << (24 % 32))) {
+    // optional bytes displayListLog = 106;
+    if (has_displaylistlog()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::BytesSize(
+          this->displaylistlog());
+    }
+
   }
   total_size += unknown_fields().size();
 
   GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
   _cached_size_ = total_size;
   GOOGLE_SAFE_CONCURRENT_WRITES_END();
   return total_size;
 }
@@ -3438,16 +3552,24 @@ void LayersPacket_Layer::MergeFrom(const
       set_filter(from.filter());
     }
     if (from.has_refid()) {
       set_refid(from.refid());
     }
     if (from.has_size()) {
       mutable_size()->::mozilla::layers::layerscope::LayersPacket_Layer_Size::MergeFrom(from.size());
     }
+    if (from.has_displaylistloglength()) {
+      set_displaylistloglength(from.displaylistloglength());
+    }
+  }
+  if (from._has_bits_[24 / 32] & (0xffu << (24 % 32))) {
+    if (from.has_displaylistlog()) {
+      set_displaylistlog(from.displaylistlog());
+    }
   }
   mutable_unknown_fields()->append(from.unknown_fields());
 }
 
 void LayersPacket_Layer::CopyFrom(const LayersPacket_Layer& from) {
   if (&from == this) return;
   Clear();
   MergeFrom(from);
@@ -3479,16 +3601,18 @@ void LayersPacket_Layer::Swap(LayersPack
     std::swap(noactionregion_, other->noactionregion_);
     std::swap(hpanregion_, other->hpanregion_);
     std::swap(vpanregion_, other->vpanregion_);
     std::swap(valid_, other->valid_);
     std::swap(color_, other->color_);
     std::swap(filter_, other->filter_);
     std::swap(refid_, other->refid_);
     std::swap(size_, other->size_);
+    std::swap(displaylistloglength_, other->displaylistloglength_);
+    std::swap(displaylistlog_, other->displaylistlog_);
     std::swap(_has_bits_[0], other->_has_bits_[0]);
     _unknown_fields_.swap(other->_unknown_fields_);
     std::swap(_cached_size_, other->_cached_size_);
   }
 }
 
 ::std::string LayersPacket_Layer::GetTypeName() const {
   return "mozilla.layers.layerscope.LayersPacket.Layer";
@@ -4172,16 +4296,18 @@ void DrawPacket_Rect::Swap(DrawPacket_Re
 
 #ifndef _MSC_VER
 const int DrawPacket::kOffsetXFieldNumber;
 const int DrawPacket::kOffsetYFieldNumber;
 const int DrawPacket::kMvMatrixFieldNumber;
 const int DrawPacket::kTotalRectsFieldNumber;
 const int DrawPacket::kLayerRectFieldNumber;
 const int DrawPacket::kLayerrefFieldNumber;
+const int DrawPacket::kTexIDsFieldNumber;
+const int DrawPacket::kTextureRectFieldNumber;
 #endif  // !_MSC_VER
 
 DrawPacket::DrawPacket()
   : ::google::protobuf::MessageLite() {
   SharedCtor();
   // @@protoc_insertion_point(constructor:mozilla.layers.layerscope.DrawPacket)
 }
 
@@ -4244,24 +4370,29 @@ void DrawPacket::Clear() {
    reinterpret_cast<char*>(16))
 
 #define ZR_(first, last) do {                              \
     size_t f = OFFSET_OF_FIELD_(first);                    \
     size_t n = OFFSET_OF_FIELD_(last) - f + sizeof(last);  \
     ::memset(&first, 0, n);                                \
   } while (0)
 
-  ZR_(offsetx_, offsety_);
-  ZR_(layerref_, totalrects_);
+  if (_has_bits_[0 / 32] & 43) {
+    ZR_(offsetx_, offsety_);
+    totalrects_ = 0u;
+    layerref_ = GOOGLE_ULONGLONG(0);
+  }
 
 #undef OFFSET_OF_FIELD_
 #undef ZR_
 
   mvmatrix_.Clear();
   layerrect_.Clear();
+  texids_.Clear();
+  texturerect_.Clear();
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
   mutable_unknown_fields()->clear();
 }
 
 bool DrawPacket::MergePartialFromCodedStream(
     ::google::protobuf::io::CodedInputStream* input) {
 #define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
   ::google::protobuf::uint32 tag;
@@ -4358,16 +4489,49 @@ bool DrawPacket::MergePartialFromCodedSt
          parse_layerref:
           DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
                    ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>(
                  input, &layerref_)));
           set_has_layerref();
         } else {
           goto handle_unusual;
         }
+        if (input->ExpectTag(56)) goto parse_texIDs;
+        break;
+      }
+
+      // repeated uint32 texIDs = 7;
+      case 7: {
+        if (tag == 56) {
+         parse_texIDs:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 1, 56, input, this->mutable_texids())));
+        } else if (tag == 58) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitiveNoInline<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, this->mutable_texids())));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(56)) goto parse_texIDs;
+        if (input->ExpectTag(66)) goto parse_textureRect;
+        break;
+      }
+
+      // repeated .mozilla.layers.layerscope.DrawPacket.Rect textureRect = 8;
+      case 8: {
+        if (tag == 66) {
+         parse_textureRect:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+                input, add_texturerect()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(66)) goto parse_textureRect;
         if (input->ExpectAtEnd()) goto success;
         break;
       }
 
       default: {
       handle_unusual:
         if (tag == 0 ||
             ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
@@ -4419,16 +4583,28 @@ void DrawPacket::SerializeWithCachedSize
       5, this->layerrect(i), output);
   }
 
   // required uint64 layerref = 6;
   if (has_layerref()) {
     ::google::protobuf::internal::WireFormatLite::WriteUInt64(6, this->layerref(), output);
   }
 
+  // repeated uint32 texIDs = 7;
+  for (int i = 0; i < this->texids_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(
+      7, this->texids(i), output);
+  }
+
+  // repeated .mozilla.layers.layerscope.DrawPacket.Rect textureRect = 8;
+  for (int i = 0; i < this->texturerect_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessage(
+      8, this->texturerect(i), output);
+  }
+
   output->WriteRaw(unknown_fields().data(),
                    unknown_fields().size());
   // @@protoc_insertion_point(serialize_end:mozilla.layers.layerscope.DrawPacket)
 }
 
 int DrawPacket::ByteSize() const {
   int total_size = 0;
 
@@ -4468,16 +4644,34 @@ int DrawPacket::ByteSize() const {
   // repeated .mozilla.layers.layerscope.DrawPacket.Rect layerRect = 5;
   total_size += 1 * this->layerrect_size();
   for (int i = 0; i < this->layerrect_size(); i++) {
     total_size +=
       ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
         this->layerrect(i));
   }
 
+  // repeated uint32 texIDs = 7;
+  {
+    int data_size = 0;
+    for (int i = 0; i < this->texids_size(); i++) {
+      data_size += ::google::protobuf::internal::WireFormatLite::
+        UInt32Size(this->texids(i));
+    }
+    total_size += 1 * this->texids_size() + data_size;
+  }
+
+  // repeated .mozilla.layers.layerscope.DrawPacket.Rect textureRect = 8;
+  total_size += 1 * this->texturerect_size();
+  for (int i = 0; i < this->texturerect_size(); i++) {
+    total_size +=
+      ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+        this->texturerect(i));
+  }
+
   total_size += unknown_fields().size();
 
   GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
   _cached_size_ = total_size;
   GOOGLE_SAFE_CONCURRENT_WRITES_END();
   return total_size;
 }
 
@@ -4485,16 +4679,18 @@ void DrawPacket::CheckTypeAndMergeFrom(
     const ::google::protobuf::MessageLite& from) {
   MergeFrom(*::google::protobuf::down_cast<const DrawPacket*>(&from));
 }
 
 void DrawPacket::MergeFrom(const DrawPacket& from) {
   GOOGLE_CHECK_NE(&from, this);
   mvmatrix_.MergeFrom(from.mvmatrix_);
   layerrect_.MergeFrom(from.layerrect_);
+  texids_.MergeFrom(from.texids_);
+  texturerect_.MergeFrom(from.texturerect_);
   if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
     if (from.has_offsetx()) {
       set_offsetx(from.offsetx());
     }
     if (from.has_offsety()) {
       set_offsety(from.offsety());
     }
     if (from.has_totalrects()) {
@@ -4512,27 +4708,30 @@ void DrawPacket::CopyFrom(const DrawPack
   Clear();
   MergeFrom(from);
 }
 
 bool DrawPacket::IsInitialized() const {
   if ((_has_bits_[0] & 0x0000002b) != 0x0000002b) return false;
 
   if (!::google::protobuf::internal::AllAreInitialized(this->layerrect())) return false;
+  if (!::google::protobuf::internal::AllAreInitialized(this->texturerect())) return false;
   return true;
 }
 
 void DrawPacket::Swap(DrawPacket* other) {
   if (other != this) {
     std::swap(offsetx_, other->offsetx_);
     std::swap(offsety_, other->offsety_);
     mvmatrix_.Swap(&other->mvmatrix_);
     std::swap(totalrects_, other->totalrects_);
     layerrect_.Swap(&other->layerrect_);
     std::swap(layerref_, other->layerref_);
+    texids_.Swap(&other->texids_);
+    texturerect_.Swap(&other->texturerect_);
     std::swap(_has_bits_[0], other->_has_bits_[0]);
     _unknown_fields_.swap(other->_unknown_fields_);
     std::swap(_cached_size_, other->_cached_size_);
   }
 }
 
 ::std::string DrawPacket::GetTypeName() const {
   return "mozilla.layers.layerscope.DrawPacket";
--- a/gfx/layers/protobuf/LayerScopePacket.pb.h
+++ b/gfx/layers/protobuf/LayerScopePacket.pb.h
@@ -178,26 +178,36 @@ class FramePacket : public ::google::pro
 
   // optional uint64 value = 1;
   inline bool has_value() const;
   inline void clear_value();
   static const int kValueFieldNumber = 1;
   inline ::google::protobuf::uint64 value() const;
   inline void set_value(::google::protobuf::uint64 value);
 
+  // optional float scale = 2;
+  inline bool has_scale() const;
+  inline void clear_scale();
+  static const int kScaleFieldNumber = 2;
+  inline float scale() const;
+  inline void set_scale(float value);
+
   // @@protoc_insertion_point(class_scope:mozilla.layers.layerscope.FramePacket)
  private:
   inline void set_has_value();
   inline void clear_has_value();
+  inline void set_has_scale();
+  inline void clear_has_scale();
 
   ::std::string _unknown_fields_;
 
   ::google::protobuf::uint32 _has_bits_[1];
   mutable int _cached_size_;
   ::google::protobuf::uint64 value_;
+  float scale_;
   #ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
   friend void  protobuf_AddDesc_LayerScopePacket_2eproto_impl();
   #else
   friend void  protobuf_AddDesc_LayerScopePacket_2eproto();
   #endif
   friend void protobuf_AssignDesc_LayerScopePacket_2eproto();
   friend void protobuf_ShutdownFile_LayerScopePacket_2eproto();
 
@@ -1346,16 +1356,35 @@ class LayersPacket_Layer : public ::goog
   inline bool has_size() const;
   inline void clear_size();
   static const int kSizeFieldNumber = 104;
   inline const ::mozilla::layers::layerscope::LayersPacket_Layer_Size& size() const;
   inline ::mozilla::layers::layerscope::LayersPacket_Layer_Size* mutable_size();
   inline ::mozilla::layers::layerscope::LayersPacket_Layer_Size* release_size();
   inline void set_allocated_size(::mozilla::layers::layerscope::LayersPacket_Layer_Size* size);
 
+  // optional uint32 displayListLogLength = 105;
+  inline bool has_displaylistloglength() const;
+  inline void clear_displaylistloglength();
+  static const int kDisplayListLogLengthFieldNumber = 105;
+  inline ::google::protobuf::uint32 displaylistloglength() const;
+  inline void set_displaylistloglength(::google::protobuf::uint32 value);
+
+  // optional bytes displayListLog = 106;
+  inline bool has_displaylistlog() const;
+  inline void clear_displaylistlog();
+  static const int kDisplayListLogFieldNumber = 106;
+  inline const ::std::string& displaylistlog() const;
+  inline void set_displaylistlog(const ::std::string& value);
+  inline void set_displaylistlog(const char* value);
+  inline void set_displaylistlog(const void* value, size_t size);
+  inline ::std::string* mutable_displaylistlog();
+  inline ::std::string* release_displaylistlog();
+  inline void set_allocated_displaylistlog(::std::string* displaylistlog);
+
   // @@protoc_insertion_point(class_scope:mozilla.layers.layerscope.LayersPacket.Layer)
  private:
   inline void set_has_type();
   inline void clear_has_type();
   inline void set_has_ptr();
   inline void clear_has_ptr();
   inline void set_has_parentptr();
   inline void clear_has_parentptr();
@@ -1394,16 +1423,20 @@ class LayersPacket_Layer : public ::goog
   inline void set_has_color();
   inline void clear_has_color();
   inline void set_has_filter();
   inline void clear_has_filter();
   inline void set_has_refid();
   inline void clear_has_refid();
   inline void set_has_size();
   inline void clear_has_size();
+  inline void set_has_displaylistloglength();
+  inline void clear_has_displaylistloglength();
+  inline void set_has_displaylistlog();
+  inline void clear_has_displaylistlog();
 
   ::std::string _unknown_fields_;
 
   ::google::protobuf::uint32 _has_bits_[1];
   mutable int _cached_size_;
   ::google::protobuf::uint64 ptr_;
   ::google::protobuf::uint64 parentptr_;
   ::mozilla::layers::layerscope::LayersPacket_Layer_Rect* clip_;
@@ -1422,16 +1455,18 @@ class LayersPacket_Layer : public ::goog
   ::mozilla::layers::layerscope::LayersPacket_Layer_Region* noactionregion_;
   ::mozilla::layers::layerscope::LayersPacket_Layer_Region* hpanregion_;
   ::mozilla::layers::layerscope::LayersPacket_Layer_Region* vpanregion_;
   ::mozilla::layers::layerscope::LayersPacket_Layer_Region* valid_;
   ::google::protobuf::uint32 color_;
   int filter_;
   ::google::protobuf::uint64 refid_;
   ::mozilla::layers::layerscope::LayersPacket_Layer_Size* size_;
+  ::std::string* displaylistlog_;
+  ::google::protobuf::uint32 displaylistloglength_;
   #ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
   friend void  protobuf_AddDesc_LayerScopePacket_2eproto_impl();
   #else
   friend void  protobuf_AddDesc_LayerScopePacket_2eproto();
   #endif
   friend void protobuf_AssignDesc_LayerScopePacket_2eproto();
   friend void protobuf_ShutdownFile_LayerScopePacket_2eproto();
 
@@ -1858,16 +1893,40 @@ class DrawPacket : public ::google::prot
 
   // required uint64 layerref = 6;
   inline bool has_layerref() const;
   inline void clear_layerref();
   static const int kLayerrefFieldNumber = 6;
   inline ::google::protobuf::uint64 layerref() const;
   inline void set_layerref(::google::protobuf::uint64 value);
 
+  // repeated uint32 texIDs = 7;
+  inline int texids_size() const;
+  inline void clear_texids();
+  static const int kTexIDsFieldNumber = 7;
+  inline ::google::protobuf::uint32 texids(int index) const;
+  inline void set_texids(int index, ::google::protobuf::uint32 value);
+  inline void add_texids(::google::protobuf::uint32 value);
+  inline const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+      texids() const;
+  inline ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+      mutable_texids();
+
+  // repeated .mozilla.layers.layerscope.DrawPacket.Rect textureRect = 8;
+  inline int texturerect_size() const;
+  inline void clear_texturerect();
+  static const int kTextureRectFieldNumber = 8;
+  inline const ::mozilla::layers::layerscope::DrawPacket_Rect& texturerect(int index) const;
+  inline ::mozilla::layers::layerscope::DrawPacket_Rect* mutable_texturerect(int index);
+  inline ::mozilla::layers::layerscope::DrawPacket_Rect* add_texturerect();
+  inline const ::google::protobuf::RepeatedPtrField< ::mozilla::layers::layerscope::DrawPacket_Rect >&
+      texturerect() const;
+  inline ::google::protobuf::RepeatedPtrField< ::mozilla::layers::layerscope::DrawPacket_Rect >*
+      mutable_texturerect();
+
   // @@protoc_insertion_point(class_scope:mozilla.layers.layerscope.DrawPacket)
  private:
   inline void set_has_offsetx();
   inline void clear_has_offsetx();
   inline void set_has_offsety();
   inline void clear_has_offsety();
   inline void set_has_totalrects();
   inline void clear_has_totalrects();
@@ -1878,16 +1937,18 @@ class DrawPacket : public ::google::prot
 
   ::google::protobuf::uint32 _has_bits_[1];
   mutable int _cached_size_;
   float offsetx_;
   float offsety_;
   ::google::protobuf::RepeatedField< float > mvmatrix_;
   ::google::protobuf::RepeatedPtrField< ::mozilla::layers::layerscope::DrawPacket_Rect > layerrect_;
   ::google::protobuf::uint64 layerref_;
+  ::google::protobuf::RepeatedField< ::google::protobuf::uint32 > texids_;
+  ::google::protobuf::RepeatedPtrField< ::mozilla::layers::layerscope::DrawPacket_Rect > texturerect_;
   ::google::protobuf::uint32 totalrects_;
   #ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
   friend void  protobuf_AddDesc_LayerScopePacket_2eproto_impl();
   #else
   friend void  protobuf_AddDesc_LayerScopePacket_2eproto();
   #endif
   friend void protobuf_AssignDesc_LayerScopePacket_2eproto();
   friend void protobuf_ShutdownFile_LayerScopePacket_2eproto();
@@ -2217,16 +2278,40 @@ inline ::google::protobuf::uint64 FrameP
   return value_;
 }
 inline void FramePacket::set_value(::google::protobuf::uint64 value) {
   set_has_value();
   value_ = value;
   // @@protoc_insertion_point(field_set:mozilla.layers.layerscope.FramePacket.value)
 }
 
+// optional float scale = 2;
+inline bool FramePacket::has_scale() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void FramePacket::set_has_scale() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void FramePacket::clear_has_scale() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+inline void FramePacket::clear_scale() {
+  scale_ = 0;
+  clear_has_scale();
+}
+inline float FramePacket::scale() const {
+  // @@protoc_insertion_point(field_get:mozilla.layers.layerscope.FramePacket.scale)
+  return scale_;
+}
+inline void FramePacket::set_scale(float value) {
+  set_has_scale();
+  scale_ = value;
+  // @@protoc_insertion_point(field_set:mozilla.layers.layerscope.FramePacket.scale)
+}
+
 // -------------------------------------------------------------------
 
 // ColorPacket
 
 // required uint64 layerref = 1;
 inline bool ColorPacket::has_layerref() const {
   return (_has_bits_[0] & 0x00000001u) != 0;
 }
@@ -3786,16 +3871,116 @@ inline void LayersPacket_Layer::set_allo
   if (size) {
     set_has_size();
   } else {
     clear_has_size();
   }
   // @@protoc_insertion_point(field_set_allocated:mozilla.layers.layerscope.LayersPacket.Layer.size)
 }
 
+// optional uint32 displayListLogLength = 105;
+inline bool LayersPacket_Layer::has_displaylistloglength() const {
+  return (_has_bits_[0] & 0x00800000u) != 0;
+}
+inline void LayersPacket_Layer::set_has_displaylistloglength() {
+  _has_bits_[0] |= 0x00800000u;
+}
+inline void LayersPacket_Layer::clear_has_displaylistloglength() {
+  _has_bits_[0] &= ~0x00800000u;
+}
+inline void LayersPacket_Layer::clear_displaylistloglength() {
+  displaylistloglength_ = 0u;
+  clear_has_displaylistloglength();
+}
+inline ::google::protobuf::uint32 LayersPacket_Layer::displaylistloglength() const {
+  // @@protoc_insertion_point(field_get:mozilla.layers.layerscope.LayersPacket.Layer.displayListLogLength)
+  return displaylistloglength_;
+}
+inline void LayersPacket_Layer::set_displaylistloglength(::google::protobuf::uint32 value) {
+  set_has_displaylistloglength();
+  displaylistloglength_ = value;
+  // @@protoc_insertion_point(field_set:mozilla.layers.layerscope.LayersPacket.Layer.displayListLogLength)
+}
+
+// optional bytes displayListLog = 106;
+inline bool LayersPacket_Layer::has_displaylistlog() const {
+  return (_has_bits_[0] & 0x01000000u) != 0;
+}
+inline void LayersPacket_Layer::set_has_displaylistlog() {
+  _has_bits_[0] |= 0x01000000u;
+}
+inline void LayersPacket_Layer::clear_has_displaylistlog() {
+  _has_bits_[0] &= ~0x01000000u;
+}
+inline void LayersPacket_Layer::clear_displaylistlog() {
+  if (displaylistlog_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
+    displaylistlog_->clear();
+  }
+  clear_has_displaylistlog();
+}
+inline const ::std::string& LayersPacket_Layer::displaylistlog() const {
+  // @@protoc_insertion_point(field_get:mozilla.layers.layerscope.LayersPacket.Layer.displayListLog)
+  return *displaylistlog_;
+}
+inline void LayersPacket_Layer::set_displaylistlog(const ::std::string& value) {
+  set_has_displaylistlog();
+  if (displaylistlog_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
+    displaylistlog_ = new ::std::string;
+  }
+  displaylistlog_->assign(value);
+  // @@protoc_insertion_point(field_set:mozilla.layers.layerscope.LayersPacket.Layer.displayListLog)
+}
+inline void LayersPacket_Layer::set_displaylistlog(const char* value) {
+  set_has_displaylistlog();
+  if (displaylistlog_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
+    displaylistlog_ = new ::std::string;
+  }
+  displaylistlog_->assign(value);
+  // @@protoc_insertion_point(field_set_char:mozilla.layers.layerscope.LayersPacket.Layer.displayListLog)
+}
+inline void LayersPacket_Layer::set_displaylistlog(const void* value, size_t size) {
+  set_has_displaylistlog();
+  if (displaylistlog_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
+    displaylistlog_ = new ::std::string;
+  }
+  displaylistlog_->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:mozilla.layers.layerscope.LayersPacket.Layer.displayListLog)
+}
+inline ::std::string* LayersPacket_Layer::mutable_displaylistlog() {
+  set_has_displaylistlog();
+  if (displaylistlog_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
+    displaylistlog_ = new ::std::string;
+  }
+  // @@protoc_insertion_point(field_mutable:mozilla.layers.layerscope.LayersPacket.Layer.displayListLog)
+  return displaylistlog_;
+}
+inline ::std::string* LayersPacket_Layer::release_displaylistlog() {
+  clear_has_displaylistlog();
+  if (displaylistlog_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
+    return NULL;
+  } else {
+    ::std::string* temp = displaylistlog_;
+    displaylistlog_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+    return temp;
+  }
+}
+inline void LayersPacket_Layer::set_allocated_displaylistlog(::std::string* displaylistlog) {
+  if (displaylistlog_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
+    delete displaylistlog_;
+  }
+  if (displaylistlog) {
+    set_has_displaylistlog();
+    displaylistlog_ = displaylistlog;
+  } else {
+    clear_has_displaylistlog();
+    displaylistlog_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  }
+  // @@protoc_insertion_point(field_set_allocated:mozilla.layers.layerscope.LayersPacket.Layer.displayListLog)
+}
+
 // -------------------------------------------------------------------
 
 // LayersPacket
 
 // repeated .mozilla.layers.layerscope.LayersPacket.Layer layer = 1;
 inline int LayersPacket::layer_size() const {
   return layer_.size();
 }
@@ -4108,16 +4293,76 @@ inline ::google::protobuf::uint64 DrawPa
   return layerref_;
 }
 inline void DrawPacket::set_layerref(::google::protobuf::uint64 value) {
   set_has_layerref();
   layerref_ = value;
   // @@protoc_insertion_point(field_set:mozilla.layers.layerscope.DrawPacket.layerref)
 }
 
+// repeated uint32 texIDs = 7;
+inline int DrawPacket::texids_size() const {
+  return texids_.size();
+}
+inline void DrawPacket::clear_texids() {
+  texids_.Clear();
+}
+inline ::google::protobuf::uint32 DrawPacket::texids(int index) const {
+  // @@protoc_insertion_point(field_get:mozilla.layers.layerscope.DrawPacket.texIDs)
+  return texids_.Get(index);
+}
+inline void DrawPacket::set_texids(int index, ::google::protobuf::uint32 value) {
+  texids_.Set(index, value);
+  // @@protoc_insertion_point(field_set:mozilla.layers.layerscope.DrawPacket.texIDs)
+}
+inline void DrawPacket::add_texids(::google::protobuf::uint32 value) {
+  texids_.Add(value);
+  // @@protoc_insertion_point(field_add:mozilla.layers.layerscope.DrawPacket.texIDs)
+}
+inline const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+DrawPacket::texids() const {
+  // @@protoc_insertion_point(field_list:mozilla.layers.layerscope.DrawPacket.texIDs)
+  return texids_;
+}
+inline ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+DrawPacket::mutable_texids() {
+  // @@protoc_insertion_point(field_mutable_list:mozilla.layers.layerscope.DrawPacket.texIDs)
+  return &texids_;
+}
+
+// repeated .mozilla.layers.layerscope.DrawPacket.Rect textureRect = 8;
+inline int DrawPacket::texturerect_size() const {
+  return texturerect_.size();
+}
+inline void DrawPacket::clear_texturerect() {
+  texturerect_.Clear();
+}
+inline const ::mozilla::layers::layerscope::DrawPacket_Rect& DrawPacket::texturerect(int index) const {
+  // @@protoc_insertion_point(field_get:mozilla.layers.layerscope.DrawPacket.textureRect)
+  return texturerect_.Get(index);
+}
+inline ::mozilla::layers::layerscope::DrawPacket_Rect* DrawPacket::mutable_texturerect(int index) {
+  // @@protoc_insertion_point(field_mutable:mozilla.layers.layerscope.DrawPacket.textureRect)
+  return texturerect_.Mutable(index);
+}
+inline ::mozilla::layers::layerscope::DrawPacket_Rect* DrawPacket::add_texturerect() {
+  // @@protoc_insertion_point(field_add:mozilla.layers.layerscope.DrawPacket.textureRect)
+  return texturerect_.Add();
+}
+inline const ::google::protobuf::RepeatedPtrField< ::mozilla::layers::layerscope::DrawPacket_Rect >&
+DrawPacket::texturerect() const {
+  // @@protoc_insertion_point(field_list:mozilla.layers.layerscope.DrawPacket.textureRect)
+  return texturerect_;
+}
+inline ::google::protobuf::RepeatedPtrField< ::mozilla::layers::layerscope::DrawPacket_Rect >*
+DrawPacket::mutable_texturerect() {
+  // @@protoc_insertion_point(field_mutable_list:mozilla.layers.layerscope.DrawPacket.textureRect)
+  return &texturerect_;
+}
+
 // -------------------------------------------------------------------
 
 // Packet
 
 // required .mozilla.layers.layerscope.Packet.DataType type = 1;
 inline bool Packet::has_type() const {
   return (_has_bits_[0] & 0x00000001u) != 0;
 }
--- a/gfx/layers/protobuf/LayerScopePacket.proto
+++ b/gfx/layers/protobuf/LayerScopePacket.proto
@@ -4,16 +4,17 @@ option optimize_for = LITE_RUNTIME;
 
 package mozilla.layers.layerscope;
 
 // ===============================
 // Server to Client messages
 // ===============================
 message FramePacket {
   optional uint64 value = 1;
+  optional float  scale = 2;
 }
 
 message ColorPacket {
   required uint64 layerref = 1;
   optional uint32 width = 2;
   optional uint32 height = 3;
   optional uint32 color = 4;
 }
@@ -109,16 +110,18 @@ message LayersPacket {
     // Color Layer
     optional uint32 color = 101;
     // Canvas & Image Layer
     optional Filter filter = 102;
     // Ref Layer
     optional uint64 refID = 103;
     // Readback Layer
     optional Size size = 104;
+    optional uint32 displayListLogLength = 105;
+    optional bytes displayListLog = 106;
   }
   repeated Layer layer = 1;
 }
 
 message MetaPacket {
   optional bool composedByHwc = 1;
 }
 
@@ -131,16 +134,18 @@ message DrawPacket {
   }
 
   required float  offsetX = 1;
   required float  offsetY = 2;
   repeated float  mvMatrix = 3;
   required uint32 totalRects = 4;
   repeated Rect   layerRect = 5;
   required uint64 layerref = 6;
+  repeated uint32 texIDs = 7;
+  repeated Rect   textureRect = 8;
 }
 
 // We only need to use this Packet.
 // Other packet definitions are just type defines
 message Packet {
   enum DataType {
     FRAMESTART = 1;
     FRAMEEND = 2;
--- a/layout/base/nsLayoutDebugger.cpp
+++ b/layout/base/nsLayoutDebugger.cpp
@@ -259,26 +259,16 @@ PrintDisplayListTo(nsDisplayListBuilder*
   }
 
   if (aDumpHtml) {
     aStream << "</ul>";
   }
 }
 
 void
-nsFrame::PrintDisplayItem(nsDisplayListBuilder* aBuilder,
-                          nsDisplayItem* aItem,
-                          std::stringstream& aStream,
-                          bool aDumpSublist,
-                          bool aDumpHtml)
-{
-  PrintDisplayItemTo(aBuilder, aItem, aStream, 0, aDumpSublist, aDumpHtml);
-}
-
-void
 nsFrame::PrintDisplayList(nsDisplayListBuilder* aBuilder,
                           const nsDisplayList& aList,
                           std::stringstream& aStream,
                           bool aDumpHtml)
 {
   PrintDisplayListTo(aBuilder, aList, aStream, 0, aDumpHtml);
 }
 
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -3359,16 +3359,20 @@ nsLayoutUtils::PaintFrame(nsRenderingCon
       *ss << "</body></html>";
     }
     if (gfxUtils::sDumpPaintingToFile) {
       fclose(gfxUtils::sDumpPaintFile);
     }
     gfxUtils::sDumpPaintFile = savedDumpFile;
     gPaintCount++;
 #endif
+
+    std::stringstream lsStream;
+    nsFrame::PrintDisplayList(&builder, list, lsStream);
+    layerManager->GetRoot()->SetDisplayListLog(lsStream.str().c_str());
   }
 
 #ifdef MOZ_DUMP_PAINTING
   if (gfxPrefs::DumpClientLayers()) {
     std::stringstream ss;
     FrameLayerBuilder::DumpRetainedLayerTree(layerManager, ss, false);
     print_stderr(ss);
   }
--- a/layout/generic/nsFrame.h
+++ b/layout/generic/nsFrame.h
@@ -729,22 +729,16 @@ public:
   // Show frame border of event target
   static void ShowEventTargetFrameBorder(bool aEnable);
   static bool GetShowEventTargetFrameBorder();
 
 #endif
 
 public:
 
-  static void PrintDisplayItem(nsDisplayListBuilder* aBuilder,
-                               nsDisplayItem* aItem,
-                               std::stringstream& aStream,
-                               bool aDumpSublist = false,
-                               bool aDumpHtml = false);
-
   static void PrintDisplayList(nsDisplayListBuilder* aBuilder,
                                const nsDisplayList& aList,
                                bool aDumpHtml = false)
   {
     std::stringstream ss;
     PrintDisplayList(aBuilder, aList, ss, aDumpHtml);
     fprintf_stderr(stderr, "%s", ss.str().c_str());
   }
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -4629,17 +4629,17 @@ public:
     if (decorations != geometry->mDecorations ||
         mVisIStartEdge != geometry->mVisIStartEdge ||
         mVisIEndEdge != geometry->mVisIEndEdge ||
         !oldRect.IsEqualInterior(newRect) ||
         !geometry->mBorderRect.IsEqualInterior(GetBorderRect())) {
       aInvalidRegion->Or(oldRect, newRect);
     }
   }
-  
+
   virtual void DisableComponentAlpha() override {
     mDisableSubpixelAA = true;
   }
 
   bool mDisableSubpixelAA;
 };
 
 void