123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854 |
- /* -*- 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
|