Bug 841601 - Add background-blend-mode implementation. r=roc

This commit is contained in:
Horia Iosif Olaru 2013-11-08 10:08:03 -05:00
Родитель 56504fb58d
Коммит b360983fd3
3 изменённых файлов: 64 добавлений и 5 удалений

Просмотреть файл

@ -320,6 +320,30 @@ static nscolor MakeBevelColor(mozilla::css::Side whichSide, uint8_t style,
nscolor aBackgroundColor,
nscolor aBorderColor);
static gfxContext::GraphicsOperator GetGFXBlendMode(uint8_t mBlendMode)
{
switch (mBlendMode) {
case NS_STYLE_BLEND_NORMAL: return gfxContext::OPERATOR_OVER;
case NS_STYLE_BLEND_MULTIPLY: return gfxContext::OPERATOR_MULTIPLY;
case NS_STYLE_BLEND_SCREEN: return gfxContext::OPERATOR_SCREEN;
case NS_STYLE_BLEND_OVERLAY: return gfxContext::OPERATOR_OVERLAY;
case NS_STYLE_BLEND_DARKEN: return gfxContext::OPERATOR_DARKEN;
case NS_STYLE_BLEND_LIGHTEN: return gfxContext::OPERATOR_LIGHTEN;
case NS_STYLE_BLEND_COLOR_DODGE: return gfxContext::OPERATOR_COLOR_DODGE;
case NS_STYLE_BLEND_COLOR_BURN: return gfxContext::OPERATOR_COLOR_BURN;
case NS_STYLE_BLEND_HARD_LIGHT: return gfxContext::OPERATOR_HARD_LIGHT;
case NS_STYLE_BLEND_SOFT_LIGHT: return gfxContext::OPERATOR_SOFT_LIGHT;
case NS_STYLE_BLEND_DIFFERENCE: return gfxContext::OPERATOR_DIFFERENCE;
case NS_STYLE_BLEND_EXCLUSION: return gfxContext::OPERATOR_EXCLUSION;
case NS_STYLE_BLEND_HUE: return gfxContext::OPERATOR_HUE;
case NS_STYLE_BLEND_SATURATION: return gfxContext::OPERATOR_SATURATION;
case NS_STYLE_BLEND_COLOR: return gfxContext::OPERATOR_COLOR;
case NS_STYLE_BLEND_LUMINOSITY: return gfxContext::OPERATOR_LUMINOSITY;
}
return gfxContext::OPERATOR_OVER;
}
static InlineBackgroundData* gInlineBGData = nullptr;
// Initialize any static variables used by nsCSSRendering.
@ -2561,10 +2585,18 @@ nsCSSRendering::PaintBackgroundWithSC(nsPresContext* aPresContext,
nsBackgroundLayerState state = PrepareBackgroundLayer(aPresContext, aForFrame,
aFlags, aBorderArea, clipState.mBGClipArea, *bg, layer);
if (!state.mFillArea.IsEmpty()) {
if (state.mCompositingOp != gfxContext::OPERATOR_OVER) {
NS_ASSERTION(ctx->CurrentOperator() == gfxContext::OPERATOR_OVER,
"It is assumed the initial operator is OPERATOR_OVER, when it is restored later");
ctx->SetOperator(state.mCompositingOp);
}
state.mImageRenderer.DrawBackground(aPresContext, aRenderingContext,
state.mDestArea, state.mFillArea,
state.mAnchor + aBorderArea.TopLeft(),
clipState.mDirtyRect);
if (state.mCompositingOp != gfxContext::OPERATOR_OVER) {
ctx->SetOperator(gfxContext::OPERATOR_OVER);
}
}
}
}
@ -2856,6 +2888,7 @@ nsCSSRendering::PrepareBackgroundLayer(nsPresContext* aPresContext,
* background-origin
* background-size
* background-break (-moz-background-inline-policy)
* background-blend-mode
*
* (background-color applies to the entire element and not to individual
* layers, so it is irrelevant to this method.)
@ -2978,6 +3011,9 @@ nsCSSRendering::PrepareBackgroundLayer(nsPresContext* aPresContext,
state.mFillArea.height = bgClipRect.height;
}
state.mFillArea.IntersectRect(state.mFillArea, bgClipRect);
state.mCompositingOp = GetGFXBlendMode(aLayer.mBlendMode);
return state;
}

Просмотреть файл

@ -213,7 +213,7 @@ struct nsBackgroundLayerState {
* @param aFlags some combination of nsCSSRendering::PAINTBG_* flags
*/
nsBackgroundLayerState(nsIFrame* aForFrame, const nsStyleImage* aImage, uint32_t aFlags)
: mImageRenderer(aForFrame, aImage, aFlags) {}
: mImageRenderer(aForFrame, aImage, aFlags), mCompositingOp(gfxContext::OPERATOR_OVER) {}
/**
* The nsImageRenderer that will be used to draw the background.
@ -237,6 +237,10 @@ struct nsBackgroundLayerState {
* PrepareBackgroundLayer.
*/
nsPoint mAnchor;
/**
* The compositing operation that the image should use
*/
gfxContext::GraphicsOperator mCompositingOp;
};
struct nsCSSRendering {

Просмотреть файл

@ -1739,11 +1739,15 @@ nsDisplayBackgroundImage::AppendBackgroundItemsToTop(nsDisplayListBuilder* aBuil
drawBackgroundImage, drawBackgroundColor);
}
// An auxiliary list is necessary in case we have background blending; if that
// is the case, background items need to be wrapped by a blend container to
// isolate blending to the background
nsDisplayList bgItemList;
// Even if we don't actually have a background color to paint, we may still need
// to create an item for hit testing.
if ((drawBackgroundColor && color != NS_RGBA(0,0,0,0)) ||
aBuilder->IsForEventDelivery()) {
aList->AppendNewToTop(
bgItemList.AppendNewToTop(
new (aBuilder) nsDisplayBackgroundColor(aBuilder, aFrame, bg,
drawBackgroundColor ? color : NS_RGBA(0, 0, 0, 0)));
}
@ -1751,25 +1755,40 @@ nsDisplayBackgroundImage::AppendBackgroundItemsToTop(nsDisplayListBuilder* aBuil
if (isThemed) {
nsDisplayThemedBackground* bgItem =
new (aBuilder) nsDisplayThemedBackground(aBuilder, aFrame);
aList->AppendNewToTop(bgItem);
bgItemList.AppendNewToTop(bgItem);
aList->AppendToTop(&bgItemList);
return true;
}
if (!bg) {
aList->AppendToTop(&bgItemList);
return false;
}
bool needBlendContainer = false;
// Passing bg == nullptr in this macro will result in one iteration with
// i = 0.
NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, bg) {
if (bg->mLayers[i].mImage.IsEmpty()) {
continue;
}
if (bg->mLayers[i].mBlendMode != NS_STYLE_BLEND_NORMAL) {
needBlendContainer = true;
}
nsDisplayBackgroundImage* bgItem =
new (aBuilder) nsDisplayBackgroundImage(aBuilder, aFrame, i, bg);
aList->AppendNewToTop(bgItem);
bgItemList.AppendNewToTop(bgItem);
}
if (needBlendContainer) {
bgItemList.AppendNewToTop(
new (aBuilder) nsDisplayBlendContainer(aBuilder, aFrame, &bgItemList));
}
aList->AppendToTop(&bgItemList);
return false;
}
@ -2091,7 +2110,7 @@ nsDisplayBackgroundImage::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
if (mBackgroundStyle->mBackgroundInlinePolicy == NS_STYLE_BG_INLINE_POLICY_EACH_BOX ||
(!mFrame->GetPrevContinuation() && !mFrame->GetNextContinuation())) {
const nsStyleBackground::Layer& layer = mBackgroundStyle->mLayers[mLayer];
if (layer.mImage.IsOpaque()) {
if (layer.mImage.IsOpaque() && layer.mBlendMode == NS_STYLE_BLEND_NORMAL) {
nsPresContext* presContext = mFrame->PresContext();
result = GetInsideClipRegion(this, presContext, layer.mClip, mBounds, aSnap);
}