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
This commit is contained in:
Jeff Muizelaar 2018-02-17 12:07:30 -05:00
parent d70a10cbd8
commit 62a9686ee2
7 changed files with 172 additions and 1 deletions

View File

@ -1222,6 +1222,30 @@ public:
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

View File

@ -526,6 +526,23 @@ DrawTargetRecording::PushLayer(bool aOpaque, Float aOpacity,
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()
{

View File

@ -231,6 +231,32 @@ public:
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

View File

@ -2067,7 +2067,15 @@ 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);
@ -2076,6 +2084,9 @@ DrawTargetSkia::PushLayer(bool aOpaque, Float aOpacity, SourceSurface* aMask,
// 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);
@ -2142,6 +2153,7 @@ DrawTargetSkia::PopLayer()
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

View File

@ -109,6 +109,12 @@ public:
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,
@ -178,12 +184,14 @@ private:
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)
@ -191,6 +199,7 @@ private:
bool mOldPermitSubpixelAA;
bool mOpaque;
Float mOpacity;
CompositionOp mCompositionOp;
RefPtr<SourceSurface> mMask;
Matrix mMaskTransform;
SkBaseDevice* mPreviousDevice;

View File

@ -256,6 +256,7 @@ public:
FONTDATA,
FONTDESC,
PUSHLAYER,
PUSHLAYERWITHBLEND,
POPLAYER,
UNSCALEDFONTCREATION,
UNSCALEDFONTDESTRUCTION,

View File

@ -530,6 +530,42 @@ private:
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)
@ -2267,6 +2303,51 @@ RecordedPushLayer::OutputSimpleEventInfo(std::stringstream &aStringStream) const
", 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
{
@ -3411,6 +3492,7 @@ RecordedFilterNodeSetInput::OutputSimpleEventInfo(std::stringstream &aStringStre
f(FONTDATA, RecordedFontData); \
f(FONTDESC, RecordedFontDescriptor); \
f(PUSHLAYER, RecordedPushLayer); \
f(PUSHLAYERWITHBLEND, RecordedPushLayerWithBlend); \
f(POPLAYER, RecordedPopLayer); \
f(UNSCALEDFONTCREATION, RecordedUnscaledFontCreation); \
f(UNSCALEDFONTDESTRUCTION, RecordedUnscaledFontDestruction); \