LCOV - code coverage report
Current view: top level - layout/style - nsStyleContext.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 129 205 62.9 %
Date: 2017-07-14 16:53:18 Functions: 15 34 44.1 %
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             : /* the interface (to internal code) for retrieving computed style data */
       7             : 
       8             : #include "nsStyleContext.h"
       9             : #include "CSSVariableImageTable.h"
      10             : #include "mozilla/DebugOnly.h"
      11             : #include "mozilla/Maybe.h"
      12             : 
      13             : #include "nsCSSAnonBoxes.h"
      14             : #include "nsCSSPseudoElements.h"
      15             : #include "nsFontMetrics.h"
      16             : #include "nsStyleConsts.h"
      17             : #include "nsStyleStruct.h"
      18             : #include "nsStyleStructInlines.h"
      19             : #include "nsString.h"
      20             : #include "nsPresContext.h"
      21             : #include "nsIStyleRule.h"
      22             : 
      23             : #include "nsCOMPtr.h"
      24             : #include "nsStyleSet.h"
      25             : #include "nsIPresShell.h"
      26             : 
      27             : #include "nsRuleNode.h"
      28             : #include "GeckoProfiler.h"
      29             : #include "nsIDocument.h"
      30             : #include "nsPrintfCString.h"
      31             : #include "RubyUtils.h"
      32             : #include "mozilla/Preferences.h"
      33             : #include "mozilla/ArenaObjectID.h"
      34             : #include "mozilla/StyleSetHandle.h"
      35             : #include "mozilla/StyleSetHandleInlines.h"
      36             : #include "mozilla/GeckoStyleContext.h"
      37             : #include "mozilla/ServoStyleContext.h"
      38             : #include "nsStyleContextInlines.h"
      39             : 
      40             : #include "mozilla/ReflowInput.h"
      41             : #include "nsLayoutUtils.h"
      42             : #include "nsCoord.h"
      43             : 
      44             : // Ensure the binding function declarations in nsStyleContext.h matches
      45             : // those in ServoBindings.h.
      46             : #include "mozilla/ServoBindings.h"
      47             : 
      48             : using namespace mozilla;
      49             : 
      50             : //----------------------------------------------------------------------
      51             : 
      52             : #ifdef DEBUG
      53             : 
      54             : // Check that the style struct IDs are in the same order as they are
      55             : // in nsStyleStructList.h, since when we set up the IDs, we include
      56             : // the inherited and reset structs spearately from nsStyleStructList.h
      57             : enum DebugStyleStruct {
      58             : #define STYLE_STRUCT(name, checkdata_cb) eDebugStyleStruct_##name,
      59             : #include "nsStyleStructList.h"
      60             : #undef STYLE_STRUCT
      61             : };
      62             : 
      63             : #define STYLE_STRUCT(name, checkdata_cb) \
      64             :   static_assert(static_cast<int>(eDebugStyleStruct_##name) == \
      65             :                   static_cast<int>(eStyleStruct_##name), \
      66             :                 "Style struct IDs are not declared in order?");
      67             : #include "nsStyleStructList.h"
      68             : #undef STYLE_STRUCT
      69             : 
      70             : const uint32_t nsStyleContext::sDependencyTable[] = {
      71             : #define STYLE_STRUCT(name, checkdata_cb)
      72             : #define STYLE_STRUCT_DEP(dep) NS_STYLE_INHERIT_BIT(dep) |
      73             : #define STYLE_STRUCT_END() 0,
      74             : #include "nsStyleStructList.h"
      75             : #undef STYLE_STRUCT
      76             : #undef STYLE_STRUCT_DEP
      77             : #undef STYLE_STRUCT_END
      78             : };
      79             : 
      80             : // Whether to perform expensive assertions in the nsStyleContext destructor.
      81             : static bool sExpensiveStyleStructAssertionsEnabled;
      82             : #endif
      83             : 
      84        2203 : nsStyleContext::nsStyleContext(nsStyleContext* aParent,
      85             :                                nsIAtom* aPseudoTag,
      86        2203 :                                CSSPseudoElementType aPseudoType)
      87             :   : mParent(aParent)
      88             :   , mPseudoTag(aPseudoTag)
      89        2203 :   , mBits(((uint64_t)aPseudoType) << NS_STYLE_CONTEXT_TYPE_SHIFT)
      90             :   , mRefCnt(0)
      91             : #ifdef DEBUG
      92        4406 :   , mFrameRefCnt(0)
      93             : #endif
      94        2203 : {}
      95             : 
      96             : void
      97        2203 : nsStyleContext::FinishConstruction()
      98             : {
      99             :   // This check has to be done "backward", because if it were written the
     100             :   // more natural way it wouldn't fail even when it needed to.
     101             :   static_assert((UINT64_MAX >> NS_STYLE_CONTEXT_TYPE_SHIFT) >=
     102             :                  static_cast<CSSPseudoElementTypeBase>(
     103             :                    CSSPseudoElementType::MAX),
     104             :                 "pseudo element bits no longer fit in a uint64_t");
     105             : 
     106             : #ifdef DEBUG
     107        2203 :   if (auto servo = GetAsServo()) {
     108           0 :     MOZ_ASSERT(servo->ComputedValues());
     109             :   } else {
     110        2203 :     MOZ_ASSERT(RuleNode());
     111             :   }
     112             : 
     113             :   static_assert(MOZ_ARRAY_LENGTH(nsStyleContext::sDependencyTable)
     114             :                   == nsStyleStructID_Length,
     115             :                 "Number of items in dependency table doesn't match IDs");
     116             : #endif
     117             : 
     118        2203 :   if (mParent) {
     119        2016 :     mParent->AddChild(this);
     120             :   }
     121             : 
     122        2203 :   SetStyleBits();
     123             : 
     124             :   #define eStyleStruct_LastItem (nsStyleStructID_Length - 1)
     125             :   static_assert(NS_STYLE_INHERIT_MASK & NS_STYLE_INHERIT_BIT(LastItem),
     126             :                 "NS_STYLE_INHERIT_MASK must be bigger, and other bits shifted");
     127             :   #undef eStyleStruct_LastItem
     128        2203 : }
     129             : 
     130             : void
     131        1618 : nsStyleContext::Destructor()
     132             : {
     133        1618 :   GeckoStyleContext* gecko = GetAsGecko();
     134             : #ifdef DEBUG
     135        1618 :   if (gecko) {
     136        1618 :     NS_ASSERTION(gecko->HasNoChildren(), "destructing context with children");
     137        1618 :     if (sExpensiveStyleStructAssertionsEnabled) {
     138             :       // Assert that the style structs we are about to destroy are not referenced
     139             :       // anywhere else in the style context tree.  These checks are expensive,
     140             :       // which is why they are not enabled by default.
     141           0 :       GeckoStyleContext* root = gecko;
     142           0 :       while (root->GetParent()) {
     143           0 :         root = root->GetParent();
     144             :       }
     145           0 :       root->AssertStructsNotUsedElsewhere(gecko,
     146           0 :                                           std::numeric_limits<int32_t>::max());
     147             :     } else {
     148             :       // In DEBUG builds when the pref is not enabled, we perform a more limited
     149             :       // check just of the children of this style context.
     150        1618 :       gecko->AssertStructsNotUsedElsewhere(gecko, 2);
     151             :     }
     152             :   }
     153             : #endif
     154             : 
     155        1618 :   nsPresContext *presContext = PresContext();
     156        3236 :   DebugOnly<nsStyleSet*> geckoStyleSet = presContext->PresShell()->StyleSet()->GetAsGecko();
     157        1618 :   NS_ASSERTION(!geckoStyleSet ||
     158             :                geckoStyleSet->GetRuleTree() == AsGecko()->RuleNode()->RuleTree() ||
     159             :                geckoStyleSet->IsInRuleTreeReconstruct(),
     160             :                "destroying style context from old rule tree too late");
     161             : 
     162        1618 :   if (mParent) {
     163        1497 :     mParent->RemoveChild(this);
     164             :   } else {
     165         121 :     presContext->StyleSet()->RootStyleContextRemoved();
     166             :   }
     167             : 
     168             :   // Free up our data structs.
     169        1618 :   if (gecko) {
     170        1618 :     gecko->DestroyCachedStructs(presContext);
     171             :   }
     172             : 
     173             :   // Free any ImageValues we were holding on to for CSS variable values.
     174        1618 :   CSSVariableImageTable::RemoveAll(this);
     175        1618 : }
     176             : 
     177        2053 : void nsStyleContext::AddChild(nsStyleContext* aChild)
     178             : {
     179        2053 :   if (GeckoStyleContext* gecko = GetAsGecko()) {
     180        2053 :     gecko->AddChild(aChild->AsGecko());
     181             :   }
     182        2053 : }
     183             : 
     184        1534 : void nsStyleContext::RemoveChild(nsStyleContext* aChild)
     185             : {
     186        1534 :   if (GeckoStyleContext* gecko = GetAsGecko()) {
     187        1534 :     gecko->RemoveChild(aChild->AsGecko());
     188             :   }
     189        1534 : }
     190             : 
     191             : void
     192          37 : nsStyleContext::MoveTo(nsStyleContext* aNewParent)
     193             : {
     194          37 :   MOZ_ASSERT(aNewParent != mParent);
     195             : 
     196             :   // This function shouldn't be getting called if the parents have different
     197             :   // values for some flags in mBits (unless the flag is also set on this style
     198             :   // context) because if that were the case we would need to recompute those
     199             :   // bits for |this|.
     200             : 
     201             : #define CHECK_FLAG(bit_) \
     202             :   MOZ_ASSERT((mParent->mBits & (bit_)) == (aNewParent->mBits & (bit_)) ||     \
     203             :              (mBits & (bit_)),                                                \
     204             :              "MoveTo cannot be called if " #bit_ " value on old and new "     \
     205             :              "style context parents do not match, unless the flag is set "    \
     206             :              "on this style context");
     207             : 
     208          37 :   CHECK_FLAG(NS_STYLE_HAS_PSEUDO_ELEMENT_DATA)
     209          37 :   CHECK_FLAG(NS_STYLE_IN_DISPLAY_NONE_SUBTREE)
     210          37 :   CHECK_FLAG(NS_STYLE_HAS_TEXT_DECORATION_LINES)
     211          37 :   CHECK_FLAG(NS_STYLE_RELEVANT_LINK_VISITED)
     212             : 
     213             : #undef CHECK_FLAG
     214             : 
     215             :   // Assertions checking for visited style are just to avoid some tricky
     216             :   // cases we can't be bothered handling at the moment.
     217          37 :   MOZ_ASSERT(!IsStyleIfVisited());
     218          37 :   MOZ_ASSERT(!mParent->IsStyleIfVisited());
     219          37 :   MOZ_ASSERT(!aNewParent->IsStyleIfVisited());
     220          37 :   MOZ_ASSERT(!mStyleIfVisited || mStyleIfVisited->mParent == mParent);
     221             : 
     222          37 :   if (mParent->HasChildThatUsesResetStyle()) {
     223           8 :     aNewParent->AddStyleBit(NS_STYLE_HAS_CHILD_THAT_USES_RESET_STYLE);
     224             :   }
     225             : 
     226          37 :   mParent->RemoveChild(this);
     227          37 :   mParent = aNewParent;
     228          37 :   mParent->AddChild(this);
     229             : 
     230          37 :   if (mStyleIfVisited) {
     231           0 :     mStyleIfVisited->mParent->RemoveChild(mStyleIfVisited);
     232           0 :     mStyleIfVisited->mParent = aNewParent;
     233           0 :     mStyleIfVisited->mParent->AddChild(mStyleIfVisited);
     234             :   }
     235          37 : }
     236             : 
     237             : template<class StyleContextLike>
     238             : nsChangeHint
     239         726 : nsStyleContext::CalcStyleDifferenceInternal(StyleContextLike* aNewContext,
     240             :                                             uint32_t* aEqualStructs,
     241             :                                             uint32_t* aSamePointerStructs)
     242             : {
     243        1452 :   AUTO_PROFILER_LABEL("nsStyleContext::CalcStyleDifferenceInternal", CSS);
     244             : 
     245             :   static_assert(nsStyleStructID_Length <= 32,
     246             :                 "aEqualStructs is not big enough");
     247             : 
     248         726 :   *aEqualStructs = 0;
     249             : 
     250         726 :   nsChangeHint hint = nsChangeHint(0);
     251         726 :   NS_ENSURE_TRUE(aNewContext, hint);
     252             :   // We must always ensure that we populate the structs on the new style
     253             :   // context that are filled in on the old context, so that if we get
     254             :   // two style changes in succession, the second of which causes a real
     255             :   // style change, the PeekStyleData doesn't return null (implying that
     256             :   // nobody ever looked at that struct's data).  In other words, we
     257             :   // can't skip later structs if we get a big change up front, because
     258             :   // we could later get a small change in one of those structs that we
     259             :   // don't want to miss.
     260             : 
     261        1452 :   DebugOnly<uint32_t> structsFound = 0;
     262             : 
     263             :   // FIXME(heycam): We should just do the comparison in
     264             :   // nsStyleVariables::CalcDifference, returning NeutralChange if there are
     265             :   // any Variables differences.
     266         726 :   const nsStyleVariables* thisVariables = PeekStyleVariables();
     267         726 :   if (thisVariables) {
     268         171 :     structsFound |= NS_STYLE_INHERIT_BIT(Variables);
     269         171 :     const nsStyleVariables* otherVariables = aNewContext->StyleVariables();
     270         171 :     if (thisVariables->mVariables == otherVariables->mVariables) {
     271          96 :       *aEqualStructs |= NS_STYLE_INHERIT_BIT(Variables);
     272             :     }
     273             :   } else {
     274         555 :     *aEqualStructs |= NS_STYLE_INHERIT_BIT(Variables);
     275             :   }
     276             : 
     277        1452 :   DebugOnly<int> styleStructCount = 1;  // count Variables already
     278             : 
     279             :   // Servo's optimization to stop the cascade when there are no style changes
     280             :   // that children need to be recascade for relies on comparing all of the
     281             :   // structs, not just those that are returned from PeekStyleData, although
     282             :   // if PeekStyleData does return null we still don't want to accumulate
     283             :   // any change hints for those structs.
     284         726 :   bool checkUnrequestedServoStructs = IsServo();
     285             : 
     286             : #define EXPAND(...) __VA_ARGS__
     287             : #define DO_STRUCT_DIFFERENCE_WITH_ARGS(struct_, extra_args_)                  \
     288             :   PR_BEGIN_MACRO                                                              \
     289             :     const nsStyle##struct_* this##struct_ = PeekStyle##struct_();             \
     290             :     bool unrequestedStruct;                                                   \
     291             :     if (this##struct_) {                                                      \
     292             :       unrequestedStruct = false;                                              \
     293             :       structsFound |= NS_STYLE_INHERIT_BIT(struct_);                          \
     294             :     } else if (checkUnrequestedServoStructs) {                                \
     295             :       this##struct_ =                                                         \
     296             :         Servo_GetStyle##struct_(AsServo()->ComputedValues());                 \
     297             :       unrequestedStruct = true;                                               \
     298             :     } else {                                                                  \
     299             :       unrequestedStruct = false;                                              \
     300             :     }                                                                         \
     301             :     if (this##struct_) {                                                      \
     302             :       const nsStyle##struct_* other##struct_ = aNewContext->Style##struct_(); \
     303             :       if (this##struct_ == other##struct_) {                                  \
     304             :         /* The very same struct, so we know that there will be no */          \
     305             :         /* differences.                                           */          \
     306             :         *aEqualStructs |= NS_STYLE_INHERIT_BIT(struct_);                      \
     307             :       } else {                                                                \
     308             :         nsChangeHint difference =                                             \
     309             :           this##struct_->CalcDifference(*other##struct_ EXPAND extra_args_);  \
     310             :         if (!unrequestedStruct) {                                             \
     311             :           hint |= difference;                                                 \
     312             :         }                                                                     \
     313             :         if (!difference) {                                                    \
     314             :           *aEqualStructs |= NS_STYLE_INHERIT_BIT(struct_);                    \
     315             :         }                                                                     \
     316             :       }                                                                       \
     317             :     } else {                                                                  \
     318             :       *aEqualStructs |= NS_STYLE_INHERIT_BIT(struct_);                        \
     319             :     }                                                                         \
     320             :     styleStructCount++;                                                       \
     321             :   PR_END_MACRO
     322             : #define DO_STRUCT_DIFFERENCE(struct_) \
     323             :   DO_STRUCT_DIFFERENCE_WITH_ARGS(struct_, ())
     324             : 
     325             :   // FIXME: The order of these DO_STRUCT_DIFFERENCE calls is no longer
     326             :   // significant.  With a small amount of effort, we could replace them with a
     327             :   // #include "nsStyleStructList.h".
     328         726 :   DO_STRUCT_DIFFERENCE(Display);
     329         726 :   DO_STRUCT_DIFFERENCE(XUL);
     330         726 :   DO_STRUCT_DIFFERENCE(Column);
     331         726 :   DO_STRUCT_DIFFERENCE(Content);
     332         726 :   DO_STRUCT_DIFFERENCE(UserInterface);
     333         726 :   DO_STRUCT_DIFFERENCE(Visibility);
     334         726 :   DO_STRUCT_DIFFERENCE(Outline);
     335         726 :   DO_STRUCT_DIFFERENCE(TableBorder);
     336         726 :   DO_STRUCT_DIFFERENCE(Table);
     337         726 :   DO_STRUCT_DIFFERENCE(UIReset);
     338         726 :   DO_STRUCT_DIFFERENCE(Text);
     339         726 :   DO_STRUCT_DIFFERENCE_WITH_ARGS(List, (, PeekStyleDisplay()));
     340         726 :   DO_STRUCT_DIFFERENCE(SVGReset);
     341         726 :   DO_STRUCT_DIFFERENCE(SVG);
     342         726 :   DO_STRUCT_DIFFERENCE_WITH_ARGS(Position, (, PeekStyleVisibility()));
     343         726 :   DO_STRUCT_DIFFERENCE(Font);
     344         726 :   DO_STRUCT_DIFFERENCE(Margin);
     345         726 :   DO_STRUCT_DIFFERENCE(Padding);
     346         726 :   DO_STRUCT_DIFFERENCE(Border);
     347         726 :   DO_STRUCT_DIFFERENCE(TextReset);
     348         726 :   DO_STRUCT_DIFFERENCE(Effects);
     349         726 :   DO_STRUCT_DIFFERENCE(Background);
     350         726 :   DO_STRUCT_DIFFERENCE(Color);
     351             : 
     352             : #undef DO_STRUCT_DIFFERENCE
     353             : #undef DO_STRUCT_DIFFERENCE_WITH_ARGS
     354             : #undef EXPAND
     355             : 
     356         726 :   MOZ_ASSERT(styleStructCount == nsStyleStructID_Length,
     357             :              "missing a call to DO_STRUCT_DIFFERENCE");
     358             : 
     359             : #ifdef DEBUG
     360             :   #define STYLE_STRUCT(name_, callback_)                                      \
     361             :     MOZ_ASSERT(!!(structsFound & NS_STYLE_INHERIT_BIT(name_)) ==              \
     362             :                !!PeekStyle##name_(),                                          \
     363             :                "PeekStyleData results must not change in the middle of "      \
     364             :                "difference calculation.");
     365             :   #include "nsStyleStructList.h"
     366             :   #undef STYLE_STRUCT
     367             : #endif
     368             : 
     369             :   // We check for struct pointer equality here rather than as part of the
     370             :   // DO_STRUCT_DIFFERENCE calls, since those calls can result in structs
     371             :   // we previously examined and found to be null on this style context
     372             :   // getting computed by later DO_STRUCT_DIFFERENCE calls (which can
     373             :   // happen when the nsRuleNode::ComputeXXXData method looks up another
     374             :   // struct.)  This is important for callers in RestyleManager that
     375             :   // need to know the equality or not of the final set of cached struct
     376             :   // pointers.
     377         726 :   *aSamePointerStructs = 0;
     378             : 
     379             : #define STYLE_STRUCT(name_, callback_)                                        \
     380             :   {                                                                           \
     381             :     const nsStyle##name_* data = PeekStyle##name_();                          \
     382             :     if (!data || data == aNewContext->Style##name_()) {                       \
     383             :       *aSamePointerStructs |= NS_STYLE_INHERIT_BIT(name_);                    \
     384             :     }                                                                         \
     385             :   }
     386             : #include "nsStyleStructList.h"
     387             : #undef STYLE_STRUCT
     388             : 
     389             :   // Note that we do not check whether this->RelevantLinkVisited() !=
     390             :   // aNewContext->RelevantLinkVisited(); we don't need to since
     391             :   // nsCSSFrameConstructor::DoContentStateChanged always adds
     392             :   // nsChangeHint_RepaintFrame for NS_EVENT_STATE_VISITED changes (and
     393             :   // needs to, since HasStateDependentStyle probably doesn't work right
     394             :   // for NS_EVENT_STATE_VISITED).  Hopefully this doesn't actually
     395             :   // expose whether links are visited to performance tests since all
     396             :   // link coloring happens asynchronously at a time when it's hard for
     397             :   // the page to measure.
     398             :   // However, we do need to compute the larger of the changes that can
     399             :   // happen depending on whether the link is visited or unvisited, since
     400             :   // doing only the one that's currently appropriate would expose which
     401             :   // links are in history to easy performance measurement.  Therefore,
     402             :   // here, we add nsChangeHint_RepaintFrame hints (the maximum for
     403             :   // things that can depend on :visited) for the properties on which we
     404             :   // call GetVisitedDependentColor.
     405         726 :   nsStyleContext *thisVis = GetStyleIfVisited(),
     406         726 :                 *otherVis = aNewContext->GetStyleIfVisited();
     407         726 :   if (!thisVis != !otherVis) {
     408             :     // One style context has a style-if-visited and the other doesn't.
     409             :     // Presume a difference.
     410           0 :     hint |= nsChangeHint_RepaintFrame;
     411         726 :   } else if (thisVis && !NS_IsHintSubset(nsChangeHint_RepaintFrame, hint)) {
     412             :     // Bug 1364484: Update comments here and potentially remove the assertion
     413             :     // below once we return a non-null visited context in CalcStyleDifference
     414             :     // using Servo values.  The approach is becoming quite similar to Gecko.
     415             :     // We'll handle visited style differently in servo. Assert against being
     416             :     // in the parallel traversal to avoid static analysis hazards when calling
     417             :     // StyleFoo() below.
     418           0 :     MOZ_ASSERT(!ServoStyleSet::IsInServoTraversal());
     419             : 
     420             :     // Both style contexts have a style-if-visited.
     421           0 :     bool change = false;
     422             : 
     423             :     // NB: Calling Peek on |this|, not |thisVis|, since callers may look
     424             :     // at a struct on |this| without looking at the same struct on
     425             :     // |thisVis| (including this function if we skip one of these checks
     426             :     // due to change being true already or due to the old style context
     427             :     // not having a style-if-visited), but not the other way around.
     428             : #define STYLE_FIELD(name_) thisVisStruct->name_ != otherVisStruct->name_
     429             : #define STYLE_STRUCT(name_, fields_)                                    \
     430             :     if (!change && PeekStyle##name_()) {                                \
     431             :       const nsStyle##name_* thisVisStruct = thisVis->Style##name_();    \
     432             :       const nsStyle##name_* otherVisStruct = otherVis->Style##name_();  \
     433             :       if (MOZ_FOR_EACH_SEPARATED(STYLE_FIELD, (||), (), fields_)) {     \
     434             :         change = true;                                                  \
     435             :       }                                                                 \
     436             :     }
     437             : #include "nsCSSVisitedDependentPropList.h"
     438             : #undef STYLE_STRUCT
     439             : #undef STYLE_FIELD
     440             : 
     441           0 :     if (change) {
     442           0 :       hint |= nsChangeHint_RepaintFrame;
     443             :     }
     444             :   }
     445             : 
     446         726 :   if (hint & nsChangeHint_UpdateContainingBlock) {
     447             :     // If a struct returned nsChangeHint_UpdateContainingBlock, that
     448             :     // means that one property's influence on whether we're a containing
     449             :     // block for abs-pos or fixed-pos elements has changed.  However, we
     450             :     // only need to return the hint if the overall computation of
     451             :     // whether we establish a containing block has changed.
     452             : 
     453             :     // This depends on data in nsStyleDisplay, nsStyleEffects and
     454             :     // nsStyleSVGReset, so we do it here.
     455             : 
     456             :     // Note that it's perhaps good for this test to be last because it
     457             :     // doesn't use Peek* functions to get the structs on the old
     458             :     // context.  But this isn't a big concern because these struct
     459             :     // getters should be called during frame construction anyway.
     460           6 :     if (ThreadsafeStyleDisplay()->IsAbsPosContainingBlockForAppropriateFrame(this) ==
     461             :         aNewContext->ThreadsafeStyleDisplay()->
     462           4 :           IsAbsPosContainingBlockForAppropriateFrame(aNewContext) &&
     463           1 :         ThreadsafeStyleDisplay()->IsFixedPosContainingBlockForAppropriateFrame(this) ==
     464             :         aNewContext->ThreadsafeStyleDisplay()->
     465             :           IsFixedPosContainingBlockForAppropriateFrame(aNewContext)) {
     466             :       // While some styles that cause the frame to be a containing block
     467             :       // has changed, the overall result hasn't.
     468           1 :       hint &= ~nsChangeHint_UpdateContainingBlock;
     469             :     }
     470             :   }
     471             : 
     472         726 :   MOZ_ASSERT(NS_IsHintSubset(hint, nsChangeHint_AllHints),
     473             :              "Added a new hint without bumping AllHints?");
     474         726 :   return hint & ~nsChangeHint_NeutralChange;
     475             : }
     476             : 
     477             : nsChangeHint
     478         726 : nsStyleContext::CalcStyleDifference(nsStyleContext* aNewContext,
     479             :                                     uint32_t* aEqualStructs,
     480             :                                     uint32_t* aSamePointerStructs)
     481             : {
     482             :   return CalcStyleDifferenceInternal(aNewContext,
     483             :                                      aEqualStructs,
     484         726 :                                      aSamePointerStructs);
     485             : }
     486             : 
     487             : class MOZ_STACK_CLASS FakeStyleContext
     488             : {
     489             : public:
     490           0 :   explicit FakeStyleContext(const ServoComputedValues* aComputedValues)
     491           0 :     : mComputedValues(aComputedValues) {}
     492             : 
     493           0 :   nsStyleContext* GetStyleIfVisited() {
     494             :     // Bug 1364484: Figure out what to do here for Stylo visited values.  We can
     495             :     // get the visited computed values:
     496             :     // RefPtr<ServoComputedValues> visitedComputedValues =
     497             :     //   Servo_ComputedValues_GetVisitedStyle(mComputedValues).Consume();
     498             :     // But what's the best way to create the nsStyleContext?
     499           0 :     return nullptr;
     500             :   }
     501             : 
     502             :   #define STYLE_STRUCT(name_, checkdata_cb_)                                  \
     503             :   const nsStyle##name_ * Style##name_() {                                     \
     504             :     return Servo_GetStyle##name_(mComputedValues);                            \
     505             :   }                                                                           \
     506             :   const nsStyle##name_ * ThreadsafeStyle##name_() {                           \
     507             :     return Servo_GetStyle##name_(mComputedValues);                            \
     508             :   }
     509             :   #include "nsStyleStructList.h"
     510             :   #undef STYLE_STRUCT
     511             : 
     512             : private:
     513             :   const ServoComputedValues* MOZ_NON_OWNING_REF mComputedValues;
     514             : };
     515             : 
     516             : nsChangeHint
     517           0 : nsStyleContext::CalcStyleDifference(const ServoComputedValues* aNewComputedValues,
     518             :                                     uint32_t* aEqualStructs,
     519             :                                     uint32_t* aSamePointerStructs)
     520             : {
     521           0 :   FakeStyleContext newContext(aNewComputedValues);
     522             :   return CalcStyleDifferenceInternal(&newContext,
     523             :                                      aEqualStructs,
     524           0 :                                      aSamePointerStructs);
     525             : }
     526             : 
     527             : namespace mozilla {
     528             : 
     529             : void
     530           0 : GeckoStyleContext::EnsureSameStructsCached(nsStyleContext* aOldContext)
     531             : {
     532             :   // NOTE(emilio): We could do better here for stylo, where we only call
     533             :   // Style##name_() because we need to run FinishStyle, but otherwise this
     534             :   // is only a bitwise or.
     535             :   //
     536             :   // We could reduce the FFI traffic we do only doing it for structs that have
     537             :   // non-trivial FinishStyle.
     538             : 
     539             : #define STYLE_STRUCT(name_, checkdata_cb_)                                    \
     540             :   if (aOldContext->PeekStyle##name_()) {                                      \
     541             :     Style##name_();                                                           \
     542             :   }
     543             : #include "nsStyleStructList.h"
     544             : #undef STYLE_STRUCT
     545           0 : }
     546             : 
     547             : } // namespace mozilla
     548             : 
     549             : #ifdef DEBUG
     550           0 : void nsStyleContext::List(FILE* out, int32_t aIndent, bool aListDescendants)
     551             : {
     552           0 :   nsAutoCString str;
     553             :   // Indent
     554             :   int32_t ix;
     555           0 :   for (ix = aIndent; --ix >= 0; ) {
     556           0 :     str.AppendLiteral("  ");
     557             :   }
     558           0 :   str.Append(nsPrintfCString("%p(%d) parent=%p ",
     559           0 :                              (void*)this, mRefCnt, (void *)mParent));
     560           0 :   if (mPseudoTag) {
     561           0 :     nsAutoString  buffer;
     562           0 :     mPseudoTag->ToString(buffer);
     563           0 :     AppendUTF16toUTF8(buffer, str);
     564           0 :     str.Append(' ');
     565             :   }
     566             : 
     567           0 :   if (IsServo()) {
     568           0 :     fprintf_stderr(out, "%s{ServoComputedValues}\n", str.get());
     569           0 :   } else if (nsRuleNode* ruleNode = AsGecko()->RuleNode()) {
     570           0 :     fprintf_stderr(out, "%s{\n", str.get());
     571           0 :     str.Truncate();
     572           0 :     while (ruleNode) {
     573           0 :       nsIStyleRule *styleRule = ruleNode->GetRule();
     574           0 :       if (styleRule) {
     575           0 :         styleRule->List(out, aIndent + 1);
     576             :       }
     577           0 :       ruleNode = ruleNode->GetParent();
     578             :     }
     579           0 :     for (ix = aIndent; --ix >= 0; ) {
     580           0 :       str.AppendLiteral("  ");
     581             :     }
     582           0 :     fprintf_stderr(out, "%s}\n", str.get());
     583             :   }
     584             :   else {
     585           0 :     fprintf_stderr(out, "%s{}\n", str.get());
     586             :   }
     587             : 
     588           0 :   if (aListDescendants) {
     589           0 :     if (GeckoStyleContext* gecko = GetAsGecko()) {
     590           0 :       gecko->ListDescendants(out, aIndent);
     591             :     }
     592             :   }
     593           0 : }
     594             : #endif
     595             : 
     596             : // Overridden to prevent the global delete from being called, since the memory
     597             : // came out of an nsIArena instead of the global delete operator's heap.
     598             : void
     599        1618 : nsStyleContext::Destroy()
     600             : {
     601        1618 :   if (IsGecko()) {
     602             :     // Get the pres context.
     603        3236 :     RefPtr<nsPresContext> presContext = PresContext();
     604             :     // Call our destructor.
     605        1618 :     this->AsGecko()->~GeckoStyleContext();
     606             :     // Don't let the memory be freed, since it will be recycled
     607             :     // instead. Don't call the global operator delete.
     608             :     presContext->PresShell()->
     609        1618 :       FreeByObjectID(eArenaObjectID_GeckoStyleContext, this);
     610             :   } else {
     611           0 :     delete static_cast<ServoStyleContext*>(this);
     612             :   }
     613        1618 : }
     614             : 
     615             : already_AddRefed<nsStyleContext>
     616        2203 : NS_NewStyleContext(nsStyleContext* aParentContext,
     617             :                    nsIAtom* aPseudoTag,
     618             :                    CSSPseudoElementType aPseudoType,
     619             :                    nsRuleNode* aRuleNode,
     620             :                    bool aSkipParentDisplayBasedStyleFixup)
     621             : {
     622        4406 :   RefPtr<nsRuleNode> node = aRuleNode;
     623             :   RefPtr<nsStyleContext> context =
     624        2203 :     new (aRuleNode->PresContext())
     625        4406 :     GeckoStyleContext(aParentContext, aPseudoTag, aPseudoType, node.forget(),
     626        6609 :                    aSkipParentDisplayBasedStyleFixup);
     627        4406 :   return context.forget();
     628             : }
     629             : 
     630             : namespace mozilla {
     631             : 
     632             : already_AddRefed<ServoStyleContext>
     633           0 : ServoStyleContext::Create(nsStyleContext* aParentContext,
     634             :                           nsPresContext* aPresContext,
     635             :                           nsIAtom* aPseudoTag,
     636             :                           CSSPseudoElementType aPseudoType,
     637             :                           already_AddRefed<ServoComputedValues> aComputedValues)
     638             : {
     639             :   RefPtr<ServoStyleContext> context =
     640             :     new ServoStyleContext(aParentContext, aPresContext, aPseudoTag, aPseudoType,
     641           0 :                           Move(aComputedValues));
     642           0 :   return context.forget();
     643             : }
     644             : 
     645             : } // namespace mozilla
     646             : 
     647             : nsIPresShell*
     648          16 : nsStyleContext::Arena()
     649             : {
     650          16 :   return PresContext()->PresShell();
     651             : }
     652             : 
     653             : template<typename Func>
     654             : static nscolor
     655         560 : GetVisitedDependentColorInternal(nsStyleContext* aSc, Func aColorFunc)
     656             : {
     657             :   nscolor colors[2];
     658         560 :   colors[0] = aColorFunc(aSc);
     659         560 :   if (nsStyleContext* visitedStyle = aSc->GetStyleIfVisited()) {
     660           0 :     colors[1] = aColorFunc(visitedStyle);
     661             :     return nsStyleContext::
     662           0 :       CombineVisitedColors(colors, aSc->RelevantLinkVisited());
     663             :   }
     664         560 :   return colors[0];
     665             : }
     666             : 
     667             : static nscolor
     668           0 : ExtractColor(nsStyleContext* aContext, const nscolor& aColor)
     669             : {
     670           0 :   return aColor;
     671             : }
     672             : 
     673             : static nscolor
     674         560 : ExtractColor(nsStyleContext* aContext, const StyleComplexColor& aColor)
     675             : {
     676         560 :   return aContext->StyleColor()->CalcComplexColor(aColor);
     677             : }
     678             : 
     679             : static nscolor
     680           0 : ExtractColor(nsStyleContext* aContext, const nsStyleSVGPaint& aPaintServer)
     681             : {
     682           0 :   return aPaintServer.Type() == eStyleSVGPaintType_Color
     683           0 :     ? aPaintServer.GetColor() : NS_RGBA(0, 0, 0, 0);
     684             : }
     685             : 
     686             : #define STYLE_FIELD(struct_, field_) aField == &struct_::field_ ||
     687             : #define STYLE_STRUCT(name_, fields_)                                          \
     688             :   template<> nscolor                                                          \
     689             :   nsStyleContext::GetVisitedDependentColor(                                   \
     690             :     decltype(nsStyle##name_::MOZ_ARG_1 fields_) nsStyle##name_::* aField)     \
     691             :   {                                                                           \
     692             :     MOZ_ASSERT(MOZ_FOR_EACH(STYLE_FIELD, (nsStyle##name_,), fields_) false,   \
     693             :                "Getting visited-dependent color for a field in nsStyle"#name_ \
     694             :                " which is not listed in nsCSSVisitedDependentPropList.h");    \
     695             :     return GetVisitedDependentColorInternal(this,                             \
     696             :                                             [aField](nsStyleContext* sc) {    \
     697             :       return ExtractColor(sc, sc->Style##name_()->*aField);                   \
     698             :     });                                                                       \
     699             :   }
     700             : #include "nsCSSVisitedDependentPropList.h"
     701             : #undef STYLE_STRUCT
     702             : #undef STYLE_FIELD
     703             : 
     704             : struct ColorIndexSet {
     705             :   uint8_t colorIndex, alphaIndex;
     706             : };
     707             : 
     708             : static const ColorIndexSet gVisitedIndices[2] = { { 0, 0 }, { 1, 0 } };
     709             : 
     710             : /* static */ nscolor
     711           0 : nsStyleContext::CombineVisitedColors(nscolor *aColors, bool aLinkIsVisited)
     712             : {
     713           0 :   if (NS_GET_A(aColors[1]) == 0) {
     714             :     // If the style-if-visited is transparent, then just use the
     715             :     // unvisited style rather than using the (meaningless) color
     716             :     // components of the visited style along with a potentially
     717             :     // non-transparent alpha value.
     718           0 :     aLinkIsVisited = false;
     719             :   }
     720             : 
     721             :   // NOTE: We want this code to have as little timing dependence as
     722             :   // possible on whether this->RelevantLinkVisited() is true.
     723             :   const ColorIndexSet &set =
     724           0 :     gVisitedIndices[aLinkIsVisited ? 1 : 0];
     725             : 
     726           0 :   nscolor colorColor = aColors[set.colorIndex];
     727           0 :   nscolor alphaColor = aColors[set.alphaIndex];
     728           0 :   return NS_RGBA(NS_GET_R(colorColor), NS_GET_G(colorColor),
     729             :                  NS_GET_B(colorColor), NS_GET_A(alphaColor));
     730             : }
     731             : 
     732             : #ifdef DEBUG
     733             : /* static */ const char*
     734           0 : nsStyleContext::StructName(nsStyleStructID aSID)
     735             : {
     736           0 :   switch (aSID) {
     737             : #define STYLE_STRUCT(name_, checkdata_cb)                                     \
     738             :     case eStyleStruct_##name_:                                                \
     739             :       return #name_;
     740             : #include "nsStyleStructList.h"
     741             : #undef STYLE_STRUCT
     742             :     default:
     743           0 :       return "Unknown";
     744             :   }
     745             : }
     746             : 
     747             : /* static */ bool
     748           0 : nsStyleContext::LookupStruct(const nsACString& aName, nsStyleStructID& aResult)
     749             : {
     750             :   if (false)
     751             :     ;
     752             : #define STYLE_STRUCT(name_, checkdata_cb_)                                    \
     753             :   else if (aName.EqualsLiteral(#name_))                                       \
     754             :     aResult = eStyleStruct_##name_;
     755             : #include "nsStyleStructList.h"
     756             : #undef STYLE_STRUCT
     757             :   else
     758           0 :     return false;
     759           0 :   return true;
     760             : }
     761             : #endif
     762             : 
     763             : #ifdef DEBUG
     764             : /* static */ void
     765           3 : nsStyleContext::Initialize()
     766             : {
     767             :   Preferences::AddBoolVarCache(
     768             :       &sExpensiveStyleStructAssertionsEnabled,
     769           3 :       "layout.css.expensive-style-struct-assertions.enabled");
     770           3 : }
     771             : #endif

Generated by: LCOV version 1.13