layout/style/nsStyleContext.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/layout/style/nsStyleContext.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,446 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +/* the interface (to internal code) for retrieving computed style data */
    1.10 +
    1.11 +#ifndef _nsStyleContext_h_
    1.12 +#define _nsStyleContext_h_
    1.13 +
    1.14 +#include "nsRuleNode.h"
    1.15 +#include "nsCSSPseudoElements.h"
    1.16 +
    1.17 +class nsIAtom;
    1.18 +class nsPresContext;
    1.19 +
    1.20 +/**
    1.21 + * An nsStyleContext represents the computed style data for an element.
    1.22 + * The computed style data are stored in a set of structs (see
    1.23 + * nsStyleStruct.h) that are cached either on the style context or in
    1.24 + * the rule tree (see nsRuleNode.h for a description of this caching and
    1.25 + * how the cached structs are shared).
    1.26 + *
    1.27 + * Since the data in |nsIStyleRule|s and |nsRuleNode|s are immutable
    1.28 + * (with a few exceptions, like system color changes), the data in an
    1.29 + * nsStyleContext are also immutable (with the additional exception of
    1.30 + * GetUniqueStyleData).  When style data change,
    1.31 + * nsFrameManager::ReResolveStyleContext creates a new style context.
    1.32 + *
    1.33 + * Style contexts are reference counted.  References are generally held
    1.34 + * by:
    1.35 + *  1. the |nsIFrame|s that are using the style context and
    1.36 + *  2. any *child* style contexts (this might be the reverse of
    1.37 + *     expectation, but it makes sense in this case)
    1.38 + * Style contexts participate in the mark phase of rule node garbage
    1.39 + * collection.
    1.40 + */
    1.41 +
    1.42 +class nsStyleContext
    1.43 +{
    1.44 +public:
    1.45 +  /**
    1.46 +   * Create a new style context.
    1.47 +   * @param aParent  The parent of a style context is used for CSS
    1.48 +   *                 inheritance.  When the element or pseudo-element
    1.49 +   *                 this style context represents the style data of
    1.50 +   *                 inherits a CSS property, the value comes from the
    1.51 +   *                 parent style context.  This means style context
    1.52 +   *                 parentage must match the definitions of inheritance
    1.53 +   *                 in the CSS specification.
    1.54 +   * @param aPseudoTag  The pseudo-element or anonymous box for which
    1.55 +   *                    this style context represents style.  Null if
    1.56 +   *                    this style context is for a normal DOM element.
    1.57 +   * @param aPseudoType  Must match aPseudoTag.
    1.58 +   * @param aRuleNode  A rule node representing the ordered sequence of
    1.59 +   *                   rules that any element, pseudo-element, or
    1.60 +   *                   anonymous box that this style context is for
    1.61 +   *                   matches.  See |nsRuleNode| and |nsIStyleRule|.
    1.62 +   * @param aSkipFlexItemStyleFixup
    1.63 +   *                 If set, this flag indicates that we should skip
    1.64 +   *                 the chunk of ApplyStyleFixups() that modifies flex
    1.65 +   *                 items' display values.
    1.66 +   */
    1.67 +  nsStyleContext(nsStyleContext* aParent, nsIAtom* aPseudoTag,
    1.68 +                 nsCSSPseudoElements::Type aPseudoType,
    1.69 +                 nsRuleNode* aRuleNode,
    1.70 +                 bool aSkipFlexItemStyleFixup);
    1.71 +  ~nsStyleContext();
    1.72 +
    1.73 +  void* operator new(size_t sz, nsPresContext* aPresContext) CPP_THROW_NEW;
    1.74 +  void Destroy();
    1.75 +
    1.76 +  nsrefcnt AddRef() {
    1.77 +    if (mRefCnt == UINT32_MAX) {
    1.78 +      NS_WARNING("refcount overflow, leaking object");
    1.79 +      return mRefCnt;
    1.80 +    }
    1.81 +    ++mRefCnt;
    1.82 +    NS_LOG_ADDREF(this, mRefCnt, "nsStyleContext", sizeof(nsStyleContext));
    1.83 +    return mRefCnt;
    1.84 +  }
    1.85 +
    1.86 +  nsrefcnt Release() {
    1.87 +    if (mRefCnt == UINT32_MAX) {
    1.88 +      NS_WARNING("refcount overflow, leaking object");
    1.89 +      return mRefCnt;
    1.90 +    }
    1.91 +    --mRefCnt;
    1.92 +    NS_LOG_RELEASE(this, mRefCnt, "nsStyleContext");
    1.93 +    if (mRefCnt == 0) {
    1.94 +      Destroy();
    1.95 +      return 0;
    1.96 +    }
    1.97 +    return mRefCnt;
    1.98 +  }
    1.99 +
   1.100 +  nsPresContext* PresContext() const { return mRuleNode->PresContext(); }
   1.101 +
   1.102 +  nsStyleContext* GetParent() const { return mParent; }
   1.103 +
   1.104 +  nsIAtom* GetPseudo() const { return mPseudoTag; }
   1.105 +  nsCSSPseudoElements::Type GetPseudoType() const {
   1.106 +    return static_cast<nsCSSPseudoElements::Type>(mBits >>
   1.107 +                                                  NS_STYLE_CONTEXT_TYPE_SHIFT);
   1.108 +  }
   1.109 +
   1.110 +  // Find, if it already exists *and is easily findable* (i.e., near the
   1.111 +  // start of the child list), a style context whose:
   1.112 +  //  * GetPseudo() matches aPseudoTag
   1.113 +  //  * RuleNode() matches aRules
   1.114 +  //  * !GetStyleIfVisited() == !aRulesIfVisited, and, if they're
   1.115 +  //    non-null, GetStyleIfVisited()->RuleNode() == aRulesIfVisited
   1.116 +  //  * RelevantLinkVisited() == aRelevantLinkVisited
   1.117 +  already_AddRefed<nsStyleContext>
   1.118 +  FindChildWithRules(const nsIAtom* aPseudoTag, nsRuleNode* aRules,
   1.119 +                     nsRuleNode* aRulesIfVisited,
   1.120 +                     bool aRelevantLinkVisited);
   1.121 +
   1.122 +  // Does this style context or any of its ancestors have text
   1.123 +  // decoration lines?
   1.124 +  bool HasTextDecorationLines() const
   1.125 +    { return !!(mBits & NS_STYLE_HAS_TEXT_DECORATION_LINES); }
   1.126 +
   1.127 +  // Does this style context represent the style for a pseudo-element or
   1.128 +  // inherit data from such a style context?  Whether this returns true
   1.129 +  // is equivalent to whether it or any of its ancestors returns
   1.130 +  // non-null for GetPseudo.
   1.131 +  bool HasPseudoElementData() const
   1.132 +    { return !!(mBits & NS_STYLE_HAS_PSEUDO_ELEMENT_DATA); }
   1.133 +
   1.134 +  // Is the only link whose visitedness is allowed to influence the
   1.135 +  // style of the node this style context is for (which is that element
   1.136 +  // or its nearest ancestor that is a link) visited?
   1.137 +  bool RelevantLinkVisited() const
   1.138 +    { return !!(mBits & NS_STYLE_RELEVANT_LINK_VISITED); }
   1.139 +
   1.140 +  // Is this a style context for a link?
   1.141 +  bool IsLinkContext() const {
   1.142 +    return
   1.143 +      GetStyleIfVisited() && GetStyleIfVisited()->GetParent() == GetParent();
   1.144 +  }
   1.145 +
   1.146 +  // Is this style context the GetStyleIfVisited() for some other style
   1.147 +  // context?
   1.148 +  bool IsStyleIfVisited() const
   1.149 +    { return !!(mBits & NS_STYLE_IS_STYLE_IF_VISITED); }
   1.150 +
   1.151 +  // Tells this style context that it should return true from
   1.152 +  // IsStyleIfVisited.
   1.153 +  void SetIsStyleIfVisited()
   1.154 +    { mBits |= NS_STYLE_IS_STYLE_IF_VISITED; }
   1.155 +
   1.156 +  // Return the style context whose style data should be used for the R,
   1.157 +  // G, and B components of color, background-color, and border-*-color
   1.158 +  // if RelevantLinkIsVisited().
   1.159 +  //
   1.160 +  // GetPseudo() and GetPseudoType() on this style context return the
   1.161 +  // same as on |this|, and its depth in the tree (number of GetParent()
   1.162 +  // calls until null is returned) is the same as |this|, since its
   1.163 +  // parent is either |this|'s parent or |this|'s parent's
   1.164 +  // style-if-visited.
   1.165 +  //
   1.166 +  // Structs on this context should never be examined without also
   1.167 +  // examining the corresponding struct on |this|.  Doing so will likely
   1.168 +  // both (1) lead to a privacy leak and (2) lead to dynamic change bugs
   1.169 +  // related to the Peek code in nsStyleContext::CalcStyleDifference.
   1.170 +  nsStyleContext* GetStyleIfVisited() const
   1.171 +    { return mStyleIfVisited; }
   1.172 +
   1.173 +  // To be called only from nsStyleSet.
   1.174 +  void SetStyleIfVisited(already_AddRefed<nsStyleContext> aStyleIfVisited)
   1.175 +  {
   1.176 +    NS_ABORT_IF_FALSE(!IsStyleIfVisited(), "this context is not visited data");
   1.177 +    NS_ASSERTION(!mStyleIfVisited, "should only be set once");
   1.178 +
   1.179 +    mStyleIfVisited = aStyleIfVisited;
   1.180 +
   1.181 +    NS_ABORT_IF_FALSE(mStyleIfVisited->IsStyleIfVisited(),
   1.182 +                      "other context is visited data");
   1.183 +    NS_ABORT_IF_FALSE(!mStyleIfVisited->GetStyleIfVisited(),
   1.184 +                      "other context does not have visited data");
   1.185 +    NS_ASSERTION(GetStyleIfVisited()->GetPseudo() == GetPseudo(),
   1.186 +                 "pseudo tag mismatch");
   1.187 +    if (GetParent() && GetParent()->GetStyleIfVisited()) {
   1.188 +      NS_ASSERTION(GetStyleIfVisited()->GetParent() ==
   1.189 +                     GetParent()->GetStyleIfVisited() ||
   1.190 +                   GetStyleIfVisited()->GetParent() == GetParent(),
   1.191 +                   "parent mismatch");
   1.192 +    } else {
   1.193 +      NS_ASSERTION(GetStyleIfVisited()->GetParent() == GetParent(),
   1.194 +                   "parent mismatch");
   1.195 +    }
   1.196 +  }
   1.197 +
   1.198 +  // Tell this style context to cache aStruct as the struct for aSID
   1.199 +  void SetStyle(nsStyleStructID aSID, void* aStruct);
   1.200 +
   1.201 +  // Setters for inherit structs only, since rulenode only sets those eagerly.
   1.202 +  #define STYLE_STRUCT_INHERITED(name_, checkdata_cb_)                      \
   1.203 +    void SetStyle##name_ (nsStyle##name_ * aStruct) {                       \
   1.204 +      void *& slot =                                                        \
   1.205 +        mCachedInheritedData.mStyleStructs[eStyleStruct_##name_];           \
   1.206 +      NS_ASSERTION(!slot ||                                                 \
   1.207 +                   (mBits &                                                 \
   1.208 +                    nsCachedStyleData::GetBitForSID(eStyleStruct_##name_)), \
   1.209 +                   "Going to leak styledata");                              \
   1.210 +      slot = aStruct;                                                       \
   1.211 +    }
   1.212 +#define STYLE_STRUCT_RESET(name_, checkdata_cb_) /* nothing */
   1.213 +  #include "nsStyleStructList.h"
   1.214 +  #undef STYLE_STRUCT_RESET
   1.215 +  #undef STYLE_STRUCT_INHERITED
   1.216 +
   1.217 +  nsRuleNode* RuleNode() { return mRuleNode; }
   1.218 +  void AddStyleBit(const uint64_t& aBit) { mBits |= aBit; }
   1.219 +
   1.220 +  /*
   1.221 +   * Mark this style context's rule node (and its ancestors) to prevent
   1.222 +   * it from being garbage collected.
   1.223 +   */
   1.224 +  void Mark();
   1.225 +
   1.226 +  /*
   1.227 +   * Get the style data for a style struct.  This is the most important
   1.228 +   * member function of nsIStyleContext.  It fills in a const pointer
   1.229 +   * to a style data struct that is appropriate for the style context's
   1.230 +   * frame.  This struct may be shared with other contexts (either in
   1.231 +   * the rule tree or the style context tree), so it should not be
   1.232 +   * modified.
   1.233 +   *
   1.234 +   * This function will NOT return null (even when out of memory) when
   1.235 +   * given a valid style struct ID, so the result does not need to be
   1.236 +   * null-checked.
   1.237 +   *
   1.238 +   * The typesafe functions below are preferred to the use of this
   1.239 +   * function, both because they're easier to read and because they're
   1.240 +   * faster.
   1.241 +   */
   1.242 +  const void* NS_FASTCALL StyleData(nsStyleStructID aSID);
   1.243 +
   1.244 +  /**
   1.245 +   * Define typesafe getter functions for each style struct by
   1.246 +   * preprocessing the list of style structs.  These functions are the
   1.247 +   * preferred way to get style data.  The macro creates functions like:
   1.248 +   *   const nsStyleBorder* StyleBorder();
   1.249 +   *   const nsStyleColor* StyleColor();
   1.250 +   */
   1.251 +  #define STYLE_STRUCT(name_, checkdata_cb_)              \
   1.252 +    const nsStyle##name_ * Style##name_() {               \
   1.253 +      return DoGetStyle##name_(true);                     \
   1.254 +    }
   1.255 +  #include "nsStyleStructList.h"
   1.256 +  #undef STYLE_STRUCT
   1.257 +
   1.258 +  /**
   1.259 +   * PeekStyle* is like GetStyle* but doesn't trigger style
   1.260 +   * computation if the data is not cached on either the style context
   1.261 +   * or the rule node.
   1.262 +   *
   1.263 +   * Perhaps this shouldn't be a public nsStyleContext API.
   1.264 +   */
   1.265 +  #define STYLE_STRUCT(name_, checkdata_cb_)              \
   1.266 +    const nsStyle##name_ * PeekStyle##name_() {           \
   1.267 +      return DoGetStyle##name_(false);                    \
   1.268 +    }
   1.269 +  #include "nsStyleStructList.h"
   1.270 +  #undef STYLE_STRUCT
   1.271 +
   1.272 +  void* GetUniqueStyleData(const nsStyleStructID& aSID);
   1.273 +
   1.274 +  /**
   1.275 +   * Compute the style changes needed during restyling when this style
   1.276 +   * context is being replaced by aOther.  (This is nonsymmetric since
   1.277 +   * we optimize by skipping comparison for styles that have never been
   1.278 +   * requested.)
   1.279 +   *
   1.280 +   * This method returns a change hint (see nsChangeHint.h).  All change
   1.281 +   * hints apply to the frame and its later continuations or ib-split
   1.282 +   * siblings.  Most (all of those except the "NotHandledForDescendants"
   1.283 +   * hints) also apply to all descendants.  The caller must pass in any
   1.284 +   * non-inherited hints that resulted from the parent style context's
   1.285 +   * style change.  The caller *may* pass more hints than needed, but
   1.286 +   * must not pass less than needed; therefore if the caller doesn't
   1.287 +   * know, the caller should pass
   1.288 +   * nsChangeHint_Hints_NotHandledForDescendants.
   1.289 +   */
   1.290 +  nsChangeHint CalcStyleDifference(nsStyleContext* aOther,
   1.291 +                                   nsChangeHint aParentHintsNotHandledForDescendants);
   1.292 +
   1.293 +  /**
   1.294 +   * Get a color that depends on link-visitedness using this and
   1.295 +   * this->GetStyleIfVisited().
   1.296 +   *
   1.297 +   * aProperty must be a color-valued property that nsStyleAnimation
   1.298 +   * knows how to extract.  It must also be a property that we know to
   1.299 +   * do change handling for in nsStyleContext::CalcDifference.
   1.300 +   *
   1.301 +   * Note that if aProperty is eCSSProperty_border_*_color, this
   1.302 +   * function handles -moz-use-text-color.
   1.303 +   */
   1.304 +  nscolor GetVisitedDependentColor(nsCSSProperty aProperty);
   1.305 +
   1.306 +  /**
   1.307 +   * aColors should be a two element array of nscolor in which the first
   1.308 +   * color is the unvisited color and the second is the visited color.
   1.309 +   *
   1.310 +   * Combine the R, G, and B components of whichever of aColors should
   1.311 +   * be used based on aLinkIsVisited with the A component of aColors[0].
   1.312 +   */
   1.313 +  static nscolor CombineVisitedColors(nscolor *aColors,
   1.314 +                                      bool aLinkIsVisited);
   1.315 +
   1.316 +  /**
   1.317 +   * Allocate a chunk of memory that is scoped to the lifetime of this
   1.318 +   * style context, i.e., memory that will automatically be freed when
   1.319 +   * this style context is destroyed.  This is intended for allocations
   1.320 +   * that are stored on this style context or its style structs.  (Use
   1.321 +   * on style structs is fine since any style context to which this
   1.322 +   * context's style structs are shared will be a descendant of this
   1.323 +   * style context and thus keep it alive.)
   1.324 +   *
   1.325 +   * This currently allocates the memory out of the pres shell arena.
   1.326 +   *
   1.327 +   * It would be relatively straightforward to write a Free method
   1.328 +   * for the underlying implementation, but we don't need it (or the
   1.329 +   * overhead of making a doubly-linked list or other structure to
   1.330 +   * support it).
   1.331 +   *
   1.332 +   * WARNING: Memory allocated using this method cannot be stored in the
   1.333 +   * rule tree, since rule nodes may outlive the style context.
   1.334 +   */
   1.335 +  void* Alloc(size_t aSize);
   1.336 +
   1.337 +  /**
   1.338 +   * Start the background image loads for this style context.
   1.339 +   */
   1.340 +  void StartBackgroundImageLoads() {
   1.341 +    // Just get our background struct; that should do the trick
   1.342 +    StyleBackground();
   1.343 +  }
   1.344 +
   1.345 +#ifdef DEBUG
   1.346 +  void List(FILE* out, int32_t aIndent);
   1.347 +  static void AssertStyleStructMaxDifferenceValid();
   1.348 +#endif
   1.349 +
   1.350 +protected:
   1.351 +  void AddChild(nsStyleContext* aChild);
   1.352 +  void RemoveChild(nsStyleContext* aChild);
   1.353 +
   1.354 +  void ApplyStyleFixups(bool aSkipFlexItemStyleFixup);
   1.355 +
   1.356 +  void FreeAllocations(nsPresContext* aPresContext);
   1.357 +
   1.358 +  // Helper function that GetStyleData and GetUniqueStyleData use.  Only
   1.359 +  // returns the structs we cache ourselves; never consults the ruletree.
   1.360 +  inline const void* GetCachedStyleData(nsStyleStructID aSID);
   1.361 +
   1.362 +  // Helper functions for GetStyle* and PeekStyle*
   1.363 +  #define STYLE_STRUCT_INHERITED(name_, checkdata_cb_)                  \
   1.364 +    const nsStyle##name_ * DoGetStyle##name_(bool aComputeData) {       \
   1.365 +      const nsStyle##name_ * cachedData =                               \
   1.366 +        static_cast<nsStyle##name_*>(                                   \
   1.367 +          mCachedInheritedData.mStyleStructs[eStyleStruct_##name_]);    \
   1.368 +      if (cachedData) /* Have it cached already, yay */                 \
   1.369 +        return cachedData;                                              \
   1.370 +      /* Have the rulenode deal */                                      \
   1.371 +      return mRuleNode->GetStyle##name_(this, aComputeData);            \
   1.372 +    }
   1.373 +  #define STYLE_STRUCT_RESET(name_, checkdata_cb_)                      \
   1.374 +    const nsStyle##name_ * DoGetStyle##name_(bool aComputeData) {       \
   1.375 +      const nsStyle##name_ * cachedData = mCachedResetData              \
   1.376 +        ? static_cast<nsStyle##name_*>(                                 \
   1.377 +            mCachedResetData->mStyleStructs[eStyleStruct_##name_])      \
   1.378 +        : nullptr;                                                      \
   1.379 +      if (cachedData) /* Have it cached already, yay */                 \
   1.380 +        return cachedData;                                              \
   1.381 +      /* Have the rulenode deal */                                      \
   1.382 +      return mRuleNode->GetStyle##name_(this, aComputeData);            \
   1.383 +    }
   1.384 +  #include "nsStyleStructList.h"
   1.385 +  #undef STYLE_STRUCT_RESET
   1.386 +  #undef STYLE_STRUCT_INHERITED
   1.387 +
   1.388 +  nsStyleContext* const mParent; // STRONG
   1.389 +
   1.390 +  // Children are kept in two circularly-linked lists.  The list anchor
   1.391 +  // is not part of the list (null for empty), and we point to the first
   1.392 +  // child.
   1.393 +  // mEmptyChild for children whose rule node is the root rule node, and
   1.394 +  // mChild for other children.  The order of children is not
   1.395 +  // meaningful.
   1.396 +  nsStyleContext* mChild;
   1.397 +  nsStyleContext* mEmptyChild;
   1.398 +  nsStyleContext* mPrevSibling;
   1.399 +  nsStyleContext* mNextSibling;
   1.400 +
   1.401 +  // Style to be used instead for the R, G, and B components of color,
   1.402 +  // background-color, and border-*-color if the nearest ancestor link
   1.403 +  // element is visited (see RelevantLinkVisited()).
   1.404 +  nsRefPtr<nsStyleContext> mStyleIfVisited;
   1.405 +
   1.406 +  // If this style context is for a pseudo-element or anonymous box,
   1.407 +  // the relevant atom.
   1.408 +  nsCOMPtr<nsIAtom> mPseudoTag;
   1.409 +
   1.410 +  // The rule node is the node in the lexicographic tree of rule nodes
   1.411 +  // (the "rule tree") that indicates which style rules are used to
   1.412 +  // compute the style data, and in what cascading order.  The least
   1.413 +  // specific rule matched is the one whose rule node is a child of the
   1.414 +  // root of the rule tree, and the most specific rule matched is the
   1.415 +  // |mRule| member of |mRuleNode|.
   1.416 +  nsRuleNode* const       mRuleNode;
   1.417 +
   1.418 +  // Private to nsStyleContext::Alloc and FreeAllocations.
   1.419 +  struct AllocationHeader {
   1.420 +    AllocationHeader* mNext;
   1.421 +    size_t mSize;
   1.422 +
   1.423 +    void* mStorageStart; // ensure the storage is at least pointer-aligned
   1.424 +  };
   1.425 +  AllocationHeader*       mAllocations;
   1.426 +
   1.427 +  // mCachedInheritedData and mCachedResetData point to both structs that
   1.428 +  // are owned by this style context and structs that are owned by one of
   1.429 +  // this style context's ancestors (which are indirectly owned since this
   1.430 +  // style context owns a reference to its parent).  If the bit in |mBits|
   1.431 +  // is set for a struct, that means that the pointer for that struct is
   1.432 +  // owned by an ancestor or by mRuleNode rather than by this style context.
   1.433 +  // Since style contexts typically have some inherited data but only sometimes
   1.434 +  // have reset data, we always allocate the mCachedInheritedData, but only
   1.435 +  // sometimes allocate the mCachedResetData.
   1.436 +  nsResetStyleData*       mCachedResetData; // Cached reset style data.
   1.437 +  nsInheritedStyleData    mCachedInheritedData; // Cached inherited style data
   1.438 +  uint64_t                mBits; // Which structs are inherited from the
   1.439 +                                 // parent context or owned by mRuleNode.
   1.440 +  uint32_t                mRefCnt;
   1.441 +};
   1.442 +
   1.443 +already_AddRefed<nsStyleContext>
   1.444 +NS_NewStyleContext(nsStyleContext* aParentContext,
   1.445 +                   nsIAtom* aPseudoTag,
   1.446 +                   nsCSSPseudoElements::Type aPseudoType,
   1.447 +                   nsRuleNode* aRuleNode,
   1.448 +                   bool aSkipFlexItemStyleFixup);
   1.449 +#endif

mercurial