Bug 1439005. Add PushLayerWithBlend. r=Bas
authorJeff Muizelaar <jmuizelaar@mozilla.com>
Sat, 17 Feb 2018 12:07:30 -0500
changeset 404325 7742669c40dbb2b66970981e95577aabae244702
parent 404324 bb75a5c7f4cc69ae9b9fd520d6028c69a25f2c32
child 404326 2a0bd14b1bfd40a6fb18e21f7ecaae45d30fed31
push id33464
push usershindli@mozilla.com
push dateSun, 18 Feb 2018 09:35:40 +0000
treeherdermozilla-central@e7438140bb20 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersBas
bugs1439005
milestone60.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 1439005. Add PushLayerWithBlend. r=Bas This makes it possible to implement nsDisplayBlend blob image invalidation. It currently only includes an implementation for Skia and DrawTargetRecording. All other backends will crash when used. MozReview-Commit-ID: 2GhdDxi4jHG
gfx/2d/2D.h
gfx/2d/DrawTargetRecording.cpp
gfx/2d/DrawTargetRecording.h
gfx/2d/DrawTargetSkia.cpp
gfx/2d/DrawTargetSkia.h
gfx/2d/RecordedEvent.h
gfx/2d/RecordedEventImpl.h
--- a/gfx/2d/2D.h
+++ b/gfx/2d/2D.h
@@ -1218,16 +1218,40 @@ public:
    */
   virtual void PushLayer(bool aOpaque, Float aOpacity,
                          SourceSurface* aMask,
                          const Matrix& aMaskTransform,
                          const IntRect& aBounds = IntRect(),
                          bool aCopyBackground = false) { MOZ_CRASH("GFX: PushLayer"); }
 
   /**
+   * 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 PushLayerWithBlend(bool aOpaque, Float aOpacity,
+                         SourceSurface* aMask,
+                         const Matrix& aMaskTransform,
+                         const IntRect& aBounds = IntRect(),
+                         bool aCopyBackground = false,
+                         CompositionOp = CompositionOp::OP_OVER) { MOZ_CRASH("GFX: PushLayerWithBlend"); }
+
+
+  /**
    * 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() { MOZ_CRASH("GFX: PopLayer"); }
 
   /**
    * Perform an in-place blur operation. This is only supported on data draw
--- a/gfx/2d/DrawTargetRecording.cpp
+++ b/gfx/2d/DrawTargetRecording.cpp
@@ -522,16 +522,33 @@ DrawTargetRecording::PushLayer(bool aOpa
   }
 
   mRecorder->RecordEvent(RecordedPushLayer(this, aOpaque, aOpacity, aMask,
                                            aMaskTransform, aBounds,
                                            aCopyBackground));
 }
 
 void
+DrawTargetRecording::PushLayerWithBlend(bool aOpaque, Float aOpacity,
+                                        SourceSurface* aMask,
+                                        const Matrix& aMaskTransform,
+                                        const IntRect& aBounds,
+                                        bool aCopyBackground,
+                                        CompositionOp aCompositionOp)
+{
+  if (aMask) {
+    EnsureSurfaceStoredRecording(mRecorder, aMask, "PushLayer");
+  }
+
+  mRecorder->RecordEvent(RecordedPushLayerWithBlend(this, aOpaque, aOpacity, aMask,
+                                           aMaskTransform, aBounds,
+                                           aCopyBackground, aCompositionOp));
+}
+
+void
 DrawTargetRecording::PopLayer()
 {
   mRecorder->RecordEvent(RecordedPopLayer(static_cast<DrawTarget*>(this)));
 }
 
 already_AddRefed<SourceSurface>
 DrawTargetRecording::CreateSourceSurfaceFromData(unsigned char *aData,
                                                  const IntSize &aSize,
--- a/gfx/2d/DrawTargetRecording.h
+++ b/gfx/2d/DrawTargetRecording.h
@@ -227,16 +227,42 @@ public:
    */
   virtual void PushLayer(bool aOpaque, Float aOpacity,
                          SourceSurface* aMask,
                          const Matrix& aMaskTransform,
                          const IntRect& aBounds = IntRect(),
                          bool aCopyBackground = false) 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.a
+   * @param aCompositionOp The CompositionOp to use when blending the layer into
+   *                       the destination
+   */
+  virtual void PushLayerWithBlend(bool aOpaque, Float aOpacity,
+                         SourceSurface* aMask,
+                         const Matrix& aMaskTransform,
+                         const IntRect& aBounds = IntRect(),
+                         bool aCopyBackground = false,
+                         CompositionOp aCompositionOp = CompositionOp::OP_OVER) 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
--- a/gfx/2d/DrawTargetSkia.cpp
+++ b/gfx/2d/DrawTargetSkia.cpp
@@ -2062,25 +2062,36 @@ DrawTargetSkia::PopClip()
   SetTransform(GetTransform());
 }
 
 void
 DrawTargetSkia::PushLayer(bool aOpaque, Float aOpacity, SourceSurface* aMask,
                           const Matrix& aMaskTransform, const IntRect& aBounds,
                           bool aCopyBackground)
 {
-  PushedLayer layer(GetPermitSubpixelAA(), aOpaque, aOpacity, aMask, aMaskTransform,
+  PushLayerWithBlend(aOpaque, aOpacity, aMask, aMaskTransform, aBounds, aCopyBackground, CompositionOp::OP_OVER);
+}
+
+void
+DrawTargetSkia::PushLayerWithBlend(bool aOpaque, Float aOpacity, SourceSurface* aMask,
+                                   const Matrix& aMaskTransform, const IntRect& aBounds,
+                                   bool aCopyBackground, CompositionOp aCompositionOp)
+{
+  PushedLayer layer(GetPermitSubpixelAA(), aOpaque, aOpacity, aCompositionOp, aMask, aMaskTransform,
                     mCanvas->getTopDevice());
   mPushedLayers.push_back(layer);
 
   SkPaint paint;
 
   // If we have a mask, set the opacity to 0 so that SkCanvas::restore skips
   // implicitly drawing the layer so that we can properly mask it in PopLayer.
   paint.setAlpha(aMask ? 0 : ColorFloatToByte(aOpacity));
+  if (!aMask) {
+    paint.setBlendMode(GfxOpToSkiaOp(layer.mCompositionOp));
+  }
 
   // aBounds is supplied in device space, but SaveLayerRec wants local space.
   SkRect bounds = IntRectToSkRect(aBounds);
   if (!bounds.isEmpty()) {
     SkMatrix inverseCTM;
     if (mCanvas->getTotalMatrix().invert(&inverseCTM)) {
       inverseCTM.mapRect(&bounds);
     } else {
@@ -2137,16 +2148,17 @@ DrawTargetSkia::PopLayer()
 #endif
     }
 
     // Restore the background with the layer's device left alive.
     mCanvas->restore();
 
     SkPaint paint;
     paint.setAlpha(ColorFloatToByte(layer.mOpacity));
+    paint.setBlendMode(GfxOpToSkiaOp(layer.mCompositionOp));
 
     SkMatrix maskMat, layerMat;
     // Get the total transform affecting the mask, considering its pattern
     // transform and the current canvas transform.
     GfxMatrixToSkiaMatrix(layer.mMaskTransform, maskMat);
     maskMat.postConcat(mCanvas->getTotalMatrix());
     if (!maskMat.invert(&layerMat)) {
       gfxDebug() << *this << ": PopLayer() failed to invert mask transform";
--- a/gfx/2d/DrawTargetSkia.h
+++ b/gfx/2d/DrawTargetSkia.h
@@ -104,16 +104,22 @@ public:
   virtual void PushClipRect(const Rect& aRect) override;
   virtual void PushDeviceSpaceClipRects(const IntRect* aRects, uint32_t aCount) override;
   virtual void PopClip() override;
   virtual void PushLayer(bool aOpaque, Float aOpacity,
                          SourceSurface* aMask,
                          const Matrix& aMaskTransform,
                          const IntRect& aBounds = IntRect(),
                          bool aCopyBackground = false) override;
+  virtual void PushLayerWithBlend(bool aOpaque, Float aOpacity,
+                                  SourceSurface* aMask,
+                                  const Matrix& aMaskTransform,
+                                  const IntRect& aBounds = IntRect(),
+                                  bool aCopyBackground = false,
+                                  CompositionOp aCompositionOp = CompositionOp::OP_OVER) override;
   virtual void PopLayer() override;
   virtual void Blur(const AlphaBoxBlur& aBlur) override;
   virtual already_AddRefed<SourceSurface> CreateSourceSurfaceFromData(unsigned char *aData,
                                                             const IntSize &aSize,
                                                             int32_t aStride,
                                                             SurfaceFormat aFormat) const override;
   virtual already_AddRefed<SourceSurface> OptimizeSourceSurface(SourceSurface *aSurface) const override;
   virtual already_AddRefed<SourceSurface> OptimizeSourceSurfaceForUnknownAlpha(SourceSurface *aSurface) const override;
@@ -173,29 +179,32 @@ private:
 
   bool UsingSkiaGPU() const;
 
   struct PushedLayer
   {
     PushedLayer(bool aOldPermitSubpixelAA,
                 bool aOpaque,
                 Float aOpacity,
+                CompositionOp aCompositionOp,
                 SourceSurface* aMask,
                 const Matrix& aMaskTransform,
                 SkBaseDevice* aPreviousDevice)
       : mOldPermitSubpixelAA(aOldPermitSubpixelAA),
         mOpaque(aOpaque),
         mOpacity(aOpacity),
+        mCompositionOp(aCompositionOp),
         mMask(aMask),
         mMaskTransform(aMaskTransform),
         mPreviousDevice(aPreviousDevice)
     {}
     bool mOldPermitSubpixelAA;
     bool mOpaque;
     Float mOpacity;
+    CompositionOp mCompositionOp;
     RefPtr<SourceSurface> mMask;
     Matrix mMaskTransform;
     SkBaseDevice* mPreviousDevice;
   };
   std::vector<PushedLayer> mPushedLayers;
 
 #ifdef USE_SKIA_GPU
   sk_sp<GrContext> mGrContext;
--- a/gfx/2d/RecordedEvent.h
+++ b/gfx/2d/RecordedEvent.h
@@ -251,16 +251,17 @@ public:
     DRAWFILTER,
     FILTERNODESETATTRIBUTE,
     FILTERNODESETINPUT,
     CREATESIMILARDRAWTARGET,
     CREATECLIPPEDDRAWTARGET,
     FONTDATA,
     FONTDESC,
     PUSHLAYER,
+    PUSHLAYERWITHBLEND,
     POPLAYER,
     UNSCALEDFONTCREATION,
     UNSCALEDFONTDESTRUCTION,
     INTOLUMINANCE,
   };
   static const uint32_t kTotalEventTypes = RecordedEvent::FILTERNODESETINPUT + 1;
 
   virtual ~RecordedEvent() {}
--- a/gfx/2d/RecordedEventImpl.h
+++ b/gfx/2d/RecordedEventImpl.h
@@ -525,16 +525,52 @@ private:
   bool mOpaque;
   Float mOpacity;
   ReferencePtr mMask;
   Matrix mMaskTransform;
   IntRect mBounds;
   bool mCopyBackground;
 };
 
+class RecordedPushLayerWithBlend : public RecordedDrawingEvent<RecordedPushLayerWithBlend> {
+public:
+  RecordedPushLayerWithBlend(DrawTarget* aDT, bool aOpaque, Float aOpacity,
+                    SourceSurface* aMask, const Matrix& aMaskTransform,
+                    const IntRect& aBounds, bool aCopyBackground,
+                    CompositionOp aCompositionOp)
+    : RecordedDrawingEvent(PUSHLAYERWITHBLEND, aDT), mOpaque(aOpaque)
+    , mOpacity(aOpacity), mMask(aMask), mMaskTransform(aMaskTransform)
+    , mBounds(aBounds), mCopyBackground(aCopyBackground)
+    , mCompositionOp(aCompositionOp)
+  {
+  }
+
+  virtual bool PlayEvent(Translator *aTranslator) const override;
+
+  template<class S> void Record(S &aStream) const;
+  virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const override;
+
+  virtual std::string GetName() const override { return "PushLayerWithBlend"; }
+
+private:
+  friend class RecordedEvent;
+
+  template<class S>
+  MOZ_IMPLICIT RecordedPushLayerWithBlend(S &aStream);
+
+  bool mOpaque;
+  Float mOpacity;
+  ReferencePtr mMask;
+  Matrix mMaskTransform;
+  IntRect mBounds;
+  bool mCopyBackground;
+  CompositionOp mCompositionOp;
+};
+
+
 class RecordedPopLayer : public RecordedDrawingEvent<RecordedPopLayer> {
 public:
   MOZ_IMPLICIT RecordedPopLayer(DrawTarget* aDT)
     : RecordedDrawingEvent(POPLAYER, aDT)
   {
   }
 
   virtual bool PlayEvent(Translator *aTranslator) const override;
@@ -2263,16 +2299,61 @@ RecordedPushLayer::RecordedPushLayer(S &
 inline void
 RecordedPushLayer::OutputSimpleEventInfo(std::stringstream &aStringStream) const
 {
   aStringStream << "[" << mDT << "] PushPLayer (Opaque=" << mOpaque <<
     ", Opacity=" << mOpacity << ", Mask Ref=" << mMask << ") ";
 }
 
 inline bool
+RecordedPushLayerWithBlend::PlayEvent(Translator *aTranslator) const
+{
+  SourceSurface* mask = mMask ? aTranslator->LookupSourceSurface(mMask)
+                              : nullptr;
+  aTranslator->LookupDrawTarget(mDT)->
+    PushLayerWithBlend(mOpaque, mOpacity, mask, mMaskTransform, mBounds, mCopyBackground, mCompositionOp);
+  return true;
+}
+
+template<class S>
+void
+RecordedPushLayerWithBlend::Record(S &aStream) const
+{
+  RecordedDrawingEvent::Record(aStream);
+  WriteElement(aStream, mOpaque);
+  WriteElement(aStream, mOpacity);
+  WriteElement(aStream, mMask);
+  WriteElement(aStream, mMaskTransform);
+  WriteElement(aStream, mBounds);
+  WriteElement(aStream, mCopyBackground);
+  WriteElement(aStream, mCompositionOp);
+}
+
+template<class S>
+RecordedPushLayerWithBlend::RecordedPushLayerWithBlend(S &aStream)
+  : RecordedDrawingEvent(PUSHLAYERWITHBLEND, aStream)
+{
+  ReadElement(aStream, mOpaque);
+  ReadElement(aStream, mOpacity);
+  ReadElement(aStream, mMask);
+  ReadElement(aStream, mMaskTransform);
+  ReadElement(aStream, mBounds);
+  ReadElement(aStream, mCopyBackground);
+  ReadElement(aStream, mCompositionOp);
+}
+
+inline void
+RecordedPushLayerWithBlend::OutputSimpleEventInfo(std::stringstream &aStringStream) const
+{
+  aStringStream << "[" << mDT << "] PushLayerWithBlend (Opaque=" << mOpaque <<
+    ", Opacity=" << mOpacity << ", Mask Ref=" << mMask << ") ";
+}
+
+
+inline bool
 RecordedPopLayer::PlayEvent(Translator *aTranslator) const
 {
   aTranslator->LookupDrawTarget(mDT)->PopLayer();
   return true;
 }
 
 template<class S>
 void
@@ -3406,16 +3487,17 @@ RecordedFilterNodeSetInput::OutputSimple
     f(MASKSURFACE, RecordedMaskSurface); \
     f(FILTERNODESETATTRIBUTE, RecordedFilterNodeSetAttribute); \
     f(FILTERNODESETINPUT, RecordedFilterNodeSetInput); \
     f(CREATESIMILARDRAWTARGET, RecordedCreateSimilarDrawTarget); \
     f(CREATECLIPPEDDRAWTARGET, RecordedCreateClippedDrawTarget); \
     f(FONTDATA, RecordedFontData); \
     f(FONTDESC, RecordedFontDescriptor); \
     f(PUSHLAYER, RecordedPushLayer); \
+    f(PUSHLAYERWITHBLEND, RecordedPushLayerWithBlend); \
     f(POPLAYER, RecordedPopLayer); \
     f(UNSCALEDFONTCREATION, RecordedUnscaledFontCreation); \
     f(UNSCALEDFONTDESTRUCTION, RecordedUnscaledFontDestruction); \
     f(INTOLUMINANCE, RecordedIntoLuminanceSource);
 
 template<class S>
 RecordedEvent *
 RecordedEvent::LoadEvent(S &aStream, EventType aType)