layout/style/nsStyleContext.h

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

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

mercurial