merge mozilla-central to mozilla-inbound

This commit is contained in:
Sebastian Hengst 2018-02-12 14:21:30 +02:00
commit fad4d039ef
12 changed files with 283 additions and 407 deletions

View File

@ -3631,7 +3631,6 @@ nsLayoutUtils::PaintFrame(gfxContext* aRenderingContext, nsIFrame* aFrame,
PaintFrameFlags aFlags)
{
AUTO_PROFILER_LABEL("nsLayoutUtils::PaintFrame", GRAPHICS);
typedef RetainedDisplayListBuilder::PartialUpdateResult PartialUpdateResult;
#ifdef MOZ_DUMP_PAINTING
if (!gPaintCountStack) {
@ -3789,7 +3788,6 @@ nsLayoutUtils::PaintFrame(gfxContext* aRenderingContext, nsIFrame* aFrame,
}
nsRect visibleRect = visibleRegion.GetBounds();
PartialUpdateResult updateState = PartialUpdateResult::Failed;
{
AUTO_PROFILER_LABEL("nsLayoutUtils::PaintFrame:BuildDisplayList",
@ -3839,20 +3837,22 @@ nsLayoutUtils::PaintFrame(gfxContext* aRenderingContext, nsIFrame* aFrame,
// Attempt to do a partial build and merge into the existing list.
// This calls BuildDisplayListForStacking context on a subset of the
// viewport.
bool merged = false;
if (useRetainedBuilder) {
if (gfxPrefs::LayoutVerifyRetainDisplayList()) {
beforeMergeChecker.Set(&list, "BM");
}
updateState = retainedBuilder->AttemptPartialUpdate(
merged = retainedBuilder->AttemptPartialUpdate(
aBackstop, beforeMergeChecker ? &toBeMergedChecker : nullptr);
if ((updateState != PartialUpdateResult::Failed) && beforeMergeChecker) {
if (merged && beforeMergeChecker) {
afterMergeChecker.Set(&list, "AM");
}
}
if ((updateState != PartialUpdateResult::Failed) &&
if (merged &&
(gfxPrefs::LayoutDisplayListBuildTwice() || afterMergeChecker)) {
updateState = PartialUpdateResult::Failed;
merged = false;
if (gfxPrefs::LayersDrawFPS()) {
if (RefPtr<LayerManager> lm = builder.GetWidgetLayerManager()) {
if (PaintTiming* pt = ClientLayerManager::MaybeGetPaintTiming(lm)) {
@ -3863,7 +3863,7 @@ nsLayoutUtils::PaintFrame(gfxContext* aRenderingContext, nsIFrame* aFrame,
dlStart = TimeStamp::Now();
}
if (updateState == PartialUpdateResult::Failed) {
if (!merged) {
list.DeleteAll(&builder);
builder.EnterPresShell(aFrame);
builder.SetDirtyRect(visibleRect);
@ -3872,7 +3872,6 @@ nsLayoutUtils::PaintFrame(gfxContext* aRenderingContext, nsIFrame* aFrame,
AddExtraBackgroundItems(builder, list, aFrame, canvasArea, visibleRegion, aBackstop);
builder.LeavePresShell(aFrame, &list);
updateState = PartialUpdateResult::Updated;
if (afterMergeChecker) {
DisplayListChecker nonRetainedChecker(&list, "NR");
@ -3910,7 +3909,6 @@ nsLayoutUtils::PaintFrame(gfxContext* aRenderingContext, nsIFrame* aFrame,
}
}
MOZ_ASSERT(updateState != PartialUpdateResult::Failed);
builder.Check();
Telemetry::AccumulateTimeDelta(Telemetry::PAINT_BUILD_DISPLAYLIST_TIME,
@ -3985,9 +3983,6 @@ nsLayoutUtils::PaintFrame(gfxContext* aRenderingContext, nsIFrame* aFrame,
if (aFlags & PaintFrameFlags::PAINT_COMPRESSED) {
flags |= nsDisplayList::PAINT_COMPRESSED;
}
if (updateState == PartialUpdateResult::NoChange) {
flags |= nsDisplayList::PAINT_IDENTICAL_DISPLAY_LIST;
}
TimeStamp paintStart = TimeStamp::Now();
RefPtr<LayerManager> layerManager

View File

@ -194,7 +194,7 @@ nsPresContext::MakeColorPref(const nsString& aColor)
bool
nsPresContext::IsDOMPaintEventPending()
{
if (!mTransactions.IsEmpty()) {
if (mFireAfterPaintEvents) {
return true;
}
nsRootPresContext* drpc = GetRootPresContext();
@ -203,6 +203,7 @@ nsPresContext::IsDOMPaintEventPending()
// fired, we record an empty invalidation in case display list
// invalidation doesn't invalidate anything further.
NotifyInvalidation(drpc->mRefreshDriver->LastTransactionId() + 1, nsRect(0, 0, 0, 0));
NS_ASSERTION(mFireAfterPaintEvents, "Why aren't we planning to fire the event?");
return true;
}
return false;
@ -314,6 +315,7 @@ nsPresContext::nsPresContext(nsIDocument* aDocument, nsPresContextType aType)
mFontFeatureValuesDirty(true),
mSuppressResizeReflow(false),
mIsVisual(false),
mFireAfterPaintEvents(false),
mIsChrome(false),
mIsChromeOriginImage(false),
mPaintFlashing(false),
@ -2594,17 +2596,6 @@ nsPresContext::NotifyInvalidation(uint64_t aTransactionId, const nsIntRect& aRec
NotifyInvalidation(aTransactionId, rect);
}
nsPresContext::TransactionInvalidations*
nsPresContext::GetInvalidations(uint64_t aTransactionId)
{
for (TransactionInvalidations& t : mTransactions) {
if (t.mTransactionId == aTransactionId) {
return &t;
}
}
return nullptr;
}
void
nsPresContext::NotifyInvalidation(uint64_t aTransactionId, const nsRect& aRect)
{
@ -2618,13 +2609,9 @@ nsPresContext::NotifyInvalidation(uint64_t aTransactionId, const nsRect& aRect)
nsPresContext* pc;
for (pc = this; pc; pc = pc->GetParentPresContext()) {
TransactionInvalidations* transaction = pc->GetInvalidations(aTransactionId);
if (transaction) {
if (pc->mFireAfterPaintEvents)
break;
} else {
transaction = pc->mTransactions.AppendElement();
transaction->mTransactionId = aTransactionId;
}
pc->mFireAfterPaintEvents = true;
}
if (!pc) {
nsRootPresContext* rpc = GetRootPresContext();
@ -2633,8 +2620,18 @@ nsPresContext::NotifyInvalidation(uint64_t aTransactionId, const nsRect& aRect)
}
}
TransactionInvalidations* transaction = GetInvalidations(aTransactionId);
MOZ_ASSERT(transaction);
TransactionInvalidations* transaction = nullptr;
for (TransactionInvalidations& t : mTransactions) {
if (t.mTransactionId == aTransactionId) {
transaction = &t;
break;
}
}
if (!transaction) {
transaction = mTransactions.AppendElement();
transaction->mTransactionId = aTransactionId;
}
transaction->mInvalidations.AppendElement(aRect);
}
@ -2686,6 +2683,7 @@ nsPresContext::ClearNotifySubDocInvalidationData(ContainerLayer* aContainer)
struct NotifyDidPaintSubdocumentCallbackClosure {
uint64_t mTransactionId;
const mozilla::TimeStamp& mTimeStamp;
bool mNeedsAnotherDidPaintNotification;
};
/* static */ bool
nsPresContext::NotifyDidPaintSubdocumentCallback(nsIDocument* aDocument, void* aData)
@ -2698,6 +2696,9 @@ nsPresContext::NotifyDidPaintSubdocumentCallback(nsIDocument* aDocument, void* a
if (pc) {
pc->NotifyDidPaintForSubtree(closure->mTransactionId,
closure->mTimeStamp);
if (pc->mFireAfterPaintEvents) {
closure->mNeedsAnotherDidPaintNotification = true;
}
}
}
return true;
@ -2742,12 +2743,12 @@ nsPresContext::NotifyDidPaintForSubtree(uint64_t aTransactionId,
if (IsRoot()) {
static_cast<nsRootPresContext*>(this)->CancelDidPaintTimers(aTransactionId);
if (mTransactions.IsEmpty()) {
if (!mFireAfterPaintEvents) {
return;
}
}
if (!PresShell()->IsVisible() && mTransactions.IsEmpty()) {
if (!PresShell()->IsVisible() && !mFireAfterPaintEvents) {
return;
}
@ -2761,13 +2762,11 @@ nsPresContext::NotifyDidPaintForSubtree(uint64_t aTransactionId,
uint32_t i = 0;
while (i < mTransactions.Length()) {
if (mTransactions[i].mTransactionId <= aTransactionId) {
if (!mTransactions[i].mInvalidations.IsEmpty()) {
nsCOMPtr<nsIRunnable> ev =
new DelayedFireDOMPaintEvent(this, &mTransactions[i].mInvalidations,
mTransactions[i].mTransactionId, aTimeStamp);
nsContentUtils::AddScriptRunner(ev);
sent = true;
}
nsCOMPtr<nsIRunnable> ev =
new DelayedFireDOMPaintEvent(this, &mTransactions[i].mInvalidations,
mTransactions[i].mTransactionId, aTimeStamp);
nsContentUtils::AddScriptRunner(ev);
sent = true;
mTransactions.RemoveElementAt(i);
} else {
i++;
@ -2782,8 +2781,14 @@ nsPresContext::NotifyDidPaintForSubtree(uint64_t aTransactionId,
nsContentUtils::AddScriptRunner(ev);
}
NotifyDidPaintSubdocumentCallbackClosure closure = { aTransactionId, aTimeStamp };
NotifyDidPaintSubdocumentCallbackClosure closure = { aTransactionId, aTimeStamp, false };
mDocument->EnumerateSubDocuments(nsPresContext::NotifyDidPaintSubdocumentCallback, &closure);
if (!closure.mNeedsAnotherDidPaintNotification &&
mTransactions.IsEmpty()) {
// Nothing more to do for the moment.
mFireAfterPaintEvents = false;
}
}
bool

View File

@ -1291,12 +1291,6 @@ protected:
const char* aName,
uint32_t aDelay);
struct TransactionInvalidations {
uint64_t mTransactionId;
nsTArray<nsRect> mInvalidations;
};
TransactionInvalidations* GetInvalidations(uint64_t aTransactionId);
// IMPORTANT: The ownership implicit in the following member variables
// has been explicitly checked. If you add any members to this class,
// please make the ownership explicit (pinkerton, scc).
@ -1365,6 +1359,10 @@ protected:
mozilla::UniquePtr<nsBidi> mBidiEngine;
struct TransactionInvalidations {
uint64_t mTransactionId;
nsTArray<nsRect> mInvalidations;
};
AutoTArray<TransactionInvalidations, 4> mTransactions;
// text performance metrics
@ -1491,6 +1489,8 @@ protected:
unsigned mIsVisual : 1;
unsigned mFireAfterPaintEvents : 1;
unsigned mIsChrome : 1;
unsigned mIsChromeOriginImage : 1;

View File

@ -104,25 +104,21 @@ SelectAGRForFrame(nsIFrame* aFrame, AnimatedGeometryRoot* aParentAGR)
// TODO: We currently descend into all children even if we don't have an AGR
// to mark, as child stacking contexts might. It would be nice if we could
// jump into those immediately rather than walking the entire thing.
bool
void
RetainedDisplayListBuilder::PreProcessDisplayList(nsDisplayList* aList,
AnimatedGeometryRoot* aAGR)
{
bool modified = false;
nsDisplayList saved;
while (nsDisplayItem* i = aList->RemoveBottom()) {
if (i->HasDeletedFrame() || !i->CanBeReused()) {
i->Destroy(&mBuilder);
modified = true;
continue;
}
nsIFrame* f = i->Frame();
if (i->GetChildren()) {
if (PreProcessDisplayList(i->GetChildren(), SelectAGRForFrame(f, aAGR))) {
modified = true;
}
PreProcessDisplayList(i->GetChildren(), SelectAGRForFrame(f, aAGR));
}
// TODO: We should be able to check the clipped bounds relative
@ -130,7 +126,6 @@ RetainedDisplayListBuilder::PreProcessDisplayList(nsDisplayList* aList,
// frame) and determine if they can ever intersect.
if (aAGR && i->GetAnimatedGeometryRoot()->GetAsyncAGR() != aAGR) {
mBuilder.MarkFrameForDisplayIfVisible(f, mBuilder.RootReferenceFrame());
modified = true;
}
// TODO: This is here because we sometimes reuse the previous display list
@ -142,7 +137,6 @@ RetainedDisplayListBuilder::PreProcessDisplayList(nsDisplayList* aList,
}
aList->AppendToTop(&saved);
aList->RestoreState();
return modified;
}
bool IsSameItem(nsDisplayItem* aFirst, nsDisplayItem* aSecond)
@ -205,13 +199,12 @@ void SwapAndRemove(nsTArray<T>& aArray, uint32_t aIndex)
aArray.RemoveElementAt(aArray.Length() - 1);
}
static bool
static void
MergeFrameRects(nsDisplayLayerEventRegions* aOldItem,
nsDisplayLayerEventRegions* aNewItem,
nsDisplayLayerEventRegions::FrameRects nsDisplayLayerEventRegions::*aRectList,
nsTArray<nsIFrame*>& aAddedFrames)
{
bool modified = false;
// Go through the old item's rect list and remove any rectangles
// belonging to invalidated frames (deleted frames should
// already be gone at this point)
@ -226,13 +219,12 @@ MergeFrameRects(nsDisplayLayerEventRegions* aOldItem,
f->RemoveDisplayItem(aOldItem);
SwapAndRemove(oldRects.mFrames, i);
SwapAndRemove(oldRects.mBoxes, i);
modified = true;
} else {
i++;
}
}
if (!aNewItem) {
return modified;
return;
}
// Copy items from the source list to the dest list, but
@ -253,15 +245,12 @@ MergeFrameRects(nsDisplayLayerEventRegions* aOldItem,
// FrameRects lists, so defer that until the end.
aAddedFrames.AppendElement(f);
MOZ_ASSERT(f != aOldItem->Frame());
modified = true;
}
}
return modified;
}
bool MergeLayerEventRegions(nsDisplayItem* aOldItem,
void MergeLayerEventRegions(nsDisplayItem* aOldItem,
nsDisplayItem* aNewItem)
{
nsDisplayLayerEventRegions* oldItem =
@ -271,13 +260,12 @@ bool MergeLayerEventRegions(nsDisplayItem* aOldItem,
nsTArray<nsIFrame*> addedFrames;
bool modified = false;
modified |= MergeFrameRects(oldItem, newItem, &nsDisplayLayerEventRegions::mHitRegion, addedFrames);
modified |= MergeFrameRects(oldItem, newItem, &nsDisplayLayerEventRegions::mMaybeHitRegion, addedFrames);
modified |= MergeFrameRects(oldItem, newItem, &nsDisplayLayerEventRegions::mDispatchToContentHitRegion, addedFrames);
modified |= MergeFrameRects(oldItem, newItem, &nsDisplayLayerEventRegions::mNoActionRegion, addedFrames);
modified |= MergeFrameRects(oldItem, newItem, &nsDisplayLayerEventRegions::mHorizontalPanRegion, addedFrames);
modified |= MergeFrameRects(oldItem, newItem, &nsDisplayLayerEventRegions::mVerticalPanRegion, addedFrames);
MergeFrameRects(oldItem, newItem, &nsDisplayLayerEventRegions::mHitRegion, addedFrames);
MergeFrameRects(oldItem, newItem, &nsDisplayLayerEventRegions::mMaybeHitRegion, addedFrames);
MergeFrameRects(oldItem, newItem, &nsDisplayLayerEventRegions::mDispatchToContentHitRegion, addedFrames);
MergeFrameRects(oldItem, newItem, &nsDisplayLayerEventRegions::mNoActionRegion, addedFrames);
MergeFrameRects(oldItem, newItem, &nsDisplayLayerEventRegions::mHorizontalPanRegion, addedFrames);
MergeFrameRects(oldItem, newItem, &nsDisplayLayerEventRegions::mVerticalPanRegion, addedFrames);
// MergeFrameRects deferred updating the display item data list during
// processing so that earlier calls didn't change the result of later
@ -287,7 +275,6 @@ bool MergeLayerEventRegions(nsDisplayItem* aOldItem,
f->AddDisplayItem(aOldItem);
}
}
return modified;
}
void
@ -401,14 +388,12 @@ void UpdateASR(nsDisplayItem* aItem,
*
* Merged List: C, A, B
*/
bool
void
RetainedDisplayListBuilder::MergeDisplayLists(nsDisplayList* aNewList,
nsDisplayList* aOldList,
nsDisplayList* aOutList,
Maybe<const ActiveScrolledRoot*>& aOutContainerASR)
{
bool modified = false;
nsDisplayList merged;
const auto UseItem = [&](nsDisplayItem* aItem) {
const ActiveScrolledRoot* itemClipASR =
@ -472,11 +457,9 @@ RetainedDisplayListBuilder::MergeDisplayLists(nsDisplayList* aNewList,
oldListLookup.Remove({ old->Frame(), old->GetPerFrameKey() });
aOldList->RemoveBottom();
old->Destroy(&mBuilder);
modified = true;
} else if (newListLookup.Get({ old->Frame(), old->GetPerFrameKey() })) {
// This old item is also in the new list, but we haven't got to it yet.
// Stop now, and we'll deal with it when we get to the new entry.
modified = true;
break;
} else {
// Recurse into the child list (without a matching new list) to
@ -484,10 +467,8 @@ RetainedDisplayListBuilder::MergeDisplayLists(nsDisplayList* aNewList,
if (old->GetChildren()) {
nsDisplayList empty;
Maybe<const ActiveScrolledRoot*> containerASRForChildren;
if (MergeDisplayLists(&empty, old->GetChildren(),
old->GetChildren(), containerASRForChildren)) {
modified = true;
}
MergeDisplayLists(&empty, old->GetChildren(),
old->GetChildren(), containerASRForChildren);
UpdateASR(old, containerASRForChildren);
old->UpdateBounds(&mBuilder);
}
@ -517,21 +498,16 @@ RetainedDisplayListBuilder::MergeDisplayLists(nsDisplayList* aNewList,
// the lists of regions and frames, so we have no need to use the
// newer item. Always use the old item instead since we assume it's
// likely to have the bigger lists and merging will be quicker.
if (MergeLayerEventRegions(oldItem, newItem)) {
modified = true;
}
MergeLayerEventRegions(oldItem, newItem);
ReuseItem(oldItem);
newItem->Destroy(&mBuilder);
} else {
if (IsAnyAncestorModified(oldItem->FrameForInvalidation())) {
modified = true;
} else if (oldItem->GetChildren()) {
if (!IsAnyAncestorModified(oldItem->FrameForInvalidation()) &&
oldItem->GetChildren()) {
MOZ_ASSERT(newItem->GetChildren());
Maybe<const ActiveScrolledRoot*> containerASRForChildren;
if (MergeDisplayLists(newItem->GetChildren(), oldItem->GetChildren(),
newItem->GetChildren(), containerASRForChildren)) {
modified = true;
}
MergeDisplayLists(newItem->GetChildren(), oldItem->GetChildren(),
newItem->GetChildren(), containerASRForChildren);
UpdateASR(newItem, containerASRForChildren);
newItem->UpdateBounds(&mBuilder);
}
@ -544,7 +520,6 @@ RetainedDisplayListBuilder::MergeDisplayLists(nsDisplayList* aNewList,
} else {
// If there was no matching item in the old list, then we only need to
// add the new item to the merged list.
modified = true;
UseItem(newItem);
}
}
@ -562,27 +537,21 @@ RetainedDisplayListBuilder::MergeDisplayLists(nsDisplayList* aNewList,
nsDisplayList empty;
Maybe<const ActiveScrolledRoot*> containerASRForChildren;
if (MergeDisplayLists(&empty, old->GetChildren(),
old->GetChildren(), containerASRForChildren)) {
modified = true;
}
MergeDisplayLists(&empty, old->GetChildren(),
old->GetChildren(), containerASRForChildren);
UpdateASR(old, containerASRForChildren);
old->UpdateBounds(&mBuilder);
}
if (old->GetType() == DisplayItemType::TYPE_LAYER_EVENT_REGIONS) {
if (MergeLayerEventRegions(old, nullptr)) {
modified = true;
}
MergeLayerEventRegions(old, nullptr);
}
ReuseItem(old);
} else {
old->Destroy(&mBuilder);
modified = true;
}
}
aOutList->AppendToTop(&merged);
return modified;
}
static void
@ -766,8 +735,6 @@ ProcessFrame(nsIFrame* aFrame, nsDisplayListBuilder& aBuilder,
{
nsIFrame* currentFrame = aFrame;
aBuilder.MarkFrameForDisplayIfVisible(aFrame, aBuilder.RootReferenceFrame());
while (currentFrame != aStopAtFrame) {
CRR_LOG("currentFrame: %p (placeholder=%d), aOverflow: %d %d %d %d\n",
currentFrame, !aStopAtStackingContext,
@ -818,10 +785,6 @@ ProcessFrame(nsIFrame* aFrame, nsDisplayListBuilder& aBuilder,
/* aStopAtStackingContextAndDisplayPortAndOOFFrame = */ true,
&currentFrame);
MOZ_ASSERT(currentFrame);
aOverflow.IntersectRect(aOverflow, currentFrame->GetVisualOverflowRectRelativeToSelf());
if (aOverflow.IsEmpty()) {
break;
}
if (nsLayoutUtils::FrameHasDisplayPort(currentFrame)) {
CRR_LOG("Frame belongs to displayport frame %p\n", currentFrame);
@ -994,20 +957,18 @@ RetainedDisplayListBuilder::ComputeRebuildRegion(nsTArray<nsIFrame*>& aModifiedF
ProcessFrame(f, mBuilder, &agr, overflow, mBuilder.RootReferenceFrame(),
aOutFramesWithProps, true);
if (!overflow.IsEmpty()) {
aOutDirty->UnionRect(*aOutDirty, overflow);
CRR_LOG("Adding area to root draw area: %d %d %d %d\n",
overflow.x, overflow.y, overflow.width, overflow.height);
aOutDirty->UnionRect(*aOutDirty, overflow);
CRR_LOG("Adding area to root draw area: %d %d %d %d\n",
overflow.x, overflow.y, overflow.width, overflow.height);
// If we get changed frames from multiple AGRS, then just give up as it gets really complex to
// track which items would need to be marked in MarkFramesForDifferentAGR.
if (!*aOutModifiedAGR) {
CRR_LOG("Setting %p as root stacking context AGR\n", agr);
*aOutModifiedAGR = agr;
} else if (agr && *aOutModifiedAGR != agr) {
CRR_LOG("Found multiple AGRs in root stacking context, giving up\n");
return false;
}
// If we get changed frames from multiple AGRS, then just give up as it gets really complex to
// track which items would need to be marked in MarkFramesForDifferentAGR.
if (!*aOutModifiedAGR) {
CRR_LOG("Setting %p as root stacking context AGR\n", agr);
*aOutModifiedAGR = agr;
} else if (agr && *aOutModifiedAGR != agr) {
CRR_LOG("Found multiple AGRs in root stacking context, giving up\n");
return false;
}
}
@ -1060,36 +1021,21 @@ ClearFrameProps(nsTArray<nsIFrame*>& aFrames)
}
}
class AutoClearFramePropsArray
{
public:
AutoClearFramePropsArray() = default;
~AutoClearFramePropsArray()
{
ClearFrameProps(mFrames);
}
nsTArray<nsIFrame*>& Frames() { return mFrames; }
bool IsEmpty() const { return mFrames.IsEmpty(); }
private:
nsTArray<nsIFrame*> mFrames;
};
void
RetainedDisplayListBuilder::ClearFramesWithProps()
{
AutoClearFramePropsArray modifiedFrames;
AutoClearFramePropsArray framesWithProps;
GetModifiedAndFramesWithProps(&mBuilder, &modifiedFrames.Frames(), &framesWithProps.Frames());
nsTArray<nsIFrame*> modifiedFrames;
nsTArray<nsIFrame*> framesWithProps;
GetModifiedAndFramesWithProps(&mBuilder, &modifiedFrames, &framesWithProps);
ClearFrameProps(modifiedFrames);
ClearFrameProps(framesWithProps);
}
auto
bool
RetainedDisplayListBuilder::AttemptPartialUpdate(
nscolor aBackstop,
mozilla::DisplayListChecker* aChecker) -> PartialUpdateResult
mozilla::DisplayListChecker* aChecker)
{
mBuilder.RemoveModifiedWindowRegions();
mBuilder.ClearWindowOpaqueRegion();
@ -1100,27 +1046,24 @@ RetainedDisplayListBuilder::AttemptPartialUpdate(
mBuilder.EnterPresShell(mBuilder.RootReferenceFrame());
// We set the override dirty regions during ComputeRebuildRegion or in
// nsLayoutUtils::InvalidateForDisplayPortChange. The display port change also
// marks the frame modified, so those regions are cleared here as well.
AutoClearFramePropsArray modifiedFrames;
AutoClearFramePropsArray framesWithProps;
GetModifiedAndFramesWithProps(&mBuilder, &modifiedFrames.Frames(), &framesWithProps.Frames());
nsTArray<nsIFrame*> modifiedFrames;
nsTArray<nsIFrame*> framesWithProps;
GetModifiedAndFramesWithProps(&mBuilder, &modifiedFrames, &framesWithProps);
// Do not allow partial builds if the retained display list is empty, or if
// ShouldBuildPartial heuristic fails.
const bool shouldBuildPartial = !mList.IsEmpty() && ShouldBuildPartial(modifiedFrames.Frames());
const bool shouldBuildPartial = !mList.IsEmpty() && ShouldBuildPartial(modifiedFrames);
if (mPreviousCaret != mBuilder.GetCaretFrame()) {
if (mPreviousCaret) {
if (mBuilder.MarkFrameModifiedDuringBuilding(mPreviousCaret)) {
modifiedFrames.Frames().AppendElement(mPreviousCaret);
modifiedFrames.AppendElement(mPreviousCaret);
}
}
if (mBuilder.GetCaretFrame()) {
if (mBuilder.MarkFrameModifiedDuringBuilding(mBuilder.GetCaretFrame())) {
modifiedFrames.Frames().AppendElement(mBuilder.GetCaretFrame());
modifiedFrames.AppendElement(mBuilder.GetCaretFrame());
}
}
@ -1129,60 +1072,61 @@ RetainedDisplayListBuilder::AttemptPartialUpdate(
nsRect modifiedDirty;
AnimatedGeometryRoot* modifiedAGR = nullptr;
if (!shouldBuildPartial ||
!ComputeRebuildRegion(modifiedFrames.Frames(), &modifiedDirty,
&modifiedAGR, framesWithProps.Frames())) {
mBuilder.LeavePresShell(mBuilder.RootReferenceFrame(), &mList);
return PartialUpdateResult::Failed;
bool merged = false;
if (shouldBuildPartial &&
ComputeRebuildRegion(modifiedFrames, &modifiedDirty,
&modifiedAGR, framesWithProps)) {
modifiedDirty.IntersectRect(modifiedDirty, mBuilder.RootReferenceFrame()->GetVisualOverflowRectRelativeToSelf());
PreProcessDisplayList(&mList, modifiedAGR);
nsDisplayList modifiedDL;
if (!modifiedDirty.IsEmpty() || !framesWithProps.IsEmpty()) {
mBuilder.SetDirtyRect(modifiedDirty);
mBuilder.SetPartialUpdate(true);
mBuilder.RootReferenceFrame()->BuildDisplayListForStackingContext(&mBuilder, &modifiedDL);
nsLayoutUtils::AddExtraBackgroundItems(mBuilder, modifiedDL, mBuilder.RootReferenceFrame(),
nsRect(nsPoint(0, 0), mBuilder.RootReferenceFrame()->GetSize()),
mBuilder.RootReferenceFrame()->GetVisualOverflowRectRelativeToSelf(),
aBackstop);
mBuilder.SetPartialUpdate(false);
//printf_stderr("Painting --- Modified list (dirty %d,%d,%d,%d):\n",
// modifiedDirty.x, modifiedDirty.y, modifiedDirty.width, modifiedDirty.height);
//nsFrame::PrintDisplayList(&mBuilder, modifiedDL);
} else {
// TODO: We can also skip layer building and painting if
// PreProcessDisplayList didn't end up changing anything
// Invariant: display items should have their original state here.
// printf_stderr("Skipping display list building since nothing needed to be done\n");
}
if (aChecker) {
aChecker->Set(&modifiedDL, "TM");
}
// |modifiedDL| can sometimes be empty here. We still perform the
// display list merging to prune unused items (for example, items that
// are not visible anymore) from the old list.
// TODO: Optimization opportunity. In this case, MergeDisplayLists()
// unnecessarily creates a hashtable of the old items.
Maybe<const ActiveScrolledRoot*> dummy;
MergeDisplayLists(&modifiedDL, &mList, &mList, dummy);
//printf_stderr("Painting --- Merged list:\n");
//nsFrame::PrintDisplayList(&mBuilder, mList);
merged = true;
}
modifiedDirty.IntersectRect(modifiedDirty, mBuilder.RootReferenceFrame()->GetVisualOverflowRectRelativeToSelf());
PartialUpdateResult result = PartialUpdateResult::NoChange;
if (PreProcessDisplayList(&mList, modifiedAGR) ||
!modifiedDirty.IsEmpty() ||
!framesWithProps.IsEmpty()) {
result = PartialUpdateResult::Updated;
}
mBuilder.SetDirtyRect(modifiedDirty);
mBuilder.SetPartialUpdate(true);
nsDisplayList modifiedDL;
mBuilder.RootReferenceFrame()->BuildDisplayListForStackingContext(&mBuilder, &modifiedDL);
if (!modifiedDL.IsEmpty()) {
nsLayoutUtils::AddExtraBackgroundItems(mBuilder, modifiedDL, mBuilder.RootReferenceFrame(),
nsRect(nsPoint(0, 0), mBuilder.RootReferenceFrame()->GetSize()),
mBuilder.RootReferenceFrame()->GetVisualOverflowRectRelativeToSelf(),
aBackstop);
}
mBuilder.SetPartialUpdate(false);
if (aChecker) {
aChecker->Set(&modifiedDL, "TM");
}
//printf_stderr("Painting --- Modified list (dirty %d,%d,%d,%d):\n",
// modifiedDirty.x, modifiedDirty.y, modifiedDirty.width, modifiedDirty.height);
//nsFrame::PrintDisplayList(&mBuilder, modifiedDL);
// |modifiedDL| can sometimes be empty here. We still perform the
// display list merging to prune unused items (for example, items that
// are not visible anymore) from the old list.
// TODO: Optimization opportunity. In this case, MergeDisplayLists()
// unnecessarily creates a hashtable of the old items.
// TODO: Ideally we could skip this if result is NoChange, but currently when
// we call RestoreState on nsDisplayWrapList it resets the clip to the base
// clip, and we need the UpdateBounds call (within MergeDisplayLists) to
// move it to the correct inner clip.
Maybe<const ActiveScrolledRoot*> dummy;
if (MergeDisplayLists(&modifiedDL, &mList, &mList, dummy)) {
result = PartialUpdateResult::Updated;
}
//printf_stderr("Painting --- Merged list:\n");
//nsFrame::PrintDisplayList(&mBuilder, mList);
mBuilder.LeavePresShell(mBuilder.RootReferenceFrame(), &mList);
return result;
// We set the override dirty regions during ComputeRebuildRegion or in
// nsLayoutUtils::InvalidateForDisplayPortChange. The display port change also
// marks the frame modified, so those regions are cleared here as well.
ClearFrameProps(modifiedFrames);
ClearFrameProps(framesWithProps);
return merged;
}

View File

@ -29,14 +29,8 @@ struct RetainedDisplayListBuilder {
nsDisplayList* List() { return &mList; }
enum class PartialUpdateResult {
Failed,
NoChange,
Updated
};
PartialUpdateResult AttemptPartialUpdate(nscolor aBackstop,
mozilla::DisplayListChecker* aChecker);
bool AttemptPartialUpdate(nscolor aBackstop,
mozilla::DisplayListChecker* aChecker);
/**
* Iterates through the display list builder reference frame document and
@ -49,9 +43,9 @@ struct RetainedDisplayListBuilder {
NS_DECLARE_FRAME_PROPERTY_DELETABLE(Cached, RetainedDisplayListBuilder)
private:
bool PreProcessDisplayList(nsDisplayList* aList, AnimatedGeometryRoot* aAGR);
void PreProcessDisplayList(nsDisplayList* aList, AnimatedGeometryRoot* aAGR);
bool MergeDisplayLists(nsDisplayList* aNewList,
void MergeDisplayLists(nsDisplayList* aNewList,
nsDisplayList* aOldList,
nsDisplayList* aOutList,
mozilla::Maybe<const mozilla::ActiveScrolledRoot*>& aOutContainerASR);

View File

@ -54,7 +54,7 @@ DECLARE_DISPLAY_ITEM_TYPE(SELECTION_OVERLAY, TYPE_RENDERS_NO_IMAGES)
DECLARE_DISPLAY_ITEM_TYPE(SOLID_COLOR, TYPE_RENDERS_NO_IMAGES)
DECLARE_DISPLAY_ITEM_TYPE(SOLID_COLOR_REGION, TYPE_RENDERS_NO_IMAGES)
DECLARE_DISPLAY_ITEM_TYPE(SUBDOCUMENT, TYPE_RENDERS_NO_IMAGES)
DECLARE_DISPLAY_ITEM_TYPE(MASK, 0)
DECLARE_DISPLAY_ITEM_TYPE(MASK, TYPE_RENDERS_NO_IMAGES)
DECLARE_DISPLAY_ITEM_TYPE(FILTER, TYPE_RENDERS_NO_IMAGES)
DECLARE_DISPLAY_ITEM_TYPE(SVG_OUTER_SVG, TYPE_RENDERS_NO_IMAGES)
DECLARE_DISPLAY_ITEM_TYPE(SVG_GEOMETRY, 0)

View File

@ -2504,100 +2504,6 @@ nsDisplayListBuilder::GetWidgetLayerManager(nsView** aView)
return nullptr;
}
FrameLayerBuilder*
nsDisplayList::BuildLayers(nsDisplayListBuilder* aBuilder,
LayerManager* aLayerManager,
uint32_t aFlags,
bool aIsWidgetTransaction)
{
nsIFrame* frame = aBuilder->RootReferenceFrame();
nsPresContext* presContext = frame->PresContext();
nsIPresShell* presShell = presContext->PresShell();
FrameLayerBuilder *layerBuilder = new FrameLayerBuilder();
layerBuilder->Init(aBuilder, aLayerManager);
if (aFlags & PAINT_COMPRESSED) {
layerBuilder->SetLayerTreeCompressionMode();
}
RefPtr<ContainerLayer> root;
{
AUTO_PROFILER_TRACING("Paint", "LayerBuilding");
if (XRE_IsContentProcess() && gfxPrefs::AlwaysPaint()) {
FrameLayerBuilder::InvalidateAllLayers(aLayerManager);
}
if (aIsWidgetTransaction) {
layerBuilder->DidBeginRetainedLayerTransaction(aLayerManager);
}
// Clear any ScrollMetadata that may have been set on the root layer on a
// previous paint. This paint will set new metrics if necessary, and if we
// don't clear the old one here, we may be left with extra metrics.
if (Layer* rootLayer = aLayerManager->GetRoot()) {
rootLayer->SetScrollMetadata(nsTArray<ScrollMetadata>());
}
ContainerLayerParameters containerParameters
(presShell->GetResolution(), presShell->GetResolution());
{
PaintTelemetry::AutoRecord record(PaintTelemetry::Metric::Layerization);
root = layerBuilder->
BuildContainerLayerFor(aBuilder, aLayerManager, frame, nullptr, this,
containerParameters, nullptr);
if (!record.GetStart().IsNull() && gfxPrefs::LayersDrawFPS()) {
if (PaintTiming* pt = ClientLayerManager::MaybeGetPaintTiming(aLayerManager)) {
pt->flbMs() = (TimeStamp::Now() - record.GetStart()).ToMilliseconds();
}
}
}
if (!root) {
return nullptr;
}
// Root is being scaled up by the X/Y resolution. Scale it back down.
root->SetPostScale(1.0f/containerParameters.mXScale,
1.0f/containerParameters.mYScale);
root->SetScaleToResolution(presShell->ScaleToResolution(),
containerParameters.mXScale);
auto callback = [root](FrameMetrics::ViewID aScrollId) -> bool {
return nsLayoutUtils::ContainsMetricsWithId(root, aScrollId);
};
if (Maybe<ScrollMetadata> rootMetadata = nsLayoutUtils::GetRootMetadata(
aBuilder, root->Manager(), containerParameters, callback)) {
root->SetScrollMetadata(rootMetadata.value());
}
// NS_WARNING is debug-only, so don't even bother checking the conditions in
// a release build.
#ifdef DEBUG
bool usingDisplayport = false;
if (nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame()) {
nsIContent* content = rootScrollFrame->GetContent();
if (content) {
usingDisplayport = nsLayoutUtils::HasDisplayPort(content);
}
}
if (usingDisplayport &&
!(root->GetContentFlags() & Layer::CONTENT_OPAQUE) &&
SpammyLayoutWarningsEnabled()) {
// See bug 693938, attachment 567017
NS_WARNING("Transparent content with displayports can be expensive.");
}
#endif
aLayerManager->SetRoot(root);
layerBuilder->WillEndTransaction();
}
return layerBuilder;
}
/**
* We paint by executing a layer manager transaction, constructing a
* single layer representing the display list, and then making it the
@ -2690,25 +2596,119 @@ already_AddRefed<LayerManager> nsDisplayList::PaintRoot(nsDisplayListBuilder* aB
presContext->MayHavePaintEventListenerInSubDocument() ? nsPresContext::NotifySubDocInvalidation : 0;
UniquePtr<LayerProperties> props;
RefPtr<ContainerLayer> root;
bool computeInvalidRect = (computeInvalidFunc ||
(!layerManager->IsCompositingCheap() && layerManager->NeedsWidgetInvalidation())) &&
widgetTransaction;
// Store the existing layer builder to reinstate it on return.
FrameLayerBuilder *oldBuilder = layerManager->GetLayerBuilder();
if (computeInvalidRect) {
props = Move(LayerProperties::CloneFrom(layerManager->GetRoot()));
FrameLayerBuilder *layerBuilder = new FrameLayerBuilder();
layerBuilder->Init(aBuilder, layerManager);
if (aFlags & PAINT_COMPRESSED) {
layerBuilder->SetLayerTreeCompressionMode();
}
if (doBeginTransaction) {
if (aCtx) {
if (!layerManager->BeginTransactionWithTarget(aCtx)) {
return nullptr;
}
} else {
if (!layerManager->BeginTransaction()) {
return nullptr;
{
AUTO_PROFILER_TRACING("Paint", "LayerBuilding");
if (doBeginTransaction) {
if (aCtx) {
if (!layerManager->BeginTransactionWithTarget(aCtx)) {
return nullptr;
}
} else {
if (!layerManager->BeginTransaction()) {
return nullptr;
}
}
}
if (XRE_IsContentProcess() && gfxPrefs::AlwaysPaint()) {
FrameLayerBuilder::InvalidateAllLayers(layerManager);
}
if (widgetTransaction) {
layerBuilder->DidBeginRetainedLayerTransaction(layerManager);
}
bool computeInvalidRect = (computeInvalidFunc ||
(!layerManager->IsCompositingCheap() && layerManager->NeedsWidgetInvalidation())) &&
widgetTransaction;
if (computeInvalidRect) {
props = Move(LayerProperties::CloneFrom(layerManager->GetRoot()));
}
// Clear any ScrollMetadata that may have been set on the root layer on a
// previous paint. This paint will set new metrics if necessary, and if we
// don't clear the old one here, we may be left with extra metrics.
if (Layer* rootLayer = layerManager->GetRoot()) {
rootLayer->SetScrollMetadata(nsTArray<ScrollMetadata>());
}
ContainerLayerParameters containerParameters
(presShell->GetResolution(), presShell->GetResolution());
{
PaintTelemetry::AutoRecord record(PaintTelemetry::Metric::Layerization);
root = layerBuilder->
BuildContainerLayerFor(aBuilder, layerManager, frame, nullptr, this,
containerParameters, nullptr);
if (!record.GetStart().IsNull() && gfxPrefs::LayersDrawFPS()) {
if (PaintTiming* pt = ClientLayerManager::MaybeGetPaintTiming(layerManager)) {
pt->flbMs() = (TimeStamp::Now() - record.GetStart()).ToMilliseconds();
}
}
}
if (!root) {
layerManager->SetUserData(&gLayerManagerLayerBuilder, oldBuilder);
return nullptr;
}
// Root is being scaled up by the X/Y resolution. Scale it back down.
root->SetPostScale(1.0f/containerParameters.mXScale,
1.0f/containerParameters.mYScale);
root->SetScaleToResolution(presShell->ScaleToResolution(),
containerParameters.mXScale);
auto callback = [root](FrameMetrics::ViewID aScrollId) -> bool {
return nsLayoutUtils::ContainsMetricsWithId(root, aScrollId);
};
if (Maybe<ScrollMetadata> rootMetadata = nsLayoutUtils::GetRootMetadata(
aBuilder, root->Manager(), containerParameters, callback)) {
root->SetScrollMetadata(rootMetadata.value());
}
// NS_WARNING is debug-only, so don't even bother checking the conditions in
// a release build.
#ifdef DEBUG
bool usingDisplayport = false;
if (nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame()) {
nsIContent* content = rootScrollFrame->GetContent();
if (content) {
usingDisplayport = nsLayoutUtils::HasDisplayPort(content);
}
}
if (usingDisplayport &&
!(root->GetContentFlags() & Layer::CONTENT_OPAQUE) &&
SpammyLayoutWarningsEnabled()) {
// See bug 693938, attachment 567017
NS_WARNING("Transparent content with displayports can be expensive.");
}
#endif
layerManager->SetRoot(root);
layerBuilder->WillEndTransaction();
}
if (widgetTransaction ||
// SVG-as-an-image docs don't paint as part of the retained layer tree,
// but they still need the invalidation state bits cleared in order for
// invalidation for CSS/SMIL animation to work properly.
(document && document->IsBeingUsedAsImage())) {
frame->ClearInvalidationStateBits();
}
bool temp = aBuilder->SetIsCompositingCheap(layerManager->IsCompositingCheap());
@ -2725,53 +2725,25 @@ already_AddRefed<LayerManager> nsDisplayList::PaintRoot(nsDisplayListBuilder* aB
}
}
// If this is the content process, we ship plugin geometry updates over with layer
// updates, so calculate that now before we call EndTransaction.
nsRootPresContext* rootPresContext = presContext->GetRootPresContext();
if (rootPresContext && XRE_IsContentProcess()) {
if (aBuilder->WillComputePluginGeometry()) {
rootPresContext->ComputePluginGeometryUpdates(aBuilder->RootReferenceFrame(), aBuilder, this);
}
// The layer system caches plugin configuration information for forwarding
// with layer updates which needs to get set during reflow. This must be
// called even if there are no windowed plugins in the page.
rootPresContext->CollectPluginGeometryUpdates(layerManager);
}
MaybeSetupTransactionIdAllocator(layerManager, presContext);
// Store the existing layer builder to reinstate it on return.
FrameLayerBuilder *oldBuilder = layerManager->GetLayerBuilder();
FrameLayerBuilder *layerBuilder = nullptr;
bool sent = false;
if (aFlags & PAINT_IDENTICAL_DISPLAY_LIST) {
sent = layerManager->EndEmptyTransaction(flags);
}
if (!sent) {
layerBuilder = BuildLayers(aBuilder, layerManager,
aFlags, widgetTransaction);
if (!layerBuilder) {
layerManager->SetUserData(&gLayerManagerLayerBuilder, oldBuilder);
return nullptr;
}
// If this is the content process, we ship plugin geometry updates over with layer
// updates, so calculate that now before we call EndTransaction.
nsRootPresContext* rootPresContext = presContext->GetRootPresContext();
if (rootPresContext && XRE_IsContentProcess()) {
if (aBuilder->WillComputePluginGeometry()) {
rootPresContext->ComputePluginGeometryUpdates(aBuilder->RootReferenceFrame(), aBuilder, this);
}
// The layer system caches plugin configuration information for forwarding
// with layer updates which needs to get set during reflow. This must be
// called even if there are no windowed plugins in the page.
rootPresContext->CollectPluginGeometryUpdates(layerManager);
}
layerManager->EndTransaction(FrameLayerBuilder::DrawPaintedLayer,
aBuilder, flags);
layerBuilder->DidEndTransaction();
}
if (widgetTransaction ||
// SVG-as-an-image docs don't paint as part of the retained layer tree,
// but they still need the invalidation state bits cleared in order for
// invalidation for CSS/SMIL animation to work properly.
(document && document->IsBeingUsedAsImage())) {
frame->ClearInvalidationStateBits();
}
layerManager->EndTransaction(FrameLayerBuilder::DrawPaintedLayer,
aBuilder, flags);
aBuilder->SetIsCompositingCheap(temp);
layerBuilder->DidEndTransaction();
if (document && widgetTransaction) {
TriggerPendingAnimations(document, layerManager->GetAnimationReadyTime());
@ -2780,11 +2752,11 @@ already_AddRefed<LayerManager> nsDisplayList::PaintRoot(nsDisplayListBuilder* aB
nsIntRegion invalid;
bool areaOverflowed = false;
if (props) {
if (!props->ComputeDifferences(layerManager->GetRoot(), invalid, computeInvalidFunc)) {
if (!props->ComputeDifferences(root, invalid, computeInvalidFunc)) {
areaOverflowed = true;
}
} else if (widgetTransaction) {
LayerProperties::ClearInvalidations(layerManager->GetRoot());
LayerProperties::ClearInvalidations(root);
}
bool shouldInvalidate = layerManager->NeedsWidgetInvalidation();

View File

@ -3090,17 +3090,11 @@ public:
PAINT_USE_WIDGET_LAYERS = 0x01,
PAINT_EXISTING_TRANSACTION = 0x04,
PAINT_NO_COMPOSITE = 0x08,
PAINT_COMPRESSED = 0x10,
PAINT_IDENTICAL_DISPLAY_LIST = 0x20
PAINT_COMPRESSED = 0x10
};
already_AddRefed<LayerManager> PaintRoot(nsDisplayListBuilder* aBuilder,
gfxContext* aCtx,
uint32_t aFlags);
mozilla::FrameLayerBuilder* BuildLayers(nsDisplayListBuilder* aBuilder,
LayerManager* aLayerManager,
uint32_t aFlags,
bool aIsWidgetTransaction);
/**
* Get the bounds. Takes the union of the bounds of all children.
* The result is not cached.
@ -4787,7 +4781,7 @@ private:
}
}
friend bool MergeLayerEventRegions(nsDisplayItem*, nsDisplayItem*);
friend void MergeLayerEventRegions(nsDisplayItem*, nsDisplayItem*);
// Relative to aFrame's reference frame.
// These are the points that are definitely in the hit region.

View File

@ -1,8 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<body>
<div style="opacity:0.5" id="hi">
<div style="position:fixed; width:200px; height:200px; background-color:blue"></div>
</div>
</body>
</html>

View File

@ -1,20 +0,0 @@
<!DOCTYPE html>
<html lang="en" class="reftest-wait">
<body>
<div style="opacity:0.5" id="hi">
<div style="position:fixed; width:200px; height:200px; background-color:blue"></div>
</div>
<script>
function doTest()
{
var opacityElement = document.getElementById("hi");
opacityElement.style.left = '100px';
document.documentElement.removeAttribute("class");
}
document.addEventListener("MozReftestInvalidate", doTest);
</script>
</body>
</html>

View File

@ -19,5 +19,5 @@ skip-if(Android) == 1428993-1.html 1428993-1-ref.html
needs-focus == 1429027-1.html 1429027-1-ref.html
== 1432553-1.html 1432553-1-ref.html
== 1432553-2.html 1432553-2-ref.html
== 1436189-1.html 1436189-1-ref.html
== 1420480-1.html 1420480-1-ref.html

View File

@ -2292,8 +2292,8 @@ HttpChannelParent::UpdateAndSerializeSecurityInfo(nsACString& aSerializedSecurit
bool
HttpChannelParent::DoSendDeleteSelf()
{
mIPCClosed = true;
bool rv = SendDeleteSelf();
mIPCClosed = true;
CleanupBackgroundChannel();