зеркало из https://github.com/mozilla/gecko-dev.git
Bug 961871 - Part 4: Fix budget calculation by adding Maybe prerenderer and animate. r=roc
This commit is contained in:
Родитель
584ac95d49
Коммит
1eda179306
|
@ -259,6 +259,12 @@ ActiveLayerTracker::NotifyInlineStyleRuleModified(nsIFrame* aFrame,
|
|||
NotifyAnimated(aFrame, aProperty);
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
ActiveLayerTracker::IsStyleMaybeAnimated(nsIFrame* aFrame, nsCSSProperty aProperty)
|
||||
{
|
||||
return IsStyleAnimated(nullptr, aFrame, aProperty);
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
ActiveLayerTracker::IsStyleAnimated(nsDisplayListBuilder* aBuilder,
|
||||
nsIFrame* aFrame, nsCSSProperty aProperty)
|
||||
|
@ -266,12 +272,12 @@ ActiveLayerTracker::IsStyleAnimated(nsDisplayListBuilder* aBuilder,
|
|||
// TODO: Add some abuse restrictions
|
||||
if ((aFrame->StyleDisplay()->mWillChangeBitField & NS_STYLE_WILL_CHANGE_TRANSFORM) &&
|
||||
aProperty == eCSSProperty_transform &&
|
||||
aBuilder->IsInWillChangeBudget(aFrame)) {
|
||||
(!aBuilder || aBuilder->IsInWillChangeBudget(aFrame))) {
|
||||
return true;
|
||||
}
|
||||
if ((aFrame->StyleDisplay()->mWillChangeBitField & NS_STYLE_WILL_CHANGE_OPACITY) &&
|
||||
aProperty == eCSSProperty_opacity &&
|
||||
aBuilder->IsInWillChangeBudget(aFrame)) {
|
||||
(!aBuilder || aBuilder->IsInWillChangeBudget(aFrame))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -56,6 +56,11 @@ public:
|
|||
* style will trigger this.
|
||||
*/
|
||||
static void NotifyInlineStyleRuleModified(nsIFrame* aFrame, nsCSSProperty aProperty);
|
||||
/**
|
||||
* Return true if aFrame's aProperty style should be considered as being animated
|
||||
* for pre-rendering.
|
||||
*/
|
||||
static bool IsStyleMaybeAnimated(nsIFrame* aFrame, nsCSSProperty aProperty);
|
||||
/**
|
||||
* Return true if aFrame's aProperty style should be considered as being animated
|
||||
* for constructing active layers.
|
||||
|
|
|
@ -2804,7 +2804,7 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList)
|
|||
nsIntRect itemDrawRect = ScaleToOutsidePixels(itemContent, snap);
|
||||
nsDisplayItem::Type itemType = item->GetType();
|
||||
bool prerenderedTransform = itemType == nsDisplayItem::TYPE_TRANSFORM &&
|
||||
static_cast<nsDisplayTransform*>(item)->ShouldPrerender();
|
||||
static_cast<nsDisplayTransform*>(item)->ShouldPrerender(mBuilder);
|
||||
nsIntRect clipRect;
|
||||
const DisplayItemClip& itemClip = item->GetClip();
|
||||
if (itemClip.HasClip()) {
|
||||
|
|
|
@ -525,6 +525,7 @@ nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame,
|
|||
mCurrentTableItem(nullptr),
|
||||
mCurrentFrame(aReferenceFrame),
|
||||
mCurrentReferenceFrame(aReferenceFrame),
|
||||
mWillChangeBudgetCalculated(false),
|
||||
mDirtyRect(-1,-1,-1,-1),
|
||||
mGlassDisplayItem(nullptr),
|
||||
mMode(aMode),
|
||||
|
@ -1111,6 +1112,11 @@ nsDisplayListBuilder::AdjustWindowDraggingRegion(nsIFrame* aFrame)
|
|||
|
||||
void
|
||||
nsDisplayListBuilder::AddToWillChangeBudget(nsIFrame* aFrame, const nsSize& aRect) {
|
||||
// Make sure that we don't query the budget before the display list is fully
|
||||
// built and that the will change budget is locked in.
|
||||
MOZ_ASSERT(!mWillChangeBudgetCalculated,
|
||||
"Can't modify the budget once it's been used.");
|
||||
|
||||
DocumentWillChangeBudget budget;
|
||||
|
||||
nsPresContext* key = aFrame->PresContext();
|
||||
|
@ -1133,6 +1139,8 @@ nsDisplayListBuilder::AddToWillChangeBudget(nsIFrame* aFrame, const nsSize& aRec
|
|||
|
||||
bool
|
||||
nsDisplayListBuilder::IsInWillChangeBudget(nsIFrame* aFrame) const {
|
||||
mWillChangeBudgetCalculated = true;
|
||||
|
||||
nsPresContext* key = aFrame->PresContext();
|
||||
if (!mWillChangeBudget.Contains(key)) {
|
||||
MOZ_ASSERT(false, "If we added nothing to our budget then this "
|
||||
|
@ -4544,8 +4552,15 @@ nsDisplayTransform::Init(nsDisplayListBuilder* aBuilder)
|
|||
{
|
||||
mStoredList.SetClip(aBuilder, DisplayItemClip::NoClip());
|
||||
mStoredList.SetVisibleRect(mChildrenVisibleRect);
|
||||
mPrerender = ShouldPrerenderTransformedContent(aBuilder, mFrame);
|
||||
if (mPrerender) {
|
||||
mMaybePrerender = ShouldPrerenderTransformedContent(aBuilder, mFrame);
|
||||
|
||||
const nsStyleDisplay* disp = mFrame->StyleDisplay();
|
||||
if ((disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_TRANSFORM)) {
|
||||
// We will only pre-render if this will-change is on budget.
|
||||
mMaybePrerender = true;
|
||||
}
|
||||
|
||||
if (mMaybePrerender) {
|
||||
bool snap;
|
||||
mVisibleRect = GetBounds(aBuilder, &snap);
|
||||
}
|
||||
|
@ -4905,10 +4920,31 @@ nsDisplayOpacity::CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
nsDisplayTransform::ShouldPrerender(nsDisplayListBuilder* aBuilder) {
|
||||
if (!mMaybePrerender) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ShouldPrerenderTransformedContent(aBuilder, mFrame)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const nsStyleDisplay* disp = mFrame->StyleDisplay();
|
||||
if ((disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_TRANSFORM) &&
|
||||
aBuilder->IsInWillChangeBudget(mFrame)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
nsDisplayTransform::CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder)
|
||||
{
|
||||
if (mPrerender) {
|
||||
if (mMaybePrerender) {
|
||||
// TODO We need to make sure that if we use async animation we actually
|
||||
// pre-render even if we're out of will change budget.
|
||||
return true;
|
||||
}
|
||||
DebugOnly<bool> prerender = ShouldPrerenderTransformedContent(aBuilder, mFrame, true);
|
||||
|
@ -4925,7 +4961,7 @@ nsDisplayTransform::ShouldPrerenderTransformedContent(nsDisplayListBuilder* aBui
|
|||
// have a compositor-animated transform, can be prerendered. An element
|
||||
// might have only just had its transform animated in which case
|
||||
// the ActiveLayerManager may not have been notified yet.
|
||||
if (!ActiveLayerTracker::IsStyleAnimated(aBuilder, aFrame, eCSSProperty_transform) &&
|
||||
if (!ActiveLayerTracker::IsStyleMaybeAnimated(aFrame, eCSSProperty_transform) &&
|
||||
(!aFrame->GetContent() ||
|
||||
!nsLayoutUtils::HasAnimationsForCompositor(aFrame->GetContent(),
|
||||
eCSSProperty_transform))) {
|
||||
|
@ -5023,7 +5059,7 @@ nsDisplayTransform::GetTransform()
|
|||
bool
|
||||
nsDisplayTransform::ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder)
|
||||
{
|
||||
return ShouldPrerender();
|
||||
return ShouldPrerender(aBuilder);
|
||||
}
|
||||
|
||||
already_AddRefed<Layer> nsDisplayTransform::BuildLayer(nsDisplayListBuilder *aBuilder,
|
||||
|
@ -5037,7 +5073,7 @@ already_AddRefed<Layer> nsDisplayTransform::BuildLayer(nsDisplayListBuilder *aBu
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
uint32_t flags = ShouldPrerender() ?
|
||||
uint32_t flags = ShouldPrerender(aBuilder) ?
|
||||
FrameLayerBuilder::CONTAINER_NOT_CLIPPED_BY_ANCESTORS : 0;
|
||||
nsRefPtr<ContainerLayer> container = aManager->GetLayerBuilder()->
|
||||
BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mStoredList.GetChildren(),
|
||||
|
@ -5058,7 +5094,7 @@ already_AddRefed<Layer> nsDisplayTransform::BuildLayer(nsDisplayListBuilder *aBu
|
|||
nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer(container, aBuilder,
|
||||
this, mFrame,
|
||||
eCSSProperty_transform);
|
||||
if (ShouldPrerender()) {
|
||||
if (ShouldPrerender(aBuilder)) {
|
||||
container->SetUserData(nsIFrame::LayerIsPrerenderedDataKey(),
|
||||
/*the value is irrelevant*/nullptr);
|
||||
container->SetContentFlags(container->GetContentFlags() | Layer::CONTENT_MAY_CHANGE_TRANSFORM);
|
||||
|
@ -5111,7 +5147,7 @@ bool nsDisplayTransform::ComputeVisibility(nsDisplayListBuilder *aBuilder,
|
|||
* think that it's painting in its original rectangular coordinate space.
|
||||
* If we can't untransform, take the entire overflow rect */
|
||||
nsRect untransformedVisibleRect;
|
||||
if (ShouldPrerender() ||
|
||||
if (ShouldPrerender(aBuilder) ||
|
||||
!UntransformVisibleRect(aBuilder, &untransformedVisibleRect))
|
||||
{
|
||||
untransformedVisibleRect = mFrame->GetVisualOverflowRectRelativeToSelf();
|
||||
|
@ -5241,7 +5277,7 @@ nsDisplayTransform::GetHitDepthAtPoint(nsDisplayListBuilder* aBuilder, const nsP
|
|||
*/
|
||||
nsRect nsDisplayTransform::GetBounds(nsDisplayListBuilder *aBuilder, bool* aSnap)
|
||||
{
|
||||
nsRect untransformedBounds = ShouldPrerender() ?
|
||||
nsRect untransformedBounds = MaybePrerender() ?
|
||||
mFrame->GetVisualOverflowRectRelativeToSelf() :
|
||||
mStoredList.GetBounds(aBuilder, aSnap);
|
||||
*aSnap = false;
|
||||
|
@ -5279,7 +5315,7 @@ nsRegion nsDisplayTransform::GetOpaqueRegion(nsDisplayListBuilder *aBuilder,
|
|||
// covers the entire window, but it allows our transform to be
|
||||
// updated extremely cheaply, without invalidating any other
|
||||
// content.
|
||||
if (ShouldPrerender() ||
|
||||
if (MaybePrerender() ||
|
||||
!UntransformVisibleRect(aBuilder, &untransformedVisible)) {
|
||||
return nsRegion();
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#define NSDISPLAYLIST_H_
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsContainerFrame.h"
|
||||
#include "nsPoint.h"
|
||||
|
@ -778,6 +779,8 @@ private:
|
|||
// will-change budget tracker
|
||||
nsDataHashtable<nsPtrHashKey<nsPresContext>, DocumentWillChangeBudget>
|
||||
mWillChangeBudget;
|
||||
// Assert that we never check the budget before its fully calculated.
|
||||
mutable mozilla::DebugOnly<bool> mWillChangeBudgetCalculated;
|
||||
// Relative to mCurrentFrame.
|
||||
nsRect mDirtyRect;
|
||||
nsRegion mWindowOpaqueRegion;
|
||||
|
@ -3464,7 +3467,16 @@ public:
|
|||
bool aLogAnimations = false);
|
||||
bool CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE;
|
||||
|
||||
bool ShouldPrerender() const { return mPrerender; }
|
||||
/**
|
||||
* This will return if it's possible for this element to be prerendered.
|
||||
* This should never return false if we're going to prerender.
|
||||
*/
|
||||
bool MaybePrerender() const { return mMaybePrerender; }
|
||||
/**
|
||||
* Check if this element will be prerendered. This must be done after the
|
||||
* display list has been fully built.
|
||||
*/
|
||||
bool ShouldPrerender(nsDisplayListBuilder* aBuilder);
|
||||
|
||||
#ifdef MOZ_DUMP_PAINTING
|
||||
virtual void WriteDebugInfo(nsACString& aTo) MOZ_OVERRIDE;
|
||||
|
@ -3486,7 +3498,9 @@ private:
|
|||
ComputeTransformFunction mTransformGetter;
|
||||
nsRect mChildrenVisibleRect;
|
||||
uint32_t mIndex;
|
||||
bool mPrerender;
|
||||
// We wont know if we pre-render until the layer building phase where we can
|
||||
// check layers will-change budget.
|
||||
bool mMaybePrerender;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -2546,7 +2546,10 @@ ScrollFrameHelper::AppendScrollPartsTo(nsDisplayListBuilder* aBuilder,
|
|||
return;
|
||||
}
|
||||
|
||||
mozilla::layers::FrameMetrics::ViewID scrollTargetId = IsScrollingActive(aBuilder)
|
||||
// We can't check will-change budget during display list building phase.
|
||||
// This means that we will build scroll bar layers for out of budget
|
||||
// will-change: scroll position.
|
||||
mozilla::layers::FrameMetrics::ViewID scrollTargetId = IsMaybeScrollingActive()
|
||||
? nsLayoutUtils::FindOrCreateIDFor(mScrolledFrame->GetContent())
|
||||
: mozilla::layers::FrameMetrics::NULL_SCROLL_ID;
|
||||
|
||||
|
@ -2765,10 +2768,10 @@ ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
|||
|
||||
if (aBuilder->IsPaintingToWindow()) {
|
||||
mScrollPosAtLastPaint = GetScrollPosition();
|
||||
if (IsScrollingActive(aBuilder) && NeedToInvalidateOnScroll(mOuter)) {
|
||||
if (IsMaybeScrollingActive() && NeedToInvalidateOnScroll(mOuter)) {
|
||||
MarkNotRecentlyScrolled();
|
||||
}
|
||||
if (IsScrollingActive(aBuilder)) {
|
||||
if (IsMaybeScrollingActive()) {
|
||||
if (mScrollPosForLayerPixelAlignment == nsPoint(-1,-1)) {
|
||||
mScrollPosForLayerPixelAlignment = mScrollPosAtLastPaint;
|
||||
}
|
||||
|
@ -2875,6 +2878,11 @@ ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
|||
dirtyRect = ExpandRectToNearlyVisible(dirtyRect);
|
||||
}
|
||||
|
||||
const nsStyleDisplay* disp = mOuter->StyleDisplay();
|
||||
if (disp && (disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_SCROLL)) {
|
||||
aBuilder->AddToWillChangeBudget(mOuter, GetScrollPositionClampingScrollPortSize());
|
||||
}
|
||||
|
||||
// Since making new layers is expensive, only use nsDisplayScrollLayer
|
||||
// if the area is scrollable and we're the content process (unless we're on
|
||||
// B2G, where we support async scrolling for scrollable elements in the
|
||||
|
@ -2896,11 +2904,6 @@ ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
|||
// info layer to make a ComputeFrameMetrics call for us as
|
||||
// nsDisplayList::PaintForFrame already calls ComputeFrameMetrics for us.
|
||||
(!mIsRoot || aBuilder->RootReferenceFrame()->PresContext() != mOuter->PresContext());
|
||||
|
||||
const nsStyleDisplay* disp = mOuter->StyleDisplay();
|
||||
bool willScroll = disp && (disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_SCROLL) &&
|
||||
aBuilder->IsInWillChangeBudget(mOuter);
|
||||
shouldBuildLayer |= willScroll;
|
||||
}
|
||||
|
||||
mScrollParentID = aBuilder->GetCurrentScrollParentId();
|
||||
|
@ -4125,6 +4128,19 @@ ScrollFrameHelper::IsScrollbarOnRight() const
|
|||
}
|
||||
}
|
||||
|
||||
bool
|
||||
ScrollFrameHelper::IsMaybeScrollingActive() const
|
||||
{
|
||||
const nsStyleDisplay* disp = mOuter->StyleDisplay();
|
||||
if (disp && (disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_SCROLL)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return mHasBeenScrolledRecently ||
|
||||
IsAlwaysActive() ||
|
||||
mShouldBuildScrollableLayer;
|
||||
}
|
||||
|
||||
bool
|
||||
ScrollFrameHelper::IsScrollingActive(nsDisplayListBuilder* aBuilder) const
|
||||
{
|
||||
|
|
|
@ -285,6 +285,7 @@ public:
|
|||
bool IsLTR() const;
|
||||
bool IsScrollbarOnRight() const;
|
||||
bool IsScrollingActive(nsDisplayListBuilder* aBuilder) const;
|
||||
bool IsMaybeScrollingActive() const;
|
||||
bool IsProcessingAsyncScroll() const {
|
||||
return mAsyncScroll != nullptr || mAsyncSmoothMSDScroll != nullptr;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче