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