Bumping manifests a=b2g-bump
[gecko.git] / layout / style / nsStyleContext.cpp
blobbabf1a8a5bb56db254f3bf9a82474b47509910d0
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 "mozilla/StyleAnimationValue.h"
23 #include "GeckoProfiler.h"
24 #include "nsIDocument.h"
25 #include "nsPrintfCString.h"
27 #ifdef DEBUG
28 // #define NOISY_DEBUG
29 #endif
31 using namespace mozilla;
33 //----------------------------------------------------------------------
36 nsStyleContext::nsStyleContext(nsStyleContext* aParent,
37 nsIAtom* aPseudoTag,
38 nsCSSPseudoElements::Type aPseudoType,
39 nsRuleNode* aRuleNode,
40 bool aSkipParentDisplayBasedStyleFixup)
41 : mParent(aParent),
42 mChild(nullptr),
43 mEmptyChild(nullptr),
44 mPseudoTag(aPseudoTag),
45 mRuleNode(aRuleNode),
46 mCachedResetData(nullptr),
47 mBits(((uint64_t)aPseudoType) << NS_STYLE_CONTEXT_TYPE_SHIFT),
48 mRefCnt(0)
49 #ifdef DEBUG
50 , mFrameRefCnt(0)
51 #endif
53 // This check has to be done "backward", because if it were written the
54 // more natural way it wouldn't fail even when it needed to.
55 static_assert((UINT64_MAX >> NS_STYLE_CONTEXT_TYPE_SHIFT) >=
56 nsCSSPseudoElements::ePseudo_MAX,
57 "pseudo element bits no longer fit in a uint64_t");
58 MOZ_ASSERT(aRuleNode);
60 mNextSibling = this;
61 mPrevSibling = this;
62 if (mParent) {
63 mParent->AddRef();
64 mParent->AddChild(this);
65 #ifdef DEBUG
66 nsRuleNode *r1 = mParent->RuleNode(), *r2 = aRuleNode;
67 while (r1->GetParent())
68 r1 = r1->GetParent();
69 while (r2->GetParent())
70 r2 = r2->GetParent();
71 NS_ASSERTION(r1 == r2, "must be in the same rule tree as parent");
72 #endif
75 mRuleNode->AddRef();
76 mRuleNode->SetUsedDirectly(); // before ApplyStyleFixups()!
78 ApplyStyleFixups(aSkipParentDisplayBasedStyleFixup);
80 #define eStyleStruct_LastItem (nsStyleStructID_Length - 1)
81 NS_ASSERTION(NS_STYLE_INHERIT_MASK & NS_STYLE_INHERIT_BIT(LastItem),
82 "NS_STYLE_INHERIT_MASK must be bigger, and other bits shifted");
83 #undef eStyleStruct_LastItem
86 nsStyleContext::~nsStyleContext()
88 NS_ASSERTION((nullptr == mChild) && (nullptr == mEmptyChild), "destructing context with children");
90 nsPresContext *presContext = mRuleNode->PresContext();
91 nsStyleSet* styleSet = presContext->PresShell()->StyleSet();
93 NS_ASSERTION(styleSet->GetRuleTree() == mRuleNode->RuleTree() ||
94 styleSet->IsInRuleTreeReconstruct(),
95 "destroying style context from old rule tree too late");
97 #ifdef DEBUG
98 #if 0
99 // Assert that the style structs we are about to destroy are not referenced
100 // anywhere else in the style context tree. These checks are expensive,
101 // which is why they are not enabled even #ifdef DEBUG.
102 nsStyleContext* root = this;
103 while (root->mParent) {
104 root = root->mParent;
106 root->AssertStructsNotUsedElsewhere(this,
107 std::numeric_limits<int32_t>::max());
108 #else
109 // In DEBUG builds we perform a more limited check just of the children
110 // of this style context.
111 AssertStructsNotUsedElsewhere(this, 2);
112 #endif
113 #endif
115 mRuleNode->Release();
117 styleSet->NotifyStyleContextDestroyed(presContext, this);
119 if (mParent) {
120 mParent->RemoveChild(this);
121 mParent->Release();
124 // Free up our data structs.
125 mCachedInheritedData.DestroyStructs(mBits, presContext);
126 if (mCachedResetData) {
127 mCachedResetData->Destroy(mBits, presContext);
131 #ifdef DEBUG
132 void
133 nsStyleContext::AssertStructsNotUsedElsewhere(
134 nsStyleContext* aDestroyingContext,
135 int32_t aLevels) const
137 if (aLevels == 0) {
138 return;
141 void* data;
143 if (mBits & NS_STYLE_IS_GOING_AWAY) {
144 return;
147 if (this != aDestroyingContext) {
148 nsInheritedStyleData& destroyingInheritedData =
149 aDestroyingContext->mCachedInheritedData;
150 #define STYLE_STRUCT_INHERITED(name_, checkdata_cb) \
151 data = destroyingInheritedData.mStyleStructs[eStyleStruct_##name_]; \
152 if (data && \
153 !(aDestroyingContext->mBits & NS_STYLE_INHERIT_BIT(name_)) && \
154 (mCachedInheritedData.mStyleStructs[eStyleStruct_##name_] == data)) { \
155 printf_stderr("style struct %p found on style context %p\n", data, this);\
156 nsString url; \
157 PresContext()->Document()->GetURL(url); \
158 printf_stderr(" in %s\n", NS_ConvertUTF16toUTF8(url).get()); \
159 MOZ_ASSERT(false, "destroying " #name_ " style struct still present " \
160 "in style context tree"); \
162 #define STYLE_STRUCT_RESET(name_, checkdata_cb)
164 #include "nsStyleStructList.h"
166 #undef STYLE_STRUCT_INHERITED
167 #undef STYLE_STRUCT_RESET
169 if (mCachedResetData) {
170 nsResetStyleData* destroyingResetData =
171 aDestroyingContext->mCachedResetData;
172 if (destroyingResetData) {
173 #define STYLE_STRUCT_INHERITED(name_, checkdata_cb_)
174 #define STYLE_STRUCT_RESET(name_, checkdata_cb) \
175 data = destroyingResetData->mStyleStructs[eStyleStruct_##name_]; \
176 if (data && \
177 !(aDestroyingContext->mBits & NS_STYLE_INHERIT_BIT(name_)) && \
178 (mCachedResetData->mStyleStructs[eStyleStruct_##name_] == data)) { \
179 printf_stderr("style struct %p found on style context %p\n", data, \
180 this); \
181 nsString url; \
182 PresContext()->Document()->GetURL(url); \
183 printf_stderr(" in %s\n", NS_ConvertUTF16toUTF8(url).get()); \
184 MOZ_ASSERT(false, "destroying " #name_ " style struct still present "\
185 "in style context tree"); \
188 #include "nsStyleStructList.h"
190 #undef STYLE_STRUCT_INHERITED
191 #undef STYLE_STRUCT_RESET
196 if (mChild) {
197 const nsStyleContext* child = mChild;
198 do {
199 child->AssertStructsNotUsedElsewhere(aDestroyingContext, aLevels - 1);
200 child = child->mNextSibling;
201 } while (child != mChild);
204 if (mEmptyChild) {
205 const nsStyleContext* child = mEmptyChild;
206 do {
207 child->AssertStructsNotUsedElsewhere(aDestroyingContext, aLevels - 1);
208 child = child->mNextSibling;
209 } while (child != mEmptyChild);
212 #endif
214 void nsStyleContext::AddChild(nsStyleContext* aChild)
216 NS_ASSERTION(aChild->mPrevSibling == aChild &&
217 aChild->mNextSibling == aChild,
218 "child already in a child list");
220 nsStyleContext **listPtr = aChild->mRuleNode->IsRoot() ? &mEmptyChild : &mChild;
221 // Explicitly dereference listPtr so that compiler doesn't have to know that mNextSibling
222 // etc. don't alias with what ever listPtr points at.
223 nsStyleContext *list = *listPtr;
225 // Insert at the beginning of the list. See also FindChildWithRules.
226 if (list) {
227 // Link into existing elements, if there are any.
228 aChild->mNextSibling = list;
229 aChild->mPrevSibling = list->mPrevSibling;
230 list->mPrevSibling->mNextSibling = aChild;
231 list->mPrevSibling = aChild;
233 (*listPtr) = aChild;
236 void nsStyleContext::RemoveChild(nsStyleContext* aChild)
238 NS_PRECONDITION(nullptr != aChild && this == aChild->mParent, "bad argument");
240 nsStyleContext **list = aChild->mRuleNode->IsRoot() ? &mEmptyChild : &mChild;
242 if (aChild->mPrevSibling != aChild) { // has siblings
243 if ((*list) == aChild) {
244 (*list) = (*list)->mNextSibling;
247 else {
248 NS_ASSERTION((*list) == aChild, "bad sibling pointers");
249 (*list) = nullptr;
252 aChild->mPrevSibling->mNextSibling = aChild->mNextSibling;
253 aChild->mNextSibling->mPrevSibling = aChild->mPrevSibling;
254 aChild->mNextSibling = aChild;
255 aChild->mPrevSibling = aChild;
258 void
259 nsStyleContext::MoveTo(nsStyleContext* aNewParent)
261 MOZ_ASSERT(aNewParent != mParent);
263 // Assertions checking for visited style are just to avoid some tricky
264 // cases we can't be bothered handling at the moment.
265 MOZ_ASSERT(!IsStyleIfVisited());
266 MOZ_ASSERT(!aNewParent->IsStyleIfVisited());
268 nsStyleContext* oldParent = mParent;
270 aNewParent->AddRef();
272 mParent->RemoveChild(this);
274 mParent = aNewParent;
275 mParent->AddChild(this);
277 oldParent->Release();
280 already_AddRefed<nsStyleContext>
281 nsStyleContext::FindChildWithRules(const nsIAtom* aPseudoTag,
282 nsRuleNode* aRuleNode,
283 nsRuleNode* aRulesIfVisited,
284 bool aRelevantLinkVisited)
286 uint32_t threshold = 10; // The # of siblings we're willing to examine
287 // before just giving this whole thing up.
289 nsRefPtr<nsStyleContext> result;
290 nsStyleContext *list = aRuleNode->IsRoot() ? mEmptyChild : mChild;
292 if (list) {
293 nsStyleContext *child = list;
294 do {
295 if (child->mRuleNode == aRuleNode &&
296 child->mPseudoTag == aPseudoTag &&
297 !child->IsStyleIfVisited() &&
298 child->RelevantLinkVisited() == aRelevantLinkVisited) {
299 bool match = false;
300 if (aRulesIfVisited) {
301 match = child->GetStyleIfVisited() &&
302 child->GetStyleIfVisited()->mRuleNode == aRulesIfVisited;
303 } else {
304 match = !child->GetStyleIfVisited();
306 if (match) {
307 result = child;
308 break;
311 child = child->mNextSibling;
312 threshold--;
313 if (threshold == 0)
314 break;
315 } while (child != list);
318 if (result) {
319 if (result != list) {
320 // Move result to the front of the list.
321 RemoveChild(result);
322 AddChild(result);
324 result->mBits |= NS_STYLE_IS_SHARED;
327 return result.forget();
330 /* static */ bool
331 nsStyleContext::ListContainsStyleContextThatUsesGrandancestorStyle(const nsStyleContext* aHead)
333 if (aHead) {
334 const nsStyleContext* child = aHead;
335 do {
336 if (child->UsesGrandancestorStyle()) {
337 return true;
339 child = child->mNextSibling;
340 } while (child != aHead);
343 return false;
346 bool
347 nsStyleContext::HasChildThatUsesGrandancestorStyle() const
349 return ListContainsStyleContextThatUsesGrandancestorStyle(mEmptyChild) ||
350 ListContainsStyleContextThatUsesGrandancestorStyle(mChild);
353 const void* nsStyleContext::GetCachedStyleData(nsStyleStructID aSID)
355 const void* cachedData;
356 if (nsCachedStyleData::IsReset(aSID)) {
357 if (mCachedResetData) {
358 cachedData = mCachedResetData->mStyleStructs[aSID];
359 } else {
360 cachedData = nullptr;
362 } else {
363 cachedData = mCachedInheritedData.mStyleStructs[aSID];
365 return cachedData;
368 const void* nsStyleContext::StyleData(nsStyleStructID aSID)
370 const void* cachedData = GetCachedStyleData(aSID);
371 if (cachedData)
372 return cachedData; // We have computed data stored on this node in the context tree.
373 return mRuleNode->GetStyleData(aSID, this, true); // Our rule node will take care of it for us.
376 // This is an evil evil function, since it forces you to alloc your own separate copy of
377 // style data! Do not use this function unless you absolutely have to! You should avoid
378 // this at all costs! -dwh
379 void*
380 nsStyleContext::GetUniqueStyleData(const nsStyleStructID& aSID)
382 // If we already own the struct and no kids could depend on it, then
383 // just return it. (We leak in this case if there are kids -- and this
384 // function really shouldn't be called for style contexts that could
385 // have kids depending on the data. ClearStyleData would be OK, but
386 // this test for no mChild or mEmptyChild doesn't catch that case.)
387 const void *current = StyleData(aSID);
388 if (!mChild && !mEmptyChild &&
389 !(mBits & nsCachedStyleData::GetBitForSID(aSID)) &&
390 GetCachedStyleData(aSID))
391 return const_cast<void*>(current);
393 void* result;
394 nsPresContext *presContext = PresContext();
395 switch (aSID) {
397 #define UNIQUE_CASE(c_) \
398 case eStyleStruct_##c_: \
399 result = new (presContext) nsStyle##c_( \
400 * static_cast<const nsStyle##c_ *>(current)); \
401 break;
403 UNIQUE_CASE(Display)
404 UNIQUE_CASE(Background)
405 UNIQUE_CASE(Text)
406 UNIQUE_CASE(TextReset)
408 #undef UNIQUE_CASE
410 default:
411 NS_ERROR("Struct type not supported. Please find another way to do this if you can!");
412 return nullptr;
415 SetStyle(aSID, result);
416 mBits &= ~static_cast<uint64_t>(nsCachedStyleData::GetBitForSID(aSID));
418 return result;
421 void
422 nsStyleContext::SetStyle(nsStyleStructID aSID, void* aStruct)
424 // This method should only be called from nsRuleNode! It is not a public
425 // method!
427 NS_ASSERTION(aSID >= 0 && aSID < nsStyleStructID_Length, "out of bounds");
429 // NOTE: nsCachedStyleData::GetStyleData works roughly the same way.
430 // See the comments there (in nsRuleNode.h) for more details about
431 // what this is doing and why.
433 void** dataSlot;
434 if (nsCachedStyleData::IsReset(aSID)) {
435 if (!mCachedResetData) {
436 mCachedResetData = new (mRuleNode->PresContext()) nsResetStyleData;
438 dataSlot = &mCachedResetData->mStyleStructs[aSID];
439 } else {
440 dataSlot = &mCachedInheritedData.mStyleStructs[aSID];
442 NS_ASSERTION(!*dataSlot || (mBits & nsCachedStyleData::GetBitForSID(aSID)),
443 "Going to leak style data");
444 *dataSlot = aStruct;
447 void
448 nsStyleContext::ApplyStyleFixups(bool aSkipParentDisplayBasedStyleFixup)
450 // See if we have any text decorations.
451 // First see if our parent has text decorations. If our parent does, then we inherit the bit.
452 if (mParent && mParent->HasTextDecorationLines()) {
453 mBits |= NS_STYLE_HAS_TEXT_DECORATION_LINES;
454 } else {
455 // We might have defined a decoration.
456 const nsStyleTextReset* text = StyleTextReset();
457 uint8_t decorationLine = text->mTextDecorationLine;
458 if (decorationLine != NS_STYLE_TEXT_DECORATION_LINE_NONE &&
459 decorationLine != NS_STYLE_TEXT_DECORATION_LINE_OVERRIDE_ALL) {
460 mBits |= NS_STYLE_HAS_TEXT_DECORATION_LINES;
464 if ((mParent && mParent->HasPseudoElementData()) || mPseudoTag) {
465 mBits |= NS_STYLE_HAS_PSEUDO_ELEMENT_DATA;
468 // Correct tables.
469 const nsStyleDisplay* disp = StyleDisplay();
470 if (disp->mDisplay == NS_STYLE_DISPLAY_TABLE) {
471 // -moz-center and -moz-right are used for HTML's alignment
472 // This is covering the <div align="right"><table>...</table></div> case.
473 // In this case, we don't want to inherit the text alignment into the table.
474 const nsStyleText* text = StyleText();
476 if (text->mTextAlign == NS_STYLE_TEXT_ALIGN_MOZ_CENTER ||
477 text->mTextAlign == NS_STYLE_TEXT_ALIGN_MOZ_RIGHT)
479 nsStyleText* uniqueText = (nsStyleText*)GetUniqueStyleData(eStyleStruct_Text);
480 uniqueText->mTextAlign = NS_STYLE_TEXT_ALIGN_DEFAULT;
484 // CSS2.1 section 9.2.4 specifies fixups for the 'display' property of
485 // the root element. We can't implement them in nsRuleNode because we
486 // don't want to store all display structs that aren't 'block',
487 // 'inline', or 'table' in the style context tree on the off chance
488 // that the root element has its style reresolved later. So do them
489 // here if needed, by changing the style data, so that other code
490 // doesn't get confused by looking at the style data.
491 if (!mParent) {
492 uint8_t displayVal = disp->mDisplay;
493 nsRuleNode::EnsureBlockDisplay(displayVal, true);
494 if (displayVal != disp->mDisplay) {
495 nsStyleDisplay *mutable_display =
496 static_cast<nsStyleDisplay*>(GetUniqueStyleData(eStyleStruct_Display));
498 // If we're in this code, then mOriginalDisplay doesn't matter
499 // for purposes of the cascade (because this nsStyleDisplay
500 // isn't living in the ruletree anyway), and for determining
501 // hypothetical boxes it's better to have mOriginalDisplay
502 // matching mDisplay here.
503 mutable_display->mOriginalDisplay = mutable_display->mDisplay =
504 displayVal;
508 // Adjust the "display" values of flex and grid items (but not for raw text,
509 // placeholders, or table-parts). CSS3 Flexbox section 4 says:
510 // # The computed 'display' of a flex item is determined
511 // # by applying the table in CSS 2.1 Chapter 9.7.
512 // ...which converts inline-level elements to their block-level equivalents.
513 // Any block-level element directly contained by elements with ruby display
514 // values are converted to their inline-level equivalents.
515 if (!aSkipParentDisplayBasedStyleFixup && mParent) {
516 // Skip display:contents ancestors to reach the potential container.
517 // (If there are only display:contents ancestors between this node and
518 // a flex/grid container ancestor, then this node is a flex/grid item, since
519 // its parent *in the frame tree* will be the flex/grid container. So we treat
520 // it like a flex/grid item here.)
521 nsStyleContext* containerContext = mParent;
522 const nsStyleDisplay* containerDisp = containerContext->StyleDisplay();
523 while (containerDisp->mDisplay == NS_STYLE_DISPLAY_CONTENTS) {
524 if (!containerContext->GetParent()) {
525 break;
527 containerContext = containerContext->GetParent();
528 containerDisp = containerContext->StyleDisplay();
530 if (containerDisp->IsFlexOrGridDisplayType() &&
531 GetPseudo() != nsCSSAnonBoxes::mozNonElement) {
532 uint8_t displayVal = disp->mDisplay;
533 // Skip table parts.
534 // NOTE: This list needs to be kept in sync with
535 // nsCSSFrameConstructor::FindDisplayData() -- specifically,
536 // this should be the list of display-values that returns
537 // FCDATA_DESIRED_PARENT_TYPE_TO_BITS from that method.
538 if (NS_STYLE_DISPLAY_TABLE_CAPTION != displayVal &&
539 NS_STYLE_DISPLAY_TABLE_ROW_GROUP != displayVal &&
540 NS_STYLE_DISPLAY_TABLE_HEADER_GROUP != displayVal &&
541 NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP != displayVal &&
542 NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP != displayVal &&
543 NS_STYLE_DISPLAY_TABLE_COLUMN != displayVal &&
544 NS_STYLE_DISPLAY_TABLE_ROW != displayVal &&
545 NS_STYLE_DISPLAY_TABLE_CELL != displayVal) {
547 // NOTE: Technically, we shouldn't modify the 'display' value of
548 // positioned elements, since they aren't flex/grid items. However,
549 // we don't need to worry about checking for that, because if we're
550 // positioned, we'll have already been through a call to
551 // EnsureBlockDisplay() in nsRuleNode, so this call here won't change
552 // anything. So we're OK.
553 nsRuleNode::EnsureBlockDisplay(displayVal);
554 if (displayVal != disp->mDisplay) {
555 NS_ASSERTION(!disp->IsAbsolutelyPositionedStyle(),
556 "We shouldn't be changing the display value of "
557 "positioned content (and we should have already "
558 "converted its display value to be block-level...)");
559 nsStyleDisplay *mutable_display =
560 static_cast<nsStyleDisplay*>(GetUniqueStyleData(eStyleStruct_Display));
561 mutable_display->mDisplay = displayVal;
566 // The display change should only occur for "in-flow" children
567 if (!disp->IsOutOfFlowStyle() &&
568 ((containerDisp->mDisplay == NS_STYLE_DISPLAY_INLINE &&
569 containerContext->IsInlineDescendantOfRuby()) ||
570 containerDisp->IsRubyDisplayType())) {
571 mBits |= NS_STYLE_IS_INLINE_DESCENDANT_OF_RUBY;
572 uint8_t displayVal = disp->mDisplay;
573 nsRuleNode::EnsureInlineDisplay(displayVal);
574 if (displayVal != disp->mDisplay) {
575 nsStyleDisplay *mutable_display =
576 static_cast<nsStyleDisplay*>(GetUniqueStyleData(eStyleStruct_Display));
577 mutable_display->mDisplay = displayVal;
582 // Compute User Interface style, to trigger loads of cursors
583 StyleUserInterface();
586 nsChangeHint
587 nsStyleContext::CalcStyleDifference(nsStyleContext* aOther,
588 nsChangeHint aParentHintsNotHandledForDescendants,
589 uint32_t* aEqualStructs)
591 PROFILER_LABEL("nsStyleContext", "CalcStyleDifference",
592 js::ProfileEntry::Category::CSS);
594 NS_ABORT_IF_FALSE(NS_IsHintSubset(aParentHintsNotHandledForDescendants,
595 nsChangeHint_Hints_NotHandledForDescendants),
596 "caller is passing inherited hints, but shouldn't be");
598 static_assert(nsStyleStructID_Length <= 32,
599 "aEqualStructs is not big enough");
601 *aEqualStructs = 0;
603 nsChangeHint hint = NS_STYLE_HINT_NONE;
604 NS_ENSURE_TRUE(aOther, hint);
605 // We must always ensure that we populate the structs on the new style
606 // context that are filled in on the old context, so that if we get
607 // two style changes in succession, the second of which causes a real
608 // style change, the PeekStyleData doesn't return null (implying that
609 // nobody ever looked at that struct's data). In other words, we
610 // can't skip later structs if we get a big change up front, because
611 // we could later get a small change in one of those structs that we
612 // don't want to miss.
614 // If our rule nodes are the same, then any differences in style data
615 // are already accounted for by differences on ancestors. We know
616 // this because CalcStyleDifference is always called on two style
617 // contexts that point to the same element, so we know that our
618 // position in the style context tree is the same and our position in
619 // the rule node tree is also the same.
620 // However, if there were noninherited style change hints on the
621 // parent, we might produce these same noninherited hints on this
622 // style context's frame due to 'inherit' values, so we do need to
623 // compare.
624 // (Things like 'em' units are handled by the change hint produced
625 // by font-size changing, so we don't need to worry about them like
626 // we worry about 'inherit' values.)
627 bool compare = mRuleNode != aOther->mRuleNode;
629 // If we had any change in variable values, then we'll need to examine
630 // all of the other style structs too, even if the new style context has
631 // the same rule node as the old one.
632 const nsStyleVariables* thisVariables = PeekStyleVariables();
633 if (thisVariables) {
634 const nsStyleVariables* otherVariables = aOther->StyleVariables();
635 if (thisVariables->mVariables == otherVariables->mVariables) {
636 *aEqualStructs |= nsCachedStyleData::GetBitForSID(eStyleStruct_Variables);
637 } else {
638 compare = true;
640 } else {
641 *aEqualStructs |= nsCachedStyleData::GetBitForSID(eStyleStruct_Variables);
644 DebugOnly<int> styleStructCount = 1; // count Variables already
646 #define DO_STRUCT_DIFFERENCE(struct_) \
647 PR_BEGIN_MACRO \
648 const nsStyle##struct_* this##struct_ = PeekStyle##struct_(); \
649 if (this##struct_) { \
650 const nsStyle##struct_* other##struct_ = aOther->Style##struct_(); \
651 nsChangeHint maxDifference = nsStyle##struct_::MaxDifference(); \
652 nsChangeHint maxDifferenceNeverInherited = \
653 nsStyle##struct_::MaxDifferenceNeverInherited(); \
654 if (this##struct_ == other##struct_) { \
655 /* The very same struct, so we know that there will be no */ \
656 /* differences. */ \
657 *aEqualStructs |= NS_STYLE_INHERIT_BIT(struct_); \
658 } else if (compare || \
659 (NS_SubtractHint(maxDifference, \
660 maxDifferenceNeverInherited) & \
661 aParentHintsNotHandledForDescendants)) { \
662 nsChangeHint difference = \
663 this##struct_->CalcDifference(*other##struct_); \
664 NS_ASSERTION(NS_IsHintSubset(difference, maxDifference), \
665 "CalcDifference() returned bigger hint than " \
666 "MaxDifference()"); \
667 NS_UpdateHint(hint, difference); \
668 if (!difference) { \
669 *aEqualStructs |= NS_STYLE_INHERIT_BIT(struct_); \
671 } else { \
672 /* We still must call CalcDifference to see if there were any */ \
673 /* changes so that we can set *aEqualStructs appropriately. */ \
674 nsChangeHint difference = \
675 this##struct_->CalcDifference(*other##struct_); \
676 NS_ASSERTION(NS_IsHintSubset(difference, maxDifference), \
677 "CalcDifference() returned bigger hint than " \
678 "MaxDifference()"); \
679 if (!difference) { \
680 *aEqualStructs |= NS_STYLE_INHERIT_BIT(struct_); \
683 } else { \
684 *aEqualStructs |= NS_STYLE_INHERIT_BIT(struct_); \
686 styleStructCount++; \
687 PR_END_MACRO
689 // In general, we want to examine structs starting with those that can
690 // cause the largest style change, down to those that can cause the
691 // smallest. This lets us skip later ones if we already have a hint
692 // that subsumes their MaxDifference. (As the hints get
693 // finer-grained, this optimization is becoming less useful, though.)
694 DO_STRUCT_DIFFERENCE(Display);
695 DO_STRUCT_DIFFERENCE(XUL);
696 DO_STRUCT_DIFFERENCE(Column);
697 DO_STRUCT_DIFFERENCE(Content);
698 DO_STRUCT_DIFFERENCE(UserInterface);
699 DO_STRUCT_DIFFERENCE(Visibility);
700 DO_STRUCT_DIFFERENCE(Outline);
701 DO_STRUCT_DIFFERENCE(TableBorder);
702 DO_STRUCT_DIFFERENCE(Table);
703 DO_STRUCT_DIFFERENCE(UIReset);
704 DO_STRUCT_DIFFERENCE(Text);
705 DO_STRUCT_DIFFERENCE(List);
706 DO_STRUCT_DIFFERENCE(Quotes);
707 DO_STRUCT_DIFFERENCE(SVGReset);
708 DO_STRUCT_DIFFERENCE(SVG);
709 DO_STRUCT_DIFFERENCE(Position);
710 DO_STRUCT_DIFFERENCE(Font);
711 DO_STRUCT_DIFFERENCE(Margin);
712 DO_STRUCT_DIFFERENCE(Padding);
713 DO_STRUCT_DIFFERENCE(Border);
714 DO_STRUCT_DIFFERENCE(TextReset);
715 DO_STRUCT_DIFFERENCE(Background);
716 DO_STRUCT_DIFFERENCE(Color);
718 #undef DO_STRUCT_DIFFERENCE
720 MOZ_ASSERT(styleStructCount == nsStyleStructID_Length,
721 "missing a call to DO_STRUCT_DIFFERENCE");
723 // Note that we do not check whether this->RelevantLinkVisited() !=
724 // aOther->RelevantLinkVisited(); we don't need to since
725 // nsCSSFrameConstructor::DoContentStateChanged always adds
726 // nsChangeHint_RepaintFrame for NS_EVENT_STATE_VISITED changes (and
727 // needs to, since HasStateDependentStyle probably doesn't work right
728 // for NS_EVENT_STATE_VISITED). Hopefully this doesn't actually
729 // expose whether links are visited to performance tests since all
730 // link coloring happens asynchronously at a time when it's hard for
731 // the page to measure.
732 // However, we do need to compute the larger of the changes that can
733 // happen depending on whether the link is visited or unvisited, since
734 // doing only the one that's currently appropriate would expose which
735 // links are in history to easy performance measurement. Therefore,
736 // here, we add nsChangeHint_RepaintFrame hints (the maximum for
737 // things that can depend on :visited) for the properties on which we
738 // call GetVisitedDependentColor.
739 nsStyleContext *thisVis = GetStyleIfVisited(),
740 *otherVis = aOther->GetStyleIfVisited();
741 if (!thisVis != !otherVis) {
742 // One style context has a style-if-visited and the other doesn't.
743 // Presume a difference.
744 NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
745 } else if (thisVis && !NS_IsHintSubset(nsChangeHint_RepaintFrame, hint)) {
746 // Both style contexts have a style-if-visited.
747 bool change = false;
749 // NB: Calling Peek on |this|, not |thisVis|, since callers may look
750 // at a struct on |this| without looking at the same struct on
751 // |thisVis| (including this function if we skip one of these checks
752 // due to change being true already or due to the old style context
753 // not having a style-if-visited), but not the other way around.
754 if (PeekStyleColor()) {
755 if (thisVis->StyleColor()->mColor !=
756 otherVis->StyleColor()->mColor) {
757 change = true;
761 // NB: Calling Peek on |this|, not |thisVis| (see above).
762 if (!change && PeekStyleBackground()) {
763 if (thisVis->StyleBackground()->mBackgroundColor !=
764 otherVis->StyleBackground()->mBackgroundColor) {
765 change = true;
769 // NB: Calling Peek on |this|, not |thisVis| (see above).
770 if (!change && PeekStyleBorder()) {
771 const nsStyleBorder *thisVisBorder = thisVis->StyleBorder();
772 const nsStyleBorder *otherVisBorder = otherVis->StyleBorder();
773 NS_FOR_CSS_SIDES(side) {
774 bool thisFG, otherFG;
775 nscolor thisColor, otherColor;
776 thisVisBorder->GetBorderColor(side, thisColor, thisFG);
777 otherVisBorder->GetBorderColor(side, otherColor, otherFG);
778 if (thisFG != otherFG || (!thisFG && thisColor != otherColor)) {
779 change = true;
780 break;
785 // NB: Calling Peek on |this|, not |thisVis| (see above).
786 if (!change && PeekStyleOutline()) {
787 const nsStyleOutline *thisVisOutline = thisVis->StyleOutline();
788 const nsStyleOutline *otherVisOutline = otherVis->StyleOutline();
789 bool haveColor;
790 nscolor thisColor, otherColor;
791 if (thisVisOutline->GetOutlineInitialColor() !=
792 otherVisOutline->GetOutlineInitialColor() ||
793 (haveColor = thisVisOutline->GetOutlineColor(thisColor)) !=
794 otherVisOutline->GetOutlineColor(otherColor) ||
795 (haveColor && thisColor != otherColor)) {
796 change = true;
800 // NB: Calling Peek on |this|, not |thisVis| (see above).
801 if (!change && PeekStyleColumn()) {
802 const nsStyleColumn *thisVisColumn = thisVis->StyleColumn();
803 const nsStyleColumn *otherVisColumn = otherVis->StyleColumn();
804 if (thisVisColumn->mColumnRuleColor != otherVisColumn->mColumnRuleColor ||
805 thisVisColumn->mColumnRuleColorIsForeground !=
806 otherVisColumn->mColumnRuleColorIsForeground) {
807 change = true;
811 // NB: Calling Peek on |this|, not |thisVis| (see above).
812 if (!change && PeekStyleTextReset()) {
813 const nsStyleTextReset *thisVisTextReset = thisVis->StyleTextReset();
814 const nsStyleTextReset *otherVisTextReset = otherVis->StyleTextReset();
815 nscolor thisVisDecColor, otherVisDecColor;
816 bool thisVisDecColorIsFG, otherVisDecColorIsFG;
817 thisVisTextReset->GetDecorationColor(thisVisDecColor,
818 thisVisDecColorIsFG);
819 otherVisTextReset->GetDecorationColor(otherVisDecColor,
820 otherVisDecColorIsFG);
821 if (thisVisDecColorIsFG != otherVisDecColorIsFG ||
822 (!thisVisDecColorIsFG && thisVisDecColor != otherVisDecColor)) {
823 change = true;
827 // NB: Calling Peek on |this|, not |thisVis| (see above).
828 if (!change && PeekStyleSVG()) {
829 const nsStyleSVG *thisVisSVG = thisVis->StyleSVG();
830 const nsStyleSVG *otherVisSVG = otherVis->StyleSVG();
831 if (thisVisSVG->mFill != otherVisSVG->mFill ||
832 thisVisSVG->mStroke != otherVisSVG->mStroke) {
833 change = true;
837 if (change) {
838 NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
842 return NS_SubtractHint(hint, nsChangeHint_NeutralChange);
845 void
846 nsStyleContext::Mark()
848 // Mark our rule node.
849 mRuleNode->Mark();
851 // Mark our children (i.e., tell them to mark their rule nodes, etc.).
852 if (mChild) {
853 nsStyleContext* child = mChild;
854 do {
855 child->Mark();
856 child = child->mNextSibling;
857 } while (mChild != child);
860 if (mEmptyChild) {
861 nsStyleContext* child = mEmptyChild;
862 do {
863 child->Mark();
864 child = child->mNextSibling;
865 } while (mEmptyChild != child);
869 #ifdef DEBUG
870 void nsStyleContext::List(FILE* out, int32_t aIndent, bool aListDescendants)
872 nsAutoCString str;
873 // Indent
874 int32_t ix;
875 for (ix = aIndent; --ix >= 0; ) {
876 str.AppendLiteral(" ");
878 str.Append(nsPrintfCString("%p(%d) parent=%p ",
879 (void*)this, mRefCnt, (void *)mParent));
880 if (mPseudoTag) {
881 nsAutoString buffer;
882 mPseudoTag->ToString(buffer);
883 AppendUTF16toUTF8(buffer, str);
884 str.Append(' ');
887 if (mRuleNode) {
888 fprintf_stderr(out, "%s{\n", str.get());
889 str.Truncate();
890 nsRuleNode* ruleNode = mRuleNode;
891 while (ruleNode) {
892 nsIStyleRule *styleRule = ruleNode->GetRule();
893 if (styleRule) {
894 styleRule->List(out, aIndent + 1);
896 ruleNode = ruleNode->GetParent();
898 for (ix = aIndent; --ix >= 0; ) {
899 str.AppendLiteral(" ");
901 fprintf_stderr(out, "%s}\n", str.get());
903 else {
904 fprintf_stderr(out, "%s{}\n", str.get());
907 if (aListDescendants) {
908 if (nullptr != mChild) {
909 nsStyleContext* child = mChild;
910 do {
911 child->List(out, aIndent + 1, aListDescendants);
912 child = child->mNextSibling;
913 } while (mChild != child);
915 if (nullptr != mEmptyChild) {
916 nsStyleContext* child = mEmptyChild;
917 do {
918 child->List(out, aIndent + 1, aListDescendants);
919 child = child->mNextSibling;
920 } while (mEmptyChild != child);
924 #endif
926 // Overloaded new operator. Initializes the memory to 0 and relies on an arena
927 // (which comes from the presShell) to perform the allocation.
928 void*
929 nsStyleContext::operator new(size_t sz, nsPresContext* aPresContext) CPP_THROW_NEW
931 // Check the recycle list first.
932 return aPresContext->PresShell()->AllocateByObjectID(nsPresArena::nsStyleContext_id, sz);
935 // Overridden to prevent the global delete from being called, since the memory
936 // came out of an nsIArena instead of the global delete operator's heap.
937 void
938 nsStyleContext::Destroy()
940 // Get the pres context from our rule node.
941 nsRefPtr<nsPresContext> presContext = mRuleNode->PresContext();
943 // Call our destructor.
944 this->~nsStyleContext();
946 // Don't let the memory be freed, since it will be recycled
947 // instead. Don't call the global operator delete.
948 presContext->PresShell()->FreeByObjectID(nsPresArena::nsStyleContext_id, this);
951 already_AddRefed<nsStyleContext>
952 NS_NewStyleContext(nsStyleContext* aParentContext,
953 nsIAtom* aPseudoTag,
954 nsCSSPseudoElements::Type aPseudoType,
955 nsRuleNode* aRuleNode,
956 bool aSkipParentDisplayBasedStyleFixup)
958 nsRefPtr<nsStyleContext> context =
959 new (aRuleNode->PresContext())
960 nsStyleContext(aParentContext, aPseudoTag, aPseudoType, aRuleNode,
961 aSkipParentDisplayBasedStyleFixup);
962 return context.forget();
965 static inline void
966 ExtractAnimationValue(nsCSSProperty aProperty,
967 nsStyleContext* aStyleContext,
968 StyleAnimationValue& aResult)
970 DebugOnly<bool> success =
971 StyleAnimationValue::ExtractComputedValue(aProperty, aStyleContext,
972 aResult);
973 NS_ABORT_IF_FALSE(success,
974 "aProperty must be extractable by StyleAnimationValue");
977 static nscolor
978 ExtractColor(nsCSSProperty aProperty,
979 nsStyleContext *aStyleContext)
981 StyleAnimationValue val;
982 ExtractAnimationValue(aProperty, aStyleContext, val);
983 return val.GetColorValue();
986 static nscolor
987 ExtractColorLenient(nsCSSProperty aProperty,
988 nsStyleContext *aStyleContext)
990 StyleAnimationValue val;
991 ExtractAnimationValue(aProperty, aStyleContext, val);
992 if (val.GetUnit() == StyleAnimationValue::eUnit_Color) {
993 return val.GetColorValue();
995 return NS_RGBA(0, 0, 0, 0);
998 struct ColorIndexSet {
999 uint8_t colorIndex, alphaIndex;
1002 static const ColorIndexSet gVisitedIndices[2] = { { 0, 0 }, { 1, 0 } };
1004 nscolor
1005 nsStyleContext::GetVisitedDependentColor(nsCSSProperty aProperty)
1007 NS_ASSERTION(aProperty == eCSSProperty_color ||
1008 aProperty == eCSSProperty_background_color ||
1009 aProperty == eCSSProperty_border_top_color ||
1010 aProperty == eCSSProperty_border_right_color_value ||
1011 aProperty == eCSSProperty_border_bottom_color ||
1012 aProperty == eCSSProperty_border_left_color_value ||
1013 aProperty == eCSSProperty_outline_color ||
1014 aProperty == eCSSProperty__moz_column_rule_color ||
1015 aProperty == eCSSProperty_text_decoration_color ||
1016 aProperty == eCSSProperty_fill ||
1017 aProperty == eCSSProperty_stroke,
1018 "we need to add to nsStyleContext::CalcStyleDifference");
1020 bool isPaintProperty = aProperty == eCSSProperty_fill ||
1021 aProperty == eCSSProperty_stroke;
1023 nscolor colors[2];
1024 colors[0] = isPaintProperty ? ExtractColorLenient(aProperty, this)
1025 : ExtractColor(aProperty, this);
1027 nsStyleContext *visitedStyle = this->GetStyleIfVisited();
1028 if (!visitedStyle) {
1029 return colors[0];
1032 colors[1] = isPaintProperty ? ExtractColorLenient(aProperty, visitedStyle)
1033 : ExtractColor(aProperty, visitedStyle);
1035 return nsStyleContext::CombineVisitedColors(colors,
1036 this->RelevantLinkVisited());
1039 /* static */ nscolor
1040 nsStyleContext::CombineVisitedColors(nscolor *aColors, bool aLinkIsVisited)
1042 if (NS_GET_A(aColors[1]) == 0) {
1043 // If the style-if-visited is transparent, then just use the
1044 // unvisited style rather than using the (meaningless) color
1045 // components of the visited style along with a potentially
1046 // non-transparent alpha value.
1047 aLinkIsVisited = false;
1050 // NOTE: We want this code to have as little timing dependence as
1051 // possible on whether this->RelevantLinkVisited() is true.
1052 const ColorIndexSet &set =
1053 gVisitedIndices[aLinkIsVisited ? 1 : 0];
1055 nscolor colorColor = aColors[set.colorIndex];
1056 nscolor alphaColor = aColors[set.alphaIndex];
1057 return NS_RGBA(NS_GET_R(colorColor), NS_GET_G(colorColor),
1058 NS_GET_B(colorColor), NS_GET_A(alphaColor));
1061 #ifdef DEBUG
1062 /* static */ void
1063 nsStyleContext::AssertStyleStructMaxDifferenceValid()
1065 #define STYLE_STRUCT(name, checkdata_cb) \
1066 MOZ_ASSERT(NS_IsHintSubset(nsStyle##name::MaxDifferenceNeverInherited(), \
1067 nsStyle##name::MaxDifference()));
1068 #include "nsStyleStructList.h"
1069 #undef STYLE_STRUCT
1072 /* static */ const char*
1073 nsStyleContext::StructName(nsStyleStructID aSID)
1075 switch (aSID) {
1076 #define STYLE_STRUCT(name_, checkdata_cb) \
1077 case eStyleStruct_##name_: \
1078 return #name_;
1079 #include "nsStyleStructList.h"
1080 #undef STYLE_STRUCT
1081 default:
1082 return "Unknown";
1086 /* static */ bool
1087 nsStyleContext::LookupStruct(const nsACString& aName, nsStyleStructID& aResult)
1089 if (false)
1091 #define STYLE_STRUCT(name_, checkdata_cb_) \
1092 else if (aName.EqualsLiteral(#name_)) \
1093 aResult = eStyleStruct_##name_;
1094 #include "nsStyleStructList.h"
1095 #undef STYLE_STRUCT
1096 else
1097 return false;
1098 return true;
1100 #endif
1102 bool
1103 nsStyleContext::HasSameCachedStyleData(nsStyleContext* aOther,
1104 nsStyleStructID aSID)
1106 return GetCachedStyleData(aSID) == aOther->GetCachedStyleData(aSID);
1109 void
1110 nsStyleContext::SwapStyleData(nsStyleContext* aNewContext, uint32_t aStructs)
1112 static_assert(nsStyleStructID_Length <= 32, "aStructs is not big enough");
1114 for (nsStyleStructID i = nsStyleStructID_Inherited_Start;
1115 i < nsStyleStructID_Inherited_Start + nsStyleStructID_Inherited_Count;
1116 i = nsStyleStructID(i + 1)) {
1117 uint32_t bit = nsCachedStyleData::GetBitForSID(i);
1118 if (!(aStructs & bit)) {
1119 continue;
1121 void*& thisData = mCachedInheritedData.mStyleStructs[i];
1122 void*& otherData = aNewContext->mCachedInheritedData.mStyleStructs[i];
1123 if (mBits & bit) {
1124 if (thisData == otherData) {
1125 thisData = nullptr;
1127 } else if (!(aNewContext->mBits & bit) && thisData && otherData) {
1128 std::swap(thisData, otherData);
1132 for (nsStyleStructID i = nsStyleStructID_Reset_Start;
1133 i < nsStyleStructID_Reset_Start + nsStyleStructID_Reset_Count;
1134 i = nsStyleStructID(i + 1)) {
1135 uint32_t bit = nsCachedStyleData::GetBitForSID(i);
1136 if (!(aStructs & bit)) {
1137 continue;
1139 if (!mCachedResetData) {
1140 mCachedResetData = new (mRuleNode->PresContext()) nsResetStyleData;
1142 if (!aNewContext->mCachedResetData) {
1143 aNewContext->mCachedResetData =
1144 new (mRuleNode->PresContext()) nsResetStyleData;
1146 void*& thisData = mCachedResetData->mStyleStructs[i];
1147 void*& otherData = aNewContext->mCachedResetData->mStyleStructs[i];
1148 if (mBits & bit) {
1149 if (thisData == otherData) {
1150 thisData = nullptr;
1152 } else if (!(aNewContext->mBits & bit) && thisData && otherData) {
1153 std::swap(thisData, otherData);
1158 void
1159 nsStyleContext::ClearCachedInheritedStyleDataOnDescendants(uint32_t aStructs)
1161 if (mChild) {
1162 nsStyleContext* child = mChild;
1163 do {
1164 child->DoClearCachedInheritedStyleDataOnDescendants(aStructs);
1165 child = child->mNextSibling;
1166 } while (mChild != child);
1168 if (mEmptyChild) {
1169 nsStyleContext* child = mEmptyChild;
1170 do {
1171 child->DoClearCachedInheritedStyleDataOnDescendants(aStructs);
1172 child = child->mNextSibling;
1173 } while (mEmptyChild != child);
1177 void
1178 nsStyleContext::DoClearCachedInheritedStyleDataOnDescendants(uint32_t aStructs)
1180 NS_ASSERTION(mFrameRefCnt == 0, "frame still referencing style context");
1181 for (nsStyleStructID i = nsStyleStructID_Inherited_Start;
1182 i < nsStyleStructID_Inherited_Start + nsStyleStructID_Inherited_Count;
1183 i = nsStyleStructID(i + 1)) {
1184 uint32_t bit = nsCachedStyleData::GetBitForSID(i);
1185 if (aStructs & bit) {
1186 if (!(mBits & bit) && mCachedInheritedData.mStyleStructs[i]) {
1187 aStructs &= ~bit;
1188 } else {
1189 mCachedInheritedData.mStyleStructs[i] = nullptr;
1194 if (mCachedResetData) {
1195 for (nsStyleStructID i = nsStyleStructID_Reset_Start;
1196 i < nsStyleStructID_Reset_Start + nsStyleStructID_Reset_Count;
1197 i = nsStyleStructID(i + 1)) {
1198 uint32_t bit = nsCachedStyleData::GetBitForSID(i);
1199 if (aStructs & bit) {
1200 if (!(mBits & bit) && mCachedResetData->mStyleStructs[i]) {
1201 aStructs &= ~bit;
1202 } else {
1203 mCachedResetData->mStyleStructs[i] = nullptr;
1209 if (aStructs == 0) {
1210 return;
1213 ClearCachedInheritedStyleDataOnDescendants(aStructs);
1216 #ifdef RESTYLE_LOGGING
1217 nsCString
1218 nsStyleContext::GetCachedStyleDataAsString(uint32_t aStructs)
1220 nsCString structs;
1221 for (nsStyleStructID i = nsStyleStructID(0);
1222 i < nsStyleStructID_Length;
1223 i = nsStyleStructID(i + 1)) {
1224 if (aStructs & nsCachedStyleData::GetBitForSID(i)) {
1225 const void* data = GetCachedStyleData(i);
1226 if (!structs.IsEmpty()) {
1227 structs.Append(' ');
1229 structs.AppendPrintf("%s=%p", StructName(i), data);
1230 if (HasCachedInheritedStyleData(i)) {
1231 structs.AppendLiteral("(dependent)");
1232 } else {
1233 structs.AppendLiteral("(owned)");
1237 return structs;
1240 int32_t&
1241 nsStyleContext::LoggingDepth()
1243 static int32_t depth = 0;
1244 return depth;
1247 void
1248 nsStyleContext::LogStyleContextTree(int32_t aLoggingDepth, uint32_t aStructs)
1250 LoggingDepth() = aLoggingDepth;
1251 LogStyleContextTree(true, aStructs);
1254 void
1255 nsStyleContext::LogStyleContextTree(bool aFirst, uint32_t aStructs)
1257 nsCString structs = GetCachedStyleDataAsString(aStructs);
1258 if (!structs.IsEmpty()) {
1259 structs.Append(' ');
1262 nsCString pseudo;
1263 if (mPseudoTag) {
1264 nsAutoString pseudoTag;
1265 mPseudoTag->ToString(pseudoTag);
1266 AppendUTF16toUTF8(pseudoTag, pseudo);
1267 pseudo.Append(' ');
1270 nsCString flags;
1271 if (IsStyleIfVisited()) {
1272 flags.AppendLiteral("IS_STYLE_IF_VISITED ");
1274 if (UsesGrandancestorStyle()) {
1275 flags.AppendLiteral("USES_GRANDANCESTOR_STYLE ");
1277 if (IsShared()) {
1278 flags.AppendLiteral("IS_SHARED ");
1281 nsCString parent;
1282 if (aFirst) {
1283 parent.AppendPrintf("parent=%p ", mParent);
1286 LOG_RESTYLE("%p(%d) %s%s%s%s",
1287 this, mRefCnt,
1288 structs.get(), pseudo.get(), flags.get(), parent.get());
1290 LOG_RESTYLE_INDENT();
1292 if (nullptr != mChild) {
1293 nsStyleContext* child = mChild;
1294 do {
1295 child->LogStyleContextTree(false, aStructs);
1296 child = child->mNextSibling;
1297 } while (mChild != child);
1299 if (nullptr != mEmptyChild) {
1300 nsStyleContext* child = mEmptyChild;
1301 do {
1302 child->LogStyleContextTree(false, aStructs);
1303 child = child->mNextSibling;
1304 } while (mEmptyChild != child);
1307 #endif