From c6d52eae0d80c7884e7ce3344825dd9affd56b86 Mon Sep 17 00:00:00 2001 From: Cameron McCormack Date: Thu, 17 Sep 2015 12:08:20 +1000 Subject: [PATCH] Bug 1203766 - Part 6: Cache resolved style contexts on nsComputedDOMStyle to avoid re-resolving if styles haven't changed. r=bzbarsky --- layout/style/nsComputedDOMStyle.cpp | 43 +++++++++++++++++++++++++---- layout/style/nsComputedDOMStyle.h | 35 +++++++++++++++++++---- 2 files changed, 67 insertions(+), 11 deletions(-) diff --git a/layout/style/nsComputedDOMStyle.cpp b/layout/style/nsComputedDOMStyle.cpp index 50a5a7461cc8..68e3b4053b33 100644 --- a/layout/style/nsComputedDOMStyle.cpp +++ b/layout/style/nsComputedDOMStyle.cpp @@ -222,7 +222,9 @@ nsComputedDOMStyle::nsComputedDOMStyle(dom::Element* aElement, : mDocumentWeak(nullptr), mOuterFrame(nullptr), mInnerFrame(nullptr), mPresShell(nullptr), mStyleType(aStyleType), - mExposeVisitedStyle(false) + mStyleContextGeneration(0), + mExposeVisitedStyle(false), + mResolvedStyleContext(false) { MOZ_ASSERT(aElement && aPresShell); @@ -572,10 +574,10 @@ nsComputedDOMStyle::GetCSSParsingEnvironment(CSSParsingEnvironment& aCSSParseEnv void nsComputedDOMStyle::UpdateCurrentStyleSources(bool aNeedsLayoutFlush) { - MOZ_ASSERT(!mStyleContext); - nsCOMPtr document = do_QueryReferent(mDocumentWeak); if (!document) { + mResolvedStyleContext = false; + mStyleContext = nullptr; return; } @@ -593,9 +595,24 @@ nsComputedDOMStyle::UpdateCurrentStyleSources(bool aNeedsLayoutFlush) mPresShell = document->GetShell(); if (!mPresShell || !mPresShell->GetPresContext()) { + mResolvedStyleContext = false; + mStyleContext = nullptr; return; } + uint64_t currentGeneration = + mPresShell->GetPresContext()->GetRestyleGeneration(); + + if (mStyleContext) { + if (mStyleContextGeneration == currentGeneration) { + // Our cached style context is still valid. + return; + } + // We've processed some restyles, so the cached style context might + // be out of date. + mStyleContext = nullptr; + } + // XXX the !mContent->IsHTMLElement(nsGkAtoms::area) // check is needed due to bug 135040 (to avoid using // mPrimaryFrame). Remove it once that's fixed. @@ -616,6 +633,7 @@ nsComputedDOMStyle::UpdateCurrentStyleSources(bool aNeedsLayoutFlush) } mStyleContext = mInnerFrame->StyleContext(); + mResolvedStyleContext = false; NS_ASSERTION(mStyleContext, "Frame without style context?"); } } @@ -649,9 +667,19 @@ nsComputedDOMStyle::UpdateCurrentStyleSources(bool aNeedsLayoutFlush) mPresShell, mStyleType); if (!mStyleContext) { + mResolvedStyleContext = false; return; } + // No need to re-get the generation, even though GetStyleContextForElement + // will flush, since we flushed style at the top of this function. + NS_ASSERTION(mPresShell && + currentGeneration == + mPresShell->GetPresContext()->GetRestyleGeneration(), + "why should we have flushed style again?"); + + mResolvedStyleContext = true; + mStyleContextGeneration = currentGeneration; NS_ASSERTION(mPseudo || !mStyleContext->HasPseudoElementData(), "should not have pseudo-element data"); } @@ -675,9 +703,12 @@ nsComputedDOMStyle::ClearCurrentStyleSources() mInnerFrame = nullptr; mPresShell = nullptr; - // Release the current style context for it should be re-resolved - // whenever a frame is not available. - mStyleContext = nullptr; + // Release the current style context if we got it off the frame. + // For a style context we resolved, keep it around so that we + // can re-use it next time this object is queried. + if (!mResolvedStyleContext) { + mStyleContext = nullptr; + } } already_AddRefed diff --git a/layout/style/nsComputedDOMStyle.h b/layout/style/nsComputedDOMStyle.h index 9d8fcc422394..b8e40cfc8eec 100644 --- a/layout/style/nsComputedDOMStyle.h +++ b/layout/style/nsComputedDOMStyle.h @@ -9,6 +9,8 @@ #define nsComputedDOMStyle_h__ #include "nsAutoPtr.h" +#include "mozilla/ArenaRefPtr.h" +#include "mozilla/ArenaRefPtrInlines.h" #include "mozilla/Attributes.h" #include "nsCOMPtr.h" #include "nscore.h" @@ -595,12 +597,23 @@ private: nsWeakPtr mDocumentWeak; nsCOMPtr mContent; - /* - * Strong reference to the style context while we're accessing the data from - * it. This can be either a style context we resolved ourselves or a style - * context we got from our frame. + /** + * Strong reference to the style context we access data from. This can be + * either a style context we resolved ourselves or a style context we got + * from our frame. + * + * If we got the style context from the frame, we clear out mStyleContext + * in ClearCurrentStyleSources. If we resolved one ourselves, then + * ClearCurrentStyleSources leaves it in mStyleContext for use the next + * time this nsComputedDOMStyle object is queried. UpdateCurrentStyleSources + * in this case will check that the style context is still valid to be used, + * by checking whether flush styles results in any restyles having been + * processed. + * + * Since an ArenaRefPtr is used to hold the style context, it will be cleared + * if the pres arena from which it was allocated goes away. */ - nsRefPtr mStyleContext; + mozilla::ArenaRefPtr mStyleContext; nsCOMPtr mPseudo; /* @@ -626,8 +639,20 @@ private: */ StyleType mStyleType; + /** + * The nsComputedDOMStyle generation at the time we last resolved a style + * context and stored it in mStyleContext. + */ + uint64_t mStyleContextGeneration; + bool mExposeVisitedStyle; + /** + * Whether we resolved a style context last time we called + * UpdateCurrentStyleSources. Initially false. + */ + bool mResolvedStyleContext; + #ifdef DEBUG bool mFlushedPendingReflows; #endif