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