layout/style/nsStyleContext.h

Fri, 16 Jan 2015 18:13:44 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 18:13:44 +0100
branch
TOR_BUG_9701
changeset 14
925c144e1f1f
permissions
-rw-r--r--

Integrate suggestion from review to improve consistency with existing code.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 /* the interface (to internal code) for retrieving computed style data */
     8 #ifndef _nsStyleContext_h_
     9 #define _nsStyleContext_h_
    11 #include "nsRuleNode.h"
    12 #include "nsCSSPseudoElements.h"
    14 class nsIAtom;
    15 class nsPresContext;
    17 /**
    18  * An nsStyleContext represents the computed style data for an element.
    19  * The computed style data are stored in a set of structs (see
    20  * nsStyleStruct.h) that are cached either on the style context or in
    21  * the rule tree (see nsRuleNode.h for a description of this caching and
    22  * how the cached structs are shared).
    23  *
    24  * Since the data in |nsIStyleRule|s and |nsRuleNode|s are immutable
    25  * (with a few exceptions, like system color changes), the data in an
    26  * nsStyleContext are also immutable (with the additional exception of
    27  * GetUniqueStyleData).  When style data change,
    28  * nsFrameManager::ReResolveStyleContext creates a new style context.
    29  *
    30  * Style contexts are reference counted.  References are generally held
    31  * by:
    32  *  1. the |nsIFrame|s that are using the style context and
    33  *  2. any *child* style contexts (this might be the reverse of
    34  *     expectation, but it makes sense in this case)
    35  * Style contexts participate in the mark phase of rule node garbage
    36  * collection.
    37  */
    39 class nsStyleContext
    40 {
    41 public:
    42   /**
    43    * Create a new style context.
    44    * @param aParent  The parent of a style context is used for CSS
    45    *                 inheritance.  When the element or pseudo-element
    46    *                 this style context represents the style data of
    47    *                 inherits a CSS property, the value comes from the
    48    *                 parent style context.  This means style context
    49    *                 parentage must match the definitions of inheritance
    50    *                 in the CSS specification.
    51    * @param aPseudoTag  The pseudo-element or anonymous box for which
    52    *                    this style context represents style.  Null if
    53    *                    this style context is for a normal DOM element.
    54    * @param aPseudoType  Must match aPseudoTag.
    55    * @param aRuleNode  A rule node representing the ordered sequence of
    56    *                   rules that any element, pseudo-element, or
    57    *                   anonymous box that this style context is for
    58    *                   matches.  See |nsRuleNode| and |nsIStyleRule|.
    59    * @param aSkipFlexItemStyleFixup
    60    *                 If set, this flag indicates that we should skip
    61    *                 the chunk of ApplyStyleFixups() that modifies flex
    62    *                 items' display values.
    63    */
    64   nsStyleContext(nsStyleContext* aParent, nsIAtom* aPseudoTag,
    65                  nsCSSPseudoElements::Type aPseudoType,
    66                  nsRuleNode* aRuleNode,
    67                  bool aSkipFlexItemStyleFixup);
    68   ~nsStyleContext();
    70   void* operator new(size_t sz, nsPresContext* aPresContext) CPP_THROW_NEW;
    71   void Destroy();
    73   nsrefcnt AddRef() {
    74     if (mRefCnt == UINT32_MAX) {
    75       NS_WARNING("refcount overflow, leaking object");
    76       return mRefCnt;
    77     }
    78     ++mRefCnt;
    79     NS_LOG_ADDREF(this, mRefCnt, "nsStyleContext", sizeof(nsStyleContext));
    80     return mRefCnt;
    81   }
    83   nsrefcnt Release() {
    84     if (mRefCnt == UINT32_MAX) {
    85       NS_WARNING("refcount overflow, leaking object");
    86       return mRefCnt;
    87     }
    88     --mRefCnt;
    89     NS_LOG_RELEASE(this, mRefCnt, "nsStyleContext");
    90     if (mRefCnt == 0) {
    91       Destroy();
    92       return 0;
    93     }
    94     return mRefCnt;
    95   }
    97   nsPresContext* PresContext() const { return mRuleNode->PresContext(); }
    99   nsStyleContext* GetParent() const { return mParent; }
   101   nsIAtom* GetPseudo() const { return mPseudoTag; }
   102   nsCSSPseudoElements::Type GetPseudoType() const {
   103     return static_cast<nsCSSPseudoElements::Type>(mBits >>
   104                                                   NS_STYLE_CONTEXT_TYPE_SHIFT);
   105   }
   107   // Find, if it already exists *and is easily findable* (i.e., near the
   108   // start of the child list), a style context whose:
   109   //  * GetPseudo() matches aPseudoTag
   110   //  * RuleNode() matches aRules
   111   //  * !GetStyleIfVisited() == !aRulesIfVisited, and, if they're
   112   //    non-null, GetStyleIfVisited()->RuleNode() == aRulesIfVisited
   113   //  * RelevantLinkVisited() == aRelevantLinkVisited
   114   already_AddRefed<nsStyleContext>
   115   FindChildWithRules(const nsIAtom* aPseudoTag, nsRuleNode* aRules,
   116                      nsRuleNode* aRulesIfVisited,
   117                      bool aRelevantLinkVisited);
   119   // Does this style context or any of its ancestors have text
   120   // decoration lines?
   121   bool HasTextDecorationLines() const
   122     { return !!(mBits & NS_STYLE_HAS_TEXT_DECORATION_LINES); }
   124   // Does this style context represent the style for a pseudo-element or
   125   // inherit data from such a style context?  Whether this returns true
   126   // is equivalent to whether it or any of its ancestors returns
   127   // non-null for GetPseudo.
   128   bool HasPseudoElementData() const
   129     { return !!(mBits & NS_STYLE_HAS_PSEUDO_ELEMENT_DATA); }
   131   // Is the only link whose visitedness is allowed to influence the
   132   // style of the node this style context is for (which is that element
   133   // or its nearest ancestor that is a link) visited?
   134   bool RelevantLinkVisited() const
   135     { return !!(mBits & NS_STYLE_RELEVANT_LINK_VISITED); }
   137   // Is this a style context for a link?
   138   bool IsLinkContext() const {
   139     return
   140       GetStyleIfVisited() && GetStyleIfVisited()->GetParent() == GetParent();
   141   }
   143   // Is this style context the GetStyleIfVisited() for some other style
   144   // context?
   145   bool IsStyleIfVisited() const
   146     { return !!(mBits & NS_STYLE_IS_STYLE_IF_VISITED); }
   148   // Tells this style context that it should return true from
   149   // IsStyleIfVisited.
   150   void SetIsStyleIfVisited()
   151     { mBits |= NS_STYLE_IS_STYLE_IF_VISITED; }
   153   // Return the style context whose style data should be used for the R,
   154   // G, and B components of color, background-color, and border-*-color
   155   // if RelevantLinkIsVisited().
   156   //
   157   // GetPseudo() and GetPseudoType() on this style context return the
   158   // same as on |this|, and its depth in the tree (number of GetParent()
   159   // calls until null is returned) is the same as |this|, since its
   160   // parent is either |this|'s parent or |this|'s parent's
   161   // style-if-visited.
   162   //
   163   // Structs on this context should never be examined without also
   164   // examining the corresponding struct on |this|.  Doing so will likely
   165   // both (1) lead to a privacy leak and (2) lead to dynamic change bugs
   166   // related to the Peek code in nsStyleContext::CalcStyleDifference.
   167   nsStyleContext* GetStyleIfVisited() const
   168     { return mStyleIfVisited; }
   170   // To be called only from nsStyleSet.
   171   void SetStyleIfVisited(already_AddRefed<nsStyleContext> aStyleIfVisited)
   172   {
   173     NS_ABORT_IF_FALSE(!IsStyleIfVisited(), "this context is not visited data");
   174     NS_ASSERTION(!mStyleIfVisited, "should only be set once");
   176     mStyleIfVisited = aStyleIfVisited;
   178     NS_ABORT_IF_FALSE(mStyleIfVisited->IsStyleIfVisited(),
   179                       "other context is visited data");
   180     NS_ABORT_IF_FALSE(!mStyleIfVisited->GetStyleIfVisited(),
   181                       "other context does not have visited data");
   182     NS_ASSERTION(GetStyleIfVisited()->GetPseudo() == GetPseudo(),
   183                  "pseudo tag mismatch");
   184     if (GetParent() && GetParent()->GetStyleIfVisited()) {
   185       NS_ASSERTION(GetStyleIfVisited()->GetParent() ==
   186                      GetParent()->GetStyleIfVisited() ||
   187                    GetStyleIfVisited()->GetParent() == GetParent(),
   188                    "parent mismatch");
   189     } else {
   190       NS_ASSERTION(GetStyleIfVisited()->GetParent() == GetParent(),
   191                    "parent mismatch");
   192     }
   193   }
   195   // Tell this style context to cache aStruct as the struct for aSID
   196   void SetStyle(nsStyleStructID aSID, void* aStruct);
   198   // Setters for inherit structs only, since rulenode only sets those eagerly.
   199   #define STYLE_STRUCT_INHERITED(name_, checkdata_cb_)                      \
   200     void SetStyle##name_ (nsStyle##name_ * aStruct) {                       \
   201       void *& slot =                                                        \
   202         mCachedInheritedData.mStyleStructs[eStyleStruct_##name_];           \
   203       NS_ASSERTION(!slot ||                                                 \
   204                    (mBits &                                                 \
   205                     nsCachedStyleData::GetBitForSID(eStyleStruct_##name_)), \
   206                    "Going to leak styledata");                              \
   207       slot = aStruct;                                                       \
   208     }
   209 #define STYLE_STRUCT_RESET(name_, checkdata_cb_) /* nothing */
   210   #include "nsStyleStructList.h"
   211   #undef STYLE_STRUCT_RESET
   212   #undef STYLE_STRUCT_INHERITED
   214   nsRuleNode* RuleNode() { return mRuleNode; }
   215   void AddStyleBit(const uint64_t& aBit) { mBits |= aBit; }
   217   /*
   218    * Mark this style context's rule node (and its ancestors) to prevent
   219    * it from being garbage collected.
   220    */
   221   void Mark();
   223   /*
   224    * Get the style data for a style struct.  This is the most important
   225    * member function of nsIStyleContext.  It fills in a const pointer
   226    * to a style data struct that is appropriate for the style context's
   227    * frame.  This struct may be shared with other contexts (either in
   228    * the rule tree or the style context tree), so it should not be
   229    * modified.
   230    *
   231    * This function will NOT return null (even when out of memory) when
   232    * given a valid style struct ID, so the result does not need to be
   233    * null-checked.
   234    *
   235    * The typesafe functions below are preferred to the use of this
   236    * function, both because they're easier to read and because they're
   237    * faster.
   238    */
   239   const void* NS_FASTCALL StyleData(nsStyleStructID aSID);
   241   /**
   242    * Define typesafe getter functions for each style struct by
   243    * preprocessing the list of style structs.  These functions are the
   244    * preferred way to get style data.  The macro creates functions like:
   245    *   const nsStyleBorder* StyleBorder();
   246    *   const nsStyleColor* StyleColor();
   247    */
   248   #define STYLE_STRUCT(name_, checkdata_cb_)              \
   249     const nsStyle##name_ * Style##name_() {               \
   250       return DoGetStyle##name_(true);                     \
   251     }
   252   #include "nsStyleStructList.h"
   253   #undef STYLE_STRUCT
   255   /**
   256    * PeekStyle* is like GetStyle* but doesn't trigger style
   257    * computation if the data is not cached on either the style context
   258    * or the rule node.
   259    *
   260    * Perhaps this shouldn't be a public nsStyleContext API.
   261    */
   262   #define STYLE_STRUCT(name_, checkdata_cb_)              \
   263     const nsStyle##name_ * PeekStyle##name_() {           \
   264       return DoGetStyle##name_(false);                    \
   265     }
   266   #include "nsStyleStructList.h"
   267   #undef STYLE_STRUCT
   269   void* GetUniqueStyleData(const nsStyleStructID& aSID);
   271   /**
   272    * Compute the style changes needed during restyling when this style
   273    * context is being replaced by aOther.  (This is nonsymmetric since
   274    * we optimize by skipping comparison for styles that have never been
   275    * requested.)
   276    *
   277    * This method returns a change hint (see nsChangeHint.h).  All change
   278    * hints apply to the frame and its later continuations or ib-split
   279    * siblings.  Most (all of those except the "NotHandledForDescendants"
   280    * hints) also apply to all descendants.  The caller must pass in any
   281    * non-inherited hints that resulted from the parent style context's
   282    * style change.  The caller *may* pass more hints than needed, but
   283    * must not pass less than needed; therefore if the caller doesn't
   284    * know, the caller should pass
   285    * nsChangeHint_Hints_NotHandledForDescendants.
   286    */
   287   nsChangeHint CalcStyleDifference(nsStyleContext* aOther,
   288                                    nsChangeHint aParentHintsNotHandledForDescendants);
   290   /**
   291    * Get a color that depends on link-visitedness using this and
   292    * this->GetStyleIfVisited().
   293    *
   294    * aProperty must be a color-valued property that nsStyleAnimation
   295    * knows how to extract.  It must also be a property that we know to
   296    * do change handling for in nsStyleContext::CalcDifference.
   297    *
   298    * Note that if aProperty is eCSSProperty_border_*_color, this
   299    * function handles -moz-use-text-color.
   300    */
   301   nscolor GetVisitedDependentColor(nsCSSProperty aProperty);
   303   /**
   304    * aColors should be a two element array of nscolor in which the first
   305    * color is the unvisited color and the second is the visited color.
   306    *
   307    * Combine the R, G, and B components of whichever of aColors should
   308    * be used based on aLinkIsVisited with the A component of aColors[0].
   309    */
   310   static nscolor CombineVisitedColors(nscolor *aColors,
   311                                       bool aLinkIsVisited);
   313   /**
   314    * Allocate a chunk of memory that is scoped to the lifetime of this
   315    * style context, i.e., memory that will automatically be freed when
   316    * this style context is destroyed.  This is intended for allocations
   317    * that are stored on this style context or its style structs.  (Use
   318    * on style structs is fine since any style context to which this
   319    * context's style structs are shared will be a descendant of this
   320    * style context and thus keep it alive.)
   321    *
   322    * This currently allocates the memory out of the pres shell arena.
   323    *
   324    * It would be relatively straightforward to write a Free method
   325    * for the underlying implementation, but we don't need it (or the
   326    * overhead of making a doubly-linked list or other structure to
   327    * support it).
   328    *
   329    * WARNING: Memory allocated using this method cannot be stored in the
   330    * rule tree, since rule nodes may outlive the style context.
   331    */
   332   void* Alloc(size_t aSize);
   334   /**
   335    * Start the background image loads for this style context.
   336    */
   337   void StartBackgroundImageLoads() {
   338     // Just get our background struct; that should do the trick
   339     StyleBackground();
   340   }
   342 #ifdef DEBUG
   343   void List(FILE* out, int32_t aIndent);
   344   static void AssertStyleStructMaxDifferenceValid();
   345 #endif
   347 protected:
   348   void AddChild(nsStyleContext* aChild);
   349   void RemoveChild(nsStyleContext* aChild);
   351   void ApplyStyleFixups(bool aSkipFlexItemStyleFixup);
   353   void FreeAllocations(nsPresContext* aPresContext);
   355   // Helper function that GetStyleData and GetUniqueStyleData use.  Only
   356   // returns the structs we cache ourselves; never consults the ruletree.
   357   inline const void* GetCachedStyleData(nsStyleStructID aSID);
   359   // Helper functions for GetStyle* and PeekStyle*
   360   #define STYLE_STRUCT_INHERITED(name_, checkdata_cb_)                  \
   361     const nsStyle##name_ * DoGetStyle##name_(bool aComputeData) {       \
   362       const nsStyle##name_ * cachedData =                               \
   363         static_cast<nsStyle##name_*>(                                   \
   364           mCachedInheritedData.mStyleStructs[eStyleStruct_##name_]);    \
   365       if (cachedData) /* Have it cached already, yay */                 \
   366         return cachedData;                                              \
   367       /* Have the rulenode deal */                                      \
   368       return mRuleNode->GetStyle##name_(this, aComputeData);            \
   369     }
   370   #define STYLE_STRUCT_RESET(name_, checkdata_cb_)                      \
   371     const nsStyle##name_ * DoGetStyle##name_(bool aComputeData) {       \
   372       const nsStyle##name_ * cachedData = mCachedResetData              \
   373         ? static_cast<nsStyle##name_*>(                                 \
   374             mCachedResetData->mStyleStructs[eStyleStruct_##name_])      \
   375         : nullptr;                                                      \
   376       if (cachedData) /* Have it cached already, yay */                 \
   377         return cachedData;                                              \
   378       /* Have the rulenode deal */                                      \
   379       return mRuleNode->GetStyle##name_(this, aComputeData);            \
   380     }
   381   #include "nsStyleStructList.h"
   382   #undef STYLE_STRUCT_RESET
   383   #undef STYLE_STRUCT_INHERITED
   385   nsStyleContext* const mParent; // STRONG
   387   // Children are kept in two circularly-linked lists.  The list anchor
   388   // is not part of the list (null for empty), and we point to the first
   389   // child.
   390   // mEmptyChild for children whose rule node is the root rule node, and
   391   // mChild for other children.  The order of children is not
   392   // meaningful.
   393   nsStyleContext* mChild;
   394   nsStyleContext* mEmptyChild;
   395   nsStyleContext* mPrevSibling;
   396   nsStyleContext* mNextSibling;
   398   // Style to be used instead for the R, G, and B components of color,
   399   // background-color, and border-*-color if the nearest ancestor link
   400   // element is visited (see RelevantLinkVisited()).
   401   nsRefPtr<nsStyleContext> mStyleIfVisited;
   403   // If this style context is for a pseudo-element or anonymous box,
   404   // the relevant atom.
   405   nsCOMPtr<nsIAtom> mPseudoTag;
   407   // The rule node is the node in the lexicographic tree of rule nodes
   408   // (the "rule tree") that indicates which style rules are used to
   409   // compute the style data, and in what cascading order.  The least
   410   // specific rule matched is the one whose rule node is a child of the
   411   // root of the rule tree, and the most specific rule matched is the
   412   // |mRule| member of |mRuleNode|.
   413   nsRuleNode* const       mRuleNode;
   415   // Private to nsStyleContext::Alloc and FreeAllocations.
   416   struct AllocationHeader {
   417     AllocationHeader* mNext;
   418     size_t mSize;
   420     void* mStorageStart; // ensure the storage is at least pointer-aligned
   421   };
   422   AllocationHeader*       mAllocations;
   424   // mCachedInheritedData and mCachedResetData point to both structs that
   425   // are owned by this style context and structs that are owned by one of
   426   // this style context's ancestors (which are indirectly owned since this
   427   // style context owns a reference to its parent).  If the bit in |mBits|
   428   // is set for a struct, that means that the pointer for that struct is
   429   // owned by an ancestor or by mRuleNode rather than by this style context.
   430   // Since style contexts typically have some inherited data but only sometimes
   431   // have reset data, we always allocate the mCachedInheritedData, but only
   432   // sometimes allocate the mCachedResetData.
   433   nsResetStyleData*       mCachedResetData; // Cached reset style data.
   434   nsInheritedStyleData    mCachedInheritedData; // Cached inherited style data
   435   uint64_t                mBits; // Which structs are inherited from the
   436                                  // parent context or owned by mRuleNode.
   437   uint32_t                mRefCnt;
   438 };
   440 already_AddRefed<nsStyleContext>
   441 NS_NewStyleContext(nsStyleContext* aParentContext,
   442                    nsIAtom* aPseudoTag,
   443                    nsCSSPseudoElements::Type aPseudoType,
   444                    nsRuleNode* aRuleNode,
   445                    bool aSkipFlexItemStyleFixup);
   446 #endif

mercurial