layout/style/nsStyleContext.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     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/. */
     6 /* the interface (to internal code) for retrieving computed style data */
     8 #include "mozilla/DebugOnly.h"
    10 #include "nsCSSAnonBoxes.h"
    11 #include "nsStyleConsts.h"
    12 #include "nsString.h"
    13 #include "nsPresContext.h"
    14 #include "nsIStyleRule.h"
    16 #include "nsCOMPtr.h"
    17 #include "nsStyleSet.h"
    18 #include "nsIPresShell.h"
    20 #include "nsRuleNode.h"
    21 #include "nsStyleContext.h"
    22 #include "nsStyleAnimation.h"
    23 #include "GeckoProfiler.h"
    25 #ifdef DEBUG
    26 // #define NOISY_DEBUG
    27 #endif
    29 using namespace mozilla;
    31 //----------------------------------------------------------------------
    34 nsStyleContext::nsStyleContext(nsStyleContext* aParent,
    35                                nsIAtom* aPseudoTag,
    36                                nsCSSPseudoElements::Type aPseudoType,
    37                                nsRuleNode* aRuleNode,
    38                                bool aSkipFlexItemStyleFixup)
    39   : mParent(aParent),
    40     mChild(nullptr),
    41     mEmptyChild(nullptr),
    42     mPseudoTag(aPseudoTag),
    43     mRuleNode(aRuleNode),
    44     mAllocations(nullptr),
    45     mCachedResetData(nullptr),
    46     mBits(((uint64_t)aPseudoType) << NS_STYLE_CONTEXT_TYPE_SHIFT),
    47     mRefCnt(0)
    48 {
    49   // This check has to be done "backward", because if it were written the
    50   // more natural way it wouldn't fail even when it needed to.
    51   static_assert((UINT64_MAX >> NS_STYLE_CONTEXT_TYPE_SHIFT) >=
    52                 nsCSSPseudoElements::ePseudo_MAX,
    53                 "pseudo element bits no longer fit in a uint64_t");
    54   MOZ_ASSERT(aRuleNode);
    56   mNextSibling = this;
    57   mPrevSibling = this;
    58   if (mParent) {
    59     mParent->AddRef();
    60     mParent->AddChild(this);
    61 #ifdef DEBUG
    62     nsRuleNode *r1 = mParent->RuleNode(), *r2 = aRuleNode;
    63     while (r1->GetParent())
    64       r1 = r1->GetParent();
    65     while (r2->GetParent())
    66       r2 = r2->GetParent();
    67     NS_ASSERTION(r1 == r2, "must be in the same rule tree as parent");
    68 #endif
    69   }
    71   mRuleNode->AddRef();
    72   mRuleNode->SetUsedDirectly(); // before ApplyStyleFixups()!
    74   ApplyStyleFixups(aSkipFlexItemStyleFixup);
    76   #define eStyleStruct_LastItem (nsStyleStructID_Length - 1)
    77   NS_ASSERTION(NS_STYLE_INHERIT_MASK & NS_STYLE_INHERIT_BIT(LastItem),
    78                "NS_STYLE_INHERIT_MASK must be bigger, and other bits shifted");
    79   #undef eStyleStruct_LastItem
    80 }
    82 nsStyleContext::~nsStyleContext()
    83 {
    84   NS_ASSERTION((nullptr == mChild) && (nullptr == mEmptyChild), "destructing context with children");
    86   nsPresContext *presContext = mRuleNode->PresContext();
    88   mRuleNode->Release();
    90   presContext->PresShell()->StyleSet()->
    91     NotifyStyleContextDestroyed(presContext, this);
    93   if (mParent) {
    94     mParent->RemoveChild(this);
    95     mParent->Release();
    96   }
    98   // Free up our data structs.
    99   mCachedInheritedData.DestroyStructs(mBits, presContext);
   100   if (mCachedResetData) {
   101     mCachedResetData->Destroy(mBits, presContext);
   102   }
   104   FreeAllocations(presContext);
   105 }
   107 void nsStyleContext::AddChild(nsStyleContext* aChild)
   108 {
   109   NS_ASSERTION(aChild->mPrevSibling == aChild &&
   110                aChild->mNextSibling == aChild,
   111                "child already in a child list");
   113   nsStyleContext **listPtr = aChild->mRuleNode->IsRoot() ? &mEmptyChild : &mChild;
   114   // Explicitly dereference listPtr so that compiler doesn't have to know that mNextSibling
   115   // etc. don't alias with what ever listPtr points at.
   116   nsStyleContext *list = *listPtr;
   118   // Insert at the beginning of the list.  See also FindChildWithRules.
   119   if (list) {
   120     // Link into existing elements, if there are any.
   121     aChild->mNextSibling = list;
   122     aChild->mPrevSibling = list->mPrevSibling;
   123     list->mPrevSibling->mNextSibling = aChild;
   124     list->mPrevSibling = aChild;
   125   }
   126   (*listPtr) = aChild;
   127 }
   129 void nsStyleContext::RemoveChild(nsStyleContext* aChild)
   130 {
   131   NS_PRECONDITION(nullptr != aChild && this == aChild->mParent, "bad argument");
   133   nsStyleContext **list = aChild->mRuleNode->IsRoot() ? &mEmptyChild : &mChild;
   135   if (aChild->mPrevSibling != aChild) { // has siblings
   136     if ((*list) == aChild) {
   137       (*list) = (*list)->mNextSibling;
   138     }
   139   } 
   140   else {
   141     NS_ASSERTION((*list) == aChild, "bad sibling pointers");
   142     (*list) = nullptr;
   143   }
   145   aChild->mPrevSibling->mNextSibling = aChild->mNextSibling;
   146   aChild->mNextSibling->mPrevSibling = aChild->mPrevSibling;
   147   aChild->mNextSibling = aChild;
   148   aChild->mPrevSibling = aChild;
   149 }
   151 already_AddRefed<nsStyleContext>
   152 nsStyleContext::FindChildWithRules(const nsIAtom* aPseudoTag, 
   153                                    nsRuleNode* aRuleNode,
   154                                    nsRuleNode* aRulesIfVisited,
   155                                    bool aRelevantLinkVisited)
   156 {
   157   NS_ABORT_IF_FALSE(aRulesIfVisited || !aRelevantLinkVisited,
   158     "aRelevantLinkVisited should only be set when we have a separate style");
   159   uint32_t threshold = 10; // The # of siblings we're willing to examine
   160                            // before just giving this whole thing up.
   162   nsRefPtr<nsStyleContext> result;
   163   nsStyleContext *list = aRuleNode->IsRoot() ? mEmptyChild : mChild;
   165   if (list) {
   166     nsStyleContext *child = list;
   167     do {
   168       if (child->mRuleNode == aRuleNode &&
   169           child->mPseudoTag == aPseudoTag &&
   170           !child->IsStyleIfVisited() &&
   171           child->RelevantLinkVisited() == aRelevantLinkVisited) {
   172         bool match = false;
   173         if (aRulesIfVisited) {
   174           match = child->GetStyleIfVisited() &&
   175                   child->GetStyleIfVisited()->mRuleNode == aRulesIfVisited;
   176         } else {
   177           match = !child->GetStyleIfVisited();
   178         }
   179         if (match) {
   180           result = child;
   181           break;
   182         }
   183       }
   184       child = child->mNextSibling;
   185       threshold--;
   186       if (threshold == 0)
   187         break;
   188     } while (child != list);
   189   }
   191   if (result) {
   192     if (result != list) {
   193       // Move result to the front of the list.
   194       RemoveChild(result);
   195       AddChild(result);
   196     }
   197   }
   199   return result.forget();
   200 }
   202 const void* nsStyleContext::GetCachedStyleData(nsStyleStructID aSID)
   203 {
   204   const void* cachedData;
   205   if (nsCachedStyleData::IsReset(aSID)) {
   206     if (mCachedResetData) {
   207       cachedData = mCachedResetData->mStyleStructs[aSID];
   208     } else {
   209       cachedData = nullptr;
   210     }
   211   } else {
   212     cachedData = mCachedInheritedData.mStyleStructs[aSID];
   213   }
   214   return cachedData;
   215 }
   217 const void* nsStyleContext::StyleData(nsStyleStructID aSID)
   218 {
   219   const void* cachedData = GetCachedStyleData(aSID);
   220   if (cachedData)
   221     return cachedData; // We have computed data stored on this node in the context tree.
   222   return mRuleNode->GetStyleData(aSID, this, true); // Our rule node will take care of it for us.
   223 }
   225 // This is an evil evil function, since it forces you to alloc your own separate copy of
   226 // style data!  Do not use this function unless you absolutely have to!  You should avoid
   227 // this at all costs! -dwh
   228 void* 
   229 nsStyleContext::GetUniqueStyleData(const nsStyleStructID& aSID)
   230 {
   231   // If we already own the struct and no kids could depend on it, then
   232   // just return it.  (We leak in this case if there are kids -- and this
   233   // function really shouldn't be called for style contexts that could
   234   // have kids depending on the data.  ClearStyleData would be OK, but
   235   // this test for no mChild or mEmptyChild doesn't catch that case.)
   236   const void *current = StyleData(aSID);
   237   if (!mChild && !mEmptyChild &&
   238       !(mBits & nsCachedStyleData::GetBitForSID(aSID)) &&
   239       GetCachedStyleData(aSID))
   240     return const_cast<void*>(current);
   242   void* result;
   243   nsPresContext *presContext = PresContext();
   244   switch (aSID) {
   246 #define UNIQUE_CASE(c_)                                                       \
   247   case eStyleStruct_##c_:                                                     \
   248     result = new (presContext) nsStyle##c_(                                   \
   249       * static_cast<const nsStyle##c_ *>(current));                           \
   250     break;
   252   UNIQUE_CASE(Display)
   253   UNIQUE_CASE(Background)
   254   UNIQUE_CASE(Text)
   255   UNIQUE_CASE(TextReset)
   257 #undef UNIQUE_CASE
   259   default:
   260     NS_ERROR("Struct type not supported.  Please find another way to do this if you can!");
   261     return nullptr;
   262   }
   264   SetStyle(aSID, result);
   265   mBits &= ~static_cast<uint64_t>(nsCachedStyleData::GetBitForSID(aSID));
   267   return result;
   268 }
   270 void
   271 nsStyleContext::SetStyle(nsStyleStructID aSID, void* aStruct)
   272 {
   273   // This method should only be called from nsRuleNode!  It is not a public
   274   // method!
   276   NS_ASSERTION(aSID >= 0 && aSID < nsStyleStructID_Length, "out of bounds");
   278   // NOTE:  nsCachedStyleData::GetStyleData works roughly the same way.
   279   // See the comments there (in nsRuleNode.h) for more details about
   280   // what this is doing and why.
   282   void** dataSlot;
   283   if (nsCachedStyleData::IsReset(aSID)) {
   284     if (!mCachedResetData) {
   285       mCachedResetData = new (mRuleNode->PresContext()) nsResetStyleData;
   286     }
   287     dataSlot = &mCachedResetData->mStyleStructs[aSID];
   288   } else {
   289     dataSlot = &mCachedInheritedData.mStyleStructs[aSID];
   290   }
   291   NS_ASSERTION(!*dataSlot || (mBits & nsCachedStyleData::GetBitForSID(aSID)),
   292                "Going to leak style data");
   293   *dataSlot = aStruct;
   294 }
   296 void
   297 nsStyleContext::ApplyStyleFixups(bool aSkipFlexItemStyleFixup)
   298 {
   299   // See if we have any text decorations.
   300   // First see if our parent has text decorations.  If our parent does, then we inherit the bit.
   301   if (mParent && mParent->HasTextDecorationLines()) {
   302     mBits |= NS_STYLE_HAS_TEXT_DECORATION_LINES;
   303   } else {
   304     // We might have defined a decoration.
   305     const nsStyleTextReset* text = StyleTextReset();
   306     uint8_t decorationLine = text->mTextDecorationLine;
   307     if (decorationLine != NS_STYLE_TEXT_DECORATION_LINE_NONE &&
   308         decorationLine != NS_STYLE_TEXT_DECORATION_LINE_OVERRIDE_ALL) {
   309       mBits |= NS_STYLE_HAS_TEXT_DECORATION_LINES;
   310     }
   311   }
   313   if ((mParent && mParent->HasPseudoElementData()) || mPseudoTag) {
   314     mBits |= NS_STYLE_HAS_PSEUDO_ELEMENT_DATA;
   315   }
   317   // Correct tables.
   318   const nsStyleDisplay* disp = StyleDisplay();
   319   if (disp->mDisplay == NS_STYLE_DISPLAY_TABLE) {
   320     // -moz-center and -moz-right are used for HTML's alignment
   321     // This is covering the <div align="right"><table>...</table></div> case.
   322     // In this case, we don't want to inherit the text alignment into the table.
   323     const nsStyleText* text = StyleText();
   325     if (text->mTextAlign == NS_STYLE_TEXT_ALIGN_MOZ_CENTER ||
   326         text->mTextAlign == NS_STYLE_TEXT_ALIGN_MOZ_RIGHT)
   327     {
   328       nsStyleText* uniqueText = (nsStyleText*)GetUniqueStyleData(eStyleStruct_Text);
   329       uniqueText->mTextAlign = NS_STYLE_TEXT_ALIGN_DEFAULT;
   330     }
   331   }
   333   // CSS2.1 section 9.2.4 specifies fixups for the 'display' property of
   334   // the root element.  We can't implement them in nsRuleNode because we
   335   // don't want to store all display structs that aren't 'block',
   336   // 'inline', or 'table' in the style context tree on the off chance
   337   // that the root element has its style reresolved later.  So do them
   338   // here if needed, by changing the style data, so that other code
   339   // doesn't get confused by looking at the style data.
   340   if (!mParent) {
   341     uint8_t displayVal = disp->mDisplay;
   342     nsRuleNode::EnsureBlockDisplay(displayVal, true);
   343     if (displayVal != disp->mDisplay) {
   344       nsStyleDisplay *mutable_display =
   345         static_cast<nsStyleDisplay*>(GetUniqueStyleData(eStyleStruct_Display));
   347       // If we're in this code, then mOriginalDisplay doesn't matter
   348       // for purposes of the cascade (because this nsStyleDisplay
   349       // isn't living in the ruletree anyway), and for determining
   350       // hypothetical boxes it's better to have mOriginalDisplay
   351       // matching mDisplay here.
   352       mutable_display->mOriginalDisplay = mutable_display->mDisplay =
   353         displayVal;
   354     }
   355   }
   357   // Adjust the "display" values of flex and grid items (but not for raw text,
   358   // placeholders, or table-parts). CSS3 Flexbox section 4 says:
   359   //   # The computed 'display' of a flex item is determined
   360   //   # by applying the table in CSS 2.1 Chapter 9.7.
   361   // ...which converts inline-level elements to their block-level equivalents.
   362   if (!aSkipFlexItemStyleFixup && mParent) {
   363     const nsStyleDisplay* parentDisp = mParent->StyleDisplay();
   364     if ((parentDisp->mDisplay == NS_STYLE_DISPLAY_FLEX ||
   365          parentDisp->mDisplay == NS_STYLE_DISPLAY_INLINE_FLEX ||
   366          parentDisp->mDisplay == NS_STYLE_DISPLAY_GRID ||
   367          parentDisp->mDisplay == NS_STYLE_DISPLAY_INLINE_GRID) &&
   368         GetPseudo() != nsCSSAnonBoxes::mozNonElement) {
   369       uint8_t displayVal = disp->mDisplay;
   370       // Skip table parts.
   371       // NOTE: This list needs to be kept in sync with
   372       // nsCSSFrameConstructor.cpp's "sDisplayData" array -- specifically,
   373       // this should be the list of display-values that have
   374       // FCDATA_DESIRED_PARENT_TYPE_TO_BITS specified in that array.
   375       if (NS_STYLE_DISPLAY_TABLE_CAPTION      != displayVal &&
   376           NS_STYLE_DISPLAY_TABLE_ROW_GROUP    != displayVal &&
   377           NS_STYLE_DISPLAY_TABLE_HEADER_GROUP != displayVal &&
   378           NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP != displayVal &&
   379           NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP != displayVal &&
   380           NS_STYLE_DISPLAY_TABLE_COLUMN       != displayVal &&
   381           NS_STYLE_DISPLAY_TABLE_ROW          != displayVal &&
   382           NS_STYLE_DISPLAY_TABLE_CELL         != displayVal) {
   384         // NOTE: Technically, we shouldn't modify the 'display' value of
   385         // positioned elements, since they aren't flex items. However, we don't
   386         // need to worry about checking for that, because if we're positioned,
   387         // we'll have already been through a call to EnsureBlockDisplay() in
   388         // nsRuleNode, so this call here won't change anything. So we're OK.
   389         nsRuleNode::EnsureBlockDisplay(displayVal);
   390         if (displayVal != disp->mDisplay) {
   391           NS_ASSERTION(!disp->IsAbsolutelyPositionedStyle(),
   392                        "We shouldn't be changing the display value of "
   393                        "positioned content (and we should have already "
   394                        "converted its display value to be block-level...)");
   395           nsStyleDisplay *mutable_display =
   396             static_cast<nsStyleDisplay*>(GetUniqueStyleData(eStyleStruct_Display));
   397           mutable_display->mDisplay = displayVal;
   398         }
   399       }
   400     }
   401   }
   403   // Compute User Interface style, to trigger loads of cursors
   404   StyleUserInterface();
   405 }
   407 nsChangeHint
   408 nsStyleContext::CalcStyleDifference(nsStyleContext* aOther,
   409                                     nsChangeHint aParentHintsNotHandledForDescendants)
   410 {
   411   PROFILER_LABEL("nsStyleContext", "CalcStyleDifference");
   413   NS_ABORT_IF_FALSE(NS_IsHintSubset(aParentHintsNotHandledForDescendants,
   414                                     nsChangeHint_Hints_NotHandledForDescendants),
   415                     "caller is passing inherited hints, but shouldn't be");
   417   nsChangeHint hint = NS_STYLE_HINT_NONE;
   418   NS_ENSURE_TRUE(aOther, hint);
   419   // We must always ensure that we populate the structs on the new style
   420   // context that are filled in on the old context, so that if we get
   421   // two style changes in succession, the second of which causes a real
   422   // style change, the PeekStyleData doesn't return null (implying that
   423   // nobody ever looked at that struct's data).  In other words, we
   424   // can't skip later structs if we get a big change up front, because
   425   // we could later get a small change in one of those structs that we
   426   // don't want to miss.
   428   // If our rule nodes are the same, then any differences in style data
   429   // are already accounted for by differences on ancestors.  We know
   430   // this because CalcStyleDifference is always called on two style
   431   // contexts that point to the same element, so we know that our
   432   // position in the style context tree is the same and our position in
   433   // the rule node tree is also the same.
   434   // However, if there were noninherited style change hints on the
   435   // parent, we might produce these same noninherited hints on this
   436   // style context's frame due to 'inherit' values, so we do need to
   437   // compare.
   438   // (Things like 'em' units are handled by the change hint produced
   439   // by font-size changing, so we don't need to worry about them like
   440   // we worry about 'inherit' values.)
   441   bool compare = mRuleNode != aOther->mRuleNode;
   443   // If we had any change in variable values, then we'll need to examine
   444   // all of the other style structs too, even if the new style context has
   445   // the same rule node as the old one.
   446   const nsStyleVariables* thisVariables = PeekStyleVariables();
   447   if (thisVariables) {
   448     const nsStyleVariables* otherVariables = aOther->StyleVariables();
   449     if (thisVariables->mVariables != otherVariables->mVariables) {
   450       compare = true;
   451     }
   452   }
   454   DebugOnly<int> styleStructCount = 1;  // count Variables already
   456 #define DO_STRUCT_DIFFERENCE(struct_)                                         \
   457   PR_BEGIN_MACRO                                                              \
   458     const nsStyle##struct_* this##struct_ = PeekStyle##struct_();             \
   459     if (this##struct_) {                                                      \
   460       const nsStyle##struct_* other##struct_ = aOther->Style##struct_();      \
   461       nsChangeHint maxDifference = nsStyle##struct_::MaxDifference();         \
   462       nsChangeHint maxDifferenceNeverInherited =                              \
   463         nsStyle##struct_::MaxDifferenceNeverInherited();                      \
   464       if ((compare ||                                                         \
   465            (NS_SubtractHint(maxDifference, maxDifferenceNeverInherited) &     \
   466             aParentHintsNotHandledForDescendants)) &&                         \
   467           !NS_IsHintSubset(maxDifference, hint) &&                            \
   468           this##struct_ != other##struct_) {                                  \
   469         NS_ASSERTION(NS_IsHintSubset(                                         \
   470              this##struct_->CalcDifference(*other##struct_),                  \
   471              nsStyle##struct_::MaxDifference()),                              \
   472              "CalcDifference() returned bigger hint than MaxDifference()");   \
   473         NS_UpdateHint(hint, this##struct_->CalcDifference(*other##struct_));  \
   474       }                                                                       \
   475     }                                                                         \
   476     styleStructCount++;                                                       \
   477   PR_END_MACRO
   479   // In general, we want to examine structs starting with those that can
   480   // cause the largest style change, down to those that can cause the
   481   // smallest.  This lets us skip later ones if we already have a hint
   482   // that subsumes their MaxDifference.  (As the hints get
   483   // finer-grained, this optimization is becoming less useful, though.)
   484   DO_STRUCT_DIFFERENCE(Display);
   485   DO_STRUCT_DIFFERENCE(XUL);
   486   DO_STRUCT_DIFFERENCE(Column);
   487   DO_STRUCT_DIFFERENCE(Content);
   488   DO_STRUCT_DIFFERENCE(UserInterface);
   489   DO_STRUCT_DIFFERENCE(Visibility);
   490   DO_STRUCT_DIFFERENCE(Outline);
   491   DO_STRUCT_DIFFERENCE(TableBorder);
   492   DO_STRUCT_DIFFERENCE(Table);
   493   DO_STRUCT_DIFFERENCE(UIReset);
   494   DO_STRUCT_DIFFERENCE(Text);
   495   DO_STRUCT_DIFFERENCE(List);
   496   DO_STRUCT_DIFFERENCE(Quotes);
   497   DO_STRUCT_DIFFERENCE(SVGReset);
   498   DO_STRUCT_DIFFERENCE(SVG);
   499   DO_STRUCT_DIFFERENCE(Position);
   500   DO_STRUCT_DIFFERENCE(Font);
   501   DO_STRUCT_DIFFERENCE(Margin);
   502   DO_STRUCT_DIFFERENCE(Padding);
   503   DO_STRUCT_DIFFERENCE(Border);
   504   DO_STRUCT_DIFFERENCE(TextReset);
   505   DO_STRUCT_DIFFERENCE(Background);
   506   DO_STRUCT_DIFFERENCE(Color);
   508 #undef DO_STRUCT_DIFFERENCE
   510   MOZ_ASSERT(styleStructCount == nsStyleStructID_Length,
   511              "missing a call to DO_STRUCT_DIFFERENCE");
   513   // Note that we do not check whether this->RelevantLinkVisited() !=
   514   // aOther->RelevantLinkVisited(); we don't need to since
   515   // nsCSSFrameConstructor::DoContentStateChanged always adds
   516   // nsChangeHint_RepaintFrame for NS_EVENT_STATE_VISITED changes (and
   517   // needs to, since HasStateDependentStyle probably doesn't work right
   518   // for NS_EVENT_STATE_VISITED).  Hopefully this doesn't actually
   519   // expose whether links are visited to performance tests since all
   520   // link coloring happens asynchronously at a time when it's hard for
   521   // the page to measure.
   522   // However, we do need to compute the larger of the changes that can
   523   // happen depending on whether the link is visited or unvisited, since
   524   // doing only the one that's currently appropriate would expose which
   525   // links are in history to easy performance measurement.  Therefore,
   526   // here, we add nsChangeHint_RepaintFrame hints (the maximum for
   527   // things that can depend on :visited) for the properties on which we
   528   // call GetVisitedDependentColor.
   529   nsStyleContext *thisVis = GetStyleIfVisited(),
   530                 *otherVis = aOther->GetStyleIfVisited();
   531   if (!thisVis != !otherVis) {
   532     // One style context has a style-if-visited and the other doesn't.
   533     // Presume a difference.
   534     NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
   535   } else if (thisVis && !NS_IsHintSubset(nsChangeHint_RepaintFrame, hint)) {
   536     // Both style contexts have a style-if-visited.
   537     bool change = false;
   539     // NB: Calling Peek on |this|, not |thisVis|, since callers may look
   540     // at a struct on |this| without looking at the same struct on
   541     // |thisVis| (including this function if we skip one of these checks
   542     // due to change being true already or due to the old style context
   543     // not having a style-if-visited), but not the other way around.
   544     if (PeekStyleColor()) {
   545       if (thisVis->StyleColor()->mColor !=
   546           otherVis->StyleColor()->mColor) {
   547         change = true;
   548       }
   549     }
   551     // NB: Calling Peek on |this|, not |thisVis| (see above).
   552     if (!change && PeekStyleBackground()) {
   553       if (thisVis->StyleBackground()->mBackgroundColor !=
   554           otherVis->StyleBackground()->mBackgroundColor) {
   555         change = true;
   556       }
   557     }
   559     // NB: Calling Peek on |this|, not |thisVis| (see above).
   560     if (!change && PeekStyleBorder()) {
   561       const nsStyleBorder *thisVisBorder = thisVis->StyleBorder();
   562       const nsStyleBorder *otherVisBorder = otherVis->StyleBorder();
   563       NS_FOR_CSS_SIDES(side) {
   564         bool thisFG, otherFG;
   565         nscolor thisColor, otherColor;
   566         thisVisBorder->GetBorderColor(side, thisColor, thisFG);
   567         otherVisBorder->GetBorderColor(side, otherColor, otherFG);
   568         if (thisFG != otherFG || (!thisFG && thisColor != otherColor)) {
   569           change = true;
   570           break;
   571         }
   572       }
   573     }
   575     // NB: Calling Peek on |this|, not |thisVis| (see above).
   576     if (!change && PeekStyleOutline()) {
   577       const nsStyleOutline *thisVisOutline = thisVis->StyleOutline();
   578       const nsStyleOutline *otherVisOutline = otherVis->StyleOutline();
   579       bool haveColor;
   580       nscolor thisColor, otherColor;
   581       if (thisVisOutline->GetOutlineInitialColor() != 
   582             otherVisOutline->GetOutlineInitialColor() ||
   583           (haveColor = thisVisOutline->GetOutlineColor(thisColor)) != 
   584             otherVisOutline->GetOutlineColor(otherColor) ||
   585           (haveColor && thisColor != otherColor)) {
   586         change = true;
   587       }
   588     }
   590     // NB: Calling Peek on |this|, not |thisVis| (see above).
   591     if (!change && PeekStyleColumn()) {
   592       const nsStyleColumn *thisVisColumn = thisVis->StyleColumn();
   593       const nsStyleColumn *otherVisColumn = otherVis->StyleColumn();
   594       if (thisVisColumn->mColumnRuleColor != otherVisColumn->mColumnRuleColor ||
   595           thisVisColumn->mColumnRuleColorIsForeground !=
   596             otherVisColumn->mColumnRuleColorIsForeground) {
   597         change = true;
   598       }
   599     }
   601     // NB: Calling Peek on |this|, not |thisVis| (see above).
   602     if (!change && PeekStyleTextReset()) {
   603       const nsStyleTextReset *thisVisTextReset = thisVis->StyleTextReset();
   604       const nsStyleTextReset *otherVisTextReset = otherVis->StyleTextReset();
   605       nscolor thisVisDecColor, otherVisDecColor;
   606       bool thisVisDecColorIsFG, otherVisDecColorIsFG;
   607       thisVisTextReset->GetDecorationColor(thisVisDecColor,
   608                                            thisVisDecColorIsFG);
   609       otherVisTextReset->GetDecorationColor(otherVisDecColor,
   610                                             otherVisDecColorIsFG);
   611       if (thisVisDecColorIsFG != otherVisDecColorIsFG ||
   612           (!thisVisDecColorIsFG && thisVisDecColor != otherVisDecColor)) {
   613         change = true;
   614       }
   615     }
   617     // NB: Calling Peek on |this|, not |thisVis| (see above).
   618     if (!change && PeekStyleSVG()) {
   619       const nsStyleSVG *thisVisSVG = thisVis->StyleSVG();
   620       const nsStyleSVG *otherVisSVG = otherVis->StyleSVG();
   621       if (thisVisSVG->mFill != otherVisSVG->mFill ||
   622           thisVisSVG->mStroke != otherVisSVG->mStroke) {
   623         change = true;
   624       }
   625     }
   627     if (change) {
   628       NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
   629     }
   630   }
   632   return hint;
   633 }
   635 void
   636 nsStyleContext::Mark()
   637 {
   638   // Mark our rule node.
   639   mRuleNode->Mark();
   641   // Mark our children (i.e., tell them to mark their rule nodes, etc.).
   642   if (mChild) {
   643     nsStyleContext* child = mChild;
   644     do {
   645       child->Mark();
   646       child = child->mNextSibling;
   647     } while (mChild != child);
   648   }
   650   if (mEmptyChild) {
   651     nsStyleContext* child = mEmptyChild;
   652     do {
   653       child->Mark();
   654       child = child->mNextSibling;
   655     } while (mEmptyChild != child);
   656   }
   657 }
   659 #ifdef DEBUG
   660 void nsStyleContext::List(FILE* out, int32_t aIndent)
   661 {
   662   // Indent
   663   int32_t ix;
   664   for (ix = aIndent; --ix >= 0; ) fputs("  ", out);
   665   fprintf(out, "%p(%d) parent=%p ",
   666           (void*)this, mRefCnt, (void *)mParent);
   667   if (mPseudoTag) {
   668     nsAutoString  buffer;
   669     mPseudoTag->ToString(buffer);
   670     fputs(NS_LossyConvertUTF16toASCII(buffer).get(), out);
   671     fputs(" ", out);
   672   }
   674   if (mRuleNode) {
   675     fputs("{\n", out);
   676     nsRuleNode* ruleNode = mRuleNode;
   677     while (ruleNode) {
   678       nsIStyleRule *styleRule = ruleNode->GetRule();
   679       if (styleRule) {
   680         styleRule->List(out, aIndent + 1);
   681       }
   682       ruleNode = ruleNode->GetParent();
   683     }
   684     for (ix = aIndent; --ix >= 0; ) fputs("  ", out);
   685     fputs("}\n", out);
   686   }
   687   else {
   688     fputs("{}\n", out);
   689   }
   691   if (nullptr != mChild) {
   692     nsStyleContext* child = mChild;
   693     do {
   694       child->List(out, aIndent + 1);
   695       child = child->mNextSibling;
   696     } while (mChild != child);
   697   }
   698   if (nullptr != mEmptyChild) {
   699     nsStyleContext* child = mEmptyChild;
   700     do {
   701       child->List(out, aIndent + 1);
   702       child = child->mNextSibling;
   703     } while (mEmptyChild != child);
   704   }
   705 }
   706 #endif
   708 // Overloaded new operator. Initializes the memory to 0 and relies on an arena
   709 // (which comes from the presShell) to perform the allocation.
   710 void* 
   711 nsStyleContext::operator new(size_t sz, nsPresContext* aPresContext) CPP_THROW_NEW
   712 {
   713   // Check the recycle list first.
   714   return aPresContext->PresShell()->AllocateByObjectID(nsPresArena::nsStyleContext_id, sz);
   715 }
   717 // Overridden to prevent the global delete from being called, since the memory
   718 // came out of an nsIArena instead of the global delete operator's heap.
   719 void 
   720 nsStyleContext::Destroy()
   721 {
   722   // Get the pres context from our rule node.
   723   nsRefPtr<nsPresContext> presContext = mRuleNode->PresContext();
   725   // Call our destructor.
   726   this->~nsStyleContext();
   728   // Don't let the memory be freed, since it will be recycled
   729   // instead. Don't call the global operator delete.
   730   presContext->PresShell()->FreeByObjectID(nsPresArena::nsStyleContext_id, this);
   731 }
   733 already_AddRefed<nsStyleContext>
   734 NS_NewStyleContext(nsStyleContext* aParentContext,
   735                    nsIAtom* aPseudoTag,
   736                    nsCSSPseudoElements::Type aPseudoType,
   737                    nsRuleNode* aRuleNode,
   738                    bool aSkipFlexItemStyleFixup)
   739 {
   740   nsRefPtr<nsStyleContext> context =
   741     new (aRuleNode->PresContext())
   742     nsStyleContext(aParentContext, aPseudoTag, aPseudoType, aRuleNode,
   743                    aSkipFlexItemStyleFixup);
   744   return context.forget();
   745 }
   747 static inline void
   748 ExtractAnimationValue(nsCSSProperty aProperty,
   749                       nsStyleContext* aStyleContext,
   750                       nsStyleAnimation::Value& aResult)
   751 {
   752   DebugOnly<bool> success =
   753     nsStyleAnimation::ExtractComputedValue(aProperty, aStyleContext, aResult);
   754   NS_ABORT_IF_FALSE(success,
   755                     "aProperty must be extractable by nsStyleAnimation");
   756 }
   758 static nscolor
   759 ExtractColor(nsCSSProperty aProperty,
   760              nsStyleContext *aStyleContext)
   761 {
   762   nsStyleAnimation::Value val;
   763   ExtractAnimationValue(aProperty, aStyleContext, val);
   764   return val.GetColorValue();
   765 }
   767 static nscolor
   768 ExtractColorLenient(nsCSSProperty aProperty,
   769                     nsStyleContext *aStyleContext)
   770 {
   771   nsStyleAnimation::Value val;
   772   ExtractAnimationValue(aProperty, aStyleContext, val);
   773   if (val.GetUnit() == nsStyleAnimation::eUnit_Color) {
   774     return val.GetColorValue();
   775   }
   776   return NS_RGBA(0, 0, 0, 0);
   777 }
   779 struct ColorIndexSet {
   780   uint8_t colorIndex, alphaIndex;
   781 };
   783 static const ColorIndexSet gVisitedIndices[2] = { { 0, 0 }, { 1, 0 } };
   785 nscolor
   786 nsStyleContext::GetVisitedDependentColor(nsCSSProperty aProperty)
   787 {
   788   NS_ASSERTION(aProperty == eCSSProperty_color ||
   789                aProperty == eCSSProperty_background_color ||
   790                aProperty == eCSSProperty_border_top_color ||
   791                aProperty == eCSSProperty_border_right_color_value ||
   792                aProperty == eCSSProperty_border_bottom_color ||
   793                aProperty == eCSSProperty_border_left_color_value ||
   794                aProperty == eCSSProperty_outline_color ||
   795                aProperty == eCSSProperty__moz_column_rule_color ||
   796                aProperty == eCSSProperty_text_decoration_color ||
   797                aProperty == eCSSProperty_fill ||
   798                aProperty == eCSSProperty_stroke,
   799                "we need to add to nsStyleContext::CalcStyleDifference");
   801   bool isPaintProperty = aProperty == eCSSProperty_fill ||
   802                          aProperty == eCSSProperty_stroke;
   804   nscolor colors[2];
   805   colors[0] = isPaintProperty ? ExtractColorLenient(aProperty, this)
   806                               : ExtractColor(aProperty, this);
   808   nsStyleContext *visitedStyle = this->GetStyleIfVisited();
   809   if (!visitedStyle) {
   810     return colors[0];
   811   }
   813   colors[1] = isPaintProperty ? ExtractColorLenient(aProperty, visitedStyle)
   814                               : ExtractColor(aProperty, visitedStyle);
   816   return nsStyleContext::CombineVisitedColors(colors,
   817                                               this->RelevantLinkVisited());
   818 }
   820 /* static */ nscolor
   821 nsStyleContext::CombineVisitedColors(nscolor *aColors, bool aLinkIsVisited)
   822 {
   823   if (NS_GET_A(aColors[1]) == 0) {
   824     // If the style-if-visited is transparent, then just use the
   825     // unvisited style rather than using the (meaningless) color
   826     // components of the visited style along with a potentially
   827     // non-transparent alpha value.
   828     aLinkIsVisited = false;
   829   }
   831   // NOTE: We want this code to have as little timing dependence as
   832   // possible on whether this->RelevantLinkVisited() is true.
   833   const ColorIndexSet &set =
   834     gVisitedIndices[aLinkIsVisited ? 1 : 0];
   836   nscolor colorColor = aColors[set.colorIndex];
   837   nscolor alphaColor = aColors[set.alphaIndex];
   838   return NS_RGBA(NS_GET_R(colorColor), NS_GET_G(colorColor),
   839                  NS_GET_B(colorColor), NS_GET_A(alphaColor));
   840 }
   842 void*
   843 nsStyleContext::Alloc(size_t aSize)
   844 {
   845   nsIPresShell *shell = PresContext()->PresShell();
   847   aSize += offsetof(AllocationHeader, mStorageStart);
   848   AllocationHeader *alloc =
   849     static_cast<AllocationHeader*>(shell->AllocateMisc(aSize));
   851   alloc->mSize = aSize; // NOTE: inflated by header
   853   alloc->mNext = mAllocations;
   854   mAllocations = alloc;
   856   return static_cast<void*>(&alloc->mStorageStart);
   857 }
   859 void
   860 nsStyleContext::FreeAllocations(nsPresContext *aPresContext)
   861 {
   862   nsIPresShell *shell = aPresContext->PresShell();
   864   for (AllocationHeader *alloc = mAllocations, *next; alloc; alloc = next) {
   865     next = alloc->mNext;
   866     shell->FreeMisc(alloc->mSize, alloc);
   867   }
   868 }
   870 #ifdef DEBUG
   871 /* static */ void
   872 nsStyleContext::AssertStyleStructMaxDifferenceValid()
   873 {
   874 #define STYLE_STRUCT(name, checkdata_cb)                                     \
   875     MOZ_ASSERT(NS_IsHintSubset(nsStyle##name::MaxDifferenceNeverInherited(), \
   876                                nsStyle##name::MaxDifference()));
   877 #include "nsStyleStructList.h"
   878 #undef STYLE_STRUCT
   879 }
   880 #endif

mercurial