LCOV - code coverage report
Current view: top level - layout/style - GeckoStyleContext.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 272 465 58.5 %
Date: 2017-07-14 16:53:18 Functions: 19 25 76.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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             : #include "mozilla/GeckoStyleContext.h"
       7             : 
       8             : #include "nsStyleConsts.h"
       9             : #include "nsStyleStruct.h"
      10             : #include "nsPresContext.h"
      11             : #include "nsRuleNode.h"
      12             : #include "nsStyleContextInlines.h"
      13             : #include "nsIFrame.h"
      14             : #include "nsLayoutUtils.h"
      15             : #include "mozilla/ReflowInput.h"
      16             : #include "RubyUtils.h"
      17             : 
      18             : using namespace mozilla;
      19             : 
      20        2203 : GeckoStyleContext::GeckoStyleContext(nsStyleContext* aParent,
      21             :                                      nsIAtom* aPseudoTag,
      22             :                                      CSSPseudoElementType aPseudoType,
      23             :                                      already_AddRefed<nsRuleNode> aRuleNode,
      24        2203 :                                      bool aSkipParentDisplayBasedStyleFixup)
      25             :   : nsStyleContext(aParent, aPseudoTag, aPseudoType)
      26             :   , mCachedResetData(nullptr)
      27             :   , mChild(nullptr)
      28             :   , mEmptyChild(nullptr)
      29        2203 :   , mRuleNode(Move(aRuleNode))
      30             : #ifdef DEBUG
      31        4406 :   , mComputingStruct(nsStyleStructID_None)
      32             : #endif
      33             : {
      34        2203 :   mBits |= NS_STYLE_CONTEXT_IS_GECKO;
      35             : 
      36        2203 :   if (aParent) {
      37             : #ifdef DEBUG
      38        2016 :     nsRuleNode *r1 = mParent->RuleNode(), *r2 = mRuleNode;
      39       20544 :     while (r1->GetParent())
      40        9264 :       r1 = r1->GetParent();
      41        8446 :     while (r2->GetParent())
      42        8446 :       r2 = r2->GetParent();
      43        2016 :     NS_ASSERTION(r1 == r2, "must be in the same rule tree as parent");
      44             : #endif
      45             :   } else {
      46         187 :     PresContext()->PresShell()->StyleSet()->RootStyleContextAdded();
      47             :   }
      48             : 
      49        2203 :   mRuleNode->SetUsedDirectly(); // before ApplyStyleFixups()!
      50             :   // FinishConstruction() calls AddChild which needs these
      51             :   // to be initialized!
      52        2203 :   mNextSibling = this;
      53        2203 :   mPrevSibling = this;
      54             : 
      55        2203 :   FinishConstruction();
      56        2203 :   ApplyStyleFixups(aSkipParentDisplayBasedStyleFixup);
      57        2203 : }
      58             : 
      59             : // Overloaded new operator. Initializes the memory to 0 and relies on an arena
      60             : // (which comes from the presShell) to perform the allocation.
      61             : void*
      62        2203 : GeckoStyleContext::operator new(size_t sz, nsPresContext* aPresContext)
      63             : {
      64        2203 :   MOZ_ASSERT(sz == sizeof(GeckoStyleContext));
      65             :   // Check the recycle list first.
      66             :   return aPresContext->PresShell()->
      67        2203 :     AllocateByObjectID(eArenaObjectID_GeckoStyleContext, sz);
      68             : }
      69             : 
      70             : 
      71             : void
      72        2548 : GeckoStyleContext::AddChild(GeckoStyleContext* aChild)
      73             : {
      74        2548 :   NS_ASSERTION(aChild->mPrevSibling == aChild &&
      75             :                aChild->mNextSibling == aChild,
      76             :                "child already in a child list");
      77             : 
      78        2548 :   GeckoStyleContext **listPtr = aChild->mRuleNode->IsRoot() ? &mEmptyChild : &mChild;
      79        2548 :   if (const nsRuleNode* source = aChild->mRuleNode) {
      80        2548 :     if (source->IsRoot()) {
      81         234 :       listPtr = &mEmptyChild;
      82             :     }
      83             :   }
      84             : 
      85             :   // Explicitly dereference listPtr so that compiler doesn't have to know that mNextSibling
      86             :   // etc. don't alias with what ever listPtr points at.
      87        2548 :   GeckoStyleContext *list = *listPtr;
      88             : 
      89             :   // Insert at the beginning of the list.  See also FindChildWithRules.
      90        2548 :   if (list) {
      91             :     // Link into existing elements, if there are any.
      92        1675 :     aChild->mNextSibling = list;
      93        1675 :     aChild->mPrevSibling = list->mPrevSibling;
      94        1675 :     list->mPrevSibling->mNextSibling = aChild;
      95        1675 :     list->mPrevSibling = aChild;
      96             :   }
      97        2548 :   (*listPtr) = aChild;
      98        2548 : }
      99             : 
     100             : void
     101        2029 : GeckoStyleContext::RemoveChild(GeckoStyleContext* aChild)
     102             : {
     103        2029 :   NS_PRECONDITION(nullptr != aChild && this == aChild->mParent, "bad argument");
     104             : 
     105        2029 :   MOZ_ASSERT(aChild->mRuleNode, "child context should have rule node");
     106        2029 :   GeckoStyleContext **list = aChild->mRuleNode->IsRoot() ? &mEmptyChild : &mChild;
     107             : 
     108        2029 :   if (aChild->mPrevSibling != aChild) { // has siblings
     109        1412 :     if ((*list) == aChild) {
     110         223 :       (*list) = (*list)->mNextSibling;
     111             :     }
     112             :   }
     113             :   else {
     114         617 :     NS_ASSERTION((*list) == aChild, "bad sibling pointers");
     115         617 :     (*list) = nullptr;
     116             :   }
     117             : 
     118        2029 :   aChild->mPrevSibling->mNextSibling = aChild->mNextSibling;
     119        2029 :   aChild->mNextSibling->mPrevSibling = aChild->mPrevSibling;
     120        2029 :   aChild->mNextSibling = aChild;
     121        2029 :   aChild->mPrevSibling = aChild;
     122        2029 : }
     123             : 
     124             : #ifdef DEBUG
     125             : void
     126           0 : GeckoStyleContext::ListDescendants(FILE* out, int32_t aIndent)
     127             : {
     128           0 :   if (nullptr != mChild) {
     129           0 :     GeckoStyleContext* child = mChild;
     130           0 :     do {
     131           0 :       child->List(out, aIndent + 1, true);
     132           0 :       child = child->mNextSibling;
     133           0 :     } while (mChild != child);
     134             :   }
     135           0 :   if (nullptr != mEmptyChild) {
     136           0 :     GeckoStyleContext* child = mEmptyChild;
     137           0 :     do {
     138           0 :       child->List(out, aIndent + 1, true);
     139           0 :       child = child->mNextSibling;
     140           0 :     } while (mEmptyChild != child);
     141             :   }
     142           0 : }
     143             : #endif
     144             : 
     145             : void
     146          95 : GeckoStyleContext::ClearCachedInheritedStyleDataOnDescendants(uint32_t aStructs)
     147             : {
     148          95 :   if (mChild) {
     149          42 :     GeckoStyleContext* child = mChild;
     150          21 :     do {
     151          63 :       child->DoClearCachedInheritedStyleDataOnDescendants(aStructs);
     152          63 :       child = child->mNextSibling;
     153          63 :     } while (mChild != child);
     154             :   }
     155          95 :   if (mEmptyChild) {
     156           0 :     GeckoStyleContext* child = mEmptyChild;
     157           0 :     do {
     158           0 :       child->DoClearCachedInheritedStyleDataOnDescendants(aStructs);
     159           0 :       child = child->mNextSibling;
     160           0 :     } while (mEmptyChild != child);
     161             :   }
     162          95 : }
     163             : 
     164             : void
     165          63 : GeckoStyleContext::DoClearCachedInheritedStyleDataOnDescendants(uint32_t aStructs)
     166             : {
     167          63 :   NS_ASSERTION(mFrameRefCnt == 0, "frame still referencing style context");
     168         630 :   for (nsStyleStructID i = nsStyleStructID_Inherited_Start;
     169         630 :        i < nsStyleStructID_Inherited_Start + nsStyleStructID_Inherited_Count;
     170         567 :        i = nsStyleStructID(i + 1)) {
     171         567 :     uint32_t bit = nsCachedStyleData::GetBitForSID(i);
     172         567 :     if (aStructs & bit) {
     173         393 :       if (!(mBits & bit) && mCachedInheritedData.mStyleStructs[i]) {
     174          36 :         aStructs &= ~bit;
     175             :       } else {
     176         357 :         mCachedInheritedData.mStyleStructs[i] = nullptr;
     177             :       }
     178             :     }
     179             :   }
     180             : 
     181          63 :   if (mCachedResetData) {
     182         784 :     for (nsStyleStructID i = nsStyleStructID_Reset_Start;
     183         784 :          i < nsStyleStructID_Reset_Start + nsStyleStructID_Reset_Count;
     184         735 :          i = nsStyleStructID(i + 1)) {
     185         735 :       uint32_t bit = nsCachedStyleData::GetBitForSID(i);
     186         735 :       if (aStructs & bit) {
     187         687 :         if (!(mBits & bit) && mCachedResetData->mStyleStructs[i]) {
     188          39 :           aStructs &= ~bit;
     189             :         } else {
     190         648 :           mCachedResetData->mStyleStructs[i] = nullptr;
     191             :         }
     192             :       }
     193             :     }
     194             :   }
     195             : 
     196          63 :   if (aStructs == 0) {
     197           0 :     return;
     198             :   }
     199             : 
     200          63 :   ClearCachedInheritedStyleDataOnDescendants(aStructs);
     201             : }
     202             : 
     203             : already_AddRefed<GeckoStyleContext>
     204        3153 : GeckoStyleContext::FindChildWithRules(const nsIAtom* aPseudoTag,
     205             :                                    nsRuleNode* aSource,
     206             :                                    nsRuleNode* aSourceIfVisited,
     207             :                                    bool aRelevantLinkVisited)
     208             : {
     209        3153 :   uint32_t threshold = 10; // The # of siblings we're willing to examine
     210             :                            // before just giving this whole thing up.
     211             : 
     212        6306 :   RefPtr<GeckoStyleContext> result;
     213        3153 :   MOZ_ASSERT(aSource);
     214        3153 :   GeckoStyleContext *list = aSource->IsRoot() ? mEmptyChild : mChild;
     215             : 
     216        3153 :   if (list) {
     217        2288 :     GeckoStyleContext *child = list;
     218        4136 :     do {
     219       14059 :       if (child->RuleNode() == aSource &&
     220        2348 :           child->mPseudoTag == aPseudoTag &&
     221        8698 :           !child->IsStyleIfVisited() &&
     222        1137 :           child->RelevantLinkVisited() == aRelevantLinkVisited) {
     223        1137 :         bool match = false;
     224        1137 :         if (aSourceIfVisited) {
     225           0 :           match = child->GetStyleIfVisited() &&
     226           0 :                   child->GetStyleIfVisited()->RuleNode() == aSourceIfVisited;
     227             :         } else {
     228        1137 :           match = !child->GetStyleIfVisited();
     229             :         }
     230        1137 :         if (match && !(child->mBits & NS_STYLE_INELIGIBLE_FOR_SHARING)) {
     231        1137 :           result = child;
     232        1137 :           break;
     233             :         }
     234             :       }
     235        5287 :       child = child->mNextSibling;
     236        5287 :       threshold--;
     237        5287 :       if (threshold == 0)
     238         103 :         break;
     239        5184 :     } while (child != list);
     240             :   }
     241             : 
     242        3153 :   if (result) {
     243        1137 :     if (result != list) {
     244             :       // Move result to the front of the list.
     245         495 :       RemoveChild(result);
     246         495 :       AddChild(result);
     247             :     }
     248        1137 :     result->mBits |= NS_STYLE_IS_SHARED;
     249             :   }
     250             : 
     251        6306 :   return result.forget();
     252             : }
     253             : 
     254             : 
     255             : 
     256             : // This is an evil evil function, since it forces you to alloc your own separate copy of
     257             : // style data!  Do not use this function unless you absolutely have to!  You should avoid
     258             : // this at all costs! -dwh
     259             : void*
     260         100 : GeckoStyleContext::GetUniqueStyleData(const nsStyleStructID& aSID)
     261             : {
     262             :   // If we already own the struct and no kids could depend on it, then
     263             :   // just return it.  (We leak in this case if there are kids -- and this
     264             :   // function really shouldn't be called for style contexts that could
     265             :   // have kids depending on the data.  ClearStyleData would be OK, but
     266             :   // this test for no mChild or mEmptyChild doesn't catch that case.)
     267         100 :   const void *current = StyleData(aSID);
     268         400 :   if (!mChild && !mEmptyChild &&
     269         300 :       !(mBits & nsCachedStyleData::GetBitForSID(aSID)) &&
     270         100 :       GetCachedStyleData(aSID))
     271           0 :     return const_cast<void*>(current);
     272             : 
     273             :   void* result;
     274         100 :   nsPresContext *presContext = PresContext();
     275         100 :   switch (aSID) {
     276             : 
     277             : #define UNIQUE_CASE(c_)                                                       \
     278             :   case eStyleStruct_##c_:                                                     \
     279             :     result = new (presContext) nsStyle##c_(                                   \
     280             :       * static_cast<const nsStyle##c_ *>(current));                           \
     281             :     break;
     282             : 
     283           0 :   UNIQUE_CASE(Font)
     284         100 :   UNIQUE_CASE(Display)
     285           0 :   UNIQUE_CASE(Text)
     286           0 :   UNIQUE_CASE(TextReset)
     287           0 :   UNIQUE_CASE(Visibility)
     288             : 
     289             : #undef UNIQUE_CASE
     290             : 
     291             :   default:
     292           0 :     NS_ERROR("Struct type not supported.  Please find another way to do this if you can!");
     293           0 :     return nullptr;
     294             :   }
     295             : 
     296         100 :   SetStyle(aSID, result);
     297         100 :   mBits &= ~static_cast<uint64_t>(nsCachedStyleData::GetBitForSID(aSID));
     298             : 
     299         100 :   return result;
     300             : }
     301             : 
     302             : 
     303             : // This is an evil function, but less evil than GetUniqueStyleData. It
     304             : // creates an empty style struct for this nsStyleContext.
     305             : void*
     306           0 : GeckoStyleContext::CreateEmptyStyleData(const nsStyleStructID& aSID)
     307             : {
     308           0 :   MOZ_ASSERT(!mChild && !mEmptyChild &&
     309             :              !(mBits & nsCachedStyleData::GetBitForSID(aSID)) &&
     310             :              !GetCachedStyleData(aSID),
     311             :              "This style should not have been computed");
     312             : 
     313             :   void* result;
     314           0 :   nsPresContext* presContext = PresContext();
     315           0 :   switch (aSID) {
     316             : #define UNIQUE_CASE(c_) \
     317             :     case eStyleStruct_##c_: \
     318             :       result = new (presContext) nsStyle##c_(presContext); \
     319             :       break;
     320             : 
     321           0 :   UNIQUE_CASE(Border)
     322           0 :   UNIQUE_CASE(Padding)
     323             : 
     324             : #undef UNIQUE_CASE
     325             : 
     326             :   default:
     327           0 :     NS_ERROR("Struct type not supported.");
     328           0 :     return nullptr;
     329             :   }
     330             : 
     331             :   // The new struct is owned by this style context, but that we don't
     332             :   // need to clear the bit in mBits because we've asserted that at the
     333             :   // top of this function.
     334           0 :   SetStyle(aSID, result);
     335           0 :   return result;
     336             : }
     337             : 
     338             : 
     339             : void
     340          49 : GeckoStyleContext::SetIneligibleForSharing()
     341             : {
     342          49 :   if (mBits & NS_STYLE_INELIGIBLE_FOR_SHARING) {
     343          31 :     return;
     344             :   }
     345          18 :   mBits |= NS_STYLE_INELIGIBLE_FOR_SHARING;
     346          18 :   if (mChild) {
     347           9 :     GeckoStyleContext* child = mChild;
     348           7 :     do {
     349          16 :       child->SetIneligibleForSharing();
     350          16 :       child = child->mNextSibling;
     351          16 :     } while (mChild != child);
     352             :   }
     353          18 :   if (mEmptyChild) {
     354           0 :     GeckoStyleContext* child = mEmptyChild;
     355           0 :     do {
     356           0 :       child->SetIneligibleForSharing();
     357           0 :       child = child->mNextSibling;
     358           0 :     } while (mEmptyChild != child);
     359             :   }
     360             : }
     361             : 
     362             : #ifdef RESTYLE_LOGGING
     363             : nsCString
     364           0 : GeckoStyleContext::GetCachedStyleDataAsString(uint32_t aStructs)
     365             : {
     366           0 :   nsCString structs;
     367           0 :   for (nsStyleStructID i = nsStyleStructID(0);
     368           0 :        i < nsStyleStructID_Length;
     369           0 :        i = nsStyleStructID(i + 1)) {
     370           0 :     if (aStructs & nsCachedStyleData::GetBitForSID(i)) {
     371           0 :       const void* data = GetCachedStyleData(i);
     372           0 :       if (!structs.IsEmpty()) {
     373           0 :         structs.Append(' ');
     374             :       }
     375           0 :       structs.AppendPrintf("%s=%p", StructName(i), data);
     376           0 :       if (HasCachedDependentStyleData(i)) {
     377           0 :         structs.AppendLiteral("(dependent)");
     378             :       } else {
     379           0 :         structs.AppendLiteral("(owned)");
     380             :       }
     381             :     }
     382             :   }
     383           0 :   return structs;
     384             : }
     385             : 
     386             : int32_t&
     387           0 : GeckoStyleContext::LoggingDepth()
     388             : {
     389             :   static int32_t depth = 0;
     390           0 :   return depth;
     391             : }
     392             : 
     393             : void
     394           0 : GeckoStyleContext::LogStyleContextTree(int32_t aLoggingDepth, uint32_t aStructs)
     395             : {
     396           0 :   LoggingDepth() = aLoggingDepth;
     397           0 :   LogStyleContextTree(true, aStructs);
     398           0 : }
     399             : 
     400             : void
     401           0 : GeckoStyleContext::LogStyleContextTree(bool aFirst, uint32_t aStructs)
     402             : {
     403           0 :   nsCString structs = GetCachedStyleDataAsString(aStructs);
     404           0 :   if (!structs.IsEmpty()) {
     405           0 :     structs.Append(' ');
     406             :   }
     407             : 
     408           0 :   nsCString pseudo;
     409           0 :   if (mPseudoTag) {
     410           0 :     nsAutoString pseudoTag;
     411           0 :     mPseudoTag->ToString(pseudoTag);
     412           0 :     AppendUTF16toUTF8(pseudoTag, pseudo);
     413           0 :     pseudo.Append(' ');
     414             :   }
     415             : 
     416           0 :   nsCString flags;
     417           0 :   if (IsStyleIfVisited()) {
     418           0 :     flags.AppendLiteral("IS_STYLE_IF_VISITED ");
     419             :   }
     420           0 :   if (HasChildThatUsesGrandancestorStyle()) {
     421           0 :     flags.AppendLiteral("CHILD_USES_GRANDANCESTOR_STYLE ");
     422             :   }
     423           0 :   if (IsShared()) {
     424           0 :     flags.AppendLiteral("IS_SHARED ");
     425             :   }
     426             : 
     427           0 :   nsCString parent;
     428           0 :   if (aFirst) {
     429           0 :     parent.AppendPrintf("parent=%p ", mParent.get());
     430             :   }
     431             : 
     432           0 :   LOG_RESTYLE("%p(%d) %s%s%s%s",
     433             :               this, mRefCnt,
     434             :               structs.get(), pseudo.get(), flags.get(), parent.get());
     435             : 
     436           0 :   LOG_RESTYLE_INDENT();
     437             : 
     438           0 :   if (nullptr != mChild) {
     439           0 :     GeckoStyleContext* child = mChild;
     440           0 :     do {
     441           0 :       child->LogStyleContextTree(false, aStructs);
     442           0 :       child = child->mNextSibling;
     443           0 :     } while (mChild != child);
     444             :   }
     445           0 :   if (nullptr != mEmptyChild) {
     446           0 :     GeckoStyleContext* child = mEmptyChild;
     447           0 :     do {
     448           0 :       child->LogStyleContextTree(false, aStructs);
     449           0 :       child = child->mNextSibling;
     450           0 :     } while (mEmptyChild != child);
     451             :   }
     452           0 : }
     453             : #endif
     454             : 
     455             : static bool
     456        2016 : ShouldSuppressLineBreak(const nsStyleContext* aContext,
     457             :                         const nsStyleDisplay* aDisplay,
     458             :                         const nsStyleContext* aParentContext,
     459             :                         const nsStyleDisplay* aParentDisplay)
     460             : {
     461             :   // The display change should only occur for "in-flow" children
     462        2016 :   if (aDisplay->IsOutOfFlowStyle()) {
     463          30 :     return false;
     464             :   }
     465             :   // Display value of any anonymous box should not be touched. In most
     466             :   // cases, anonymous boxes are actually not in ruby frame, but instead,
     467             :   // some other frame with a ruby display value. Non-element pseudos
     468             :   // which represents text frames, as well as ruby pseudos are excluded
     469             :   // because we still want to set the flag for them.
     470        5602 :   if ((aContext->GetPseudoType() == CSSPseudoElementType::InheritingAnonBox ||
     471        1986 :        aContext->GetPseudoType() == CSSPseudoElementType::NonInheritingAnonBox) &&
     472        2490 :       !nsCSSAnonBoxes::IsNonElement(aContext->GetPseudo()) &&
     473         148 :       !RubyUtils::IsRubyPseudo(aContext->GetPseudo())) {
     474         148 :     return false;
     475             :   }
     476        1838 :   if (aParentContext->ShouldSuppressLineBreak()) {
     477             :     // Line break suppressing bit is propagated to any children of
     478             :     // line participants, which include inline, contents, and inline
     479             :     // ruby boxes.
     480           0 :     if (aParentDisplay->mDisplay == mozilla::StyleDisplay::Inline ||
     481           0 :         aParentDisplay->mDisplay == mozilla::StyleDisplay::Contents ||
     482           0 :         aParentDisplay->mDisplay == mozilla::StyleDisplay::Ruby ||
     483           0 :         aParentDisplay->mDisplay == mozilla::StyleDisplay::RubyBaseContainer) {
     484           0 :       return true;
     485             :     }
     486             :   }
     487             :   // Any descendant of ruby level containers is non-breakable, but
     488             :   // the level containers themselves are breakable. We have to check
     489             :   // the container display type against all ruby display type here
     490             :   // because any of the ruby boxes could be anonymous.
     491             :   // Note that, when certain HTML tags, e.g. form controls, have ruby
     492             :   // level container display type, they could also escape from this flag
     493             :   // while they shouldn't. However, it is generally fine since they
     494             :   // won't usually break the assertion that there is no line break
     495             :   // inside ruby, because:
     496             :   // 1. their display types, the ruby level container types, are inline-
     497             :   //    outside, which means they won't cause any forced line break; and
     498             :   // 2. they never start an inline span, which means their children, if
     499             :   //    any, won't be able to break the line its ruby ancestor lays; and
     500             :   // 3. their parent frame is always a ruby content frame (due to
     501             :   //    anonymous ruby box generation), which makes line layout suppress
     502             :   //    any optional line break around this frame.
     503             :   // However, there is one special case which is BR tag, because it
     504             :   // directly affects the line layout. This case is handled by the BR
     505             :   // frame which checks the flag of its parent frame instead of itself.
     506        3676 :   if ((aParentDisplay->IsRubyDisplayType() &&
     507           0 :        aDisplay->mDisplay != mozilla::StyleDisplay::RubyBaseContainer &&
     508        1838 :        aDisplay->mDisplay != mozilla::StyleDisplay::RubyTextContainer) ||
     509             :       // Since ruby base and ruby text may exist themselves without any
     510             :       // non-anonymous frame outside, we should also check them.
     511        5514 :       aDisplay->mDisplay == mozilla::StyleDisplay::RubyBase ||
     512        1838 :       aDisplay->mDisplay == mozilla::StyleDisplay::RubyText) {
     513           0 :     return true;
     514             :   }
     515        1838 :   return false;
     516             : }
     517             : 
     518             : void
     519        2203 : nsStyleContext::SetStyleBits()
     520             : {
     521             :   // Here we set up various style bits for both the Gecko and Servo paths.
     522             :   // _Only_ change the bits here.  For fixups of the computed values, you can
     523             :   // add to ApplyStyleFixups in Gecko and StyleAdjuster as part of Servo's
     524             :   // cascade.
     525             : 
     526             :   // See if we have any text decorations.
     527             :   // First see if our parent has text decorations.  If our parent does, then we inherit the bit.
     528        2203 :   if (mParent && mParent->HasTextDecorationLines()) {
     529           0 :     AddStyleBit(NS_STYLE_HAS_TEXT_DECORATION_LINES);
     530             :   } else {
     531             :     // We might have defined a decoration.
     532        2203 :     if (StyleTextReset()->HasTextDecorationLines()) {
     533           0 :       AddStyleBit(NS_STYLE_HAS_TEXT_DECORATION_LINES);
     534             :     }
     535             :   }
     536             : 
     537        2203 :   if ((mParent && mParent->HasPseudoElementData()) || IsPseudoElement()) {
     538         107 :     AddStyleBit(NS_STYLE_HAS_PSEUDO_ELEMENT_DATA);
     539             :   }
     540             : 
     541             :   // Set the NS_STYLE_IN_DISPLAY_NONE_SUBTREE bit
     542        2203 :   const nsStyleDisplay* disp = StyleDisplay();
     543        4269 :   if ((mParent && mParent->IsInDisplayNoneSubtree()) ||
     544        2066 :       disp->mDisplay == mozilla::StyleDisplay::None) {
     545         675 :     AddStyleBit(NS_STYLE_IN_DISPLAY_NONE_SUBTREE);
     546             :   }
     547             : 
     548             :   // Mark text combined for text-combine-upright, as needed.
     549        4822 :   if (mPseudoTag == nsCSSAnonBoxes::mozText && mParent &&
     550         208 :       mParent->StyleVisibility()->mWritingMode !=
     551        2203 :         NS_STYLE_WRITING_MODE_HORIZONTAL_TB &&
     552           0 :       mParent->StyleText()->mTextCombineUpright ==
     553             :         NS_STYLE_TEXT_COMBINE_UPRIGHT_ALL) {
     554           0 :     AddStyleBit(NS_STYLE_IS_TEXT_COMBINED);
     555             :   }
     556        2203 : }
     557             : 
     558             : // Flex & grid containers blockify their children.
     559             : //  "The display value of a flex item is blockified"
     560             : //    https://drafts.csswg.org/css-flexbox-1/#flex-items
     561             : //  "The display value of a grid item is blockified"
     562             : //    https://drafts.csswg.org/css-grid/#grid-items
     563             : static bool
     564        1295 : ShouldBlockifyChildren(const nsStyleDisplay* aStyleDisp)
     565             : {
     566        1295 :   auto displayVal = aStyleDisp->mDisplay;
     567        1295 :   return mozilla::StyleDisplay::Flex == displayVal ||
     568        1295 :     mozilla::StyleDisplay::InlineFlex == displayVal ||
     569        2590 :     mozilla::StyleDisplay::Grid == displayVal ||
     570        1295 :     mozilla::StyleDisplay::InlineGrid == displayVal;
     571             : }
     572             : 
     573             : #ifdef DEBUG
     574             : void
     575        1618 : GeckoStyleContext::AssertStructsNotUsedElsewhere(
     576             :                                        GeckoStyleContext* aDestroyingContext,
     577             :                                        int32_t aLevels) const
     578             : {
     579        1618 :   if (aLevels == 0) {
     580           0 :     return;
     581             :   }
     582             : 
     583             :   void* data;
     584             : 
     585        1618 :   if (mBits & NS_STYLE_IS_GOING_AWAY) {
     586           0 :     return;
     587             :   }
     588             : 
     589        1618 :   if (this != aDestroyingContext) {
     590             :     nsInheritedStyleData& destroyingInheritedData =
     591           0 :       aDestroyingContext->mCachedInheritedData;
     592             : #define STYLE_STRUCT_INHERITED(name_, checkdata_cb)                            \
     593             :     data = destroyingInheritedData.mStyleStructs[eStyleStruct_##name_];        \
     594             :     if (data &&                                                                \
     595             :         !(aDestroyingContext->mBits & NS_STYLE_INHERIT_BIT(name_)) &&          \
     596             :          (mCachedInheritedData.mStyleStructs[eStyleStruct_##name_] == data)) { \
     597             :       printf_stderr("style struct %p found on style context %p\n", data, this);\
     598             :       nsString url;                                                            \
     599             :       nsresult rv = PresContext()->Document()->GetURL(url);                    \
     600             :       if (NS_SUCCEEDED(rv)) {                                                  \
     601             :         printf_stderr("  in %s\n", NS_ConvertUTF16toUTF8(url).get());          \
     602             :       }                                                                        \
     603             :       MOZ_ASSERT(false, "destroying " #name_ " style struct still present "    \
     604             :                         "in style context tree");                              \
     605             :     }
     606             : #define STYLE_STRUCT_RESET(name_, checkdata_cb)
     607             : 
     608             : #include "nsStyleStructList.h"
     609             : 
     610             : #undef STYLE_STRUCT_INHERITED
     611             : #undef STYLE_STRUCT_RESET
     612             : 
     613           0 :     if (mCachedResetData) {
     614             :       nsResetStyleData* destroyingResetData =
     615           0 :         aDestroyingContext->mCachedResetData;
     616           0 :       if (destroyingResetData) {
     617             : #define STYLE_STRUCT_INHERITED(name_, checkdata_cb_)
     618             : #define STYLE_STRUCT_RESET(name_, checkdata_cb)                                \
     619             :         data = destroyingResetData->mStyleStructs[eStyleStruct_##name_];       \
     620             :         if (data &&                                                            \
     621             :             !(aDestroyingContext->mBits & NS_STYLE_INHERIT_BIT(name_)) &&      \
     622             :             (mCachedResetData->mStyleStructs[eStyleStruct_##name_] == data)) { \
     623             :           printf_stderr("style struct %p found on style context %p\n", data,   \
     624             :                         this);                                                 \
     625             :           nsString url;                                                        \
     626             :           nsresult rv = PresContext()->Document()->GetURL(url);                \
     627             :           if (NS_SUCCEEDED(rv)) {                                              \
     628             :             printf_stderr("  in %s\n", NS_ConvertUTF16toUTF8(url).get());      \
     629             :           }                                                                    \
     630             :           MOZ_ASSERT(false, "destroying " #name_ " style struct still present "\
     631             :                             "in style context tree");                          \
     632             :         }
     633             : 
     634             : #include "nsStyleStructList.h"
     635             : 
     636             : #undef STYLE_STRUCT_INHERITED
     637             : #undef STYLE_STRUCT_RESET
     638             :       }
     639             :     }
     640             :   }
     641             : 
     642        1618 :   if (mChild) {
     643           0 :     const GeckoStyleContext* child = mChild;
     644           0 :     do {
     645           0 :       child->AssertStructsNotUsedElsewhere(aDestroyingContext, aLevels - 1);
     646           0 :       child = child->mNextSibling;
     647           0 :     } while (child != mChild);
     648             :   }
     649             : 
     650        1618 :   if (mEmptyChild) {
     651           0 :     const GeckoStyleContext* child = mEmptyChild;
     652           0 :     do {
     653           0 :       child->AssertStructsNotUsedElsewhere(aDestroyingContext, aLevels - 1);
     654           0 :       child = child->mNextSibling;
     655           0 :     } while (child != mEmptyChild);
     656             :   }
     657             : }
     658             : #endif
     659             : 
     660             : 
     661             : void
     662        2203 : GeckoStyleContext::ApplyStyleFixups(bool aSkipParentDisplayBasedStyleFixup)
     663             : {
     664             : #define GET_UNIQUE_STYLE_DATA(name_) \
     665             :   static_cast<nsStyle##name_*>(GetUniqueStyleData(eStyleStruct_##name_))
     666             : 
     667             :   // CSS Inline Layout Level 3 - 3.5 Sizing Initial Letters:
     668             :   // For an N-line drop initial in a Western script, the cap-height of the
     669             :   // letter needs to be (N – 1) times the line-height, plus the cap-height
     670             :   // of the surrounding text.
     671        2203 :   if (mPseudoTag == nsCSSPseudoElements::firstLetter) {
     672           0 :     const nsStyleTextReset* textReset = StyleTextReset();
     673           0 :     if (textReset->mInitialLetterSize != 0.0f) {
     674           0 :       nsStyleContext* containerSC = mParent;
     675           0 :       const nsStyleDisplay* containerDisp = containerSC->StyleDisplay();
     676           0 :       while (containerDisp->mDisplay == mozilla::StyleDisplay::Contents) {
     677           0 :         if (!containerSC->GetParent()) {
     678           0 :           break;
     679             :         }
     680           0 :         containerSC = containerSC->GetParent();
     681           0 :         containerDisp = containerSC->StyleDisplay();
     682             :       }
     683             :       nscoord containerLH =
     684           0 :         ReflowInput::CalcLineHeight(nullptr, containerSC, NS_AUTOHEIGHT, 1.0f);
     685             :       RefPtr<nsFontMetrics> containerFM =
     686           0 :         nsLayoutUtils::GetFontMetricsForStyleContext(containerSC);
     687           0 :       MOZ_ASSERT(containerFM, "Should have fontMetrics!!");
     688           0 :       nscoord containerCH = containerFM->CapHeight();
     689             :       RefPtr<nsFontMetrics> firstLetterFM =
     690           0 :         nsLayoutUtils::GetFontMetricsForStyleContext(this);
     691           0 :       MOZ_ASSERT(firstLetterFM, "Should have fontMetrics!!");
     692           0 :       nscoord firstLetterCH = firstLetterFM->CapHeight();
     693           0 :       nsStyleFont* mutableStyleFont = GET_UNIQUE_STYLE_DATA(Font);
     694             :       float invCapHeightRatio =
     695           0 :         mutableStyleFont->mFont.size / NSCoordToFloat(firstLetterCH);
     696           0 :       mutableStyleFont->mFont.size =
     697           0 :         NSToCoordRound(((textReset->mInitialLetterSize - 1) * containerLH +
     698             :                         containerCH) *
     699             :                        invCapHeightRatio);
     700             :     }
     701             :   }
     702             : 
     703             :   // Change writing mode of text frame for text-combine-upright. We use
     704             :   // style structs of the parent to avoid triggering computation before
     705             :   // we change the writing mode.
     706             :   // It is safe to look at the parent's style because we are looking at
     707             :   // inherited properties, and ::-moz-text never matches any rules.
     708        4822 :   if (mPseudoTag == nsCSSAnonBoxes::mozText && mParent &&
     709         208 :       mParent->StyleVisibility()->mWritingMode !=
     710        2203 :         NS_STYLE_WRITING_MODE_HORIZONTAL_TB &&
     711           0 :       mParent->StyleText()->mTextCombineUpright ==
     712             :         NS_STYLE_TEXT_COMBINE_UPRIGHT_ALL) {
     713           0 :     MOZ_ASSERT(!PeekStyleVisibility(), "If StyleVisibility was already "
     714             :                "computed, some properties may have been computed "
     715             :                "incorrectly based on the old writing mode value");
     716           0 :     nsStyleVisibility* mutableVis = GET_UNIQUE_STYLE_DATA(Visibility);
     717           0 :     mutableVis->mWritingMode = NS_STYLE_WRITING_MODE_HORIZONTAL_TB;
     718             :   }
     719             : 
     720             :   // CSS 2.1 10.1: Propagate the root element's 'direction' to the ICB.
     721             :   // (PageContentFrame/CanvasFrame etc will inherit 'direction')
     722        2203 :   if (mPseudoTag == nsCSSAnonBoxes::viewport) {
     723          50 :     nsPresContext* presContext = PresContext();
     724          50 :     mozilla::dom::Element* docElement = presContext->Document()->GetRootElement();
     725          50 :     if (docElement) {
     726             :       RefPtr<nsStyleContext> rootStyle =
     727         100 :         presContext->StyleSet()->AsGecko()->ResolveStyleFor(docElement, nullptr);
     728          50 :       auto dir = rootStyle->StyleVisibility()->mDirection;
     729          50 :       if (dir != StyleVisibility()->mDirection) {
     730           0 :         nsStyleVisibility* uniqueVisibility = GET_UNIQUE_STYLE_DATA(Visibility);
     731           0 :         uniqueVisibility->mDirection = dir;
     732             :       }
     733             :     }
     734             :   }
     735             : 
     736             :   // Correct tables.
     737        2203 :   const nsStyleDisplay* disp = StyleDisplay();
     738        2203 :   if (disp->mDisplay == mozilla::StyleDisplay::Table) {
     739             :     // -moz-center and -moz-right are used for HTML's alignment
     740             :     // This is covering the <div align="right"><table>...</table></div> case.
     741             :     // In this case, we don't want to inherit the text alignment into the table.
     742           0 :     const nsStyleText* text = StyleText();
     743             : 
     744           0 :     if (text->mTextAlign == NS_STYLE_TEXT_ALIGN_MOZ_LEFT ||
     745           0 :         text->mTextAlign == NS_STYLE_TEXT_ALIGN_MOZ_CENTER ||
     746           0 :         text->mTextAlign == NS_STYLE_TEXT_ALIGN_MOZ_RIGHT)
     747             :     {
     748           0 :       nsStyleText* uniqueText = GET_UNIQUE_STYLE_DATA(Text);
     749           0 :       uniqueText->mTextAlign = NS_STYLE_TEXT_ALIGN_START;
     750             :     }
     751             :   }
     752             : 
     753             :   // CSS2.1 section 9.2.4 specifies fixups for the 'display' property of
     754             :   // the root element.  We can't implement them in nsRuleNode because we
     755             :   // don't want to store all display structs that aren't 'block',
     756             :   // 'inline', or 'table' in the style context tree on the off chance
     757             :   // that the root element has its style reresolved later.  So do them
     758             :   // here if needed, by changing the style data, so that other code
     759             :   // doesn't get confused by looking at the style data.
     760        2575 :   if (!mParent &&
     761             :       // We don't want to blockify various anon boxes that just happen to not
     762             :       // inherit from anything.  So restrict blockification only to actual
     763             :       // elements, the viewport (which should be block anyway, but in SVG
     764             :       // document's isn't because we lazy-load ua.css there), and the ::backdrop
     765             :       // pseudo-element.  This last is explicitly allowed to have any specified
     766             :       // display type in the spec, but computes to a blockified display type per
     767             :       // various provisions of
     768             :       // https://fullscreen.spec.whatwg.org/#new-stacking-layer
     769         239 :       (!mPseudoTag ||
     770          54 :        mPseudoTag == nsCSSAnonBoxes::viewport ||
     771           2 :        mPseudoTag == nsCSSPseudoElements::backdrop)) {
     772         185 :     auto displayVal = disp->mDisplay;
     773         185 :     if (displayVal != mozilla::StyleDisplay::Contents) {
     774         185 :       nsRuleNode::EnsureBlockDisplay(displayVal, true);
     775             :     } else {
     776             :       // http://dev.w3.org/csswg/css-display/#transformations
     777             :       // "... a display-outside of 'contents' computes to block-level
     778             :       //  on the root element."
     779           0 :       displayVal = mozilla::StyleDisplay::Block;
     780             :     }
     781         185 :     if (displayVal != disp->mDisplay) {
     782         100 :       nsStyleDisplay* mutable_display = GET_UNIQUE_STYLE_DATA(Display);
     783         100 :       disp = mutable_display;
     784             : 
     785             :       // If we're in this code, then mOriginalDisplay doesn't matter
     786             :       // for purposes of the cascade (because this nsStyleDisplay
     787             :       // isn't living in the ruletree anyway), and for determining
     788             :       // hypothetical boxes it's better to have mOriginalDisplay
     789             :       // matching mDisplay here.
     790         100 :       mutable_display->mOriginalDisplay = mutable_display->mDisplay =
     791             :         displayVal;
     792             :     }
     793             :   }
     794             : 
     795             :   // Adjust the "display" values of flex and grid items (but not for raw text
     796             :   // or placeholders). CSS3 Flexbox section 4 says:
     797             :   //   # The computed 'display' of a flex item is determined
     798             :   //   # by applying the table in CSS 2.1 Chapter 9.7.
     799             :   // ...which converts inline-level elements to their block-level equivalents.
     800             :   // Any block-level element directly contained by elements with ruby display
     801             :   // values are converted to their inline-level equivalents.
     802        2203 :   if (!aSkipParentDisplayBasedStyleFixup && mParent) {
     803             :     // Skip display:contents ancestors to reach the potential container.
     804             :     // (If there are only display:contents ancestors between this node and
     805             :     // a flex/grid container ancestor, then this node is a flex/grid item, since
     806             :     // its parent *in the frame tree* will be the flex/grid container. So we treat
     807             :     // it like a flex/grid item here.)
     808        1295 :     nsStyleContext* containerContext = mParent;
     809        1295 :     const nsStyleDisplay* containerDisp = containerContext->StyleDisplay();
     810        1295 :     while (containerDisp->mDisplay == mozilla::StyleDisplay::Contents) {
     811           0 :       if (!containerContext->GetParent()) {
     812           0 :         break;
     813             :       }
     814           0 :       containerContext = containerContext->GetParent();
     815           0 :       containerDisp = containerContext->StyleDisplay();
     816             :     }
     817        1295 :     if (ShouldBlockifyChildren(containerDisp) &&
     818           0 :         !nsCSSAnonBoxes::IsNonElement(GetPseudo())) {
     819             :       // NOTE: Technically, we shouldn't modify the 'display' value of
     820             :       // positioned elements, since they aren't flex/grid items. However,
     821             :       // we don't need to worry about checking for that, because if we're
     822             :       // positioned, we'll have already been through a call to
     823             :       // EnsureBlockDisplay() in nsRuleNode, so this call here won't change
     824             :       // anything. So we're OK.
     825           0 :       auto displayVal = disp->mDisplay;
     826           0 :       nsRuleNode::EnsureBlockDisplay(displayVal);
     827           0 :       if (displayVal != disp->mDisplay) {
     828           0 :         NS_ASSERTION(!disp->IsAbsolutelyPositionedStyle(),
     829             :                      "We shouldn't be changing the display value of "
     830             :                      "positioned content (and we should have already "
     831             :                      "converted its display value to be block-level...)");
     832           0 :         nsStyleDisplay* mutable_display = GET_UNIQUE_STYLE_DATA(Display);
     833           0 :         disp = mutable_display;
     834           0 :         mutable_display->mDisplay = displayVal;
     835             :       }
     836             :     }
     837             :   }
     838             : 
     839             :   // Note: This must come after the blockification above, otherwise we fail
     840             :   // the grid-item-blockifying-001.html reftest.
     841        4219 :   if (mParent && ::ShouldSuppressLineBreak(this, disp, mParent,
     842        4219 :                                            mParent->StyleDisplay())) {
     843           0 :     mBits |= NS_STYLE_SUPPRESS_LINEBREAK;
     844           0 :     auto displayVal = disp->mDisplay;
     845           0 :     nsRuleNode::EnsureInlineDisplay(displayVal);
     846           0 :     if (displayVal != disp->mDisplay) {
     847           0 :       nsStyleDisplay* mutable_display = GET_UNIQUE_STYLE_DATA(Display);
     848           0 :       disp = mutable_display;
     849           0 :       mutable_display->mDisplay = displayVal;
     850             :     }
     851             :   }
     852             :   // Suppress border/padding of ruby level containers
     853        4406 :   if (disp->mDisplay == mozilla::StyleDisplay::RubyBaseContainer ||
     854        2203 :       disp->mDisplay == mozilla::StyleDisplay::RubyTextContainer) {
     855           0 :     CreateEmptyStyleData(eStyleStruct_Border);
     856           0 :     CreateEmptyStyleData(eStyleStruct_Padding);
     857             :   }
     858        2203 :   if (disp->IsRubyDisplayType()) {
     859             :     // Per CSS Ruby spec section Bidi Reordering, for all ruby boxes,
     860             :     // the 'normal' and 'embed' values of 'unicode-bidi' should compute to
     861             :     // 'isolate', and 'bidi-override' should compute to 'isolate-override'.
     862           0 :     const nsStyleTextReset* textReset = StyleTextReset();
     863           0 :     uint8_t unicodeBidi = textReset->mUnicodeBidi;
     864           0 :     if (unicodeBidi == NS_STYLE_UNICODE_BIDI_NORMAL ||
     865             :         unicodeBidi == NS_STYLE_UNICODE_BIDI_EMBED) {
     866           0 :       unicodeBidi = NS_STYLE_UNICODE_BIDI_ISOLATE;
     867           0 :     } else if (unicodeBidi == NS_STYLE_UNICODE_BIDI_BIDI_OVERRIDE) {
     868           0 :       unicodeBidi = NS_STYLE_UNICODE_BIDI_ISOLATE_OVERRIDE;
     869             :     }
     870           0 :     if (unicodeBidi != textReset->mUnicodeBidi) {
     871           0 :       nsStyleTextReset* mutableTextReset = GET_UNIQUE_STYLE_DATA(TextReset);
     872           0 :       mutableTextReset->mUnicodeBidi = unicodeBidi;
     873             :     }
     874             :   }
     875             : 
     876             :   /*
     877             :    * According to https://drafts.csswg.org/css-writing-modes-3/#block-flow:
     878             :    *
     879             :    * If a box has a different block flow direction than its containing block:
     880             :    *   * If the box has a specified display of inline, its display computes
     881             :    *     to inline-block. [CSS21]
     882             :    *   ...etc.
     883             :    */
     884        4773 :   if (disp->mDisplay == mozilla::StyleDisplay::Inline &&
     885        2360 :       !nsCSSAnonBoxes::IsNonElement(mPseudoTag) &&
     886         157 :       mParent) {
     887         157 :     auto cbContext = GetParent();
     888         157 :     while (cbContext->StyleDisplay()->mDisplay == mozilla::StyleDisplay::Contents) {
     889           0 :       cbContext = cbContext->GetParent();
     890             :     }
     891         157 :     MOZ_ASSERT(cbContext, "the root context can't have display:contents");
     892             :     // We don't need the full mozilla::WritingMode value (incorporating dir
     893             :     // and text-orientation) here; just the writing-mode property is enough.
     894         314 :     if (StyleVisibility()->mWritingMode !=
     895         157 :           cbContext->StyleVisibility()->mWritingMode) {
     896           0 :       nsStyleDisplay* mutable_display = GET_UNIQUE_STYLE_DATA(Display);
     897           0 :       disp = mutable_display;
     898           0 :       mutable_display->mOriginalDisplay = mutable_display->mDisplay =
     899             :         mozilla::StyleDisplay::InlineBlock;
     900             :     }
     901             :   }
     902             : 
     903             :   // Compute User Interface style, to trigger loads of cursors
     904        2203 :   StyleUserInterface();
     905             : #undef GET_UNIQUE_STYLE_DATA
     906        2203 : }
     907             : 
     908             : bool
     909        1618 : GeckoStyleContext::HasNoChildren() const
     910             : {
     911        1618 :   return (nullptr == mChild) && (nullptr == mEmptyChild);
     912             : }
     913             : 
     914             : void
     915        4605 : GeckoStyleContext::SetStyle(nsStyleStructID aSID, void* aStruct)
     916             : {
     917             :   // This method should only be called from nsRuleNode!  It is not a public
     918             :   // method!
     919             : 
     920        4605 :   NS_ASSERTION(aSID >= 0 && aSID < nsStyleStructID_Length, "out of bounds");
     921             : 
     922             :   // NOTE:  nsCachedStyleData::GetStyleData works roughly the same way.
     923             :   // See the comments there (in nsRuleNode.h) for more details about
     924             :   // what this is doing and why.
     925             : 
     926             :   void** dataSlot;
     927        4605 :   if (nsCachedStyleData::IsReset(aSID)) {
     928        1107 :     if (!mCachedResetData) {
     929         570 :       mCachedResetData = new (PresContext()) nsResetStyleData;
     930             :     }
     931        1107 :     dataSlot = &mCachedResetData->mStyleStructs[aSID];
     932             :   } else {
     933        3498 :     dataSlot = &mCachedInheritedData.mStyleStructs[aSID];
     934             :   }
     935        4605 :   NS_ASSERTION(!*dataSlot || (mBits & nsCachedStyleData::GetBitForSID(aSID)),
     936             :                "Going to leak style data");
     937        4605 :   *dataSlot = aStruct;
     938        4605 : }
     939             : 
     940             : 
     941             : const void*
     942        3775 : GeckoStyleContext::StyleData(nsStyleStructID aSID)
     943             : {
     944        3775 :   const void* cachedData = GetCachedStyleData(aSID);
     945        3775 :   if (cachedData)
     946        2948 :     return cachedData; // We have computed data stored on this node in the context tree.
     947             :   // Our style source will take care of it for us.
     948         827 :   const void* newData = AsGecko()->RuleNode()->GetStyleData(aSID, this->AsGecko(), true);
     949         827 :   if (!nsCachedStyleData::IsReset(aSID)) {
     950             :     // always cache inherited data on the style context; the rule
     951             :     // node set the bit in mBits for us if needed.
     952         415 :     mCachedInheritedData.mStyleStructs[aSID] = const_cast<void*>(newData);
     953             :   }
     954             : 
     955         827 :   return newData;
     956             : }
     957             : 
     958             : void
     959        1618 : GeckoStyleContext::DestroyCachedStructs(nsPresContext* aPresContext)
     960             : {
     961        1618 :   mCachedInheritedData.DestroyStructs(mBits, aPresContext);
     962        1618 :   if (mCachedResetData) {
     963         643 :     mCachedResetData->Destroy(mBits, aPresContext);
     964             :   }
     965        1618 : }
     966             : 
     967             : 
     968             : void
     969         379 : GeckoStyleContext::SwapStyleData(GeckoStyleContext* aNewContext, uint32_t aStructs)
     970             : {
     971             :   static_assert(nsStyleStructID_Length <= 32, "aStructs is not big enough");
     972             : 
     973        3790 :   for (nsStyleStructID i = nsStyleStructID_Inherited_Start;
     974        3790 :        i < nsStyleStructID_Inherited_Start + nsStyleStructID_Inherited_Count;
     975        3411 :        i = nsStyleStructID(i + 1)) {
     976        3411 :     uint32_t bit = nsCachedStyleData::GetBitForSID(i);
     977        3411 :     if (!(aStructs & bit)) {
     978          88 :       continue;
     979             :     }
     980        3323 :     void*& thisData = mCachedInheritedData.mStyleStructs[i];
     981        3323 :     void*& otherData = aNewContext->mCachedInheritedData.mStyleStructs[i];
     982        3323 :     if (mBits & bit) {
     983         904 :       if (thisData == otherData) {
     984         853 :         thisData = nullptr;
     985             :       }
     986        2419 :     } else if (!(aNewContext->mBits & bit) && thisData && otherData) {
     987         486 :       std::swap(thisData, otherData);
     988             :     }
     989             :   }
     990             : 
     991        6064 :   for (nsStyleStructID i = nsStyleStructID_Reset_Start;
     992        6064 :        i < nsStyleStructID_Reset_Start + nsStyleStructID_Reset_Count;
     993        5685 :        i = nsStyleStructID(i + 1)) {
     994        5685 :     uint32_t bit = nsCachedStyleData::GetBitForSID(i);
     995        5685 :     if (!(aStructs & bit)) {
     996          21 :       continue;
     997             :     }
     998        5664 :     if (!mCachedResetData) {
     999         125 :       mCachedResetData = new (PresContext()) nsResetStyleData;
    1000             :     }
    1001        5664 :     if (!aNewContext->mCachedResetData) {
    1002         195 :       aNewContext->mCachedResetData = new (PresContext()) nsResetStyleData;
    1003             :     }
    1004        5664 :     void*& thisData = mCachedResetData->mStyleStructs[i];
    1005        5664 :     void*& otherData = aNewContext->mCachedResetData->mStyleStructs[i];
    1006        5664 :     if (mBits & bit) {
    1007         120 :       if (thisData == otherData) {
    1008          39 :         thisData = nullptr;
    1009             :       }
    1010        5544 :     } else if (!(aNewContext->mBits & bit) && thisData && otherData) {
    1011         283 :       std::swap(thisData, otherData);
    1012             :     }
    1013             :   }
    1014         379 : }

Generated by: LCOV version 1.13