diff --git a/layout/base/RestyleManager.cpp b/layout/base/RestyleManager.cpp index 591aa1d3e861..719c76f70e5e 100644 --- a/layout/base/RestyleManager.cpp +++ b/layout/base/RestyleManager.cpp @@ -2877,6 +2877,12 @@ ElementRestyler::Restyle(nsRestyleHint aRestyleHint) // to the style context (as is done by nsTransformedTextRun objects, which // can be referenced by a text frame's mTextRun longer than the frame's // mStyleContext). + // + // Also, we don't want this style context to get any more uses by being + // returned from nsStyleContext::FindChildWithRules, so we add the + // NS_STYLE_INELIGIBLE_FOR_SHARING bit to it. + oldContext->SetIneligibleForSharing(); + ContextToClear* toClear = mContextsToClear.AppendElement(); toClear->mStyleContext = Move(oldContext); toClear->mStructs = swappedStructs; diff --git a/layout/style/nsStyleContext.cpp b/layout/style/nsStyleContext.cpp index 2b4f5c7c56e4..2a9ae073eecb 100644 --- a/layout/style/nsStyleContext.cpp +++ b/layout/style/nsStyleContext.cpp @@ -351,7 +351,7 @@ nsStyleContext::FindChildWithRules(const nsIAtom* aPseudoTag, } else { match = !child->GetStyleIfVisited(); } - if (match) { + if (match && !(child->mBits & NS_STYLE_INELIGIBLE_FOR_SHARING)) { result = child; break; } @@ -1404,6 +1404,29 @@ nsStyleContext::DoClearCachedInheritedStyleDataOnDescendants(uint32_t aStructs) ClearCachedInheritedStyleDataOnDescendants(aStructs); } +void +nsStyleContext::SetIneligibleForSharing() +{ + if (mBits & NS_STYLE_INELIGIBLE_FOR_SHARING) { + return; + } + mBits |= NS_STYLE_INELIGIBLE_FOR_SHARING; + if (mChild) { + nsStyleContext* child = mChild; + do { + child->SetIneligibleForSharing(); + child = child->mNextSibling; + } while (mChild != child); + } + if (mEmptyChild) { + nsStyleContext* child = mEmptyChild; + do { + child->SetIneligibleForSharing(); + child = child->mNextSibling; + } while (mEmptyChild != child); + } +} + #ifdef RESTYLE_LOGGING nsCString nsStyleContext::GetCachedStyleDataAsString(uint32_t aStructs) diff --git a/layout/style/nsStyleContext.h b/layout/style/nsStyleContext.h index f0cf8e418598..33ba5699a3a1 100644 --- a/layout/style/nsStyleContext.h +++ b/layout/style/nsStyleContext.h @@ -431,6 +431,13 @@ public: */ void ClearCachedInheritedStyleDataOnDescendants(uint32_t aStructs); + /** + * Sets the NS_STYLE_INELIGIBLE_FOR_SHARING bit on this style context + * and its descendants. If it finds a descendant that has the bit + * already set, assumes that it can skip that subtree. + */ + void SetIneligibleForSharing(); + #ifdef DEBUG void List(FILE* out, int32_t aIndent, bool aListDescendants = true); static void AssertStyleStructMaxDifferenceValid(); diff --git a/layout/style/nsStyleStruct.h b/layout/style/nsStyleStruct.h index 2678c8ed6edf..a122b7ec6776 100644 --- a/layout/style/nsStyleStruct.h +++ b/layout/style/nsStyleStruct.h @@ -60,8 +60,10 @@ class imgIContainer; #define NS_STYLE_SUPPRESS_LINEBREAK 0x080000000 // See nsStyleContext::IsInDisplayNoneSubtree #define NS_STYLE_IN_DISPLAY_NONE_SUBTREE 0x100000000 +// See nsStyleContext::FindChildWithRules +#define NS_STYLE_INELIGIBLE_FOR_SHARING 0x200000000 // See nsStyleContext::GetPseudoEnum -#define NS_STYLE_CONTEXT_TYPE_SHIFT 33 +#define NS_STYLE_CONTEXT_TYPE_SHIFT 34 // Additional bits for nsRuleNode's mDependentBits: #define NS_RULE_NODE_GC_MARK 0x02000000 diff --git a/layout/style/test/chrome/chrome.ini b/layout/style/test/chrome/chrome.ini index 5faaf82ffa19..7016d8561755 100644 --- a/layout/style/test/chrome/chrome.ini +++ b/layout/style/test/chrome/chrome.ini @@ -9,6 +9,7 @@ support-files = [test_addSheet.html] [test_additional_sheets.html] [test_author_specified_style.html] +[test_bug1157097.html] [test_bug535806.xul] [test_hover.html] skip-if = buildapp == 'mulet' diff --git a/layout/style/test/chrome/test_bug1157097.html b/layout/style/test/chrome/test_bug1157097.html new file mode 100644 index 000000000000..748a9eed2dae --- /dev/null +++ b/layout/style/test/chrome/test_bug1157097.html @@ -0,0 +1,31 @@ + +
+