layout/style/nsStyleSet.cpp

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

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

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

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 /*
michael@0 7 * the container for the style sheets that apply to a presentation, and
michael@0 8 * the internal API that the style system exposes for creating (and
michael@0 9 * potentially re-creating) style contexts
michael@0 10 */
michael@0 11
michael@0 12 #include "mozilla/ArrayUtils.h"
michael@0 13 #include "mozilla/EventStates.h"
michael@0 14 #include "mozilla/MemoryReporting.h"
michael@0 15
michael@0 16 #include "nsStyleSet.h"
michael@0 17 #include "nsCSSStyleSheet.h"
michael@0 18 #include "nsIDocumentInlines.h"
michael@0 19 #include "nsRuleWalker.h"
michael@0 20 #include "nsStyleContext.h"
michael@0 21 #include "mozilla/css/StyleRule.h"
michael@0 22 #include "nsCSSAnonBoxes.h"
michael@0 23 #include "nsCSSPseudoElements.h"
michael@0 24 #include "nsCSSRuleProcessor.h"
michael@0 25 #include "nsDataHashtable.h"
michael@0 26 #include "nsIContent.h"
michael@0 27 #include "nsRuleData.h"
michael@0 28 #include "nsRuleProcessorData.h"
michael@0 29 #include "nsTransitionManager.h"
michael@0 30 #include "nsAnimationManager.h"
michael@0 31 #include "nsStyleSheetService.h"
michael@0 32 #include "mozilla/dom/Element.h"
michael@0 33 #include "GeckoProfiler.h"
michael@0 34 #include "nsHTMLCSSStyleSheet.h"
michael@0 35 #include "nsHTMLStyleSheet.h"
michael@0 36 #include "nsCSSRules.h"
michael@0 37
michael@0 38 using namespace mozilla;
michael@0 39 using namespace mozilla::dom;
michael@0 40
michael@0 41 NS_IMPL_ISUPPORTS(nsEmptyStyleRule, nsIStyleRule)
michael@0 42
michael@0 43 /* virtual */ void
michael@0 44 nsEmptyStyleRule::MapRuleInfoInto(nsRuleData* aRuleData)
michael@0 45 {
michael@0 46 }
michael@0 47
michael@0 48 #ifdef DEBUG
michael@0 49 /* virtual */ void
michael@0 50 nsEmptyStyleRule::List(FILE* out, int32_t aIndent) const
michael@0 51 {
michael@0 52 for (int32_t index = aIndent; --index >= 0; ) fputs(" ", out);
michael@0 53 fputs("[empty style rule] {}\n", out);
michael@0 54 }
michael@0 55 #endif
michael@0 56
michael@0 57 NS_IMPL_ISUPPORTS(nsInitialStyleRule, nsIStyleRule)
michael@0 58
michael@0 59 /* virtual */ void
michael@0 60 nsInitialStyleRule::MapRuleInfoInto(nsRuleData* aRuleData)
michael@0 61 {
michael@0 62 // Iterate over the property groups
michael@0 63 for (nsStyleStructID sid = nsStyleStructID(0);
michael@0 64 sid < nsStyleStructID_Length; sid = nsStyleStructID(sid + 1)) {
michael@0 65 if (aRuleData->mSIDs & (1 << sid)) {
michael@0 66 // Iterate over nsCSSValues within the property group
michael@0 67 nsCSSValue * const value_start =
michael@0 68 aRuleData->mValueStorage + aRuleData->mValueOffsets[sid];
michael@0 69 for (nsCSSValue *value = value_start,
michael@0 70 *value_end = value + nsCSSProps::PropertyCountInStruct(sid);
michael@0 71 value != value_end; ++value) {
michael@0 72 // If MathML is disabled take care not to set MathML properties (or we
michael@0 73 // will trigger assertions in nsRuleNode)
michael@0 74 if (sid == eStyleStruct_Font &&
michael@0 75 !aRuleData->mPresContext->Document()->GetMathMLEnabled()) {
michael@0 76 size_t index = value - value_start;
michael@0 77 if (index == nsCSSProps::PropertyIndexInStruct(
michael@0 78 eCSSProperty_script_level) ||
michael@0 79 index == nsCSSProps::PropertyIndexInStruct(
michael@0 80 eCSSProperty_script_size_multiplier) ||
michael@0 81 index == nsCSSProps::PropertyIndexInStruct(
michael@0 82 eCSSProperty_script_min_size) ||
michael@0 83 index == nsCSSProps::PropertyIndexInStruct(
michael@0 84 eCSSProperty_math_variant) ||
michael@0 85 index == nsCSSProps::PropertyIndexInStruct(
michael@0 86 eCSSProperty_math_display)) {
michael@0 87 continue;
michael@0 88 }
michael@0 89 }
michael@0 90 if (value->GetUnit() == eCSSUnit_Null) {
michael@0 91 value->SetInitialValue();
michael@0 92 }
michael@0 93 }
michael@0 94 }
michael@0 95 }
michael@0 96 }
michael@0 97
michael@0 98 #ifdef DEBUG
michael@0 99 /* virtual */ void
michael@0 100 nsInitialStyleRule::List(FILE* out, int32_t aIndent) const
michael@0 101 {
michael@0 102 for (int32_t index = aIndent; --index >= 0; ) fputs(" ", out);
michael@0 103 fputs("[initial style rule] {}\n", out);
michael@0 104 }
michael@0 105 #endif
michael@0 106
michael@0 107 NS_IMPL_ISUPPORTS(nsDisableTextZoomStyleRule, nsIStyleRule)
michael@0 108
michael@0 109 /* virtual */ void
michael@0 110 nsDisableTextZoomStyleRule::MapRuleInfoInto(nsRuleData* aRuleData)
michael@0 111 {
michael@0 112 if (!(aRuleData->mSIDs & NS_STYLE_INHERIT_BIT(Font)))
michael@0 113 return;
michael@0 114
michael@0 115 nsCSSValue* value = aRuleData->ValueForTextZoom();
michael@0 116 if (value->GetUnit() == eCSSUnit_Null)
michael@0 117 value->SetNoneValue();
michael@0 118 }
michael@0 119
michael@0 120 #ifdef DEBUG
michael@0 121 /* virtual */ void
michael@0 122 nsDisableTextZoomStyleRule::List(FILE* out, int32_t aIndent) const
michael@0 123 {
michael@0 124 for (int32_t index = aIndent; --index >= 0; ) fputs(" ", out);
michael@0 125 fputs("[disable text zoom style rule] {}\n", out);
michael@0 126 }
michael@0 127 #endif
michael@0 128
michael@0 129 static const nsStyleSet::sheetType gCSSSheetTypes[] = {
michael@0 130 // From lowest to highest in cascading order.
michael@0 131 nsStyleSet::eAgentSheet,
michael@0 132 nsStyleSet::eUserSheet,
michael@0 133 nsStyleSet::eDocSheet,
michael@0 134 nsStyleSet::eScopedDocSheet,
michael@0 135 nsStyleSet::eOverrideSheet
michael@0 136 };
michael@0 137
michael@0 138 nsStyleSet::nsStyleSet()
michael@0 139 : mRuleTree(nullptr),
michael@0 140 mBatching(0),
michael@0 141 mInShutdown(false),
michael@0 142 mAuthorStyleDisabled(false),
michael@0 143 mInReconstruct(false),
michael@0 144 mInitFontFeatureValuesLookup(true),
michael@0 145 mDirty(0),
michael@0 146 mUnusedRuleNodeCount(0)
michael@0 147 {
michael@0 148 }
michael@0 149
michael@0 150 size_t
michael@0 151 nsStyleSet::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
michael@0 152 {
michael@0 153 size_t n = aMallocSizeOf(this);
michael@0 154
michael@0 155 for (int i = 0; i < eSheetTypeCount; i++) {
michael@0 156 if (mRuleProcessors[i]) {
michael@0 157 n += mRuleProcessors[i]->SizeOfIncludingThis(aMallocSizeOf);
michael@0 158 }
michael@0 159 n += mSheets[i].SizeOfExcludingThis(nullptr, aMallocSizeOf);
michael@0 160 }
michael@0 161
michael@0 162 for (uint32_t i = 0; i < mScopedDocSheetRuleProcessors.Length(); i++) {
michael@0 163 n += mScopedDocSheetRuleProcessors[i]->SizeOfIncludingThis(aMallocSizeOf);
michael@0 164 }
michael@0 165 n += mScopedDocSheetRuleProcessors.SizeOfExcludingThis(aMallocSizeOf);
michael@0 166
michael@0 167 n += mRoots.SizeOfExcludingThis(aMallocSizeOf);
michael@0 168 n += mOldRuleTrees.SizeOfExcludingThis(aMallocSizeOf);
michael@0 169
michael@0 170 return n;
michael@0 171 }
michael@0 172
michael@0 173 void
michael@0 174 nsStyleSet::Init(nsPresContext *aPresContext)
michael@0 175 {
michael@0 176 mFirstLineRule = new nsEmptyStyleRule;
michael@0 177 mFirstLetterRule = new nsEmptyStyleRule;
michael@0 178 mPlaceholderRule = new nsEmptyStyleRule;
michael@0 179 mDisableTextZoomStyleRule = new nsDisableTextZoomStyleRule;
michael@0 180
michael@0 181 mRuleTree = nsRuleNode::CreateRootNode(aPresContext);
michael@0 182
michael@0 183 GatherRuleProcessors(eAnimationSheet);
michael@0 184 GatherRuleProcessors(eTransitionSheet);
michael@0 185 }
michael@0 186
michael@0 187 nsresult
michael@0 188 nsStyleSet::BeginReconstruct()
michael@0 189 {
michael@0 190 NS_ASSERTION(!mInReconstruct, "Unmatched begin/end?");
michael@0 191 NS_ASSERTION(mRuleTree, "Reconstructing before first construction?");
michael@0 192
michael@0 193 // Create a new rule tree root
michael@0 194 nsRuleNode* newTree =
michael@0 195 nsRuleNode::CreateRootNode(mRuleTree->PresContext());
michael@0 196 if (!newTree)
michael@0 197 return NS_ERROR_OUT_OF_MEMORY;
michael@0 198
michael@0 199 // Save the old rule tree so we can destroy it later
michael@0 200 if (!mOldRuleTrees.AppendElement(mRuleTree)) {
michael@0 201 newTree->Destroy();
michael@0 202 return NS_ERROR_OUT_OF_MEMORY;
michael@0 203 }
michael@0 204
michael@0 205 // We need to keep mRoots so that the rule tree GC will only free the
michael@0 206 // rule trees that really aren't referenced anymore (which should be
michael@0 207 // all of them, if there are no bugs in reresolution code).
michael@0 208
michael@0 209 mInReconstruct = true;
michael@0 210 mRuleTree = newTree;
michael@0 211
michael@0 212 return NS_OK;
michael@0 213 }
michael@0 214
michael@0 215 void
michael@0 216 nsStyleSet::EndReconstruct()
michael@0 217 {
michael@0 218 NS_ASSERTION(mInReconstruct, "Unmatched begin/end?");
michael@0 219 mInReconstruct = false;
michael@0 220 #ifdef DEBUG
michael@0 221 for (int32_t i = mRoots.Length() - 1; i >= 0; --i) {
michael@0 222 nsRuleNode *n = mRoots[i]->RuleNode();
michael@0 223 while (n->GetParent()) {
michael@0 224 n = n->GetParent();
michael@0 225 }
michael@0 226 // Since nsStyleContext's mParent and mRuleNode are immutable, and
michael@0 227 // style contexts own their parents, and nsStyleContext asserts in
michael@0 228 // its constructor that the style context and its parent are in the
michael@0 229 // same rule tree, we don't need to check any of the children of
michael@0 230 // mRoots; we only need to check the rule nodes of mRoots
michael@0 231 // themselves.
michael@0 232
michael@0 233 NS_ASSERTION(n == mRuleTree, "style context has old rule node");
michael@0 234 }
michael@0 235 #endif
michael@0 236 // This *should* destroy the only element of mOldRuleTrees, but in
michael@0 237 // case of some bugs (which would trigger the above assertions), it
michael@0 238 // won't.
michael@0 239 GCRuleTrees();
michael@0 240 }
michael@0 241
michael@0 242 void
michael@0 243 nsStyleSet::SetQuirkStyleSheet(nsIStyleSheet* aQuirkStyleSheet)
michael@0 244 {
michael@0 245 NS_ASSERTION(aQuirkStyleSheet, "Must have quirk sheet if this is called");
michael@0 246 NS_ASSERTION(!mQuirkStyleSheet, "Multiple calls to SetQuirkStyleSheet?");
michael@0 247 NS_ASSERTION(mSheets[eAgentSheet].IndexOf(aQuirkStyleSheet) != -1,
michael@0 248 "Quirk style sheet not one of our agent sheets?");
michael@0 249 mQuirkStyleSheet = aQuirkStyleSheet;
michael@0 250 }
michael@0 251
michael@0 252 typedef nsDataHashtable<nsPtrHashKey<nsINode>, uint32_t> ScopeDepthCache;
michael@0 253
michael@0 254 // Returns the depth of a style scope element, with 1 being the depth of
michael@0 255 // a style scope element that has no ancestor style scope elements. The
michael@0 256 // depth does not count intervening non-scope elements.
michael@0 257 static uint32_t
michael@0 258 GetScopeDepth(nsINode* aScopeElement, ScopeDepthCache& aCache)
michael@0 259 {
michael@0 260 nsINode* parent = aScopeElement->GetParent();
michael@0 261 if (!parent || !parent->IsElementInStyleScope()) {
michael@0 262 return 1;
michael@0 263 }
michael@0 264
michael@0 265 uint32_t depth = aCache.Get(aScopeElement);
michael@0 266 if (!depth) {
michael@0 267 for (nsINode* n = parent; n; n = n->GetParent()) {
michael@0 268 if (n->IsScopedStyleRoot()) {
michael@0 269 depth = GetScopeDepth(n, aCache) + 1;
michael@0 270 aCache.Put(aScopeElement, depth);
michael@0 271 break;
michael@0 272 }
michael@0 273 }
michael@0 274 }
michael@0 275 return depth;
michael@0 276 }
michael@0 277
michael@0 278 struct ScopedSheetOrder
michael@0 279 {
michael@0 280 nsCSSStyleSheet* mSheet;
michael@0 281 uint32_t mDepth;
michael@0 282 uint32_t mOrder;
michael@0 283
michael@0 284 bool operator==(const ScopedSheetOrder& aRHS) const
michael@0 285 {
michael@0 286 return mDepth == aRHS.mDepth &&
michael@0 287 mOrder == aRHS.mOrder;
michael@0 288 }
michael@0 289
michael@0 290 bool operator<(const ScopedSheetOrder& aRHS) const
michael@0 291 {
michael@0 292 if (mDepth != aRHS.mDepth) {
michael@0 293 return mDepth < aRHS.mDepth;
michael@0 294 }
michael@0 295 return mOrder < aRHS.mOrder;
michael@0 296 }
michael@0 297 };
michael@0 298
michael@0 299 // Sorts aSheets such that style sheets for ancestor scopes come
michael@0 300 // before those for descendant scopes, and with sheets for a single
michael@0 301 // scope in document order.
michael@0 302 static void
michael@0 303 SortStyleSheetsByScope(nsTArray<nsCSSStyleSheet*>& aSheets)
michael@0 304 {
michael@0 305 uint32_t n = aSheets.Length();
michael@0 306 if (n == 1) {
michael@0 307 return;
michael@0 308 }
michael@0 309
michael@0 310 ScopeDepthCache cache;
michael@0 311
michael@0 312 nsTArray<ScopedSheetOrder> sheets;
michael@0 313 sheets.SetLength(n);
michael@0 314
michael@0 315 // For each sheet, record the depth of its scope element and its original
michael@0 316 // document order.
michael@0 317 for (uint32_t i = 0; i < n; i++) {
michael@0 318 sheets[i].mSheet = aSheets[i];
michael@0 319 sheets[i].mDepth = GetScopeDepth(aSheets[i]->GetScopeElement(), cache);
michael@0 320 sheets[i].mOrder = i;
michael@0 321 }
michael@0 322
michael@0 323 // Sort by depth first, then document order.
michael@0 324 sheets.Sort();
michael@0 325
michael@0 326 for (uint32_t i = 0; i < n; i++) {
michael@0 327 aSheets[i] = sheets[i].mSheet;
michael@0 328 }
michael@0 329 }
michael@0 330
michael@0 331 nsresult
michael@0 332 nsStyleSet::GatherRuleProcessors(sheetType aType)
michael@0 333 {
michael@0 334 mRuleProcessors[aType] = nullptr;
michael@0 335 if (aType == eScopedDocSheet) {
michael@0 336 for (uint32_t i = 0; i < mScopedDocSheetRuleProcessors.Length(); i++) {
michael@0 337 nsIStyleRuleProcessor* processor = mScopedDocSheetRuleProcessors[i].get();
michael@0 338 Element* scope =
michael@0 339 static_cast<nsCSSRuleProcessor*>(processor)->GetScopeElement();
michael@0 340 scope->ClearIsScopedStyleRoot();
michael@0 341 }
michael@0 342 mScopedDocSheetRuleProcessors.Clear();
michael@0 343 }
michael@0 344 if (mAuthorStyleDisabled && (aType == eDocSheet ||
michael@0 345 aType == eScopedDocSheet ||
michael@0 346 aType == eStyleAttrSheet)) {
michael@0 347 // Don't regather if this level is disabled. Note that we gather
michael@0 348 // preshint sheets no matter what, but then skip them for some
michael@0 349 // elements later if mAuthorStyleDisabled.
michael@0 350 return NS_OK;
michael@0 351 }
michael@0 352 switch (aType) {
michael@0 353 // handle the types for which have a rule processor that does not
michael@0 354 // implement the style sheet interface.
michael@0 355 case eAnimationSheet:
michael@0 356 MOZ_ASSERT(mSheets[aType].Count() == 0);
michael@0 357 mRuleProcessors[aType] = PresContext()->AnimationManager();
michael@0 358 return NS_OK;
michael@0 359 case eTransitionSheet:
michael@0 360 MOZ_ASSERT(mSheets[aType].Count() == 0);
michael@0 361 mRuleProcessors[aType] = PresContext()->TransitionManager();
michael@0 362 return NS_OK;
michael@0 363 case eStyleAttrSheet:
michael@0 364 MOZ_ASSERT(mSheets[aType].Count() == 0);
michael@0 365 mRuleProcessors[aType] = PresContext()->Document()->GetInlineStyleSheet();
michael@0 366 return NS_OK;
michael@0 367 case ePresHintSheet:
michael@0 368 MOZ_ASSERT(mSheets[aType].Count() == 0);
michael@0 369 mRuleProcessors[aType] = PresContext()->Document()->GetAttributeStyleSheet();
michael@0 370 return NS_OK;
michael@0 371 default:
michael@0 372 // keep going
michael@0 373 break;
michael@0 374 }
michael@0 375 if (aType == eScopedDocSheet) {
michael@0 376 // Create a rule processor for each scope.
michael@0 377 uint32_t count = mSheets[eScopedDocSheet].Count();
michael@0 378 if (count) {
michael@0 379 // Gather the scoped style sheets into an array as
michael@0 380 // nsCSSStyleSheets, and mark all of their scope elements
michael@0 381 // as scoped style roots.
michael@0 382 nsTArray<nsCSSStyleSheet*> sheets(count);
michael@0 383 for (uint32_t i = 0; i < count; i++) {
michael@0 384 nsRefPtr<nsCSSStyleSheet> sheet =
michael@0 385 do_QueryObject(mSheets[eScopedDocSheet].ObjectAt(i));
michael@0 386 sheets.AppendElement(sheet);
michael@0 387
michael@0 388 Element* scope = sheet->GetScopeElement();
michael@0 389 scope->SetIsScopedStyleRoot();
michael@0 390 }
michael@0 391
michael@0 392 // Sort the scoped style sheets so that those for the same scope are
michael@0 393 // adjacent and that ancestor scopes come before descendent scopes.
michael@0 394 SortStyleSheetsByScope(sheets);
michael@0 395
michael@0 396 uint32_t start = 0, end;
michael@0 397 do {
michael@0 398 // Find the range of style sheets with the same scope.
michael@0 399 Element* scope = sheets[start]->GetScopeElement();
michael@0 400 end = start + 1;
michael@0 401 while (end < count && sheets[end]->GetScopeElement() == scope) {
michael@0 402 end++;
michael@0 403 }
michael@0 404
michael@0 405 scope->SetIsScopedStyleRoot();
michael@0 406
michael@0 407 // Create a rule processor for the scope.
michael@0 408 nsTArray< nsRefPtr<nsCSSStyleSheet> > sheetsForScope;
michael@0 409 sheetsForScope.AppendElements(sheets.Elements() + start, end - start);
michael@0 410 mScopedDocSheetRuleProcessors.AppendElement
michael@0 411 (new nsCSSRuleProcessor(sheetsForScope, uint8_t(aType), scope));
michael@0 412
michael@0 413 start = end;
michael@0 414 } while (start < count);
michael@0 415 }
michael@0 416 return NS_OK;
michael@0 417 }
michael@0 418 if (mSheets[aType].Count()) {
michael@0 419 switch (aType) {
michael@0 420 case eAgentSheet:
michael@0 421 case eUserSheet:
michael@0 422 case eDocSheet:
michael@0 423 case eOverrideSheet: {
michael@0 424 // levels containing CSS stylesheets (apart from eScopedDocSheet)
michael@0 425 nsCOMArray<nsIStyleSheet>& sheets = mSheets[aType];
michael@0 426 nsTArray<nsRefPtr<nsCSSStyleSheet> > cssSheets(sheets.Count());
michael@0 427 for (int32_t i = 0, i_end = sheets.Count(); i < i_end; ++i) {
michael@0 428 nsRefPtr<nsCSSStyleSheet> cssSheet = do_QueryObject(sheets[i]);
michael@0 429 NS_ASSERTION(cssSheet, "not a CSS sheet");
michael@0 430 cssSheets.AppendElement(cssSheet);
michael@0 431 }
michael@0 432 mRuleProcessors[aType] =
michael@0 433 new nsCSSRuleProcessor(cssSheets, uint8_t(aType), nullptr);
michael@0 434 } break;
michael@0 435
michael@0 436 default:
michael@0 437 // levels containing non-CSS stylesheets
michael@0 438 NS_ASSERTION(mSheets[aType].Count() == 1, "only one sheet per level");
michael@0 439 mRuleProcessors[aType] = do_QueryInterface(mSheets[aType][0]);
michael@0 440 break;
michael@0 441 }
michael@0 442 }
michael@0 443
michael@0 444 return NS_OK;
michael@0 445 }
michael@0 446
michael@0 447 static bool
michael@0 448 IsScopedStyleSheet(nsIStyleSheet* aSheet)
michael@0 449 {
michael@0 450 nsRefPtr<nsCSSStyleSheet> cssSheet = do_QueryObject(aSheet);
michael@0 451 NS_ASSERTION(cssSheet, "expected aSheet to be an nsCSSStyleSheet");
michael@0 452
michael@0 453 return cssSheet->GetScopeElement();
michael@0 454 }
michael@0 455
michael@0 456 nsresult
michael@0 457 nsStyleSet::AppendStyleSheet(sheetType aType, nsIStyleSheet *aSheet)
michael@0 458 {
michael@0 459 NS_PRECONDITION(aSheet, "null arg");
michael@0 460 NS_ASSERTION(aSheet->IsApplicable(),
michael@0 461 "Inapplicable sheet being placed in style set");
michael@0 462 mSheets[aType].RemoveObject(aSheet);
michael@0 463 if (!mSheets[aType].AppendObject(aSheet))
michael@0 464 return NS_ERROR_OUT_OF_MEMORY;
michael@0 465
michael@0 466 return DirtyRuleProcessors(aType);
michael@0 467 }
michael@0 468
michael@0 469 nsresult
michael@0 470 nsStyleSet::PrependStyleSheet(sheetType aType, nsIStyleSheet *aSheet)
michael@0 471 {
michael@0 472 NS_PRECONDITION(aSheet, "null arg");
michael@0 473 NS_ASSERTION(aSheet->IsApplicable(),
michael@0 474 "Inapplicable sheet being placed in style set");
michael@0 475 mSheets[aType].RemoveObject(aSheet);
michael@0 476 if (!mSheets[aType].InsertObjectAt(aSheet, 0))
michael@0 477 return NS_ERROR_OUT_OF_MEMORY;
michael@0 478
michael@0 479 return DirtyRuleProcessors(aType);
michael@0 480 }
michael@0 481
michael@0 482 nsresult
michael@0 483 nsStyleSet::RemoveStyleSheet(sheetType aType, nsIStyleSheet *aSheet)
michael@0 484 {
michael@0 485 NS_PRECONDITION(aSheet, "null arg");
michael@0 486 NS_ASSERTION(aSheet->IsComplete(),
michael@0 487 "Incomplete sheet being removed from style set");
michael@0 488 mSheets[aType].RemoveObject(aSheet);
michael@0 489
michael@0 490 return DirtyRuleProcessors(aType);
michael@0 491 }
michael@0 492
michael@0 493 nsresult
michael@0 494 nsStyleSet::ReplaceSheets(sheetType aType,
michael@0 495 const nsCOMArray<nsIStyleSheet> &aNewSheets)
michael@0 496 {
michael@0 497 mSheets[aType].Clear();
michael@0 498 if (!mSheets[aType].AppendObjects(aNewSheets))
michael@0 499 return NS_ERROR_OUT_OF_MEMORY;
michael@0 500
michael@0 501 return DirtyRuleProcessors(aType);
michael@0 502 }
michael@0 503
michael@0 504 nsresult
michael@0 505 nsStyleSet::InsertStyleSheetBefore(sheetType aType, nsIStyleSheet *aNewSheet,
michael@0 506 nsIStyleSheet *aReferenceSheet)
michael@0 507 {
michael@0 508 NS_PRECONDITION(aNewSheet && aReferenceSheet, "null arg");
michael@0 509 NS_ASSERTION(aNewSheet->IsApplicable(),
michael@0 510 "Inapplicable sheet being placed in style set");
michael@0 511
michael@0 512 mSheets[aType].RemoveObject(aNewSheet);
michael@0 513 int32_t idx = mSheets[aType].IndexOf(aReferenceSheet);
michael@0 514 if (idx < 0)
michael@0 515 return NS_ERROR_INVALID_ARG;
michael@0 516
michael@0 517 if (!mSheets[aType].InsertObjectAt(aNewSheet, idx))
michael@0 518 return NS_ERROR_OUT_OF_MEMORY;
michael@0 519
michael@0 520 return DirtyRuleProcessors(aType);
michael@0 521 }
michael@0 522
michael@0 523 nsresult
michael@0 524 nsStyleSet::DirtyRuleProcessors(sheetType aType)
michael@0 525 {
michael@0 526 if (!mBatching)
michael@0 527 return GatherRuleProcessors(aType);
michael@0 528
michael@0 529 mDirty |= 1 << aType;
michael@0 530 return NS_OK;
michael@0 531 }
michael@0 532
michael@0 533 bool
michael@0 534 nsStyleSet::GetAuthorStyleDisabled()
michael@0 535 {
michael@0 536 return mAuthorStyleDisabled;
michael@0 537 }
michael@0 538
michael@0 539 nsresult
michael@0 540 nsStyleSet::SetAuthorStyleDisabled(bool aStyleDisabled)
michael@0 541 {
michael@0 542 if (aStyleDisabled == !mAuthorStyleDisabled) {
michael@0 543 mAuthorStyleDisabled = aStyleDisabled;
michael@0 544 BeginUpdate();
michael@0 545 mDirty |= 1 << eDocSheet |
michael@0 546 1 << eScopedDocSheet |
michael@0 547 1 << eStyleAttrSheet;
michael@0 548 return EndUpdate();
michael@0 549 }
michael@0 550 return NS_OK;
michael@0 551 }
michael@0 552
michael@0 553 // -------- Doc Sheets
michael@0 554
michael@0 555 nsresult
michael@0 556 nsStyleSet::AddDocStyleSheet(nsIStyleSheet* aSheet, nsIDocument* aDocument)
michael@0 557 {
michael@0 558 NS_PRECONDITION(aSheet && aDocument, "null arg");
michael@0 559 NS_ASSERTION(aSheet->IsApplicable(),
michael@0 560 "Inapplicable sheet being placed in style set");
michael@0 561
michael@0 562 sheetType type = IsScopedStyleSheet(aSheet) ?
michael@0 563 eScopedDocSheet :
michael@0 564 eDocSheet;
michael@0 565 nsCOMArray<nsIStyleSheet>& sheets = mSheets[type];
michael@0 566
michael@0 567 sheets.RemoveObject(aSheet);
michael@0 568 nsStyleSheetService *sheetService = nsStyleSheetService::GetInstance();
michael@0 569
michael@0 570 // lowest index first
michael@0 571 int32_t newDocIndex = aDocument->GetIndexOfStyleSheet(aSheet);
michael@0 572
michael@0 573 int32_t count = sheets.Count();
michael@0 574 int32_t index;
michael@0 575 for (index = 0; index < count; index++) {
michael@0 576 nsIStyleSheet* sheet = sheets.ObjectAt(index);
michael@0 577 int32_t sheetDocIndex = aDocument->GetIndexOfStyleSheet(sheet);
michael@0 578 if (sheetDocIndex > newDocIndex)
michael@0 579 break;
michael@0 580
michael@0 581 // If the sheet is not owned by the document it can be an author
michael@0 582 // sheet registered at nsStyleSheetService or an additional author
michael@0 583 // sheet on the document, which means the new
michael@0 584 // doc sheet should end up before it.
michael@0 585 if (sheetDocIndex < 0 &&
michael@0 586 ((sheetService &&
michael@0 587 sheetService->AuthorStyleSheets()->IndexOf(sheet) >= 0) ||
michael@0 588 sheet == aDocument->FirstAdditionalAuthorSheet()))
michael@0 589 break;
michael@0 590 }
michael@0 591 if (!sheets.InsertObjectAt(aSheet, index))
michael@0 592 return NS_ERROR_OUT_OF_MEMORY;
michael@0 593
michael@0 594 return DirtyRuleProcessors(type);
michael@0 595 }
michael@0 596
michael@0 597 nsresult
michael@0 598 nsStyleSet::RemoveDocStyleSheet(nsIStyleSheet *aSheet)
michael@0 599 {
michael@0 600 nsRefPtr<nsCSSStyleSheet> cssSheet = do_QueryObject(aSheet);
michael@0 601 bool isScoped = cssSheet && cssSheet->GetScopeElement();
michael@0 602 return RemoveStyleSheet(isScoped ? eScopedDocSheet : eDocSheet, aSheet);
michael@0 603 }
michael@0 604
michael@0 605 // Batching
michael@0 606 void
michael@0 607 nsStyleSet::BeginUpdate()
michael@0 608 {
michael@0 609 ++mBatching;
michael@0 610 }
michael@0 611
michael@0 612 nsresult
michael@0 613 nsStyleSet::EndUpdate()
michael@0 614 {
michael@0 615 NS_ASSERTION(mBatching > 0, "Unbalanced EndUpdate");
michael@0 616 if (--mBatching) {
michael@0 617 // We're not completely done yet.
michael@0 618 return NS_OK;
michael@0 619 }
michael@0 620
michael@0 621 for (int i = 0; i < eSheetTypeCount; ++i) {
michael@0 622 if (mDirty & (1 << i)) {
michael@0 623 nsresult rv = GatherRuleProcessors(sheetType(i));
michael@0 624 NS_ENSURE_SUCCESS(rv, rv);
michael@0 625 }
michael@0 626 }
michael@0 627
michael@0 628 mDirty = 0;
michael@0 629 return NS_OK;
michael@0 630 }
michael@0 631
michael@0 632 void
michael@0 633 nsStyleSet::EnableQuirkStyleSheet(bool aEnable)
michael@0 634 {
michael@0 635 #ifdef DEBUG
michael@0 636 bool oldEnabled;
michael@0 637 {
michael@0 638 nsCOMPtr<nsIDOMCSSStyleSheet> domSheet =
michael@0 639 do_QueryInterface(mQuirkStyleSheet);
michael@0 640 domSheet->GetDisabled(&oldEnabled);
michael@0 641 oldEnabled = !oldEnabled;
michael@0 642 }
michael@0 643 #endif
michael@0 644 mQuirkStyleSheet->SetEnabled(aEnable);
michael@0 645 #ifdef DEBUG
michael@0 646 // This should always be OK, since SetEnabled should call
michael@0 647 // ClearRuleCascades.
michael@0 648 // Note that we can hit this codepath multiple times when document.open()
michael@0 649 // (potentially implied) happens multiple times.
michael@0 650 if (mRuleProcessors[eAgentSheet] && aEnable != oldEnabled) {
michael@0 651 static_cast<nsCSSRuleProcessor*>(static_cast<nsIStyleRuleProcessor*>(
michael@0 652 mRuleProcessors[eAgentSheet]))->AssertQuirksChangeOK();
michael@0 653 }
michael@0 654 #endif
michael@0 655 }
michael@0 656
michael@0 657 template<class T>
michael@0 658 static bool
michael@0 659 EnumRulesMatching(nsIStyleRuleProcessor* aProcessor, void* aData)
michael@0 660 {
michael@0 661 T* data = static_cast<T*>(aData);
michael@0 662 aProcessor->RulesMatching(data);
michael@0 663 return true;
michael@0 664 }
michael@0 665
michael@0 666 static inline bool
michael@0 667 IsMoreSpecificThanAnimation(nsRuleNode *aRuleNode)
michael@0 668 {
michael@0 669 return !aRuleNode->IsRoot() &&
michael@0 670 (aRuleNode->GetLevel() == nsStyleSet::eTransitionSheet ||
michael@0 671 aRuleNode->IsImportantRule());
michael@0 672 }
michael@0 673
michael@0 674 static nsIStyleRule*
michael@0 675 GetAnimationRule(nsRuleNode *aRuleNode)
michael@0 676 {
michael@0 677 nsRuleNode *n = aRuleNode;
michael@0 678 while (IsMoreSpecificThanAnimation(n)) {
michael@0 679 n = n->GetParent();
michael@0 680 }
michael@0 681
michael@0 682 if (n->IsRoot() || n->GetLevel() != nsStyleSet::eAnimationSheet) {
michael@0 683 return nullptr;
michael@0 684 }
michael@0 685
michael@0 686 return n->GetRule();
michael@0 687 }
michael@0 688
michael@0 689 static nsRuleNode*
michael@0 690 ReplaceAnimationRule(nsRuleNode *aOldRuleNode,
michael@0 691 nsIStyleRule *aOldAnimRule,
michael@0 692 nsIStyleRule *aNewAnimRule)
michael@0 693 {
michael@0 694 nsTArray<nsRuleNode*> moreSpecificNodes;
michael@0 695
michael@0 696 nsRuleNode *n = aOldRuleNode;
michael@0 697 while (IsMoreSpecificThanAnimation(n)) {
michael@0 698 moreSpecificNodes.AppendElement(n);
michael@0 699 n = n->GetParent();
michael@0 700 }
michael@0 701
michael@0 702 if (aOldAnimRule) {
michael@0 703 NS_ABORT_IF_FALSE(n->GetRule() == aOldAnimRule, "wrong rule");
michael@0 704 NS_ABORT_IF_FALSE(n->GetLevel() == nsStyleSet::eAnimationSheet,
michael@0 705 "wrong level");
michael@0 706 n = n->GetParent();
michael@0 707 }
michael@0 708
michael@0 709 NS_ABORT_IF_FALSE(!IsMoreSpecificThanAnimation(n) &&
michael@0 710 (n->IsRoot() ||
michael@0 711 n->GetLevel() != nsStyleSet::eAnimationSheet),
michael@0 712 "wrong level");
michael@0 713
michael@0 714 if (aNewAnimRule) {
michael@0 715 n = n->Transition(aNewAnimRule, nsStyleSet::eAnimationSheet, false);
michael@0 716 }
michael@0 717
michael@0 718 for (uint32_t i = moreSpecificNodes.Length(); i-- != 0; ) {
michael@0 719 nsRuleNode *oldNode = moreSpecificNodes[i];
michael@0 720 n = n->Transition(oldNode->GetRule(), oldNode->GetLevel(),
michael@0 721 oldNode->IsImportantRule());
michael@0 722 }
michael@0 723
michael@0 724 return n;
michael@0 725 }
michael@0 726
michael@0 727 /**
michael@0 728 * |GetContext| implements sharing of style contexts (not just the data
michael@0 729 * on the rule nodes) between siblings and cousins of the same
michael@0 730 * generation. (It works for cousins of the same generation since
michael@0 731 * |aParentContext| could itself be a shared context.)
michael@0 732 */
michael@0 733 already_AddRefed<nsStyleContext>
michael@0 734 nsStyleSet::GetContext(nsStyleContext* aParentContext,
michael@0 735 nsRuleNode* aRuleNode,
michael@0 736 // aVisitedRuleNode may be null; if it is null
michael@0 737 // it means that we don't need to force creation
michael@0 738 // of a StyleIfVisited. (But if we make one
michael@0 739 // because aParentContext has one, then aRuleNode
michael@0 740 // should be used.)
michael@0 741 nsRuleNode* aVisitedRuleNode,
michael@0 742 nsIAtom* aPseudoTag,
michael@0 743 nsCSSPseudoElements::Type aPseudoType,
michael@0 744 Element* aElementForAnimation,
michael@0 745 uint32_t aFlags)
michael@0 746 {
michael@0 747 NS_PRECONDITION((!aPseudoTag &&
michael@0 748 aPseudoType ==
michael@0 749 nsCSSPseudoElements::ePseudo_NotPseudoElement) ||
michael@0 750 (aPseudoTag &&
michael@0 751 nsCSSPseudoElements::GetPseudoType(aPseudoTag) ==
michael@0 752 aPseudoType),
michael@0 753 "Pseudo mismatch");
michael@0 754
michael@0 755 if (aVisitedRuleNode == aRuleNode) {
michael@0 756 // No need to force creation of a visited style in this case.
michael@0 757 aVisitedRuleNode = nullptr;
michael@0 758 }
michael@0 759
michael@0 760 // Ensure |aVisitedRuleNode != nullptr| corresponds to the need to
michael@0 761 // create an if-visited style context, and that in that case, we have
michael@0 762 // parentIfVisited set correctly.
michael@0 763 nsStyleContext *parentIfVisited =
michael@0 764 aParentContext ? aParentContext->GetStyleIfVisited() : nullptr;
michael@0 765 if (parentIfVisited) {
michael@0 766 if (!aVisitedRuleNode) {
michael@0 767 aVisitedRuleNode = aRuleNode;
michael@0 768 }
michael@0 769 } else {
michael@0 770 if (aVisitedRuleNode) {
michael@0 771 parentIfVisited = aParentContext;
michael@0 772 }
michael@0 773 }
michael@0 774
michael@0 775 if (aFlags & eIsLink) {
michael@0 776 // If this node is a link, we want its visited's style context's
michael@0 777 // parent to be the regular style context of its parent, because
michael@0 778 // only the visitedness of the relevant link should influence style.
michael@0 779 parentIfVisited = aParentContext;
michael@0 780 }
michael@0 781
michael@0 782 nsRefPtr<nsStyleContext> result;
michael@0 783 if (aParentContext)
michael@0 784 result = aParentContext->FindChildWithRules(aPseudoTag, aRuleNode,
michael@0 785 aVisitedRuleNode,
michael@0 786 aFlags & eIsVisitedLink);
michael@0 787
michael@0 788 #ifdef NOISY_DEBUG
michael@0 789 if (result)
michael@0 790 fprintf(stdout, "--- SharedSC %d ---\n", ++gSharedCount);
michael@0 791 else
michael@0 792 fprintf(stdout, "+++ NewSC %d +++\n", ++gNewCount);
michael@0 793 #endif
michael@0 794
michael@0 795 if (!result) {
michael@0 796 result = NS_NewStyleContext(aParentContext, aPseudoTag, aPseudoType,
michael@0 797 aRuleNode, aFlags & eSkipFlexItemStyleFixup);
michael@0 798 if (aVisitedRuleNode) {
michael@0 799 nsRefPtr<nsStyleContext> resultIfVisited =
michael@0 800 NS_NewStyleContext(parentIfVisited, aPseudoTag, aPseudoType,
michael@0 801 aVisitedRuleNode,
michael@0 802 aFlags & eSkipFlexItemStyleFixup);
michael@0 803 if (!parentIfVisited) {
michael@0 804 mRoots.AppendElement(resultIfVisited);
michael@0 805 }
michael@0 806 resultIfVisited->SetIsStyleIfVisited();
michael@0 807 result->SetStyleIfVisited(resultIfVisited.forget());
michael@0 808
michael@0 809 bool relevantLinkVisited = (aFlags & eIsLink) ?
michael@0 810 (aFlags & eIsVisitedLink) :
michael@0 811 (aParentContext && aParentContext->RelevantLinkVisited());
michael@0 812
michael@0 813 if (relevantLinkVisited) {
michael@0 814 result->AddStyleBit(NS_STYLE_RELEVANT_LINK_VISITED);
michael@0 815 }
michael@0 816 }
michael@0 817 if (!aParentContext) {
michael@0 818 mRoots.AppendElement(result);
michael@0 819 }
michael@0 820 }
michael@0 821 else {
michael@0 822 NS_ASSERTION(result->GetPseudoType() == aPseudoType, "Unexpected type");
michael@0 823 NS_ASSERTION(result->GetPseudo() == aPseudoTag, "Unexpected pseudo");
michael@0 824 }
michael@0 825
michael@0 826 if (aFlags & eDoAnimation) {
michael@0 827 // Normally the animation manager has already added the correct
michael@0 828 // style rule. However, if the animation-name just changed, it
michael@0 829 // might have been wrong. So ask it to double-check based on the
michael@0 830 // resulting style context.
michael@0 831 nsIStyleRule *oldAnimRule = GetAnimationRule(aRuleNode);
michael@0 832 nsIStyleRule *animRule = PresContext()->AnimationManager()->
michael@0 833 CheckAnimationRule(result, aElementForAnimation);
michael@0 834 NS_ABORT_IF_FALSE(result->RuleNode() == aRuleNode,
michael@0 835 "unexpected rule node");
michael@0 836 NS_ABORT_IF_FALSE(!result->GetStyleIfVisited() == !aVisitedRuleNode,
michael@0 837 "unexpected visited rule node");
michael@0 838 NS_ABORT_IF_FALSE(!aVisitedRuleNode ||
michael@0 839 result->GetStyleIfVisited()->RuleNode() ==
michael@0 840 aVisitedRuleNode,
michael@0 841 "unexpected visited rule node");
michael@0 842 NS_ABORT_IF_FALSE(!aVisitedRuleNode ||
michael@0 843 oldAnimRule == GetAnimationRule(aVisitedRuleNode),
michael@0 844 "animation rule mismatch between rule nodes");
michael@0 845 if (oldAnimRule != animRule) {
michael@0 846 nsRuleNode *ruleNode =
michael@0 847 ReplaceAnimationRule(aRuleNode, oldAnimRule, animRule);
michael@0 848 nsRuleNode *visitedRuleNode = aVisitedRuleNode
michael@0 849 ? ReplaceAnimationRule(aVisitedRuleNode, oldAnimRule, animRule)
michael@0 850 : nullptr;
michael@0 851 NS_ABORT_IF_FALSE(!visitedRuleNode ||
michael@0 852 GetAnimationRule(ruleNode) ==
michael@0 853 GetAnimationRule(visitedRuleNode),
michael@0 854 "animation rule mismatch between rule nodes");
michael@0 855 result = GetContext(aParentContext, ruleNode, visitedRuleNode,
michael@0 856 aPseudoTag, aPseudoType, nullptr,
michael@0 857 aFlags & ~eDoAnimation);
michael@0 858 }
michael@0 859 }
michael@0 860
michael@0 861 if (aElementForAnimation && aElementForAnimation->IsHTML(nsGkAtoms::body) &&
michael@0 862 aPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement &&
michael@0 863 PresContext()->CompatibilityMode() == eCompatibility_NavQuirks) {
michael@0 864 nsIDocument* doc = aElementForAnimation->GetCurrentDoc();
michael@0 865 if (doc && doc->GetBodyElement() == aElementForAnimation) {
michael@0 866 // Update the prescontext's body color
michael@0 867 PresContext()->SetBodyTextColor(result->StyleColor()->mColor);
michael@0 868 }
michael@0 869 }
michael@0 870
michael@0 871 return result.forget();
michael@0 872 }
michael@0 873
michael@0 874 void
michael@0 875 nsStyleSet::AddImportantRules(nsRuleNode* aCurrLevelNode,
michael@0 876 nsRuleNode* aLastPrevLevelNode,
michael@0 877 nsRuleWalker* aRuleWalker)
michael@0 878 {
michael@0 879 NS_ASSERTION(aCurrLevelNode &&
michael@0 880 aCurrLevelNode != aLastPrevLevelNode, "How did we get here?");
michael@0 881
michael@0 882 nsAutoTArray<nsIStyleRule*, 16> importantRules;
michael@0 883 for (nsRuleNode *node = aCurrLevelNode; node != aLastPrevLevelNode;
michael@0 884 node = node->GetParent()) {
michael@0 885 // We guarantee that we never walk the root node here, so no need
michael@0 886 // to null-check GetRule(). Furthermore, it must be a CSS rule.
michael@0 887 NS_ASSERTION(nsRefPtr<css::StyleRule>(do_QueryObject(node->GetRule())),
michael@0 888 "Unexpected non-CSS rule");
michael@0 889
michael@0 890 nsIStyleRule* impRule =
michael@0 891 static_cast<css::StyleRule*>(node->GetRule())->GetImportantRule();
michael@0 892 if (impRule)
michael@0 893 importantRules.AppendElement(impRule);
michael@0 894 }
michael@0 895
michael@0 896 NS_ASSERTION(importantRules.Length() != 0,
michael@0 897 "Why did we think there were important rules?");
michael@0 898
michael@0 899 for (uint32_t i = importantRules.Length(); i-- != 0; ) {
michael@0 900 aRuleWalker->Forward(importantRules[i]);
michael@0 901 }
michael@0 902 }
michael@0 903
michael@0 904 #ifdef DEBUG
michael@0 905 void
michael@0 906 nsStyleSet::AssertNoImportantRules(nsRuleNode* aCurrLevelNode,
michael@0 907 nsRuleNode* aLastPrevLevelNode)
michael@0 908 {
michael@0 909 if (!aCurrLevelNode)
michael@0 910 return;
michael@0 911
michael@0 912 for (nsRuleNode *node = aCurrLevelNode; node != aLastPrevLevelNode;
michael@0 913 node = node->GetParent()) {
michael@0 914 nsRefPtr<css::StyleRule> rule(do_QueryObject(node->GetRule()));
michael@0 915 NS_ASSERTION(rule, "Unexpected non-CSS rule");
michael@0 916
michael@0 917 NS_ASSERTION(!rule->GetImportantRule(), "Unexpected important rule");
michael@0 918 }
michael@0 919 }
michael@0 920
michael@0 921 void
michael@0 922 nsStyleSet::AssertNoCSSRules(nsRuleNode* aCurrLevelNode,
michael@0 923 nsRuleNode* aLastPrevLevelNode)
michael@0 924 {
michael@0 925 if (!aCurrLevelNode)
michael@0 926 return;
michael@0 927
michael@0 928 for (nsRuleNode *node = aCurrLevelNode; node != aLastPrevLevelNode;
michael@0 929 node = node->GetParent()) {
michael@0 930 nsIStyleRule *rule = node->GetRule();
michael@0 931 nsRefPtr<css::StyleRule> cssRule(do_QueryObject(rule));
michael@0 932 NS_ASSERTION(!cssRule || !cssRule->Selector(), "Unexpected CSS rule");
michael@0 933 }
michael@0 934 }
michael@0 935 #endif
michael@0 936
michael@0 937 // Enumerate the rules in a way that cares about the order of the rules.
michael@0 938 void
michael@0 939 nsStyleSet::FileRules(nsIStyleRuleProcessor::EnumFunc aCollectorFunc,
michael@0 940 RuleProcessorData* aData, Element* aElement,
michael@0 941 nsRuleWalker* aRuleWalker)
michael@0 942 {
michael@0 943 PROFILER_LABEL("nsStyleSet", "FileRules");
michael@0 944
michael@0 945 // Cascading order:
michael@0 946 // [least important]
michael@0 947 // - UA normal rules = Agent normal
michael@0 948 // - User normal rules = User normal
michael@0 949 // - Presentation hints = PresHint normal
michael@0 950 // - Author normal rules = Document normal
michael@0 951 // - Override normal rules = Override normal
michael@0 952 // - animation rules = Animation normal
michael@0 953 // - Author !important rules = Document !important
michael@0 954 // - Override !important rules = Override !important
michael@0 955 // - User !important rules = User !important
michael@0 956 // - UA !important rules = Agent !important
michael@0 957 // - transition rules = Transition normal
michael@0 958 // [most important]
michael@0 959
michael@0 960 // Save off the last rule before we start walking our agent sheets;
michael@0 961 // this will be either the root or one of the restriction rules.
michael@0 962 nsRuleNode* lastRestrictionRN = aRuleWalker->CurrentNode();
michael@0 963
michael@0 964 aRuleWalker->SetLevel(eAgentSheet, false, true);
michael@0 965 if (mRuleProcessors[eAgentSheet])
michael@0 966 (*aCollectorFunc)(mRuleProcessors[eAgentSheet], aData);
michael@0 967 nsRuleNode* lastAgentRN = aRuleWalker->CurrentNode();
michael@0 968 bool haveImportantUARules = !aRuleWalker->GetCheckForImportantRules();
michael@0 969
michael@0 970 aRuleWalker->SetLevel(eUserSheet, false, true);
michael@0 971 bool skipUserStyles =
michael@0 972 aElement && aElement->IsInNativeAnonymousSubtree();
michael@0 973 if (!skipUserStyles && mRuleProcessors[eUserSheet]) // NOTE: different
michael@0 974 (*aCollectorFunc)(mRuleProcessors[eUserSheet], aData);
michael@0 975 nsRuleNode* lastUserRN = aRuleWalker->CurrentNode();
michael@0 976 bool haveImportantUserRules = !aRuleWalker->GetCheckForImportantRules();
michael@0 977
michael@0 978 aRuleWalker->SetLevel(ePresHintSheet, false, false);
michael@0 979 if (mRuleProcessors[ePresHintSheet])
michael@0 980 (*aCollectorFunc)(mRuleProcessors[ePresHintSheet], aData);
michael@0 981 nsRuleNode* lastPresHintRN = aRuleWalker->CurrentNode();
michael@0 982
michael@0 983 aRuleWalker->SetLevel(eDocSheet, false, true);
michael@0 984 bool cutOffInheritance = false;
michael@0 985 if (mBindingManager && aElement) {
michael@0 986 // We can supply additional document-level sheets that should be walked.
michael@0 987 mBindingManager->WalkRules(aCollectorFunc,
michael@0 988 static_cast<ElementDependentRuleProcessorData*>(aData),
michael@0 989 &cutOffInheritance);
michael@0 990 }
michael@0 991 if (!skipUserStyles && !cutOffInheritance && // NOTE: different
michael@0 992 mRuleProcessors[eDocSheet])
michael@0 993 (*aCollectorFunc)(mRuleProcessors[eDocSheet], aData);
michael@0 994 nsRuleNode* lastDocRN = aRuleWalker->CurrentNode();
michael@0 995 bool haveImportantDocRules = !aRuleWalker->GetCheckForImportantRules();
michael@0 996 nsTArray<nsRuleNode*> lastScopedRNs;
michael@0 997 nsTArray<bool> haveImportantScopedRules;
michael@0 998 bool haveAnyImportantScopedRules = false;
michael@0 999 if (!skipUserStyles && !cutOffInheritance &&
michael@0 1000 aElement && aElement->IsElementInStyleScope()) {
michael@0 1001 lastScopedRNs.SetLength(mScopedDocSheetRuleProcessors.Length());
michael@0 1002 haveImportantScopedRules.SetLength(mScopedDocSheetRuleProcessors.Length());
michael@0 1003 for (uint32_t i = 0; i < mScopedDocSheetRuleProcessors.Length(); i++) {
michael@0 1004 aRuleWalker->SetLevel(eScopedDocSheet, false, true);
michael@0 1005 nsCSSRuleProcessor* processor =
michael@0 1006 static_cast<nsCSSRuleProcessor*>(mScopedDocSheetRuleProcessors[i].get());
michael@0 1007 aData->mScope = processor->GetScopeElement();
michael@0 1008 (*aCollectorFunc)(mScopedDocSheetRuleProcessors[i], aData);
michael@0 1009 lastScopedRNs[i] = aRuleWalker->CurrentNode();
michael@0 1010 haveImportantScopedRules[i] = !aRuleWalker->GetCheckForImportantRules();
michael@0 1011 haveAnyImportantScopedRules = haveAnyImportantScopedRules || haveImportantScopedRules[i];
michael@0 1012 }
michael@0 1013 aData->mScope = nullptr;
michael@0 1014 }
michael@0 1015 nsRuleNode* lastScopedRN = aRuleWalker->CurrentNode();
michael@0 1016 aRuleWalker->SetLevel(eStyleAttrSheet, false, true);
michael@0 1017 if (mRuleProcessors[eStyleAttrSheet])
michael@0 1018 (*aCollectorFunc)(mRuleProcessors[eStyleAttrSheet], aData);
michael@0 1019 nsRuleNode* lastStyleAttrRN = aRuleWalker->CurrentNode();
michael@0 1020 bool haveImportantStyleAttrRules = !aRuleWalker->GetCheckForImportantRules();
michael@0 1021
michael@0 1022 aRuleWalker->SetLevel(eOverrideSheet, false, true);
michael@0 1023 if (mRuleProcessors[eOverrideSheet])
michael@0 1024 (*aCollectorFunc)(mRuleProcessors[eOverrideSheet], aData);
michael@0 1025 nsRuleNode* lastOvrRN = aRuleWalker->CurrentNode();
michael@0 1026 bool haveImportantOverrideRules = !aRuleWalker->GetCheckForImportantRules();
michael@0 1027
michael@0 1028 // This needs to match IsMoreSpecificThanAnimation() above.
michael@0 1029 aRuleWalker->SetLevel(eAnimationSheet, false, false);
michael@0 1030 (*aCollectorFunc)(mRuleProcessors[eAnimationSheet], aData);
michael@0 1031
michael@0 1032 if (haveAnyImportantScopedRules) {
michael@0 1033 for (uint32_t i = lastScopedRNs.Length(); i-- != 0; ) {
michael@0 1034 aRuleWalker->SetLevel(eScopedDocSheet, true, false);
michael@0 1035 nsRuleNode* startRN = lastScopedRNs[i];
michael@0 1036 nsRuleNode* endRN = i == 0 ? lastDocRN : lastScopedRNs[i - 1];
michael@0 1037 if (haveImportantScopedRules[i]) {
michael@0 1038 AddImportantRules(startRN, endRN, aRuleWalker); // scoped
michael@0 1039 }
michael@0 1040 #ifdef DEBUG
michael@0 1041 else {
michael@0 1042 AssertNoImportantRules(startRN, endRN);
michael@0 1043 }
michael@0 1044 #endif
michael@0 1045 }
michael@0 1046 }
michael@0 1047 #ifdef DEBUG
michael@0 1048 else {
michael@0 1049 AssertNoImportantRules(lastScopedRN, lastDocRN);
michael@0 1050 }
michael@0 1051 #endif
michael@0 1052
michael@0 1053 if (haveImportantDocRules) {
michael@0 1054 aRuleWalker->SetLevel(eDocSheet, true, false);
michael@0 1055 AddImportantRules(lastDocRN, lastPresHintRN, aRuleWalker); // doc
michael@0 1056 }
michael@0 1057 #ifdef DEBUG
michael@0 1058 else {
michael@0 1059 AssertNoImportantRules(lastDocRN, lastPresHintRN);
michael@0 1060 }
michael@0 1061 #endif
michael@0 1062
michael@0 1063 if (haveImportantStyleAttrRules) {
michael@0 1064 aRuleWalker->SetLevel(eStyleAttrSheet, true, false);
michael@0 1065 AddImportantRules(lastStyleAttrRN, lastScopedRN, aRuleWalker); // style attr
michael@0 1066 }
michael@0 1067 #ifdef DEBUG
michael@0 1068 else {
michael@0 1069 AssertNoImportantRules(lastStyleAttrRN, lastScopedRN);
michael@0 1070 }
michael@0 1071 #endif
michael@0 1072
michael@0 1073 if (haveImportantOverrideRules) {
michael@0 1074 aRuleWalker->SetLevel(eOverrideSheet, true, false);
michael@0 1075 AddImportantRules(lastOvrRN, lastStyleAttrRN, aRuleWalker); // override
michael@0 1076 }
michael@0 1077 #ifdef DEBUG
michael@0 1078 else {
michael@0 1079 AssertNoImportantRules(lastOvrRN, lastStyleAttrRN);
michael@0 1080 }
michael@0 1081 #endif
michael@0 1082
michael@0 1083 #ifdef DEBUG
michael@0 1084 AssertNoCSSRules(lastPresHintRN, lastUserRN);
michael@0 1085 #endif
michael@0 1086
michael@0 1087 if (haveImportantUserRules) {
michael@0 1088 aRuleWalker->SetLevel(eUserSheet, true, false);
michael@0 1089 AddImportantRules(lastUserRN, lastAgentRN, aRuleWalker); //user
michael@0 1090 }
michael@0 1091 #ifdef DEBUG
michael@0 1092 else {
michael@0 1093 AssertNoImportantRules(lastUserRN, lastAgentRN);
michael@0 1094 }
michael@0 1095 #endif
michael@0 1096
michael@0 1097 if (haveImportantUARules) {
michael@0 1098 aRuleWalker->SetLevel(eAgentSheet, true, false);
michael@0 1099 AddImportantRules(lastAgentRN, lastRestrictionRN, aRuleWalker); //agent
michael@0 1100 }
michael@0 1101 #ifdef DEBUG
michael@0 1102 else {
michael@0 1103 AssertNoImportantRules(lastAgentRN, lastRestrictionRN);
michael@0 1104 }
michael@0 1105 #endif
michael@0 1106
michael@0 1107 #ifdef DEBUG
michael@0 1108 AssertNoCSSRules(lastRestrictionRN, mRuleTree);
michael@0 1109 #endif
michael@0 1110
michael@0 1111 #ifdef DEBUG
michael@0 1112 nsRuleNode *lastImportantRN = aRuleWalker->CurrentNode();
michael@0 1113 #endif
michael@0 1114 aRuleWalker->SetLevel(eTransitionSheet, false, false);
michael@0 1115 (*aCollectorFunc)(mRuleProcessors[eTransitionSheet], aData);
michael@0 1116 #ifdef DEBUG
michael@0 1117 AssertNoCSSRules(aRuleWalker->CurrentNode(), lastImportantRN);
michael@0 1118 #endif
michael@0 1119
michael@0 1120 }
michael@0 1121
michael@0 1122 // Enumerate all the rules in a way that doesn't care about the order
michael@0 1123 // of the rules and doesn't walk !important-rules.
michael@0 1124 void
michael@0 1125 nsStyleSet::WalkRuleProcessors(nsIStyleRuleProcessor::EnumFunc aFunc,
michael@0 1126 ElementDependentRuleProcessorData* aData,
michael@0 1127 bool aWalkAllXBLStylesheets)
michael@0 1128 {
michael@0 1129 if (mRuleProcessors[eAgentSheet])
michael@0 1130 (*aFunc)(mRuleProcessors[eAgentSheet], aData);
michael@0 1131
michael@0 1132 bool skipUserStyles = aData->mElement->IsInNativeAnonymousSubtree();
michael@0 1133 if (!skipUserStyles && mRuleProcessors[eUserSheet]) // NOTE: different
michael@0 1134 (*aFunc)(mRuleProcessors[eUserSheet], aData);
michael@0 1135
michael@0 1136 if (mRuleProcessors[ePresHintSheet])
michael@0 1137 (*aFunc)(mRuleProcessors[ePresHintSheet], aData);
michael@0 1138
michael@0 1139 bool cutOffInheritance = false;
michael@0 1140 if (mBindingManager) {
michael@0 1141 // We can supply additional document-level sheets that should be walked.
michael@0 1142 if (aWalkAllXBLStylesheets) {
michael@0 1143 mBindingManager->WalkAllRules(aFunc, aData);
michael@0 1144 } else {
michael@0 1145 mBindingManager->WalkRules(aFunc, aData, &cutOffInheritance);
michael@0 1146 }
michael@0 1147 }
michael@0 1148 if (!skipUserStyles && !cutOffInheritance) {
michael@0 1149 if (mRuleProcessors[eDocSheet]) // NOTE: different
michael@0 1150 (*aFunc)(mRuleProcessors[eDocSheet], aData);
michael@0 1151 if (aData->mElement->IsElementInStyleScope()) {
michael@0 1152 for (uint32_t i = 0; i < mScopedDocSheetRuleProcessors.Length(); i++)
michael@0 1153 (*aFunc)(mScopedDocSheetRuleProcessors[i], aData);
michael@0 1154 }
michael@0 1155 }
michael@0 1156 if (mRuleProcessors[eStyleAttrSheet])
michael@0 1157 (*aFunc)(mRuleProcessors[eStyleAttrSheet], aData);
michael@0 1158 if (mRuleProcessors[eOverrideSheet])
michael@0 1159 (*aFunc)(mRuleProcessors[eOverrideSheet], aData);
michael@0 1160 (*aFunc)(mRuleProcessors[eAnimationSheet], aData);
michael@0 1161 (*aFunc)(mRuleProcessors[eTransitionSheet], aData);
michael@0 1162 }
michael@0 1163
michael@0 1164 static void
michael@0 1165 InitStyleScopes(TreeMatchContext& aTreeContext, Element* aElement)
michael@0 1166 {
michael@0 1167 if (aElement->IsElementInStyleScope()) {
michael@0 1168 aTreeContext.InitStyleScopes(aElement->GetParentElement());
michael@0 1169 }
michael@0 1170 }
michael@0 1171
michael@0 1172 already_AddRefed<nsStyleContext>
michael@0 1173 nsStyleSet::ResolveStyleFor(Element* aElement,
michael@0 1174 nsStyleContext* aParentContext)
michael@0 1175 {
michael@0 1176 TreeMatchContext treeContext(true, nsRuleWalker::eRelevantLinkUnvisited,
michael@0 1177 aElement->OwnerDoc());
michael@0 1178 InitStyleScopes(treeContext, aElement);
michael@0 1179 return ResolveStyleFor(aElement, aParentContext, treeContext);
michael@0 1180 }
michael@0 1181
michael@0 1182 already_AddRefed<nsStyleContext>
michael@0 1183 nsStyleSet::ResolveStyleFor(Element* aElement,
michael@0 1184 nsStyleContext* aParentContext,
michael@0 1185 TreeMatchContext& aTreeMatchContext)
michael@0 1186 {
michael@0 1187 NS_ENSURE_FALSE(mInShutdown, nullptr);
michael@0 1188 NS_ASSERTION(aElement, "aElement must not be null");
michael@0 1189
michael@0 1190 nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
michael@0 1191 aTreeMatchContext.ResetForUnvisitedMatching();
michael@0 1192 ElementRuleProcessorData data(PresContext(), aElement, &ruleWalker,
michael@0 1193 aTreeMatchContext);
michael@0 1194 WalkDisableTextZoomRule(aElement, &ruleWalker);
michael@0 1195 FileRules(EnumRulesMatching<ElementRuleProcessorData>, &data, aElement,
michael@0 1196 &ruleWalker);
michael@0 1197
michael@0 1198 nsRuleNode *ruleNode = ruleWalker.CurrentNode();
michael@0 1199 nsRuleNode *visitedRuleNode = nullptr;
michael@0 1200
michael@0 1201 if (aTreeMatchContext.HaveRelevantLink()) {
michael@0 1202 aTreeMatchContext.ResetForVisitedMatching();
michael@0 1203 ruleWalker.Reset();
michael@0 1204 FileRules(EnumRulesMatching<ElementRuleProcessorData>, &data, aElement,
michael@0 1205 &ruleWalker);
michael@0 1206 visitedRuleNode = ruleWalker.CurrentNode();
michael@0 1207 }
michael@0 1208
michael@0 1209 uint32_t flags = eDoAnimation;
michael@0 1210 if (nsCSSRuleProcessor::IsLink(aElement)) {
michael@0 1211 flags |= eIsLink;
michael@0 1212 }
michael@0 1213 if (nsCSSRuleProcessor::GetContentState(aElement, aTreeMatchContext).
michael@0 1214 HasState(NS_EVENT_STATE_VISITED)) {
michael@0 1215 flags |= eIsVisitedLink;
michael@0 1216 }
michael@0 1217 if (aTreeMatchContext.mSkippingFlexItemStyleFixup) {
michael@0 1218 flags |= eSkipFlexItemStyleFixup;
michael@0 1219 }
michael@0 1220
michael@0 1221 return GetContext(aParentContext, ruleNode, visitedRuleNode,
michael@0 1222 nullptr, nsCSSPseudoElements::ePseudo_NotPseudoElement,
michael@0 1223 aElement, flags);
michael@0 1224 }
michael@0 1225
michael@0 1226 already_AddRefed<nsStyleContext>
michael@0 1227 nsStyleSet::ResolveStyleForRules(nsStyleContext* aParentContext,
michael@0 1228 const nsTArray< nsCOMPtr<nsIStyleRule> > &aRules)
michael@0 1229 {
michael@0 1230 NS_ENSURE_FALSE(mInShutdown, nullptr);
michael@0 1231
michael@0 1232 nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
michael@0 1233 // FIXME: Perhaps this should be passed in, but it probably doesn't
michael@0 1234 // matter.
michael@0 1235 ruleWalker.SetLevel(eDocSheet, false, false);
michael@0 1236 for (uint32_t i = 0; i < aRules.Length(); i++) {
michael@0 1237 ruleWalker.ForwardOnPossiblyCSSRule(aRules.ElementAt(i));
michael@0 1238 }
michael@0 1239
michael@0 1240 return GetContext(aParentContext, ruleWalker.CurrentNode(), nullptr,
michael@0 1241 nullptr, nsCSSPseudoElements::ePseudo_NotPseudoElement,
michael@0 1242 nullptr, eNoFlags);
michael@0 1243 }
michael@0 1244
michael@0 1245 already_AddRefed<nsStyleContext>
michael@0 1246 nsStyleSet::ResolveStyleForRules(nsStyleContext* aParentContext,
michael@0 1247 nsStyleContext* aOldStyle,
michael@0 1248 const nsTArray<RuleAndLevel>& aRules)
michael@0 1249 {
michael@0 1250 nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
michael@0 1251 for (int32_t i = aRules.Length() - 1; i >= 0; --i) {
michael@0 1252 ruleWalker.SetLevel(aRules[i].mLevel, false, false);
michael@0 1253 ruleWalker.ForwardOnPossiblyCSSRule(aRules[i].mRule);
michael@0 1254 }
michael@0 1255
michael@0 1256 uint32_t flags = eNoFlags;
michael@0 1257 if (aOldStyle->IsLinkContext()) {
michael@0 1258 flags |= eIsLink;
michael@0 1259 }
michael@0 1260 if (aOldStyle->RelevantLinkVisited()) {
michael@0 1261 flags |= eIsVisitedLink;
michael@0 1262 }
michael@0 1263
michael@0 1264 return GetContext(aParentContext, ruleWalker.CurrentNode(), nullptr,
michael@0 1265 nullptr, nsCSSPseudoElements::ePseudo_NotPseudoElement,
michael@0 1266 nullptr, flags);
michael@0 1267 }
michael@0 1268
michael@0 1269 already_AddRefed<nsStyleContext>
michael@0 1270 nsStyleSet::ResolveStyleByAddingRules(nsStyleContext* aBaseContext,
michael@0 1271 const nsCOMArray<nsIStyleRule> &aRules)
michael@0 1272 {
michael@0 1273 NS_ENSURE_FALSE(mInShutdown, nullptr);
michael@0 1274
michael@0 1275 nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
michael@0 1276 ruleWalker.SetCurrentNode(aBaseContext->RuleNode());
michael@0 1277 // FIXME: Perhaps this should be passed in, but it probably doesn't
michael@0 1278 // matter.
michael@0 1279 ruleWalker.SetLevel(eDocSheet, false, false);
michael@0 1280 for (int32_t i = 0; i < aRules.Count(); i++) {
michael@0 1281 ruleWalker.ForwardOnPossiblyCSSRule(aRules.ObjectAt(i));
michael@0 1282 }
michael@0 1283
michael@0 1284 nsRuleNode *ruleNode = ruleWalker.CurrentNode();
michael@0 1285 nsRuleNode *visitedRuleNode = nullptr;
michael@0 1286
michael@0 1287 if (aBaseContext->GetStyleIfVisited()) {
michael@0 1288 ruleWalker.SetCurrentNode(aBaseContext->GetStyleIfVisited()->RuleNode());
michael@0 1289 for (int32_t i = 0; i < aRules.Count(); i++) {
michael@0 1290 ruleWalker.ForwardOnPossiblyCSSRule(aRules.ObjectAt(i));
michael@0 1291 }
michael@0 1292 visitedRuleNode = ruleWalker.CurrentNode();
michael@0 1293 }
michael@0 1294
michael@0 1295 uint32_t flags = eNoFlags;
michael@0 1296 if (aBaseContext->IsLinkContext()) {
michael@0 1297 flags |= eIsLink;
michael@0 1298 }
michael@0 1299 if (aBaseContext->RelevantLinkVisited()) {
michael@0 1300 flags |= eIsVisitedLink;
michael@0 1301 }
michael@0 1302 return GetContext(aBaseContext->GetParent(), ruleNode, visitedRuleNode,
michael@0 1303 aBaseContext->GetPseudo(),
michael@0 1304 aBaseContext->GetPseudoType(),
michael@0 1305 nullptr, flags);
michael@0 1306 }
michael@0 1307
michael@0 1308 already_AddRefed<nsStyleContext>
michael@0 1309 nsStyleSet::ResolveStyleForNonElement(nsStyleContext* aParentContext)
michael@0 1310 {
michael@0 1311 return GetContext(aParentContext, mRuleTree, nullptr,
michael@0 1312 nsCSSAnonBoxes::mozNonElement,
michael@0 1313 nsCSSPseudoElements::ePseudo_AnonBox, nullptr,
michael@0 1314 eNoFlags);
michael@0 1315 }
michael@0 1316
michael@0 1317 void
michael@0 1318 nsStyleSet::WalkRestrictionRule(nsCSSPseudoElements::Type aPseudoType,
michael@0 1319 nsRuleWalker* aRuleWalker)
michael@0 1320 {
michael@0 1321 // This needs to match GetPseudoRestriction in nsRuleNode.cpp.
michael@0 1322 aRuleWalker->SetLevel(eAgentSheet, false, false);
michael@0 1323 if (aPseudoType == nsCSSPseudoElements::ePseudo_firstLetter)
michael@0 1324 aRuleWalker->Forward(mFirstLetterRule);
michael@0 1325 else if (aPseudoType == nsCSSPseudoElements::ePseudo_firstLine)
michael@0 1326 aRuleWalker->Forward(mFirstLineRule);
michael@0 1327 else if (aPseudoType == nsCSSPseudoElements::ePseudo_mozPlaceholder)
michael@0 1328 aRuleWalker->Forward(mPlaceholderRule);
michael@0 1329 }
michael@0 1330
michael@0 1331 void
michael@0 1332 nsStyleSet::WalkDisableTextZoomRule(Element* aElement, nsRuleWalker* aRuleWalker)
michael@0 1333 {
michael@0 1334 aRuleWalker->SetLevel(eAgentSheet, false, false);
michael@0 1335 if (aElement->IsSVG(nsGkAtoms::text))
michael@0 1336 aRuleWalker->Forward(mDisableTextZoomStyleRule);
michael@0 1337 }
michael@0 1338
michael@0 1339 already_AddRefed<nsStyleContext>
michael@0 1340 nsStyleSet::ResolvePseudoElementStyle(Element* aParentElement,
michael@0 1341 nsCSSPseudoElements::Type aType,
michael@0 1342 nsStyleContext* aParentContext,
michael@0 1343 Element* aPseudoElement)
michael@0 1344 {
michael@0 1345 NS_ENSURE_FALSE(mInShutdown, nullptr);
michael@0 1346
michael@0 1347 NS_ASSERTION(aType < nsCSSPseudoElements::ePseudo_PseudoElementCount,
michael@0 1348 "must have pseudo element type");
michael@0 1349 NS_ASSERTION(aParentElement, "Must have parent element");
michael@0 1350
michael@0 1351 nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
michael@0 1352 TreeMatchContext treeContext(true, nsRuleWalker::eRelevantLinkUnvisited,
michael@0 1353 aParentElement->OwnerDoc());
michael@0 1354 InitStyleScopes(treeContext, aParentElement);
michael@0 1355 PseudoElementRuleProcessorData data(PresContext(), aParentElement,
michael@0 1356 &ruleWalker, aType, treeContext,
michael@0 1357 aPseudoElement);
michael@0 1358 WalkRestrictionRule(aType, &ruleWalker);
michael@0 1359 FileRules(EnumRulesMatching<PseudoElementRuleProcessorData>, &data,
michael@0 1360 aParentElement, &ruleWalker);
michael@0 1361
michael@0 1362 nsRuleNode *ruleNode = ruleWalker.CurrentNode();
michael@0 1363 nsRuleNode *visitedRuleNode = nullptr;
michael@0 1364
michael@0 1365 if (treeContext.HaveRelevantLink()) {
michael@0 1366 treeContext.ResetForVisitedMatching();
michael@0 1367 ruleWalker.Reset();
michael@0 1368 WalkRestrictionRule(aType, &ruleWalker);
michael@0 1369 FileRules(EnumRulesMatching<PseudoElementRuleProcessorData>, &data,
michael@0 1370 aParentElement, &ruleWalker);
michael@0 1371 visitedRuleNode = ruleWalker.CurrentNode();
michael@0 1372 }
michael@0 1373
michael@0 1374 // For pseudos, |data.IsLink()| being true means that
michael@0 1375 // our parent node is a link.
michael@0 1376 uint32_t flags = eNoFlags;
michael@0 1377 if (aType == nsCSSPseudoElements::ePseudo_before ||
michael@0 1378 aType == nsCSSPseudoElements::ePseudo_after) {
michael@0 1379 flags |= eDoAnimation;
michael@0 1380 } else {
michael@0 1381 // Flex containers don't expect to have any pseudo-element children aside
michael@0 1382 // from ::before and ::after. So if we have such a child, we're not
michael@0 1383 // actually in a flex container, and we should skip flex-item style fixup.
michael@0 1384 flags |= eSkipFlexItemStyleFixup;
michael@0 1385 }
michael@0 1386
michael@0 1387 return GetContext(aParentContext, ruleNode, visitedRuleNode,
michael@0 1388 nsCSSPseudoElements::GetPseudoAtom(aType), aType,
michael@0 1389 aParentElement, flags);
michael@0 1390 }
michael@0 1391
michael@0 1392 already_AddRefed<nsStyleContext>
michael@0 1393 nsStyleSet::ProbePseudoElementStyle(Element* aParentElement,
michael@0 1394 nsCSSPseudoElements::Type aType,
michael@0 1395 nsStyleContext* aParentContext)
michael@0 1396 {
michael@0 1397 TreeMatchContext treeContext(true, nsRuleWalker::eRelevantLinkUnvisited,
michael@0 1398 aParentElement->OwnerDoc());
michael@0 1399 InitStyleScopes(treeContext, aParentElement);
michael@0 1400 return ProbePseudoElementStyle(aParentElement, aType, aParentContext,
michael@0 1401 treeContext);
michael@0 1402 }
michael@0 1403
michael@0 1404 already_AddRefed<nsStyleContext>
michael@0 1405 nsStyleSet::ProbePseudoElementStyle(Element* aParentElement,
michael@0 1406 nsCSSPseudoElements::Type aType,
michael@0 1407 nsStyleContext* aParentContext,
michael@0 1408 TreeMatchContext& aTreeMatchContext,
michael@0 1409 Element* aPseudoElement)
michael@0 1410 {
michael@0 1411 NS_ENSURE_FALSE(mInShutdown, nullptr);
michael@0 1412
michael@0 1413 NS_ASSERTION(aType < nsCSSPseudoElements::ePseudo_PseudoElementCount,
michael@0 1414 "must have pseudo element type");
michael@0 1415 NS_ASSERTION(aParentElement, "aParentElement must not be null");
michael@0 1416
michael@0 1417 nsIAtom* pseudoTag = nsCSSPseudoElements::GetPseudoAtom(aType);
michael@0 1418 nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
michael@0 1419 aTreeMatchContext.ResetForUnvisitedMatching();
michael@0 1420 PseudoElementRuleProcessorData data(PresContext(), aParentElement,
michael@0 1421 &ruleWalker, aType, aTreeMatchContext,
michael@0 1422 aPseudoElement);
michael@0 1423 WalkRestrictionRule(aType, &ruleWalker);
michael@0 1424 // not the root if there was a restriction rule
michael@0 1425 nsRuleNode *adjustedRoot = ruleWalker.CurrentNode();
michael@0 1426 FileRules(EnumRulesMatching<PseudoElementRuleProcessorData>, &data,
michael@0 1427 aParentElement, &ruleWalker);
michael@0 1428
michael@0 1429 nsRuleNode *ruleNode = ruleWalker.CurrentNode();
michael@0 1430 if (ruleNode == adjustedRoot) {
michael@0 1431 return nullptr;
michael@0 1432 }
michael@0 1433
michael@0 1434 nsRuleNode *visitedRuleNode = nullptr;
michael@0 1435
michael@0 1436 if (aTreeMatchContext.HaveRelevantLink()) {
michael@0 1437 aTreeMatchContext.ResetForVisitedMatching();
michael@0 1438 ruleWalker.Reset();
michael@0 1439 WalkRestrictionRule(aType, &ruleWalker);
michael@0 1440 FileRules(EnumRulesMatching<PseudoElementRuleProcessorData>, &data,
michael@0 1441 aParentElement, &ruleWalker);
michael@0 1442 visitedRuleNode = ruleWalker.CurrentNode();
michael@0 1443 }
michael@0 1444
michael@0 1445 // For pseudos, |data.IsLink()| being true means that
michael@0 1446 // our parent node is a link.
michael@0 1447 uint32_t flags = eNoFlags;
michael@0 1448 if (aType == nsCSSPseudoElements::ePseudo_before ||
michael@0 1449 aType == nsCSSPseudoElements::ePseudo_after) {
michael@0 1450 flags |= eDoAnimation;
michael@0 1451 } else {
michael@0 1452 // Flex containers don't expect to have any pseudo-element children aside
michael@0 1453 // from ::before and ::after. So if we have such a child, we're not
michael@0 1454 // actually in a flex container, and we should skip flex-item style fixup.
michael@0 1455 flags |= eSkipFlexItemStyleFixup;
michael@0 1456 }
michael@0 1457
michael@0 1458 nsRefPtr<nsStyleContext> result =
michael@0 1459 GetContext(aParentContext, ruleNode, visitedRuleNode,
michael@0 1460 pseudoTag, aType,
michael@0 1461 aParentElement, flags);
michael@0 1462
michael@0 1463 // For :before and :after pseudo-elements, having display: none or no
michael@0 1464 // 'content' property is equivalent to not having the pseudo-element
michael@0 1465 // at all.
michael@0 1466 if (result &&
michael@0 1467 (pseudoTag == nsCSSPseudoElements::before ||
michael@0 1468 pseudoTag == nsCSSPseudoElements::after)) {
michael@0 1469 const nsStyleDisplay *display = result->StyleDisplay();
michael@0 1470 const nsStyleContent *content = result->StyleContent();
michael@0 1471 // XXXldb What is contentCount for |content: ""|?
michael@0 1472 if (display->mDisplay == NS_STYLE_DISPLAY_NONE ||
michael@0 1473 content->ContentCount() == 0) {
michael@0 1474 result = nullptr;
michael@0 1475 }
michael@0 1476 }
michael@0 1477
michael@0 1478 return result.forget();
michael@0 1479 }
michael@0 1480
michael@0 1481 already_AddRefed<nsStyleContext>
michael@0 1482 nsStyleSet::ResolveAnonymousBoxStyle(nsIAtom* aPseudoTag,
michael@0 1483 nsStyleContext* aParentContext)
michael@0 1484 {
michael@0 1485 NS_ENSURE_FALSE(mInShutdown, nullptr);
michael@0 1486
michael@0 1487 #ifdef DEBUG
michael@0 1488 bool isAnonBox = nsCSSAnonBoxes::IsAnonBox(aPseudoTag)
michael@0 1489 #ifdef MOZ_XUL
michael@0 1490 && !nsCSSAnonBoxes::IsTreePseudoElement(aPseudoTag)
michael@0 1491 #endif
michael@0 1492 ;
michael@0 1493 NS_PRECONDITION(isAnonBox, "Unexpected pseudo");
michael@0 1494 #endif
michael@0 1495
michael@0 1496 nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
michael@0 1497 AnonBoxRuleProcessorData data(PresContext(), aPseudoTag, &ruleWalker);
michael@0 1498 FileRules(EnumRulesMatching<AnonBoxRuleProcessorData>, &data, nullptr,
michael@0 1499 &ruleWalker);
michael@0 1500
michael@0 1501 if (aPseudoTag == nsCSSAnonBoxes::pageContent) {
michael@0 1502 // Add any @page rules that are specified.
michael@0 1503 nsTArray<nsCSSPageRule*> rules;
michael@0 1504 nsTArray<css::ImportantRule*> importantRules;
michael@0 1505 nsPresContext* presContext = PresContext();
michael@0 1506 presContext->StyleSet()->AppendPageRules(presContext, rules);
michael@0 1507 for (uint32_t i = 0, i_end = rules.Length(); i != i_end; ++i) {
michael@0 1508 ruleWalker.Forward(rules[i]);
michael@0 1509 css::ImportantRule* importantRule = rules[i]->GetImportantRule();
michael@0 1510 if (importantRule) {
michael@0 1511 importantRules.AppendElement(importantRule);
michael@0 1512 }
michael@0 1513 }
michael@0 1514 for (uint32_t i = 0, i_end = importantRules.Length(); i != i_end; ++i) {
michael@0 1515 ruleWalker.Forward(importantRules[i]);
michael@0 1516 }
michael@0 1517 }
michael@0 1518
michael@0 1519 return GetContext(aParentContext, ruleWalker.CurrentNode(), nullptr,
michael@0 1520 aPseudoTag, nsCSSPseudoElements::ePseudo_AnonBox,
michael@0 1521 nullptr, eNoFlags);
michael@0 1522 }
michael@0 1523
michael@0 1524 #ifdef MOZ_XUL
michael@0 1525 already_AddRefed<nsStyleContext>
michael@0 1526 nsStyleSet::ResolveXULTreePseudoStyle(Element* aParentElement,
michael@0 1527 nsIAtom* aPseudoTag,
michael@0 1528 nsStyleContext* aParentContext,
michael@0 1529 nsICSSPseudoComparator* aComparator)
michael@0 1530 {
michael@0 1531 NS_ENSURE_FALSE(mInShutdown, nullptr);
michael@0 1532
michael@0 1533 NS_ASSERTION(aPseudoTag, "must have pseudo tag");
michael@0 1534 NS_ASSERTION(nsCSSAnonBoxes::IsTreePseudoElement(aPseudoTag),
michael@0 1535 "Unexpected pseudo");
michael@0 1536
michael@0 1537 nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
michael@0 1538 TreeMatchContext treeContext(true, nsRuleWalker::eRelevantLinkUnvisited,
michael@0 1539 aParentElement->OwnerDoc());
michael@0 1540 InitStyleScopes(treeContext, aParentElement);
michael@0 1541 XULTreeRuleProcessorData data(PresContext(), aParentElement, &ruleWalker,
michael@0 1542 aPseudoTag, aComparator, treeContext);
michael@0 1543 FileRules(EnumRulesMatching<XULTreeRuleProcessorData>, &data, aParentElement,
michael@0 1544 &ruleWalker);
michael@0 1545
michael@0 1546 nsRuleNode *ruleNode = ruleWalker.CurrentNode();
michael@0 1547 nsRuleNode *visitedRuleNode = nullptr;
michael@0 1548
michael@0 1549 if (treeContext.HaveRelevantLink()) {
michael@0 1550 treeContext.ResetForVisitedMatching();
michael@0 1551 ruleWalker.Reset();
michael@0 1552 FileRules(EnumRulesMatching<XULTreeRuleProcessorData>, &data,
michael@0 1553 aParentElement, &ruleWalker);
michael@0 1554 visitedRuleNode = ruleWalker.CurrentNode();
michael@0 1555 }
michael@0 1556
michael@0 1557 return GetContext(aParentContext, ruleNode, visitedRuleNode,
michael@0 1558 // For pseudos, |data.IsLink()| being true means that
michael@0 1559 // our parent node is a link.
michael@0 1560 aPseudoTag, nsCSSPseudoElements::ePseudo_XULTree,
michael@0 1561 nullptr, eNoFlags);
michael@0 1562 }
michael@0 1563 #endif
michael@0 1564
michael@0 1565 bool
michael@0 1566 nsStyleSet::AppendFontFaceRules(nsPresContext* aPresContext,
michael@0 1567 nsTArray<nsFontFaceRuleContainer>& aArray)
michael@0 1568 {
michael@0 1569 NS_ENSURE_FALSE(mInShutdown, false);
michael@0 1570
michael@0 1571 for (uint32_t i = 0; i < ArrayLength(gCSSSheetTypes); ++i) {
michael@0 1572 if (gCSSSheetTypes[i] == eScopedDocSheet)
michael@0 1573 continue;
michael@0 1574 nsCSSRuleProcessor *ruleProc = static_cast<nsCSSRuleProcessor*>
michael@0 1575 (mRuleProcessors[gCSSSheetTypes[i]].get());
michael@0 1576 if (ruleProc && !ruleProc->AppendFontFaceRules(aPresContext, aArray))
michael@0 1577 return false;
michael@0 1578 }
michael@0 1579 return true;
michael@0 1580 }
michael@0 1581
michael@0 1582 nsCSSKeyframesRule*
michael@0 1583 nsStyleSet::KeyframesRuleForName(nsPresContext* aPresContext,
michael@0 1584 const nsString& aName)
michael@0 1585 {
michael@0 1586 NS_ENSURE_FALSE(mInShutdown, nullptr);
michael@0 1587
michael@0 1588 for (uint32_t i = ArrayLength(gCSSSheetTypes); i-- != 0; ) {
michael@0 1589 if (gCSSSheetTypes[i] == eScopedDocSheet)
michael@0 1590 continue;
michael@0 1591 nsCSSRuleProcessor *ruleProc = static_cast<nsCSSRuleProcessor*>
michael@0 1592 (mRuleProcessors[gCSSSheetTypes[i]].get());
michael@0 1593 if (!ruleProc)
michael@0 1594 continue;
michael@0 1595 nsCSSKeyframesRule* result =
michael@0 1596 ruleProc->KeyframesRuleForName(aPresContext, aName);
michael@0 1597 if (result)
michael@0 1598 return result;
michael@0 1599 }
michael@0 1600 return nullptr;
michael@0 1601 }
michael@0 1602
michael@0 1603 bool
michael@0 1604 nsStyleSet::AppendFontFeatureValuesRules(nsPresContext* aPresContext,
michael@0 1605 nsTArray<nsCSSFontFeatureValuesRule*>& aArray)
michael@0 1606 {
michael@0 1607 NS_ENSURE_FALSE(mInShutdown, false);
michael@0 1608
michael@0 1609 for (uint32_t i = 0; i < ArrayLength(gCSSSheetTypes); ++i) {
michael@0 1610 nsCSSRuleProcessor *ruleProc = static_cast<nsCSSRuleProcessor*>
michael@0 1611 (mRuleProcessors[gCSSSheetTypes[i]].get());
michael@0 1612 if (ruleProc &&
michael@0 1613 !ruleProc->AppendFontFeatureValuesRules(aPresContext, aArray))
michael@0 1614 {
michael@0 1615 return false;
michael@0 1616 }
michael@0 1617 }
michael@0 1618 return true;
michael@0 1619 }
michael@0 1620
michael@0 1621 already_AddRefed<gfxFontFeatureValueSet>
michael@0 1622 nsStyleSet::GetFontFeatureValuesLookup()
michael@0 1623 {
michael@0 1624 if (mInitFontFeatureValuesLookup) {
michael@0 1625 mInitFontFeatureValuesLookup = false;
michael@0 1626
michael@0 1627 nsTArray<nsCSSFontFeatureValuesRule*> rules;
michael@0 1628 AppendFontFeatureValuesRules(PresContext(), rules);
michael@0 1629
michael@0 1630 mFontFeatureValuesLookup = new gfxFontFeatureValueSet();
michael@0 1631
michael@0 1632 uint32_t i, numRules = rules.Length();
michael@0 1633 for (i = 0; i < numRules; i++) {
michael@0 1634 nsCSSFontFeatureValuesRule *rule = rules[i];
michael@0 1635
michael@0 1636 const nsTArray<nsString>& familyList = rule->GetFamilyList();
michael@0 1637 const nsTArray<gfxFontFeatureValueSet::FeatureValues>&
michael@0 1638 featureValues = rule->GetFeatureValues();
michael@0 1639
michael@0 1640 // for each family
michael@0 1641 uint32_t f, numFam;
michael@0 1642
michael@0 1643 numFam = familyList.Length();
michael@0 1644 for (f = 0; f < numFam; f++) {
michael@0 1645 const nsString& family = familyList.ElementAt(f);
michael@0 1646 nsAutoString silly(family);
michael@0 1647 mFontFeatureValuesLookup->AddFontFeatureValues(silly, featureValues);
michael@0 1648 }
michael@0 1649 }
michael@0 1650 }
michael@0 1651
michael@0 1652 nsRefPtr<gfxFontFeatureValueSet> lookup = mFontFeatureValuesLookup;
michael@0 1653 return lookup.forget();
michael@0 1654 }
michael@0 1655
michael@0 1656 bool
michael@0 1657 nsStyleSet::AppendPageRules(nsPresContext* aPresContext,
michael@0 1658 nsTArray<nsCSSPageRule*>& aArray)
michael@0 1659 {
michael@0 1660 NS_ENSURE_FALSE(mInShutdown, false);
michael@0 1661
michael@0 1662 for (uint32_t i = 0; i < ArrayLength(gCSSSheetTypes); ++i) {
michael@0 1663 if (gCSSSheetTypes[i] == eScopedDocSheet)
michael@0 1664 continue;
michael@0 1665 nsCSSRuleProcessor* ruleProc = static_cast<nsCSSRuleProcessor*>
michael@0 1666 (mRuleProcessors[gCSSSheetTypes[i]].get());
michael@0 1667 if (ruleProc && !ruleProc->AppendPageRules(aPresContext, aArray))
michael@0 1668 return false;
michael@0 1669 }
michael@0 1670 return true;
michael@0 1671 }
michael@0 1672
michael@0 1673 void
michael@0 1674 nsStyleSet::BeginShutdown(nsPresContext* aPresContext)
michael@0 1675 {
michael@0 1676 mInShutdown = 1;
michael@0 1677 mRoots.Clear(); // no longer valid, since we won't keep it up to date
michael@0 1678 }
michael@0 1679
michael@0 1680 void
michael@0 1681 nsStyleSet::Shutdown(nsPresContext* aPresContext)
michael@0 1682 {
michael@0 1683 mRuleTree->Destroy();
michael@0 1684 mRuleTree = nullptr;
michael@0 1685
michael@0 1686 // We can have old rule trees either because:
michael@0 1687 // (1) we failed the assertions in EndReconstruct, or
michael@0 1688 // (2) we're shutting down within a reconstruct (see bug 462392)
michael@0 1689 for (uint32_t i = mOldRuleTrees.Length(); i > 0; ) {
michael@0 1690 --i;
michael@0 1691 mOldRuleTrees[i]->Destroy();
michael@0 1692 }
michael@0 1693 mOldRuleTrees.Clear();
michael@0 1694 }
michael@0 1695
michael@0 1696 static const uint32_t kGCInterval = 300;
michael@0 1697
michael@0 1698 void
michael@0 1699 nsStyleSet::NotifyStyleContextDestroyed(nsPresContext* aPresContext,
michael@0 1700 nsStyleContext* aStyleContext)
michael@0 1701 {
michael@0 1702 if (mInShutdown)
michael@0 1703 return;
michael@0 1704
michael@0 1705 // Remove style contexts from mRoots even if mOldRuleTree is non-null. This
michael@0 1706 // could be a style context from the new ruletree!
michael@0 1707 if (!aStyleContext->GetParent()) {
michael@0 1708 mRoots.RemoveElement(aStyleContext);
michael@0 1709 }
michael@0 1710
michael@0 1711 if (mInReconstruct)
michael@0 1712 return;
michael@0 1713
michael@0 1714 if (mUnusedRuleNodeCount >= kGCInterval) {
michael@0 1715 GCRuleTrees();
michael@0 1716 }
michael@0 1717 }
michael@0 1718
michael@0 1719 void
michael@0 1720 nsStyleSet::GCRuleTrees()
michael@0 1721 {
michael@0 1722 mUnusedRuleNodeCount = 0;
michael@0 1723
michael@0 1724 // Mark the style context tree by marking all style contexts which
michael@0 1725 // have no parent, which will mark all descendants. This will reach
michael@0 1726 // style contexts in the undisplayed map and "additional style
michael@0 1727 // contexts" since they are descendants of the roots.
michael@0 1728 for (int32_t i = mRoots.Length() - 1; i >= 0; --i) {
michael@0 1729 mRoots[i]->Mark();
michael@0 1730 }
michael@0 1731
michael@0 1732 // Sweep the rule tree.
michael@0 1733 #ifdef DEBUG
michael@0 1734 bool deleted =
michael@0 1735 #endif
michael@0 1736 mRuleTree->Sweep();
michael@0 1737 NS_ASSERTION(!deleted, "Root node must not be gc'd");
michael@0 1738
michael@0 1739 // Sweep the old rule trees.
michael@0 1740 for (uint32_t i = mOldRuleTrees.Length(); i > 0; ) {
michael@0 1741 --i;
michael@0 1742 if (mOldRuleTrees[i]->Sweep()) {
michael@0 1743 // It was deleted, as it should be.
michael@0 1744 mOldRuleTrees.RemoveElementAt(i);
michael@0 1745 } else {
michael@0 1746 NS_NOTREACHED("old rule tree still referenced");
michael@0 1747 }
michael@0 1748 }
michael@0 1749 }
michael@0 1750
michael@0 1751 /**
michael@0 1752 * Return an equivalent to aRuleNode with both animation and transition
michael@0 1753 * rules removed, and post a restyle if needed.
michael@0 1754 */
michael@0 1755 static inline nsRuleNode*
michael@0 1756 SkipAnimationRules(nsRuleNode* aRuleNode, Element* aElement, bool isPseudo)
michael@0 1757 {
michael@0 1758 nsRuleNode* ruleNode = aRuleNode;
michael@0 1759 // The transition rule must be at the top of the cascade.
michael@0 1760 if (!ruleNode->IsRoot() &&
michael@0 1761 ruleNode->GetLevel() == nsStyleSet::eTransitionSheet) {
michael@0 1762 ruleNode = ruleNode->GetParent();
michael@0 1763 }
michael@0 1764 NS_ABORT_IF_FALSE(ruleNode->IsRoot() ||
michael@0 1765 ruleNode->GetLevel() != nsStyleSet::eTransitionSheet,
michael@0 1766 "can't have more than one transition rule");
michael@0 1767
michael@0 1768 // Use our existing ReplaceAnimationRule function to replace the
michael@0 1769 // animation rule, if present.
michael@0 1770 nsIStyleRule* animationRule = GetAnimationRule(ruleNode);
michael@0 1771 if (animationRule) {
michael@0 1772 ruleNode = ReplaceAnimationRule(ruleNode, animationRule, nullptr);
michael@0 1773 }
michael@0 1774
michael@0 1775 if (ruleNode != aRuleNode) {
michael@0 1776 NS_ASSERTION(aElement, "How can we have transition rules but no element?");
michael@0 1777 // Need to do an animation restyle, just like
michael@0 1778 // nsTransitionManager::WalkTransitionRule and
michael@0 1779 // nsAnimationManager::GetAnimationRule would.
michael@0 1780 nsRestyleHint hint = isPseudo ? eRestyle_Subtree : eRestyle_Self;
michael@0 1781 aRuleNode->PresContext()->PresShell()->RestyleForAnimation(aElement, hint);
michael@0 1782 }
michael@0 1783 return ruleNode;
michael@0 1784 }
michael@0 1785
michael@0 1786 already_AddRefed<nsStyleContext>
michael@0 1787 nsStyleSet::ReparentStyleContext(nsStyleContext* aStyleContext,
michael@0 1788 nsStyleContext* aNewParentContext,
michael@0 1789 Element* aElement)
michael@0 1790 {
michael@0 1791 MOZ_ASSERT(aStyleContext, "aStyleContext must not be null");
michael@0 1792
michael@0 1793 // This short-circuit is OK because we don't call TryStartingTransition
michael@0 1794 // during style reresolution if the style context pointer hasn't changed.
michael@0 1795 if (aStyleContext->GetParent() == aNewParentContext) {
michael@0 1796 nsRefPtr<nsStyleContext> ret = aStyleContext;
michael@0 1797 return ret.forget();
michael@0 1798 }
michael@0 1799
michael@0 1800 nsIAtom* pseudoTag = aStyleContext->GetPseudo();
michael@0 1801 nsCSSPseudoElements::Type pseudoType = aStyleContext->GetPseudoType();
michael@0 1802 nsRuleNode* ruleNode = aStyleContext->RuleNode();
michael@0 1803
michael@0 1804 // Skip transition rules as needed just like
michael@0 1805 // nsTransitionManager::WalkTransitionRule would.
michael@0 1806 bool skipAnimationRules = PresContext()->IsProcessingRestyles() &&
michael@0 1807 !PresContext()->IsProcessingAnimationStyleChange();
michael@0 1808 if (skipAnimationRules) {
michael@0 1809 // Make sure that we're not using transition rules or animation rules for
michael@0 1810 // our new style context. If we need them, an animation restyle will
michael@0 1811 // provide.
michael@0 1812 ruleNode =
michael@0 1813 SkipAnimationRules(ruleNode, aElement,
michael@0 1814 pseudoType !=
michael@0 1815 nsCSSPseudoElements::ePseudo_NotPseudoElement);
michael@0 1816 }
michael@0 1817
michael@0 1818 nsRuleNode* visitedRuleNode = nullptr;
michael@0 1819 nsStyleContext* visitedContext = aStyleContext->GetStyleIfVisited();
michael@0 1820 // Reparenting a style context just changes where we inherit from,
michael@0 1821 // not what rules we match or what our DOM looks like. In
michael@0 1822 // particular, it doesn't change whether this is a style context for
michael@0 1823 // a link.
michael@0 1824 if (visitedContext) {
michael@0 1825 visitedRuleNode = visitedContext->RuleNode();
michael@0 1826 // Again, skip transition rules as needed
michael@0 1827 if (skipAnimationRules) {
michael@0 1828 // FIXME do something here for animations?
michael@0 1829 visitedRuleNode =
michael@0 1830 SkipAnimationRules(visitedRuleNode, aElement,
michael@0 1831 pseudoType !=
michael@0 1832 nsCSSPseudoElements::ePseudo_NotPseudoElement);
michael@0 1833 }
michael@0 1834 }
michael@0 1835
michael@0 1836 uint32_t flags = eNoFlags;
michael@0 1837 if (aStyleContext->IsLinkContext()) {
michael@0 1838 flags |= eIsLink;
michael@0 1839 }
michael@0 1840
michael@0 1841 // If we're a style context for a link, then we already know whether
michael@0 1842 // our relevant link is visited, since that does not depend on our
michael@0 1843 // parent. Otherwise, we need to match aNewParentContext.
michael@0 1844 bool relevantLinkVisited = aStyleContext->IsLinkContext() ?
michael@0 1845 aStyleContext->RelevantLinkVisited() :
michael@0 1846 aNewParentContext->RelevantLinkVisited();
michael@0 1847
michael@0 1848 if (relevantLinkVisited) {
michael@0 1849 flags |= eIsVisitedLink;
michael@0 1850 }
michael@0 1851
michael@0 1852 if (pseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement ||
michael@0 1853 pseudoType == nsCSSPseudoElements::ePseudo_before ||
michael@0 1854 pseudoType == nsCSSPseudoElements::ePseudo_after) {
michael@0 1855 flags |= eDoAnimation;
michael@0 1856 }
michael@0 1857
michael@0 1858 if (aElement && aElement->IsRootOfAnonymousSubtree()) {
michael@0 1859 // For anonymous subtree roots, don't tweak "display" value based on
michael@0 1860 // whether or not the parent is styled as a flex container. (If the parent
michael@0 1861 // has anonymous-subtree kids, then we know it's not actually going to get
michael@0 1862 // a flex container frame, anyway.)
michael@0 1863 flags |= eSkipFlexItemStyleFixup;
michael@0 1864 }
michael@0 1865
michael@0 1866 return GetContext(aNewParentContext, ruleNode, visitedRuleNode,
michael@0 1867 pseudoTag, pseudoType,
michael@0 1868 aElement, flags);
michael@0 1869 }
michael@0 1870
michael@0 1871 struct MOZ_STACK_CLASS StatefulData : public StateRuleProcessorData {
michael@0 1872 StatefulData(nsPresContext* aPresContext, Element* aElement,
michael@0 1873 EventStates aStateMask, TreeMatchContext& aTreeMatchContext)
michael@0 1874 : StateRuleProcessorData(aPresContext, aElement, aStateMask,
michael@0 1875 aTreeMatchContext),
michael@0 1876 mHint(nsRestyleHint(0))
michael@0 1877 {}
michael@0 1878 nsRestyleHint mHint;
michael@0 1879 };
michael@0 1880
michael@0 1881 struct MOZ_STACK_CLASS StatefulPseudoElementData : public PseudoElementStateRuleProcessorData {
michael@0 1882 StatefulPseudoElementData(nsPresContext* aPresContext, Element* aElement,
michael@0 1883 EventStates aStateMask, nsCSSPseudoElements::Type aPseudoType,
michael@0 1884 TreeMatchContext& aTreeMatchContext, Element* aPseudoElement)
michael@0 1885 : PseudoElementStateRuleProcessorData(aPresContext, aElement, aStateMask,
michael@0 1886 aPseudoType, aTreeMatchContext,
michael@0 1887 aPseudoElement),
michael@0 1888 mHint(nsRestyleHint(0))
michael@0 1889 {}
michael@0 1890 nsRestyleHint mHint;
michael@0 1891 };
michael@0 1892
michael@0 1893 static bool SheetHasDocumentStateStyle(nsIStyleRuleProcessor* aProcessor,
michael@0 1894 void *aData)
michael@0 1895 {
michael@0 1896 StatefulData* data = (StatefulData*)aData;
michael@0 1897 if (aProcessor->HasDocumentStateDependentStyle(data)) {
michael@0 1898 data->mHint = eRestyle_Self;
michael@0 1899 return false; // don't continue
michael@0 1900 }
michael@0 1901 return true; // continue
michael@0 1902 }
michael@0 1903
michael@0 1904 // Test if style is dependent on a document state.
michael@0 1905 bool
michael@0 1906 nsStyleSet::HasDocumentStateDependentStyle(nsPresContext* aPresContext,
michael@0 1907 nsIContent* aContent,
michael@0 1908 EventStates aStateMask)
michael@0 1909 {
michael@0 1910 if (!aContent || !aContent->IsElement())
michael@0 1911 return false;
michael@0 1912
michael@0 1913 TreeMatchContext treeContext(false, nsRuleWalker::eLinksVisitedOrUnvisited,
michael@0 1914 aContent->OwnerDoc());
michael@0 1915 InitStyleScopes(treeContext, aContent->AsElement());
michael@0 1916 StatefulData data(aPresContext, aContent->AsElement(), aStateMask,
michael@0 1917 treeContext);
michael@0 1918 WalkRuleProcessors(SheetHasDocumentStateStyle, &data, true);
michael@0 1919 return data.mHint != 0;
michael@0 1920 }
michael@0 1921
michael@0 1922 static bool SheetHasStatefulStyle(nsIStyleRuleProcessor* aProcessor,
michael@0 1923 void *aData)
michael@0 1924 {
michael@0 1925 StatefulData* data = (StatefulData*)aData;
michael@0 1926 nsRestyleHint hint = aProcessor->HasStateDependentStyle(data);
michael@0 1927 data->mHint = nsRestyleHint(data->mHint | hint);
michael@0 1928 return true; // continue
michael@0 1929 }
michael@0 1930
michael@0 1931 static bool SheetHasStatefulPseudoElementStyle(nsIStyleRuleProcessor* aProcessor,
michael@0 1932 void *aData)
michael@0 1933 {
michael@0 1934 StatefulPseudoElementData* data = (StatefulPseudoElementData*)aData;
michael@0 1935 nsRestyleHint hint = aProcessor->HasStateDependentStyle(data);
michael@0 1936 data->mHint = nsRestyleHint(data->mHint | hint);
michael@0 1937 return true; // continue
michael@0 1938 }
michael@0 1939
michael@0 1940 // Test if style is dependent on content state
michael@0 1941 nsRestyleHint
michael@0 1942 nsStyleSet::HasStateDependentStyle(nsPresContext* aPresContext,
michael@0 1943 Element* aElement,
michael@0 1944 EventStates aStateMask)
michael@0 1945 {
michael@0 1946 TreeMatchContext treeContext(false, nsRuleWalker::eLinksVisitedOrUnvisited,
michael@0 1947 aElement->OwnerDoc());
michael@0 1948 InitStyleScopes(treeContext, aElement);
michael@0 1949 StatefulData data(aPresContext, aElement, aStateMask, treeContext);
michael@0 1950 WalkRuleProcessors(SheetHasStatefulStyle, &data, false);
michael@0 1951 return data.mHint;
michael@0 1952 }
michael@0 1953
michael@0 1954 nsRestyleHint
michael@0 1955 nsStyleSet::HasStateDependentStyle(nsPresContext* aPresContext,
michael@0 1956 Element* aElement,
michael@0 1957 nsCSSPseudoElements::Type aPseudoType,
michael@0 1958 Element* aPseudoElement,
michael@0 1959 EventStates aStateMask)
michael@0 1960 {
michael@0 1961 TreeMatchContext treeContext(false, nsRuleWalker::eLinksVisitedOrUnvisited,
michael@0 1962 aElement->OwnerDoc());
michael@0 1963 InitStyleScopes(treeContext, aElement);
michael@0 1964 StatefulPseudoElementData data(aPresContext, aElement, aStateMask,
michael@0 1965 aPseudoType, treeContext, aPseudoElement);
michael@0 1966 WalkRuleProcessors(SheetHasStatefulPseudoElementStyle, &data, false);
michael@0 1967 return data.mHint;
michael@0 1968 }
michael@0 1969
michael@0 1970 struct MOZ_STACK_CLASS AttributeData : public AttributeRuleProcessorData {
michael@0 1971 AttributeData(nsPresContext* aPresContext,
michael@0 1972 Element* aElement, nsIAtom* aAttribute, int32_t aModType,
michael@0 1973 bool aAttrHasChanged, TreeMatchContext& aTreeMatchContext)
michael@0 1974 : AttributeRuleProcessorData(aPresContext, aElement, aAttribute, aModType,
michael@0 1975 aAttrHasChanged, aTreeMatchContext),
michael@0 1976 mHint(nsRestyleHint(0))
michael@0 1977 {}
michael@0 1978 nsRestyleHint mHint;
michael@0 1979 };
michael@0 1980
michael@0 1981 static bool
michael@0 1982 SheetHasAttributeStyle(nsIStyleRuleProcessor* aProcessor, void *aData)
michael@0 1983 {
michael@0 1984 AttributeData* data = (AttributeData*)aData;
michael@0 1985 nsRestyleHint hint = aProcessor->HasAttributeDependentStyle(data);
michael@0 1986 data->mHint = nsRestyleHint(data->mHint | hint);
michael@0 1987 return true; // continue
michael@0 1988 }
michael@0 1989
michael@0 1990 // Test if style is dependent on content state
michael@0 1991 nsRestyleHint
michael@0 1992 nsStyleSet::HasAttributeDependentStyle(nsPresContext* aPresContext,
michael@0 1993 Element* aElement,
michael@0 1994 nsIAtom* aAttribute,
michael@0 1995 int32_t aModType,
michael@0 1996 bool aAttrHasChanged)
michael@0 1997 {
michael@0 1998 TreeMatchContext treeContext(false, nsRuleWalker::eLinksVisitedOrUnvisited,
michael@0 1999 aElement->OwnerDoc());
michael@0 2000 InitStyleScopes(treeContext, aElement);
michael@0 2001 AttributeData data(aPresContext, aElement, aAttribute,
michael@0 2002 aModType, aAttrHasChanged, treeContext);
michael@0 2003 WalkRuleProcessors(SheetHasAttributeStyle, &data, false);
michael@0 2004 return data.mHint;
michael@0 2005 }
michael@0 2006
michael@0 2007 bool
michael@0 2008 nsStyleSet::MediumFeaturesChanged(nsPresContext* aPresContext)
michael@0 2009 {
michael@0 2010 // We can't use WalkRuleProcessors without a content node.
michael@0 2011 bool stylesChanged = false;
michael@0 2012 for (uint32_t i = 0; i < ArrayLength(mRuleProcessors); ++i) {
michael@0 2013 nsIStyleRuleProcessor *processor = mRuleProcessors[i];
michael@0 2014 if (!processor) {
michael@0 2015 continue;
michael@0 2016 }
michael@0 2017 bool thisChanged = processor->MediumFeaturesChanged(aPresContext);
michael@0 2018 stylesChanged = stylesChanged || thisChanged;
michael@0 2019 }
michael@0 2020 for (uint32_t i = 0; i < mScopedDocSheetRuleProcessors.Length(); ++i) {
michael@0 2021 nsIStyleRuleProcessor *processor = mScopedDocSheetRuleProcessors[i];
michael@0 2022 bool thisChanged = processor->MediumFeaturesChanged(aPresContext);
michael@0 2023 stylesChanged = stylesChanged || thisChanged;
michael@0 2024 }
michael@0 2025
michael@0 2026 if (mBindingManager) {
michael@0 2027 bool thisChanged = false;
michael@0 2028 mBindingManager->MediumFeaturesChanged(aPresContext, &thisChanged);
michael@0 2029 stylesChanged = stylesChanged || thisChanged;
michael@0 2030 }
michael@0 2031
michael@0 2032 return stylesChanged;
michael@0 2033 }
michael@0 2034
michael@0 2035 nsCSSStyleSheet::EnsureUniqueInnerResult
michael@0 2036 nsStyleSet::EnsureUniqueInnerOnCSSSheets()
michael@0 2037 {
michael@0 2038 nsAutoTArray<nsCSSStyleSheet*, 32> queue;
michael@0 2039 for (uint32_t i = 0; i < ArrayLength(gCSSSheetTypes); ++i) {
michael@0 2040 nsCOMArray<nsIStyleSheet> &sheets = mSheets[gCSSSheetTypes[i]];
michael@0 2041 for (uint32_t j = 0, j_end = sheets.Count(); j < j_end; ++j) {
michael@0 2042 nsCSSStyleSheet *sheet = static_cast<nsCSSStyleSheet*>(sheets[j]);
michael@0 2043 queue.AppendElement(sheet);
michael@0 2044 }
michael@0 2045 }
michael@0 2046
michael@0 2047 if (mBindingManager) {
michael@0 2048 mBindingManager->AppendAllSheets(queue);
michael@0 2049 }
michael@0 2050
michael@0 2051 nsCSSStyleSheet::EnsureUniqueInnerResult res =
michael@0 2052 nsCSSStyleSheet::eUniqueInner_AlreadyUnique;
michael@0 2053 while (!queue.IsEmpty()) {
michael@0 2054 uint32_t idx = queue.Length() - 1;
michael@0 2055 nsCSSStyleSheet *sheet = queue[idx];
michael@0 2056 queue.RemoveElementAt(idx);
michael@0 2057
michael@0 2058 nsCSSStyleSheet::EnsureUniqueInnerResult sheetRes =
michael@0 2059 sheet->EnsureUniqueInner();
michael@0 2060 if (sheetRes == nsCSSStyleSheet::eUniqueInner_ClonedInner) {
michael@0 2061 res = sheetRes;
michael@0 2062 }
michael@0 2063
michael@0 2064 // Enqueue all the sheet's children.
michael@0 2065 sheet->AppendAllChildSheets(queue);
michael@0 2066 }
michael@0 2067 return res;
michael@0 2068 }
michael@0 2069
michael@0 2070 nsIStyleRule*
michael@0 2071 nsStyleSet::InitialStyleRule()
michael@0 2072 {
michael@0 2073 if (!mInitialStyleRule) {
michael@0 2074 mInitialStyleRule = new nsInitialStyleRule;
michael@0 2075 }
michael@0 2076 return mInitialStyleRule;
michael@0 2077 }

mercurial