зеркало из https://github.com/mozilla/gecko-dev.git
Bug 902525 - Part 3: create a layer for content that stores the blend mode r=roc
This commit is contained in:
Родитель
0383e51844
Коммит
fc566afdce
|
@ -30,6 +30,7 @@ DECLARE_DISPLAY_ITEM_TYPE(FRAMESET_BLANK)
|
|||
DECLARE_DISPLAY_ITEM_TYPE(HEADER_FOOTER)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(IMAGE)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(LIST_FOCUS)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(MIX_BLEND_MODE)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(OPACITY)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(OPTION_EVENT_GRABBER)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(OUTLINE)
|
||||
|
|
|
@ -3119,6 +3119,98 @@ bool nsDisplayOpacity::TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* a
|
|||
return true;
|
||||
}
|
||||
|
||||
nsDisplayMixBlendMode::nsDisplayMixBlendMode(nsDisplayListBuilder* aBuilder,
|
||||
nsIFrame* aFrame, nsDisplayList* aList,
|
||||
uint32_t aFlags)
|
||||
: nsDisplayWrapList(aBuilder, aFrame, aList) {
|
||||
MOZ_COUNT_CTOR(nsDisplayMixBlendMode);
|
||||
}
|
||||
|
||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||
nsDisplayMixBlendMode::~nsDisplayMixBlendMode() {
|
||||
MOZ_COUNT_DTOR(nsDisplayMixBlendMode);
|
||||
}
|
||||
#endif
|
||||
|
||||
nsRegion nsDisplayMixBlendMode::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
|
||||
bool* aSnap) {
|
||||
*aSnap = false;
|
||||
// We are never considered opaque
|
||||
return nsRegion();
|
||||
}
|
||||
|
||||
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;
|
||||
default: MOZ_ASSERT(false); return gfxContext::OPERATOR_OVER;
|
||||
}
|
||||
|
||||
return gfxContext::OPERATOR_OVER;
|
||||
}
|
||||
|
||||
// nsDisplayMixBlendMode uses layers for rendering
|
||||
already_AddRefed<Layer>
|
||||
nsDisplayMixBlendMode::BuildLayer(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager,
|
||||
const ContainerParameters& aContainerParameters) {
|
||||
nsRefPtr<Layer> container = aManager->GetLayerBuilder()->
|
||||
BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList,
|
||||
aContainerParameters, nullptr);
|
||||
if (!container) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
container->SetMixBlendMode(GetGFXBlendMode(mFrame->StyleDisplay()->mMixBlendMode));
|
||||
|
||||
return container.forget();
|
||||
}
|
||||
|
||||
bool nsDisplayMixBlendMode::ComputeVisibility(nsDisplayListBuilder* aBuilder,
|
||||
nsRegion* aVisibleRegion,
|
||||
const nsRect& aAllowVisibleRegionExpansion) {
|
||||
// Our children are need their backdrop so we should not allow them to subtract
|
||||
// area from aVisibleRegion. We do need to find out what is visible under
|
||||
// our children in the temporary compositing buffer, because if our children
|
||||
// paint our entire bounds opaquely then we don't need an alpha channel in
|
||||
// the temporary compositing buffer.
|
||||
nsRect bounds = GetClippedBounds(aBuilder);
|
||||
nsRegion visibleUnderChildren;
|
||||
visibleUnderChildren.And(*aVisibleRegion, bounds);
|
||||
nsRect allowExpansion = bounds.Intersect(aAllowVisibleRegionExpansion);
|
||||
return
|
||||
nsDisplayWrapList::ComputeVisibility(aBuilder, &visibleUnderChildren,
|
||||
allowExpansion);
|
||||
}
|
||||
|
||||
bool nsDisplayMixBlendMode::TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem) {
|
||||
if (aItem->GetType() != TYPE_MIX_BLEND_MODE)
|
||||
return false;
|
||||
// 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())
|
||||
return false;
|
||||
if (aItem->GetClip() != GetClip())
|
||||
return false;
|
||||
MergeFromTrackingMergedFrames(static_cast<nsDisplayMixBlendMode*>(aItem));
|
||||
return true;
|
||||
}
|
||||
|
||||
nsDisplayBlendContainer::nsDisplayBlendContainer(nsDisplayListBuilder* aBuilder,
|
||||
nsIFrame* aFrame, nsDisplayList* aList,
|
||||
uint32_t aFlags)
|
||||
|
|
|
@ -2507,6 +2507,38 @@ public:
|
|||
bool CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE;
|
||||
};
|
||||
|
||||
class nsDisplayMixBlendMode : public nsDisplayWrapList {
|
||||
public:
|
||||
nsDisplayMixBlendMode(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
|
||||
nsDisplayList* aList, uint32_t aFlags = 0);
|
||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||
virtual ~nsDisplayMixBlendMode();
|
||||
#endif
|
||||
|
||||
nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder, bool* aSnap);
|
||||
|
||||
virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager,
|
||||
const ContainerParameters& aContainerParameters) MOZ_OVERRIDE;
|
||||
virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
|
||||
const nsDisplayItemGeometry* aGeometry,
|
||||
nsRegion* aInvalidRegion) MOZ_OVERRIDE
|
||||
{
|
||||
// We don't need to compute an invalidation region since we have LayerTreeInvalidation
|
||||
}
|
||||
virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager,
|
||||
const ContainerParameters& aParameters) MOZ_OVERRIDE
|
||||
{
|
||||
return mozilla::LAYER_INACTIVE;
|
||||
}
|
||||
virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
|
||||
nsRegion* aVisibleRegion,
|
||||
const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE;
|
||||
virtual bool TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem) MOZ_OVERRIDE;
|
||||
NS_DISPLAY_DECL_NAME("MixBlendMode", TYPE_MIX_BLEND_MODE)
|
||||
};
|
||||
|
||||
class nsDisplayBlendContainer : public nsDisplayWrapList {
|
||||
public:
|
||||
nsDisplayBlendContainer(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
|
||||
|
|
|
@ -1997,6 +1997,16 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
|
|||
new (aBuilder) nsDisplayTransform(aBuilder, this, &resultList));
|
||||
}
|
||||
}
|
||||
|
||||
/* If there's blending, wrap up the list in a blend-mode item. Note
|
||||
* that opacity can be applied before blending as the blend color is
|
||||
* not affected by foreground opacity (only background alpha).
|
||||
*/
|
||||
|
||||
if (useBlendMode && !resultList.IsEmpty()) {
|
||||
resultList.AppendNewToTop(
|
||||
new (aBuilder) nsDisplayMixBlendMode(aBuilder, this, &resultList));
|
||||
}
|
||||
|
||||
if (aBuilder->ContainsBlendMode()) {
|
||||
resultList.AppendNewToTop(
|
||||
|
|
|
@ -342,7 +342,7 @@ nsSVGImageFrame::PaintSVG(nsRenderingContext *aContext,
|
|||
opacity = StyleDisplay()->mOpacity;
|
||||
}
|
||||
|
||||
if (opacity != 1.0f) {
|
||||
if (opacity != 1.0f || StyleDisplay()->mMixBlendMode != NS_STYLE_BLEND_NORMAL) {
|
||||
ctx->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
|
||||
}
|
||||
|
||||
|
@ -396,7 +396,7 @@ nsSVGImageFrame::PaintSVG(nsRenderingContext *aContext,
|
|||
drawFlags);
|
||||
}
|
||||
|
||||
if (opacity != 1.0f) {
|
||||
if (opacity != 1.0f || StyleDisplay()->mMixBlendMode != NS_STYLE_BLEND_NORMAL) {
|
||||
ctx->PopGroupToSource();
|
||||
ctx->SetOperator(gfxContext::OPERATOR_OVER);
|
||||
ctx->Paint(opacity);
|
||||
|
|
|
@ -494,7 +494,8 @@ nsSVGIntegrationUtils::PaintFramesWithEffects(nsRenderingContext* aCtx,
|
|||
bool complexEffects = false;
|
||||
/* Check if we need to do additional operations on this child's
|
||||
* rendering, which necessitates rendering into another surface. */
|
||||
if (opacity != 1.0f || maskFrame || (clipPathFrame && !isTrivialClip)) {
|
||||
if (opacity != 1.0f || maskFrame || (clipPathFrame && !isTrivialClip)
|
||||
|| aFrame->StyleDisplay()->mMixBlendMode != NS_STYLE_BLEND_NORMAL) {
|
||||
complexEffects = true;
|
||||
gfx->Save();
|
||||
aCtx->IntersectClip(aFrame->GetVisualOverflowRectRelativeToSelf() +
|
||||
|
|
|
@ -846,7 +846,8 @@ nsSVGUtils::PaintFrameWithEffects(nsRenderingContext *aContext,
|
|||
|
||||
/* Check if we need to do additional operations on this child's
|
||||
* rendering, which necessitates rendering into another surface. */
|
||||
if (opacity != 1.0f || maskFrame || (clipPathFrame && !isTrivialClip)) {
|
||||
if (opacity != 1.0f || maskFrame || (clipPathFrame && !isTrivialClip)
|
||||
|| aFrame->StyleDisplay()->mMixBlendMode != NS_STYLE_BLEND_NORMAL) {
|
||||
complexEffects = true;
|
||||
gfx->Save();
|
||||
if (!(aFrame->GetStateBits() & NS_FRAME_IS_NONDISPLAY)) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче