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