Bug 1157097 - Don't share a style context that will have its cached style data cleared. r=dbaron

This commit is contained in:
Cameron McCormack 2015-04-29 14:47:15 +10:00
parent e4451c3407
commit 348a675cf6
6 changed files with 72 additions and 2 deletions

View File

@ -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;

View File

@ -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)

View File

@ -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();

View File

@ -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

View File

@ -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'

View File

@ -0,0 +1,31 @@
<!DOCTYPE html>
<title>Test for bug 1157097</title>
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
<style>
.blue { color: blue; }
.red { color: red; }
.inline-block { display: inline-block; }
</style>
<body onload=run()>
<p><span id=s1 class=blue><b></b></span><span id=s2 class=red><b></b></span></p>
<script>
var Ci = Components.interfaces;
var windowUtils = window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
function run() {
windowUtils.postRestyleSelfEvent(document.querySelector("p"));
document.querySelectorAll("span")[0].className = "";
document.querySelectorAll("b")[0].className = "inline-block";
document.querySelectorAll("span")[1].className = "blue";
windowUtils.postRestyleSelfEvent(document.querySelectorAll("b")[1]);
document.body.offsetTop;
ok(true, "finished (hopefully we didn't assert)");
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
</script>