Send SimpleLayerAttributes separately from CommonLayerAttributes. (bug 1332567 part 6, r=mattwoodrow)
authorDavid Anderson <danderson@mozilla.com>
Tue, 24 Jan 2017 16:41:18 -0800
changeset 379942 44f9535628fd46d78fe020a8175bedc5f8b98680
parent 379941 810b96fdc6718f10916cb0851e9a392286bdbeb6
child 379943 2781e8137927e3970b142807a47d614650611966
push id1468
push userasasaki@mozilla.com
push dateMon, 05 Jun 2017 19:31:07 +0000
treeherdermozilla-release@0641fc6ee9d1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow
bugs1332567
milestone54.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Send SimpleLayerAttributes separately from CommonLayerAttributes. (bug 1332567 part 6, r=mattwoodrow)
gfx/ipc/GfxMessageUtils.h
gfx/layers/LayerAttributes.h
gfx/layers/Layers.cpp
gfx/layers/Layers.h
gfx/layers/client/ClientLayerManager.cpp
gfx/layers/client/ClientLayerManager.h
gfx/layers/ipc/LayerTransactionParent.cpp
gfx/layers/ipc/LayersMessages.ipdlh
gfx/layers/ipc/ShadowLayers.cpp
gfx/layers/ipc/ShadowLayers.h
--- a/gfx/ipc/GfxMessageUtils.h
+++ b/gfx/ipc/GfxMessageUtils.h
@@ -18,16 +18,17 @@
 #include "gfxTelemetry.h"
 #include "gfxTypes.h"
 #include "ipc/IPCMessageUtils.h"
 #include "mozilla/gfx/Matrix.h"
 #include "mozilla/layers/AsyncDragMetrics.h"
 #include "mozilla/layers/CompositorOptions.h"
 #include "mozilla/layers/CompositorTypes.h"
 #include "mozilla/layers/GeckoContentController.h"
+#include "mozilla/layers/LayerAttributes.h"
 #include "mozilla/layers/LayersTypes.h"
 #include "nsRect.h"
 #include "nsRegion.h"
 #include "mozilla/Array.h"
 
 #include <stdint.h>
 
 #ifdef _MSC_VER
@@ -1341,11 +1342,25 @@ struct ParamTraits<mozilla::layers::Comp
     WriteParam(aMsg, aParam.mUseAPZ);
   }
 
   static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult) {
     return ReadParam(aMsg, aIter, &aResult->mUseAPZ);
   }
 };
 
+template <>
+struct ParamTraits<mozilla::layers::SimpleLayerAttributes>
+{
+  typedef mozilla::layers::SimpleLayerAttributes paramType;
+
+  static void Write(Message* aMsg, const paramType& aParam) {
+    aMsg->WriteBytes(&aParam, sizeof(aParam));
+  }
+
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult) {
+    return aMsg->ReadBytesInto(aIter, aResult, sizeof(paramType));
+  }
+};
+
 } /* namespace IPC */
 
 #endif /* __GFXMESSAGEUTILS_H__ */
--- a/gfx/layers/LayerAttributes.h
+++ b/gfx/layers/LayerAttributes.h
@@ -5,23 +5,28 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #ifndef mozilla_gfx_layers_LayerAttributes_h
 #define mozilla_gfx_layers_LayerAttributes_h
 
 #include "mozilla/gfx/Types.h"
 #include "mozilla/layers/LayersTypes.h"
 
+namespace IPC {
+template <typename T> struct ParamTraits;
+} // namespace IPC
+
 namespace mozilla {
 namespace layers {
 
 // Infrequently changing layer attributes that require no special
 // serialization work.
 class SimpleLayerAttributes final
 {
+  friend struct IPC::ParamTraits<mozilla::layers::SimpleLayerAttributes>;
 public:
   SimpleLayerAttributes()
    : mTransformIsPerspective(false),
      mPostXScale(1.0f),
      mPostYScale(1.0f),
      mContentFlags(0),
      mOpacity(1.0f),
      mIsFixedPosition(false),
--- a/gfx/layers/Layers.cpp
+++ b/gfx/layers/Layers.cpp
@@ -151,23 +151,16 @@ LayerManager::CreatePersistentBufferProv
   if (!bufferProvider) {
     bufferProvider = PersistentBufferProviderBasic::Create(aSize, aFormat,
       gfxPlatform::GetPlatform()->GetFallbackCanvasBackend());
   }
 
   return bufferProvider.forget();
 }
 
-#ifdef DEBUG
-void
-LayerManager::Mutated(Layer* aLayer)
-{
-}
-#endif  // DEBUG
-
 already_AddRefed<ImageContainer>
 LayerManager::CreateImageContainer(ImageContainer::Mode flag)
 {
   RefPtr<ImageContainer> container = new ImageContainer(flag);
   return container.forget();
 }
 
 bool
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -355,22 +355,18 @@ public:
   LayerMetricsWrapper GetRootContentLayer();
 
   /**
    * CONSTRUCTION PHASE ONLY
    * Called when a managee has mutated.
    * Subclasses overriding this method must first call their
    * superclass's impl
    */
-#ifdef DEBUG
-  // In debug builds, we check some properties of |aLayer|.
-  virtual void Mutated(Layer* aLayer);
-#else
   virtual void Mutated(Layer* aLayer) { }
-#endif
+  virtual void MutatedSimple(Layer* aLayer) { }
 
   /**
    * Hints that can be used during PaintedLayer creation to influence the type
    * or properties of the layer created.
    *
    * NONE: No hint.
    * SCROLLABLE: This layer may represent scrollable content.
    */
@@ -837,33 +833,33 @@ public:
    */
   void SetContentFlags(uint32_t aFlags)
   {
     NS_ASSERTION((aFlags & (CONTENT_OPAQUE | CONTENT_COMPONENT_ALPHA)) !=
                  (CONTENT_OPAQUE | CONTENT_COMPONENT_ALPHA),
                  "Can't be opaque and require component alpha");
     if (mSimpleAttrs.SetContentFlags(aFlags)) {
       MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) ContentFlags", this));
-      Mutated();
+      MutatedSimple();
     }
   }
 
   /**
    * CONSTRUCTION PHASE ONLY
    * The union of the bounds of all the display item that got flattened
    * into this layer. This is intended to be an approximation to the
    * size of the layer if the nearest scrollable ancestor had an infinitely
    * large displayport. Computing this more exactly is too expensive,
    * but this approximation is sufficient for what we need to use it for.
    */
   virtual void SetLayerBounds(const gfx::IntRect& aLayerBounds)
   {
     if (mSimpleAttrs.SetLayerBounds(aLayerBounds)) {
       MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) LayerBounds", this));
-      Mutated();
+      MutatedSimple();
     }
   }
 
   /**
    * CONSTRUCTION PHASE ONLY
    * Tell this layer which region will be visible. The visible region
    * is a region which contains all the contents of the layer that can
    * actually affect the rendering of the window. It can exclude areas
@@ -977,33 +973,33 @@ public:
    * CONSTRUCTION PHASE ONLY
    * Set the opacity which will be applied to this layer as it
    * is composited to the destination.
    */
   void SetOpacity(float aOpacity)
   {
     if (mSimpleAttrs.SetOpacity(aOpacity)) {
       MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) Opacity", this));
-      Mutated();
+      MutatedSimple();
     }
   }
 
   void SetMixBlendMode(gfx::CompositionOp aMixBlendMode)
   {
     if (mSimpleAttrs.SetMixBlendMode(aMixBlendMode)) {
       MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) MixBlendMode", this));
-      Mutated();
+      MutatedSimple();
     }
   }
 
   void SetForceIsolatedGroup(bool aForceIsolatedGroup)
   {
     if (mSimpleAttrs.SetForceIsolatedGroup(aForceIsolatedGroup)) {
       MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) ForceIsolatedGroup", this));
-      Mutated();
+      MutatedSimple();
     }
   }
 
   bool GetForceIsolatedGroup() const
   {
     return mSimpleAttrs.ForceIsolatedGroup();
   }
 
@@ -1054,17 +1050,17 @@ public:
    * mClipRect is always fixed to the layer contents (which may or may not be
    * scrolled by some of the scroll frames associated with the layer, depending
    * on whether the layer is fixed).)
    */
   void SetScrolledClip(const Maybe<LayerClip>& aScrolledClip)
   {
     if (mSimpleAttrs.SetScrolledClip(aScrolledClip)) {
       MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) ScrolledClip", this));
-      Mutated();
+      MutatedSimple();
     }
   }
 
   /**
    * CONSTRUCTION PHASE ONLY
    * Set a layer to mask this layer.
    *
    * The mask layer should be applied using its effective transform (after it
@@ -1124,17 +1120,17 @@ public:
   {
     NS_ASSERTION(!aMatrix.IsSingular(),
                  "Shouldn't be trying to draw with a singular matrix!");
     mPendingTransform = nullptr;
     if (!mSimpleAttrs.SetTransform(aMatrix)) {
       return;
     }
     MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) BaseTransform", this));
-    Mutated();
+    MutatedSimple();
   }
 
   /**
    * Can be called at any time.
    *
    * Like SetBaseTransform(), but can be called before the next
    * transform (i.e. outside an open transaction).  Semantically, this
    * method enqueues a new transform value to be set immediately after
@@ -1146,44 +1142,44 @@ public:
   }
 
   void SetPostScale(float aXScale, float aYScale)
   {
     if (!mSimpleAttrs.SetPostScale(aXScale, aYScale)) {
       return;
     }
     MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) PostScale", this));
-    Mutated();
+    MutatedSimple();
   }
 
   /**
    * CONSTRUCTION PHASE ONLY
    * A layer is "fixed position" when it draws content from a content
    * (not chrome) document, the topmost content document has a root scrollframe
    * with a displayport, but the layer does not move when that displayport scrolls.
    */
   void SetIsFixedPosition(bool aFixedPosition)
   {
     if (mSimpleAttrs.SetIsFixedPosition(aFixedPosition)) {
       MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) IsFixedPosition", this));
-      Mutated();
+      MutatedSimple();
     }
   }
 
   /**
    * CONSTRUCTION PHASE ONLY
    * This flag is true when the transform on the layer is a perspective
    * transform. The compositor treats perspective transforms specially
    * for async scrolling purposes.
    */
   void SetTransformIsPerspective(bool aTransformIsPerspective)
   {
     if (mSimpleAttrs.SetTransformIsPerspective(aTransformIsPerspective)) {
       MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) TransformIsPerspective", this));
-      Mutated();
+      MutatedSimple();
     }
   }
 
   // Call AddAnimation to add a new animation to this layer from layout code.
   // Caller must fill in all the properties of the returned animation.
   // A later animation overrides an earlier one.
   Animation* AddAnimation();
   // ClearAnimations clears animations on this layer.
@@ -1223,17 +1219,17 @@ public:
    *     combining appropriate values from mozilla::SideBits.
    */
   void SetFixedPositionData(FrameMetrics::ViewID aScrollId,
                             const LayerPoint& aAnchor,
                             int32_t aSides)
   {
     if (mSimpleAttrs.SetFixedPositionData(aScrollId, aAnchor, aSides)) {
       MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) FixedPositionData", this));
-      Mutated();
+      MutatedSimple();
     }
   }
 
   /**
    * CONSTRUCTION PHASE ONLY
    * If a layer is "sticky position", |aScrollId| holds the scroll identifier
    * of the scrollable content that contains it. The difference between the two
    * rectangles |aOuter| and |aInner| is treated as two intervals in each
@@ -1241,41 +1237,49 @@ public:
    * dimension, while that component of the scroll position lies within either
    * interval, the layer should not move relative to its scrolling container.
    */
   void SetStickyPositionData(FrameMetrics::ViewID aScrollId, LayerRect aOuter,
                              LayerRect aInner)
   {
     if (mSimpleAttrs.SetStickyPositionData(aScrollId, aOuter, aInner)) {
       MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) StickyPositionData", this));
-      Mutated();
+      MutatedSimple();
     }
   }
 
   /**
    * CONSTRUCTION PHASE ONLY
    * If a layer is a scrollbar layer, |aScrollId| holds the scroll identifier
    * of the scrollable content that the scrollbar is for.
    */
   void SetScrollbarData(FrameMetrics::ViewID aScrollId, ScrollDirection aDir, float aThumbRatio)
   {
     if (mSimpleAttrs.SetScrollbarData(aScrollId, aDir, aThumbRatio)) {
       MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) ScrollbarData", this));
-      Mutated();
+      MutatedSimple();
     }
   }
 
   // Set during construction for the container layer of scrollbar components.
   void SetIsScrollbarContainer()
   {
     if (mSimpleAttrs.SetIsScrollbarContainer()) {
-      Mutated();
+      MutatedSimple();
     }
   }
 
+  // Used when forwarding transactions. Do not use at any other time.
+  void SetSimpleAttributes(const SimpleLayerAttributes& aAttrs) {
+    mSimpleAttrs = aAttrs;
+  }
+  const SimpleLayerAttributes& GetSimpleAttributes() const {
+    return mSimpleAttrs;
+  }
+
   // These getters can be used anytime.
   float GetOpacity() { return mSimpleAttrs.Opacity(); }
   gfx::CompositionOp GetMixBlendMode() const { return mSimpleAttrs.MixBlendMode(); }
   const Maybe<ParentLayerIntRect>& GetClipRect() const { return mClipRect; }
   const Maybe<LayerClip>& GetScrolledClip() const { return mSimpleAttrs.ScrolledClip(); }
   Maybe<ParentLayerIntRect> GetScrolledClipRect() const;
   uint32_t GetContentFlags() { return mSimpleAttrs.ContentFlags(); }
   const gfx::IntRect& GetLayerBounds() const { return mSimpleAttrs.LayerBounds(); }
@@ -1758,20 +1762,22 @@ public:
 
 #ifdef DEBUG
   void SetDebugColorIndex(uint32_t aIndex) { mDebugColorIndex = aIndex; }
   uint32_t GetDebugColorIndex() { return mDebugColorIndex; }
 #endif
 
   virtual LayerRenderState GetRenderState() { return LayerRenderState(); }
 
-  void Mutated()
-  {
+  void Mutated() {
     mManager->Mutated(this);
   }
+  void MutatedSimple() {
+    mManager->MutatedSimple(this);
+  }
 
   virtual int32_t GetMaxLayerSize() { return Manager()->GetMaxTextureSize(); }
 
   /**
    * Returns true if this layer's effective transform is not just
    * a translation by integers, or if this layer or some ancestor layer
    * is marked as having a transform that may change without a full layer
    * transaction.
--- a/gfx/layers/client/ClientLayerManager.cpp
+++ b/gfx/layers/client/ClientLayerManager.cpp
@@ -189,16 +189,25 @@ void
 ClientLayerManager::Mutated(Layer* aLayer)
 {
   LayerManager::Mutated(aLayer);
 
   NS_ASSERTION(InConstruction() || InDrawing(), "wrong phase");
   mForwarder->Mutated(Hold(aLayer));
 }
 
+void
+ClientLayerManager::MutatedSimple(Layer* aLayer)
+{
+  LayerManager::MutatedSimple(aLayer);
+
+  NS_ASSERTION(InConstruction() || InDrawing(), "wrong phase");
+  mForwarder->MutatedSimple(Hold(aLayer));
+}
+
 already_AddRefed<ReadbackLayer>
 ClientLayerManager::CreateReadbackLayer()
 {
   RefPtr<ReadbackLayer> layer = new ClientReadbackLayer(this);
   return layer.forget();
 }
 
 bool
--- a/gfx/layers/client/ClientLayerManager.h
+++ b/gfx/layers/client/ClientLayerManager.h
@@ -74,16 +74,17 @@ public:
     return AsShadowForwarder()->GetCompositorBackendType();
   }
   virtual void GetBackendName(nsAString& name) override;
   virtual const char* Name() const override { return "Client"; }
 
   virtual void SetRoot(Layer* aLayer) override;
 
   virtual void Mutated(Layer* aLayer) override;
+  virtual void MutatedSimple(Layer* aLayer) override;
 
   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;
--- a/gfx/layers/ipc/LayerTransactionParent.cpp
+++ b/gfx/layers/ipc/LayerTransactionParent.cpp
@@ -431,16 +431,27 @@ LayerTransactionParent::RecvUpdate(const
       }
       break;
     }
     default:
       MOZ_CRASH("not reached");
     }
   }
 
+  // Process simple attribute updates.
+  for (const auto& op : aInfo.setSimpleAttrs()) {
+    MOZ_LAYERS_LOG(("[ParentSide] SetSimpleLayerAttributes"));
+    Layer* layer = AsLayer(op.layer());
+    if (!layer) {
+      return IPC_FAIL_NO_REASON(this);
+    }
+    layer->SetSimpleAttributes(op.attrs());
+    updateHitTestingTree = true;
+  }
+
   // Process attribute updates.
   for (const auto& op : aInfo.setAttrs()) {
     MOZ_LAYERS_LOG(("[ParentSide] SetLayerAttributes"));
     if (!SetLayerAttributes(op)) {
       return IPC_FAIL_NO_REASON(this);
     }
     updateHitTestingTree = true;
   }
@@ -507,45 +518,19 @@ LayerTransactionParent::SetLayerAttribut
 {
   Layer* layer = AsLayer(aOp.layer());
   if (!layer) {
     return false;
   }
 
   const LayerAttributes& attrs = aOp.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());
-  layer->SetScrolledClip(common.scrolledClip());
-  layer->SetBaseTransform(common.transform());
-  layer->SetTransformIsPerspective(common.transformIsPerspective());
-  layer->SetPostScale(common.postXScale(), common.postYScale());
-  layer->SetIsFixedPosition(common.isFixedPosition());
-  if (common.isFixedPosition()) {
-    layer->SetFixedPositionData(common.fixedPositionScrollContainerId(),
-                                common.fixedPositionAnchor(),
-                                common.fixedPositionSides());
-  }
-  if (common.isStickyPosition()) {
-    layer->SetStickyPositionData(common.stickyScrollContainerId(),
-                                 common.stickyScrollRangeOuter(),
-                                 common.stickyScrollRangeInner());
-  }
-  layer->SetScrollbarData(common.scrollbarTargetContainerId(),
-    static_cast<ScrollDirection>(common.scrollbarDirection()),
-    common.scrollbarThumbRatio());
-  if (common.isScrollbarContainer()) {
-    layer->SetIsScrollbarContainer();
-  }
-  layer->SetMixBlendMode((gfx::CompositionOp)common.mixBlendMode());
-  layer->SetForceIsolatedGroup(common.forceIsolatedGroup());
   if (LayerHandle maskLayer = common.maskLayer()) {
     layer->SetMaskLayer(AsLayer(maskLayer));
   } else {
     layer->SetMaskLayer(nullptr);
   }
   layer->SetAnimations(common.animations());
   layer->SetScrollMetadata(common.scrollMetadata());
   layer->SetDisplayListLog(common.displayListLog().get());
--- a/gfx/layers/ipc/LayersMessages.ipdlh
+++ b/gfx/layers/ipc/LayersMessages.ipdlh
@@ -45,16 +45,17 @@ using mozilla::layers::FrameMetrics::Vie
 using mozilla::layers::LayersBackend from "mozilla/layers/LayersTypes.h";
 using mozilla::layers::MaybeLayerClip from "FrameMetrics.h";
 using mozilla::gfx::Glyph from "Layers.h";
 using mozilla::layers::BorderColors from "mozilla/layers/LayersTypes.h";
 using mozilla::layers::BorderCorners from "mozilla/layers/LayersTypes.h";
 using mozilla::layers::BorderWidths from "mozilla/layers/LayersTypes.h";
 using mozilla::layers::LayerHandle from "mozilla/layers/LayersTypes.h";
 using mozilla::layers::CompositableHandle from "mozilla/layers/LayersTypes.h";
+using mozilla::layers::SimpleLayerAttributes from "mozilla/layers/LayerAttributes.h";
 
 namespace mozilla {
 namespace layers {
 
 struct TargetConfig {
   IntRect naturalBounds;
   ScreenRotation rotation;
   ScreenOrientationInternal orientation;
@@ -227,42 +228,20 @@ struct Animation {
   // animations with a composite mode of additive or accumulate, and only for
   // the first animation in the set (i.e. the animation that is lowest in the
   // stack). In all other cases the value is null_t.
   Animatable baseStyle;
 };
 
 // Change a layer's attributes
 struct CommonLayerAttributes {
-  IntRect layerBounds;
   LayerIntRegion visibleRegion;
   EventRegions eventRegions;
-  Matrix4x4 transform;
-  bool transformIsPerspective;
-  float postXScale;
-  float postYScale;
-  uint32_t contentFlags;
-  float opacity;
   bool useClipRect;
   ParentLayerIntRect clipRect;
-  MaybeLayerClip scrolledClip;
-  bool isFixedPosition;
-  uint64_t fixedPositionScrollContainerId;
-  LayerPoint fixedPositionAnchor;
-  int32_t fixedPositionSides;
-  bool isStickyPosition;
-  uint64_t stickyScrollContainerId;
-  LayerRect stickyScrollRangeOuter;
-  LayerRect stickyScrollRangeInner;
-  uint64_t scrollbarTargetContainerId;
-  uint32_t scrollbarDirection;
-  float scrollbarThumbRatio;
-  bool isScrollbarContainer;
-  int8_t mixBlendMode;
-  bool forceIsolatedGroup;
   LayerHandle maskLayer;
   LayerHandle[] ancestorMaskLayers;
   // Animated colors will only honored for ColorLayers.
   Animation[] animations;
   nsIntRegion invalidRegion;
   ScrollMetadata[] scrollMetadata;
   nsCString displayListLog;
 };
@@ -325,16 +304,21 @@ struct LayerAttributes {
 // See nsIWidget Configurations
 struct PluginWindowData {
   uintptr_t windowId;
   LayoutDeviceIntRect[] clip;
   LayoutDeviceIntRect bounds;
   bool visible;
 };
 
+struct OpSetSimpleLayerAttributes {
+  LayerHandle layer;
+  SimpleLayerAttributes attrs;
+};
+
 struct OpSetLayerAttributes {
   LayerHandle layer;
   LayerAttributes attrs;
 };
 
 // Monkey with the tree structure
 struct OpSetRoot          { LayerHandle root; };
 struct OpInsertAfter      { LayerHandle container; LayerHandle childLayer; LayerHandle after; };
@@ -536,16 +520,17 @@ union EditReply {
 
 union AsyncParentMessageData {
   OpNotifyNotUsed;
 };
 
 struct TransactionInfo
 {
   Edit[] cset;
+  OpSetSimpleLayerAttributes[] setSimpleAttrs;
   OpSetLayerAttributes[] setAttrs;
   CompositableOperation[] paints;
   OpDestroy[] toDestroy;
   uint64_t fwdTransactionId;
   uint64_t id;
   TargetConfig targetConfig;
   PluginWindowData[] plugins;
   bool isFirstPaint;
--- a/gfx/layers/ipc/ShadowLayers.cpp
+++ b/gfx/layers/ipc/ShadowLayers.cpp
@@ -104,42 +104,52 @@ public:
     MOZ_ASSERT(!Finished(), "forgot BeginTransaction?");
     mPaints.AppendElement(Edit(aPaint));
   }
   void AddMutant(ShadowableLayer* aLayer)
   {
     MOZ_ASSERT(!Finished(), "forgot BeginTransaction?");
     mMutants.PutEntry(aLayer);
   }
+  void AddSimpleMutant(ShadowableLayer* aLayer)
+  {
+    MOZ_ASSERT(!Finished(), "forgot BeginTransaction?");
+    mSimpleMutants.PutEntry(aLayer);
+  }
   void End()
   {
     mCset.Clear();
     mPaints.Clear();
     mMutants.Clear();
+    mSimpleMutants.Clear();
     mDestroyedActors.Clear();
     mOpen = false;
     mSwapRequired = false;
     mRotationChanged = false;
   }
 
   bool Empty() const {
-    return mCset.IsEmpty() && mPaints.IsEmpty() && mMutants.IsEmpty()
-           && mDestroyedActors.IsEmpty();
+    return mCset.IsEmpty() &&
+           mPaints.IsEmpty() &&
+           mMutants.IsEmpty() &&
+           mSimpleMutants.IsEmpty() &&
+           mDestroyedActors.IsEmpty();
   }
   bool RotationChanged() const {
     return mRotationChanged;
   }
   bool Finished() const { return !mOpen && Empty(); }
 
   bool Opened() const { return mOpen; }
 
   EditVector mCset;
   nsTArray<CompositableOperation> mPaints;
   OpDestroyVector mDestroyedActors;
   ShadowableLayerSet mMutants;
+  ShadowableLayerSet mSimpleMutants;
   gfx::IntRect mTargetBounds;
   ScreenRotation mTargetRotation;
   dom::ScreenOrientationInternal mTargetOrientation;
   bool mSwapRequired;
 
 private:
   bool mOpen;
   bool mRotationChanged;
@@ -274,17 +284,23 @@ void
 ShadowLayerForwarder::CreatedRefLayer(ShadowableLayer* aRef)
 {
   CreatedLayer<OpCreateRefLayer>(mTxn, aRef);
 }
 
 void
 ShadowLayerForwarder::Mutated(ShadowableLayer* aMutant)
 {
-mTxn->AddMutant(aMutant);
+  mTxn->AddMutant(aMutant);
+}
+
+void
+ShadowLayerForwarder::MutatedSimple(ShadowableLayer* aMutant)
+{
+  mTxn->AddSimpleMutant(aMutant);
 }
 
 void
 ShadowLayerForwarder::SetRoot(ShadowableLayer* aRoot)
 {
   mTxn->AddEdit(OpSetRoot(Shadow(aRoot)));
 }
 void
@@ -598,16 +614,29 @@ ShadowLayerForwarder::EndTransaction(con
     // across multiple frames.
     gfxPlatform::GetPlatform()->FlushContentDrawing();
   }
 
   MOZ_LAYERS_LOG(("[LayersForwarder] destroying buffers..."));
 
   MOZ_LAYERS_LOG(("[LayersForwarder] building transaction..."));
 
+  nsTArray<OpSetSimpleLayerAttributes> setSimpleAttrs;
+  for (ShadowableLayerSet::Iterator it(&mTxn->mSimpleMutants); !it.Done(); it.Next()) {
+    ShadowableLayer* shadow = it.Get()->GetKey();
+    if (!shadow->HasShadow()) {
+      continue;
+    }
+
+    Layer* mutant = shadow->AsLayer();
+    setSimpleAttrs.AppendElement(OpSetSimpleLayerAttributes(
+      Shadow(shadow),
+      mutant->GetSimpleAttributes()));
+  }
+
   nsTArray<OpSetLayerAttributes> setAttrs;
 
   // We purposely add attribute-change ops to the final changeset
   // before we add paint ops.  This allows layers to record the
   // attribute changes before new pixels arrive, which can be useful
   // for setting up back/front buffers.
   RenderTraceScope rendertrace2("Foward Transaction", "000092");
   for (ShadowableLayerSet::Iterator it(&mTxn->mMutants);
@@ -620,55 +649,21 @@ ShadowLayerForwarder::EndTransaction(con
     Layer* mutant = shadow->AsLayer();
     MOZ_ASSERT(!!mutant, "unshadowable layer?");
 
     OpSetLayerAttributes op;
     op.layer() = Shadow(shadow);
 
     LayerAttributes& attrs = op.attrs();
     CommonLayerAttributes& common = attrs.common();
-    common.layerBounds() = mutant->GetLayerBounds();
     common.visibleRegion() = mutant->GetVisibleRegion();
     common.eventRegions() = mutant->GetEventRegions();
-    common.postXScale() = mutant->GetPostXScale();
-    common.postYScale() = mutant->GetPostYScale();
-    common.transform() = mutant->GetBaseTransform();
-    common.transformIsPerspective() = mutant->GetTransformIsPerspective();
-    common.contentFlags() = mutant->GetContentFlags();
-    common.opacity() = mutant->GetOpacity();
     common.useClipRect() = !!mutant->GetClipRect();
     common.clipRect() = (common.useClipRect() ?
                          *mutant->GetClipRect() : ParentLayerIntRect());
-    common.scrolledClip() = mutant->GetScrolledClip();
-    common.isFixedPosition() = mutant->GetIsFixedPosition();
-    if (mutant->GetIsFixedPosition()) {
-      common.fixedPositionScrollContainerId() = mutant->GetFixedPositionScrollContainerId();
-      common.fixedPositionAnchor() = mutant->GetFixedPositionAnchor();
-      common.fixedPositionSides() = mutant->GetFixedPositionSides();
-    }
-    common.isStickyPosition() = mutant->GetIsStickyPosition();
-    if (mutant->GetIsStickyPosition()) {
-      common.stickyScrollContainerId() = mutant->GetStickyScrollContainerId();
-      common.stickyScrollRangeOuter() = mutant->GetStickyScrollRangeOuter();
-      common.stickyScrollRangeInner() = mutant->GetStickyScrollRangeInner();
-    } else {
-#ifdef MOZ_VALGRIND
-      // Initialize these so that Valgrind doesn't complain when we send them
-      // to another process.
-      common.stickyScrollContainerId() = 0;
-      common.stickyScrollRangeOuter() = LayerRect();
-      common.stickyScrollRangeInner() = LayerRect();
-#endif
-    }
-    common.scrollbarTargetContainerId() = mutant->GetScrollbarTargetContainerId();
-    common.scrollbarDirection() = (uint32_t)mutant->GetScrollbarDirection();
-    common.scrollbarThumbRatio() = mutant->GetScrollbarThumbRatio();
-    common.isScrollbarContainer() = mutant->IsScrollbarContainer();
-    common.mixBlendMode() = (int8_t)mutant->GetMixBlendMode();
-    common.forceIsolatedGroup() = mutant->GetForceIsolatedGroup();
     if (Layer* maskLayer = mutant->GetMaskLayer()) {
       common.maskLayer() = Shadow(maskLayer->AsShadowableLayer());
     } else {
       common.maskLayer() = LayerHandle();
     }
     common.animations() = mutant->GetAnimations();
     common.invalidRegion() = mutant->GetInvalidRegion().GetRegion();
     common.scrollMetadata() = mutant->GetAllScrollMetadata();
@@ -694,16 +689,17 @@ ShadowLayerForwarder::EndTransaction(con
       !mTxn->RotationChanged())
   {
     return true;
   }
 
   mWindowOverlayChanged = false;
 
   info.cset() = Move(mTxn->mCset);
+  info.setSimpleAttrs() = Move(setSimpleAttrs);
   info.setAttrs() = Move(setAttrs);
   info.paints() = Move(mTxn->mPaints);
   info.toDestroy() = mTxn->mDestroyedActors;
   info.fwdTransactionId() = GetFwdTransactionId();
   info.id() = aId;
   info.plugins() = mPluginWindowData;
   info.isFirstPaint() = mIsFirstPaint;
   info.scheduleComposite() = aScheduleComposite;
--- a/gfx/layers/ipc/ShadowLayers.h
+++ b/gfx/layers/ipc/ShadowLayers.h
@@ -211,19 +211,21 @@ public:
   void CreatedCanvasLayer(ShadowableLayer* aCanvas);
   void CreatedRefLayer(ShadowableLayer* aRef);
   void CreatedTextLayer(ShadowableLayer* aRef);
   void CreatedBorderLayer(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.
+   * forwards all attributes when any of the appropriate attribute
+   * set is mutated.
    */
   void Mutated(ShadowableLayer* aMutant);
+  void MutatedSimple(ShadowableLayer* aMutant);
 
   void SetRoot(ShadowableLayer* aRoot);
   /**
    * Insert |aChild| after |aAfter| in |aContainer|.  |aAfter| can be
    * nullptr to indicated that |aChild| should be appended to the end of
    * |aContainer|'s child list.
    */
   void InsertAfter(ShadowableLayer* aContainer,