зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1363805 - Part 3: Do lazy flushing if possible. r=heycam
Skips flushing current document if the target of getComputedDOMStyle cannot be affected by any pending restyles. MozReview-Commit-ID: C87HDIDvOth --HG-- extra : rebase_source : 064880493f9aac2599689cdd0749200bb579c60b
This commit is contained in:
Родитель
619e849e4c
Коммит
f3f406f76b
|
@ -569,6 +569,20 @@ EffectCompositor::HasThrottledStyleUpdates() const
|
|||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
EffectCompositor::HasPendingStyleUpdatesFor(Element* aElement) const
|
||||
{
|
||||
for (auto& elementSet : mElementsToRestyle) {
|
||||
for (auto iter = elementSet.ConstIter(); !iter.Done(); iter.Next()) {
|
||||
if (iter.Key().mElement->Contains(aElement)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
EffectCompositor::AddStyleUpdatesTo(RestyleTracker& aTracker)
|
||||
{
|
||||
|
|
|
@ -168,6 +168,7 @@ public:
|
|||
|
||||
bool HasPendingStyleUpdates() const;
|
||||
bool HasThrottledStyleUpdates() const;
|
||||
bool HasPendingStyleUpdatesFor(dom::Element* aElement) const;
|
||||
|
||||
// Tell the restyle tracker about all the animated styles that have
|
||||
// pending updates so that it can update the animation rule for these
|
||||
|
|
|
@ -3651,6 +3651,12 @@ GeckoRestyleManager::ComputeAndProcessStyleChange(
|
|||
ClearCachedInheritedStyleDataOnDescendants(contextsToClear);
|
||||
}
|
||||
|
||||
bool
|
||||
GeckoRestyleManager::HasPendingRestyles() const
|
||||
{
|
||||
return mPendingRestyles.Count() != 0;
|
||||
}
|
||||
|
||||
nsStyleSet*
|
||||
ElementRestyler::StyleSet() const
|
||||
{
|
||||
|
|
|
@ -345,6 +345,7 @@ public:
|
|||
#endif
|
||||
|
||||
bool IsProcessingRestyles() { return mIsProcessingRestyles; }
|
||||
bool HasPendingRestyles() const;
|
||||
|
||||
private:
|
||||
inline nsStyleSet* StyleSet() const {
|
||||
|
|
|
@ -1196,11 +1196,16 @@ ServoRestyleManager::ProcessPendingRestyles()
|
|||
void
|
||||
ServoRestyleManager::ProcessAllPendingAttributeAndStateInvalidations()
|
||||
{
|
||||
AutoTimelineMarker marker(mPresContext->GetDocShell(),
|
||||
"ProcessAllPendingAttributeAndStateInvalidations");
|
||||
if (mSnapshots.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
for (auto iter = mSnapshots.Iter(); !iter.Done(); iter.Next()) {
|
||||
// Servo data for the element might have been dropped. (e.g. by removing
|
||||
// from its document)
|
||||
if (iter.Key()->HasFlag(ELEMENT_HAS_SNAPSHOT)) {
|
||||
Servo_ProcessInvalidations(StyleSet()->RawSet(), iter.Key(), &mSnapshots);
|
||||
}
|
||||
}
|
||||
ClearSnapshots();
|
||||
}
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "mozilla/StyleSetHandle.h"
|
||||
#include "mozilla/StyleSetHandleInlines.h"
|
||||
#include "mozilla/GeckoRestyleManager.h"
|
||||
#include "mozilla/ServoRestyleManager.h"
|
||||
#include "mozilla/RestyleManagerInlines.h"
|
||||
#include "imgIRequest.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
|
@ -101,6 +102,71 @@ GetBackgroundList(T nsStyleImageLayers::Layer::* aMember,
|
|||
return valueList.forget();
|
||||
}
|
||||
|
||||
// Whether there is any pending restyle for the element or any of its ancestors.
|
||||
static bool
|
||||
ContentNeedsRestyle(nsIContent* aContent)
|
||||
{
|
||||
MOZ_ASSERT(aContent);
|
||||
nsIContent* node = aContent;
|
||||
while (node) {
|
||||
// Check if the element has any flag for restyling. For Gecko, we also need
|
||||
// another flag to know if there is any child has LaterSiblings restyle
|
||||
// hint.
|
||||
if (node->HasFlag(ELEMENT_ALL_RESTYLE_FLAGS |
|
||||
ELEMENT_HAS_CHILD_WITH_LATER_SIBLINGS_HINT)) {
|
||||
return true;
|
||||
}
|
||||
node = node->GetFlattenedTreeParent();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Whether aDocument needs to restyle for aElement
|
||||
static bool
|
||||
DocumentNeedsRestyle(const nsIDocument* aDocument, Element* aElement)
|
||||
{
|
||||
nsIPresShell* shell = aDocument->GetShell();
|
||||
if (!shell) {
|
||||
return true;
|
||||
}
|
||||
// Unfortunately we don't know if the sheet change affects mContent or not, so
|
||||
// just assume it will and that we need to flush normally.
|
||||
StyleSetHandle styleSet = shell->StyleSet();
|
||||
if (styleSet->StyleSheetsHaveChanged()) {
|
||||
return true;
|
||||
}
|
||||
// If any ancestor has pending animation, flush it.
|
||||
nsPresContext* context = shell->GetPresContext();
|
||||
if (context->EffectCompositor()->HasPendingStyleUpdatesFor(aElement)) {
|
||||
return true;
|
||||
}
|
||||
if (styleSet->IsServo()) {
|
||||
// For Servo, we need to process the restyle-hint-invalidations first, to
|
||||
// expand LaterSiblings hint, so that we can look whether ancestors need
|
||||
// restyling.
|
||||
ServoRestyleManager* restyleManager = context->RestyleManager()->AsServo();
|
||||
restyleManager->ProcessAllPendingAttributeAndStateInvalidations();
|
||||
|
||||
// Then if there is a restyle root, we check if the root is an ancestor of
|
||||
// this content. If it is not, then we don't need to restyle immediately.
|
||||
// Note this is different from Gecko: we only check if any ancestor needs
|
||||
// to restyle _itself_, not descendants, since dirty descendants can be
|
||||
// another subtree.
|
||||
if (aDocument->GetServoRestyleRoot() &&
|
||||
restyleManager->HasPendingRestyleAncestor(aElement)) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
// For Gecko, first check if there is any pending restyle, then we check if
|
||||
// any ancestor has dirty bits for restyle.
|
||||
GeckoRestyleManager* restyleManager = context->RestyleManager()->AsGecko();
|
||||
if (restyleManager->HasPendingRestyles() && ContentNeedsRestyle(aElement)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* An object that represents the ordered set of properties that are exposed on
|
||||
* an nsComputedDOMStyle object and how their computed values can be obtained.
|
||||
|
@ -807,6 +873,32 @@ nsComputedDOMStyle::SetFrameStyleContext(nsStyleContext* aContext,
|
|||
mStyleContextGeneration = aGeneration;
|
||||
}
|
||||
|
||||
FlushTarget
|
||||
nsComputedDOMStyle::GetFlushTarget(nsIDocument* aDocument) const
|
||||
{
|
||||
// If mContent is not in the same document, we could do some checks to know if
|
||||
// there are some pending restyles can be ignored across documents (since we
|
||||
// will use the caller document's style), but it can be complicated and should
|
||||
// be an edge case, so we just don't bother to do the optimization in this
|
||||
// case.
|
||||
if (aDocument != mContent->OwnerDoc()) {
|
||||
return FlushTarget::Normal;
|
||||
}
|
||||
if (DocumentNeedsRestyle(aDocument, mContent->AsElement())) {
|
||||
return FlushTarget::Normal;
|
||||
}
|
||||
// If parent document is there, also needs to check if there is some change
|
||||
// that needs to flush this document (e.g. size change for iframe).
|
||||
while (nsIDocument* parentDocument = aDocument->GetParentDocument()) {
|
||||
Element* element = parentDocument->FindContentForSubDocument(aDocument);
|
||||
if (DocumentNeedsRestyle(parentDocument, element)) {
|
||||
return FlushTarget::Normal;
|
||||
}
|
||||
aDocument = parentDocument;
|
||||
}
|
||||
return FlushTarget::ParentOnly;
|
||||
}
|
||||
|
||||
void
|
||||
nsComputedDOMStyle::UpdateCurrentStyleSources(bool aNeedsLayoutFlush)
|
||||
{
|
||||
|
@ -816,12 +908,15 @@ nsComputedDOMStyle::UpdateCurrentStyleSources(bool aNeedsLayoutFlush)
|
|||
return;
|
||||
}
|
||||
|
||||
// If the property we are computing relies on layout, then we must flush.
|
||||
FlushTarget target = aNeedsLayoutFlush ? FlushTarget::Normal : GetFlushTarget(document);
|
||||
|
||||
// Flush _before_ getting the presshell, since that could create a new
|
||||
// presshell. Also note that we want to flush the style on the document
|
||||
// we're computing style in, not on the document mContent is in -- the two
|
||||
// may be different.
|
||||
document->FlushPendingNotifications(
|
||||
aNeedsLayoutFlush ? FlushType::Layout : FlushType::Style);
|
||||
aNeedsLayoutFlush ? FlushType::Layout : FlushType::Style, target);
|
||||
#ifdef DEBUG
|
||||
mFlushedPendingReflows = aNeedsLayoutFlush;
|
||||
#endif
|
||||
|
@ -933,9 +1028,11 @@ nsComputedDOMStyle::UpdateCurrentStyleSources(bool aNeedsLayoutFlush)
|
|||
|
||||
// No need to re-get the generation, even though GetStyleContext
|
||||
// will flush, since we flushed style at the top of this function.
|
||||
NS_ASSERTION(mPresShell &&
|
||||
// We don't need to check this if we only flushed the parent.
|
||||
NS_ASSERTION(target == FlushTarget::ParentOnly ||
|
||||
(mPresShell &&
|
||||
currentGeneration ==
|
||||
mPresShell->GetPresContext()->GetUndisplayedRestyleGeneration(),
|
||||
mPresShell->GetPresContext()->GetUndisplayedRestyleGeneration()),
|
||||
"why should we have flushed style again?");
|
||||
|
||||
SetResolvedStyleContext(Move(resolvedStyleContext), currentGeneration);
|
||||
|
|
|
@ -715,6 +715,10 @@ private:
|
|||
void BasicShapeRadiiToString(nsAString& aCssText,
|
||||
const nsStyleCorners& aCorners);
|
||||
|
||||
// Find out if we can safely skip flushing for aDocument (i.e. pending
|
||||
// restyles does not affect mContent).
|
||||
mozilla::FlushTarget GetFlushTarget(nsIDocument* aDocument) const;
|
||||
|
||||
|
||||
static nsComputedStyleMap* GetComputedStyleMap();
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче