1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/style/nsStyleContext.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,880 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +/* the interface (to internal code) for retrieving computed style data */ 1.10 + 1.11 +#include "mozilla/DebugOnly.h" 1.12 + 1.13 +#include "nsCSSAnonBoxes.h" 1.14 +#include "nsStyleConsts.h" 1.15 +#include "nsString.h" 1.16 +#include "nsPresContext.h" 1.17 +#include "nsIStyleRule.h" 1.18 + 1.19 +#include "nsCOMPtr.h" 1.20 +#include "nsStyleSet.h" 1.21 +#include "nsIPresShell.h" 1.22 + 1.23 +#include "nsRuleNode.h" 1.24 +#include "nsStyleContext.h" 1.25 +#include "nsStyleAnimation.h" 1.26 +#include "GeckoProfiler.h" 1.27 + 1.28 +#ifdef DEBUG 1.29 +// #define NOISY_DEBUG 1.30 +#endif 1.31 + 1.32 +using namespace mozilla; 1.33 + 1.34 +//---------------------------------------------------------------------- 1.35 + 1.36 + 1.37 +nsStyleContext::nsStyleContext(nsStyleContext* aParent, 1.38 + nsIAtom* aPseudoTag, 1.39 + nsCSSPseudoElements::Type aPseudoType, 1.40 + nsRuleNode* aRuleNode, 1.41 + bool aSkipFlexItemStyleFixup) 1.42 + : mParent(aParent), 1.43 + mChild(nullptr), 1.44 + mEmptyChild(nullptr), 1.45 + mPseudoTag(aPseudoTag), 1.46 + mRuleNode(aRuleNode), 1.47 + mAllocations(nullptr), 1.48 + mCachedResetData(nullptr), 1.49 + mBits(((uint64_t)aPseudoType) << NS_STYLE_CONTEXT_TYPE_SHIFT), 1.50 + mRefCnt(0) 1.51 +{ 1.52 + // This check has to be done "backward", because if it were written the 1.53 + // more natural way it wouldn't fail even when it needed to. 1.54 + static_assert((UINT64_MAX >> NS_STYLE_CONTEXT_TYPE_SHIFT) >= 1.55 + nsCSSPseudoElements::ePseudo_MAX, 1.56 + "pseudo element bits no longer fit in a uint64_t"); 1.57 + MOZ_ASSERT(aRuleNode); 1.58 + 1.59 + mNextSibling = this; 1.60 + mPrevSibling = this; 1.61 + if (mParent) { 1.62 + mParent->AddRef(); 1.63 + mParent->AddChild(this); 1.64 +#ifdef DEBUG 1.65 + nsRuleNode *r1 = mParent->RuleNode(), *r2 = aRuleNode; 1.66 + while (r1->GetParent()) 1.67 + r1 = r1->GetParent(); 1.68 + while (r2->GetParent()) 1.69 + r2 = r2->GetParent(); 1.70 + NS_ASSERTION(r1 == r2, "must be in the same rule tree as parent"); 1.71 +#endif 1.72 + } 1.73 + 1.74 + mRuleNode->AddRef(); 1.75 + mRuleNode->SetUsedDirectly(); // before ApplyStyleFixups()! 1.76 + 1.77 + ApplyStyleFixups(aSkipFlexItemStyleFixup); 1.78 + 1.79 + #define eStyleStruct_LastItem (nsStyleStructID_Length - 1) 1.80 + NS_ASSERTION(NS_STYLE_INHERIT_MASK & NS_STYLE_INHERIT_BIT(LastItem), 1.81 + "NS_STYLE_INHERIT_MASK must be bigger, and other bits shifted"); 1.82 + #undef eStyleStruct_LastItem 1.83 +} 1.84 + 1.85 +nsStyleContext::~nsStyleContext() 1.86 +{ 1.87 + NS_ASSERTION((nullptr == mChild) && (nullptr == mEmptyChild), "destructing context with children"); 1.88 + 1.89 + nsPresContext *presContext = mRuleNode->PresContext(); 1.90 + 1.91 + mRuleNode->Release(); 1.92 + 1.93 + presContext->PresShell()->StyleSet()-> 1.94 + NotifyStyleContextDestroyed(presContext, this); 1.95 + 1.96 + if (mParent) { 1.97 + mParent->RemoveChild(this); 1.98 + mParent->Release(); 1.99 + } 1.100 + 1.101 + // Free up our data structs. 1.102 + mCachedInheritedData.DestroyStructs(mBits, presContext); 1.103 + if (mCachedResetData) { 1.104 + mCachedResetData->Destroy(mBits, presContext); 1.105 + } 1.106 + 1.107 + FreeAllocations(presContext); 1.108 +} 1.109 + 1.110 +void nsStyleContext::AddChild(nsStyleContext* aChild) 1.111 +{ 1.112 + NS_ASSERTION(aChild->mPrevSibling == aChild && 1.113 + aChild->mNextSibling == aChild, 1.114 + "child already in a child list"); 1.115 + 1.116 + nsStyleContext **listPtr = aChild->mRuleNode->IsRoot() ? &mEmptyChild : &mChild; 1.117 + // Explicitly dereference listPtr so that compiler doesn't have to know that mNextSibling 1.118 + // etc. don't alias with what ever listPtr points at. 1.119 + nsStyleContext *list = *listPtr; 1.120 + 1.121 + // Insert at the beginning of the list. See also FindChildWithRules. 1.122 + if (list) { 1.123 + // Link into existing elements, if there are any. 1.124 + aChild->mNextSibling = list; 1.125 + aChild->mPrevSibling = list->mPrevSibling; 1.126 + list->mPrevSibling->mNextSibling = aChild; 1.127 + list->mPrevSibling = aChild; 1.128 + } 1.129 + (*listPtr) = aChild; 1.130 +} 1.131 + 1.132 +void nsStyleContext::RemoveChild(nsStyleContext* aChild) 1.133 +{ 1.134 + NS_PRECONDITION(nullptr != aChild && this == aChild->mParent, "bad argument"); 1.135 + 1.136 + nsStyleContext **list = aChild->mRuleNode->IsRoot() ? &mEmptyChild : &mChild; 1.137 + 1.138 + if (aChild->mPrevSibling != aChild) { // has siblings 1.139 + if ((*list) == aChild) { 1.140 + (*list) = (*list)->mNextSibling; 1.141 + } 1.142 + } 1.143 + else { 1.144 + NS_ASSERTION((*list) == aChild, "bad sibling pointers"); 1.145 + (*list) = nullptr; 1.146 + } 1.147 + 1.148 + aChild->mPrevSibling->mNextSibling = aChild->mNextSibling; 1.149 + aChild->mNextSibling->mPrevSibling = aChild->mPrevSibling; 1.150 + aChild->mNextSibling = aChild; 1.151 + aChild->mPrevSibling = aChild; 1.152 +} 1.153 + 1.154 +already_AddRefed<nsStyleContext> 1.155 +nsStyleContext::FindChildWithRules(const nsIAtom* aPseudoTag, 1.156 + nsRuleNode* aRuleNode, 1.157 + nsRuleNode* aRulesIfVisited, 1.158 + bool aRelevantLinkVisited) 1.159 +{ 1.160 + NS_ABORT_IF_FALSE(aRulesIfVisited || !aRelevantLinkVisited, 1.161 + "aRelevantLinkVisited should only be set when we have a separate style"); 1.162 + uint32_t threshold = 10; // The # of siblings we're willing to examine 1.163 + // before just giving this whole thing up. 1.164 + 1.165 + nsRefPtr<nsStyleContext> result; 1.166 + nsStyleContext *list = aRuleNode->IsRoot() ? mEmptyChild : mChild; 1.167 + 1.168 + if (list) { 1.169 + nsStyleContext *child = list; 1.170 + do { 1.171 + if (child->mRuleNode == aRuleNode && 1.172 + child->mPseudoTag == aPseudoTag && 1.173 + !child->IsStyleIfVisited() && 1.174 + child->RelevantLinkVisited() == aRelevantLinkVisited) { 1.175 + bool match = false; 1.176 + if (aRulesIfVisited) { 1.177 + match = child->GetStyleIfVisited() && 1.178 + child->GetStyleIfVisited()->mRuleNode == aRulesIfVisited; 1.179 + } else { 1.180 + match = !child->GetStyleIfVisited(); 1.181 + } 1.182 + if (match) { 1.183 + result = child; 1.184 + break; 1.185 + } 1.186 + } 1.187 + child = child->mNextSibling; 1.188 + threshold--; 1.189 + if (threshold == 0) 1.190 + break; 1.191 + } while (child != list); 1.192 + } 1.193 + 1.194 + if (result) { 1.195 + if (result != list) { 1.196 + // Move result to the front of the list. 1.197 + RemoveChild(result); 1.198 + AddChild(result); 1.199 + } 1.200 + } 1.201 + 1.202 + return result.forget(); 1.203 +} 1.204 + 1.205 +const void* nsStyleContext::GetCachedStyleData(nsStyleStructID aSID) 1.206 +{ 1.207 + const void* cachedData; 1.208 + if (nsCachedStyleData::IsReset(aSID)) { 1.209 + if (mCachedResetData) { 1.210 + cachedData = mCachedResetData->mStyleStructs[aSID]; 1.211 + } else { 1.212 + cachedData = nullptr; 1.213 + } 1.214 + } else { 1.215 + cachedData = mCachedInheritedData.mStyleStructs[aSID]; 1.216 + } 1.217 + return cachedData; 1.218 +} 1.219 + 1.220 +const void* nsStyleContext::StyleData(nsStyleStructID aSID) 1.221 +{ 1.222 + const void* cachedData = GetCachedStyleData(aSID); 1.223 + if (cachedData) 1.224 + return cachedData; // We have computed data stored on this node in the context tree. 1.225 + return mRuleNode->GetStyleData(aSID, this, true); // Our rule node will take care of it for us. 1.226 +} 1.227 + 1.228 +// This is an evil evil function, since it forces you to alloc your own separate copy of 1.229 +// style data! Do not use this function unless you absolutely have to! You should avoid 1.230 +// this at all costs! -dwh 1.231 +void* 1.232 +nsStyleContext::GetUniqueStyleData(const nsStyleStructID& aSID) 1.233 +{ 1.234 + // If we already own the struct and no kids could depend on it, then 1.235 + // just return it. (We leak in this case if there are kids -- and this 1.236 + // function really shouldn't be called for style contexts that could 1.237 + // have kids depending on the data. ClearStyleData would be OK, but 1.238 + // this test for no mChild or mEmptyChild doesn't catch that case.) 1.239 + const void *current = StyleData(aSID); 1.240 + if (!mChild && !mEmptyChild && 1.241 + !(mBits & nsCachedStyleData::GetBitForSID(aSID)) && 1.242 + GetCachedStyleData(aSID)) 1.243 + return const_cast<void*>(current); 1.244 + 1.245 + void* result; 1.246 + nsPresContext *presContext = PresContext(); 1.247 + switch (aSID) { 1.248 + 1.249 +#define UNIQUE_CASE(c_) \ 1.250 + case eStyleStruct_##c_: \ 1.251 + result = new (presContext) nsStyle##c_( \ 1.252 + * static_cast<const nsStyle##c_ *>(current)); \ 1.253 + break; 1.254 + 1.255 + UNIQUE_CASE(Display) 1.256 + UNIQUE_CASE(Background) 1.257 + UNIQUE_CASE(Text) 1.258 + UNIQUE_CASE(TextReset) 1.259 + 1.260 +#undef UNIQUE_CASE 1.261 + 1.262 + default: 1.263 + NS_ERROR("Struct type not supported. Please find another way to do this if you can!"); 1.264 + return nullptr; 1.265 + } 1.266 + 1.267 + SetStyle(aSID, result); 1.268 + mBits &= ~static_cast<uint64_t>(nsCachedStyleData::GetBitForSID(aSID)); 1.269 + 1.270 + return result; 1.271 +} 1.272 + 1.273 +void 1.274 +nsStyleContext::SetStyle(nsStyleStructID aSID, void* aStruct) 1.275 +{ 1.276 + // This method should only be called from nsRuleNode! It is not a public 1.277 + // method! 1.278 + 1.279 + NS_ASSERTION(aSID >= 0 && aSID < nsStyleStructID_Length, "out of bounds"); 1.280 + 1.281 + // NOTE: nsCachedStyleData::GetStyleData works roughly the same way. 1.282 + // See the comments there (in nsRuleNode.h) for more details about 1.283 + // what this is doing and why. 1.284 + 1.285 + void** dataSlot; 1.286 + if (nsCachedStyleData::IsReset(aSID)) { 1.287 + if (!mCachedResetData) { 1.288 + mCachedResetData = new (mRuleNode->PresContext()) nsResetStyleData; 1.289 + } 1.290 + dataSlot = &mCachedResetData->mStyleStructs[aSID]; 1.291 + } else { 1.292 + dataSlot = &mCachedInheritedData.mStyleStructs[aSID]; 1.293 + } 1.294 + NS_ASSERTION(!*dataSlot || (mBits & nsCachedStyleData::GetBitForSID(aSID)), 1.295 + "Going to leak style data"); 1.296 + *dataSlot = aStruct; 1.297 +} 1.298 + 1.299 +void 1.300 +nsStyleContext::ApplyStyleFixups(bool aSkipFlexItemStyleFixup) 1.301 +{ 1.302 + // See if we have any text decorations. 1.303 + // First see if our parent has text decorations. If our parent does, then we inherit the bit. 1.304 + if (mParent && mParent->HasTextDecorationLines()) { 1.305 + mBits |= NS_STYLE_HAS_TEXT_DECORATION_LINES; 1.306 + } else { 1.307 + // We might have defined a decoration. 1.308 + const nsStyleTextReset* text = StyleTextReset(); 1.309 + uint8_t decorationLine = text->mTextDecorationLine; 1.310 + if (decorationLine != NS_STYLE_TEXT_DECORATION_LINE_NONE && 1.311 + decorationLine != NS_STYLE_TEXT_DECORATION_LINE_OVERRIDE_ALL) { 1.312 + mBits |= NS_STYLE_HAS_TEXT_DECORATION_LINES; 1.313 + } 1.314 + } 1.315 + 1.316 + if ((mParent && mParent->HasPseudoElementData()) || mPseudoTag) { 1.317 + mBits |= NS_STYLE_HAS_PSEUDO_ELEMENT_DATA; 1.318 + } 1.319 + 1.320 + // Correct tables. 1.321 + const nsStyleDisplay* disp = StyleDisplay(); 1.322 + if (disp->mDisplay == NS_STYLE_DISPLAY_TABLE) { 1.323 + // -moz-center and -moz-right are used for HTML's alignment 1.324 + // This is covering the <div align="right"><table>...</table></div> case. 1.325 + // In this case, we don't want to inherit the text alignment into the table. 1.326 + const nsStyleText* text = StyleText(); 1.327 + 1.328 + if (text->mTextAlign == NS_STYLE_TEXT_ALIGN_MOZ_CENTER || 1.329 + text->mTextAlign == NS_STYLE_TEXT_ALIGN_MOZ_RIGHT) 1.330 + { 1.331 + nsStyleText* uniqueText = (nsStyleText*)GetUniqueStyleData(eStyleStruct_Text); 1.332 + uniqueText->mTextAlign = NS_STYLE_TEXT_ALIGN_DEFAULT; 1.333 + } 1.334 + } 1.335 + 1.336 + // CSS2.1 section 9.2.4 specifies fixups for the 'display' property of 1.337 + // the root element. We can't implement them in nsRuleNode because we 1.338 + // don't want to store all display structs that aren't 'block', 1.339 + // 'inline', or 'table' in the style context tree on the off chance 1.340 + // that the root element has its style reresolved later. So do them 1.341 + // here if needed, by changing the style data, so that other code 1.342 + // doesn't get confused by looking at the style data. 1.343 + if (!mParent) { 1.344 + uint8_t displayVal = disp->mDisplay; 1.345 + nsRuleNode::EnsureBlockDisplay(displayVal, true); 1.346 + if (displayVal != disp->mDisplay) { 1.347 + nsStyleDisplay *mutable_display = 1.348 + static_cast<nsStyleDisplay*>(GetUniqueStyleData(eStyleStruct_Display)); 1.349 + 1.350 + // If we're in this code, then mOriginalDisplay doesn't matter 1.351 + // for purposes of the cascade (because this nsStyleDisplay 1.352 + // isn't living in the ruletree anyway), and for determining 1.353 + // hypothetical boxes it's better to have mOriginalDisplay 1.354 + // matching mDisplay here. 1.355 + mutable_display->mOriginalDisplay = mutable_display->mDisplay = 1.356 + displayVal; 1.357 + } 1.358 + } 1.359 + 1.360 + // Adjust the "display" values of flex and grid items (but not for raw text, 1.361 + // placeholders, or table-parts). CSS3 Flexbox section 4 says: 1.362 + // # The computed 'display' of a flex item is determined 1.363 + // # by applying the table in CSS 2.1 Chapter 9.7. 1.364 + // ...which converts inline-level elements to their block-level equivalents. 1.365 + if (!aSkipFlexItemStyleFixup && mParent) { 1.366 + const nsStyleDisplay* parentDisp = mParent->StyleDisplay(); 1.367 + if ((parentDisp->mDisplay == NS_STYLE_DISPLAY_FLEX || 1.368 + parentDisp->mDisplay == NS_STYLE_DISPLAY_INLINE_FLEX || 1.369 + parentDisp->mDisplay == NS_STYLE_DISPLAY_GRID || 1.370 + parentDisp->mDisplay == NS_STYLE_DISPLAY_INLINE_GRID) && 1.371 + GetPseudo() != nsCSSAnonBoxes::mozNonElement) { 1.372 + uint8_t displayVal = disp->mDisplay; 1.373 + // Skip table parts. 1.374 + // NOTE: This list needs to be kept in sync with 1.375 + // nsCSSFrameConstructor.cpp's "sDisplayData" array -- specifically, 1.376 + // this should be the list of display-values that have 1.377 + // FCDATA_DESIRED_PARENT_TYPE_TO_BITS specified in that array. 1.378 + if (NS_STYLE_DISPLAY_TABLE_CAPTION != displayVal && 1.379 + NS_STYLE_DISPLAY_TABLE_ROW_GROUP != displayVal && 1.380 + NS_STYLE_DISPLAY_TABLE_HEADER_GROUP != displayVal && 1.381 + NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP != displayVal && 1.382 + NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP != displayVal && 1.383 + NS_STYLE_DISPLAY_TABLE_COLUMN != displayVal && 1.384 + NS_STYLE_DISPLAY_TABLE_ROW != displayVal && 1.385 + NS_STYLE_DISPLAY_TABLE_CELL != displayVal) { 1.386 + 1.387 + // NOTE: Technically, we shouldn't modify the 'display' value of 1.388 + // positioned elements, since they aren't flex items. However, we don't 1.389 + // need to worry about checking for that, because if we're positioned, 1.390 + // we'll have already been through a call to EnsureBlockDisplay() in 1.391 + // nsRuleNode, so this call here won't change anything. So we're OK. 1.392 + nsRuleNode::EnsureBlockDisplay(displayVal); 1.393 + if (displayVal != disp->mDisplay) { 1.394 + NS_ASSERTION(!disp->IsAbsolutelyPositionedStyle(), 1.395 + "We shouldn't be changing the display value of " 1.396 + "positioned content (and we should have already " 1.397 + "converted its display value to be block-level...)"); 1.398 + nsStyleDisplay *mutable_display = 1.399 + static_cast<nsStyleDisplay*>(GetUniqueStyleData(eStyleStruct_Display)); 1.400 + mutable_display->mDisplay = displayVal; 1.401 + } 1.402 + } 1.403 + } 1.404 + } 1.405 + 1.406 + // Compute User Interface style, to trigger loads of cursors 1.407 + StyleUserInterface(); 1.408 +} 1.409 + 1.410 +nsChangeHint 1.411 +nsStyleContext::CalcStyleDifference(nsStyleContext* aOther, 1.412 + nsChangeHint aParentHintsNotHandledForDescendants) 1.413 +{ 1.414 + PROFILER_LABEL("nsStyleContext", "CalcStyleDifference"); 1.415 + 1.416 + NS_ABORT_IF_FALSE(NS_IsHintSubset(aParentHintsNotHandledForDescendants, 1.417 + nsChangeHint_Hints_NotHandledForDescendants), 1.418 + "caller is passing inherited hints, but shouldn't be"); 1.419 + 1.420 + nsChangeHint hint = NS_STYLE_HINT_NONE; 1.421 + NS_ENSURE_TRUE(aOther, hint); 1.422 + // We must always ensure that we populate the structs on the new style 1.423 + // context that are filled in on the old context, so that if we get 1.424 + // two style changes in succession, the second of which causes a real 1.425 + // style change, the PeekStyleData doesn't return null (implying that 1.426 + // nobody ever looked at that struct's data). In other words, we 1.427 + // can't skip later structs if we get a big change up front, because 1.428 + // we could later get a small change in one of those structs that we 1.429 + // don't want to miss. 1.430 + 1.431 + // If our rule nodes are the same, then any differences in style data 1.432 + // are already accounted for by differences on ancestors. We know 1.433 + // this because CalcStyleDifference is always called on two style 1.434 + // contexts that point to the same element, so we know that our 1.435 + // position in the style context tree is the same and our position in 1.436 + // the rule node tree is also the same. 1.437 + // However, if there were noninherited style change hints on the 1.438 + // parent, we might produce these same noninherited hints on this 1.439 + // style context's frame due to 'inherit' values, so we do need to 1.440 + // compare. 1.441 + // (Things like 'em' units are handled by the change hint produced 1.442 + // by font-size changing, so we don't need to worry about them like 1.443 + // we worry about 'inherit' values.) 1.444 + bool compare = mRuleNode != aOther->mRuleNode; 1.445 + 1.446 + // If we had any change in variable values, then we'll need to examine 1.447 + // all of the other style structs too, even if the new style context has 1.448 + // the same rule node as the old one. 1.449 + const nsStyleVariables* thisVariables = PeekStyleVariables(); 1.450 + if (thisVariables) { 1.451 + const nsStyleVariables* otherVariables = aOther->StyleVariables(); 1.452 + if (thisVariables->mVariables != otherVariables->mVariables) { 1.453 + compare = true; 1.454 + } 1.455 + } 1.456 + 1.457 + DebugOnly<int> styleStructCount = 1; // count Variables already 1.458 + 1.459 +#define DO_STRUCT_DIFFERENCE(struct_) \ 1.460 + PR_BEGIN_MACRO \ 1.461 + const nsStyle##struct_* this##struct_ = PeekStyle##struct_(); \ 1.462 + if (this##struct_) { \ 1.463 + const nsStyle##struct_* other##struct_ = aOther->Style##struct_(); \ 1.464 + nsChangeHint maxDifference = nsStyle##struct_::MaxDifference(); \ 1.465 + nsChangeHint maxDifferenceNeverInherited = \ 1.466 + nsStyle##struct_::MaxDifferenceNeverInherited(); \ 1.467 + if ((compare || \ 1.468 + (NS_SubtractHint(maxDifference, maxDifferenceNeverInherited) & \ 1.469 + aParentHintsNotHandledForDescendants)) && \ 1.470 + !NS_IsHintSubset(maxDifference, hint) && \ 1.471 + this##struct_ != other##struct_) { \ 1.472 + NS_ASSERTION(NS_IsHintSubset( \ 1.473 + this##struct_->CalcDifference(*other##struct_), \ 1.474 + nsStyle##struct_::MaxDifference()), \ 1.475 + "CalcDifference() returned bigger hint than MaxDifference()"); \ 1.476 + NS_UpdateHint(hint, this##struct_->CalcDifference(*other##struct_)); \ 1.477 + } \ 1.478 + } \ 1.479 + styleStructCount++; \ 1.480 + PR_END_MACRO 1.481 + 1.482 + // In general, we want to examine structs starting with those that can 1.483 + // cause the largest style change, down to those that can cause the 1.484 + // smallest. This lets us skip later ones if we already have a hint 1.485 + // that subsumes their MaxDifference. (As the hints get 1.486 + // finer-grained, this optimization is becoming less useful, though.) 1.487 + DO_STRUCT_DIFFERENCE(Display); 1.488 + DO_STRUCT_DIFFERENCE(XUL); 1.489 + DO_STRUCT_DIFFERENCE(Column); 1.490 + DO_STRUCT_DIFFERENCE(Content); 1.491 + DO_STRUCT_DIFFERENCE(UserInterface); 1.492 + DO_STRUCT_DIFFERENCE(Visibility); 1.493 + DO_STRUCT_DIFFERENCE(Outline); 1.494 + DO_STRUCT_DIFFERENCE(TableBorder); 1.495 + DO_STRUCT_DIFFERENCE(Table); 1.496 + DO_STRUCT_DIFFERENCE(UIReset); 1.497 + DO_STRUCT_DIFFERENCE(Text); 1.498 + DO_STRUCT_DIFFERENCE(List); 1.499 + DO_STRUCT_DIFFERENCE(Quotes); 1.500 + DO_STRUCT_DIFFERENCE(SVGReset); 1.501 + DO_STRUCT_DIFFERENCE(SVG); 1.502 + DO_STRUCT_DIFFERENCE(Position); 1.503 + DO_STRUCT_DIFFERENCE(Font); 1.504 + DO_STRUCT_DIFFERENCE(Margin); 1.505 + DO_STRUCT_DIFFERENCE(Padding); 1.506 + DO_STRUCT_DIFFERENCE(Border); 1.507 + DO_STRUCT_DIFFERENCE(TextReset); 1.508 + DO_STRUCT_DIFFERENCE(Background); 1.509 + DO_STRUCT_DIFFERENCE(Color); 1.510 + 1.511 +#undef DO_STRUCT_DIFFERENCE 1.512 + 1.513 + MOZ_ASSERT(styleStructCount == nsStyleStructID_Length, 1.514 + "missing a call to DO_STRUCT_DIFFERENCE"); 1.515 + 1.516 + // Note that we do not check whether this->RelevantLinkVisited() != 1.517 + // aOther->RelevantLinkVisited(); we don't need to since 1.518 + // nsCSSFrameConstructor::DoContentStateChanged always adds 1.519 + // nsChangeHint_RepaintFrame for NS_EVENT_STATE_VISITED changes (and 1.520 + // needs to, since HasStateDependentStyle probably doesn't work right 1.521 + // for NS_EVENT_STATE_VISITED). Hopefully this doesn't actually 1.522 + // expose whether links are visited to performance tests since all 1.523 + // link coloring happens asynchronously at a time when it's hard for 1.524 + // the page to measure. 1.525 + // However, we do need to compute the larger of the changes that can 1.526 + // happen depending on whether the link is visited or unvisited, since 1.527 + // doing only the one that's currently appropriate would expose which 1.528 + // links are in history to easy performance measurement. Therefore, 1.529 + // here, we add nsChangeHint_RepaintFrame hints (the maximum for 1.530 + // things that can depend on :visited) for the properties on which we 1.531 + // call GetVisitedDependentColor. 1.532 + nsStyleContext *thisVis = GetStyleIfVisited(), 1.533 + *otherVis = aOther->GetStyleIfVisited(); 1.534 + if (!thisVis != !otherVis) { 1.535 + // One style context has a style-if-visited and the other doesn't. 1.536 + // Presume a difference. 1.537 + NS_UpdateHint(hint, nsChangeHint_RepaintFrame); 1.538 + } else if (thisVis && !NS_IsHintSubset(nsChangeHint_RepaintFrame, hint)) { 1.539 + // Both style contexts have a style-if-visited. 1.540 + bool change = false; 1.541 + 1.542 + // NB: Calling Peek on |this|, not |thisVis|, since callers may look 1.543 + // at a struct on |this| without looking at the same struct on 1.544 + // |thisVis| (including this function if we skip one of these checks 1.545 + // due to change being true already or due to the old style context 1.546 + // not having a style-if-visited), but not the other way around. 1.547 + if (PeekStyleColor()) { 1.548 + if (thisVis->StyleColor()->mColor != 1.549 + otherVis->StyleColor()->mColor) { 1.550 + change = true; 1.551 + } 1.552 + } 1.553 + 1.554 + // NB: Calling Peek on |this|, not |thisVis| (see above). 1.555 + if (!change && PeekStyleBackground()) { 1.556 + if (thisVis->StyleBackground()->mBackgroundColor != 1.557 + otherVis->StyleBackground()->mBackgroundColor) { 1.558 + change = true; 1.559 + } 1.560 + } 1.561 + 1.562 + // NB: Calling Peek on |this|, not |thisVis| (see above). 1.563 + if (!change && PeekStyleBorder()) { 1.564 + const nsStyleBorder *thisVisBorder = thisVis->StyleBorder(); 1.565 + const nsStyleBorder *otherVisBorder = otherVis->StyleBorder(); 1.566 + NS_FOR_CSS_SIDES(side) { 1.567 + bool thisFG, otherFG; 1.568 + nscolor thisColor, otherColor; 1.569 + thisVisBorder->GetBorderColor(side, thisColor, thisFG); 1.570 + otherVisBorder->GetBorderColor(side, otherColor, otherFG); 1.571 + if (thisFG != otherFG || (!thisFG && thisColor != otherColor)) { 1.572 + change = true; 1.573 + break; 1.574 + } 1.575 + } 1.576 + } 1.577 + 1.578 + // NB: Calling Peek on |this|, not |thisVis| (see above). 1.579 + if (!change && PeekStyleOutline()) { 1.580 + const nsStyleOutline *thisVisOutline = thisVis->StyleOutline(); 1.581 + const nsStyleOutline *otherVisOutline = otherVis->StyleOutline(); 1.582 + bool haveColor; 1.583 + nscolor thisColor, otherColor; 1.584 + if (thisVisOutline->GetOutlineInitialColor() != 1.585 + otherVisOutline->GetOutlineInitialColor() || 1.586 + (haveColor = thisVisOutline->GetOutlineColor(thisColor)) != 1.587 + otherVisOutline->GetOutlineColor(otherColor) || 1.588 + (haveColor && thisColor != otherColor)) { 1.589 + change = true; 1.590 + } 1.591 + } 1.592 + 1.593 + // NB: Calling Peek on |this|, not |thisVis| (see above). 1.594 + if (!change && PeekStyleColumn()) { 1.595 + const nsStyleColumn *thisVisColumn = thisVis->StyleColumn(); 1.596 + const nsStyleColumn *otherVisColumn = otherVis->StyleColumn(); 1.597 + if (thisVisColumn->mColumnRuleColor != otherVisColumn->mColumnRuleColor || 1.598 + thisVisColumn->mColumnRuleColorIsForeground != 1.599 + otherVisColumn->mColumnRuleColorIsForeground) { 1.600 + change = true; 1.601 + } 1.602 + } 1.603 + 1.604 + // NB: Calling Peek on |this|, not |thisVis| (see above). 1.605 + if (!change && PeekStyleTextReset()) { 1.606 + const nsStyleTextReset *thisVisTextReset = thisVis->StyleTextReset(); 1.607 + const nsStyleTextReset *otherVisTextReset = otherVis->StyleTextReset(); 1.608 + nscolor thisVisDecColor, otherVisDecColor; 1.609 + bool thisVisDecColorIsFG, otherVisDecColorIsFG; 1.610 + thisVisTextReset->GetDecorationColor(thisVisDecColor, 1.611 + thisVisDecColorIsFG); 1.612 + otherVisTextReset->GetDecorationColor(otherVisDecColor, 1.613 + otherVisDecColorIsFG); 1.614 + if (thisVisDecColorIsFG != otherVisDecColorIsFG || 1.615 + (!thisVisDecColorIsFG && thisVisDecColor != otherVisDecColor)) { 1.616 + change = true; 1.617 + } 1.618 + } 1.619 + 1.620 + // NB: Calling Peek on |this|, not |thisVis| (see above). 1.621 + if (!change && PeekStyleSVG()) { 1.622 + const nsStyleSVG *thisVisSVG = thisVis->StyleSVG(); 1.623 + const nsStyleSVG *otherVisSVG = otherVis->StyleSVG(); 1.624 + if (thisVisSVG->mFill != otherVisSVG->mFill || 1.625 + thisVisSVG->mStroke != otherVisSVG->mStroke) { 1.626 + change = true; 1.627 + } 1.628 + } 1.629 + 1.630 + if (change) { 1.631 + NS_UpdateHint(hint, nsChangeHint_RepaintFrame); 1.632 + } 1.633 + } 1.634 + 1.635 + return hint; 1.636 +} 1.637 + 1.638 +void 1.639 +nsStyleContext::Mark() 1.640 +{ 1.641 + // Mark our rule node. 1.642 + mRuleNode->Mark(); 1.643 + 1.644 + // Mark our children (i.e., tell them to mark their rule nodes, etc.). 1.645 + if (mChild) { 1.646 + nsStyleContext* child = mChild; 1.647 + do { 1.648 + child->Mark(); 1.649 + child = child->mNextSibling; 1.650 + } while (mChild != child); 1.651 + } 1.652 + 1.653 + if (mEmptyChild) { 1.654 + nsStyleContext* child = mEmptyChild; 1.655 + do { 1.656 + child->Mark(); 1.657 + child = child->mNextSibling; 1.658 + } while (mEmptyChild != child); 1.659 + } 1.660 +} 1.661 + 1.662 +#ifdef DEBUG 1.663 +void nsStyleContext::List(FILE* out, int32_t aIndent) 1.664 +{ 1.665 + // Indent 1.666 + int32_t ix; 1.667 + for (ix = aIndent; --ix >= 0; ) fputs(" ", out); 1.668 + fprintf(out, "%p(%d) parent=%p ", 1.669 + (void*)this, mRefCnt, (void *)mParent); 1.670 + if (mPseudoTag) { 1.671 + nsAutoString buffer; 1.672 + mPseudoTag->ToString(buffer); 1.673 + fputs(NS_LossyConvertUTF16toASCII(buffer).get(), out); 1.674 + fputs(" ", out); 1.675 + } 1.676 + 1.677 + if (mRuleNode) { 1.678 + fputs("{\n", out); 1.679 + nsRuleNode* ruleNode = mRuleNode; 1.680 + while (ruleNode) { 1.681 + nsIStyleRule *styleRule = ruleNode->GetRule(); 1.682 + if (styleRule) { 1.683 + styleRule->List(out, aIndent + 1); 1.684 + } 1.685 + ruleNode = ruleNode->GetParent(); 1.686 + } 1.687 + for (ix = aIndent; --ix >= 0; ) fputs(" ", out); 1.688 + fputs("}\n", out); 1.689 + } 1.690 + else { 1.691 + fputs("{}\n", out); 1.692 + } 1.693 + 1.694 + if (nullptr != mChild) { 1.695 + nsStyleContext* child = mChild; 1.696 + do { 1.697 + child->List(out, aIndent + 1); 1.698 + child = child->mNextSibling; 1.699 + } while (mChild != child); 1.700 + } 1.701 + if (nullptr != mEmptyChild) { 1.702 + nsStyleContext* child = mEmptyChild; 1.703 + do { 1.704 + child->List(out, aIndent + 1); 1.705 + child = child->mNextSibling; 1.706 + } while (mEmptyChild != child); 1.707 + } 1.708 +} 1.709 +#endif 1.710 + 1.711 +// Overloaded new operator. Initializes the memory to 0 and relies on an arena 1.712 +// (which comes from the presShell) to perform the allocation. 1.713 +void* 1.714 +nsStyleContext::operator new(size_t sz, nsPresContext* aPresContext) CPP_THROW_NEW 1.715 +{ 1.716 + // Check the recycle list first. 1.717 + return aPresContext->PresShell()->AllocateByObjectID(nsPresArena::nsStyleContext_id, sz); 1.718 +} 1.719 + 1.720 +// Overridden to prevent the global delete from being called, since the memory 1.721 +// came out of an nsIArena instead of the global delete operator's heap. 1.722 +void 1.723 +nsStyleContext::Destroy() 1.724 +{ 1.725 + // Get the pres context from our rule node. 1.726 + nsRefPtr<nsPresContext> presContext = mRuleNode->PresContext(); 1.727 + 1.728 + // Call our destructor. 1.729 + this->~nsStyleContext(); 1.730 + 1.731 + // Don't let the memory be freed, since it will be recycled 1.732 + // instead. Don't call the global operator delete. 1.733 + presContext->PresShell()->FreeByObjectID(nsPresArena::nsStyleContext_id, this); 1.734 +} 1.735 + 1.736 +already_AddRefed<nsStyleContext> 1.737 +NS_NewStyleContext(nsStyleContext* aParentContext, 1.738 + nsIAtom* aPseudoTag, 1.739 + nsCSSPseudoElements::Type aPseudoType, 1.740 + nsRuleNode* aRuleNode, 1.741 + bool aSkipFlexItemStyleFixup) 1.742 +{ 1.743 + nsRefPtr<nsStyleContext> context = 1.744 + new (aRuleNode->PresContext()) 1.745 + nsStyleContext(aParentContext, aPseudoTag, aPseudoType, aRuleNode, 1.746 + aSkipFlexItemStyleFixup); 1.747 + return context.forget(); 1.748 +} 1.749 + 1.750 +static inline void 1.751 +ExtractAnimationValue(nsCSSProperty aProperty, 1.752 + nsStyleContext* aStyleContext, 1.753 + nsStyleAnimation::Value& aResult) 1.754 +{ 1.755 + DebugOnly<bool> success = 1.756 + nsStyleAnimation::ExtractComputedValue(aProperty, aStyleContext, aResult); 1.757 + NS_ABORT_IF_FALSE(success, 1.758 + "aProperty must be extractable by nsStyleAnimation"); 1.759 +} 1.760 + 1.761 +static nscolor 1.762 +ExtractColor(nsCSSProperty aProperty, 1.763 + nsStyleContext *aStyleContext) 1.764 +{ 1.765 + nsStyleAnimation::Value val; 1.766 + ExtractAnimationValue(aProperty, aStyleContext, val); 1.767 + return val.GetColorValue(); 1.768 +} 1.769 + 1.770 +static nscolor 1.771 +ExtractColorLenient(nsCSSProperty aProperty, 1.772 + nsStyleContext *aStyleContext) 1.773 +{ 1.774 + nsStyleAnimation::Value val; 1.775 + ExtractAnimationValue(aProperty, aStyleContext, val); 1.776 + if (val.GetUnit() == nsStyleAnimation::eUnit_Color) { 1.777 + return val.GetColorValue(); 1.778 + } 1.779 + return NS_RGBA(0, 0, 0, 0); 1.780 +} 1.781 + 1.782 +struct ColorIndexSet { 1.783 + uint8_t colorIndex, alphaIndex; 1.784 +}; 1.785 + 1.786 +static const ColorIndexSet gVisitedIndices[2] = { { 0, 0 }, { 1, 0 } }; 1.787 + 1.788 +nscolor 1.789 +nsStyleContext::GetVisitedDependentColor(nsCSSProperty aProperty) 1.790 +{ 1.791 + NS_ASSERTION(aProperty == eCSSProperty_color || 1.792 + aProperty == eCSSProperty_background_color || 1.793 + aProperty == eCSSProperty_border_top_color || 1.794 + aProperty == eCSSProperty_border_right_color_value || 1.795 + aProperty == eCSSProperty_border_bottom_color || 1.796 + aProperty == eCSSProperty_border_left_color_value || 1.797 + aProperty == eCSSProperty_outline_color || 1.798 + aProperty == eCSSProperty__moz_column_rule_color || 1.799 + aProperty == eCSSProperty_text_decoration_color || 1.800 + aProperty == eCSSProperty_fill || 1.801 + aProperty == eCSSProperty_stroke, 1.802 + "we need to add to nsStyleContext::CalcStyleDifference"); 1.803 + 1.804 + bool isPaintProperty = aProperty == eCSSProperty_fill || 1.805 + aProperty == eCSSProperty_stroke; 1.806 + 1.807 + nscolor colors[2]; 1.808 + colors[0] = isPaintProperty ? ExtractColorLenient(aProperty, this) 1.809 + : ExtractColor(aProperty, this); 1.810 + 1.811 + nsStyleContext *visitedStyle = this->GetStyleIfVisited(); 1.812 + if (!visitedStyle) { 1.813 + return colors[0]; 1.814 + } 1.815 + 1.816 + colors[1] = isPaintProperty ? ExtractColorLenient(aProperty, visitedStyle) 1.817 + : ExtractColor(aProperty, visitedStyle); 1.818 + 1.819 + return nsStyleContext::CombineVisitedColors(colors, 1.820 + this->RelevantLinkVisited()); 1.821 +} 1.822 + 1.823 +/* static */ nscolor 1.824 +nsStyleContext::CombineVisitedColors(nscolor *aColors, bool aLinkIsVisited) 1.825 +{ 1.826 + if (NS_GET_A(aColors[1]) == 0) { 1.827 + // If the style-if-visited is transparent, then just use the 1.828 + // unvisited style rather than using the (meaningless) color 1.829 + // components of the visited style along with a potentially 1.830 + // non-transparent alpha value. 1.831 + aLinkIsVisited = false; 1.832 + } 1.833 + 1.834 + // NOTE: We want this code to have as little timing dependence as 1.835 + // possible on whether this->RelevantLinkVisited() is true. 1.836 + const ColorIndexSet &set = 1.837 + gVisitedIndices[aLinkIsVisited ? 1 : 0]; 1.838 + 1.839 + nscolor colorColor = aColors[set.colorIndex]; 1.840 + nscolor alphaColor = aColors[set.alphaIndex]; 1.841 + return NS_RGBA(NS_GET_R(colorColor), NS_GET_G(colorColor), 1.842 + NS_GET_B(colorColor), NS_GET_A(alphaColor)); 1.843 +} 1.844 + 1.845 +void* 1.846 +nsStyleContext::Alloc(size_t aSize) 1.847 +{ 1.848 + nsIPresShell *shell = PresContext()->PresShell(); 1.849 + 1.850 + aSize += offsetof(AllocationHeader, mStorageStart); 1.851 + AllocationHeader *alloc = 1.852 + static_cast<AllocationHeader*>(shell->AllocateMisc(aSize)); 1.853 + 1.854 + alloc->mSize = aSize; // NOTE: inflated by header 1.855 + 1.856 + alloc->mNext = mAllocations; 1.857 + mAllocations = alloc; 1.858 + 1.859 + return static_cast<void*>(&alloc->mStorageStart); 1.860 +} 1.861 + 1.862 +void 1.863 +nsStyleContext::FreeAllocations(nsPresContext *aPresContext) 1.864 +{ 1.865 + nsIPresShell *shell = aPresContext->PresShell(); 1.866 + 1.867 + for (AllocationHeader *alloc = mAllocations, *next; alloc; alloc = next) { 1.868 + next = alloc->mNext; 1.869 + shell->FreeMisc(alloc->mSize, alloc); 1.870 + } 1.871 +} 1.872 + 1.873 +#ifdef DEBUG 1.874 +/* static */ void 1.875 +nsStyleContext::AssertStyleStructMaxDifferenceValid() 1.876 +{ 1.877 +#define STYLE_STRUCT(name, checkdata_cb) \ 1.878 + MOZ_ASSERT(NS_IsHintSubset(nsStyle##name::MaxDifferenceNeverInherited(), \ 1.879 + nsStyle##name::MaxDifference())); 1.880 +#include "nsStyleStructList.h" 1.881 +#undef STYLE_STRUCT 1.882 +} 1.883 +#endif