Bug 1367553: Move dirty style tracking to the StyleSet. r=heycam

MozReview-Commit-ID: 2ut8SAwNGN2

--HG--
extra : rebase_source : d9f7d7f1da7b38e595021795ee902e63746c8161
This commit is contained in:
Emilio Cobos Álvarez 2017-05-24 02:53:08 +02:00
parent 0d2aa9ed3e
commit d4ee389879
8 changed files with 157 additions and 73 deletions

View File

@ -52,7 +52,6 @@
#include "nsIContentIterator.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/Event.h" // for Event::GetEventPopupControlState()
#include "mozilla/dom/ShadowRoot.h"
#include "mozilla/dom/PointerEvent.h"
#include "nsIDocument.h"
#include "nsAnimationManager.h"
@ -784,7 +783,6 @@ nsIPresShell::nsIPresShell()
, mCanvasBackgroundColor(NS_RGBA(0,0,0,0))
, mSelectionFlags(0)
, mRenderFlags(0)
, mStylesHaveChanged(false)
, mDidInitialize(false)
, mIsDestroying(false)
, mIsReflowing(false)
@ -1544,7 +1542,6 @@ PresShell::AddUserSheet(StyleSheet* aSheet)
}
mStyleSet->EndUpdate();
RestyleForCSSRuleChanges();
}
@ -2535,8 +2532,9 @@ PresShell::EndUpdate(nsIDocument *aDocument, nsUpdateType aUpdateType)
if (aUpdateType & UPDATE_STYLE) {
mStyleSet->EndUpdate();
if (mStylesHaveChanged || !mChangedScopeStyleRoots.IsEmpty())
if (mStyleSet->StyleSheetsHaveChanged()) {
RestyleForCSSRuleChanges();
}
}
mFrameConstructor->EndUpdate();
@ -4546,17 +4544,6 @@ PresShell::ReconstructFrames()
void
nsIPresShell::RestyleForCSSRuleChanges()
{
AutoTArray<RefPtr<mozilla::dom::Element>,1> scopeRoots;
mChangedScopeStyleRoots.SwapElements(scopeRoots);
if (mStylesHaveChanged) {
// If we need to restyle everything, no need to restyle individual
// scoped style roots.
scopeRoots.Clear();
}
mStylesHaveChanged = false;
if (mIsDestroying) {
// We don't want to mess with restyles at this point
return;
@ -4568,33 +4555,12 @@ nsIPresShell::RestyleForCSSRuleChanges()
mPresContext->RebuildCounterStyles();
}
Element* root = mDocument->GetRootElement();
if (!mDidInitialize) {
// Nothing to do here, since we have no frames yet
return;
}
if (!root) {
// No content to restyle
return;
}
RestyleManager* restyleManager = mPresContext->RestyleManager();
if (scopeRoots.IsEmpty()) {
// If scopeRoots is empty, we know that mStylesHaveChanged was true at
// the beginning of this function, and that we need to restyle the whole
// document.
restyleManager->PostRestyleEventForCSSRuleChanges(root,
eRestyle_Subtree,
nsChangeHint(0));
} else {
for (Element* scopeRoot : scopeRoots) {
restyleManager->PostRestyleEventForCSSRuleChanges(scopeRoot,
eRestyle_Subtree,
nsChangeHint(0));
}
}
mStyleSet->InvalidateStyleForCSSRuleChanges();
}
void
@ -4602,27 +4568,9 @@ PresShell::RecordStyleSheetChange(StyleSheet* aStyleSheet)
{
// too bad we can't check that the update is UPDATE_STYLE
NS_ASSERTION(mUpdateCount != 0, "must be in an update");
MOZ_ASSERT(aStyleSheet->IsServo() == mStyleSet->IsServo());
if (mStylesHaveChanged)
return;
// Tell Servo that the contents of style sheets have changed.
if (ServoStyleSet* set = mStyleSet->GetAsServo()) {
set->NoteStyleSheetsChanged();
}
if (aStyleSheet->IsGecko()) {
// XXXheycam ServoStyleSheets don't support <style scoped> yet.
Element* scopeElement = aStyleSheet->AsGecko()->GetScopeElement();
if (scopeElement) {
mChangedScopeStyleRoots.AppendElement(scopeElement);
return;
}
} else {
NS_WARNING("stylo: ServoStyleSheets don't support <style scoped>");
}
mStylesHaveChanged = true;
mStyleSet->RecordStyleSheetChange(aStyleSheet);
}
void
@ -6352,7 +6300,7 @@ private:
void
PresShell::RecordShadowStyleChange(ShadowRoot* aShadowRoot)
{
mChangedScopeStyleRoots.AppendElement(aShadowRoot->GetHost()->AsElement());
mStyleSet->RecordShadowStyleChange(aShadowRoot);
}
void

View File

@ -1862,11 +1862,6 @@ protected:
// changes in a way that prevents us from being able to (usefully)
// re-use old pixels.
RenderFlags mRenderFlags;
// Indicates that the whole document must be restyled. Changes to scoped
// style sheets are recorded in mChangedScopeStyleRoots rather than here
// in mStylesHaveChanged.
bool mStylesHaveChanged : 1;
bool mDidInitialize : 1;
bool mIsDestroying : 1;
bool mIsReflowing : 1;
@ -1906,15 +1901,6 @@ protected:
uint32_t mPresShellId;
// List of subtrees rooted at style scope roots that need to be restyled.
// When a change to a scoped style sheet is made, we add the style scope
// root to this array rather than setting mStylesHaveChanged = true, since
// we know we don't need to restyle the whole document. However, if in the
// same update block we have already had other changes that require
// the whole document to be restyled (i.e., mStylesHaveChanged is already
// true), then we don't bother adding the scope root here.
AutoTArray<RefPtr<mozilla::dom::Element>,1> mChangedScopeStyleRoots;
static nsIContent* gKeyDownTarget;
// Cached font inflation values. This is done to prevent changing of font

View File

@ -125,6 +125,15 @@ ServoStyleSet::Shutdown()
mRawSet = nullptr;
}
void
ServoStyleSet::InvalidateStyleForCSSRuleChanges()
{
if (Element* root = mPresContext->Document()->GetRootElement()) {
mPresContext->RestyleManager()->PostRestyleEventForCSSRuleChanges(
root, eRestyle_Subtree, nsChangeHint(0));
}
}
size_t
ServoStyleSet::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
{

View File

@ -105,6 +105,24 @@ public:
void BeginShutdown();
void Shutdown();
void RecordStyleSheetChange(mozilla::ServoStyleSheet*)
{
NoteStyleSheetsChanged();
}
void RecordShadowStyleChange(mozilla::dom::ShadowRoot* aShadowRoot) {
// FIXME(emilio): When we properly support shadow dom we'll need to do
// better.
NoteStyleSheetsChanged();
}
bool StyleSheetsHaveChanged() const
{
return StylistNeedsUpdate();
}
void InvalidateStyleForCSSRuleChanges();
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
const RawServoStyleSet& RawSet() const { return *mRawSet; }

View File

@ -22,6 +22,7 @@ class CSSStyleSheet;
class ServoStyleSet;
namespace dom {
class Element;
class ShadowRoot;
} // namespace dom
} // namespace mozilla
class nsCSSCounterStyleRule;
@ -153,6 +154,10 @@ public:
inline StyleSheet* StyleSheetAt(SheetType aType, int32_t aIndex) const;
inline nsresult RemoveDocStyleSheet(StyleSheet* aSheet);
inline nsresult AddDocStyleSheet(StyleSheet* aSheet, nsIDocument* aDocument);
inline void RecordStyleSheetChange(StyleSheet* aSheet);
inline void RecordShadowStyleChange(mozilla::dom::ShadowRoot* aShadowRoot);
inline bool StyleSheetsHaveChanged() const;
inline void InvalidateStyleForCSSRuleChanges();
inline already_AddRefed<nsStyleContext>
ProbePseudoElementStyle(dom::Element* aParentElement,
mozilla::CSSPseudoElementType aType,

View File

@ -220,6 +220,31 @@ StyleSetHandle::Ptr::AddDocStyleSheet(StyleSheet* aSheet,
(aSheet->AsServo(), aDocument));
}
void
StyleSetHandle::Ptr::RecordStyleSheetChange(StyleSheet* aSheet)
{
FORWARD_CONCRETE(RecordStyleSheetChange, (aSheet->AsGecko()),
(aSheet->AsServo()));
}
void
StyleSetHandle::Ptr::RecordShadowStyleChange(mozilla::dom::ShadowRoot* aShadowRoot)
{
FORWARD(RecordShadowStyleChange, (aShadowRoot));
}
bool
StyleSetHandle::Ptr::StyleSheetsHaveChanged() const
{
FORWARD(StyleSheetsHaveChanged, ());
}
void
StyleSetHandle::Ptr::InvalidateStyleForCSSRuleChanges()
{
FORWARD(InvalidateStyleForCSSRuleChanges, ());
}
// check whether there is ::before/::after style for an element
already_AddRefed<nsStyleContext>
StyleSetHandle::Ptr::ProbePseudoElementStyle(dom::Element* aParentElement,

View File

@ -33,6 +33,7 @@
#include "nsAnimationManager.h"
#include "nsStyleSheetService.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/ShadowRoot.h"
#include "GeckoProfiler.h"
#include "nsHTMLCSSStyleSheet.h"
#include "nsHTMLStyleSheet.h"
@ -210,6 +211,7 @@ nsStyleSet::IsCSSSheetType(SheetType aSheetType)
nsStyleSet::nsStyleSet()
: mRuleTree(nullptr),
mBatching(0),
mStylesHaveChanged(0),
mInShutdown(false),
mInGC(false),
mAuthorStyleDisabled(false),
@ -2366,6 +2368,68 @@ nsStyleSet::Shutdown()
MOZ_ASSERT(mUnusedRuleNodeCount == 0);
}
void
nsStyleSet::RecordStyleSheetChange(CSSStyleSheet* aStyleSheet)
{
MOZ_ASSERT(mBatching != 0, "Should be in an update");
if (mStylesHaveChanged) {
return;
}
if (Element* scopeElement = aStyleSheet->GetScopeElement()) {
mChangedScopeStyleRoots.AppendElement(scopeElement);
return;
}
mStylesHaveChanged = true;
// If we need to restyle everything, no need to restyle individual
// scoped style roots.
mChangedScopeStyleRoots.Clear();
}
void
nsStyleSet::RecordShadowStyleChange(ShadowRoot* aShadowRoot)
{
if (mStylesHaveChanged) {
return;
}
mChangedScopeStyleRoots.AppendElement(aShadowRoot->GetHost()->AsElement());
}
void
nsStyleSet::InvalidateStyleForCSSRuleChanges()
{
MOZ_ASSERT_IF(mStylesHaveChanged, mChangedScopeStyleRoots.IsEmpty());
AutoTArray<RefPtr<mozilla::dom::Element>, 1> scopeRoots;
mChangedScopeStyleRoots.SwapElements(scopeRoots);
mStylesHaveChanged = false;
nsPresContext* presContext = PresContext();
RestyleManager* restyleManager = presContext->RestyleManager();
Element* root = presContext->Document()->GetRootElement();
if (!root) {
// No content to restyle
return;
}
if (scopeRoots.IsEmpty()) {
// If scopeRoots is empty, we know that mStylesHaveChanged was true at
// the beginning of this function, and that we need to restyle the whole
// document.
restyleManager->PostRestyleEventForCSSRuleChanges(root,
eRestyle_Subtree,
nsChangeHint(0));
} else {
for (Element* scopeRoot : scopeRoots) {
restyleManager->PostRestyleEventForCSSRuleChanges(scopeRoot,
eRestyle_Subtree,
nsChangeHint(0));
}
}
}
void
nsStyleSet::GCRuleTrees()

View File

@ -41,8 +41,11 @@ struct TreeMatchContext;
namespace mozilla {
class CSSStyleSheet;
class EventStates;
enum class CSSPseudoElementType : uint8_t;
class EventStates;
namespace dom {
class ShadowRoot;
} // namespace dom
} // namespace mozilla
class nsEmptyStyleRule final : public nsIStyleRule
@ -329,6 +332,19 @@ class nsStyleSet final
// Free all of the data associated with this style set.
void Shutdown();
// Notes that a style sheet has changed.
void RecordStyleSheetChange(mozilla::CSSStyleSheet* aStyleSheet);
// Notes that style sheets have changed in a shadow root.
void RecordShadowStyleChange(mozilla::dom::ShadowRoot* aShadowRoot);
bool StyleSheetsHaveChanged() const
{
return mStylesHaveChanged || !mChangedScopeStyleRoots.IsEmpty();
}
void InvalidateStyleForCSSRuleChanges();
// Get a new style context that lives in a different parent
// The new context will be the same as the old if the new parent is the
// same as the old parent.
@ -603,8 +619,21 @@ private:
// lexicographic tree of matched rules that style
// contexts use to look up properties.
// List of subtrees rooted at style scope roots that need to be restyled.
// When a change to a scoped style sheet is made, we add the style scope
// root to this array rather than setting mStylesHaveChanged = true, since
// we know we don't need to restyle the whole document. However, if in the
// same update block we have already had other changes that require
// the whole document to be restyled (i.e., mStylesHaveChanged is already
// true), then we don't bother adding the scope root here.
AutoTArray<RefPtr<mozilla::dom::Element>,1> mChangedScopeStyleRoots;
uint16_t mBatching;
// Indicates that the whole document must be restyled. Changes to scoped
// style sheets are recorded in mChangedScopeStyleRoots rather than here
// in mStylesHaveChanged.
unsigned mStylesHaveChanged : 1;
unsigned mInShutdown : 1;
unsigned mInGC : 1;
unsigned mAuthorStyleDisabled: 1;