summaryrefslogtreecommitdiffstats
path: root/layout/style/nsStyleContext.h
diff options
context:
space:
mode:
Diffstat (limited to 'layout/style/nsStyleContext.h')
-rw-r--r--layout/style/nsStyleContext.h853
1 files changed, 853 insertions, 0 deletions
diff --git a/layout/style/nsStyleContext.h b/layout/style/nsStyleContext.h
new file mode 100644
index 000000000..b0b4896a3
--- /dev/null
+++ b/layout/style/nsStyleContext.h
@@ -0,0 +1,853 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* the interface (to internal code) for retrieving computed style data */
+
+#ifndef _nsStyleContext_h_
+#define _nsStyleContext_h_
+
+#include "mozilla/Assertions.h"
+#include "mozilla/RestyleLogging.h"
+#include "mozilla/StyleContextSource.h"
+#include "nsCSSAnonBoxes.h"
+#include "nsStyleSet.h"
+
+class nsIAtom;
+class nsPresContext;
+
+namespace mozilla {
+enum class CSSPseudoElementType : uint8_t;
+} // namespace mozilla
+
+extern "C" {
+#define STYLE_STRUCT(name_, checkdata_cb_) \
+ struct nsStyle##name_; \
+ const nsStyle##name_* Servo_GetStyle##name_( \
+ ServoComputedValuesBorrowedOrNull computed_values);
+#include "nsStyleStructList.h"
+#undef STYLE_STRUCT
+}
+
+/**
+ * An nsStyleContext represents the computed style data for an element.
+ * The computed style data are stored in a set of structs (see
+ * nsStyleStruct.h) that are cached either on the style context or in
+ * the rule tree (see nsRuleNode.h for a description of this caching and
+ * how the cached structs are shared).
+ *
+ * Since the data in |nsIStyleRule|s and |nsRuleNode|s are immutable
+ * (with a few exceptions, like system color changes), the data in an
+ * nsStyleContext are also immutable (with the additional exception of
+ * GetUniqueStyleData). When style data change,
+ * ElementRestyler::Restyle creates a new style context.
+ *
+ * Style contexts are reference counted. References are generally held
+ * by:
+ * 1. the |nsIFrame|s that are using the style context and
+ * 2. any *child* style contexts (this might be the reverse of
+ * expectation, but it makes sense in this case)
+ */
+
+class nsStyleContext final
+{
+public:
+ /**
+ * Create a new style context.
+ * @param aParent The parent of a style context is used for CSS
+ * inheritance. When the element or pseudo-element
+ * this style context represents the style data of
+ * inherits a CSS property, the value comes from the
+ * parent style context. This means style context
+ * parentage must match the definitions of inheritance
+ * in the CSS specification.
+ * @param aPseudoTag The pseudo-element or anonymous box for which
+ * this style context represents style. Null if
+ * this style context is for a normal DOM element.
+ * @param aPseudoType Must match aPseudoTag.
+ * @param aRuleNode A rule node representing the ordered sequence of
+ * rules that any element, pseudo-element, or
+ * anonymous box that this style context is for
+ * matches. See |nsRuleNode| and |nsIStyleRule|.
+ * @param aSkipParentDisplayBasedStyleFixup
+ * If set, this flag indicates that we should skip
+ * the chunk of ApplyStyleFixups() that applies to
+ * special cases where a child element's style may
+ * need to be modified based on its parent's display
+ * value.
+ */
+ nsStyleContext(nsStyleContext* aParent, nsIAtom* aPseudoTag,
+ mozilla::CSSPseudoElementType aPseudoType,
+ already_AddRefed<nsRuleNode> aRuleNode,
+ bool aSkipParentDisplayBasedStyleFixup);
+
+ // Version of the above that takes a ServoComputedValues instead of a Gecko
+ // nsRuleNode.
+ nsStyleContext(nsStyleContext* aParent,
+ nsPresContext* aPresContext,
+ nsIAtom* aPseudoTag,
+ mozilla::CSSPseudoElementType aPseudoType,
+ already_AddRefed<ServoComputedValues> aComputedValues,
+ bool aSkipParentDisplayBasedStyleFixup);
+
+ void* operator new(size_t sz, nsPresContext* aPresContext);
+ void Destroy();
+
+ // These two methods are for use by ArenaRefPtr.
+ static mozilla::ArenaObjectID ArenaObjectID()
+ {
+ return mozilla::eArenaObjectID_nsStyleContext;
+ }
+ nsIPresShell* Arena();
+
+#ifdef DEBUG
+ /**
+ * Initializes a cached pref, which is only used in DEBUG code.
+ */
+ static void Initialize();
+#endif
+
+ nsrefcnt AddRef() {
+ if (mRefCnt == UINT32_MAX) {
+ NS_WARNING("refcount overflow, leaking object");
+ return mRefCnt;
+ }
+ ++mRefCnt;
+ NS_LOG_ADDREF(this, mRefCnt, "nsStyleContext", sizeof(nsStyleContext));
+ return mRefCnt;
+ }
+
+ nsrefcnt Release() {
+ if (mRefCnt == UINT32_MAX) {
+ NS_WARNING("refcount overflow, leaking object");
+ return mRefCnt;
+ }
+ --mRefCnt;
+ NS_LOG_RELEASE(this, mRefCnt, "nsStyleContext");
+ if (mRefCnt == 0) {
+ Destroy();
+ return 0;
+ }
+ return mRefCnt;
+ }
+
+#ifdef DEBUG
+ void FrameAddRef() {
+ ++mFrameRefCnt;
+ }
+
+ void FrameRelease() {
+ --mFrameRefCnt;
+ }
+
+ uint32_t FrameRefCnt() const {
+ return mFrameRefCnt;
+ }
+#endif
+
+ bool HasSingleReference() const {
+ NS_ASSERTION(mRefCnt != 0,
+ "do not call HasSingleReference on a newly created "
+ "nsStyleContext with no references yet");
+ return mRefCnt == 1;
+ }
+
+ nsPresContext* PresContext() const {
+#ifdef MOZ_STYLO
+ return mPresContext;
+#else
+ return mSource.AsGeckoRuleNode()->PresContext();
+#endif
+ }
+
+ nsStyleContext* GetParent() const { return mParent; }
+
+ nsIAtom* GetPseudo() const { return mPseudoTag; }
+ mozilla::CSSPseudoElementType GetPseudoType() const {
+ return static_cast<mozilla::CSSPseudoElementType>(
+ mBits >> NS_STYLE_CONTEXT_TYPE_SHIFT);
+ }
+
+ bool IsAnonBox() const {
+ return GetPseudoType() == mozilla::CSSPseudoElementType::AnonBox;
+ }
+ bool IsPseudoElement() const { return mPseudoTag && !IsAnonBox(); }
+
+
+ // Find, if it already exists *and is easily findable* (i.e., near the
+ // start of the child list), a style context whose:
+ // * GetPseudo() matches aPseudoTag
+ // * mSource matches aSource
+ // * !!GetStyleIfVisited() == !!aSourceIfVisited, and, if they're
+ // non-null, GetStyleIfVisited()->mSource == aSourceIfVisited
+ // * RelevantLinkVisited() == aRelevantLinkVisited
+ already_AddRefed<nsStyleContext>
+ FindChildWithRules(const nsIAtom* aPseudoTag,
+ mozilla::NonOwningStyleContextSource aSource,
+ mozilla::NonOwningStyleContextSource aSourceIfVisited,
+ bool aRelevantLinkVisited);
+
+ // Does this style context or any of its ancestors have text
+ // decoration lines?
+ // Differs from nsStyleTextReset::HasTextDecorationLines, which tests
+ // only the data for a single context.
+ bool HasTextDecorationLines() const
+ { return !!(mBits & NS_STYLE_HAS_TEXT_DECORATION_LINES); }
+
+ // Whether any line break inside should be suppressed? If this returns
+ // true, the line should not be broken inside, which means inlines act
+ // as if nowrap is set, <br> is suppressed, and blocks are inlinized.
+ // This bit is propogated to all children of line partitipants. It is
+ // currently used by ruby to make its content frames unbreakable.
+ // NOTE: for nsTextFrame, use nsTextFrame::ShouldSuppressLineBreak()
+ // instead of this method.
+ bool ShouldSuppressLineBreak() const
+ { return !!(mBits & NS_STYLE_SUPPRESS_LINEBREAK); }
+
+ // Does this style context or any of its ancestors have display:none set?
+ bool IsInDisplayNoneSubtree() const
+ { return !!(mBits & NS_STYLE_IN_DISPLAY_NONE_SUBTREE); }
+
+ // Is this horizontal-in-vertical (tate-chu-yoko) text? This flag is
+ // only set on style contexts whose pseudo is nsCSSAnonBoxes::mozText.
+ bool IsTextCombined() const
+ { return !!(mBits & NS_STYLE_IS_TEXT_COMBINED); }
+
+ // Does this style context represent the style for a pseudo-element or
+ // inherit data from such a style context? Whether this returns true
+ // is equivalent to whether it or any of its ancestors returns
+ // non-null for IsPseudoElement().
+ bool HasPseudoElementData() const
+ { return !!(mBits & NS_STYLE_HAS_PSEUDO_ELEMENT_DATA); }
+
+ bool HasChildThatUsesResetStyle() const
+ { return mBits & NS_STYLE_HAS_CHILD_THAT_USES_RESET_STYLE; }
+
+ // Is the only link whose visitedness is allowed to influence the
+ // style of the node this style context is for (which is that element
+ // or its nearest ancestor that is a link) visited?
+ bool RelevantLinkVisited() const
+ { return !!(mBits & NS_STYLE_RELEVANT_LINK_VISITED); }
+
+ // Is this a style context for a link?
+ bool IsLinkContext() const {
+ return
+ GetStyleIfVisited() && GetStyleIfVisited()->GetParent() == GetParent();
+ }
+
+ // Is this style context the GetStyleIfVisited() for some other style
+ // context?
+ bool IsStyleIfVisited() const
+ { return !!(mBits & NS_STYLE_IS_STYLE_IF_VISITED); }
+
+ // Tells this style context that it should return true from
+ // IsStyleIfVisited.
+ void SetIsStyleIfVisited()
+ { mBits |= NS_STYLE_IS_STYLE_IF_VISITED; }
+
+ // Return the style context whose style data should be used for the R,
+ // G, and B components of color, background-color, and border-*-color
+ // if RelevantLinkIsVisited().
+ //
+ // GetPseudo() and GetPseudoType() on this style context return the
+ // same as on |this|, and its depth in the tree (number of GetParent()
+ // calls until null is returned) is the same as |this|, since its
+ // parent is either |this|'s parent or |this|'s parent's
+ // style-if-visited.
+ //
+ // Structs on this context should never be examined without also
+ // examining the corresponding struct on |this|. Doing so will likely
+ // both (1) lead to a privacy leak and (2) lead to dynamic change bugs
+ // related to the Peek code in nsStyleContext::CalcStyleDifference.
+ nsStyleContext* GetStyleIfVisited() const
+ { return mStyleIfVisited; }
+
+ // To be called only from nsStyleSet.
+ void SetStyleIfVisited(already_AddRefed<nsStyleContext> aStyleIfVisited)
+ {
+ MOZ_ASSERT(!IsStyleIfVisited(), "this context is not visited data");
+ NS_ASSERTION(!mStyleIfVisited, "should only be set once");
+
+ mStyleIfVisited = aStyleIfVisited;
+
+ MOZ_ASSERT(mStyleIfVisited->IsStyleIfVisited(),
+ "other context is visited data");
+ MOZ_ASSERT(!mStyleIfVisited->GetStyleIfVisited(),
+ "other context does not have visited data");
+ NS_ASSERTION(GetStyleIfVisited()->GetPseudo() == GetPseudo(),
+ "pseudo tag mismatch");
+ if (GetParent() && GetParent()->GetStyleIfVisited()) {
+ NS_ASSERTION(GetStyleIfVisited()->GetParent() ==
+ GetParent()->GetStyleIfVisited() ||
+ GetStyleIfVisited()->GetParent() == GetParent(),
+ "parent mismatch");
+ } else {
+ NS_ASSERTION(GetStyleIfVisited()->GetParent() == GetParent(),
+ "parent mismatch");
+ }
+ }
+
+ // Does any descendant of this style context have any style values
+ // that were computed based on this style context's ancestors?
+ bool HasChildThatUsesGrandancestorStyle() const
+ { return !!(mBits & NS_STYLE_CHILD_USES_GRANDANCESTOR_STYLE); }
+
+ // Is this style context shared with a sibling or cousin?
+ // (See nsStyleSet::GetContext.)
+ bool IsShared() const
+ { return !!(mBits & NS_STYLE_IS_SHARED); }
+
+ // Tell this style context to cache aStruct as the struct for aSID
+ void SetStyle(nsStyleStructID aSID, void* aStruct);
+
+ /**
+ * Returns whether this style context has cached style data for a
+ * given style struct and it does NOT own that struct. This can
+ * happen because it was inherited from the parent style context, or
+ * because it was stored conditionally on the rule node.
+ */
+ bool HasCachedDependentStyleData(nsStyleStructID aSID) {
+ return mBits & nsCachedStyleData::GetBitForSID(aSID);
+ }
+
+ nsRuleNode* RuleNode() {
+ MOZ_RELEASE_ASSERT(mSource.IsGeckoRuleNode());
+ return mSource.AsGeckoRuleNode();
+ }
+
+ void AddStyleBit(const uint64_t& aBit) { mBits |= aBit; }
+
+ /*
+ * Get the style data for a style struct. This is the most important
+ * member function of nsStyleContext. It fills in a const pointer
+ * to a style data struct that is appropriate for the style context's
+ * frame. This struct may be shared with other contexts (either in
+ * the rule tree or the style context tree), so it should not be
+ * modified.
+ *
+ * This function will NOT return null (even when out of memory) when
+ * given a valid style struct ID, so the result does not need to be
+ * null-checked.
+ *
+ * The typesafe functions below are preferred to the use of this
+ * function, both because they're easier to read and because they're
+ * faster.
+ */
+ const void* NS_FASTCALL StyleData(nsStyleStructID aSID);
+
+ /**
+ * Define typesafe getter functions for each style struct by
+ * preprocessing the list of style structs. These functions are the
+ * preferred way to get style data. The macro creates functions like:
+ * const nsStyleBorder* StyleBorder();
+ * const nsStyleColor* StyleColor();
+ */
+ #define STYLE_STRUCT(name_, checkdata_cb_) \
+ const nsStyle##name_ * Style##name_() { \
+ return DoGetStyle##name_<true>(); \
+ }
+ #include "nsStyleStructList.h"
+ #undef STYLE_STRUCT
+
+ /**
+ * PeekStyle* is like Style* but doesn't trigger style
+ * computation if the data is not cached on either the style context
+ * or the rule node.
+ *
+ * Perhaps this shouldn't be a public nsStyleContext API.
+ */
+ #define STYLE_STRUCT(name_, checkdata_cb_) \
+ const nsStyle##name_ * PeekStyle##name_() { \
+ return DoGetStyle##name_<false>(); \
+ }
+ #include "nsStyleStructList.h"
+ #undef STYLE_STRUCT
+
+ /**
+ * Compute the style changes needed during restyling when this style
+ * context is being replaced by aNewContext. (This is nonsymmetric since
+ * we optimize by skipping comparison for styles that have never been
+ * requested.)
+ *
+ * This method returns a change hint (see nsChangeHint.h). All change
+ * hints apply to the frame and its later continuations or ib-split
+ * siblings. Most (all of those except the "NotHandledForDescendants"
+ * hints) also apply to all descendants. The caller must pass in any
+ * non-inherited hints that resulted from the parent style context's
+ * style change. The caller *may* pass more hints than needed, but
+ * must not pass less than needed; therefore if the caller doesn't
+ * know, the caller should pass
+ * nsChangeHint_Hints_NotHandledForDescendants.
+ *
+ * aEqualStructs must not be null. Into it will be stored a bitfield
+ * representing which structs were compared to be non-equal.
+ */
+ nsChangeHint CalcStyleDifference(nsStyleContext* aNewContext,
+ nsChangeHint aParentHintsNotHandledForDescendants,
+ uint32_t* aEqualStructs,
+ uint32_t* aSamePointerStructs);
+
+ /**
+ * Like the above, but allows comparing ServoComputedValues instead of needing
+ * a full-fledged style context.
+ */
+ nsChangeHint CalcStyleDifference(const ServoComputedValues* aNewComputedValues,
+ nsChangeHint aParentHintsNotHandledForDescendants,
+ uint32_t* aEqualStructs,
+ uint32_t* aSamePointerStructs);
+
+private:
+ template<class StyleContextLike>
+ nsChangeHint CalcStyleDifferenceInternal(StyleContextLike* aNewContext,
+ nsChangeHint aParentHintsNotHandledForDescendants,
+ uint32_t* aEqualStructs,
+ uint32_t* aSamePointerStructs);
+
+public:
+ /**
+ * Get a color that depends on link-visitedness using this and
+ * this->GetStyleIfVisited().
+ *
+ * aProperty must be a color-valued property that StyleAnimationValue
+ * knows how to extract. It must also be a property that we know to
+ * do change handling for in nsStyleContext::CalcDifference.
+ */
+ nscolor GetVisitedDependentColor(nsCSSPropertyID aProperty);
+
+ /**
+ * aColors should be a two element array of nscolor in which the first
+ * color is the unvisited color and the second is the visited color.
+ *
+ * Combine the R, G, and B components of whichever of aColors should
+ * be used based on aLinkIsVisited with the A component of aColors[0].
+ */
+ static nscolor CombineVisitedColors(nscolor *aColors,
+ bool aLinkIsVisited);
+
+ /**
+ * Start the background image loads for this style context.
+ */
+ void StartBackgroundImageLoads() {
+ // Just get our background struct; that should do the trick
+ StyleBackground();
+ }
+
+ /**
+ * Moves this style context to a new parent.
+ *
+ * This function violates style context tree immutability, and
+ * is a very low-level function and should only be used after verifying
+ * many conditions that make it safe to call.
+ */
+ void MoveTo(nsStyleContext* aNewParent);
+
+ /**
+ * Swaps owned style struct pointers between this and aNewContext, on
+ * the assumption that aNewContext is the new style context for a frame
+ * and this is the old one. aStructs indicates which structs to consider
+ * swapping; only those which are owned in both this and aNewContext
+ * will be swapped.
+ *
+ * Additionally, if there are identical struct pointers for one of the
+ * structs indicated by aStructs, and it is not an owned struct on this,
+ * then the cached struct slot on this will be set to null. If the struct
+ * has been swapped on an ancestor, this style context (being the old one)
+ * will be left caching the struct pointer on the new ancestor, despite
+ * inheriting from the old ancestor. This is not normally a problem, as
+ * this style context will usually be destroyed by being released at the
+ * end of ElementRestyler::Restyle; but for style contexts held on to outside
+ * of the frame, we need to clear out the cached pointer so that if we need
+ * it again we'll re-fetch it from the new ancestor.
+ */
+ void SwapStyleData(nsStyleContext* aNewContext, uint32_t aStructs);
+
+ /**
+ * On each descendant of this style context, clears out any cached inherited
+ * structs indicated in aStructs.
+ */
+ void ClearCachedInheritedStyleDataOnDescendants(uint32_t aStructs);
+
+ /**
+ * Sets the NS_STYLE_INELIGIBLE_FOR_SHARING bit on this style context
+ * and its descendants. If it finds a descendant that has the bit
+ * already set, assumes that it can skip that subtree.
+ */
+ void SetIneligibleForSharing();
+
+#ifdef DEBUG
+ void List(FILE* out, int32_t aIndent, bool aListDescendants = true);
+ static void AssertStyleStructMaxDifferenceValid();
+ static const char* StructName(nsStyleStructID aSID);
+ static bool LookupStruct(const nsACString& aName, nsStyleStructID& aResult);
+#endif
+
+#ifdef RESTYLE_LOGGING
+ nsCString GetCachedStyleDataAsString(uint32_t aStructs);
+ void LogStyleContextTree(int32_t aLoggingDepth, uint32_t aStructs);
+ int32_t& LoggingDepth();
+#endif
+
+ /**
+ * Return style data that is currently cached on the style context.
+ * Only returns the structs we cache ourselves; never consults the
+ * rule tree.
+ *
+ * For "internal" use only in nsStyleContext and nsRuleNode.
+ */
+ const void* GetCachedStyleData(nsStyleStructID aSID)
+ {
+ const void* cachedData;
+ if (nsCachedStyleData::IsReset(aSID)) {
+ if (mCachedResetData) {
+ cachedData = mCachedResetData->mStyleStructs[aSID];
+ } else {
+ cachedData = nullptr;
+ }
+ } else {
+ cachedData = mCachedInheritedData.mStyleStructs[aSID];
+ }
+ return cachedData;
+ }
+
+ mozilla::NonOwningStyleContextSource StyleSource() const { return mSource.AsRaw(); }
+
+#ifdef MOZ_STYLO
+ // NOTE: It'd be great to assert here that the previous change hint is always
+ // consumed.
+ //
+ // This is not the case right now, since the changes of childs of frames that
+ // go through frame construction are not consumed.
+ void StoreChangeHint(nsChangeHint aHint)
+ {
+ MOZ_ASSERT(!IsShared());
+ mStoredChangeHint = aHint;
+#ifdef DEBUG
+ mConsumedChangeHint = false;
+#endif
+ }
+
+ nsChangeHint ConsumeStoredChangeHint()
+ {
+ MOZ_ASSERT(!mConsumedChangeHint, "Re-consuming the same change hint!");
+ nsChangeHint result = mStoredChangeHint;
+ mStoredChangeHint = nsChangeHint(0);
+#ifdef DEBUG
+ mConsumedChangeHint = true;
+#endif
+ return result;
+ }
+#else
+ void StoreChangeHint(nsChangeHint aHint)
+ {
+ MOZ_CRASH("stylo: Called nsStyleContext::StoreChangeHint in a non MOZ_STYLO "
+ "build.");
+ }
+
+ nsChangeHint ConsumeStoredChangeHint()
+ {
+ MOZ_CRASH("stylo: Called nsStyleContext::ComsumeStoredChangeHint in a non "
+ "MOZ_STYLO build.");
+ }
+#endif
+
+private:
+ // Private destructor, to discourage deletion outside of Release():
+ ~nsStyleContext();
+
+ // Delegated Helper constructor.
+ nsStyleContext(nsStyleContext* aParent,
+ mozilla::OwningStyleContextSource&& aSource,
+ nsIAtom* aPseudoTag,
+ mozilla::CSSPseudoElementType aPseudoType);
+
+ // Helper post-contruct hook.
+ void FinishConstruction(bool aSkipParentDisplayBasedStyleFixup);
+
+ void AddChild(nsStyleContext* aChild);
+ void RemoveChild(nsStyleContext* aChild);
+
+ void* GetUniqueStyleData(const nsStyleStructID& aSID);
+ void* CreateEmptyStyleData(const nsStyleStructID& aSID);
+
+ void SetStyleBits();
+ void ApplyStyleFixups(bool aSkipParentDisplayBasedStyleFixup);
+
+ const void* StyleStructFromServoComputedValues(nsStyleStructID aSID) {
+ switch (aSID) {
+#define STYLE_STRUCT(name_, checkdata_cb_) \
+ case eStyleStruct_##name_: \
+ return Servo_GetStyle##name_(mSource.AsServoComputedValues());
+#include "nsStyleStructList.h"
+#undef STYLE_STRUCT
+ default:
+ MOZ_ASSERT_UNREACHABLE("unexpected nsStyleStructID value");
+ return nullptr;
+ }
+ }
+
+#ifdef DEBUG
+ struct AutoCheckDependency {
+
+ nsStyleContext* mStyleContext;
+ nsStyleStructID mOuterSID;
+
+ AutoCheckDependency(nsStyleContext* aContext, nsStyleStructID aInnerSID)
+ : mStyleContext(aContext)
+ {
+ mOuterSID = aContext->mComputingStruct;
+ MOZ_ASSERT(mOuterSID == nsStyleStructID_None ||
+ DependencyAllowed(mOuterSID, aInnerSID),
+ "Undeclared dependency, see generate-stylestructlist.py");
+ aContext->mComputingStruct = aInnerSID;
+ }
+
+ ~AutoCheckDependency()
+ {
+ mStyleContext->mComputingStruct = mOuterSID;
+ }
+
+ };
+
+#define AUTO_CHECK_DEPENDENCY(sid_) \
+ AutoCheckDependency checkNesting_(this, sid_)
+#else
+#define AUTO_CHECK_DEPENDENCY(sid_)
+#endif
+
+ // Helper functions for GetStyle* and PeekStyle*
+ #define STYLE_STRUCT_INHERITED(name_, checkdata_cb_) \
+ template<bool aComputeData> \
+ const nsStyle##name_ * DoGetStyle##name_() { \
+ const nsStyle##name_ * cachedData = \
+ static_cast<nsStyle##name_*>( \
+ mCachedInheritedData.mStyleStructs[eStyleStruct_##name_]); \
+ if (cachedData) /* Have it cached already, yay */ \
+ return cachedData; \
+ if (!aComputeData) { \
+ /* We always cache inherited structs on the context when we */ \
+ /* compute them. */ \
+ return nullptr; \
+ } \
+ /* Have the rulenode deal */ \
+ AUTO_CHECK_DEPENDENCY(eStyleStruct_##name_); \
+ const nsStyle##name_ * newData; \
+ if (mSource.IsGeckoRuleNode()) { \
+ newData = mSource.AsGeckoRuleNode()-> \
+ GetStyle##name_<aComputeData>(this, mBits); \
+ } else { \
+ /** \
+ * Reach the parent to grab the inherited style struct if \
+ * we're a text node. \
+ * \
+ * This causes the parent element's style context to cache any \
+ * inherited structs we request for a text node, which means we \
+ * don't have to compute change hints for the text node, as \
+ * handling the change on the parent element is sufficient. \
+ * \
+ * Note that adding the inherit bit is ok, because the struct \
+ * pointer returned by the parent and the child is owned by \
+ * Servo. This is fine if the pointers are the same (as it \
+ * should, read below), because both style context sources will \
+ * hold it. \
+ * \
+ * In the case of a mishandled frame, we could end up with the \
+ * pointer to and old parent style, but that's fine too, since \
+ * the parent style context will remain alive until we reframe, \
+ * in which case we'll discard both style contexts. Also, we \
+ * hold a strong reference to the parent style context, which \
+ * makes it a non-issue. \
+ * \
+ * Also, note that the assertion below should be true, except \
+ * for those frames we still don't handle correctly, like \
+ * anonymous table wrappers, in which case the pointers will \
+ * differ. \
+ * \
+ * That means we're not going to restyle correctly text frames \
+ * of anonymous table wrappers, for example. It's kind of \
+ * embarrassing, but I think it's not worth it to add more \
+ * logic here unconditionally, given that's going to be fixed. \
+ * \
+ * TODO(emilio): Convert to a strong assertion once we support \
+ * all kinds of random frames. In fact, this can be a great \
+ * assertion to debug them. \
+ */ \
+ if (mPseudoTag == nsCSSAnonBoxes::mozText) { \
+ MOZ_ASSERT(mParent); \
+ newData = mParent->DoGetStyle##name_<true>(); \
+ NS_WARNING_ASSERTION( \
+ newData == Servo_GetStyle##name_(mSource.AsServoComputedValues()), \
+ "bad newData"); \
+ } else { \
+ newData = \
+ Servo_GetStyle##name_(mSource.AsServoComputedValues()); \
+ } \
+ /* perform any remaining main thread work on the struct */ \
+ const_cast<nsStyle##name_*>(newData)->FinishStyle(PresContext());\
+ /* the Servo-backed StyleContextSource owns the struct */ \
+ AddStyleBit(NS_STYLE_INHERIT_BIT(name_)); \
+ } \
+ /* always cache inherited data on the style context; the rule */ \
+ /* node set the bit in mBits for us if needed. */ \
+ mCachedInheritedData.mStyleStructs[eStyleStruct_##name_] = \
+ const_cast<nsStyle##name_ *>(newData); \
+ return newData; \
+ }
+ #define STYLE_STRUCT_RESET(name_, checkdata_cb_) \
+ template<bool aComputeData> \
+ const nsStyle##name_ * DoGetStyle##name_() { \
+ if (mCachedResetData) { \
+ const nsStyle##name_ * cachedData = \
+ static_cast<nsStyle##name_*>( \
+ mCachedResetData->mStyleStructs[eStyleStruct_##name_]); \
+ if (cachedData) /* Have it cached already, yay */ \
+ return cachedData; \
+ } \
+ /* Have the rulenode deal */ \
+ AUTO_CHECK_DEPENDENCY(eStyleStruct_##name_); \
+ const nsStyle##name_ * newData; \
+ if (mSource.IsGeckoRuleNode()) { \
+ newData = mSource.AsGeckoRuleNode()-> \
+ GetStyle##name_<aComputeData>(this); \
+ } else { \
+ newData = \
+ Servo_GetStyle##name_(mSource.AsServoComputedValues()); \
+ /* perform any remaining main thread work on the struct */ \
+ const_cast<nsStyle##name_*>(newData)->FinishStyle(PresContext());\
+ /* The Servo-backed StyleContextSource owns the struct. \
+ * \
+ * XXXbholley: Unconditionally caching reset structs here \
+ * defeats the memory optimization where we lazily allocate \
+ * mCachedResetData, so that we can avoid performing an FFI \
+ * call each time we want to get the style structs. We should \
+ * measure the tradeoffs at some point. If the FFI overhead is \
+ * low and the memory win significant, we should consider \
+ * _always_ grabbing the struct over FFI, and potentially \
+ * giving mCachedInheritedData the same treatment. \
+ * \
+ * Note that there is a similar comment in StyleData(). \
+ */ \
+ AddStyleBit(NS_STYLE_INHERIT_BIT(name_)); \
+ SetStyle(eStyleStruct_##name_, \
+ const_cast<nsStyle##name_*>(newData)); \
+ } \
+ return newData; \
+ }
+ #include "nsStyleStructList.h"
+ #undef STYLE_STRUCT_RESET
+ #undef STYLE_STRUCT_INHERITED
+
+ // Helper for ClearCachedInheritedStyleDataOnDescendants.
+ void DoClearCachedInheritedStyleDataOnDescendants(uint32_t aStructs);
+
+#ifdef DEBUG
+ void AssertStructsNotUsedElsewhere(nsStyleContext* aDestroyingContext,
+ int32_t aLevels) const;
+#endif
+
+#ifdef RESTYLE_LOGGING
+ void LogStyleContextTree(bool aFirst, uint32_t aStructs);
+
+ // This only gets called under call trees where we've already checked
+ // that PresContext()->RestyleManager()->ShouldLogRestyle() returned true.
+ // It exists here just to satisfy LOG_RESTYLE's expectations.
+ bool ShouldLogRestyle() { return true; }
+#endif
+
+ RefPtr<nsStyleContext> mParent;
+
+ // Children are kept in two circularly-linked lists. The list anchor
+ // is not part of the list (null for empty), and we point to the first
+ // child.
+ // mEmptyChild for children whose rule node is the root rule node, and
+ // mChild for other children. The order of children is not
+ // meaningful.
+ nsStyleContext* mChild;
+ nsStyleContext* mEmptyChild;
+ nsStyleContext* mPrevSibling;
+ nsStyleContext* mNextSibling;
+
+ // Style to be used instead for the R, G, and B components of color,
+ // background-color, and border-*-color if the nearest ancestor link
+ // element is visited (see RelevantLinkVisited()).
+ RefPtr<nsStyleContext> mStyleIfVisited;
+
+ // If this style context is for a pseudo-element or anonymous box,
+ // the relevant atom.
+ nsCOMPtr<nsIAtom> mPseudoTag;
+
+ // The source for our style data, either a Gecko nsRuleNode or a Servo
+ // ComputedValues struct. This never changes after construction, except
+ // when it's released and nulled out during teardown.
+ const mozilla::OwningStyleContextSource mSource;
+
+#ifdef MOZ_STYLO
+ // In Gecko, we can get this off the rule node. We make this conditional
+ // on stylo builds to avoid the memory bloat on release.
+ nsPresContext* mPresContext;
+#endif
+
+ // mCachedInheritedData and mCachedResetData point to both structs that
+ // are owned by this style context and structs that are owned by one of
+ // this style context's ancestors (which are indirectly owned since this
+ // style context owns a reference to its parent). If the bit in |mBits|
+ // is set for a struct, that means that the pointer for that struct is
+ // owned by an ancestor or by the rule node rather than by this style context.
+ // Since style contexts typically have some inherited data but only sometimes
+ // have reset data, we always allocate the mCachedInheritedData, but only
+ // sometimes allocate the mCachedResetData.
+ nsResetStyleData* mCachedResetData; // Cached reset style data.
+ nsInheritedStyleData mCachedInheritedData; // Cached inherited style data
+
+ // mBits stores a number of things:
+ // - It records (using the style struct bits) which structs are
+ // inherited from the parent context or owned by the rule node (i.e.,
+ // not owned by the style context).
+ // - It also stores the additional bits listed at the top of
+ // nsStyleStruct.h.
+ uint64_t mBits;
+
+ uint32_t mRefCnt;
+
+ // For now we store change hints on the style context during parallel traversal.
+ // We should improve this - see bug 1289861.
+#ifdef MOZ_STYLO
+ nsChangeHint mStoredChangeHint;
+#ifdef DEBUG
+ bool mConsumedChangeHint;
+#endif
+#endif
+
+#ifdef DEBUG
+ uint32_t mFrameRefCnt; // number of frames that use this
+ // as their style context
+
+ nsStyleStructID mComputingStruct;
+
+ static bool DependencyAllowed(nsStyleStructID aOuterSID,
+ nsStyleStructID aInnerSID)
+ {
+ return !!(sDependencyTable[aOuterSID] &
+ nsCachedStyleData::GetBitForSID(aInnerSID));
+ }
+
+ static const uint32_t sDependencyTable[];
+#endif
+};
+
+already_AddRefed<nsStyleContext>
+NS_NewStyleContext(nsStyleContext* aParentContext,
+ nsIAtom* aPseudoTag,
+ mozilla::CSSPseudoElementType aPseudoType,
+ nsRuleNode* aRuleNode,
+ bool aSkipParentDisplayBasedStyleFixup);
+
+already_AddRefed<nsStyleContext>
+NS_NewStyleContext(nsStyleContext* aParentContext,
+ nsPresContext* aPresContext,
+ nsIAtom* aPseudoTag,
+ mozilla::CSSPseudoElementType aPseudoType,
+ already_AddRefed<ServoComputedValues> aComputedValues,
+ bool aSkipParentDisplayBasedStyleFixup);
+
+#endif