Bug 1132371. Allow opacity items that only contain one item that paints (and others that don't) to flatten away as well. r=mattwoodrow

The optimization that allows opacity items that only contain one item (which can fold the opacity into it's own drawing) to flatten away will never apply when we have layer event region items. This is because opacity generates a stacking context and we always push a new layer event regions item for a stacking context. So if we want to keep this optimization we need to extend to to at least two items. Layer event regions items have empty bounds, which allows the non-overlapping test to pass for layer event region items. Although it will work with any non-overlapping items.
This commit is contained in:
Timothy Nikkel 2015-02-19 19:04:09 -06:00
parent 19e6db2719
commit d5358ff2dc
5 changed files with 79 additions and 16 deletions

View File

@ -2960,15 +2960,21 @@ nsDisplayThemedBackground::GetBoundsInternal() {
return r + ToReferenceFrame();
}
bool
void
nsDisplayBackgroundColor::ApplyOpacity(nsDisplayListBuilder* aBuilder,
float aOpacity,
const DisplayItemClip* aClip)
{
NS_ASSERTION(CanApplyOpacity(), "ApplyOpacity should be allowed");
mColor.a = mColor.a * aOpacity;
if (aClip) {
IntersectClip(aBuilder, *aClip);
}
}
bool
nsDisplayBackgroundColor::CanApplyOpacity() const
{
return true;
}
@ -3822,15 +3828,21 @@ nsDisplayOpacity::NeedsActiveLayer(nsDisplayListBuilder* aBuilder)
return false;
}
bool
void
nsDisplayOpacity::ApplyOpacity(nsDisplayListBuilder* aBuilder,
float aOpacity,
const DisplayItemClip* aClip)
{
NS_ASSERTION(CanApplyOpacity(), "ApplyOpacity should be allowed");
mOpacity = mOpacity * aOpacity;
if (aClip) {
IntersectClip(aBuilder, *aClip);
}
}
bool
nsDisplayOpacity::CanApplyOpacity() const
{
return true;
}
@ -3841,14 +3853,41 @@ nsDisplayOpacity::ShouldFlattenAway(nsDisplayListBuilder* aBuilder)
return false;
nsDisplayItem* child = mList.GetBottom();
// Only try folding our opacity down if we have a single
// child. We could potentially do this also if we had multiple
// children as long as they don't overlap.
if (!child || child->GetAbove()) {
// Only try folding our opacity down if we have at most three children
// that don't overlap and can all apply the opacity to themselves.
if (!child) {
return false;
}
struct {
nsDisplayItem* item;
nsRect bounds;
} children[3];
bool snap;
uint32_t numChildren = 0;
for (; numChildren < ArrayLength(children) && child; numChildren++, child = child->GetAbove()) {
if (!child->CanApplyOpacity()) {
return false;
}
children[numChildren].item = child;
children[numChildren].bounds = child->GetBounds(aBuilder, &snap);
}
if (child) {
// we have a fourth (or more) child
return false;
}
return child->ApplyOpacity(aBuilder, mOpacity, mClip);
for (uint32_t i = 0; i < numChildren; i++) {
for (uint32_t j = i+1; j < numChildren; j++) {
if (children[i].bounds.Intersects(children[j].bounds)) {
return false;
}
}
}
for (uint32_t i = 0; i < numChildren; i++) {
children[i].item->ApplyOpacity(aBuilder, mOpacity, mClip);
}
return true;
}
nsDisplayItem::LayerState

View File

@ -1367,12 +1367,19 @@ public:
virtual const nsRect& GetVisibleRectForChildren() const { return mVisibleRect; }
/**
* Stores the given opacity value to be applied when drawing. Returns
* false if this isn't supported for this display item.
* Stores the given opacity value to be applied when drawing. It is an error to
* call this if CanApplyOpacity returned false.
*/
virtual bool ApplyOpacity(nsDisplayListBuilder* aBuilder,
virtual void ApplyOpacity(nsDisplayListBuilder* aBuilder,
float aOpacity,
const DisplayItemClip* aClip) {
NS_ASSERTION(CanApplyOpacity(), "ApplyOpacity not supported on this type");
}
/**
* Returns true if this display item would return true from ApplyOpacity without
* actually applying the opacity. Otherwise returns false.
*/
virtual bool CanApplyOpacity() const {
return false;
}
@ -2377,9 +2384,10 @@ public:
virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) MOZ_OVERRIDE;
virtual bool ApplyOpacity(nsDisplayListBuilder* aBuilder,
virtual void ApplyOpacity(nsDisplayListBuilder* aBuilder,
float aOpacity,
const DisplayItemClip* aClip) MOZ_OVERRIDE;
virtual bool CanApplyOpacity() const MOZ_OVERRIDE;
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE
{
@ -2486,14 +2494,18 @@ public:
const nsDisplayItemGeometry* aGeometry,
nsRegion* aInvalidRegion) MOZ_OVERRIDE;
virtual bool ApplyOpacity(nsDisplayListBuilder* aBuilder,
virtual void ApplyOpacity(nsDisplayListBuilder* aBuilder,
float aOpacity,
const DisplayItemClip* aClip) MOZ_OVERRIDE
{
NS_ASSERTION(CanApplyOpacity(), "ApplyOpacity should be allowed");
mOpacity = aOpacity;
if (aClip) {
IntersectClip(aBuilder, *aClip);
}
}
virtual bool CanApplyOpacity() const MOZ_OVERRIDE
{
return true;
}
@ -2636,6 +2648,17 @@ public:
return mHitRegion.GetBounds().Union(mMaybeHitRegion.GetBounds());
}
virtual void ApplyOpacity(nsDisplayListBuilder* aBuilder,
float aOpacity,
const DisplayItemClip* aClip) MOZ_OVERRIDE
{
NS_ASSERTION(CanApplyOpacity(), "ApplyOpacity should be allowed");
}
virtual bool CanApplyOpacity() const MOZ_OVERRIDE
{
return true;
}
NS_DISPLAY_DECL_NAME("LayerEventRegions", TYPE_LAYER_EVENT_REGIONS)
// Indicate that aFrame's border-box contributes to the event regions for
@ -2865,9 +2888,10 @@ public:
{
// We don't need to compute an invalidation region since we have LayerTreeInvalidation
}
virtual bool ApplyOpacity(nsDisplayListBuilder* aBuilder,
virtual void ApplyOpacity(nsDisplayListBuilder* aBuilder,
float aOpacity,
const DisplayItemClip* aClip) MOZ_OVERRIDE;
virtual bool CanApplyOpacity() const MOZ_OVERRIDE;
virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE;
bool NeedsActiveLayer(nsDisplayListBuilder* aBuilder);
NS_DISPLAY_DECL_NAME("Opacity", TYPE_OPACITY)

View File

@ -4,7 +4,7 @@
<style>
#image {
position:fixed;
opacity:0.5;
opacity:0.50196078431;
left:0;
top:0;
width:100%;

View File

@ -7,7 +7,7 @@
height:0;
}
#d2 {
opacity:0.5;
opacity:0.50196078431;
}
#d3 {
position:absolute;

View File

@ -7,7 +7,7 @@
height:0;
}
#d2 {
opacity:0.5;
opacity:0.50196078431;
}
#image {
position:fixed;