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"
13 #include "nsPresContext.h"
14 #include "nsIStyleRule.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"
26 // #define NOISY_DEBUG
29 using namespace mozilla
;
31 //----------------------------------------------------------------------
34 nsStyleContext::nsStyleContext(nsStyleContext
* aParent
,
36 nsCSSPseudoElements::Type aPseudoType
,
37 nsRuleNode
* aRuleNode
,
38 bool aSkipParentDisplayBasedStyleFixup
)
42 mPseudoTag(aPseudoTag
),
44 mCachedResetData(nullptr),
45 mBits(((uint64_t)aPseudoType
) << NS_STYLE_CONTEXT_TYPE_SHIFT
),
48 // This check has to be done "backward", because if it were written the
49 // more natural way it wouldn't fail even when it needed to.
50 static_assert((UINT64_MAX
>> NS_STYLE_CONTEXT_TYPE_SHIFT
) >=
51 nsCSSPseudoElements::ePseudo_MAX
,
52 "pseudo element bits no longer fit in a uint64_t");
53 MOZ_ASSERT(aRuleNode
);
59 mParent
->AddChild(this);
61 nsRuleNode
*r1
= mParent
->RuleNode(), *r2
= aRuleNode
;
62 while (r1
->GetParent())
64 while (r2
->GetParent())
66 NS_ASSERTION(r1
== r2
, "must be in the same rule tree as parent");
71 mRuleNode
->SetUsedDirectly(); // before ApplyStyleFixups()!
73 ApplyStyleFixups(aSkipParentDisplayBasedStyleFixup
);
75 #define eStyleStruct_LastItem (nsStyleStructID_Length - 1)
76 NS_ASSERTION(NS_STYLE_INHERIT_MASK
& NS_STYLE_INHERIT_BIT(LastItem
),
77 "NS_STYLE_INHERIT_MASK must be bigger, and other bits shifted");
78 #undef eStyleStruct_LastItem
81 nsStyleContext::~nsStyleContext()
83 NS_ASSERTION((nullptr == mChild
) && (nullptr == mEmptyChild
), "destructing context with children");
85 nsPresContext
*presContext
= mRuleNode
->PresContext();
89 presContext
->PresShell()->StyleSet()->
90 NotifyStyleContextDestroyed(presContext
, this);
93 mParent
->RemoveChild(this);
97 // Free up our data structs.
98 mCachedInheritedData
.DestroyStructs(mBits
, presContext
);
99 if (mCachedResetData
) {
100 mCachedResetData
->Destroy(mBits
, presContext
);
104 void nsStyleContext::AddChild(nsStyleContext
* aChild
)
106 NS_ASSERTION(aChild
->mPrevSibling
== aChild
&&
107 aChild
->mNextSibling
== aChild
,
108 "child already in a child list");
110 nsStyleContext
**listPtr
= aChild
->mRuleNode
->IsRoot() ? &mEmptyChild
: &mChild
;
111 // Explicitly dereference listPtr so that compiler doesn't have to know that mNextSibling
112 // etc. don't alias with what ever listPtr points at.
113 nsStyleContext
*list
= *listPtr
;
115 // Insert at the beginning of the list. See also FindChildWithRules.
117 // Link into existing elements, if there are any.
118 aChild
->mNextSibling
= list
;
119 aChild
->mPrevSibling
= list
->mPrevSibling
;
120 list
->mPrevSibling
->mNextSibling
= aChild
;
121 list
->mPrevSibling
= aChild
;
126 void nsStyleContext::RemoveChild(nsStyleContext
* aChild
)
128 NS_PRECONDITION(nullptr != aChild
&& this == aChild
->mParent
, "bad argument");
130 nsStyleContext
**list
= aChild
->mRuleNode
->IsRoot() ? &mEmptyChild
: &mChild
;
132 if (aChild
->mPrevSibling
!= aChild
) { // has siblings
133 if ((*list
) == aChild
) {
134 (*list
) = (*list
)->mNextSibling
;
138 NS_ASSERTION((*list
) == aChild
, "bad sibling pointers");
142 aChild
->mPrevSibling
->mNextSibling
= aChild
->mNextSibling
;
143 aChild
->mNextSibling
->mPrevSibling
= aChild
->mPrevSibling
;
144 aChild
->mNextSibling
= aChild
;
145 aChild
->mPrevSibling
= aChild
;
148 already_AddRefed
<nsStyleContext
>
149 nsStyleContext::FindChildWithRules(const nsIAtom
* aPseudoTag
,
150 nsRuleNode
* aRuleNode
,
151 nsRuleNode
* aRulesIfVisited
,
152 bool aRelevantLinkVisited
)
154 NS_ABORT_IF_FALSE(aRulesIfVisited
|| !aRelevantLinkVisited
,
155 "aRelevantLinkVisited should only be set when we have a separate style");
156 uint32_t threshold
= 10; // The # of siblings we're willing to examine
157 // before just giving this whole thing up.
159 nsRefPtr
<nsStyleContext
> result
;
160 nsStyleContext
*list
= aRuleNode
->IsRoot() ? mEmptyChild
: mChild
;
163 nsStyleContext
*child
= list
;
165 if (child
->mRuleNode
== aRuleNode
&&
166 child
->mPseudoTag
== aPseudoTag
&&
167 !child
->IsStyleIfVisited() &&
168 child
->RelevantLinkVisited() == aRelevantLinkVisited
) {
170 if (aRulesIfVisited
) {
171 match
= child
->GetStyleIfVisited() &&
172 child
->GetStyleIfVisited()->mRuleNode
== aRulesIfVisited
;
174 match
= !child
->GetStyleIfVisited();
181 child
= child
->mNextSibling
;
185 } while (child
!= list
);
189 if (result
!= list
) {
190 // Move result to the front of the list.
196 return result
.forget();
199 const void* nsStyleContext::GetCachedStyleData(nsStyleStructID aSID
)
201 const void* cachedData
;
202 if (nsCachedStyleData::IsReset(aSID
)) {
203 if (mCachedResetData
) {
204 cachedData
= mCachedResetData
->mStyleStructs
[aSID
];
206 cachedData
= nullptr;
209 cachedData
= mCachedInheritedData
.mStyleStructs
[aSID
];
214 const void* nsStyleContext::StyleData(nsStyleStructID aSID
)
216 const void* cachedData
= GetCachedStyleData(aSID
);
218 return cachedData
; // We have computed data stored on this node in the context tree.
219 return mRuleNode
->GetStyleData(aSID
, this, true); // Our rule node will take care of it for us.
222 // This is an evil evil function, since it forces you to alloc your own separate copy of
223 // style data! Do not use this function unless you absolutely have to! You should avoid
224 // this at all costs! -dwh
226 nsStyleContext::GetUniqueStyleData(const nsStyleStructID
& aSID
)
228 // If we already own the struct and no kids could depend on it, then
229 // just return it. (We leak in this case if there are kids -- and this
230 // function really shouldn't be called for style contexts that could
231 // have kids depending on the data. ClearStyleData would be OK, but
232 // this test for no mChild or mEmptyChild doesn't catch that case.)
233 const void *current
= StyleData(aSID
);
234 if (!mChild
&& !mEmptyChild
&&
235 !(mBits
& nsCachedStyleData::GetBitForSID(aSID
)) &&
236 GetCachedStyleData(aSID
))
237 return const_cast<void*>(current
);
240 nsPresContext
*presContext
= PresContext();
243 #define UNIQUE_CASE(c_) \
244 case eStyleStruct_##c_: \
245 result = new (presContext) nsStyle##c_( \
246 * static_cast<const nsStyle##c_ *>(current)); \
250 UNIQUE_CASE(Background
)
252 UNIQUE_CASE(TextReset
)
257 NS_ERROR("Struct type not supported. Please find another way to do this if you can!");
261 SetStyle(aSID
, result
);
262 mBits
&= ~static_cast<uint64_t>(nsCachedStyleData::GetBitForSID(aSID
));
268 nsStyleContext::SetStyle(nsStyleStructID aSID
, void* aStruct
)
270 // This method should only be called from nsRuleNode! It is not a public
273 NS_ASSERTION(aSID
>= 0 && aSID
< nsStyleStructID_Length
, "out of bounds");
275 // NOTE: nsCachedStyleData::GetStyleData works roughly the same way.
276 // See the comments there (in nsRuleNode.h) for more details about
277 // what this is doing and why.
280 if (nsCachedStyleData::IsReset(aSID
)) {
281 if (!mCachedResetData
) {
282 mCachedResetData
= new (mRuleNode
->PresContext()) nsResetStyleData
;
284 dataSlot
= &mCachedResetData
->mStyleStructs
[aSID
];
286 dataSlot
= &mCachedInheritedData
.mStyleStructs
[aSID
];
288 NS_ASSERTION(!*dataSlot
|| (mBits
& nsCachedStyleData::GetBitForSID(aSID
)),
289 "Going to leak style data");
294 nsStyleContext::ApplyStyleFixups(bool aSkipParentDisplayBasedStyleFixup
)
296 // See if we have any text decorations.
297 // First see if our parent has text decorations. If our parent does, then we inherit the bit.
298 if (mParent
&& mParent
->HasTextDecorationLines()) {
299 mBits
|= NS_STYLE_HAS_TEXT_DECORATION_LINES
;
301 // We might have defined a decoration.
302 const nsStyleTextReset
* text
= StyleTextReset();
303 uint8_t decorationLine
= text
->mTextDecorationLine
;
304 if (decorationLine
!= NS_STYLE_TEXT_DECORATION_LINE_NONE
&&
305 decorationLine
!= NS_STYLE_TEXT_DECORATION_LINE_OVERRIDE_ALL
) {
306 mBits
|= NS_STYLE_HAS_TEXT_DECORATION_LINES
;
310 if ((mParent
&& mParent
->HasPseudoElementData()) || mPseudoTag
) {
311 mBits
|= NS_STYLE_HAS_PSEUDO_ELEMENT_DATA
;
315 const nsStyleDisplay
* disp
= StyleDisplay();
316 if (disp
->mDisplay
== NS_STYLE_DISPLAY_TABLE
) {
317 // -moz-center and -moz-right are used for HTML's alignment
318 // This is covering the <div align="right"><table>...</table></div> case.
319 // In this case, we don't want to inherit the text alignment into the table.
320 const nsStyleText
* text
= StyleText();
322 if (text
->mTextAlign
== NS_STYLE_TEXT_ALIGN_MOZ_CENTER
||
323 text
->mTextAlign
== NS_STYLE_TEXT_ALIGN_MOZ_RIGHT
)
325 nsStyleText
* uniqueText
= (nsStyleText
*)GetUniqueStyleData(eStyleStruct_Text
);
326 uniqueText
->mTextAlign
= NS_STYLE_TEXT_ALIGN_DEFAULT
;
330 // CSS2.1 section 9.2.4 specifies fixups for the 'display' property of
331 // the root element. We can't implement them in nsRuleNode because we
332 // don't want to store all display structs that aren't 'block',
333 // 'inline', or 'table' in the style context tree on the off chance
334 // that the root element has its style reresolved later. So do them
335 // here if needed, by changing the style data, so that other code
336 // doesn't get confused by looking at the style data.
338 uint8_t displayVal
= disp
->mDisplay
;
339 nsRuleNode::EnsureBlockDisplay(displayVal
, true);
340 if (displayVal
!= disp
->mDisplay
) {
341 nsStyleDisplay
*mutable_display
=
342 static_cast<nsStyleDisplay
*>(GetUniqueStyleData(eStyleStruct_Display
));
344 // If we're in this code, then mOriginalDisplay doesn't matter
345 // for purposes of the cascade (because this nsStyleDisplay
346 // isn't living in the ruletree anyway), and for determining
347 // hypothetical boxes it's better to have mOriginalDisplay
348 // matching mDisplay here.
349 mutable_display
->mOriginalDisplay
= mutable_display
->mDisplay
=
354 // Adjust the "display" values of flex and grid items (but not for raw text,
355 // placeholders, or table-parts). CSS3 Flexbox section 4 says:
356 // # The computed 'display' of a flex item is determined
357 // # by applying the table in CSS 2.1 Chapter 9.7.
358 // ...which converts inline-level elements to their block-level equivalents.
359 // Any direct children of elements with Ruby display values which are
360 // block-level are converted to their inline-level equivalents.
361 if (!aSkipParentDisplayBasedStyleFixup
&& mParent
) {
362 const nsStyleDisplay
* parentDisp
= mParent
->StyleDisplay();
363 if (parentDisp
->IsFlexOrGridDisplayType() &&
364 GetPseudo() != nsCSSAnonBoxes::mozNonElement
) {
365 uint8_t displayVal
= disp
->mDisplay
;
367 // NOTE: This list needs to be kept in sync with
368 // nsCSSFrameConstructor.cpp's "sDisplayData" array -- specifically,
369 // this should be the list of display-values that have
370 // FCDATA_DESIRED_PARENT_TYPE_TO_BITS specified in that array.
371 if (NS_STYLE_DISPLAY_TABLE_CAPTION
!= displayVal
&&
372 NS_STYLE_DISPLAY_TABLE_ROW_GROUP
!= displayVal
&&
373 NS_STYLE_DISPLAY_TABLE_HEADER_GROUP
!= displayVal
&&
374 NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP
!= displayVal
&&
375 NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP
!= displayVal
&&
376 NS_STYLE_DISPLAY_TABLE_COLUMN
!= displayVal
&&
377 NS_STYLE_DISPLAY_TABLE_ROW
!= displayVal
&&
378 NS_STYLE_DISPLAY_TABLE_CELL
!= displayVal
) {
380 // NOTE: Technically, we shouldn't modify the 'display' value of
381 // positioned elements, since they aren't flex/grid items. However,
382 // we don't need to worry about checking for that, because if we're
383 // positioned, we'll have already been through a call to
384 // EnsureBlockDisplay() in nsRuleNode, so this call here won't change
385 // anything. So we're OK.
386 nsRuleNode::EnsureBlockDisplay(displayVal
);
387 if (displayVal
!= disp
->mDisplay
) {
388 NS_ASSERTION(!disp
->IsAbsolutelyPositionedStyle(),
389 "We shouldn't be changing the display value of "
390 "positioned content (and we should have already "
391 "converted its display value to be block-level...)");
392 nsStyleDisplay
*mutable_display
=
393 static_cast<nsStyleDisplay
*>(GetUniqueStyleData(eStyleStruct_Display
));
394 mutable_display
->mDisplay
= displayVal
;
397 } else if (parentDisp
->IsRubyDisplayType()) {
398 uint8_t displayVal
= disp
->mDisplay
;
399 nsRuleNode::EnsureInlineDisplay(displayVal
);
400 // The display change should only occur for "in-flow" children
401 if (displayVal
!= disp
->mDisplay
&&
402 !disp
->IsOutOfFlowStyle()) {
403 nsStyleDisplay
*mutable_display
=
404 static_cast<nsStyleDisplay
*>(GetUniqueStyleData(eStyleStruct_Display
));
405 mutable_display
->mDisplay
= displayVal
;
410 // Compute User Interface style, to trigger loads of cursors
411 StyleUserInterface();
415 nsStyleContext::CalcStyleDifference(nsStyleContext
* aOther
,
416 nsChangeHint aParentHintsNotHandledForDescendants
)
418 PROFILER_LABEL("nsStyleContext", "CalcStyleDifference",
419 js::ProfileEntry::Category::CSS
);
421 NS_ABORT_IF_FALSE(NS_IsHintSubset(aParentHintsNotHandledForDescendants
,
422 nsChangeHint_Hints_NotHandledForDescendants
),
423 "caller is passing inherited hints, but shouldn't be");
425 nsChangeHint hint
= NS_STYLE_HINT_NONE
;
426 NS_ENSURE_TRUE(aOther
, hint
);
427 // We must always ensure that we populate the structs on the new style
428 // context that are filled in on the old context, so that if we get
429 // two style changes in succession, the second of which causes a real
430 // style change, the PeekStyleData doesn't return null (implying that
431 // nobody ever looked at that struct's data). In other words, we
432 // can't skip later structs if we get a big change up front, because
433 // we could later get a small change in one of those structs that we
434 // don't want to miss.
436 // If our rule nodes are the same, then any differences in style data
437 // are already accounted for by differences on ancestors. We know
438 // this because CalcStyleDifference is always called on two style
439 // contexts that point to the same element, so we know that our
440 // position in the style context tree is the same and our position in
441 // the rule node tree is also the same.
442 // However, if there were noninherited style change hints on the
443 // parent, we might produce these same noninherited hints on this
444 // style context's frame due to 'inherit' values, so we do need to
446 // (Things like 'em' units are handled by the change hint produced
447 // by font-size changing, so we don't need to worry about them like
448 // we worry about 'inherit' values.)
449 bool compare
= mRuleNode
!= aOther
->mRuleNode
;
451 // If we had any change in variable values, then we'll need to examine
452 // all of the other style structs too, even if the new style context has
453 // the same rule node as the old one.
454 const nsStyleVariables
* thisVariables
= PeekStyleVariables();
456 const nsStyleVariables
* otherVariables
= aOther
->StyleVariables();
457 if (thisVariables
->mVariables
!= otherVariables
->mVariables
) {
462 DebugOnly
<int> styleStructCount
= 1; // count Variables already
464 #define DO_STRUCT_DIFFERENCE(struct_) \
466 const nsStyle##struct_* this##struct_ = PeekStyle##struct_(); \
467 if (this##struct_) { \
468 const nsStyle##struct_* other##struct_ = aOther->Style##struct_(); \
469 nsChangeHint maxDifference = nsStyle##struct_::MaxDifference(); \
470 nsChangeHint maxDifferenceNeverInherited = \
471 nsStyle##struct_::MaxDifferenceNeverInherited(); \
473 (NS_SubtractHint(maxDifference, maxDifferenceNeverInherited) & \
474 aParentHintsNotHandledForDescendants)) && \
475 !NS_IsHintSubset(maxDifference, hint) && \
476 this##struct_ != other##struct_) { \
477 NS_ASSERTION(NS_IsHintSubset( \
478 this##struct_->CalcDifference(*other##struct_), \
479 nsStyle##struct_::MaxDifference()), \
480 "CalcDifference() returned bigger hint than MaxDifference()"); \
481 NS_UpdateHint(hint, this##struct_->CalcDifference(*other##struct_)); \
484 styleStructCount++; \
487 // In general, we want to examine structs starting with those that can
488 // cause the largest style change, down to those that can cause the
489 // smallest. This lets us skip later ones if we already have a hint
490 // that subsumes their MaxDifference. (As the hints get
491 // finer-grained, this optimization is becoming less useful, though.)
492 DO_STRUCT_DIFFERENCE(Display
);
493 DO_STRUCT_DIFFERENCE(XUL
);
494 DO_STRUCT_DIFFERENCE(Column
);
495 DO_STRUCT_DIFFERENCE(Content
);
496 DO_STRUCT_DIFFERENCE(UserInterface
);
497 DO_STRUCT_DIFFERENCE(Visibility
);
498 DO_STRUCT_DIFFERENCE(Outline
);
499 DO_STRUCT_DIFFERENCE(TableBorder
);
500 DO_STRUCT_DIFFERENCE(Table
);
501 DO_STRUCT_DIFFERENCE(UIReset
);
502 DO_STRUCT_DIFFERENCE(Text
);
503 DO_STRUCT_DIFFERENCE(List
);
504 DO_STRUCT_DIFFERENCE(Quotes
);
505 DO_STRUCT_DIFFERENCE(SVGReset
);
506 DO_STRUCT_DIFFERENCE(SVG
);
507 DO_STRUCT_DIFFERENCE(Position
);
508 DO_STRUCT_DIFFERENCE(Font
);
509 DO_STRUCT_DIFFERENCE(Margin
);
510 DO_STRUCT_DIFFERENCE(Padding
);
511 DO_STRUCT_DIFFERENCE(Border
);
512 DO_STRUCT_DIFFERENCE(TextReset
);
513 DO_STRUCT_DIFFERENCE(Background
);
514 DO_STRUCT_DIFFERENCE(Color
);
516 #undef DO_STRUCT_DIFFERENCE
518 MOZ_ASSERT(styleStructCount
== nsStyleStructID_Length
,
519 "missing a call to DO_STRUCT_DIFFERENCE");
521 // Note that we do not check whether this->RelevantLinkVisited() !=
522 // aOther->RelevantLinkVisited(); we don't need to since
523 // nsCSSFrameConstructor::DoContentStateChanged always adds
524 // nsChangeHint_RepaintFrame for NS_EVENT_STATE_VISITED changes (and
525 // needs to, since HasStateDependentStyle probably doesn't work right
526 // for NS_EVENT_STATE_VISITED). Hopefully this doesn't actually
527 // expose whether links are visited to performance tests since all
528 // link coloring happens asynchronously at a time when it's hard for
529 // the page to measure.
530 // However, we do need to compute the larger of the changes that can
531 // happen depending on whether the link is visited or unvisited, since
532 // doing only the one that's currently appropriate would expose which
533 // links are in history to easy performance measurement. Therefore,
534 // here, we add nsChangeHint_RepaintFrame hints (the maximum for
535 // things that can depend on :visited) for the properties on which we
536 // call GetVisitedDependentColor.
537 nsStyleContext
*thisVis
= GetStyleIfVisited(),
538 *otherVis
= aOther
->GetStyleIfVisited();
539 if (!thisVis
!= !otherVis
) {
540 // One style context has a style-if-visited and the other doesn't.
541 // Presume a difference.
542 NS_UpdateHint(hint
, nsChangeHint_RepaintFrame
);
543 } else if (thisVis
&& !NS_IsHintSubset(nsChangeHint_RepaintFrame
, hint
)) {
544 // Both style contexts have a style-if-visited.
547 // NB: Calling Peek on |this|, not |thisVis|, since callers may look
548 // at a struct on |this| without looking at the same struct on
549 // |thisVis| (including this function if we skip one of these checks
550 // due to change being true already or due to the old style context
551 // not having a style-if-visited), but not the other way around.
552 if (PeekStyleColor()) {
553 if (thisVis
->StyleColor()->mColor
!=
554 otherVis
->StyleColor()->mColor
) {
559 // NB: Calling Peek on |this|, not |thisVis| (see above).
560 if (!change
&& PeekStyleBackground()) {
561 if (thisVis
->StyleBackground()->mBackgroundColor
!=
562 otherVis
->StyleBackground()->mBackgroundColor
) {
567 // NB: Calling Peek on |this|, not |thisVis| (see above).
568 if (!change
&& PeekStyleBorder()) {
569 const nsStyleBorder
*thisVisBorder
= thisVis
->StyleBorder();
570 const nsStyleBorder
*otherVisBorder
= otherVis
->StyleBorder();
571 NS_FOR_CSS_SIDES(side
) {
572 bool thisFG
, otherFG
;
573 nscolor thisColor
, otherColor
;
574 thisVisBorder
->GetBorderColor(side
, thisColor
, thisFG
);
575 otherVisBorder
->GetBorderColor(side
, otherColor
, otherFG
);
576 if (thisFG
!= otherFG
|| (!thisFG
&& thisColor
!= otherColor
)) {
583 // NB: Calling Peek on |this|, not |thisVis| (see above).
584 if (!change
&& PeekStyleOutline()) {
585 const nsStyleOutline
*thisVisOutline
= thisVis
->StyleOutline();
586 const nsStyleOutline
*otherVisOutline
= otherVis
->StyleOutline();
588 nscolor thisColor
, otherColor
;
589 if (thisVisOutline
->GetOutlineInitialColor() !=
590 otherVisOutline
->GetOutlineInitialColor() ||
591 (haveColor
= thisVisOutline
->GetOutlineColor(thisColor
)) !=
592 otherVisOutline
->GetOutlineColor(otherColor
) ||
593 (haveColor
&& thisColor
!= otherColor
)) {
598 // NB: Calling Peek on |this|, not |thisVis| (see above).
599 if (!change
&& PeekStyleColumn()) {
600 const nsStyleColumn
*thisVisColumn
= thisVis
->StyleColumn();
601 const nsStyleColumn
*otherVisColumn
= otherVis
->StyleColumn();
602 if (thisVisColumn
->mColumnRuleColor
!= otherVisColumn
->mColumnRuleColor
||
603 thisVisColumn
->mColumnRuleColorIsForeground
!=
604 otherVisColumn
->mColumnRuleColorIsForeground
) {
609 // NB: Calling Peek on |this|, not |thisVis| (see above).
610 if (!change
&& PeekStyleTextReset()) {
611 const nsStyleTextReset
*thisVisTextReset
= thisVis
->StyleTextReset();
612 const nsStyleTextReset
*otherVisTextReset
= otherVis
->StyleTextReset();
613 nscolor thisVisDecColor
, otherVisDecColor
;
614 bool thisVisDecColorIsFG
, otherVisDecColorIsFG
;
615 thisVisTextReset
->GetDecorationColor(thisVisDecColor
,
616 thisVisDecColorIsFG
);
617 otherVisTextReset
->GetDecorationColor(otherVisDecColor
,
618 otherVisDecColorIsFG
);
619 if (thisVisDecColorIsFG
!= otherVisDecColorIsFG
||
620 (!thisVisDecColorIsFG
&& thisVisDecColor
!= otherVisDecColor
)) {
625 // NB: Calling Peek on |this|, not |thisVis| (see above).
626 if (!change
&& PeekStyleSVG()) {
627 const nsStyleSVG
*thisVisSVG
= thisVis
->StyleSVG();
628 const nsStyleSVG
*otherVisSVG
= otherVis
->StyleSVG();
629 if (thisVisSVG
->mFill
!= otherVisSVG
->mFill
||
630 thisVisSVG
->mStroke
!= otherVisSVG
->mStroke
) {
636 NS_UpdateHint(hint
, nsChangeHint_RepaintFrame
);
644 nsStyleContext::Mark()
646 // Mark our rule node.
649 // Mark our children (i.e., tell them to mark their rule nodes, etc.).
651 nsStyleContext
* child
= mChild
;
654 child
= child
->mNextSibling
;
655 } while (mChild
!= child
);
659 nsStyleContext
* child
= mEmptyChild
;
662 child
= child
->mNextSibling
;
663 } while (mEmptyChild
!= child
);
668 void nsStyleContext::List(FILE* out
, int32_t aIndent
)
672 for (ix
= aIndent
; --ix
>= 0; ) fputs(" ", out
);
673 fprintf(out
, "%p(%d) parent=%p ",
674 (void*)this, mRefCnt
, (void *)mParent
);
677 mPseudoTag
->ToString(buffer
);
678 fputs(NS_LossyConvertUTF16toASCII(buffer
).get(), out
);
684 nsRuleNode
* ruleNode
= mRuleNode
;
686 nsIStyleRule
*styleRule
= ruleNode
->GetRule();
688 styleRule
->List(out
, aIndent
+ 1);
690 ruleNode
= ruleNode
->GetParent();
692 for (ix
= aIndent
; --ix
>= 0; ) fputs(" ", out
);
699 if (nullptr != mChild
) {
700 nsStyleContext
* child
= mChild
;
702 child
->List(out
, aIndent
+ 1);
703 child
= child
->mNextSibling
;
704 } while (mChild
!= child
);
706 if (nullptr != mEmptyChild
) {
707 nsStyleContext
* child
= mEmptyChild
;
709 child
->List(out
, aIndent
+ 1);
710 child
= child
->mNextSibling
;
711 } while (mEmptyChild
!= child
);
716 // Overloaded new operator. Initializes the memory to 0 and relies on an arena
717 // (which comes from the presShell) to perform the allocation.
719 nsStyleContext::operator new(size_t sz
, nsPresContext
* aPresContext
) CPP_THROW_NEW
721 // Check the recycle list first.
722 return aPresContext
->PresShell()->AllocateByObjectID(nsPresArena::nsStyleContext_id
, sz
);
725 // Overridden to prevent the global delete from being called, since the memory
726 // came out of an nsIArena instead of the global delete operator's heap.
728 nsStyleContext::Destroy()
730 // Get the pres context from our rule node.
731 nsRefPtr
<nsPresContext
> presContext
= mRuleNode
->PresContext();
733 // Call our destructor.
734 this->~nsStyleContext();
736 // Don't let the memory be freed, since it will be recycled
737 // instead. Don't call the global operator delete.
738 presContext
->PresShell()->FreeByObjectID(nsPresArena::nsStyleContext_id
, this);
741 already_AddRefed
<nsStyleContext
>
742 NS_NewStyleContext(nsStyleContext
* aParentContext
,
744 nsCSSPseudoElements::Type aPseudoType
,
745 nsRuleNode
* aRuleNode
,
746 bool aSkipParentDisplayBasedStyleFixup
)
748 nsRefPtr
<nsStyleContext
> context
=
749 new (aRuleNode
->PresContext())
750 nsStyleContext(aParentContext
, aPseudoTag
, aPseudoType
, aRuleNode
,
751 aSkipParentDisplayBasedStyleFixup
);
752 return context
.forget();
756 ExtractAnimationValue(nsCSSProperty aProperty
,
757 nsStyleContext
* aStyleContext
,
758 StyleAnimationValue
& aResult
)
760 DebugOnly
<bool> success
=
761 StyleAnimationValue::ExtractComputedValue(aProperty
, aStyleContext
,
763 NS_ABORT_IF_FALSE(success
,
764 "aProperty must be extractable by StyleAnimationValue");
768 ExtractColor(nsCSSProperty aProperty
,
769 nsStyleContext
*aStyleContext
)
771 StyleAnimationValue val
;
772 ExtractAnimationValue(aProperty
, aStyleContext
, val
);
773 return val
.GetColorValue();
777 ExtractColorLenient(nsCSSProperty aProperty
,
778 nsStyleContext
*aStyleContext
)
780 StyleAnimationValue val
;
781 ExtractAnimationValue(aProperty
, aStyleContext
, val
);
782 if (val
.GetUnit() == StyleAnimationValue::eUnit_Color
) {
783 return val
.GetColorValue();
785 return NS_RGBA(0, 0, 0, 0);
788 struct ColorIndexSet
{
789 uint8_t colorIndex
, alphaIndex
;
792 static const ColorIndexSet gVisitedIndices
[2] = { { 0, 0 }, { 1, 0 } };
795 nsStyleContext::GetVisitedDependentColor(nsCSSProperty aProperty
)
797 NS_ASSERTION(aProperty
== eCSSProperty_color
||
798 aProperty
== eCSSProperty_background_color
||
799 aProperty
== eCSSProperty_border_top_color
||
800 aProperty
== eCSSProperty_border_right_color_value
||
801 aProperty
== eCSSProperty_border_bottom_color
||
802 aProperty
== eCSSProperty_border_left_color_value
||
803 aProperty
== eCSSProperty_outline_color
||
804 aProperty
== eCSSProperty__moz_column_rule_color
||
805 aProperty
== eCSSProperty_text_decoration_color
||
806 aProperty
== eCSSProperty_fill
||
807 aProperty
== eCSSProperty_stroke
,
808 "we need to add to nsStyleContext::CalcStyleDifference");
810 bool isPaintProperty
= aProperty
== eCSSProperty_fill
||
811 aProperty
== eCSSProperty_stroke
;
814 colors
[0] = isPaintProperty
? ExtractColorLenient(aProperty
, this)
815 : ExtractColor(aProperty
, this);
817 nsStyleContext
*visitedStyle
= this->GetStyleIfVisited();
822 colors
[1] = isPaintProperty
? ExtractColorLenient(aProperty
, visitedStyle
)
823 : ExtractColor(aProperty
, visitedStyle
);
825 return nsStyleContext::CombineVisitedColors(colors
,
826 this->RelevantLinkVisited());
830 nsStyleContext::CombineVisitedColors(nscolor
*aColors
, bool aLinkIsVisited
)
832 if (NS_GET_A(aColors
[1]) == 0) {
833 // If the style-if-visited is transparent, then just use the
834 // unvisited style rather than using the (meaningless) color
835 // components of the visited style along with a potentially
836 // non-transparent alpha value.
837 aLinkIsVisited
= false;
840 // NOTE: We want this code to have as little timing dependence as
841 // possible on whether this->RelevantLinkVisited() is true.
842 const ColorIndexSet
&set
=
843 gVisitedIndices
[aLinkIsVisited
? 1 : 0];
845 nscolor colorColor
= aColors
[set
.colorIndex
];
846 nscolor alphaColor
= aColors
[set
.alphaIndex
];
847 return NS_RGBA(NS_GET_R(colorColor
), NS_GET_G(colorColor
),
848 NS_GET_B(colorColor
), NS_GET_A(alphaColor
));
853 nsStyleContext::AssertStyleStructMaxDifferenceValid()
855 #define STYLE_STRUCT(name, checkdata_cb) \
856 MOZ_ASSERT(NS_IsHintSubset(nsStyle##name::MaxDifferenceNeverInherited(), \
857 nsStyle##name::MaxDifference()));
858 #include "nsStyleStructList.h"