зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
f0ee7a9279
Коммит
f278a7e08c
|
@ -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
|
||||||
|
|
Загрузка…
Ссылка в новой задаче