зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1442190 - Part 5: Use FLBDisplayItemIterator and flatten inactive nsDisplayOpacity in more cases r=mattwoodrow
MozReview-Commit-ID: 9I8YvMDEFHy --HG-- extra : rebase_source : 558bc22776028658a0071344e79b8b107bf09783
This commit is contained in:
Родитель
92bc4e6aff
Коммит
88ed321351
|
@ -575,7 +575,8 @@ public:
|
|||
const nsIntRect& aVisibleRect,
|
||||
const DisplayItemClip& aClip,
|
||||
LayerState aLayerState,
|
||||
nsDisplayList *aList);
|
||||
nsDisplayList *aList,
|
||||
DisplayItemEntryType aType);
|
||||
AnimatedGeometryRoot* GetAnimatedGeometryRoot() { return mAnimatedGeometryRoot; }
|
||||
|
||||
/**
|
||||
|
@ -771,7 +772,11 @@ public:
|
|||
* These items get added by Accumulate().
|
||||
*/
|
||||
nsTArray<AssignedDisplayItem> mAssignedDisplayItems;
|
||||
|
||||
/**
|
||||
* Tracks the active opacity markers by holding the indices to PUSH_OPACITY
|
||||
* items in |mAssignedDisplayItems|.
|
||||
*/
|
||||
nsTArray<size_t> mOpacityIndices;
|
||||
};
|
||||
|
||||
struct NewLayerEntry {
|
||||
|
@ -1619,7 +1624,8 @@ public:
|
|||
mAnimatedGeometryRootPosition(0, 0),
|
||||
mLastItemCount(0),
|
||||
mContainerLayerFrame(nullptr),
|
||||
mHasExplicitLastPaintOffset(false) {}
|
||||
mHasExplicitLastPaintOffset(false)
|
||||
{}
|
||||
|
||||
NS_INLINE_DECL_REFCOUNTING(PaintedDisplayItemLayerUserData);
|
||||
|
||||
|
@ -2730,6 +2736,13 @@ 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);
|
||||
|
@ -3299,6 +3312,8 @@ 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> paintedLayer = CreatePaintedLayer(data);
|
||||
|
@ -3367,6 +3382,11 @@ 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;
|
||||
|
@ -3574,32 +3594,68 @@ IsItemAreaInWindowOpaqueRegion(nsDisplayListBuilder* aBuilder,
|
|||
|
||||
void
|
||||
PaintedLayerData::Accumulate(ContainerState* aState,
|
||||
nsDisplayItem* aItem,
|
||||
const nsIntRect& aVisibleRect,
|
||||
const DisplayItemClip& aClip,
|
||||
LayerState aLayerState,
|
||||
nsDisplayList* aList)
|
||||
nsDisplayItem* aItem,
|
||||
const nsIntRect& aVisibleRect,
|
||||
const DisplayItemClip& aClip,
|
||||
LayerState aLayerState,
|
||||
nsDisplayList* aList,
|
||||
DisplayItemEntryType aType)
|
||||
{
|
||||
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(),
|
||||
aItem->HasMergedFrames() ? nullptr : aItem->GetDisplayItemData());
|
||||
mAssignedDisplayItems.AppendElement(AssignedDisplayItem(aItem, aClip, aLayerState, 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);
|
||||
}
|
||||
|
||||
if (aItem->MustPaintOnContentSide()) {
|
||||
mShouldPaintOnContentSide = true;
|
||||
|
@ -3618,10 +3674,15 @@ PaintedLayerData::Accumulate(ContainerState* aState,
|
|||
return;
|
||||
}
|
||||
|
||||
nsIntRegion opaquePixels = aState->ComputeOpaqueRect(aItem,
|
||||
mAnimatedGeometryRoot, mASR, aClip, aList,
|
||||
&mHideAllLayersBelow, &mOpaqueForAnimatedGeometryRootParent);
|
||||
opaquePixels.AndWith(aVisibleRect);
|
||||
nsIntRegion opaquePixels;
|
||||
|
||||
// Active opacity means no opaque pixels.
|
||||
if (!hasOpacity) {
|
||||
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.
|
||||
|
@ -3638,7 +3699,10 @@ PaintedLayerData::Accumulate(ContainerState* aState,
|
|||
|
||||
bool isFirstVisibleItem = mVisibleRegion.IsEmpty();
|
||||
|
||||
Maybe<nscolor> uniformColor = aItem->IsUniform(aState->mBuilder);
|
||||
Maybe<nscolor> uniformColor;
|
||||
if (!hasOpacity) {
|
||||
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
|
||||
|
@ -3696,18 +3760,17 @@ PaintedLayerData::Accumulate(ContainerState* aState,
|
|||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3717,8 +3780,7 @@ PaintedLayerData::Accumulate(ContainerState* aState,
|
|||
// not support subpixel positioning of text that animated transforms can
|
||||
// generate. bug 633097
|
||||
if (aState->mParameters.mInActiveTransformedSubtree &&
|
||||
(mNeedComponentAlpha ||
|
||||
!aItem->GetComponentAlphaBounds(aState->mBuilder).IsEmpty())) {
|
||||
(mNeedComponentAlpha || !componentAlphaBounds.IsEmpty())) {
|
||||
mDisableFlattening = true;
|
||||
}
|
||||
}
|
||||
|
@ -4215,11 +4277,20 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList)
|
|||
|
||||
AnimatedGeometryRoot* lastAnimatedGeometryRoot = nullptr;
|
||||
nsPoint lastTopLeft;
|
||||
FlattenedDisplayItemIterator iter(mBuilder, aList);
|
||||
while (nsDisplayItem* i = iter.GetNext()) {
|
||||
|
||||
// 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;
|
||||
|
||||
|
||||
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)
|
||||
|
@ -4251,20 +4322,23 @@ 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<nsDisplayItem*, 1> mergedItems;
|
||||
mergedItems.AppendElement(item);
|
||||
while (nsDisplayItem* peek = iter.PeekNext()) {
|
||||
if (!item->CanMerge(peek)) {
|
||||
break;
|
||||
|
||||
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(peek);
|
||||
|
||||
// Move the iterator forward since we will merge this item.
|
||||
i = iter.GetNext();
|
||||
}
|
||||
|
||||
if (mergedItems.Length() > 1) {
|
||||
|
@ -4290,10 +4364,14 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList)
|
|||
continue;
|
||||
}
|
||||
|
||||
LayerState layerState = item->GetLayerState(mBuilder, mManager, mParameters);
|
||||
if (layerState == LAYER_INACTIVE &&
|
||||
nsDisplayItem::ForceActiveLayers()) {
|
||||
layerState = LAYER_ACTIVE;
|
||||
LayerState layerState = LAYER_NONE;
|
||||
|
||||
if (marker == DisplayItemEntryType::ITEM) {
|
||||
layerState = item->GetLayerState(mBuilder, mManager, mParameters);
|
||||
|
||||
if (layerState == LAYER_INACTIVE && nsDisplayItem::ForceActiveLayers()) {
|
||||
layerState = LAYER_ACTIVE;
|
||||
}
|
||||
}
|
||||
|
||||
bool forceInactive = false;
|
||||
|
@ -4396,6 +4474,11 @@ 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 ||
|
||||
|
@ -4715,14 +4798,21 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList)
|
|||
const bool backfaceHidden = item->In3DContextAndBackfaceIsHidden();
|
||||
const nsIFrame* referenceFrame = item->ReferenceFrame();
|
||||
|
||||
PaintedLayerData* paintedLayerData =
|
||||
mPaintedLayerDataTree.FindPaintedLayerFor(animatedGeometryRoot, itemASR, layerClipChain,
|
||||
itemVisibleRect, backfaceHidden,
|
||||
[&](PaintedLayerData* aData) {
|
||||
NewPaintedLayerData(aData, animatedGeometryRoot, itemASR,
|
||||
layerClipChain, scrollMetadataASR, topLeft,
|
||||
referenceFrame, backfaceHidden);
|
||||
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);
|
||||
});
|
||||
}
|
||||
MOZ_ASSERT(paintedLayerData);
|
||||
|
||||
if (itemType == DisplayItemType::TYPE_LAYER_EVENT_REGIONS) {
|
||||
nsDisplayLayerEventRegions* eventRegions =
|
||||
|
@ -4733,7 +4823,8 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList)
|
|||
static_cast<nsDisplayCompositorHitTestInfo*>(item);
|
||||
paintedLayerData->AccumulateHitTestInfo(this, hitTestInfo);
|
||||
} else {
|
||||
paintedLayerData->Accumulate(this, item, itemVisibleRect, itemClip, layerState, aList);
|
||||
paintedLayerData->Accumulate(this, item, itemVisibleRect, itemClip,
|
||||
layerState, aList, marker);
|
||||
|
||||
if (!paintedLayerData->mLayer) {
|
||||
// Try to recycle the old layer of this display item.
|
||||
|
@ -4752,6 +4843,18 @@ 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();
|
||||
|
@ -4759,6 +4862,8 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList)
|
|||
aList->SetNeedsTransparentSurface();
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(selectedPLD == nullptr);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -5091,13 +5196,17 @@ FrameLayerBuilder::StoreDataForFrame(nsIFrame* aFrame,
|
|||
AssignedDisplayItem::AssignedDisplayItem(nsDisplayItem* aItem,
|
||||
const DisplayItemClip& aClip,
|
||||
LayerState aLayerState,
|
||||
DisplayItemData* aData)
|
||||
DisplayItemData* aData,
|
||||
DisplayItemEntryType aType,
|
||||
const bool aHasOpacity)
|
||||
: mItem(aItem)
|
||||
, mClip(aClip)
|
||||
, mLayerState(aLayerState)
|
||||
, mDisplayItemData(aData)
|
||||
, mReused(aItem->IsReused())
|
||||
, mMerged(aItem->HasMergedFrames())
|
||||
, mType(aType)
|
||||
, mHasOpacity(aHasOpacity)
|
||||
{}
|
||||
|
||||
AssignedDisplayItem::~AssignedDisplayItem()
|
||||
|
@ -6038,6 +6147,16 @@ FrameLayerBuilder::RecomputeVisibilityForItems(nsTArray<AssignedDisplayItem>& 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,
|
||||
|
@ -6072,6 +6191,70 @@ FrameLayerBuilder::RecomputeVisibilityForItems(nsTArray<AssignedDisplayItem>& 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<nsDisplayOpacity*>(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<int, 2> mClips;
|
||||
gfxContext* mContext;
|
||||
};
|
||||
|
||||
void
|
||||
FrameLayerBuilder::PaintItems(nsTArray<AssignedDisplayItem>& aItems,
|
||||
const nsIntRect& aRect,
|
||||
|
@ -6089,73 +6272,102 @@ FrameLayerBuilder::PaintItems(nsTArray<AssignedDisplayItem>& aItems,
|
|||
NSIntPixelsToAppUnits(aOffset.y, appUnitsPerDevPixel));
|
||||
boundRect.ScaleInverseRoundOut(aXScale, aYScale);
|
||||
|
||||
DisplayItemClip currentClip;
|
||||
bool currentClipIsSetInContext = false;
|
||||
DisplayItemClip tmpClip;
|
||||
DisplayItemClip currentClip, tmpClip;
|
||||
|
||||
int opacityNesting = 0;
|
||||
ClipTracker clipTracker(aContext);
|
||||
|
||||
for (uint32_t i = 0; i < aItems.Length(); ++i) {
|
||||
AssignedDisplayItem* cdi = &aItems[i];
|
||||
if (!cdi->mItem) {
|
||||
AssignedDisplayItem& cdi = aItems[i];
|
||||
nsDisplayItem* item = cdi.mItem;
|
||||
|
||||
if (!item) {
|
||||
MOZ_ASSERT(cdi.mType == DisplayItemEntryType::ITEM);
|
||||
continue;
|
||||
}
|
||||
|
||||
nsRect paintRect = cdi->mItem->GetVisibleRect().Intersect(boundRect);
|
||||
if (paintRect.IsEmpty())
|
||||
const nsRect& visibleRect = item->GetVisibleRect();
|
||||
|
||||
nsRect paintRect = visibleRect.Intersect(boundRect);
|
||||
if (paintRect.IsEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef MOZ_DUMP_PAINTING
|
||||
AUTO_PROFILER_LABEL_DYNAMIC_CSTR("FrameLayerBuilder::PaintItems", GRAPHICS,
|
||||
cdi->mItem->Name());
|
||||
item->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 = &cdi->mItem->GetClip();
|
||||
const DisplayItemClip* clip = &item->GetClip();
|
||||
if (clip->GetRoundedRectCount() > 0 &&
|
||||
!clip->IsRectClippedByRoundedCorner(cdi->mItem->GetVisibleRect())) {
|
||||
!clip->IsRectClippedByRoundedCorner(visibleRect)) {
|
||||
tmpClip = *clip;
|
||||
tmpClip.RemoveRoundedCorners();
|
||||
clip = &tmpClip;
|
||||
}
|
||||
if (currentClipIsSetInContext != clip->HasClip() ||
|
||||
if (clipTracker.HasClip(opacityNesting) != clip->HasClip() ||
|
||||
(clip->HasClip() && *clip != currentClip)) {
|
||||
if (currentClipIsSetInContext) {
|
||||
aContext->Restore();
|
||||
}
|
||||
currentClipIsSetInContext = clip->HasClip();
|
||||
if (currentClipIsSetInContext) {
|
||||
clipTracker.PopClipIfNeeded(opacityNesting);
|
||||
|
||||
if (clip->HasClip()) {
|
||||
currentClip = *clip;
|
||||
aContext->Save();
|
||||
currentClip.ApplyTo(aContext, aPresContext->AppUnitsPerDevPixel());
|
||||
clipTracker.SaveClip(opacityNesting);
|
||||
currentClip.ApplyTo(aContext, appUnitsPerDevPixel);
|
||||
aContext->NewPath();
|
||||
}
|
||||
}
|
||||
|
||||
if (cdi->mInactiveLayerManager) {
|
||||
if (cdi.mInactiveLayerManager) {
|
||||
bool saved = aDrawTarget.GetPermitSubpixelAA();
|
||||
PaintInactiveLayer(aBuilder, cdi->mInactiveLayerManager, cdi->mItem, aContext, aContext);
|
||||
PaintInactiveLayer(aBuilder, cdi.mInactiveLayerManager,
|
||||
item, aContext, aContext);
|
||||
aDrawTarget.SetPermitSubpixelAA(saved);
|
||||
} else {
|
||||
nsIFrame* frame = cdi->mItem->Frame();
|
||||
nsIFrame* frame = item->Frame();
|
||||
if (aBuilder->IsPaintingToWindow()) {
|
||||
frame->AddStateBits(NS_FRAME_PAINTED_THEBES);
|
||||
}
|
||||
#ifdef MOZ_DUMP_PAINTING
|
||||
if (gfxEnv::DumpPaintItems()) {
|
||||
DebugPaintItem(aDrawTarget, aPresContext, cdi->mItem, aBuilder);
|
||||
DebugPaintItem(aDrawTarget, aPresContext, item, aBuilder);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
cdi->mItem->Paint(aBuilder, aContext);
|
||||
item->Paint(aBuilder, aContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (currentClipIsSetInContext) {
|
||||
aContext->Restore();
|
||||
}
|
||||
clipTracker.PopClipIfNeeded(opacityNesting);
|
||||
MOZ_ASSERT(opacityNesting == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -48,6 +48,7 @@ class PaintedDisplayItemLayerUserData;
|
|||
enum class DisplayItemEntryType {
|
||||
ITEM,
|
||||
PUSH_OPACITY,
|
||||
PUSH_OPACITY_WITH_BG,
|
||||
POP_OPACITY
|
||||
};
|
||||
|
||||
|
@ -221,7 +222,9 @@ struct AssignedDisplayItem
|
|||
AssignedDisplayItem(nsDisplayItem* aItem,
|
||||
const DisplayItemClip& aClip,
|
||||
LayerState aLayerState,
|
||||
DisplayItemData* aData);
|
||||
DisplayItemData* aData,
|
||||
DisplayItemEntryType aType,
|
||||
const bool aHasOpacity);
|
||||
~AssignedDisplayItem();
|
||||
|
||||
nsDisplayItem* mItem;
|
||||
|
@ -238,6 +241,9 @@ struct AssignedDisplayItem
|
|||
|
||||
bool mReused;
|
||||
bool mMerged;
|
||||
|
||||
DisplayItemEntryType mType;
|
||||
bool mHasOpacity;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -6612,7 +6612,10 @@ nsDisplayOpacity::ShouldFlattenAway(nsDisplayListBuilder* aBuilder)
|
|||
return false;
|
||||
}
|
||||
|
||||
return ApplyOpacityToChildren(aBuilder);
|
||||
// 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
|
||||
|
|
Загрузка…
Ссылка в новой задаче