Bug 1248913 - Let nsDisplayBackgroundImage specify the background blend mode. r?mattwoodrow
This is needed because blending for nsDisplayBackgroundImage items will soon
happen outside of nsDisplayBackgroundImage::Paint, it will be done by an
nsDisplayBlendMode item that wraps the nsDisplayBackgroundImage item.
MozReview-Commit-ID: 20cILOGVFEG
--- a/layout/base/nsCSSRendering.cpp
+++ b/layout/base/nsCSSRendering.cpp
@@ -1647,17 +1647,18 @@ nsCSSRendering::PaintBoxShadowInner(nsPr
DrawResult
nsCSSRendering::PaintBackground(nsPresContext* aPresContext,
nsRenderingContext& aRenderingContext,
nsIFrame* aForFrame,
const nsRect& aDirtyRect,
const nsRect& aBorderArea,
uint32_t aFlags,
nsRect* aBGClipRect,
- int32_t aLayer)
+ int32_t aLayer,
+ CompositionOp aCompositonOp)
{
PROFILER_LABEL("nsCSSRendering", "PaintBackground",
js::ProfileEntry::Category::GRAPHICS);
NS_PRECONDITION(aForFrame,
"Frame is expected to be provided to PaintBackground");
nsStyleContext *sc;
@@ -1677,17 +1678,17 @@ nsCSSRendering::PaintBackground(nsPresCo
}
sc = aForFrame->StyleContext();
}
return PaintBackgroundWithSC(aPresContext, aRenderingContext, aForFrame,
aDirtyRect, aBorderArea, sc,
*aForFrame->StyleBorder(), aFlags,
- aBGClipRect, aLayer);
+ aBGClipRect, aLayer, aCompositonOp);
}
static bool
IsOpaqueBorderEdge(const nsStyleBorder& aBorder, mozilla::css::Side aSide)
{
if (aBorder.GetComputedBorder().Side(aSide) == 0)
return true;
switch (aBorder.GetBorderStyle(aSide)) {
@@ -2853,17 +2854,18 @@ nsCSSRendering::PaintBackgroundWithSC(ns
nsRenderingContext& aRenderingContext,
nsIFrame* aForFrame,
const nsRect& aDirtyRect,
const nsRect& aBorderArea,
nsStyleContext* aBackgroundSC,
const nsStyleBorder& aBorder,
uint32_t aFlags,
nsRect* aBGClipRect,
- int32_t aLayer)
+ int32_t aLayer,
+ CompositionOp aCompositonOp)
{
NS_PRECONDITION(aForFrame,
"Frame is expected to be provided to PaintBackground");
DrawResult result = DrawResult::SUCCESS;
// Check to see if we have an appearance defined. If so, we let the theme
// renderer draw the background and bail out.
@@ -3028,39 +3030,43 @@ nsCSSRendering::PaintBackgroundWithSC(ns
ctx->NewPath();
ctx->SnappedRectangle(clip);
ctx->Clip();
}
}
}
if ((aLayer < 0 || i == (uint32_t)startLayer) &&
!clipState.mDirtyRectGfx.IsEmpty()) {
+ // When we're drawing a single layer, use the specified composition op,
+ // otherwise get the compositon op from the image layer.
+ CompositionOp co = (aLayer >= 0) ? aCompositonOp :
+ (paintMask ? GetGFXCompositeMode(layer.mComposite) :
+ GetGFXBlendMode(layer.mBlendMode));
nsBackgroundLayerState state =
PrepareImageLayer(aPresContext, aForFrame,
aFlags, paintBorderArea, clipState.mBGClipArea,
- layer, paintMask);
+ layer, co);
result &= state.mImageRenderer.PrepareResult();
if (!state.mFillArea.IsEmpty()) {
// Always using OP_OVER mode while drawing the bottom mask layer.
bool isBottomMaskLayer = paintMask ?
(i == (layers.mImageCount - 1)) : false;
- if (state.mCompositionOp != CompositionOp::OP_OVER &&
- !isBottomMaskLayer) {
+ if (co != CompositionOp::OP_OVER && !isBottomMaskLayer) {
NS_ASSERTION(ctx->CurrentOp() == CompositionOp::OP_OVER,
"It is assumed the initial op is OP_OVER, when it is restored later");
- ctx->SetOp(state.mCompositionOp);
+ ctx->SetOp(co);
}
result &=
state.mImageRenderer.DrawBackground(aPresContext, aRenderingContext,
state.mDestArea, state.mFillArea,
state.mAnchor + paintBorderArea.TopLeft(),
clipState.mDirtyRect);
- if (state.mCompositionOp != CompositionOp::OP_OVER) {
+ if (co != CompositionOp::OP_OVER) {
ctx->SetOp(CompositionOp::OP_OVER);
}
}
}
}
}
return result;
@@ -3218,17 +3224,17 @@ ComputeDrawnSizeForBackground(const CSSS
nsBackgroundLayerState
nsCSSRendering::PrepareImageLayer(nsPresContext* aPresContext,
nsIFrame* aForFrame,
uint32_t aFlags,
const nsRect& aBorderArea,
const nsRect& aBGClipRect,
const nsStyleImageLayers::Layer& aLayer,
- bool aMask)
+ CompositionOp aCompositonOp)
{
/*
* The properties we need to keep in mind when drawing style image
* layers are:
*
* background-image/ mask-image
* background-repeat/ mask-repeat
* background-attachment
@@ -3380,19 +3386,16 @@ nsCSSRendering::PrepareImageLayer(nsPres
} else {
repeatMode = ExtendMode::REPEAT_Y;
}
}
state.mImageRenderer.SetExtendMode(repeatMode);
state.mFillArea.IntersectRect(state.mFillArea, bgClipRect);
- state.mCompositionOp = aMask ? GetGFXCompositeMode(aLayer.mComposite) :
- GetGFXBlendMode(aLayer.mBlendMode);
-
return state;
}
nsRect
nsCSSRendering::GetBackgroundLayerRect(nsPresContext* aPresContext,
nsIFrame* aForFrame,
const nsRect& aBorderArea,
const nsRect& aClipRect,
--- a/layout/base/nsCSSRendering.h
+++ b/layout/base/nsCSSRendering.h
@@ -310,17 +310,16 @@ struct nsBackgroundLayerState {
typedef mozilla::gfx::CompositionOp CompositionOp;
/**
* @param aFlags some combination of nsCSSRendering::PAINTBG_* flags
*/
nsBackgroundLayerState(nsIFrame* aForFrame, const nsStyleImage* aImage,
uint32_t aFlags)
: mImageRenderer(aForFrame, aImage, aFlags)
- , mCompositionOp(CompositionOp::OP_OVER)
{}
/**
* The nsImageRenderer that will be used to draw the background.
*/
nsImageRenderer mImageRenderer;
/**
* A rectangle that one copy of the image tile is mapped onto. Same
@@ -335,20 +334,16 @@ struct nsBackgroundLayerState {
*/
nsRect mFillArea;
/**
* The anchor point that should be snapped to a pixel corner. Same
* coordinate system as aBorderArea/aBGClipRect passed into
* PrepareImageLayer.
*/
nsPoint mAnchor;
- /**
- * The composition operation that the image should use.
- */
- CompositionOp mCompositionOp;
};
struct nsCSSRendering {
typedef mozilla::gfx::CompositionOp CompositionOp;
typedef mozilla::gfx::DrawTarget DrawTarget;
typedef mozilla::gfx::Float Float;
typedef mozilla::gfx::Point Point;
typedef mozilla::gfx::Rect Rect;
@@ -540,17 +535,17 @@ struct nsCSSRendering {
static nsBackgroundLayerState
PrepareImageLayer(nsPresContext* aPresContext,
nsIFrame* aForFrame,
uint32_t aFlags,
const nsRect& aBorderArea,
const nsRect& aBGClipRect,
const nsStyleImageLayers::Layer& aLayer,
- bool aMask = false);
+ CompositionOp aCompositionOp = CompositionOp::OP_OVER);
struct ImageLayerClipState {
nsRect mBGClipArea; // Affected by mClippedRadii
nsRect mAdditionalBGClipArea; // Not affected by mClippedRadii
nsRect mDirtyRect;
gfxRect mDirtyRectGfx;
nscoord mRadii[8];
@@ -597,38 +592,43 @@ struct nsCSSRendering {
};
static DrawResult PaintBackground(nsPresContext* aPresContext,
nsRenderingContext& aRenderingContext,
nsIFrame* aForFrame,
const nsRect& aDirtyRect,
const nsRect& aBorderArea,
uint32_t aFlags,
nsRect* aBGClipRect = nullptr,
- int32_t aLayer = -1);
+ int32_t aLayer = -1,
+ CompositionOp aCompositionOp = CompositionOp::OP_OVER);
/**
* Same as |PaintBackground|, except using the provided style structs.
* This short-circuits the code that ensures that the root element's
* background is drawn on the canvas.
* The aLayer parameter allows you to paint a single layer of the background.
* The default value for aLayer, -1, means that all layers will be painted.
* The background color will only be painted if the back-most layer is also
* being painted.
+ * aCompositionOp is only respected if a single layer is specified (aLayer != -1).
+ * If all layers are painted, the image layer's blend mode (or the mask
+ * layer's composition mode) will be used.
*/
static DrawResult PaintBackgroundWithSC(nsPresContext* aPresContext,
nsRenderingContext& aRenderingContext,
nsIFrame* aForFrame,
const nsRect& aDirtyRect,
const nsRect& aBorderArea,
nsStyleContext *aStyleContext,
const nsStyleBorder& aBorder,
uint32_t aFlags,
nsRect* aBGClipRect = nullptr,
- int32_t aLayer = -1);
+ int32_t aLayer = -1,
+ CompositionOp aCompositionOp = CompositionOp::OP_OVER);
/**
* Returns the rectangle covered by the given background layer image, taking
* into account background positioning, sizing, and repetition, but not
* clipping.
*/
static nsRect GetBackgroundLayerRect(nsPresContext* aPresContext,
nsIFrame* aForFrame,
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -2970,21 +2970,23 @@ nsDisplayBackgroundImage::Paint(nsDispla
void
nsDisplayBackgroundImage::PaintInternal(nsDisplayListBuilder* aBuilder,
nsRenderingContext* aCtx, const nsRect& aBounds,
nsRect* aClipRect) {
nsPoint offset = ToReferenceFrame();
uint32_t flags = aBuilder->GetBackgroundPaintFlags();
CheckForBorderItem(this, flags);
+ const nsStyleImageLayers::Layer &layer = mBackgroundStyle->mImage.mLayers[mLayer];
image::DrawResult result =
nsCSSRendering::PaintBackground(mFrame->PresContext(), *aCtx, mFrame,
aBounds,
nsRect(offset, mFrame->GetSize()),
- flags, aClipRect, mLayer);
+ flags, aClipRect, mLayer,
+ nsCSSRendering::GetGFXBlendMode(layer.mBlendMode));
nsDisplayBackgroundGeometry::UpdateDrawResult(this, result);
}
void nsDisplayBackgroundImage::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion* aInvalidRegion)
{
--- a/layout/svg/nsSVGIntegrationUtils.cpp
+++ b/layout/svg/nsSVGIntegrationUtils.cpp
@@ -580,19 +580,17 @@ nsSVGIntegrationUtils::PaintFramesWithEf
nsRenderingContext rc(target);
nsCSSRendering::PaintBackgroundWithSC(aFrame->PresContext(),
rc,
aFrame,
aDirtyRect,
aBorderArea,
firstFrame->StyleContext(),
*aFrame->StyleBorder(),
- flags,
- nullptr,
- -1);
+ flags);
maskSurface = targetDT->Snapshot();
// Compute mask transform.
Matrix mat = ToMatrix(aContext.CurrentMatrix());
mat.Invert();
maskTransform = Matrix::Translation(drawRect.x, drawRect.y) * mat;
}