зеркало из https://github.com/mozilla/gecko-dev.git
Bug 696253, patch 5: implement parsing/computation for CSS property 'align-self'. r=dbaron
This commit is contained in:
Родитель
85e8349a15
Коммит
0dd40b90f7
|
@ -765,6 +765,9 @@ interface nsIDOMCSS2Properties : nsISupports
|
|||
attribute DOMString MozAlignItems;
|
||||
// raises(DOMException) on setting
|
||||
|
||||
attribute DOMString MozAlignSelf;
|
||||
// raises(DOMException) on setting
|
||||
|
||||
attribute DOMString MozFlexDirection;
|
||||
// raises(DOMException) on setting
|
||||
|
||||
|
|
|
@ -408,6 +408,12 @@ static inline mozilla::css::Side operator++(mozilla::css::Side& side, int) {
|
|||
// For convenience/clarity (since we use this default value in multiple places)
|
||||
#define NS_STYLE_ALIGN_ITEMS_INITIAL_VALUE NS_STYLE_ALIGN_ITEMS_STRETCH
|
||||
|
||||
// The "align-self" property accepts all of the normal "align-items" values
|
||||
// (above) plus a special 'auto' value that computes to the parent's
|
||||
// "align-items" value. Our computed style code internally represents 'auto'
|
||||
// with this enum until we actually evaluate it:
|
||||
#define NS_STYLE_ALIGN_SELF_AUTO 5
|
||||
|
||||
// See nsStylePosition
|
||||
#define NS_STYLE_FLEX_DIRECTION_ROW 0
|
||||
#define NS_STYLE_FLEX_DIRECTION_ROW_REVERSE 1
|
||||
|
|
|
@ -1522,6 +1522,16 @@ CSS_PROP_POSITION(
|
|||
kAlignItemsKTable,
|
||||
offsetof(nsStylePosition, mAlignItems),
|
||||
eStyleAnimType_EnumU8)
|
||||
CSS_PROP_POSITION(
|
||||
-moz-align-self,
|
||||
align_self,
|
||||
CSS_PROP_DOMPROP_PREFIXED(AlignSelf),
|
||||
CSS_PROPERTY_PARSE_VALUE,
|
||||
"",
|
||||
VARIANT_HK,
|
||||
kAlignSelfKTable,
|
||||
offsetof(nsStylePosition, mAlignSelf),
|
||||
eStyleAnimType_EnumU8)
|
||||
CSS_PROP_POSITION(
|
||||
-moz-flex-direction,
|
||||
flex_direction,
|
||||
|
|
|
@ -912,6 +912,17 @@ const PRInt32 nsCSSProps::kAlignItemsKTable[] = {
|
|||
eCSSKeyword_UNKNOWN,-1
|
||||
};
|
||||
|
||||
// Note: 'align-self' takes the same keywords as 'align-items', plus 'auto'.
|
||||
const PRInt32 nsCSSProps::kAlignSelfKTable[] = {
|
||||
eCSSKeyword_flex_start, NS_STYLE_ALIGN_ITEMS_FLEX_START,
|
||||
eCSSKeyword_flex_end, NS_STYLE_ALIGN_ITEMS_FLEX_END,
|
||||
eCSSKeyword_center, NS_STYLE_ALIGN_ITEMS_CENTER,
|
||||
eCSSKeyword_baseline, NS_STYLE_ALIGN_ITEMS_BASELINE,
|
||||
eCSSKeyword_stretch, NS_STYLE_ALIGN_ITEMS_STRETCH,
|
||||
eCSSKeyword_auto, NS_STYLE_ALIGN_SELF_AUTO,
|
||||
eCSSKeyword_UNKNOWN,-1
|
||||
};
|
||||
|
||||
const PRInt32 nsCSSProps::kFlexDirectionKTable[] = {
|
||||
eCSSKeyword_row, NS_STYLE_FLEX_DIRECTION_ROW,
|
||||
eCSSKeyword_row_reverse, NS_STYLE_FLEX_DIRECTION_ROW_REVERSE,
|
||||
|
|
|
@ -352,6 +352,7 @@ public:
|
|||
static const PRInt32 kEmptyCellsKTable[];
|
||||
#ifdef MOZ_FLEXBOX
|
||||
static const PRInt32 kAlignItemsKTable[];
|
||||
static const PRInt32 kAlignSelfKTable[];
|
||||
static const PRInt32 kFlexDirectionKTable[];
|
||||
static const PRInt32 kJustifyContentKTable[];
|
||||
#endif // MOZ_FLEXBOX
|
||||
|
|
|
@ -2935,6 +2935,32 @@ nsComputedDOMStyle::DoGetAlignItems()
|
|||
return val;
|
||||
}
|
||||
|
||||
nsIDOMCSSValue*
|
||||
nsComputedDOMStyle::DoGetAlignSelf()
|
||||
{
|
||||
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
|
||||
PRUint8 computedAlignSelf = GetStylePosition()->mAlignSelf;
|
||||
|
||||
if (computedAlignSelf == NS_STYLE_ALIGN_SELF_AUTO) {
|
||||
// "align-self: auto" needs to compute to parent's align-items value.
|
||||
nsStyleContext* parentStyleContext = mStyleContextHolder->GetParent();
|
||||
if (parentStyleContext) {
|
||||
computedAlignSelf =
|
||||
parentStyleContext->GetStylePosition()->mAlignItems;
|
||||
} else {
|
||||
// No parent --> use default.
|
||||
computedAlignSelf = NS_STYLE_ALIGN_ITEMS_INITIAL_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
NS_ABORT_IF_FALSE(computedAlignSelf != NS_STYLE_ALIGN_SELF_AUTO,
|
||||
"Should have swapped out 'auto' for something non-auto");
|
||||
val->SetIdent(
|
||||
nsCSSProps::ValueToKeywordEnum(computedAlignSelf,
|
||||
nsCSSProps::kAlignSelfKTable));
|
||||
return val;
|
||||
}
|
||||
|
||||
nsIDOMCSSValue*
|
||||
nsComputedDOMStyle::DoGetFlexDirection()
|
||||
{
|
||||
|
@ -4651,6 +4677,7 @@ nsComputedDOMStyle::GetQueryablePropertyMap(PRUint32* aLength)
|
|||
|
||||
#ifdef MOZ_FLEXBOX
|
||||
COMPUTED_STYLE_MAP_ENTRY(align_items, AlignItems),
|
||||
COMPUTED_STYLE_MAP_ENTRY(align_self, AlignSelf),
|
||||
#endif // MOZ_FLEXBOX
|
||||
COMPUTED_STYLE_MAP_ENTRY(animation_delay, AnimationDelay),
|
||||
COMPUTED_STYLE_MAP_ENTRY(animation_direction, AnimationDirection),
|
||||
|
|
|
@ -360,6 +360,7 @@ private:
|
|||
#ifdef MOZ_FLEXBOX
|
||||
/* CSS Flexbox properties */
|
||||
nsIDOMCSSValue* DoGetAlignItems();
|
||||
nsIDOMCSSValue* DoGetAlignSelf();
|
||||
nsIDOMCSSValue* DoGetFlexDirection();
|
||||
nsIDOMCSSValue* DoGetOrder();
|
||||
nsIDOMCSSValue* DoGetJustifyContent();
|
||||
|
|
|
@ -6431,6 +6431,60 @@ nsRuleNode::ComputePositionData(void* aStartStruct,
|
|||
SETDSC_ENUMERATED, parentPos->mAlignItems,
|
||||
NS_STYLE_ALIGN_ITEMS_INITIAL_VALUE, 0, 0, 0, 0);
|
||||
|
||||
// align-self: enum, inherit, initial
|
||||
// NOTE: align-self's initial value is the special keyword "auto", which is
|
||||
// supposed to compute to our parent's computed value of "align-items". So
|
||||
// technically, "auto" itself is never a valid computed value for align-self,
|
||||
// since it always computes to something else. Despite that, we do actually
|
||||
// store "auto" in nsStylePosition::mAlignSelf, as NS_STYLE_ALIGN_SELF_AUTO
|
||||
// (and then resolve it as-necessary). We do this because "auto" is the
|
||||
// initial value for this property, so if we were to actually resolve it in
|
||||
// nsStylePosition, we'd never be able to share any nsStylePosition structs
|
||||
// in the rule tree, since their mAlignSelf values would depend on the parent
|
||||
// style, by default.
|
||||
if (aRuleData->ValueForAlignSelf()->GetUnit() == eCSSUnit_Inherit) {
|
||||
// Special handling for "align-self: inherit", in case we're inheriting
|
||||
// "align-self: auto", in which case we need to resolve the parent's "auto"
|
||||
// and inherit that resolved value.
|
||||
PRUint8 inheritedAlignSelf = parentPos->mAlignSelf;
|
||||
if (inheritedAlignSelf == NS_STYLE_ALIGN_SELF_AUTO) {
|
||||
if (parentPos == pos) {
|
||||
// We're the root node. (If we weren't, COMPUTE_START_RESET would've
|
||||
// given us a distinct parentPos, since we've got an 'inherit' value.)
|
||||
// Nothing to inherit from --> just use default value.
|
||||
inheritedAlignSelf = NS_STYLE_ALIGN_ITEMS_INITIAL_VALUE;
|
||||
} else {
|
||||
// Our parent's "auto" value should resolve to our grandparent's value
|
||||
// for "align-items". So, that's what we're supposed to inherit.
|
||||
NS_ABORT_IF_FALSE(aContext->GetParent(),
|
||||
"we've got a distinct parent style-struct already, "
|
||||
"so we should have a parent style-context");
|
||||
nsStyleContext* grandparentContext = aContext->GetParent()->GetParent();
|
||||
if (!grandparentContext) {
|
||||
// No grandparent --> our parent is the root node, so its
|
||||
// "align-self: auto" computes to the default "align-items" value:
|
||||
inheritedAlignSelf = NS_STYLE_ALIGN_ITEMS_INITIAL_VALUE;
|
||||
} else {
|
||||
// Normal case -- we have a grandparent.
|
||||
// Its "align-items" value is what we should end up inheriting.
|
||||
const nsStylePosition* grandparentPos =
|
||||
grandparentContext->GetStylePosition();
|
||||
inheritedAlignSelf = grandparentPos->mAlignItems;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pos->mAlignSelf = inheritedAlignSelf;
|
||||
canStoreInRuleTree = false;
|
||||
} else {
|
||||
SetDiscrete(*aRuleData->ValueForAlignSelf(),
|
||||
pos->mAlignSelf, canStoreInRuleTree,
|
||||
SETDSC_ENUMERATED,
|
||||
parentPos->mAlignSelf, // (unused -- we handled inherit above)
|
||||
NS_STYLE_ALIGN_SELF_AUTO, // initial == auto
|
||||
0, 0, 0, 0);
|
||||
}
|
||||
|
||||
// flex-direction: enum, inherit, initial
|
||||
SetDiscrete(*aRuleData->ValueForFlexDirection(),
|
||||
pos->mFlexDirection, canStoreInRuleTree,
|
||||
|
|
|
@ -1127,6 +1127,7 @@ nsStylePosition::nsStylePosition(void)
|
|||
mBoxSizing = NS_STYLE_BOX_SIZING_CONTENT;
|
||||
#ifdef MOZ_FLEXBOX
|
||||
mAlignItems = NS_STYLE_ALIGN_ITEMS_INITIAL_VALUE;
|
||||
mAlignSelf = NS_STYLE_ALIGN_SELF_AUTO;
|
||||
mFlexDirection = NS_STYLE_FLEX_DIRECTION_ROW;
|
||||
mJustifyContent = NS_STYLE_JUSTIFY_CONTENT_FLEX_START;
|
||||
mOrder = NS_STYLE_ORDER_INITIAL;
|
||||
|
@ -1160,7 +1161,8 @@ nsChangeHint nsStylePosition::CalcDifference(const nsStylePosition& aOther) cons
|
|||
// NOTE: Changes to "order" on a flex item may trigger some repositioning.
|
||||
// If we're in a multi-line flex container, it also may affect our size
|
||||
// (and that of our container & siblings) by shuffling items between lines.
|
||||
if (mOrder != aOther.mOrder) {
|
||||
if (mAlignSelf != aOther.mAlignSelf ||
|
||||
mOrder != aOther.mOrder) {
|
||||
return NS_CombineHint(hint, nsChangeHint_ReflowFrame);
|
||||
}
|
||||
|
||||
|
|
|
@ -1095,6 +1095,7 @@ struct nsStylePosition {
|
|||
PRUint8 mBoxSizing; // [reset] see nsStyleConsts.h
|
||||
#ifdef MOZ_FLEXBOX
|
||||
PRUint8 mAlignItems; // [reset] see nsStyleConsts.h
|
||||
PRUint8 mAlignSelf; // [reset] see nsStyleConsts.h
|
||||
PRUint8 mFlexDirection; // [reset] see nsStyleConsts.h
|
||||
PRUint8 mJustifyContent; // [reset] see nsStyleConsts.h
|
||||
PRInt32 mOrder; // [reset] integer
|
||||
|
|
|
@ -202,6 +202,12 @@ _TEST_FILES = test_acid3_test46.html \
|
|||
test_bug721136.html \
|
||||
$(NULL)
|
||||
|
||||
ifdef MOZ_FLEXBOX
|
||||
_TEST_FILES += \
|
||||
test_flexbox_align_self_auto.html \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
_VISITED_REFTEST_FILES = \
|
||||
$(shell find $(topsrcdir)/layout/reftests/css-visited/ -name '*.html' -o -name '*.xhtml') \
|
||||
$(topsrcdir)/layout/reftests/svg/pseudo-classes-02.svg \
|
||||
|
|
|
@ -746,6 +746,15 @@ var gCSSProperties = {
|
|||
other_values: [ "flex-start", "flex-end", "center", "baseline" ],
|
||||
invalid_values: [ "space-between", "abc", "30px" ]
|
||||
},
|
||||
"-moz-align-self": {
|
||||
domProp: "MozAlignSelf",
|
||||
inherited: false,
|
||||
type: CSS_TYPE_LONGHAND,
|
||||
// (Assuming defaults on the parent, 'auto' will compute to 'stretch'.)
|
||||
initial_values: [ "auto", "stretch" ],
|
||||
other_values: [ "flex-start", "flex-end", "center", "baseline" ],
|
||||
invalid_values: [ "space-between", "abc", "30px" ]
|
||||
},
|
||||
"-moz-flex-direction": {
|
||||
domProp: "MozFlexDirection",
|
||||
inherited: false,
|
||||
|
|
|
@ -0,0 +1,216 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=696253
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test behavior of 'align-self:auto' (Bug 696253)</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<style type="text/css">
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=696253">Mozilla Bug 696253</a>
|
||||
<div id="display">
|
||||
<div id="myDiv"></div>
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Test behavior of 'align-self:auto' (Bug 696253)
|
||||
* ===============================================
|
||||
*
|
||||
* The value "align-self: auto" is special. It's the initial value for
|
||||
* "align-self", and it's supposed to compute to the parent's "align-items" value.
|
||||
*
|
||||
* However, to allow its style-struct to be shared by default, we internally
|
||||
* make it compute to a special "auto" enumerated value, and then we resolve that
|
||||
* to the correct value by examining the parent's style struct whenever we actually
|
||||
* need to use it.
|
||||
*
|
||||
* This test makes sure that optimization isn't detectable to content.
|
||||
*
|
||||
* One special case of this is inheritance -- e.g.:
|
||||
*
|
||||
* <html style="align-items: baseline">
|
||||
* <body style="align-self: auto; align-items: center">
|
||||
* <div style="align-self: inherit">
|
||||
*
|
||||
* In that example, the child div's "inherit" should get the _computed_ value
|
||||
* of "align-self" on the body. That, in turn, is "auto", so it should compute to
|
||||
* its parent's "align-items" value, which is "baseline". So we need to end up
|
||||
* with a computed "align-self" value of "baseline" on the child.
|
||||
*
|
||||
* (NOTE: if we instead allowed the child div to directly inherit the value "auto"
|
||||
* from its parent, then we'd get different & incorrect behavior. The div would
|
||||
* resolve that inherited "auto" value to its own parent's "align-items" value,
|
||||
* which is "center" -- not "baseline".)
|
||||
*
|
||||
* This mochitest tests that situation and a few other similar tricky situations.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Utility function for getting computed style of "align-self":
|
||||
*/
|
||||
function getComputedAlignSelf(elem) {
|
||||
return window.getComputedStyle(elem, "").MozAlignSelf;
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests that are useful regardless of whether we have a parent node:
|
||||
*/
|
||||
function testGeneralNode(elem) {
|
||||
// Test initial computed style
|
||||
// (Initial value should be 'auto', which should compute to 'stretch')
|
||||
is(getComputedAlignSelf(elem), "stretch",
|
||||
"initial computed value of 'align-self' should be 'stretch', " +
|
||||
"if we haven't explicitly set any style on the parent");
|
||||
|
||||
// Test value after setting align-self explicitly to "auto"
|
||||
elem.style.MozAlignSelf = "auto";
|
||||
is(getComputedAlignSelf(elem), "stretch",
|
||||
"computed value of 'align-self: auto' should be 'stretch', " +
|
||||
"if we haven't explicitly set any style on the parent");
|
||||
elem.style.MozAlignSelf = ""; // clean up
|
||||
|
||||
// Test value after setting align-self explicitly to "inherit"
|
||||
elem.style.MozAlignSelf = "inherit";
|
||||
is(getComputedAlignSelf(elem), "stretch",
|
||||
"computed value of 'align-self: inherit' should be 'stretch', " +
|
||||
"if we haven't explicitly set any style on the parent");
|
||||
elem.style.MozAlignSelf = ""; // clean up
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests that depend on us having a parent node:
|
||||
*/
|
||||
function testNodeThatHasParent(elem) {
|
||||
// Sanity-check that we actually do have a styleable parent:
|
||||
ok(elem.parentNode && elem.parentNode.style,
|
||||
"bug in test -- expecting caller to pass us a node with a parent");
|
||||
|
||||
// Test initial computed style when "align-items" has been set on our parent.
|
||||
// (elem's initial "align-self" value should be "auto", which should compute
|
||||
// to its parent's "align-items" value, which in this case is "center".)
|
||||
elem.parentNode.style.MozAlignItems = "center";
|
||||
is(getComputedAlignSelf(elem), "center",
|
||||
"initial computed value of 'align-self' should match parent's " +
|
||||
"specified 'align-items' value");
|
||||
|
||||
// ...and now test computed style after setting "align-self" explicitly to
|
||||
// "auto" (with parent "align-items" still at "center")
|
||||
elem.style.MozAlignSelf = "auto";
|
||||
is(getComputedAlignSelf(elem), "center",
|
||||
"computed value of 'align-self: auto' should match parent's " +
|
||||
"specified 'align-items' value");
|
||||
|
||||
elem.style.MozAlignSelf = ""; // clean up
|
||||
elem.parentNode.style.MozAlignItems = ""; // clean up
|
||||
|
||||
// Finally: test computed style after setting "align-self" to "inherit"
|
||||
// and leaving parent at its initial value (which should be "auto", which
|
||||
// should compute to "stretch")
|
||||
elem.style.MozAlignSelf = "inherit";
|
||||
is(getComputedAlignSelf(elem), "stretch",
|
||||
"computed value of 'align-self: inherit' should take parent's " +
|
||||
"computed 'align-self' value (which should be 'stretch', " +
|
||||
"if we haven't explicitly set any other style");
|
||||
elem.style.MozAlignSelf = ""; // clean up
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests that depend on us having a grandparent node:
|
||||
*/
|
||||
function testNodeThatHasGrandparent(elem) {
|
||||
// Sanity-check that we actually do have a styleable grandparent:
|
||||
ok(elem.parentNode && elem.parentNode.parentNode &&
|
||||
elem.parentNode.parentNode.style,
|
||||
"bug in test -- should be getting a node with a grandparent");
|
||||
|
||||
// Test computed "align-self" after we set "align-self" to "inherit" on our elem
|
||||
// and to "auto" on its parent, and "align-items" to "baseline" on its
|
||||
// grandparent. The parent's "auto" value should resolve to "baseline", and
|
||||
// that's what our elem should inherit.
|
||||
|
||||
elem.style.MozAlignSelf = "inherit";
|
||||
elem.parentNode.style.MozAlignSelf = "auto";
|
||||
elem.parentNode.parentNode.style.MozAlignItems = "baseline";
|
||||
|
||||
is(getComputedAlignSelf(elem), "baseline",
|
||||
"computed value of 'align-self:inherit' on node when parent has " +
|
||||
"'align-self:auto' and grandparent has 'align-items:baseline'")
|
||||
|
||||
// clean up:
|
||||
elem.style.MozAlignSelf = "";
|
||||
elem.parentNode.style.MozAlignSelf = "";
|
||||
elem.parentNode.parentNode.style.MozAlignItems = "";
|
||||
|
||||
// Test computed "align-self" after we set it to "auto" on our node, set
|
||||
// "align-items" to "inherit" on its parent, and "align-items" to "baseline"
|
||||
// on its grandparent. The parent's "inherit" should compute to "baseline",
|
||||
// and our elem's "auto" value should resolve to that.
|
||||
elem.style.MozAlignSelf = "auto";
|
||||
elem.parentNode.style.MozAlignItems = "inherit";
|
||||
elem.parentNode.parentNode.style.MozAlignItems = "baseline";
|
||||
is(getComputedAlignSelf(elem), "baseline",
|
||||
"computed value of 'align-self:auto on node when parent has " +
|
||||
"'align-items:inherit' and grandparent has 'align-items:baseline'")
|
||||
|
||||
// clean up:
|
||||
elem.style.MozAlignSelf = "";
|
||||
elem.parentNode.style.MozAlignItems = "";
|
||||
elem.parentNode.parentNode.style.MozAlignItems = "";
|
||||
}
|
||||
|
||||
/*
|
||||
* Main test function
|
||||
*/
|
||||
function main() {
|
||||
// Test the root node
|
||||
// ==================
|
||||
// (It's special because it has no parent style context.)
|
||||
|
||||
var rootNode = document.documentElement;
|
||||
|
||||
// Sanity-check that we actually have the root node, as far as CSS is concerned.
|
||||
// (Note: rootNode.parentNode is a HTMLDocument object -- not an element that
|
||||
// we inherit style from.)
|
||||
ok(!rootNode.parentNode.style,
|
||||
"expecting root node to have no node to inherit style from");
|
||||
|
||||
testGeneralNode(rootNode);
|
||||
|
||||
// Test the body node
|
||||
// ==================
|
||||
// (It's special because it has no grandparent style context.)
|
||||
|
||||
var body = document.getElementsByTagName("body")[0];
|
||||
is(body.parentNode, document.documentElement,
|
||||
"expecting body element's parent to be the root node");
|
||||
|
||||
testGeneralNode(body);
|
||||
testNodeThatHasParent(body);
|
||||
|
||||
// Test the <div id="display"> node
|
||||
// ================================
|
||||
// (It has both a parent and a grandparent style context.)
|
||||
|
||||
var displayNode = document.getElementById("display");
|
||||
is(displayNode.parentNode.parentNode, document.documentElement,
|
||||
"expecting 'display' node's grandparent to be the root node");
|
||||
|
||||
testGeneralNode(displayNode);
|
||||
testNodeThatHasParent(displayNode);
|
||||
testNodeThatHasGrandparent(displayNode);
|
||||
}
|
||||
|
||||
main();
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
Загрузка…
Ссылка в новой задаче