зеркало из 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 "nsViewManager.h"
|
||||
#include "nsCanvasFrame.h"
|
||||
#include "mozilla/AutoRestore.h"
|
||||
|
||||
/**
|
||||
* 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());
|
||||
}
|
||||
|
||||
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) {
|
||||
if (ShouldSilentlyDiscardItem(aNewItem)) {
|
||||
aNewItem->Destroy(mBuilder->Builder());
|
||||
return aPreviousItem;
|
||||
}
|
||||
|
||||
OldListIndex oldIndex;
|
||||
if (!HasModifiedFrame(aNewItem) &&
|
||||
HasMatchingItemInOldList(aNewItem, &oldIndex)) {
|
||||
|
@ -344,8 +362,7 @@ class MergeState {
|
|||
Maybe<const ActiveScrolledRoot*> containerASRForChildren;
|
||||
if (mBuilder->MergeDisplayLists(
|
||||
aNewItem->GetChildren(), oldItem->GetChildren(),
|
||||
destItem->GetChildren(), containerASRForChildren,
|
||||
aNewItem->GetPerFrameKey())) {
|
||||
destItem->GetChildren(), containerASRForChildren, aNewItem)) {
|
||||
destItem->InvalidateCachedChildInfo();
|
||||
mResultIsModified = true;
|
||||
}
|
||||
|
@ -363,12 +380,12 @@ class MergeState {
|
|||
} else {
|
||||
aNewItem->Destroy(mBuilder->Builder());
|
||||
}
|
||||
return newIndex;
|
||||
return Some(newIndex);
|
||||
}
|
||||
}
|
||||
mResultIsModified = true;
|
||||
return AddNewNode(aNewItem, Nothing(), Span<MergedListIndex>(),
|
||||
aPreviousItem);
|
||||
return Some(AddNewNode(aNewItem, Nothing(), Span<MergedListIndex>(),
|
||||
aPreviousItem));
|
||||
}
|
||||
|
||||
bool ShouldUseNewItem(nsDisplayItem* aNewItem) {
|
||||
|
@ -505,16 +522,20 @@ class MergeState {
|
|||
void ProcessOldNode(OldListIndex aNode,
|
||||
nsTArray<MergedListIndex>&& aDirectPredecessors) {
|
||||
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));
|
||||
mResultIsModified = true;
|
||||
} else {
|
||||
if (item->GetChildren()) {
|
||||
Maybe<const ActiveScrolledRoot*> containerASRForChildren;
|
||||
nsDisplayList empty;
|
||||
if (mBuilder->MergeDisplayLists(
|
||||
&empty, item->GetChildren(), item->GetChildren(),
|
||||
containerASRForChildren, item->GetPerFrameKey())) {
|
||||
if (mBuilder->MergeDisplayLists(&empty, item->GetChildren(),
|
||||
item->GetChildren(),
|
||||
containerASRForChildren, item)) {
|
||||
item->InvalidateCachedChildInfo();
|
||||
mResultIsModified = true;
|
||||
}
|
||||
|
@ -630,13 +651,20 @@ bool RetainedDisplayListBuilder::MergeDisplayLists(
|
|||
nsDisplayList* aNewList, RetainedDisplayList* aOldList,
|
||||
RetainedDisplayList* aOutList,
|
||||
mozilla::Maybe<const mozilla::ActiveScrolledRoot*>& aOutContainerASR,
|
||||
uint32_t aOuterKey) {
|
||||
MergeState merge(this, *aOldList, aOuterKey);
|
||||
nsDisplayItem* aOuterItem) {
|
||||
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;
|
||||
while (nsDisplayItem* item = aNewList->RemoveBottom()) {
|
||||
previousItemIndex =
|
||||
Some(merge.ProcessItemFromNewList(item, previousItemIndex));
|
||||
previousItemIndex = merge.ProcessItemFromNewList(item, previousItemIndex);
|
||||
}
|
||||
|
||||
*aOutList = merge.Finalize();
|
||||
|
|
|
@ -95,7 +95,8 @@ RetainedDisplayListData* GetOrSetRetainedDisplayListData(nsIFrame* aRootFrame);
|
|||
struct RetainedDisplayListBuilder {
|
||||
RetainedDisplayListBuilder(nsIFrame* aReferenceFrame,
|
||||
nsDisplayListBuilderMode aMode, bool aBuildCaret)
|
||||
: mBuilder(aReferenceFrame, aMode, aBuildCaret, true) {}
|
||||
: mBuilder(aReferenceFrame, aMode, aBuildCaret, true),
|
||||
mCurrentSubtreeIsForEventsAndPluginsOnly(false) {}
|
||||
~RetainedDisplayListBuilder() { mList.DeleteAll(&mBuilder); }
|
||||
|
||||
nsDisplayListBuilder* Builder() { return &mBuilder; }
|
||||
|
@ -122,11 +123,20 @@ struct RetainedDisplayListBuilder {
|
|||
AnimatedGeometryRoot* aAGR,
|
||||
uint32_t aCallerKey = 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(
|
||||
nsDisplayList* aNewList, RetainedDisplayList* aOldList,
|
||||
RetainedDisplayList* aOutList,
|
||||
mozilla::Maybe<const mozilla::ActiveScrolledRoot*>& aOutContainerASR,
|
||||
uint32_t aOuterKey = 0);
|
||||
nsDisplayItem* aOuterItem = nullptr);
|
||||
|
||||
bool ComputeRebuildRegion(nsTArray<nsIFrame*>& aModifiedFrames,
|
||||
nsRect* aOutDirty,
|
||||
|
@ -145,6 +155,10 @@ struct RetainedDisplayListBuilder {
|
|||
nsDisplayListBuilder mBuilder;
|
||||
RetainedDisplayList mList;
|
||||
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_
|
||||
|
|
|
@ -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 1477831-1.html
|
||||
load 1504033.html
|
||||
load 1514544-1.html
|
||||
|
|
Загрузка…
Ссылка в новой задаче