Bug 1358495 - Part 2: Implement window.getComputedStyleWithoutFlushing. r?heycam
Added FlushingFlag into mozilla::layout instead of nsComputedDOMStyle, because
including nsComputedDOMStyle.h in nsGlobalWindow.h will cause problems in
unified build.
MozReview-Commit-ID: 9FsyZxO7jWv
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -280,16 +280,17 @@ static const char kStorageEnabled[] = "d
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::dom::ipc;
using mozilla::BasePrincipal;
using mozilla::OriginAttributes;
using mozilla::TimeStamp;
using mozilla::TimeDuration;
using mozilla::dom::cache::CacheStorage;
+using mozilla::layout::FlushingFlag;
static LazyLogModule gDOMLeakPRLog("DOMLeak");
nsGlobalWindow::WindowByIdTable *nsGlobalWindow::sWindowsById = nullptr;
bool nsGlobalWindow::sWarnedAboutWindowInternal = false;
bool nsGlobalWindow::sIdleObserversAPIFuzzTimeDisabled = false;
static int32_t gRefCnt = 0;
@@ -10988,54 +10989,71 @@ nsGlobalWindow::UpdateCanvasFocus(bool a
}
already_AddRefed<nsICSSDeclaration>
nsGlobalWindow::GetComputedStyle(Element& aElt, const nsAString& aPseudoElt,
ErrorResult& aError)
{
MOZ_ASSERT(IsInnerWindow());
FORWARD_TO_OUTER_OR_THROW(GetComputedStyleOuter,
- (aElt, aPseudoElt), aError, nullptr);
+ (aElt, aPseudoElt,
+ FlushingFlag::eNormalFlushing), aError, nullptr);
+}
+
+already_AddRefed<nsICSSDeclaration>
+nsGlobalWindow::GetComputedStyleWithoutFlushing(Element& aElt,
+ const nsAString& aPseudoElt,
+ ErrorResult& aError)
+{
+ MOZ_ASSERT(IsInnerWindow());
+ FORWARD_TO_OUTER_OR_THROW(GetComputedStyleOuter,
+ (aElt, aPseudoElt,
+ FlushingFlag::eWithoutFlushing), aError, nullptr);
}
already_AddRefed<nsICSSDeclaration>
nsGlobalWindow::GetComputedStyleOuter(Element& aElt,
- const nsAString& aPseudoElt)
+ const nsAString& aPseudoElt,
+ FlushingFlag aFlushingFlag)
{
MOZ_RELEASE_ASSERT(IsOuterWindow());
if (!mDocShell) {
return nullptr;
}
nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
if (!presShell) {
- // Try flushing frames on our parent in case there's a pending
- // style change that will create the presshell.
- auto* parent = nsGlobalWindow::Cast(GetPrivateParent());
- if (!parent) {
- return nullptr;
- }
-
- parent->FlushPendingNotifications(FlushType::Frames);
+ if (aFlushingFlag == FlushingFlag::eNormalFlushing) {
+ // Try flushing frames on our parent in case there's a pending
+ // style change that will create the presshell.
+ auto* parent = nsGlobalWindow::Cast(GetPrivateParent());
+ if (!parent) {
+ return nullptr;
+ }
+
+ parent->FlushPendingNotifications(FlushType::Frames);
+ }
// Might have killed mDocShell
if (!mDocShell) {
return nullptr;
}
presShell = mDocShell->GetPresShell();
if (!presShell) {
return nullptr;
}
}
RefPtr<nsComputedDOMStyle> compStyle =
- NS_NewComputedDOMStyle(&aElt, aPseudoElt, presShell);
+ NS_NewComputedDOMStyle(&aElt, aPseudoElt, presShell,
+ nsComputedDOMStyle::eWithAnimation,
+ aFlushingFlag);
return compStyle.forget();
}
Storage*
nsGlobalWindow::GetSessionStorage(ErrorResult& aError)
{
MOZ_RELEASE_ASSERT(IsInnerWindow());
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -147,16 +147,19 @@ class WakeLock;
class WindowOrientationObserver;
#endif
class Worklet;
namespace cache {
class CacheStorage;
} // namespace cache
class IDBFactory;
} // namespace dom
+namespace layout {
+enum class FlushingFlag : uint8_t;
+} // namespace layout
} // namespace mozilla
extern already_AddRefed<nsIScriptTimeoutHandler>
NS_CreateJSTimeoutHandler(JSContext* aCx, nsGlobalWindow *aWindow,
mozilla::dom::Function& aFunction,
const mozilla::dom::Sequence<JS::Value>& aArguments,
mozilla::ErrorResult& aError);
@@ -1040,16 +1043,20 @@ public:
GetLocalStorage(mozilla::ErrorResult& aError);
mozilla::dom::Selection* GetSelectionOuter();
mozilla::dom::Selection* GetSelection(mozilla::ErrorResult& aError);
already_AddRefed<nsISelection> GetSelection() override;
mozilla::dom::IDBFactory* GetIndexedDB(mozilla::ErrorResult& aError);
already_AddRefed<nsICSSDeclaration>
GetComputedStyle(mozilla::dom::Element& aElt, const nsAString& aPseudoElt,
mozilla::ErrorResult& aError) override;
+ already_AddRefed<nsICSSDeclaration>
+ GetComputedStyleWithoutFlushing(mozilla::dom::Element& aElt,
+ const nsAString& aPseudoElt,
+ mozilla::ErrorResult& aError) override;
already_AddRefed<mozilla::dom::MediaQueryList> MatchMediaOuter(const nsAString& aQuery);
already_AddRefed<mozilla::dom::MediaQueryList> MatchMedia(const nsAString& aQuery,
mozilla::ErrorResult& aError);
nsScreen* GetScreen(mozilla::ErrorResult& aError);
nsIDOMScreen* GetScreen() override;
void MoveToOuter(int32_t aXPos, int32_t aYPos,
mozilla::dom::CallerType aCallerType,
mozilla::ErrorResult& aError);
@@ -1724,17 +1731,18 @@ protected:
public:
// Outer windows only.
nsDOMWindowList* GetWindowList();
protected:
already_AddRefed<nsICSSDeclaration>
GetComputedStyleOuter(mozilla::dom::Element& aElt,
- const nsAString& aPseudoElt);
+ const nsAString& aPseudoElt,
+ mozilla::layout::FlushingFlag aFlushingFlag);
// Outer windows only.
void PreloadLocalStorage();
// Returns CSS pixels based on primary screen. Outer windows only.
mozilla::CSSIntPoint GetScreenXY(mozilla::dom::CallerType aCallerType,
mozilla::ErrorResult& aError);
--- a/dom/base/nsPIDOMWindow.h
+++ b/dom/base/nsPIDOMWindow.h
@@ -589,16 +589,20 @@ public:
nsISupports* aExtraArgument,
nsPIDOMWindowOuter** _retval) = 0;
virtual nsresult GetInnerWidth(int32_t* aWidth) = 0;
virtual nsresult GetInnerHeight(int32_t* aHeight) = 0;
virtual already_AddRefed<nsICSSDeclaration>
GetComputedStyle(mozilla::dom::Element& aElt, const nsAString& aPseudoElt,
mozilla::ErrorResult& aError) = 0;
+ virtual already_AddRefed<nsICSSDeclaration>
+ GetComputedStyleWithoutFlushing(mozilla::dom::Element& aElt,
+ const nsAString& aPseudoElt,
+ mozilla::ErrorResult& aError) = 0;
virtual already_AddRefed<nsIDOMElement> GetFrameElement() = 0;
virtual already_AddRefed<nsIDOMOfflineResourceList> GetApplicationCache() = 0;
virtual bool Closed() = 0;
virtual bool GetFullScreen() = 0;
virtual nsresult SetFullScreen(bool aFullScreen) = 0;
virtual nsresult Focus() = 0;
virtual nsresult Close() = 0;
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -62,21 +62,22 @@ using namespace mozilla::dom;
/*
* This is the implementation of the readonly CSSStyleDeclaration that is
* returned by the getComputedStyle() function.
*/
already_AddRefed<nsComputedDOMStyle>
NS_NewComputedDOMStyle(dom::Element* aElement, const nsAString& aPseudoElt,
nsIPresShell* aPresShell,
- nsComputedDOMStyle::AnimationFlag aFlag)
+ nsComputedDOMStyle::AnimationFlag aFlag,
+ mozilla::layout::FlushingFlag aFlushingFlag)
{
RefPtr<nsComputedDOMStyle> computedStyle;
computedStyle = new nsComputedDOMStyle(aElement, aPseudoElt,
- aPresShell, aFlag);
+ aPresShell, aFlag, aFlushingFlag);
return computedStyle.forget();
}
static nsDOMCSSValueList*
GetROCSSValueList(bool aCommaDelimited)
{
return new nsDOMCSSValueList(aCommaDelimited, true);
}
@@ -240,25 +241,27 @@ nsComputedStyleMap::Update()
}
}
mExposedPropertyCount = index;
}
nsComputedDOMStyle::nsComputedDOMStyle(dom::Element* aElement,
const nsAString& aPseudoElt,
nsIPresShell* aPresShell,
- AnimationFlag aFlag)
+ AnimationFlag aFlag,
+ FlushingFlag aFlushingFlag)
: mDocumentWeak(nullptr)
, mOuterFrame(nullptr)
, mInnerFrame(nullptr)
, mPresShell(nullptr)
, mStyleContextGeneration(0)
, mExposeVisitedStyle(false)
, mResolvedStyleContext(false)
, mAnimationFlag(aFlag)
+ , mFlushingFlag(aFlushingFlag)
{
MOZ_ASSERT(aElement && aPresShell);
mDocumentWeak = do_GetWeakReference(aPresShell->GetDocument());
mContent = aElement;
mPseudo = nsCSSPseudoElements::GetPseudoAtom(aPseudoElt);
MOZ_ASSERT(aPresShell->GetPresContext());
@@ -753,27 +756,30 @@ void
nsComputedDOMStyle::UpdateCurrentStyleSources(bool aNeedsLayoutFlush)
{
nsCOMPtr<nsIDocument> document = do_QueryReferent(mDocumentWeak);
if (!document) {
ClearStyleContext();
return;
}
- document->FlushPendingLinkUpdates();
-
- // 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);
+ AssertFlushedPendingReflows();
+ if (mFlushingFlag == FlushingFlag::eNormalFlushing) {
+ document->FlushPendingLinkUpdates();
+
+ // 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);
#ifdef DEBUG
- mFlushedPendingReflows = aNeedsLayoutFlush;
+ mFlushedPendingReflows = aNeedsLayoutFlush;
#endif
+ }
mPresShell = document->GetShell();
if (!mPresShell || !mPresShell->GetPresContext()) {
ClearStyleContext();
return;
}
uint64_t currentGeneration =
--- a/layout/style/nsComputedDOMStyle.h
+++ b/layout/style/nsComputedDOMStyle.h
@@ -41,24 +41,34 @@ class nsROCSSPrimitiveValue;
class nsStyleCoord;
class nsStyleCorners;
struct nsStyleFilter;
class nsStyleGradient;
struct nsStyleImage;
class nsStyleSides;
struct nsTimingFunction;
+namespace mozilla {
+namespace layout {
+enum class FlushingFlag : uint8_t {
+ eNormalFlushing,
+ eWithoutFlushing,
+};
+} // namespace layout
+} // namespace mozilla
+
class nsComputedDOMStyle final : public nsDOMCSSDeclaration
, public nsStubMutationObserver
{
private:
// Convenience typedefs:
typedef nsCSSProps::KTableEntry KTableEntry;
typedef mozilla::dom::CSSValue CSSValue;
typedef mozilla::StyleGeometryBox StyleGeometryBox;
+ typedef mozilla::layout::FlushingFlag FlushingFlag;
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsComputedDOMStyle,
nsICSSDeclaration)
NS_DECL_NSICSSDECLARATION
@@ -72,17 +82,18 @@ public:
enum AnimationFlag {
eWithAnimation,
eWithoutAnimation,
};
nsComputedDOMStyle(mozilla::dom::Element* aElement,
const nsAString& aPseudoElt,
nsIPresShell* aPresShell,
- AnimationFlag aFlag = eWithAnimation);
+ AnimationFlag aFlag = eWithAnimation,
+ FlushingFlag aFlushingFlag = FlushingFlag::eNormalFlushing);
virtual nsINode *GetParentObject() override
{
return mContent;
}
static already_AddRefed<nsStyleContext>
GetStyleContext(mozilla::dom::Element* aElement, nsIAtom* aPseudo,
@@ -748,21 +759,28 @@ private:
*/
bool mResolvedStyleContext;
/**
* Whether we include animation rules in the computed style.
*/
AnimationFlag mAnimationFlag;
+ /**
+ * Whether we should ignore style flushing while getting properties.
+ */
+ FlushingFlag mFlushingFlag;
+
#ifdef DEBUG
bool mFlushedPendingReflows;
#endif
};
already_AddRefed<nsComputedDOMStyle>
NS_NewComputedDOMStyle(mozilla::dom::Element* aElement,
const nsAString& aPseudoElt,
nsIPresShell* aPresShell,
nsComputedDOMStyle::AnimationFlag aFlag =
- nsComputedDOMStyle::eWithAnimation);
+ nsComputedDOMStyle::eWithAnimation,
+ mozilla::layout::FlushingFlag aFlushingFlag =
+ mozilla::layout::FlushingFlag::eNormalFlushing);
#endif /* nsComputedDOMStyle_h__ */