Bug 1500864 - Cull items within opacity:0 containers when merging with retained display lists. r=mstange

Differential Revision: https://phabricator.services.mozilla.com/D14304

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Matt Woodrow 2018-12-16 23:35:42 +00:00
Родитель f0ee7a9279
Коммит f278a7e08c
4 изменённых файлов: 74 добавлений и 16 удалений

Просмотреть файл

@ -13,6 +13,7 @@
#include "nsSubDocumentFrame.h" #include "nsSubDocumentFrame.h"
#include "nsViewManager.h" #include "nsViewManager.h"
#include "nsCanvasFrame.h" #include "nsCanvasFrame.h"
#include "mozilla/AutoRestore.h"
/** /**
* Code for doing display list building for a modified subset of the window, * Code for doing display list building for a modified subset of the window,
@ -317,8 +318,25 @@ class MergeState {
MOZ_RELEASE_ASSERT(mOldItems.Length() == mOldDAG.Length()); MOZ_RELEASE_ASSERT(mOldItems.Length() == mOldDAG.Length());
} }
MergedListIndex ProcessItemFromNewList( // Items within an opacity:0 container (excluding plugins and hit test info)
// aren't needed, so we can strip them out from both the old and new lists.
// Do this silently, so that these changes don't result in us reporting that
// the display list changed. Both FrameLayerBuilder and
// WebRenderCommandBuilder also do this removal, so it's functionally correct
// to report that the display list is identical.
bool ShouldSilentlyDiscardItem(nsDisplayItem* aItem) {
return aItem && mBuilder->mCurrentSubtreeIsForEventsAndPluginsOnly &&
(aItem->GetType() != DisplayItemType::TYPE_COMPOSITOR_HITTEST_INFO &&
aItem->GetType() != DisplayItemType::TYPE_PLUGIN);
}
Maybe<MergedListIndex> ProcessItemFromNewList(
nsDisplayItem* aNewItem, const Maybe<MergedListIndex>& aPreviousItem) { nsDisplayItem* aNewItem, const Maybe<MergedListIndex>& aPreviousItem) {
if (ShouldSilentlyDiscardItem(aNewItem)) {
aNewItem->Destroy(mBuilder->Builder());
return aPreviousItem;
}
OldListIndex oldIndex; OldListIndex oldIndex;
if (!HasModifiedFrame(aNewItem) && if (!HasModifiedFrame(aNewItem) &&
HasMatchingItemInOldList(aNewItem, &oldIndex)) { HasMatchingItemInOldList(aNewItem, &oldIndex)) {
@ -344,8 +362,7 @@ class MergeState {
Maybe<const ActiveScrolledRoot*> containerASRForChildren; Maybe<const ActiveScrolledRoot*> containerASRForChildren;
if (mBuilder->MergeDisplayLists( if (mBuilder->MergeDisplayLists(
aNewItem->GetChildren(), oldItem->GetChildren(), aNewItem->GetChildren(), oldItem->GetChildren(),
destItem->GetChildren(), containerASRForChildren, destItem->GetChildren(), containerASRForChildren, aNewItem)) {
aNewItem->GetPerFrameKey())) {
destItem->InvalidateCachedChildInfo(); destItem->InvalidateCachedChildInfo();
mResultIsModified = true; mResultIsModified = true;
} }
@ -363,12 +380,12 @@ class MergeState {
} else { } else {
aNewItem->Destroy(mBuilder->Builder()); aNewItem->Destroy(mBuilder->Builder());
} }
return newIndex; return Some(newIndex);
} }
} }
mResultIsModified = true; mResultIsModified = true;
return AddNewNode(aNewItem, Nothing(), Span<MergedListIndex>(), return Some(AddNewNode(aNewItem, Nothing(), Span<MergedListIndex>(),
aPreviousItem); aPreviousItem));
} }
bool ShouldUseNewItem(nsDisplayItem* aNewItem) { bool ShouldUseNewItem(nsDisplayItem* aNewItem) {
@ -505,16 +522,20 @@ class MergeState {
void ProcessOldNode(OldListIndex aNode, void ProcessOldNode(OldListIndex aNode,
nsTArray<MergedListIndex>&& aDirectPredecessors) { nsTArray<MergedListIndex>&& aDirectPredecessors) {
nsDisplayItem* item = mOldItems[aNode.val].mItem; nsDisplayItem* item = mOldItems[aNode.val].mItem;
if (mOldItems[aNode.val].IsChanged() || HasModifiedFrame(item)) { if (ShouldSilentlyDiscardItem(item)) {
// If the item should be discarded, then just silently drop it and
// don't mark the display list as being modified.
mOldItems[aNode.val].Discard(mBuilder, std::move(aDirectPredecessors));
} else if (mOldItems[aNode.val].IsChanged() || HasModifiedFrame(item)) {
mOldItems[aNode.val].Discard(mBuilder, std::move(aDirectPredecessors)); mOldItems[aNode.val].Discard(mBuilder, std::move(aDirectPredecessors));
mResultIsModified = true; mResultIsModified = true;
} else { } else {
if (item->GetChildren()) { if (item->GetChildren()) {
Maybe<const ActiveScrolledRoot*> containerASRForChildren; Maybe<const ActiveScrolledRoot*> containerASRForChildren;
nsDisplayList empty; nsDisplayList empty;
if (mBuilder->MergeDisplayLists( if (mBuilder->MergeDisplayLists(&empty, item->GetChildren(),
&empty, item->GetChildren(), item->GetChildren(), item->GetChildren(),
containerASRForChildren, item->GetPerFrameKey())) { containerASRForChildren, item)) {
item->InvalidateCachedChildInfo(); item->InvalidateCachedChildInfo();
mResultIsModified = true; mResultIsModified = true;
} }
@ -630,13 +651,20 @@ bool RetainedDisplayListBuilder::MergeDisplayLists(
nsDisplayList* aNewList, RetainedDisplayList* aOldList, nsDisplayList* aNewList, RetainedDisplayList* aOldList,
RetainedDisplayList* aOutList, RetainedDisplayList* aOutList,
mozilla::Maybe<const mozilla::ActiveScrolledRoot*>& aOutContainerASR, mozilla::Maybe<const mozilla::ActiveScrolledRoot*>& aOutContainerASR,
uint32_t aOuterKey) { nsDisplayItem* aOuterItem) {
MergeState merge(this, *aOldList, aOuterKey); MergeState merge(this, *aOldList,
aOuterItem ? aOuterItem->GetPerFrameKey() : 0);
AutoRestore<bool> restoreForEventAndPluginsOnly(
mCurrentSubtreeIsForEventsAndPluginsOnly);
if (aOuterItem && aOuterItem->GetType() == DisplayItemType::TYPE_OPACITY &&
static_cast<nsDisplayOpacity*>(aOuterItem)->ForEventsAndPluginsOnly()) {
mCurrentSubtreeIsForEventsAndPluginsOnly = true;
}
Maybe<MergedListIndex> previousItemIndex; Maybe<MergedListIndex> previousItemIndex;
while (nsDisplayItem* item = aNewList->RemoveBottom()) { while (nsDisplayItem* item = aNewList->RemoveBottom()) {
previousItemIndex = previousItemIndex = merge.ProcessItemFromNewList(item, previousItemIndex);
Some(merge.ProcessItemFromNewList(item, previousItemIndex));
} }
*aOutList = merge.Finalize(); *aOutList = merge.Finalize();

Просмотреть файл

@ -95,7 +95,8 @@ RetainedDisplayListData* GetOrSetRetainedDisplayListData(nsIFrame* aRootFrame);
struct RetainedDisplayListBuilder { struct RetainedDisplayListBuilder {
RetainedDisplayListBuilder(nsIFrame* aReferenceFrame, RetainedDisplayListBuilder(nsIFrame* aReferenceFrame,
nsDisplayListBuilderMode aMode, bool aBuildCaret) nsDisplayListBuilderMode aMode, bool aBuildCaret)
: mBuilder(aReferenceFrame, aMode, aBuildCaret, true) {} : mBuilder(aReferenceFrame, aMode, aBuildCaret, true),
mCurrentSubtreeIsForEventsAndPluginsOnly(false) {}
~RetainedDisplayListBuilder() { mList.DeleteAll(&mBuilder); } ~RetainedDisplayListBuilder() { mList.DeleteAll(&mBuilder); }
nsDisplayListBuilder* Builder() { return &mBuilder; } nsDisplayListBuilder* Builder() { return &mBuilder; }
@ -122,11 +123,20 @@ struct RetainedDisplayListBuilder {
AnimatedGeometryRoot* aAGR, AnimatedGeometryRoot* aAGR,
uint32_t aCallerKey = 0, uint32_t aCallerKey = 0,
uint32_t aNestingDepth = 0); uint32_t aNestingDepth = 0);
/**
* Merges items from aNewList into non-invalidated items from aOldList and
* stores the result in aOutList.
*
* aOuterItem is a pointer to an item that owns one of the lists, if
* available. If both lists are populated, then both outer items must not be
* invalidated, and identical, so either can be passed here.
*/
bool MergeDisplayLists( bool MergeDisplayLists(
nsDisplayList* aNewList, RetainedDisplayList* aOldList, nsDisplayList* aNewList, RetainedDisplayList* aOldList,
RetainedDisplayList* aOutList, RetainedDisplayList* aOutList,
mozilla::Maybe<const mozilla::ActiveScrolledRoot*>& aOutContainerASR, mozilla::Maybe<const mozilla::ActiveScrolledRoot*>& aOutContainerASR,
uint32_t aOuterKey = 0); nsDisplayItem* aOuterItem = nullptr);
bool ComputeRebuildRegion(nsTArray<nsIFrame*>& aModifiedFrames, bool ComputeRebuildRegion(nsTArray<nsIFrame*>& aModifiedFrames,
nsRect* aOutDirty, nsRect* aOutDirty,
@ -145,6 +155,10 @@ struct RetainedDisplayListBuilder {
nsDisplayListBuilder mBuilder; nsDisplayListBuilder mBuilder;
RetainedDisplayList mList; RetainedDisplayList mList;
WeakFrame mPreviousCaret; WeakFrame mPreviousCaret;
// True if we're currently within an opacity:0 container, and only
// plugin and hit test items should be considered.
bool mCurrentSubtreeIsForEventsAndPluginsOnly;
}; };
#endif // RETAINEDDISPLAYLISTBUILDER_H_ #endif // RETAINEDDISPLAYLISTBUILDER_H_

Просмотреть файл

@ -0,0 +1,15 @@
<html class="reftest-wait">
<script>
setTimeout(function() {
a.appendChild(b);
document.documentElement.className = "";
}, 100)
</script>
<style>
:root { opacity: 0 }
</style>
A
<textarea id="a" hidden=""></textarea>
<object id="b" >
A
</html>

Просмотреть файл

@ -16,3 +16,4 @@ load 1468124-1.html
load 1469472.html load 1469472.html
load 1477831-1.html load 1477831-1.html
load 1504033.html load 1504033.html
load 1514544-1.html