Implement hixie's first-line proposal: only inherit properties that inherit by

default from ::first-line.  Inherit the reset properties from its style parent
(which is the node that we'd inherit from if the ::first-line were not there).
Bug 395623, r+sr=dbaron, a=beltzner


git-svn-id: svn://10.0.0.236/trunk@238907 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
bzbarsky%mit.edu
2007-11-07 17:13:01 +00:00
parent 47847ab457
commit b983f5f096
26 changed files with 493 additions and 14 deletions

View File

@@ -853,7 +853,7 @@ VerifyStyleTree(nsPresContext* aPresContext, nsIFrame* aFrame,
while (child) {
if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW)
|| (child->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)) {
// only do frames that are in flow
// only do frames that don't have placeholders
if (nsGkAtoms::placeholderFrame == child->GetType()) {
// placeholder: first recurse and verify the out of flow frame,
// then verify the placeholder's context
@@ -905,6 +905,15 @@ nsFrameManager::DebugVerifyStyleTree(nsIFrame* aFrame)
nsresult
nsFrameManager::ReParentStyleContext(nsIFrame* aFrame)
{
if (nsGkAtoms::placeholderFrame == aFrame->GetType()) {
// Also reparent the out-of-flow
nsIFrame* outOfFlow =
nsPlaceholderFrame::GetRealFrameForPlaceholder(aFrame);
NS_ASSERTION(outOfFlow, "no out-of-flow frame");
ReParentStyleContext(outOfFlow);
}
// DO NOT verify the style tree before reparenting. The frame
// tree has already been changed, so this check would just fail.
nsStyleContext* oldContext = aFrame->GetStyleContext();
@@ -938,6 +947,16 @@ nsFrameManager::ReParentStyleContext(nsIFrame* aFrame)
newParentContext);
if (newContext) {
if (newContext != oldContext) {
// Make sure to call CalcStyleDifference so that the new context ends
// up resolving all the structs the old context resolved.
nsChangeHint styleChange = oldContext->CalcStyleDifference(newContext);
// The style change is always 0 because we have the same rulenode and
// CalcStyleDifference optimizes us away. That's OK, though:
// reparenting should never trigger a frame reconstruct, and whenever
// it's happening we already plan to reflow and repaint the frames.
NS_ASSERTION(!(styleChange & nsChangeHint_ReconstructFrame),
"Our frame tree is likely to be bogus!");
PRInt32 listIndex = 0;
nsIAtom* childList = nsnull;
nsIFrame* child;
@@ -947,27 +966,22 @@ nsFrameManager::ReParentStyleContext(nsIFrame* aFrame)
do {
child = aFrame->GetFirstChild(childList);
while (child) {
// only do frames that are in flow
if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW)
|| (child->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)) {
// only do frames that don't have placeholders
if ((!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW) ||
(child->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)) &&
child != providerChild) {
#ifdef DEBUG
if (nsGkAtoms::placeholderFrame == child->GetType()) {
// get out of flow frame and recurse there
nsIFrame* outOfFlowFrame =
nsPlaceholderFrame::GetRealFrameForPlaceholder(child);
NS_ASSERTION(outOfFlowFrame, "no out-of-flow frame");
NS_ASSERTION(outOfFlowFrame != providerChild,
"Out of flow provider?");
ReParentStyleContext(outOfFlowFrame);
// reparent placeholder too
ReParentStyleContext(child);
}
else if (child != providerChild) {
// regular frame, not reparented yet
ReParentStyleContext(child);
}
#endif
ReParentStyleContext(child);
}
child = child->GetNextSibling();
@@ -1001,6 +1015,21 @@ nsFrameManager::ReParentStyleContext(nsIFrame* aFrame)
oldExtraContext,
newContext);
if (newExtraContext) {
if (newExtraContext != oldExtraContext) {
// Make sure to call CalcStyleDifference so that the new
// context ends up resolving all the structs the old context
// resolved.
styleChange =
oldExtraContext->CalcStyleDifference(newExtraContext);
// The style change is always 0 because we have the same
// rulenode and CalcStyleDifference optimizes us away. That's
// OK, though: reparenting should never trigger a frame
// reconstruct, and whenever it's happening we already plan to
// reflow and repaint the frames.
NS_ASSERTION(!(styleChange & nsChangeHint_ReconstructFrame),
"Our frame tree is likely to be bogus!");
}
aFrame->SetAdditionalStyleContext(contextIndex, newExtraContext);
}
}

View File

@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html>
<head>
<style>
body { color: red }
body::first-line { color: green; }
</style>
</head>
<body>
This should be green
</body>
</html>

View File

@@ -0,0 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<style>
body { color: green }
</style>
</head>
<body>
This should be green
</body>
</html>

View File

@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html>
<head>
<style>
div { color: green }
</style>
</head>
<body>
<div><span style="float: left">This should be green</span></div>
</body>
</html>

View File

@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head>
<style>
div { color: green }
div::first-line { color: red }
</style>
</head>
<body>
<div><span style="float: left">This should be green</span></div>
</body>
</html>

View File

@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html>
<head>
<style>
div { color: red }
div::first-line { color: green }
</style>
</head>
<body>
<div><span><span style="float: left">This should be green</span></span></div>
</body>
</html>

View File

@@ -0,0 +1,16 @@
<!DOCTYPE html>
<html>
<head>
<style>
div { color: green }
div::first-line { color: red }
</style>
</head>
<body onload="document.getElementById('test').className = ''">
<div>
<span class="some value" style="float: left">
This should be green
</span>
</div>
</body>
</html>

View File

@@ -0,0 +1,22 @@
<!DOCTYPE html>
<html>
<head>
<style>
div { color: green }
div::first-line { color: red }
</style>
<script>
function runTest() {
var s = document.createElement("span");
s.setAttribute("style", "float: left");
s.appendChild(document.createTextNode("This should be green"));
var i = document.getElementById("i");
i.parentNode.insertBefore(s, i);
}
</script>
</head>
<body onload="runTest()">
<div><span id="i"></span></div>
</body>
</html>

View File

@@ -0,0 +1,21 @@
# basic functionality
== basic-1.html basic-ref.html
# handling of out-of-flows when ::first-line happens
== out-of-flow-1a.html out-of-flow-1-ref.html
== out-of-flow-1b.html out-of-flow-1-ref.html
== out-of-flow-1c.html out-of-flow-1-ref.html
fails == out-of-flow-1d.html out-of-flow-1-ref.html # bug 396645
# stress-tests
== stress-1.html about:blank # assertion test
== stress-2.html stress-2-ref.html # assertion + rendering test
== stress-3.html about:blank # assertion test
== stress-4.html about:blank # assertion/crash test
== stress-5.html about:blank # assertion/crash test
== stress-6.html about:blank # assertion/crash test
== stress-7.html about:blank # assertion/crash test
== stress-8.html stress-8-ref.html # assertion/crash test
== stress-9.html stress-9-ref.html # assertion/crash test
== stress-10.html about:blank # crash test
== stress-11.xhtml stress-11-ref.xhtml # crash test

View File

@@ -0,0 +1,41 @@
<!DOCTYPE html>
<html class="reftest-wait">
<head>
<style>
.fl:first-line { }
.inh { position: inherit; }
.abs { position: absolute; }
body { visibility: hidden; }
</style>
<script>
function boom()
{
x = document.getElementById("x");
y = document.getElementById("y");
x.setAttribute('class', "fl abs");
y.setAttribute('class', "inh");
setTimeout(boom2, 5);
}
function boom2()
{
y.setAttribute('class', "abs");
document.body.offsetWidth;
document.documentElement.className = "";
}
</script>
</head>
<body onload="setTimeout(boom, 5);">
<div id="x">
<p id="y">foo</p>
</div>
</body>
</html>

View File

@@ -0,0 +1,5 @@
<style>
*::first-line { }
*::before { content:"before text";}
</style>
<object style="position: fixed;-moz-column-count: 100;"><ol style="float: right;">

View File

@@ -0,0 +1,9 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<style>
*::before { content:"--"; }
</style>
<caption></caption>
<span></span>
This should not crash Mozilla
</html>

View File

@@ -0,0 +1,18 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<style>
*::first-line { }
*::before { content:"--"; }
</style>
<script>
function doe() {
document.getElementsByTagName('caption')[0].removeAttribute('style');
document.documentElement.offsetHeight;
document.getElementsByTagName('span')[0].removeAttribute('style');
}
window.onload=doe;
</script>
<caption style="float: left;"></caption>
<span style="float: right;"></span>
This should not crash Mozilla
</html>

View File

@@ -0,0 +1,10 @@
<!DOCTYPE html>
<html>
<body>
<div>
<b><span>Foo</span></b>
</div>
</body>
</html>

View File

@@ -0,0 +1,26 @@
<!DOCTYPE html>
<html class="reftest-wait">
<head>
<style>
#fl:first-line { }
</style>
<script>
function boom()
{
document.getElementById("s").style.overflow = "auto";
document.body.offsetWidth;
document.documentElement.className = "";
}
</script>
</head>
<body onload="setTimeout(boom, 300);">
<div id="fl">
<b><span id="s">Foo</span></b>
</div>
</body>
</html>

View File

@@ -0,0 +1,35 @@
<!DOCTYPE html>
<html class="reftest-wait" id="fl" style="position: absolute">
<head>
<style>
.flcounter:first-line { content: counter(egg); }
#fl:first-line { }
</style>
<script>
function boom()
{
document.documentElement.appendChild(document.createTextNode("\n"));
document.getElementById("div").style.counterReset = "";
setTimeout(boom2, 20);
}
function boom2()
{
document.body.removeAttribute("class");
document.body.offsetWidth;
document.documentElement.className = "";
}
</script>
</head>
<body style="position: inherit; float: left;" class="flcounter" onload="boom();">
<div id="div" style="counter-reset: chicken;"></div>
</body>
</html>

View File

@@ -0,0 +1,28 @@
<!DOCTYPE html>
<html class="reftest-wait">
<head>
<style>
#a:first-child::first-line { }
body { visibility: hidden; }
</style>
<script>
function runTest() {
document.getElementById("test").removeAttribute('style');
document.body.offsetWidth;
document.documentElement.className = "";
}
</script>
</head><body>
<div style="position:absolute;">
<span id="a" style="position:fixed;">
<span>
<span style="display:table;position:absolute;">
</span>
</span>
Loading this should not crash Mozilla
</span>
</div>
</body></html>

View File

@@ -0,0 +1,25 @@
<!DOCTYPE html>
<html>
<head>
<style>
#b::first-letter { }
#c::first-line { }
</style>
</head>
<body style="visibility: hidden">
This page should not crash Mozilla
<div id="c">
<table>
<div id="b" style="display:table-header-group;">
<q>
text
<div style="position:fixed;">
<q>y</q>
</div>
</q>
</div>
<span style="display: table;"></span>
</div>
</body>
</html>

View File

@@ -0,0 +1,47 @@
<!DOCTYPE html>
<html class="reftest-wait"><head>
<style>
#b td::first-line { font-size:110%;}
nobr::first-line { font-size:110%;}
#b td::after { content:"anonymous text"; }
nobr::after{ content:"anonymous text"; }
#b::before { content:"before text";}
#b td::before { content:"before text";}
body { visibility: hidden; }
</style>
</head>
<body>
<table style="display: table-row;"></table><nobr style="display: list-item; -moz-column-count: 2;">
<table id="b" style="display: inline;"></table>
</nobr>
<br>
This page should not crash Mozilla
<script>
function doe(){
var td = document.createElement('td');;
td.setAttribute('height', '50%');
var tr = document.createElement('tr');;
tr.setAttribute('height', '50%');
tr.appendChild(td);
document.getElementsByTagName('table')[1].appendChild(tr);
document.body.offsetHeight;
var td = document.createElement('td');;
td.setAttribute('height', '50%');
document.getElementsByTagName('tr')[0].appendChild(td);
document.body.offsetHeight;
var td = document.createElement('td');;
td.setAttribute('height', '50%');
document.getElementsByTagName('tr')[0].appendChild(td);
document.body.offsetWidth;
document.documentElement.className = "";
}
setTimeout(doe, 60);
</script>
</body>
</html>

View File

@@ -0,0 +1,17 @@
<!DOCTYPE html>
<html><head>
<style>
body > span::first-line { }
span::before { content:"before text"; border:3px solid black;}
</style>
</head>
<body>
<span style=" float: left; -moz-column-count: 2;">
<span style="float: right;">
<span style=" float: right;-moz-column-count: 2;"></span>
</span>
</span>
</body>
</html>

View File

@@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<body>
<div>
a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a
b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b
a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a
b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b
a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a
b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b
a b a b a b a b a b
</div>
</body>
</html>

View File

@@ -0,0 +1,18 @@
<!DOCTYPE html>
<html>
<head><style>
div:first-line {}
</style></head>
<body>
<div>
a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a
b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b
a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a
b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b
a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a
b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b
a b a b a b a b a b
</div>
</body>
</html>

View File

@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html><head>
<style>
*::after { content:"anonymous text"; }
*::before { content:"before text"; }
</style>
</head>
<body>
<ol style="overflow: hidden; float: right; -moz-column-count: 3;">
<span style="overflow: auto; float: left;"></span>
</ol>
</body>
</html>

View File

@@ -0,0 +1,15 @@
<!DOCTYPE html>
<html><head>
<style>
*::first-line { }
*::after { content:"anonymous text"; }
*::before { content:"before text"; }
</style>
</head>
<body>
<ol style="overflow: hidden; float: right; -moz-column-count: 3;">
<span style="overflow: auto; float: left;"></span>
</ol>
</body>
</html>

View File

@@ -39,6 +39,9 @@ include counters/reftest.list
# first-letter/
include first-letter/reftest.list
# first-line/
include first-line/reftest.list
# svg/
include svg/reftest.list

View File

@@ -1797,6 +1797,11 @@ nsRuleNode::AdjustLogicalBoxProp(nsStyleContext* aContext,
"should not have bothered calling Compute*Data"); \
\
nsStyleContext* parentContext = aContext->GetParent(); \
if (parentContext && \
parentContext->GetPseudoType() == nsCSSPseudoElements::firstLine) { \
/* Reset structs don't inherit from first-line */ \
parentContext = parentContext->GetParent(); \
} \
\
const nsRuleData##rdtype_& rdata_ = \
static_cast<const nsRuleData##rdtype_&>(aData); \