Bug 1248913 - Build nsDisplayBlendMode items for background-blend-mode. r?mattwoodrow
MozReview-Commit-ID: 72IzlcgHFtd
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -2478,16 +2478,19 @@ nsDisplayBackgroundImage::AppendBackgrou
aList->AppendToTop(&bgItemList);
return true;
}
if (!bg) {
aList->AppendToTop(&bgItemList);
return false;
}
+
+ const DisplayItemScrollClip* scrollClip =
+ aBuilder->ClipState().GetCurrentInnermostScrollClip();
bool needBlendContainer = false;
// Passing bg == nullptr in this macro will result in one iteration with
// i = 0.
NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, bg->mImage) {
if (bg->mImage.mLayers[i].mImage.IsEmpty()) {
continue;
@@ -2499,30 +2502,39 @@ nsDisplayBackgroundImage::AppendBackgrou
DisplayListClipState::AutoSaveRestore clipState(aBuilder);
if (!aBuilder->IsForEventDelivery()) {
const nsStyleImageLayers::Layer& layer = bg->mImage.mLayers[i];
SetBackgroundClipRegion(clipState, aFrame, toRef,
layer, willPaintBorder);
}
+ nsDisplayList thisItemList;
nsDisplayBackgroundImage* bgItem =
new (aBuilder) nsDisplayBackgroundImage(aBuilder, aFrame, i, bg);
if (bgItem->ShouldFixToViewport(aBuilder)) {
- bgItemList.AppendNewToTop(
+ thisItemList.AppendNewToTop(
nsDisplayFixedPosition::CreateForFixedBackground(aBuilder, aFrame, bgItem, i));
} else {
- bgItemList.AppendNewToTop(bgItem);
+ thisItemList.AppendNewToTop(bgItem);
}
+
+ if (bg->mImage.mLayers[i].mBlendMode != NS_STYLE_BLEND_NORMAL) {
+ thisItemList.AppendNewToTop(
+ new (aBuilder) nsDisplayBlendMode(aBuilder, aFrame, &thisItemList,
+ bg->mImage.mLayers[i].mBlendMode,
+ scrollClip, i + 1));
+ }
+ bgItemList.AppendToTop(&thisItemList);
}
if (needBlendContainer) {
bgItemList.AppendNewToTop(
- new (aBuilder) nsDisplayBlendContainer(aBuilder, aFrame, &bgItemList));
+ new (aBuilder) nsDisplayBlendContainer(aBuilder, aFrame, &bgItemList, scrollClip));
}
aList->AppendToTop(&bgItemList);
return false;
}
// Check that the rounded border of aFrame, added to aToReferenceFrame,
// intersects aRect. Assumes that the unrounded border has already
@@ -2970,23 +2982,22 @@ 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,
- nsCSSRendering::GetGFXBlendMode(layer.mBlendMode));
+ CompositionOp::OP_OVER);
nsDisplayBackgroundGeometry::UpdateDrawResult(this, result);
}
void nsDisplayBackgroundImage::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion* aInvalidRegion)
{
@@ -4320,19 +4331,21 @@ void
nsDisplayOpacity::WriteDebugInfo(std::stringstream& aStream)
{
aStream << " (opacity " << mOpacity << ")";
}
nsDisplayBlendMode::nsDisplayBlendMode(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame, nsDisplayList* aList,
uint8_t aBlendMode,
- const DisplayItemScrollClip* aScrollClip)
+ const DisplayItemScrollClip* aScrollClip,
+ uint32_t aIndex)
: nsDisplayWrapList(aBuilder, aFrame, aList, aScrollClip)
, mBlendMode(aBlendMode)
+ , mIndex(aIndex)
{
MOZ_COUNT_CTOR(nsDisplayBlendMode);
}
#ifdef NS_BUILD_REFCNT_LOGGING
nsDisplayBlendMode::~nsDisplayBlendMode() {
MOZ_COUNT_DTOR(nsDisplayBlendMode);
}
@@ -4384,26 +4397,28 @@ bool nsDisplayBlendMode::ComputeVisibili
nsRegion visibleUnderChildren;
visibleUnderChildren.And(*aVisibleRegion, bounds);
return nsDisplayWrapList::ComputeVisibility(aBuilder, &visibleUnderChildren);
}
bool nsDisplayBlendMode::TryMerge(nsDisplayItem* aItem) {
if (aItem->GetType() != TYPE_BLEND_MODE)
return false;
+ nsDisplayBlendMode* item = static_cast<nsDisplayBlendMode*>(aItem);
// items for the same content element should be merged into a single
// compositing group
- // aItem->GetUnderlyingFrame() returns non-null because it's nsDisplayOpacity
- if (aItem->Frame()->GetContent() != mFrame->GetContent())
+ if (item->Frame()->GetContent() != mFrame->GetContent())
return false;
- if (aItem->GetClip() != GetClip())
+ if (item->mIndex != 0 || mIndex != 0)
+ return false; // don't merge background-blend-mode items
+ if (item->GetClip() != GetClip())
return false;
- if (aItem->ScrollClip() != ScrollClip())
+ if (item->ScrollClip() != ScrollClip())
return false;
- MergeFromTrackingMergedFrames(static_cast<nsDisplayBlendMode*>(aItem));
+ MergeFromTrackingMergedFrames(item);
return true;
}
nsDisplayBlendContainer::nsDisplayBlendContainer(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame, nsDisplayList* aList,
const DisplayItemScrollClip* aScrollClip)
: nsDisplayWrapList(aBuilder, aFrame, aList, aScrollClip)
, mIndex(0)
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -3387,46 +3387,52 @@ private:
float mOpacity;
bool mForEventsOnly;
};
class nsDisplayBlendMode : public nsDisplayWrapList {
public:
nsDisplayBlendMode(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
nsDisplayList* aList, uint8_t aBlendMode,
- const DisplayItemScrollClip* aScrollClip);
+ const DisplayItemScrollClip* aScrollClip,
+ uint32_t aIndex = 0);
#ifdef NS_BUILD_REFCNT_LOGGING
virtual ~nsDisplayBlendMode();
#endif
nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
bool* aSnap) override;
virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerLayerParameters& aContainerParameters) override;
virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion* aInvalidRegion) override
{
// We don't need to compute an invalidation region since we have LayerTreeInvalidation
}
+ virtual uint32_t GetPerFrameKey() override {
+ return (mIndex << nsDisplayItem::TYPE_BITS) |
+ nsDisplayItem::GetPerFrameKey();
+ }
virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerLayerParameters& aParameters) override;
virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
nsRegion* aVisibleRegion) override;
virtual bool TryMerge(nsDisplayItem* aItem) override;
virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override {
return false;
}
NS_DISPLAY_DECL_NAME("BlendMode", TYPE_BLEND_MODE)
private:
uint8_t mBlendMode;
+ uint32_t mIndex;
};
class nsDisplayBlendContainer : public nsDisplayWrapList {
public:
// Use this constructor for blend containers that can have active child layers.
nsDisplayBlendContainer(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
nsDisplayList* aList,
const DisplayItemScrollClip* aScrollClip);
--- a/layout/generic/nsCanvasFrame.cpp
+++ b/layout/generic/nsCanvasFrame.cpp
@@ -402,40 +402,54 @@ nsCanvasFrame::BuildDisplayList(nsDispla
new (aBuilder) nsDisplayCanvasThemedBackground(aBuilder, this));
return;
}
if (!bg) {
return;
}
+ const DisplayItemScrollClip* scrollClip =
+ aBuilder->ClipState().GetCurrentInnermostScrollClip();
+
bool needBlendContainer = false;
// Create separate items for each background layer.
const nsStyleImageLayers& layers = bg->mImage;
NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, layers) {
if (layers.mLayers[i].mImage.IsEmpty()) {
continue;
}
if (layers.mLayers[i].mBlendMode != NS_STYLE_BLEND_NORMAL) {
needBlendContainer = true;
}
+
+ nsDisplayList thisItemList;
nsDisplayCanvasBackgroundImage* bgItem =
new (aBuilder) nsDisplayCanvasBackgroundImage(aBuilder, this, i, bg);
if (bgItem->ShouldFixToViewport(aBuilder)) {
- aLists.BorderBackground()->AppendNewToTop(
+ thisItemList.AppendNewToTop(
nsDisplayFixedPosition::CreateForFixedBackground(aBuilder, this, bgItem, i));
} else {
- aLists.BorderBackground()->AppendNewToTop(bgItem);
+ thisItemList.AppendNewToTop(bgItem);
}
+
+ if (layers.mLayers[i].mBlendMode != NS_STYLE_BLEND_NORMAL) {
+ thisItemList.AppendNewToTop(
+ new (aBuilder) nsDisplayBlendMode(aBuilder, this, &thisItemList,
+ layers.mLayers[i].mBlendMode,
+ scrollClip, i + 1));
+ }
+ aLists.BorderBackground()->AppendToTop(&thisItemList);
}
if (needBlendContainer) {
aLists.BorderBackground()->AppendNewToTop(
- new (aBuilder) nsDisplayBlendContainer(aBuilder, this, aLists.BorderBackground()));
+ new (aBuilder) nsDisplayBlendContainer(aBuilder, this, aLists.BorderBackground(),
+ scrollClip));
}
}
for (nsIFrame* kid : PrincipalChildList()) {
// Put our child into its own pseudo-stack.
BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aLists);
}