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/. */ 5 6 /* the interface (to internal code) for retrieving computed style data */ 7 8 #ifndef _nsStyleContext_h_ 9 #define _nsStyleContext_h_ 10 11 #include "mozilla/Assertions.h" 12 #include "mozilla/RestyleLogging.h" 13 #include "mozilla/StyleContextSource.h" 14 #include "nsCSSAnonBoxes.h" 15 #include "nsStyleSet.h" 16 17 class nsIAtom; 18 class nsPresContext; 19 20 namespace mozilla { 21 enum class CSSPseudoElementType : uint8_t; 22 } // namespace mozilla 23 24 extern "C" { 25 #define STYLE_STRUCT(name_, checkdata_cb_) \ 26 struct nsStyle##name_; \ 27 const nsStyle##name_* Servo_GetStyle##name_( \ 28 ServoComputedValuesBorrowedOrNull computed_values); 29 #include "nsStyleStructList.h" 30 #undef STYLE_STRUCT 31 } 32 33 /** 34 * An nsStyleContext represents the computed style data for an element. 35 * The computed style data are stored in a set of structs (see 36 * nsStyleStruct.h) that are cached either on the style context or in 37 * the rule tree (see nsRuleNode.h for a description of this caching and 38 * how the cached structs are shared). 39 * 40 * Since the data in |nsIStyleRule|s and |nsRuleNode|s are immutable 41 * (with a few exceptions, like system color changes), the data in an 42 * nsStyleContext are also immutable (with the additional exception of 43 * GetUniqueStyleData). When style data change, 44 * ElementRestyler::Restyle creates a new style context. 45 * 46 * Style contexts are reference counted. References are generally held 47 * by: 48 * 1. the |nsIFrame|s that are using the style context and 49 * 2. any *child* style contexts (this might be the reverse of 50 * expectation, but it makes sense in this case) 51 */ 52 53 class nsStyleContext final 54 { 55 public: 56 /** 57 * Create a new style context. 58 * @param aParent The parent of a style context is used for CSS 59 * inheritance. When the element or pseudo-element 60 * this style context represents the style data of 61 * inherits a CSS property, the value comes from the 62 * parent style context. This means style context 63 * parentage must match the definitions of inheritance 64 * in the CSS specification. 65 * @param aPseudoTag The pseudo-element or anonymous box for which 66 * this style context represents style. Null if 67 * this style context is for a normal DOM element. 68 * @param aPseudoType Must match aPseudoTag. 69 * @param aRuleNode A rule node representing the ordered sequence of 70 * rules that any element, pseudo-element, or 71 * anonymous box that this style context is for 72 * matches. See |nsRuleNode| and |nsIStyleRule|. 73 * @param aSkipParentDisplayBasedStyleFixup 74 * If set, this flag indicates that we should skip 75 * the chunk of ApplyStyleFixups() that applies to 76 * special cases where a child element's style may 77 * need to be modified based on its parent's display 78 * value. 79 */ 80 nsStyleContext(nsStyleContext* aParent, nsIAtom* aPseudoTag, 81 mozilla::CSSPseudoElementType aPseudoType, 82 already_AddRefed<nsRuleNode> aRuleNode, 83 bool aSkipParentDisplayBasedStyleFixup); 84 85 // Version of the above that takes a ServoComputedValues instead of a Gecko 86 // nsRuleNode. 87 nsStyleContext(nsStyleContext* aParent, 88 nsPresContext* aPresContext, 89 nsIAtom* aPseudoTag, 90 mozilla::CSSPseudoElementType aPseudoType, 91 already_AddRefed<ServoComputedValues> aComputedValues, 92 bool aSkipParentDisplayBasedStyleFixup); 93 94 void* operator new(size_t sz, nsPresContext* aPresContext); 95 void Destroy(); 96 97 // These two methods are for use by ArenaRefPtr. ArenaObjectID()98 static mozilla::ArenaObjectID ArenaObjectID() 99 { 100 return mozilla::eArenaObjectID_nsStyleContext; 101 } 102 nsIPresShell* Arena(); 103 104 #ifdef DEBUG 105 /** 106 * Initializes a cached pref, which is only used in DEBUG code. 107 */ 108 static void Initialize(); 109 #endif 110 AddRef()111 nsrefcnt AddRef() { 112 if (mRefCnt == UINT32_MAX) { 113 NS_WARNING("refcount overflow, leaking object"); 114 return mRefCnt; 115 } 116 ++mRefCnt; 117 NS_LOG_ADDREF(this, mRefCnt, "nsStyleContext", sizeof(nsStyleContext)); 118 return mRefCnt; 119 } 120 Release()121 nsrefcnt Release() { 122 if (mRefCnt == UINT32_MAX) { 123 NS_WARNING("refcount overflow, leaking object"); 124 return mRefCnt; 125 } 126 --mRefCnt; 127 NS_LOG_RELEASE(this, mRefCnt, "nsStyleContext"); 128 if (mRefCnt == 0) { 129 Destroy(); 130 return 0; 131 } 132 return mRefCnt; 133 } 134 135 #ifdef DEBUG FrameAddRef()136 void FrameAddRef() { 137 ++mFrameRefCnt; 138 } 139 FrameRelease()140 void FrameRelease() { 141 --mFrameRefCnt; 142 } 143 FrameRefCnt()144 uint32_t FrameRefCnt() const { 145 return mFrameRefCnt; 146 } 147 #endif 148 HasSingleReference()149 bool HasSingleReference() const { 150 NS_ASSERTION(mRefCnt != 0, 151 "do not call HasSingleReference on a newly created " 152 "nsStyleContext with no references yet"); 153 return mRefCnt == 1; 154 } 155 PresContext()156 nsPresContext* PresContext() const { 157 #ifdef MOZ_STYLO 158 return mPresContext; 159 #else 160 return mSource.AsGeckoRuleNode()->PresContext(); 161 #endif 162 } 163 GetParent()164 nsStyleContext* GetParent() const { return mParent; } 165 GetPseudo()166 nsIAtom* GetPseudo() const { return mPseudoTag; } GetPseudoType()167 mozilla::CSSPseudoElementType GetPseudoType() const { 168 return static_cast<mozilla::CSSPseudoElementType>( 169 mBits >> NS_STYLE_CONTEXT_TYPE_SHIFT); 170 } 171 IsAnonBox()172 bool IsAnonBox() const { 173 return GetPseudoType() == mozilla::CSSPseudoElementType::AnonBox; 174 } IsPseudoElement()175 bool IsPseudoElement() const { return mPseudoTag && !IsAnonBox(); } 176 177 178 // Find, if it already exists *and is easily findable* (i.e., near the 179 // start of the child list), a style context whose: 180 // * GetPseudo() matches aPseudoTag 181 // * mSource matches aSource 182 // * !!GetStyleIfVisited() == !!aSourceIfVisited, and, if they're 183 // non-null, GetStyleIfVisited()->mSource == aSourceIfVisited 184 // * RelevantLinkVisited() == aRelevantLinkVisited 185 already_AddRefed<nsStyleContext> 186 FindChildWithRules(const nsIAtom* aPseudoTag, 187 mozilla::NonOwningStyleContextSource aSource, 188 mozilla::NonOwningStyleContextSource aSourceIfVisited, 189 bool aRelevantLinkVisited); 190 191 // Does this style context or any of its ancestors have text 192 // decoration lines? 193 // Differs from nsStyleTextReset::HasTextDecorationLines, which tests 194 // only the data for a single context. HasTextDecorationLines()195 bool HasTextDecorationLines() const 196 { return !!(mBits & NS_STYLE_HAS_TEXT_DECORATION_LINES); } 197 198 // Whether any line break inside should be suppressed? If this returns 199 // true, the line should not be broken inside, which means inlines act 200 // as if nowrap is set, <br> is suppressed, and blocks are inlinized. 201 // This bit is propogated to all children of line partitipants. It is 202 // currently used by ruby to make its content frames unbreakable. 203 // NOTE: for nsTextFrame, use nsTextFrame::ShouldSuppressLineBreak() 204 // instead of this method. ShouldSuppressLineBreak()205 bool ShouldSuppressLineBreak() const 206 { return !!(mBits & NS_STYLE_SUPPRESS_LINEBREAK); } 207 208 // Does this style context or any of its ancestors have display:none set? IsInDisplayNoneSubtree()209 bool IsInDisplayNoneSubtree() const 210 { return !!(mBits & NS_STYLE_IN_DISPLAY_NONE_SUBTREE); } 211 212 // Is this horizontal-in-vertical (tate-chu-yoko) text? This flag is 213 // only set on style contexts whose pseudo is nsCSSAnonBoxes::mozText. IsTextCombined()214 bool IsTextCombined() const 215 { return !!(mBits & NS_STYLE_IS_TEXT_COMBINED); } 216 217 // Does this style context represent the style for a pseudo-element or 218 // inherit data from such a style context? Whether this returns true 219 // is equivalent to whether it or any of its ancestors returns 220 // non-null for IsPseudoElement(). HasPseudoElementData()221 bool HasPseudoElementData() const 222 { return !!(mBits & NS_STYLE_HAS_PSEUDO_ELEMENT_DATA); } 223 HasChildThatUsesResetStyle()224 bool HasChildThatUsesResetStyle() const 225 { return mBits & NS_STYLE_HAS_CHILD_THAT_USES_RESET_STYLE; } 226 227 // Is the only link whose visitedness is allowed to influence the 228 // style of the node this style context is for (which is that element 229 // or its nearest ancestor that is a link) visited? RelevantLinkVisited()230 bool RelevantLinkVisited() const 231 { return !!(mBits & NS_STYLE_RELEVANT_LINK_VISITED); } 232 233 // Is this a style context for a link? IsLinkContext()234 bool IsLinkContext() const { 235 return 236 GetStyleIfVisited() && GetStyleIfVisited()->GetParent() == GetParent(); 237 } 238 239 // Is this style context the GetStyleIfVisited() for some other style 240 // context? IsStyleIfVisited()241 bool IsStyleIfVisited() const 242 { return !!(mBits & NS_STYLE_IS_STYLE_IF_VISITED); } 243 244 // Tells this style context that it should return true from 245 // IsStyleIfVisited. SetIsStyleIfVisited()246 void SetIsStyleIfVisited() 247 { mBits |= NS_STYLE_IS_STYLE_IF_VISITED; } 248 249 // Return the style context whose style data should be used for the R, 250 // G, and B components of color, background-color, and border-*-color 251 // if RelevantLinkIsVisited(). 252 // 253 // GetPseudo() and GetPseudoType() on this style context return the 254 // same as on |this|, and its depth in the tree (number of GetParent() 255 // calls until null is returned) is the same as |this|, since its 256 // parent is either |this|'s parent or |this|'s parent's 257 // style-if-visited. 258 // 259 // Structs on this context should never be examined without also 260 // examining the corresponding struct on |this|. Doing so will likely 261 // both (1) lead to a privacy leak and (2) lead to dynamic change bugs 262 // related to the Peek code in nsStyleContext::CalcStyleDifference. GetStyleIfVisited()263 nsStyleContext* GetStyleIfVisited() const 264 { return mStyleIfVisited; } 265 266 // To be called only from nsStyleSet. SetStyleIfVisited(already_AddRefed<nsStyleContext> aStyleIfVisited)267 void SetStyleIfVisited(already_AddRefed<nsStyleContext> aStyleIfVisited) 268 { 269 MOZ_ASSERT(!IsStyleIfVisited(), "this context is not visited data"); 270 NS_ASSERTION(!mStyleIfVisited, "should only be set once"); 271 272 mStyleIfVisited = aStyleIfVisited; 273 274 MOZ_ASSERT(mStyleIfVisited->IsStyleIfVisited(), 275 "other context is visited data"); 276 MOZ_ASSERT(!mStyleIfVisited->GetStyleIfVisited(), 277 "other context does not have visited data"); 278 NS_ASSERTION(GetStyleIfVisited()->GetPseudo() == GetPseudo(), 279 "pseudo tag mismatch"); 280 if (GetParent() && GetParent()->GetStyleIfVisited()) { 281 NS_ASSERTION(GetStyleIfVisited()->GetParent() == 282 GetParent()->GetStyleIfVisited() || 283 GetStyleIfVisited()->GetParent() == GetParent(), 284 "parent mismatch"); 285 } else { 286 NS_ASSERTION(GetStyleIfVisited()->GetParent() == GetParent(), 287 "parent mismatch"); 288 } 289 } 290 291 // Does any descendant of this style context have any style values 292 // that were computed based on this style context's ancestors? HasChildThatUsesGrandancestorStyle()293 bool HasChildThatUsesGrandancestorStyle() const 294 { return !!(mBits & NS_STYLE_CHILD_USES_GRANDANCESTOR_STYLE); } 295 296 // Is this style context shared with a sibling or cousin? 297 // (See nsStyleSet::GetContext.) IsShared()298 bool IsShared() const 299 { return !!(mBits & NS_STYLE_IS_SHARED); } 300 301 // Tell this style context to cache aStruct as the struct for aSID 302 void SetStyle(nsStyleStructID aSID, void* aStruct); 303 304 /** 305 * Returns whether this style context has cached style data for a 306 * given style struct and it does NOT own that struct. This can 307 * happen because it was inherited from the parent style context, or 308 * because it was stored conditionally on the rule node. 309 */ HasCachedDependentStyleData(nsStyleStructID aSID)310 bool HasCachedDependentStyleData(nsStyleStructID aSID) { 311 return mBits & nsCachedStyleData::GetBitForSID(aSID); 312 } 313 RuleNode()314 nsRuleNode* RuleNode() { 315 MOZ_RELEASE_ASSERT(mSource.IsGeckoRuleNode()); 316 return mSource.AsGeckoRuleNode(); 317 } 318 AddStyleBit(const uint64_t & aBit)319 void AddStyleBit(const uint64_t& aBit) { mBits |= aBit; } 320 321 /* 322 * Get the style data for a style struct. This is the most important 323 * member function of nsStyleContext. It fills in a const pointer 324 * to a style data struct that is appropriate for the style context's 325 * frame. This struct may be shared with other contexts (either in 326 * the rule tree or the style context tree), so it should not be 327 * modified. 328 * 329 * This function will NOT return null (even when out of memory) when 330 * given a valid style struct ID, so the result does not need to be 331 * null-checked. 332 * 333 * The typesafe functions below are preferred to the use of this 334 * function, both because they're easier to read and because they're 335 * faster. 336 */ 337 const void* NS_FASTCALL StyleData(nsStyleStructID aSID); 338 339 /** 340 * Define typesafe getter functions for each style struct by 341 * preprocessing the list of style structs. These functions are the 342 * preferred way to get style data. The macro creates functions like: 343 * const nsStyleBorder* StyleBorder(); 344 * const nsStyleColor* StyleColor(); 345 */ 346 #define STYLE_STRUCT(name_, checkdata_cb_) \ 347 const nsStyle##name_ * Style##name_() { \ 348 return DoGetStyle##name_<true>(); \ 349 } 350 #include "nsStyleStructList.h" 351 #undef STYLE_STRUCT 352 353 /** 354 * PeekStyle* is like Style* but doesn't trigger style 355 * computation if the data is not cached on either the style context 356 * or the rule node. 357 * 358 * Perhaps this shouldn't be a public nsStyleContext API. 359 */ 360 #define STYLE_STRUCT(name_, checkdata_cb_) \ 361 const nsStyle##name_ * PeekStyle##name_() { \ 362 return DoGetStyle##name_<false>(); \ 363 } 364 #include "nsStyleStructList.h" 365 #undef STYLE_STRUCT 366 367 /** 368 * Compute the style changes needed during restyling when this style 369 * context is being replaced by aNewContext. (This is nonsymmetric since 370 * we optimize by skipping comparison for styles that have never been 371 * requested.) 372 * 373 * This method returns a change hint (see nsChangeHint.h). All change 374 * hints apply to the frame and its later continuations or ib-split 375 * siblings. Most (all of those except the "NotHandledForDescendants" 376 * hints) also apply to all descendants. The caller must pass in any 377 * non-inherited hints that resulted from the parent style context's 378 * style change. The caller *may* pass more hints than needed, but 379 * must not pass less than needed; therefore if the caller doesn't 380 * know, the caller should pass 381 * nsChangeHint_Hints_NotHandledForDescendants. 382 * 383 * aEqualStructs must not be null. Into it will be stored a bitfield 384 * representing which structs were compared to be non-equal. 385 */ 386 nsChangeHint CalcStyleDifference(nsStyleContext* aNewContext, 387 nsChangeHint aParentHintsNotHandledForDescendants, 388 uint32_t* aEqualStructs, 389 uint32_t* aSamePointerStructs); 390 391 /** 392 * Like the above, but allows comparing ServoComputedValues instead of needing 393 * a full-fledged style context. 394 */ 395 nsChangeHint CalcStyleDifference(const ServoComputedValues* aNewComputedValues, 396 nsChangeHint aParentHintsNotHandledForDescendants, 397 uint32_t* aEqualStructs, 398 uint32_t* aSamePointerStructs); 399 400 private: 401 template<class StyleContextLike> 402 nsChangeHint CalcStyleDifferenceInternal(StyleContextLike* aNewContext, 403 nsChangeHint aParentHintsNotHandledForDescendants, 404 uint32_t* aEqualStructs, 405 uint32_t* aSamePointerStructs); 406 407 public: 408 /** 409 * Get a color that depends on link-visitedness using this and 410 * this->GetStyleIfVisited(). 411 * 412 * aProperty must be a color-valued property that StyleAnimationValue 413 * knows how to extract. It must also be a property that we know to 414 * do change handling for in nsStyleContext::CalcDifference. 415 */ 416 nscolor GetVisitedDependentColor(nsCSSPropertyID aProperty); 417 418 /** 419 * aColors should be a two element array of nscolor in which the first 420 * color is the unvisited color and the second is the visited color. 421 * 422 * Combine the R, G, and B components of whichever of aColors should 423 * be used based on aLinkIsVisited with the A component of aColors[0]. 424 */ 425 static nscolor CombineVisitedColors(nscolor *aColors, 426 bool aLinkIsVisited); 427 428 /** 429 * Start the background image loads for this style context. 430 */ StartBackgroundImageLoads()431 void StartBackgroundImageLoads() { 432 // Just get our background struct; that should do the trick 433 StyleBackground(); 434 } 435 436 /** 437 * Moves this style context to a new parent. 438 * 439 * This function violates style context tree immutability, and 440 * is a very low-level function and should only be used after verifying 441 * many conditions that make it safe to call. 442 */ 443 void MoveTo(nsStyleContext* aNewParent); 444 445 /** 446 * Swaps owned style struct pointers between this and aNewContext, on 447 * the assumption that aNewContext is the new style context for a frame 448 * and this is the old one. aStructs indicates which structs to consider 449 * swapping; only those which are owned in both this and aNewContext 450 * will be swapped. 451 * 452 * Additionally, if there are identical struct pointers for one of the 453 * structs indicated by aStructs, and it is not an owned struct on this, 454 * then the cached struct slot on this will be set to null. If the struct 455 * has been swapped on an ancestor, this style context (being the old one) 456 * will be left caching the struct pointer on the new ancestor, despite 457 * inheriting from the old ancestor. This is not normally a problem, as 458 * this style context will usually be destroyed by being released at the 459 * end of ElementRestyler::Restyle; but for style contexts held on to outside 460 * of the frame, we need to clear out the cached pointer so that if we need 461 * it again we'll re-fetch it from the new ancestor. 462 */ 463 void SwapStyleData(nsStyleContext* aNewContext, uint32_t aStructs); 464 465 /** 466 * On each descendant of this style context, clears out any cached inherited 467 * structs indicated in aStructs. 468 */ 469 void ClearCachedInheritedStyleDataOnDescendants(uint32_t aStructs); 470 471 /** 472 * Sets the NS_STYLE_INELIGIBLE_FOR_SHARING bit on this style context 473 * and its descendants. If it finds a descendant that has the bit 474 * already set, assumes that it can skip that subtree. 475 */ 476 void SetIneligibleForSharing(); 477 478 #ifdef DEBUG 479 void List(FILE* out, int32_t aIndent, bool aListDescendants = true); 480 static void AssertStyleStructMaxDifferenceValid(); 481 static const char* StructName(nsStyleStructID aSID); 482 static bool LookupStruct(const nsACString& aName, nsStyleStructID& aResult); 483 #endif 484 485 #ifdef RESTYLE_LOGGING 486 nsCString GetCachedStyleDataAsString(uint32_t aStructs); 487 void LogStyleContextTree(int32_t aLoggingDepth, uint32_t aStructs); 488 int32_t& LoggingDepth(); 489 #endif 490 491 /** 492 * Return style data that is currently cached on the style context. 493 * Only returns the structs we cache ourselves; never consults the 494 * rule tree. 495 * 496 * For "internal" use only in nsStyleContext and nsRuleNode. 497 */ GetCachedStyleData(nsStyleStructID aSID)498 const void* GetCachedStyleData(nsStyleStructID aSID) 499 { 500 const void* cachedData; 501 if (nsCachedStyleData::IsReset(aSID)) { 502 if (mCachedResetData) { 503 cachedData = mCachedResetData->mStyleStructs[aSID]; 504 } else { 505 cachedData = nullptr; 506 } 507 } else { 508 cachedData = mCachedInheritedData.mStyleStructs[aSID]; 509 } 510 return cachedData; 511 } 512 StyleSource()513 mozilla::NonOwningStyleContextSource StyleSource() const { return mSource.AsRaw(); } 514 515 #ifdef MOZ_STYLO 516 // NOTE: It'd be great to assert here that the previous change hint is always 517 // consumed. 518 // 519 // This is not the case right now, since the changes of childs of frames that 520 // go through frame construction are not consumed. StoreChangeHint(nsChangeHint aHint)521 void StoreChangeHint(nsChangeHint aHint) 522 { 523 MOZ_ASSERT(!IsShared()); 524 mStoredChangeHint = aHint; 525 #ifdef DEBUG 526 mConsumedChangeHint = false; 527 #endif 528 } 529 ConsumeStoredChangeHint()530 nsChangeHint ConsumeStoredChangeHint() 531 { 532 MOZ_ASSERT(!mConsumedChangeHint, "Re-consuming the same change hint!"); 533 nsChangeHint result = mStoredChangeHint; 534 mStoredChangeHint = nsChangeHint(0); 535 #ifdef DEBUG 536 mConsumedChangeHint = true; 537 #endif 538 return result; 539 } 540 #else StoreChangeHint(nsChangeHint aHint)541 void StoreChangeHint(nsChangeHint aHint) 542 { 543 MOZ_CRASH("stylo: Called nsStyleContext::StoreChangeHint in a non MOZ_STYLO " 544 "build."); 545 } 546 ConsumeStoredChangeHint()547 nsChangeHint ConsumeStoredChangeHint() 548 { 549 MOZ_CRASH("stylo: Called nsStyleContext::ComsumeStoredChangeHint in a non " 550 "MOZ_STYLO build."); 551 } 552 #endif 553 554 private: 555 // Private destructor, to discourage deletion outside of Release(): 556 ~nsStyleContext(); 557 558 // Delegated Helper constructor. 559 nsStyleContext(nsStyleContext* aParent, 560 mozilla::OwningStyleContextSource&& aSource, 561 nsIAtom* aPseudoTag, 562 mozilla::CSSPseudoElementType aPseudoType); 563 564 // Helper post-contruct hook. 565 void FinishConstruction(bool aSkipParentDisplayBasedStyleFixup); 566 567 void AddChild(nsStyleContext* aChild); 568 void RemoveChild(nsStyleContext* aChild); 569 570 void* GetUniqueStyleData(const nsStyleStructID& aSID); 571 void* CreateEmptyStyleData(const nsStyleStructID& aSID); 572 573 void SetStyleBits(); 574 void ApplyStyleFixups(bool aSkipParentDisplayBasedStyleFixup); 575 StyleStructFromServoComputedValues(nsStyleStructID aSID)576 const void* StyleStructFromServoComputedValues(nsStyleStructID aSID) { 577 switch (aSID) { 578 #define STYLE_STRUCT(name_, checkdata_cb_) \ 579 case eStyleStruct_##name_: \ 580 return Servo_GetStyle##name_(mSource.AsServoComputedValues()); 581 #include "nsStyleStructList.h" 582 #undef STYLE_STRUCT 583 default: 584 MOZ_ASSERT_UNREACHABLE("unexpected nsStyleStructID value"); 585 return nullptr; 586 } 587 } 588 589 #ifdef DEBUG 590 struct AutoCheckDependency { 591 592 nsStyleContext* mStyleContext; 593 nsStyleStructID mOuterSID; 594 AutoCheckDependencyAutoCheckDependency595 AutoCheckDependency(nsStyleContext* aContext, nsStyleStructID aInnerSID) 596 : mStyleContext(aContext) 597 { 598 mOuterSID = aContext->mComputingStruct; 599 MOZ_ASSERT(mOuterSID == nsStyleStructID_None || 600 DependencyAllowed(mOuterSID, aInnerSID), 601 "Undeclared dependency, see generate-stylestructlist.py"); 602 aContext->mComputingStruct = aInnerSID; 603 } 604 ~AutoCheckDependencyAutoCheckDependency605 ~AutoCheckDependency() 606 { 607 mStyleContext->mComputingStruct = mOuterSID; 608 } 609 610 }; 611 612 #define AUTO_CHECK_DEPENDENCY(sid_) \ 613 AutoCheckDependency checkNesting_(this, sid_) 614 #else 615 #define AUTO_CHECK_DEPENDENCY(sid_) 616 #endif 617 618 // Helper functions for GetStyle* and PeekStyle* 619 #define STYLE_STRUCT_INHERITED(name_, checkdata_cb_) \ 620 template<bool aComputeData> \ 621 const nsStyle##name_ * DoGetStyle##name_() { \ 622 const nsStyle##name_ * cachedData = \ 623 static_cast<nsStyle##name_*>( \ 624 mCachedInheritedData.mStyleStructs[eStyleStruct_##name_]); \ 625 if (cachedData) /* Have it cached already, yay */ \ 626 return cachedData; \ 627 if (!aComputeData) { \ 628 /* We always cache inherited structs on the context when we */ \ 629 /* compute them. */ \ 630 return nullptr; \ 631 } \ 632 /* Have the rulenode deal */ \ 633 AUTO_CHECK_DEPENDENCY(eStyleStruct_##name_); \ 634 const nsStyle##name_ * newData; \ 635 if (mSource.IsGeckoRuleNode()) { \ 636 newData = mSource.AsGeckoRuleNode()-> \ 637 GetStyle##name_<aComputeData>(this, mBits); \ 638 } else { \ 639 /** \ 640 * Reach the parent to grab the inherited style struct if \ 641 * we're a text node. \ 642 * \ 643 * This causes the parent element's style context to cache any \ 644 * inherited structs we request for a text node, which means we \ 645 * don't have to compute change hints for the text node, as \ 646 * handling the change on the parent element is sufficient. \ 647 * \ 648 * Note that adding the inherit bit is ok, because the struct \ 649 * pointer returned by the parent and the child is owned by \ 650 * Servo. This is fine if the pointers are the same (as it \ 651 * should, read below), because both style context sources will \ 652 * hold it. \ 653 * \ 654 * In the case of a mishandled frame, we could end up with the \ 655 * pointer to and old parent style, but that's fine too, since \ 656 * the parent style context will remain alive until we reframe, \ 657 * in which case we'll discard both style contexts. Also, we \ 658 * hold a strong reference to the parent style context, which \ 659 * makes it a non-issue. \ 660 * \ 661 * Also, note that the assertion below should be true, except \ 662 * for those frames we still don't handle correctly, like \ 663 * anonymous table wrappers, in which case the pointers will \ 664 * differ. \ 665 * \ 666 * That means we're not going to restyle correctly text frames \ 667 * of anonymous table wrappers, for example. It's kind of \ 668 * embarrassing, but I think it's not worth it to add more \ 669 * logic here unconditionally, given that's going to be fixed. \ 670 * \ 671 * TODO(emilio): Convert to a strong assertion once we support \ 672 * all kinds of random frames. In fact, this can be a great \ 673 * assertion to debug them. \ 674 */ \ 675 if (mPseudoTag == nsCSSAnonBoxes::mozText) { \ 676 MOZ_ASSERT(mParent); \ 677 newData = mParent->DoGetStyle##name_<true>(); \ 678 NS_WARNING_ASSERTION( \ 679 newData == Servo_GetStyle##name_(mSource.AsServoComputedValues()), \ 680 "bad newData"); \ 681 } else { \ 682 newData = \ 683 Servo_GetStyle##name_(mSource.AsServoComputedValues()); \ 684 } \ 685 /* perform any remaining main thread work on the struct */ \ 686 const_cast<nsStyle##name_*>(newData)->FinishStyle(PresContext());\ 687 /* the Servo-backed StyleContextSource owns the struct */ \ 688 AddStyleBit(NS_STYLE_INHERIT_BIT(name_)); \ 689 } \ 690 /* always cache inherited data on the style context; the rule */ \ 691 /* node set the bit in mBits for us if needed. */ \ 692 mCachedInheritedData.mStyleStructs[eStyleStruct_##name_] = \ 693 const_cast<nsStyle##name_ *>(newData); \ 694 return newData; \ 695 } 696 #define STYLE_STRUCT_RESET(name_, checkdata_cb_) \ 697 template<bool aComputeData> \ 698 const nsStyle##name_ * DoGetStyle##name_() { \ 699 if (mCachedResetData) { \ 700 const nsStyle##name_ * cachedData = \ 701 static_cast<nsStyle##name_*>( \ 702 mCachedResetData->mStyleStructs[eStyleStruct_##name_]); \ 703 if (cachedData) /* Have it cached already, yay */ \ 704 return cachedData; \ 705 } \ 706 /* Have the rulenode deal */ \ 707 AUTO_CHECK_DEPENDENCY(eStyleStruct_##name_); \ 708 const nsStyle##name_ * newData; \ 709 if (mSource.IsGeckoRuleNode()) { \ 710 newData = mSource.AsGeckoRuleNode()-> \ 711 GetStyle##name_<aComputeData>(this); \ 712 } else { \ 713 newData = \ 714 Servo_GetStyle##name_(mSource.AsServoComputedValues()); \ 715 /* perform any remaining main thread work on the struct */ \ 716 const_cast<nsStyle##name_*>(newData)->FinishStyle(PresContext());\ 717 /* The Servo-backed StyleContextSource owns the struct. \ 718 * \ 719 * XXXbholley: Unconditionally caching reset structs here \ 720 * defeats the memory optimization where we lazily allocate \ 721 * mCachedResetData, so that we can avoid performing an FFI \ 722 * call each time we want to get the style structs. We should \ 723 * measure the tradeoffs at some point. If the FFI overhead is \ 724 * low and the memory win significant, we should consider \ 725 * _always_ grabbing the struct over FFI, and potentially \ 726 * giving mCachedInheritedData the same treatment. \ 727 * \ 728 * Note that there is a similar comment in StyleData(). \ 729 */ \ 730 AddStyleBit(NS_STYLE_INHERIT_BIT(name_)); \ 731 SetStyle(eStyleStruct_##name_, \ 732 const_cast<nsStyle##name_*>(newData)); \ 733 } \ 734 return newData; \ 735 } 736 #include "nsStyleStructList.h" 737 #undef STYLE_STRUCT_RESET 738 #undef STYLE_STRUCT_INHERITED 739 740 // Helper for ClearCachedInheritedStyleDataOnDescendants. 741 void DoClearCachedInheritedStyleDataOnDescendants(uint32_t aStructs); 742 743 #ifdef DEBUG 744 void AssertStructsNotUsedElsewhere(nsStyleContext* aDestroyingContext, 745 int32_t aLevels) const; 746 #endif 747 748 #ifdef RESTYLE_LOGGING 749 void LogStyleContextTree(bool aFirst, uint32_t aStructs); 750 751 // This only gets called under call trees where we've already checked 752 // that PresContext()->RestyleManager()->ShouldLogRestyle() returned true. 753 // It exists here just to satisfy LOG_RESTYLE's expectations. ShouldLogRestyle()754 bool ShouldLogRestyle() { return true; } 755 #endif 756 757 RefPtr<nsStyleContext> mParent; 758 759 // Children are kept in two circularly-linked lists. The list anchor 760 // is not part of the list (null for empty), and we point to the first 761 // child. 762 // mEmptyChild for children whose rule node is the root rule node, and 763 // mChild for other children. The order of children is not 764 // meaningful. 765 nsStyleContext* mChild; 766 nsStyleContext* mEmptyChild; 767 nsStyleContext* mPrevSibling; 768 nsStyleContext* mNextSibling; 769 770 // Style to be used instead for the R, G, and B components of color, 771 // background-color, and border-*-color if the nearest ancestor link 772 // element is visited (see RelevantLinkVisited()). 773 RefPtr<nsStyleContext> mStyleIfVisited; 774 775 // If this style context is for a pseudo-element or anonymous box, 776 // the relevant atom. 777 nsCOMPtr<nsIAtom> mPseudoTag; 778 779 // The source for our style data, either a Gecko nsRuleNode or a Servo 780 // ComputedValues struct. This never changes after construction, except 781 // when it's released and nulled out during teardown. 782 const mozilla::OwningStyleContextSource mSource; 783 784 #ifdef MOZ_STYLO 785 // In Gecko, we can get this off the rule node. We make this conditional 786 // on stylo builds to avoid the memory bloat on release. 787 nsPresContext* mPresContext; 788 #endif 789 790 // mCachedInheritedData and mCachedResetData point to both structs that 791 // are owned by this style context and structs that are owned by one of 792 // this style context's ancestors (which are indirectly owned since this 793 // style context owns a reference to its parent). If the bit in |mBits| 794 // is set for a struct, that means that the pointer for that struct is 795 // owned by an ancestor or by the rule node rather than by this style context. 796 // Since style contexts typically have some inherited data but only sometimes 797 // have reset data, we always allocate the mCachedInheritedData, but only 798 // sometimes allocate the mCachedResetData. 799 nsResetStyleData* mCachedResetData; // Cached reset style data. 800 nsInheritedStyleData mCachedInheritedData; // Cached inherited style data 801 802 // mBits stores a number of things: 803 // - It records (using the style struct bits) which structs are 804 // inherited from the parent context or owned by the rule node (i.e., 805 // not owned by the style context). 806 // - It also stores the additional bits listed at the top of 807 // nsStyleStruct.h. 808 uint64_t mBits; 809 810 uint32_t mRefCnt; 811 812 // For now we store change hints on the style context during parallel traversal. 813 // We should improve this - see bug 1289861. 814 #ifdef MOZ_STYLO 815 nsChangeHint mStoredChangeHint; 816 #ifdef DEBUG 817 bool mConsumedChangeHint; 818 #endif 819 #endif 820 821 #ifdef DEBUG 822 uint32_t mFrameRefCnt; // number of frames that use this 823 // as their style context 824 825 nsStyleStructID mComputingStruct; 826 DependencyAllowed(nsStyleStructID aOuterSID,nsStyleStructID aInnerSID)827 static bool DependencyAllowed(nsStyleStructID aOuterSID, 828 nsStyleStructID aInnerSID) 829 { 830 return !!(sDependencyTable[aOuterSID] & 831 nsCachedStyleData::GetBitForSID(aInnerSID)); 832 } 833 834 static const uint32_t sDependencyTable[]; 835 #endif 836 }; 837 838 already_AddRefed<nsStyleContext> 839 NS_NewStyleContext(nsStyleContext* aParentContext, 840 nsIAtom* aPseudoTag, 841 mozilla::CSSPseudoElementType aPseudoType, 842 nsRuleNode* aRuleNode, 843 bool aSkipParentDisplayBasedStyleFixup); 844 845 already_AddRefed<nsStyleContext> 846 NS_NewStyleContext(nsStyleContext* aParentContext, 847 nsPresContext* aPresContext, 848 nsIAtom* aPseudoTag, 849 mozilla::CSSPseudoElementType aPseudoType, 850 already_AddRefed<ServoComputedValues> aComputedValues, 851 bool aSkipParentDisplayBasedStyleFixup); 852 853 #endif 854