Bug 867454: Treat a flex container's ::before and ::after generated content nodes as flex items. r=bz

This commit is contained in:
Daniel Holbert 2013-05-02 14:04:47 -07:00
parent c5cdc01cec
commit e4d322eb18
10 changed files with 333 additions and 8 deletions

View File

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html>
<head>
<style>
.a { display: flex; }
.a:after { content: 'a'; }
</style>
</head>
<body>
<div class="a"><div></div></div>
</body>
</html>

View File

@ -0,0 +1,14 @@
<!DOCTYPE html>
<html>
<head>
<style>
body::first-line { }
div::after { content: 'A'; }
</style>
</head>
<body>
<div style="display: inline-flex;"> &#x062A;</div>
</body>
</html>

View File

@ -447,6 +447,7 @@ load 810726.html
load 840818.html
test-pref(layout.css.flexbox.enabled,true) load 812822-1.html
asserts(1) test-pref(layout.css.flexbox.enabled,true) load 824297-1.html # bug 399262
test-pref(layout.css.flexbox.enabled,true) load 826483-1.html
asserts(1) test-pref(layout.css.flexbox.enabled,true) load 826532-1.html # bug 399262
test-pref(layout.css.flexbox.enabled,true) load 827168-1.html
load 836895.html
@ -460,3 +461,4 @@ load 849603.html
test-pref(layout.css.flexbox.enabled,true) load 851396-1.html
test-pref(layout.css.flexbox.enabled,true) load 854263-1.html
test-pref(layout.css.flexbox.enabled,true) load 862947-1.html
test-pref(layout.css.flexbox.enabled,true) load 866547-1.html

View File

@ -528,6 +528,24 @@ IsOrderLEQWithDOMFallback(nsIFrame* aFrame1,
return order1 < order2;
}
// If either frame is for generated content from :before or ::after, then
// we can't use nsContentUtils::PositionIsBefore(), since that method won't
// recognize generated content as being an actual sibling of other nodes.
// We know where ::before and ::after nodes *effectively* insert in the DOM
// tree, though (at the beginning & end), so we can just special-case them.
nsIAtom* pseudo1 = aFrame1->StyleContext()->GetPseudo();
nsIAtom* pseudo2 = aFrame2->StyleContext()->GetPseudo();
if (pseudo1 == nsCSSPseudoElements::before ||
pseudo2 == nsCSSPseudoElements::after) {
// frame1 is ::before and/or frame2 is ::after => frame1 is LEQ frame2.
return true;
}
if (pseudo1 == nsCSSPseudoElements::after ||
pseudo2 == nsCSSPseudoElements::before) {
// frame1 is ::after and/or frame2 is ::before => frame1 is not LEQ frame2.
return false;
}
// Same "order" value --> use DOM position.
nsIContent* content1 = GetContentForComparison(aFrame1);
nsIContent* content2 = GetContentForComparison(aFrame2);

View File

@ -0,0 +1,57 @@
<!DOCTYPE html>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!-- Reference case where we've swapped in actual divs (fakeBefore/fakeAfter)
for the testcase's ::before and ::after generated content.
fakeBefore div is always the first child; fakeAfter is always the last.
-->
<html>
<head>
<meta charset="utf-8">
<style>
.flexContainer {
display: flex;
align-items: flex-end;
justify-content: space-between;
height: 50px;
width: 300px;
margin-bottom: 2px;
background: lightgray;
}
.fakeBefore {
align-self: center;
content: 'b';
background: yellow;
}
.fakeAfter {
align-self: center;
content: 'a';
background: lightblue;
}
</style>
</head>
<body>
<div class="flexContainer">
<div class="fakeBefore">b</div>
x
<div>y</div>
z
</div>
<div class="flexContainer">
x
<div>y</div>
z
<div class="fakeAfter">a</div>
</div>
<div class="flexContainer">
<div class="fakeBefore">b</div>
x
<div>y</div>
z
<div class="fakeAfter">a</div>
</div>
</body>
</html>

View File

@ -0,0 +1,52 @@
<!DOCTYPE html>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!-- Testcase to ensure we handle ::before and ::after pseudo-elements on
a flex container and treat them as flex items (e.g. honoring "align-self",
and not merging them into anonymous flex items formed around text).
-->
<html>
<head>
<meta charset="utf-8">
<style>
.flexContainer {
display: flex;
align-items: flex-end;
justify-content: space-between;
height: 50px;
width: 300px;
margin-bottom: 2px;
background: lightgray;
}
div.withBefore::before {
align-self: center;
content: 'b';
background: yellow;
}
div.withAfter::after {
align-self: center;
content: 'a';
background: lightblue;
}
</style>
</head>
<body>
<div class="flexContainer withBefore">
x
<div>y</div>
z
</div>
<div class="flexContainer withAfter">
x
<div>y</div>
z
</div>
<div class="flexContainer withBefore withAfter">
x
<div>y</div>
z
</div>
</body>
</html>

View File

@ -0,0 +1,83 @@
<!DOCTYPE html>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!-- Reference case where we've swapped in actual divs (fakeBefore/fakeAfter)
for the testcase's ::before and ::after generated content.
fakeBefore div is always the first child; fakeAfter is always the last.
-->
<html>
<head>
<meta charset="utf-8">
<style>
.flexContainer {
display: flex;
margin-bottom: 2px;
background: lightgray;
}
.fakeBefore {
background: yellow;
/* This 'order' value should place us after the other elements, visually,
even though we're ::before. */
order: 1;
}
.fakeAfter {
background: lightblue;
order: -1;
}
</style>
</head>
<body>
<!-- 'b' should be at end, due to its high 'order' value: -->
<div class="flexContainer">
<div class="fakeBefore">b</div>
<div>I</div>
</div>
<!-- 'b' should be at beginning, since it's '::before' and the other item has
a matching 'order' value: -->
<div class="flexContainer">
<div class="fakeBefore">b</div>
<div style="order: 1">I</div>
</div>
<!-- 'a' should be at beginning, due to its low 'order' value: -->
<div class="flexContainer">
<div>I</div>
<div class="fakeAfter">a</div>
</div>
<!-- 'a' should be at end, since it's '::after' and the other item has
a matching 'order' value: -->
<div class="flexContainer">
<div style="order: -1">I</div>
<div class="fakeAfter">a</div>
</div>
<!-- As above, the ::after 'a' should be at beginning, and the ::before 'b'
should be at end, due to their 'order' values -->
<div class="flexContainer">
<div class="fakeBefore">b</div>
<div>I</div>
<div class="fakeAfter">a</div>
</div>
<!-- ...but now the normal item "I" has its order increased, so it'll go
at the end. -->
<div class="flexContainer">
<div class="fakeBefore">b</div>
<div style="order: 1">I</div>
<div class="fakeAfter">a</div>
</div>
<!-- ...and now the normal item "I" has its order reduced, so it'll go
at the beginning. -->
<div class="flexContainer">
<div class="fakeBefore">b</div>
<div style="order: -1">I</div>
<div class="fakeAfter">a</div>
</div>
</body>
</html>

View File

@ -0,0 +1,75 @@
<!DOCTYPE html>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!-- Testcase to ensure we handle ::before and ::after pseudo-elements on
a flex container and treat them as flex items (e.g. honoring "order").
-->
<html>
<head>
<meta charset="utf-8">
<style>
.flexContainer {
display: flex;
margin-bottom: 2px;
background: lightgray;
}
.withBefore::before {
content: 'b';
background: yellow;
/* This 'order' value should place us after the other elements, visually,
even though we're ::before. */
order: 1;
}
.withAfter::after {
content: 'a';
background: lightblue;
/* This 'order' value should place us before the other elements, visually,
even though we're ::after. */
order: -1;
}
</style>
</head>
<body>
<!-- 'b' should be at end, due to its high 'order' value: -->
<div class="flexContainer withBefore">
<div>I</div>
</div>
<!-- 'b' should be at beginning, since it's '::before' and the other item has
a matching 'order' value: -->
<div class="flexContainer withBefore">
<div style="order: 1">I</div>
</div>
<!-- 'a' should be at beginning, due to its low 'order' value: -->
<div class="flexContainer withAfter">
<div>I</div>
</div>
<!-- 'b' should be at beginning, since it's '::after' and the other item has
a matching 'order' value: -->
<div class="flexContainer withAfter">
<div style="order: -1">I</div>
</div>
<!-- As above, the ::after 'a' should be at beginning, and the ::before 'b'
should be at end, due to their 'order' values -->
<div class="flexContainer withBefore withAfter">
<div>I</div>
</div>
<!-- ...but now the normal item "I" has its order increased, so it'll go
at the end. -->
<div class="flexContainer withBefore withAfter">
<div style="order: 1">I</div>
</div>
<!-- ...and now the normal item "I" has its order reduced, so it'll go
at the beginning. -->
<div class="flexContainer withBefore withAfter">
<div style="order: -1">I</div>
</div>
</body>
</html>

View File

@ -224,3 +224,7 @@ fuzzy-if(gtk2Widget,1,66) == flexbox-widget-flex-items-1.html flexbox-widget-fle
fuzzy-if(gtk2Widget,1,74) == flexbox-widget-flex-items-2.html flexbox-widget-flex-items-2-ref.html
fuzzy-if(gtk2Widget,1,58) == flexbox-widget-flex-items-3.html flexbox-widget-flex-items-3-ref.html
fuzzy-if(gtk2Widget,1,31) == flexbox-widget-flex-items-4.html flexbox-widget-flex-items-4-ref.html
# Tests for flex containers with pseudo-elements
== flexbox-with-pseuedo-elements-1.html flexbox-with-pseuedo-elements-1-ref.html
== flexbox-with-pseuedo-elements-2.html flexbox-with-pseuedo-elements-2-ref.html

View File

@ -1321,13 +1321,15 @@ nsStyleSet::ResolvePseudoElementStyle(Element* aParentElement,
// For pseudos, |data.IsLink()| being true means that
// our parent node is a link.
// Also: Flex containers shouldn't have pseudo-elements, so given that we're
// looking up pseudo-element style, make sure we're not treating our node as
// a flex item.
uint32_t flags = eSkipFlexItemStyleFixup;
uint32_t flags = eNoFlags;
if (aType == nsCSSPseudoElements::ePseudo_before ||
aType == nsCSSPseudoElements::ePseudo_after) {
flags |= eDoAnimation;
} else {
// Flex containers don't expect to have any pseudo-element children aside
// from ::before and ::after. So if we have such a child, we're not
// actually in a flex container, and we should skip flex-item style fixup.
flags |= eSkipFlexItemStyleFixup;
}
return GetContext(aParentContext, ruleNode, visitedRuleNode,
@ -1387,13 +1389,15 @@ nsStyleSet::ProbePseudoElementStyle(Element* aParentElement,
// For pseudos, |data.IsLink()| being true means that
// our parent node is a link.
// Also: Flex containers shouldn't have pseudo-elements, so given that we're
// looking up pseudo-element style, make sure we're not treating our node as
// a flex item.
uint32_t flags = eSkipFlexItemStyleFixup;
uint32_t flags = eNoFlags;
if (aType == nsCSSPseudoElements::ePseudo_before ||
aType == nsCSSPseudoElements::ePseudo_after) {
flags |= eDoAnimation;
} else {
// Flex containers don't expect to have any pseudo-element children aside
// from ::before and ::after. So if we have such a child, we're not
// actually in a flex container, and we should skip flex-item style fixup.
flags |= eSkipFlexItemStyleFixup;
}
nsRefPtr<nsStyleContext> result =