Bug 1240437: Implement PushLayer and PopLayer for DrawTargetRecording. r=bas, a=lizzard
authorBob Owen <bobowencode@gmail.com>
Tue, 26 Jan 2016 10:03:07 +0000
changeset 303855 ff09e358297be50b2e299e045fb050d7d31bddc9
parent 303854 a02e509588b0f0d345452d2cea202e435fd7f18c
child 303856 414cb97f68072c39817fe205d663b01704e1ffa0
push id9038
push usercbook@mozilla.com
push dateTue, 09 Feb 2016 15:43:38 +0000
treeherdermozilla-aurora@6426f9752a17 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbas, lizzard
bugs1240437
milestone46.0a2
Bug 1240437: Implement PushLayer and PopLayer for DrawTargetRecording. r=bas, a=lizzard
gfx/2d/DrawTargetRecording.cpp
gfx/2d/DrawTargetRecording.h
gfx/2d/RecordedEvent.cpp
gfx/2d/RecordedEvent.h
--- a/gfx/2d/DrawTargetRecording.cpp
+++ b/gfx/2d/DrawTargetRecording.cpp
@@ -553,16 +553,40 @@ DrawTargetRecording::PushClipRect(const 
 
 void
 DrawTargetRecording::PopClip()
 {
   mRecorder->RecordEvent(RecordedPopClip(this));
   mFinalDT->PopClip();
 }
 
+void
+DrawTargetRecording::PushLayer(bool aOpaque, Float aOpacity,
+                               SourceSurface* aMask,
+                               const Matrix& aMaskTransform,
+                               const IntRect& aBounds, bool aCopyBackground)
+{
+  if (aMask) {
+    EnsureSurfaceStored(mRecorder, aMask, "PushLayer");
+  }
+
+  mRecorder->RecordEvent(RecordedPushLayer(this, aOpacity, aOpacity, aMask,
+                                           aMaskTransform, aBounds,
+                                           aCopyBackground));
+  mFinalDT->PushLayer(aOpacity, aOpacity, aMask, aMaskTransform, aBounds,
+                      aCopyBackground);
+}
+
+void
+DrawTargetRecording::PopLayer()
+{
+  mRecorder->RecordEvent(RecordedPopLayer(this));
+  mFinalDT->PopLayer();
+}
+
 already_AddRefed<SourceSurface>
 DrawTargetRecording::CreateSourceSurfaceFromData(unsigned char *aData,
                                                  const IntSize &aSize,
                                                  int32_t aStride,
                                                  SurfaceFormat aFormat) const
 {
   RefPtr<SourceSurface> surf = mFinalDT->CreateSourceSurfaceFromData(aData, aSize, aStride, aFormat);
 
--- a/gfx/2d/DrawTargetRecording.h
+++ b/gfx/2d/DrawTargetRecording.h
@@ -212,16 +212,45 @@ public:
    */
   virtual void PushClipRect(const Rect &aRect) override;
 
   /* Pop a clip from the DrawTarget. A pop without a corresponding push will
    * be ignored.
    */
   virtual void PopClip() override;
 
+  /**
+   * Push a 'layer' to the DrawTarget, a layer is a temporary surface that all
+   * drawing will be redirected to, this is used for example to support group
+   * opacity or the masking of groups. Clips must be balanced within a layer,
+   * i.e. between a matching PushLayer/PopLayer pair there must be as many
+   * PushClip(Rect) calls as there are PopClip calls.
+   *
+   * @param aOpaque Whether the layer will be opaque
+   * @param aOpacity Opacity of the layer
+   * @param aMask Mask applied to the layer
+   * @param aMaskTransform Transform applied to the layer mask
+   * @param aBounds Optional bounds in device space to which the layer is
+   *                limited in size.
+   * @param aCopyBackground Whether to copy the background into the layer, this
+   *                        is only supported when aOpaque is true.
+   */
+  virtual void PushLayer(bool aOpaque, Float aOpacity,
+                         SourceSurface* aMask,
+                         const Matrix& aMaskTransform,
+                         const IntRect& aBounds = IntRect(),
+                         bool aCopyBackground = false) override;
+
+  /**
+   * This balances a call to PushLayer and proceeds to blend the layer back
+   * onto the background. This blend will blend the temporary surface back
+   * onto the target in device space using POINT sampling and operator over.
+   */
+  virtual void PopLayer() override;
+
   /*
    * Create a SourceSurface optimized for use with this DrawTarget from
    * existing bitmap data in memory.
    *
    * The SourceSurface does not take ownership of aData, and may be freed at any time.
    */
   virtual already_AddRefed<SourceSurface> CreateSourceSurfaceFromData(unsigned char *aData,
                                                                   const IntSize &aSize,
@@ -281,16 +310,20 @@ public:
    */
   virtual void SetTransform(const Matrix &aTransform) override;
 
   /* Tries to get a native surface for a DrawTarget, this may fail if the
    * draw target cannot convert to this surface type.
    */
   virtual void *GetNativeSurface(NativeSurfaceType aType) override { return mFinalDT->GetNativeSurface(aType); }
 
+  virtual bool IsCurrentGroupOpaque() override {
+    return mFinalDT->IsCurrentGroupOpaque();
+  }
+
 private:
   Path *GetPathForPathRecording(const Path *aPath) const;
   already_AddRefed<PathRecording> EnsurePathStored(const Path *aPath);
   void EnsurePatternDependenciesStored(const Pattern &aPattern);
 
   RefPtr<DrawEventRecorderPrivate> mRecorder;
   RefPtr<DrawTarget> mFinalDT;
 };
--- a/gfx/2d/RecordedEvent.cpp
+++ b/gfx/2d/RecordedEvent.cpp
@@ -75,16 +75,18 @@ RecordedEvent::LoadEventFromStream(std::
     LOAD_EVENT_TYPE(SNAPSHOT, RecordedSnapshot);
     LOAD_EVENT_TYPE(SCALEDFONTCREATION, RecordedScaledFontCreation);
     LOAD_EVENT_TYPE(SCALEDFONTDESTRUCTION, RecordedScaledFontDestruction);
     LOAD_EVENT_TYPE(MASKSURFACE, RecordedMaskSurface);
     LOAD_EVENT_TYPE(FILTERNODESETATTRIBUTE, RecordedFilterNodeSetAttribute);
     LOAD_EVENT_TYPE(FILTERNODESETINPUT, RecordedFilterNodeSetInput);
     LOAD_EVENT_TYPE(CREATESIMILARDRAWTARGET, RecordedCreateSimilarDrawTarget);
     LOAD_EVENT_TYPE(FONTDATA, RecordedFontData);
+    LOAD_EVENT_TYPE(PUSHLAYER, RecordedPushLayer);
+    LOAD_EVENT_TYPE(POPLAYER, RecordedPopLayer);
   default:
     return nullptr;
   }
 }
 
 string
 RecordedEvent::GetEventName(EventType aType)
 {
@@ -152,16 +154,20 @@ RecordedEvent::GetEventName(EventType aT
   case FILTERNODESETATTRIBUTE:
     return "SetAttribute";
   case FILTERNODESETINPUT:
     return "SetInput";
   case CREATESIMILARDRAWTARGET:
     return "CreateSimilarDrawTarget";
   case FONTDATA:
     return "FontData";
+  case PUSHLAYER:
+    return "PushLayer";
+  case POPLAYER:
+    return "PopLayer";
   default:
     return "Unknown";
   }
 }
 
 void
 RecordedEvent::RecordPatternData(std::ostream &aStream, const PatternStorage &aPattern) const
 {
@@ -923,16 +929,78 @@ RecordedPopClip::RecordedPopClip(istream
 
 void
 RecordedPopClip::OutputSimpleEventInfo(stringstream &aStringStream) const
 {
   aStringStream << "[" << mDT << "] PopClip";
 }
 
 void
+RecordedPushLayer::PlayEvent(Translator *aTranslator) const
+{
+  SourceSurface* mask = mMask ? aTranslator->LookupSourceSurface(mMask)
+                              : nullptr;
+  aTranslator->LookupDrawTarget(mDT)->
+    PushLayer(mOpaque, mOpacity, mask, mMaskTransform, mBounds, mCopyBackground);
+}
+
+void
+RecordedPushLayer::RecordToStream(ostream &aStream) const
+{
+  RecordedDrawingEvent::RecordToStream(aStream);
+  WriteElement(aStream, mOpaque);
+  WriteElement(aStream, mOpacity);
+  WriteElement(aStream, mMask);
+  WriteElement(aStream, mMaskTransform);
+  WriteElement(aStream, mBounds);
+  WriteElement(aStream, mCopyBackground);
+}
+
+RecordedPushLayer::RecordedPushLayer(istream &aStream)
+  : RecordedDrawingEvent(PUSHLAYER, aStream)
+{
+  ReadElement(aStream, mOpaque);
+  ReadElement(aStream, mOpacity);
+  ReadElement(aStream, mMask);
+  ReadElement(aStream, mMaskTransform);
+  ReadElement(aStream, mBounds);
+  ReadElement(aStream, mCopyBackground);
+}
+
+void
+RecordedPushLayer::OutputSimpleEventInfo(stringstream &aStringStream) const
+{
+  aStringStream << "[" << mDT << "] PushPLayer (Opaque=" << mOpaque <<
+    ", Opacity=" << mOpacity << ", Mask Ref=" << mMask << ") ";
+}
+
+void
+RecordedPopLayer::PlayEvent(Translator *aTranslator) const
+{
+  aTranslator->LookupDrawTarget(mDT)->PopLayer();
+}
+
+void
+RecordedPopLayer::RecordToStream(ostream &aStream) const
+{
+  RecordedDrawingEvent::RecordToStream(aStream);
+}
+
+RecordedPopLayer::RecordedPopLayer(istream &aStream)
+  : RecordedDrawingEvent(POPLAYER, aStream)
+{
+}
+
+void
+RecordedPopLayer::OutputSimpleEventInfo(stringstream &aStringStream) const
+{
+  aStringStream << "[" << mDT << "] PopLayer";
+}
+
+void
 RecordedSetTransform::PlayEvent(Translator *aTranslator) const
 {
   aTranslator->LookupDrawTarget(mDT)->SetTransform(mTransform);
 }
 
 void
 RecordedSetTransform::RecordToStream(ostream &aStream) const
 {
--- a/gfx/2d/RecordedEvent.h
+++ b/gfx/2d/RecordedEvent.h
@@ -22,17 +22,17 @@ const uint32_t kMagicInt = 0xc001feed;
 
 // A change in major revision means a change in event binary format, causing
 // loss of backwards compatibility. Old streams will not work in a player
 // using a newer major revision. And new streams will not work in a player
 // using an older major revision.
 const uint16_t kMajorRevision = 4;
 // A change in minor revision means additions of new events. New streams will
 // not play in older players.
-const uint16_t kMinorRevision = 0;
+const uint16_t kMinorRevision = 1;
 
 struct ReferencePtr
 {
   ReferencePtr()
     : mLongPtr(0)
   {}
 
   MOZ_IMPLICIT ReferencePtr(const void* aLongPtr)
@@ -187,16 +187,18 @@ public:
     MASKSURFACE,
     FILTERNODECREATION,
     FILTERNODEDESTRUCTION,
     DRAWFILTER,
     FILTERNODESETATTRIBUTE,
     FILTERNODESETINPUT,
     CREATESIMILARDRAWTARGET,
     FONTDATA,
+    PUSHLAYER,
+    POPLAYER,
   };
   static const uint32_t kTotalEventTypes = RecordedEvent::FILTERNODESETINPUT + 1;
 
   virtual ~RecordedEvent() {}
 
   static std::string GetEventName(EventType aType);
 
   virtual void PlayEvent(Translator *aTranslator) const {}
@@ -619,16 +621,65 @@ public:
 
   virtual std::string GetName() const { return "PopClip"; }
 private:
   friend class RecordedEvent;
 
   MOZ_IMPLICIT RecordedPopClip(std::istream &aStream);
 };
 
+class RecordedPushLayer : public RecordedDrawingEvent {
+public:
+  RecordedPushLayer(DrawTarget* aDT, bool aOpaque, Float aOpacity,
+                    SourceSurface* aMask, const Matrix& aMaskTransform,
+                    const IntRect& aBounds, bool aCopyBackground)
+    : RecordedDrawingEvent(PUSHLAYER, aDT), mOpaque(aOpaque)
+    , mOpacity(aOpacity), mMask(aMask), mMaskTransform(aMaskTransform)
+    , mBounds(aBounds), mCopyBackground(aCopyBackground)
+  {
+  }
+
+  virtual void PlayEvent(Translator *aTranslator) const;
+
+  virtual void RecordToStream(std::ostream &aStream) const;
+  virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const;
+
+  virtual std::string GetName() const { return "PushLayer"; }
+private:
+  friend class RecordedEvent;
+
+  MOZ_IMPLICIT RecordedPushLayer(std::istream &aStream);
+
+  bool mOpaque;
+  Float mOpacity;
+  ReferencePtr mMask;
+  Matrix mMaskTransform;
+  IntRect mBounds;
+  bool mCopyBackground;
+};
+
+class RecordedPopLayer : public RecordedDrawingEvent {
+public:
+  RecordedPopLayer(DrawTarget* aDT)
+    : RecordedDrawingEvent(POPLAYER, aDT)
+  {
+  }
+
+  virtual void PlayEvent(Translator *aTranslator) const;
+
+  virtual void RecordToStream(std::ostream &aStream) const;
+  virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const;
+
+  virtual std::string GetName() const { return "PopLayer"; }
+private:
+  friend class RecordedEvent;
+
+  MOZ_IMPLICIT RecordedPopLayer(std::istream &aStream);
+};
+
 class RecordedSetTransform : public RecordedDrawingEvent {
 public:
   RecordedSetTransform(DrawTarget *aDT, const Matrix &aTransform)
     : RecordedDrawingEvent(SETTRANSFORM, aDT), mTransform(aTransform)
   {
   }
 
   virtual void PlayEvent(Translator *aTranslator) const;