diff --git a/layout/painting/FrameLayerBuilder.cpp b/layout/painting/FrameLayerBuilder.cpp index b511c918d099..a263ee5713b1 100644 --- a/layout/painting/FrameLayerBuilder.cpp +++ b/layout/painting/FrameLayerBuilder.cpp @@ -55,7 +55,6 @@ #include #include -#include using namespace mozilla::layers; using namespace mozilla::gfx; @@ -119,99 +118,6 @@ static inline MaskLayerImageCache* GetMaskLayerImageCache() return gMaskLayerImageCache; } -struct DisplayItemEntry { - DisplayItemEntry(nsDisplayItem* aItem, - DisplayItemEntryType aType) - : mItem(aItem) - , mType(aType) - {} - - nsDisplayItem* mItem; - DisplayItemEntryType mType; -}; - -class FLBDisplayItemIterator : protected FlattenedDisplayItemIterator -{ -public: - FLBDisplayItemIterator(nsDisplayListBuilder* aBuilder, - nsDisplayList* aList, - ContainerState* aState) - : FlattenedDisplayItemIterator(aBuilder, aList, false) - , mState(aState) - { - MOZ_ASSERT(mState); - ResolveFlattening(); - } - - DisplayItemEntry GetNextEntry() - { - if (!mMarkers.empty()) { - DisplayItemEntry entry = mMarkers.front(); - mMarkers.pop_front(); - return entry; - } - - nsDisplayItem* next = GetNext(); - return DisplayItemEntry { next, DisplayItemEntryType::ITEM }; - } - - nsDisplayItem* GetNext() - { - // This function is only supposed to be called if there are no markers set. - // Breaking this invariant can potentially break effect flattening and/or - // display item merging. - MOZ_ASSERT(mMarkers.empty()); - - return FlattenedDisplayItemIterator::GetNext(); - } - - bool HasNext() const - { - return FlattenedDisplayItemIterator::HasNext() || !mMarkers.empty(); - } - - nsDisplayItem* PeekNext() - { - return mNext; - } - -private: - bool ShouldFlattenNextItem() const override; - - void StartNested(nsDisplayItem* aItem) override - { - if (aItem->GetType() == DisplayItemType::TYPE_OPACITY) { - nsDisplayOpacity* opacity = static_cast (aItem); - - if (opacity->OpacityAppliedToChildren()) { - // If the opacity was already applied to children, there is no need to - // emit opacity markers. - return; - } - - mMarkers.emplace_back(aItem, DisplayItemEntryType::PUSH_OPACITY); - mActiveMarkers.AppendElement(aItem); - } - } - - void EndNested(nsDisplayItem* aItem) override - { - if (mActiveMarkers.IsEmpty() || mActiveMarkers.LastElement() != aItem) { - // Do not emit an end marker if this item did not emit a start marker. - return; - } - - if (aItem->GetType() == DisplayItemType::TYPE_OPACITY) { - mMarkers.emplace_back(aItem, DisplayItemEntryType::POP_OPACITY); - mActiveMarkers.RemoveLastElement(); - } - } - - std::list mMarkers; - AutoTArray mActiveMarkers; - ContainerState* mState; -}; - DisplayItemData::DisplayItemData(LayerManagerData* aParent, uint32_t aKey, Layer* aLayer, nsIFrame* aFrame) @@ -575,8 +481,7 @@ public: const nsIntRect& aVisibleRect, const DisplayItemClip& aClip, LayerState aLayerState, - nsDisplayList *aList, - DisplayItemEntryType aType); + nsDisplayList *aList); AnimatedGeometryRoot* GetAnimatedGeometryRoot() { return mAnimatedGeometryRoot; } /** @@ -772,11 +677,7 @@ public: * These items get added by Accumulate(). */ nsTArray mAssignedDisplayItems; - /** - * Tracks the active opacity markers by holding the indices to PUSH_OPACITY - * items in |mAssignedDisplayItems|. - */ - nsTArray mOpacityIndices; + }; struct NewLayerEntry { @@ -1312,7 +1213,6 @@ public: protected: friend class PaintedLayerData; - friend class FLBDisplayItemIterator; LayerManager::PaintedLayerCreationHint GetLayerCreationHint(AnimatedGeometryRoot* aAnimatedGeometryRoot); @@ -1576,43 +1476,6 @@ protected: nsRect mLastDisplayPortRect; }; -bool -FLBDisplayItemIterator::ShouldFlattenNextItem() const -{ - if (!mNext) { - return false; - } - - if (!mNext->ShouldFlattenAway(mBuilder)) { - return false; - } - - if (mNext->GetType() == DisplayItemType::TYPE_OPACITY) { - nsDisplayOpacity* opacity = static_cast(mNext); - - if (opacity->OpacityAppliedToChildren()) { - // This is the previous opacity flattening path, where the opacity has - // been applied to children. - return true; - } - - if (!mState->mManager->IsWidgetLayerManager()) { - // Do not flatten opacity inside an inactive layer tree. - return false; - } - - LayerState layerState = mNext->GetLayerState(mState->mBuilder, - mState->mManager, - mState->mParameters); - - // Do not flatten opacity if child display items require an active layer. - return (layerState == LayerState::LAYER_NONE || - layerState == LayerState::LAYER_INACTIVE); - } - - return true; -} - class PaintedDisplayItemLayerUserData : public LayerUserData { public: @@ -1624,8 +1487,7 @@ public: mAnimatedGeometryRootPosition(0, 0), mLastItemCount(0), mContainerLayerFrame(nullptr), - mHasExplicitLastPaintOffset(false) - {} + mHasExplicitLastPaintOffset(false) {} NS_INLINE_DECL_REFCOUNTING(PaintedDisplayItemLayerUserData); @@ -2736,13 +2598,6 @@ ContainerState::FindOpaqueBackgroundColorInLayer(const PaintedLayerData* aData, appUnitRect.ScaleInverseRoundOut(mParameters.mXScale, mParameters.mYScale); for (auto& assignedItem : Reversed(aData->mAssignedDisplayItems)) { - if (assignedItem.mType != DisplayItemEntryType::ITEM || - assignedItem.mHasOpacity) { - // |assignedItem| is either an effect marker, or within a flatten opacity - // group. In both cases, there is no opaque area. - continue; - } - nsDisplayItem* item = assignedItem.mItem; bool snap; nsRect bounds = item->GetBounds(mBuilder, &snap); @@ -3312,8 +3167,6 @@ void ContainerState::FinishPaintedLayerData(PaintedLayerData& aData, FindOpaqueB { PaintedLayerData* data = &aData; - MOZ_ASSERT(data->mOpacityIndices.IsEmpty()); - if (!data->mLayer) { // No layer was recycled, so we create a new one. RefPtr paintedLayer = CreatePaintedLayer(data); @@ -3382,11 +3235,6 @@ void ContainerState::FinishPaintedLayerData(PaintedLayerData& aData, FindOpaqueB MOZ_ASSERT(item.mItem->GetType() != DisplayItemType::TYPE_LAYER_EVENT_REGIONS); MOZ_ASSERT(item.mItem->GetType() != DisplayItemType::TYPE_COMPOSITOR_HITTEST_INFO); - if (item.mType == DisplayItemEntryType::POP_OPACITY) { - // Do not invalidate for end markers. - continue; - } - InvalidateForLayerChange(item.mItem, data->mLayer, item.mDisplayItemData); mLayerBuilder->AddPaintedDisplayItem(data, item, *this, layer); item.mDisplayItemData = nullptr; @@ -3594,68 +3442,32 @@ IsItemAreaInWindowOpaqueRegion(nsDisplayListBuilder* aBuilder, void PaintedLayerData::Accumulate(ContainerState* aState, - nsDisplayItem* aItem, - const nsIntRect& aVisibleRect, - const DisplayItemClip& aClip, - LayerState aLayerState, - nsDisplayList* aList, - DisplayItemEntryType aType) + nsDisplayItem* aItem, + const nsIntRect& aVisibleRect, + const DisplayItemClip& aClip, + LayerState aLayerState, + nsDisplayList* aList) { FLB_LOG_PAINTED_LAYER_DECISION(this, "Accumulating dp=%s(%p), f=%p against pld=%p\n", aItem->Name(), aItem, aItem->Frame(), this); - const bool hasOpacity = mOpacityIndices.Length() > 0; - - if (aType == DisplayItemEntryType::POP_OPACITY) { - MOZ_ASSERT(!mOpacityIndices.IsEmpty()); - mOpacityIndices.RemoveLastElement(); - - AssignedDisplayItem item(aItem, aClip, aLayerState, - nullptr, aType, hasOpacity); - mAssignedDisplayItems.AppendElement(Move(item)); - return; - } - if (aState->mBuilder->NeedToForceTransparentSurfaceForItem(aItem)) { mForceTransparentSurface = true; } - - nsRect componentAlphaBounds; if (aState->mParameters.mDisableSubpixelAntialiasingInDescendants) { // Disable component alpha. - // Note that the transform (if any) on the PaintedLayer is always an integer - // translation so we don't have to factor that in here. + // Note that the transform (if any) on the PaintedLayer is always an integer translation so + // we don't have to factor that in here. aItem->DisableComponentAlpha(); - } else { - componentAlphaBounds = aItem->GetComponentAlphaBounds(aState->mBuilder); - - if (!componentAlphaBounds.IsEmpty()) { - // This display item needs background copy when pushing opacity group. - for (size_t i : mOpacityIndices) { - AssignedDisplayItem& item = mAssignedDisplayItems[i]; - MOZ_ASSERT(item.mType == DisplayItemEntryType::PUSH_OPACITY || - item.mType == DisplayItemEntryType::PUSH_OPACITY_WITH_BG); - item.mType = DisplayItemEntryType::PUSH_OPACITY_WITH_BG; - } - } } bool clipMatches = mItemClip == aClip; mItemClip = aClip; - DisplayItemData* currentData = - aItem->HasMergedFrames() ? nullptr : aItem->GetDisplayItemData(); - DisplayItemData* oldData = - aState->mLayerBuilder->GetOldLayerForFrame(aItem->Frame(), - aItem->GetPerFrameKey(), - currentData); - AssignedDisplayItem item(aItem, aClip, aLayerState, - oldData, aType, hasOpacity); - mAssignedDisplayItems.AppendElement(Move(item)); - - if (aType == DisplayItemEntryType::PUSH_OPACITY) { - mOpacityIndices.AppendElement(mAssignedDisplayItems.Length() - 1); - } + aState->mLayerBuilder->GetOldLayerForFrame(aItem->Frame(), + aItem->GetPerFrameKey(), + aItem->HasMergedFrames() ? nullptr : aItem->GetDisplayItemData()); + mAssignedDisplayItems.AppendElement(AssignedDisplayItem(aItem, aClip, aLayerState, oldData)); if (aItem->MustPaintOnContentSide()) { mShouldPaintOnContentSide = true; @@ -3674,15 +3486,10 @@ PaintedLayerData::Accumulate(ContainerState* aState, return; } - nsIntRegion opaquePixels; - - // Active opacity means no opaque pixels. - if (!hasOpacity) { - opaquePixels = aState->ComputeOpaqueRect(aItem, mAnimatedGeometryRoot, mASR, - aClip, aList, &mHideAllLayersBelow, - &mOpaqueForAnimatedGeometryRootParent); - opaquePixels.AndWith(aVisibleRect); - } + nsIntRegion opaquePixels = aState->ComputeOpaqueRect(aItem, + mAnimatedGeometryRoot, mASR, aClip, aList, + &mHideAllLayersBelow, &mOpaqueForAnimatedGeometryRootParent); + opaquePixels.AndWith(aVisibleRect); /* Mark as available for conversion to image layer if this is a nsDisplayImage and * it's the only thing visible in this layer. @@ -3699,10 +3506,7 @@ PaintedLayerData::Accumulate(ContainerState* aState, bool isFirstVisibleItem = mVisibleRegion.IsEmpty(); - Maybe uniformColor; - if (!hasOpacity) { - uniformColor = aItem->IsUniform(aState->mBuilder); - } + Maybe uniformColor = aItem->IsUniform(aState->mBuilder); // Some display items have to exist (so they can set forceTransparentSurface // below) but don't draw anything. They'll return true for isUniform but @@ -3760,17 +3564,18 @@ PaintedLayerData::Accumulate(ContainerState* aState, } } - if (!aState->mParameters.mDisableSubpixelAntialiasingInDescendants && - !componentAlphaBounds.IsEmpty()) { - nsIntRect componentAlphaRect = - aState->ScaleToOutsidePixels(componentAlphaBounds, false).Intersect(aVisibleRect); - - if (!mOpaqueRegion.Contains(componentAlphaRect)) { - if (IsItemAreaInWindowOpaqueRegion(aState->mBuilder, aItem, - componentAlphaBounds.Intersect(aItem->GetVisibleRect()))) { - mNeedComponentAlpha = true; - } else { - aItem->DisableComponentAlpha(); + if (!aState->mParameters.mDisableSubpixelAntialiasingInDescendants) { + nsRect componentAlpha = aItem->GetComponentAlphaBounds(aState->mBuilder); + if (!componentAlpha.IsEmpty()) { + nsIntRect componentAlphaRect = + aState->ScaleToOutsidePixels(componentAlpha, false).Intersect(aVisibleRect); + if (!mOpaqueRegion.Contains(componentAlphaRect)) { + if (IsItemAreaInWindowOpaqueRegion(aState->mBuilder, aItem, + componentAlpha.Intersect(aItem->GetVisibleRect()))) { + mNeedComponentAlpha = true; + } else { + aItem->DisableComponentAlpha(); + } } } } @@ -3780,7 +3585,8 @@ PaintedLayerData::Accumulate(ContainerState* aState, // not support subpixel positioning of text that animated transforms can // generate. bug 633097 if (aState->mParameters.mInActiveTransformedSubtree && - (mNeedComponentAlpha || !componentAlphaBounds.IsEmpty())) { + (mNeedComponentAlpha || + !aItem->GetComponentAlphaBounds(aState->mBuilder).IsEmpty())) { mDisableFlattening = true; } } @@ -4277,20 +4083,11 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList) AnimatedGeometryRoot* lastAnimatedGeometryRoot = nullptr; nsPoint lastTopLeft; - - // Tracks the PaintedLayerData that the item will be accumulated in, if it is - // non-null. Currently only used with PUSH_OPACITY and POP_OPACITY markers. - PaintedLayerData* selectedPLD = nullptr; - - FLBDisplayItemIterator iter(mBuilder, aList, this); - while (iter.HasNext()) { - DisplayItemEntry e = iter.GetNextEntry(); - nsDisplayItem* i = e.mItem; - DisplayItemEntryType marker = e.mType; - - + FlattenedDisplayItemIterator iter(mBuilder, aList); + while (nsDisplayItem* i = iter.GetNext()) { nsDisplayItem* item = i; MOZ_ASSERT(item); + DisplayItemType itemType = item->GetType(); // If the item is a event regions item, but is empty (has no regions in it) @@ -4322,23 +4119,20 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList) // Only allow either LayerEventRegions or CompositorHitTestInfo items. MOZ_ASSERT(!(hadLayerEventRegions && hadCompositorHitTestInfo)); + // Peek ahead to the next item and see if it can be merged with the current // item. We create a list of consecutive items that can be merged together. AutoTArray mergedItems; - - if (marker == DisplayItemEntryType::ITEM) { - mergedItems.AppendElement(item); - - while (nsDisplayItem* peek = iter.PeekNext()) { - if (!item->CanMerge(peek)) { - break; - } - - mergedItems.AppendElement(peek); - - // Move the iterator forward since we will merge this item. - i = iter.GetNext(); + mergedItems.AppendElement(item); + while (nsDisplayItem* peek = iter.PeekNext()) { + if (!item->CanMerge(peek)) { + break; } + + mergedItems.AppendElement(peek); + + // Move the iterator forward since we will merge this item. + i = iter.GetNext(); } if (mergedItems.Length() > 1) { @@ -4364,14 +4158,10 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList) continue; } - LayerState layerState = LAYER_NONE; - - if (marker == DisplayItemEntryType::ITEM) { - layerState = item->GetLayerState(mBuilder, mManager, mParameters); - - if (layerState == LAYER_INACTIVE && nsDisplayItem::ForceActiveLayers()) { - layerState = LAYER_ACTIVE; - } + LayerState layerState = item->GetLayerState(mBuilder, mManager, mParameters); + if (layerState == LAYER_INACTIVE && + nsDisplayItem::ForceActiveLayers()) { + layerState = LAYER_ACTIVE; } bool forceInactive = false; @@ -4474,11 +4264,6 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList) layerCount++; - // Currently we do not support flattening effects within nested inactive - // layer trees. - MOZ_ASSERT(selectedPLD == nullptr); - MOZ_ASSERT(marker == DisplayItemEntryType::ITEM); - // LAYER_ACTIVE_EMPTY means the layer is created just for its metadata. // We should never see an empty layer with any visible content! NS_ASSERTION(layerState != LAYER_ACTIVE_EMPTY || @@ -4798,21 +4583,14 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList) const bool backfaceHidden = item->In3DContextAndBackfaceIsHidden(); const nsIFrame* referenceFrame = item->ReferenceFrame(); - PaintedLayerData* paintedLayerData = selectedPLD; - - if (!selectedPLD) { - MOZ_ASSERT(marker != DisplayItemEntryType::POP_OPACITY); - - paintedLayerData = - mPaintedLayerDataTree.FindPaintedLayerFor(animatedGeometryRoot, itemASR, layerClipChain, - itemVisibleRect, backfaceHidden, - [&](PaintedLayerData* aData) { - NewPaintedLayerData(aData, animatedGeometryRoot, itemASR, - layerClipChain, scrollMetadataASR, topLeft, - referenceFrame, backfaceHidden); + PaintedLayerData* paintedLayerData = + mPaintedLayerDataTree.FindPaintedLayerFor(animatedGeometryRoot, itemASR, layerClipChain, + itemVisibleRect, backfaceHidden, + [&](PaintedLayerData* aData) { + NewPaintedLayerData(aData, animatedGeometryRoot, itemASR, + layerClipChain, scrollMetadataASR, topLeft, + referenceFrame, backfaceHidden); }); - } - MOZ_ASSERT(paintedLayerData); if (itemType == DisplayItemType::TYPE_LAYER_EVENT_REGIONS) { nsDisplayLayerEventRegions* eventRegions = @@ -4823,8 +4601,7 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList) static_cast(item); paintedLayerData->AccumulateHitTestInfo(this, hitTestInfo); } else { - paintedLayerData->Accumulate(this, item, itemVisibleRect, itemClip, - layerState, aList, marker); + paintedLayerData->Accumulate(this, item, itemVisibleRect, itemClip, layerState, aList); if (!paintedLayerData->mLayer) { // Try to recycle the old layer of this display item. @@ -4843,18 +4620,6 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList) } } } - - if (marker == DisplayItemEntryType::PUSH_OPACITY) { - selectedPLD = paintedLayerData; - } - - if (marker == DisplayItemEntryType::POP_OPACITY ) { - MOZ_ASSERT(selectedPLD); - - if (selectedPLD->mOpacityIndices.IsEmpty()) { - selectedPLD = nullptr; - } - } } nsDisplayList* childItems = item->GetSameCoordinateSystemChildren(); @@ -4862,8 +4627,6 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList) aList->SetNeedsTransparentSurface(); } } - - MOZ_ASSERT(selectedPLD == nullptr); } void @@ -5196,17 +4959,13 @@ FrameLayerBuilder::StoreDataForFrame(nsIFrame* aFrame, AssignedDisplayItem::AssignedDisplayItem(nsDisplayItem* aItem, const DisplayItemClip& aClip, LayerState aLayerState, - DisplayItemData* aData, - DisplayItemEntryType aType, - const bool aHasOpacity) + DisplayItemData* aData) : mItem(aItem) , mClip(aClip) , mLayerState(aLayerState) , mDisplayItemData(aData) , mReused(aItem->IsReused()) , mMerged(aItem->HasMergedFrames()) - , mType(aType) - , mHasOpacity(aHasOpacity) {} AssignedDisplayItem::~AssignedDisplayItem() @@ -6147,16 +5906,6 @@ FrameLayerBuilder::RecomputeVisibilityForItems(nsTArray& aI if (!cdi->mItem) { continue; } - - if (cdi->mType == DisplayItemEntryType::POP_OPACITY || - (cdi->mType == DisplayItemEntryType::ITEM && cdi->mHasOpacity)) { - // The visibility calculations are skipped when the item is an effect end - // marker, or when the display item is within a flattened opacity group. - // This is because RecomputeVisibility has already been called for the - // group item, and all the children. - continue; - } - const DisplayItemClip& clip = cdi->mItem->GetClip(); NS_ASSERTION(AppUnitsPerDevPixel(cdi->mItem) == aAppUnitsPerDevPixel, @@ -6191,70 +5940,6 @@ FrameLayerBuilder::RecomputeVisibilityForItems(nsTArray& aI } } -/** - * Sets the clip chain and starts a new opacity group. - */ -static void -PushOpacity(gfxContext* aContext, - const nsRect& aPaintRect, - AssignedDisplayItem& aItem, - const int32_t aAUPDP) -{ - MOZ_ASSERT(aItem.mType == DisplayItemEntryType::PUSH_OPACITY || - aItem.mType == DisplayItemEntryType::PUSH_OPACITY_WITH_BG); - MOZ_ASSERT(aItem.mItem->GetType() == DisplayItemType::TYPE_OPACITY); - - aContext->Save(); - - DisplayItemClip clip; - clip.SetTo(aPaintRect); - clip.IntersectWith(aItem.mItem->GetClip()); - clip.ApplyTo(aContext, aAUPDP); - - nsDisplayOpacity* opacityItem = static_cast(aItem.mItem); - const float opacity = opacityItem->GetOpacity(); - - if (aItem.mType == DisplayItemEntryType::PUSH_OPACITY_WITH_BG) { - aContext->PushGroupAndCopyBackground(gfxContentType::COLOR_ALPHA, opacity); - } else { - aContext->PushGroupForBlendBack(gfxContentType::COLOR_ALPHA, opacity); - } -} - -/** - * Tracks item clips per opacity nesting level. - */ -struct ClipTracker { - explicit ClipTracker(gfxContext* aContext) - : mContext(aContext) - {} - - bool HasClip(int aOpacityNesting) const - { - return !mClips.IsEmpty() && - mClips.LastElement() == aOpacityNesting; - } - - void PopClipIfNeeded(int aOpacityNesting) - { - if (!HasClip(aOpacityNesting)) { - return; - } - - mContext->Restore(); - mClips.RemoveLastElement(); - }; - - void SaveClip(int aOpacityNesting) - { - mContext->Save(); - mClips.AppendElement(aOpacityNesting); - }; - - AutoTArray mClips; - gfxContext* mContext; -}; - void FrameLayerBuilder::PaintItems(nsTArray& aItems, const nsIntRect& aRect, @@ -6272,102 +5957,73 @@ FrameLayerBuilder::PaintItems(nsTArray& aItems, NSIntPixelsToAppUnits(aOffset.y, appUnitsPerDevPixel)); boundRect.ScaleInverseRoundOut(aXScale, aYScale); - DisplayItemClip currentClip, tmpClip; - - int opacityNesting = 0; - ClipTracker clipTracker(aContext); + DisplayItemClip currentClip; + bool currentClipIsSetInContext = false; + DisplayItemClip tmpClip; for (uint32_t i = 0; i < aItems.Length(); ++i) { - AssignedDisplayItem& cdi = aItems[i]; - nsDisplayItem* item = cdi.mItem; - - if (!item) { - MOZ_ASSERT(cdi.mType == DisplayItemEntryType::ITEM); + AssignedDisplayItem* cdi = &aItems[i]; + if (!cdi->mItem) { continue; } - const nsRect& visibleRect = item->GetVisibleRect(); - - nsRect paintRect = visibleRect.Intersect(boundRect); - if (paintRect.IsEmpty()) { + nsRect paintRect = cdi->mItem->GetVisibleRect().Intersect(boundRect); + if (paintRect.IsEmpty()) continue; - } #ifdef MOZ_DUMP_PAINTING AUTO_PROFILER_LABEL_DYNAMIC_CSTR("FrameLayerBuilder::PaintItems", GRAPHICS, - item->Name()); + cdi->mItem->Name()); #else AUTO_PROFILER_LABEL("FrameLayerBuilder::PaintItems", GRAPHICS); #endif - MOZ_ASSERT((opacityNesting == 0 && !cdi.mHasOpacity) || - (opacityNesting > 0 && cdi.mHasOpacity)); - - if (cdi.mType == DisplayItemEntryType::PUSH_OPACITY || - cdi.mType == DisplayItemEntryType::PUSH_OPACITY_WITH_BG) { - clipTracker.PopClipIfNeeded(opacityNesting); - PushOpacity(aContext, paintRect, cdi, appUnitsPerDevPixel); - opacityNesting++; - } - - if (cdi.mType == DisplayItemEntryType::POP_OPACITY) { - MOZ_ASSERT(item->GetType() == DisplayItemType::TYPE_OPACITY); - MOZ_ASSERT(opacityNesting > 0); - - clipTracker.PopClipIfNeeded(opacityNesting); - aContext->PopGroupAndBlend(); - aContext->Restore(); - opacityNesting--; - } - - if (cdi.mType != DisplayItemEntryType::ITEM) { - continue; - } - // If the new desired clip state is different from the current state, // update the clip. - const DisplayItemClip* clip = &item->GetClip(); + const DisplayItemClip* clip = &cdi->mItem->GetClip(); if (clip->GetRoundedRectCount() > 0 && - !clip->IsRectClippedByRoundedCorner(visibleRect)) { + !clip->IsRectClippedByRoundedCorner(cdi->mItem->GetVisibleRect())) { tmpClip = *clip; tmpClip.RemoveRoundedCorners(); clip = &tmpClip; } - if (clipTracker.HasClip(opacityNesting) != clip->HasClip() || + if (currentClipIsSetInContext != clip->HasClip() || (clip->HasClip() && *clip != currentClip)) { - clipTracker.PopClipIfNeeded(opacityNesting); - - if (clip->HasClip()) { + if (currentClipIsSetInContext) { + aContext->Restore(); + } + currentClipIsSetInContext = clip->HasClip(); + if (currentClipIsSetInContext) { currentClip = *clip; - clipTracker.SaveClip(opacityNesting); - currentClip.ApplyTo(aContext, appUnitsPerDevPixel); + aContext->Save(); + currentClip.ApplyTo(aContext, aPresContext->AppUnitsPerDevPixel()); aContext->NewPath(); } } - if (cdi.mInactiveLayerManager) { + if (cdi->mInactiveLayerManager) { bool saved = aDrawTarget.GetPermitSubpixelAA(); - PaintInactiveLayer(aBuilder, cdi.mInactiveLayerManager, - item, aContext, aContext); + PaintInactiveLayer(aBuilder, cdi->mInactiveLayerManager, cdi->mItem, aContext, aContext); aDrawTarget.SetPermitSubpixelAA(saved); } else { - nsIFrame* frame = item->Frame(); + nsIFrame* frame = cdi->mItem->Frame(); if (aBuilder->IsPaintingToWindow()) { frame->AddStateBits(NS_FRAME_PAINTED_THEBES); } #ifdef MOZ_DUMP_PAINTING if (gfxEnv::DumpPaintItems()) { - DebugPaintItem(aDrawTarget, aPresContext, item, aBuilder); + DebugPaintItem(aDrawTarget, aPresContext, cdi->mItem, aBuilder); } else #endif { - item->Paint(aBuilder, aContext); + cdi->mItem->Paint(aBuilder, aContext); } } } - clipTracker.PopClipIfNeeded(opacityNesting); - MOZ_ASSERT(opacityNesting == 0); + if (currentClipIsSetInContext) { + aContext->Restore(); + } } /** diff --git a/layout/painting/FrameLayerBuilder.h b/layout/painting/FrameLayerBuilder.h index ce0b078a1208..1d5300fca7c0 100644 --- a/layout/painting/FrameLayerBuilder.h +++ b/layout/painting/FrameLayerBuilder.h @@ -45,13 +45,6 @@ class PaintedLayerData; class ContainerState; class PaintedDisplayItemLayerUserData; -enum class DisplayItemEntryType { - ITEM, - PUSH_OPACITY, - PUSH_OPACITY_WITH_BG, - POP_OPACITY -}; - /** * Retained data storage: * @@ -222,9 +215,7 @@ struct AssignedDisplayItem AssignedDisplayItem(nsDisplayItem* aItem, const DisplayItemClip& aClip, LayerState aLayerState, - DisplayItemData* aData, - DisplayItemEntryType aType, - const bool aHasOpacity); + DisplayItemData* aData); ~AssignedDisplayItem(); nsDisplayItem* mItem; @@ -241,9 +232,6 @@ struct AssignedDisplayItem bool mReused; bool mMerged; - - DisplayItemEntryType mType; - bool mHasOpacity; }; diff --git a/layout/painting/nsDisplayList.cpp b/layout/painting/nsDisplayList.cpp index 9d22c69cd22b..ec8bfba2dd33 100644 --- a/layout/painting/nsDisplayList.cpp +++ b/layout/painting/nsDisplayList.cpp @@ -6409,7 +6409,6 @@ nsDisplayOpacity::nsDisplayOpacity(nsDisplayListBuilder* aBuilder, : nsDisplayWrapList(aBuilder, aFrame, aList, aActiveScrolledRoot, true) , mOpacity(aFrame->StyleEffects()->mOpacity) , mForEventsAndPluginsOnly(aForEventsAndPluginsOnly) - , mOpacityAppliedToChildren(false) { MOZ_COUNT_CTOR(nsDisplayOpacity); mState.mOpacity = mOpacity; @@ -6545,8 +6544,27 @@ CollectItemsWithOpacity(nsDisplayList* aList, } bool -nsDisplayOpacity::ApplyOpacityToChildren(nsDisplayListBuilder* aBuilder) +nsDisplayOpacity::ShouldFlattenAway(nsDisplayListBuilder* aBuilder) { + if (mFrame->GetPrevContinuation() || + mFrame->GetNextContinuation()) { + // If we've been split, then we might need to merge, so + // don't flatten us away. + return false; + } + + if (NeedsActiveLayer(aBuilder, mFrame) || mOpacity == 0.0) { + // If our opacity is zero then we'll discard all descendant display items + // except for layer event regions, so there's no point in doing this + // optimization (and if we do do it, then invalidations of those descendants + // might trigger repainting). + return false; + } + + if (mList.IsEmpty()) { + return false; + } + // Only try folding our opacity down if we have at most kMaxChildCount // children that don't overlap and can all apply the opacity to themselves. static const size_t kMaxChildCount = 3; @@ -6583,41 +6601,9 @@ nsDisplayOpacity::ApplyOpacityToChildren(nsDisplayListBuilder* aBuilder) children[i].item->ApplyOpacity(aBuilder, mOpacity, mClipChain); } - mOpacityAppliedToChildren = true; return true; } -bool -nsDisplayOpacity::ShouldFlattenAway(nsDisplayListBuilder* aBuilder) -{ - // ShouldFlattenAway() should be called only once during painting. - MOZ_ASSERT(!mOpacityAppliedToChildren); - - if (mFrame->GetPrevContinuation() || - mFrame->GetNextContinuation()) { - // If we've been split, then we might need to merge, so - // don't flatten us away. - return false; - } - - if (NeedsActiveLayer(aBuilder, mFrame) || mOpacity == 0.0) { - // If our opacity is zero then we'll discard all descendant display items - // except for layer event regions, so there's no point in doing this - // optimization (and if we do do it, then invalidations of those descendants - // might trigger repainting). - return false; - } - - if (mList.IsEmpty()) { - return false; - } - - // Return true if we successfully applied opacity to child items, or if - // WebRender is not in use. In the latter case, the opacity gets flattened and - // applied during layer building. - return ApplyOpacityToChildren(aBuilder) || !gfxVars::UseWebRender(); -} - nsDisplayItem::LayerState nsDisplayOpacity::GetLayerState(nsDisplayListBuilder* aBuilder, LayerManager* aManager, @@ -6654,20 +6640,6 @@ nsDisplayOpacity::ComputeVisibility(nsDisplayListBuilder* aBuilder, nsDisplayWrapList::ComputeVisibility(aBuilder, &visibleUnderChildren); } -void -nsDisplayOpacity::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, - const nsDisplayItemGeometry* aGeometry, - nsRegion* aInvalidRegion) const -{ - const nsDisplayOpacityGeometry* geometry = - static_cast(aGeometry); - - bool snap; - if (mOpacity != geometry->mOpacity) { - aInvalidRegion->Or(GetBounds(aBuilder, &snap), geometry->mBounds); - } -} - void nsDisplayOpacity::WriteDebugInfo(std::stringstream& aStream) { diff --git a/layout/painting/nsDisplayList.h b/layout/painting/nsDisplayList.h index bf42fd81192f..88f6959ac747 100644 --- a/layout/painting/nsDisplayList.h +++ b/layout/painting/nsDisplayList.h @@ -3203,92 +3203,6 @@ private: bool mForceTransparentSurface; }; -class FlattenedDisplayItemIterator -{ -public: - FlattenedDisplayItemIterator(nsDisplayListBuilder* aBuilder, - nsDisplayList* aList, - const bool aResolveFlattening = true) - : mBuilder(aBuilder) - , mNext(aList->GetBottom()) - { - if (aResolveFlattening) { - // This is done conditionally in case subclass overrides - // ShouldFlattenNextItem(). - ResolveFlattening(); - } - } - - virtual ~FlattenedDisplayItemIterator() - { - MOZ_ASSERT(!HasNext()); - } - - nsDisplayItem* GetNext() - { - nsDisplayItem* next = mNext; - - // Advance mNext to the following item - if (next) { - mNext = mNext->GetAbove(); - ResolveFlattening(); - } - return next; - } - - bool HasNext() const - { - return mNext || !mStack.IsEmpty(); - } - - nsDisplayItem* PeekNext() - { - return mNext; - } - -protected: - bool AtEndOfNestedList() const - { - return !mNext && mStack.Length() > 0; - } - - virtual bool ShouldFlattenNextItem() const - { - return mNext && mNext->ShouldFlattenAway(mBuilder); - } - - void ResolveFlattening() - { - // Handle the case where we reach the end of a nested list, or the current - // item should start a new nested list. Repeat this until we find an actual - // item, or the very end of the outer list. - while (AtEndOfNestedList() || ShouldFlattenNextItem()) { - if (AtEndOfNestedList()) { - // Pop the last item off the stack. - mNext = mStack.LastElement(); - EndNested(mNext); - mStack.RemoveElementAt(mStack.Length() - 1); - // We stored the item that was flattened, so advance to the next. - mNext = mNext->GetAbove(); - } else { - // This item wants to be flattened. Store the current item on the stack, - // and use the first item in the child list instead. - mStack.AppendElement(mNext); - StartNested(mNext); - nsDisplayList* childItems = mNext->GetSameCoordinateSystemChildren(); - mNext = childItems->GetBottom(); - } - } - } - - virtual void EndNested(nsDisplayItem* aItem) {} - virtual void StartNested(nsDisplayItem* aItem) {} - - nsDisplayListBuilder* mBuilder; - nsDisplayItem* mNext; - AutoTArray mStack; -}; - /** * This is passed as a parameter to nsIFrame::BuildDisplayList. That method * will put any generated items onto the appropriate list given here. It's @@ -5246,18 +5160,12 @@ public: nsDisplayList* aList, const ActiveScrolledRoot* aActiveScrolledRoot, bool aForEventsAndPluginsOnly); - nsDisplayOpacity(nsDisplayListBuilder* aBuilder, const nsDisplayOpacity& aOther) : nsDisplayWrapList(aBuilder, aOther) , mOpacity(aOther.mOpacity) , mForEventsAndPluginsOnly(aOther.mForEventsAndPluginsOnly) - , mOpacityAppliedToChildren(false) - { - // We should not try to merge flattened opacities. - MOZ_ASSERT(!aOther.mOpacityAppliedToChildren); - } - + {} #ifdef NS_BUILD_REFCNT_LOGGING virtual ~nsDisplayOpacity(); #endif @@ -5266,7 +5174,6 @@ public: { nsDisplayItem::RestoreState(); mOpacity = mState.mOpacity; - mOpacityAppliedToChildren = false; } virtual nsDisplayWrapList* Clone(nsDisplayListBuilder* aBuilder) const override @@ -5294,15 +5201,12 @@ public: return HasSameTypeAndClip(aItem) && HasSameContent(aItem); } - virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) override - { - return new nsDisplayOpacityGeometry(this, aBuilder, mOpacity); - } - virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, const nsDisplayItemGeometry* aGeometry, - nsRegion* aInvalidRegion) const override; - + nsRegion* aInvalidRegion) const override + { + // We don't need to compute an invalidation region since we have LayerTreeInvalidation + } virtual bool IsInvalid(nsRect& aRect) const override { if (mForEventsAndPluginsOnly) { @@ -5315,12 +5219,6 @@ public: const DisplayItemClipChain* aClip) override; virtual bool CanApplyOpacity() const override; virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override; - - /** - * Returns true if ShouldFlattenAway() applied opacity to children. - */ - bool OpacityAppliedToChildren() const { return mOpacityAppliedToChildren; } - static bool NeedsActiveLayer(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame); NS_DISPLAY_DECL_NAME("Opacity", TYPE_OPACITY) virtual void WriteDebugInfo(std::stringstream& aStream) override; @@ -5336,11 +5234,8 @@ public: float GetOpacity() { return mOpacity; } private: - bool ApplyOpacityToChildren(nsDisplayListBuilder* aBuilder); - float mOpacity; bool mForEventsAndPluginsOnly; - bool mOpacityAppliedToChildren; struct { float mOpacity; @@ -6876,6 +6771,72 @@ public: mutable mozilla::Maybe mIsFrameSelected; }; +class FlattenedDisplayItemIterator +{ +public: + FlattenedDisplayItemIterator(nsDisplayListBuilder* aBuilder, + nsDisplayList* aList) + : mBuilder(aBuilder) + , mNext(aList->GetBottom()) + { + ResolveFlattening(); + } + + nsDisplayItem* GetNext() + { + nsDisplayItem* next = mNext; + + // Advance mNext to the following item + if (next) { + mNext = mNext->GetAbove(); + ResolveFlattening(); + } + return next; + } + + nsDisplayItem* PeekNext() + { + return mNext; + } + +private: + bool AtEndOfNestedList() + { + return !mNext && mStack.Length() > 0; + } + + bool ShouldFlattenNextItem() + { + return mNext && mNext->ShouldFlattenAway(mBuilder); + } + + void ResolveFlattening() + { + // Handle the case where we reach the end of a nested list, or the current + // item should start a new nested list. Repeat this until we find an actual + // item, or the very end of the outer list. + while (AtEndOfNestedList() || ShouldFlattenNextItem()) { + if (AtEndOfNestedList()) { + // Pop the last item off the stack. + mNext = mStack.PopLastElement(); + // We stored the item that was flattened, so advance to the next. + mNext = mNext->GetAbove(); + } else { + // This item wants to be flattened. Store the current item on the stack, + // and use the first item in the child list instead. + mStack.AppendElement(mNext); + nsDisplayList* childItems = mNext->GetSameCoordinateSystemChildren(); + mNext = childItems->GetBottom(); + } + } + } + + + nsDisplayListBuilder* mBuilder; + nsDisplayItem* mNext; + AutoTArray mStack; +}; + /** * A display item that for webrender to handle SVG */ diff --git a/layout/painting/nsDisplayListInvalidation.h b/layout/painting/nsDisplayListInvalidation.h index b57a3cd36a47..ca41c33a702c 100644 --- a/layout/painting/nsDisplayListInvalidation.h +++ b/layout/painting/nsDisplayListInvalidation.h @@ -353,17 +353,4 @@ public: nsPoint mFrameOffsetToViewport; }; -class nsDisplayOpacityGeometry : public nsDisplayItemGenericGeometry -{ -public: - nsDisplayOpacityGeometry(nsDisplayItem* aItem, - nsDisplayListBuilder* aBuilder, - float aOpacity) - : nsDisplayItemGenericGeometry(aItem, aBuilder) - , mOpacity(aOpacity) - {} - - float mOpacity; -}; - #endif /*NSDISPLAYLISTINVALIDATION_H_*/ diff --git a/layout/reftests/bugs/reftest.list b/layout/reftests/bugs/reftest.list index d334b7ceee45..15f6609b2e51 100644 --- a/layout/reftests/bugs/reftest.list +++ b/layout/reftests/bugs/reftest.list @@ -1682,7 +1682,7 @@ HTTP == 652991-3.html 652991-3-ref.html HTTP == 652991-4.html 652991-4-ref.html fuzzy-if(skiaContent,1,5) == 653930-1.html 653930-1-ref.html == 654057-1.html 654057-1-ref.html -fuzzy-if(skiaContent,1,65536) == 654950-1.html 654950-1-ref.html # Quartz alpha blending doesn't match GL alpha blending +fuzzy-if(skiaContent,1,4500) == 654950-1.html 654950-1-ref.html # Quartz alpha blending doesn't match GL alpha blending == 655549-1.html 655549-1-ref.html == 655836-1.html 655836-1-ref.html != 656875.html about:blank diff --git a/layout/reftests/css-grid/reftest.list b/layout/reftests/css-grid/reftest.list index f34a3d58c319..ce1874644e80 100644 --- a/layout/reftests/css-grid/reftest.list +++ b/layout/reftests/css-grid/reftest.list @@ -16,7 +16,7 @@ fails == grid-whitespace-handling-1b.xhtml grid-whitespace-handling-1-ref.xhtml == grid-track-sizing-001.html grid-track-sizing-001-ref.html == grid-track-sizing-002.html grid-track-sizing-002-ref.html == grid-abspos-items-001.html grid-abspos-items-001-ref.html -fuzzy(180,3) == grid-abspos-items-002.html grid-abspos-items-002-ref.html # flattening differences +== grid-abspos-items-002.html grid-abspos-items-002-ref.html == grid-abspos-items-003.html grid-abspos-items-003-ref.html == grid-abspos-items-004.html grid-abspos-items-004-ref.html == grid-abspos-items-005.html grid-abspos-items-005-ref.html diff --git a/layout/reftests/text-overflow/reftest.list b/layout/reftests/text-overflow/reftest.list index f1c1f322b620..6deb8bb9fb5a 100644 --- a/layout/reftests/text-overflow/reftest.list +++ b/layout/reftests/text-overflow/reftest.list @@ -5,7 +5,7 @@ fuzzy-if(Android,16,244) == marker-basic.html marker-basic-ref.html # Bug 11282 skip-if(Android) == bidi-simple.html bidi-simple-ref.html # Fails on Android due to anti-aliasing skip-if(!gtkWidget) fuzzy-if(gtkWidget,2,289) == bidi-simple-scrolled.html bidi-simple-scrolled-ref.html # Fails on Windows and OSX due to anti-aliasing fuzzy-if(Android,24,4000) fuzzy-if(cocoaWidget,1,40) fuzzy-if(asyncPan&&!layersGPUAccelerated,149,1836) == scroll-rounding.html scroll-rounding-ref.html # bug 760264 -fuzzy(2,453) fuzzy-if(skiaContent,16,435) fails-if(gtkWidget) fuzzy-if(webrender&&winWidget,50-50,499-499) == anonymous-block.html anonymous-block-ref.html # gtkWidget:bug 1309103, skia: subpixel aa +fuzzy(2,453) fuzzy-if(skiaContent,9,2100) fails-if(gtkWidget) fuzzy-if(webrender&&winWidget,50-50,499-499) == anonymous-block.html anonymous-block-ref.html # gtkWidget:bug 1309103 == false-marker-overlap.html false-marker-overlap-ref.html == visibility-hidden.html visibility-hidden-ref.html fuzzy-if(asyncPan&&!layersGPUAccelerated,102,1724) fuzzy-if(gtkWidget,10,8) == block-padding.html block-padding-ref.html