зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1176792 part 1 - [css-grid] Implement the 'grid-column-gap', 'grid-row-gap', and 'grid-gap' properties in the style system. r=dholbert,dbaron
This commit is contained in:
Родитель
a852415412
Коммит
0edbd4ad4c
|
@ -1019,6 +1019,18 @@ Declaration::GetValue(nsCSSProperty aProperty, nsAString& aValue,
|
|||
// This can express either grid-template-{areas,columns,rows}
|
||||
// or grid-auto-{flow,columns,rows}, but not both.
|
||||
case eCSSProperty_grid: {
|
||||
const nsCSSValue& columnGapValue =
|
||||
*data->ValueFor(eCSSProperty_grid_column_gap);
|
||||
if (columnGapValue.GetUnit() != eCSSUnit_Pixel ||
|
||||
columnGapValue.GetFloatValue() != 0.0f) {
|
||||
return; // Not serializable, bail.
|
||||
}
|
||||
const nsCSSValue& rowGapValue =
|
||||
*data->ValueFor(eCSSProperty_grid_row_gap);
|
||||
if (rowGapValue.GetUnit() != eCSSUnit_Pixel ||
|
||||
rowGapValue.GetFloatValue() != 0.0f) {
|
||||
return; // Not serializable, bail.
|
||||
}
|
||||
const nsCSSValue& areasValue =
|
||||
*data->ValueFor(eCSSProperty_grid_template_areas);
|
||||
const nsCSSValue& columnsValue =
|
||||
|
@ -1151,6 +1163,25 @@ Declaration::GetValue(nsCSSProperty aProperty, nsAString& aValue,
|
|||
}
|
||||
break;
|
||||
}
|
||||
case eCSSProperty_grid_gap: {
|
||||
const nsCSSProperty* subprops =
|
||||
nsCSSProps::SubpropertyEntryFor(aProperty);
|
||||
MOZ_ASSERT(subprops[2] == eCSSProperty_UNKNOWN,
|
||||
"must have exactly two subproperties");
|
||||
|
||||
nsAutoString val1, val2;
|
||||
AppendValueToString(subprops[0], val1, aSerialization);
|
||||
AppendValueToString(subprops[1], val2, aSerialization);
|
||||
if (val1 == val2) {
|
||||
aValue.Append(val1);
|
||||
} else {
|
||||
aValue.Append(val1);
|
||||
aValue.Append(' ');
|
||||
aValue.Append(val2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case eCSSProperty__moz_transform: {
|
||||
// shorthands that are just aliases with different parsing rules
|
||||
const nsCSSProperty* subprops =
|
||||
|
|
|
@ -960,6 +960,7 @@ protected:
|
|||
bool ParseGridColumnRow(nsCSSProperty aStartPropID,
|
||||
nsCSSProperty aEndPropID);
|
||||
bool ParseGridArea();
|
||||
bool ParseGridGap();
|
||||
|
||||
// parsing 'align/justify-items/self' from the css-align spec
|
||||
bool ParseAlignJustifyPosition(nsCSSValue& aResult,
|
||||
|
@ -9146,6 +9147,13 @@ CSSParserImpl::ParseGrid()
|
|||
return false;
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/css-grid/#grid-shorthand
|
||||
// "Also, the gutter properties are reset by this shorthand,
|
||||
// even though they can't be set by it."
|
||||
value.SetFloatValue(0.0f, eCSSUnit_Pixel);
|
||||
AppendValue(eCSSProperty_grid_column_gap, value);
|
||||
AppendValue(eCSSProperty_grid_row_gap, value);
|
||||
|
||||
// The values starts with a <'grid-auto-flow'> if and only if
|
||||
// it starts with a 'dense', 'column' or 'row' keyword.
|
||||
if (mToken.mType == eCSSToken_Ident) {
|
||||
|
@ -9411,6 +9419,30 @@ CSSParserImpl::ParseGridArea()
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CSSParserImpl::ParseGridGap()
|
||||
{
|
||||
nsCSSValue first;
|
||||
if (ParseSingleTokenVariant(first, VARIANT_INHERIT, nullptr)) {
|
||||
AppendValue(eCSSProperty_grid_column_gap, first);
|
||||
AppendValue(eCSSProperty_grid_row_gap, first);
|
||||
return true;
|
||||
}
|
||||
if (ParseNonNegativeVariant(first, VARIANT_LCALC, nullptr) !=
|
||||
CSSParseResult::Ok) {
|
||||
return false;
|
||||
}
|
||||
nsCSSValue second;
|
||||
auto result = ParseNonNegativeVariant(second, VARIANT_LCALC, nullptr);
|
||||
if (result == CSSParseResult::Error) {
|
||||
return false;
|
||||
}
|
||||
AppendValue(eCSSProperty_grid_column_gap, first);
|
||||
AppendValue(eCSSProperty_grid_row_gap,
|
||||
result == CSSParseResult::NotFound ? first : second);
|
||||
return true;
|
||||
}
|
||||
|
||||
// [ $aTable && <overflow-position>? ] ?
|
||||
// $aTable is for <content-position> or <self-position>
|
||||
bool
|
||||
|
@ -10655,6 +10687,8 @@ CSSParserImpl::ParsePropertyByFunction(nsCSSProperty aPropID)
|
|||
eCSSProperty_grid_row_end);
|
||||
case eCSSProperty_grid_area:
|
||||
return ParseGridArea();
|
||||
case eCSSProperty_grid_gap:
|
||||
return ParseGridGap();
|
||||
case eCSSProperty_image_region:
|
||||
return ParseRect(eCSSProperty_image_region);
|
||||
case eCSSProperty_align_content:
|
||||
|
|
|
@ -2125,6 +2125,34 @@ CSS_PROP_SHORTHAND(
|
|||
GridArea,
|
||||
CSS_PROPERTY_PARSE_FUNCTION,
|
||||
"layout.css.grid.enabled")
|
||||
CSS_PROP_POSITION(
|
||||
grid-column-gap,
|
||||
grid_column_gap,
|
||||
GridColumnGap,
|
||||
CSS_PROPERTY_PARSE_VALUE |
|
||||
CSS_PROPERTY_VALUE_NONNEGATIVE,
|
||||
"layout.css.grid.enabled",
|
||||
VARIANT_HL | VARIANT_CALC,
|
||||
nullptr,
|
||||
offsetof(nsStylePosition, mGridColumnGap),
|
||||
eStyleAnimType_nscoord)
|
||||
CSS_PROP_POSITION(
|
||||
grid-row-gap,
|
||||
grid_row_gap,
|
||||
GridRowGap,
|
||||
CSS_PROPERTY_PARSE_VALUE |
|
||||
CSS_PROPERTY_VALUE_NONNEGATIVE,
|
||||
"layout.css.grid.enabled",
|
||||
VARIANT_HL | VARIANT_CALC,
|
||||
nullptr,
|
||||
offsetof(nsStylePosition, mGridRowGap),
|
||||
eStyleAnimType_nscoord)
|
||||
CSS_PROP_SHORTHAND(
|
||||
grid-gap,
|
||||
grid_gap,
|
||||
GridGap,
|
||||
CSS_PROPERTY_PARSE_FUNCTION,
|
||||
"layout.css.grid.enabled")
|
||||
CSS_PROP_POSITION(
|
||||
height,
|
||||
height,
|
||||
|
|
|
@ -2702,6 +2702,8 @@ static const nsCSSProperty gGridSubpropTable[] = {
|
|||
eCSSProperty_grid_auto_flow,
|
||||
eCSSProperty_grid_auto_columns,
|
||||
eCSSProperty_grid_auto_rows,
|
||||
eCSSProperty_grid_column_gap, // can only be reset, not get/set
|
||||
eCSSProperty_grid_row_gap, // can only be reset, not get/set
|
||||
eCSSProperty_UNKNOWN
|
||||
};
|
||||
|
||||
|
@ -2725,6 +2727,12 @@ static const nsCSSProperty gGridAreaSubpropTable[] = {
|
|||
eCSSProperty_UNKNOWN
|
||||
};
|
||||
|
||||
static const nsCSSProperty gGridGapSubpropTable[] = {
|
||||
eCSSProperty_grid_column_gap,
|
||||
eCSSProperty_grid_row_gap,
|
||||
eCSSProperty_UNKNOWN
|
||||
};
|
||||
|
||||
static const nsCSSProperty gOverflowSubpropTable[] = {
|
||||
eCSSProperty_overflow_x,
|
||||
eCSSProperty_overflow_y,
|
||||
|
|
|
@ -2556,6 +2556,22 @@ nsComputedDOMStyle::DoGetGridRowEnd()
|
|||
return GetGridLine(StylePosition()->mGridRowEnd);
|
||||
}
|
||||
|
||||
CSSValue*
|
||||
nsComputedDOMStyle::DoGetGridColumnGap()
|
||||
{
|
||||
nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
|
||||
val->SetAppUnits(StylePosition()->mGridColumnGap);
|
||||
return val;
|
||||
}
|
||||
|
||||
CSSValue*
|
||||
nsComputedDOMStyle::DoGetGridRowGap()
|
||||
{
|
||||
nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
|
||||
val->SetAppUnits(StylePosition()->mGridRowGap);
|
||||
return val;
|
||||
}
|
||||
|
||||
CSSValue*
|
||||
nsComputedDOMStyle::DoGetPaddingTop()
|
||||
{
|
||||
|
|
|
@ -266,6 +266,8 @@ private:
|
|||
mozilla::dom::CSSValue* DoGetGridColumnEnd();
|
||||
mozilla::dom::CSSValue* DoGetGridRowStart();
|
||||
mozilla::dom::CSSValue* DoGetGridRowEnd();
|
||||
mozilla::dom::CSSValue* DoGetGridColumnGap();
|
||||
mozilla::dom::CSSValue* DoGetGridRowGap();
|
||||
|
||||
/* Background properties */
|
||||
mozilla::dom::CSSValue* DoGetBackgroundAttachment();
|
||||
|
|
|
@ -138,8 +138,10 @@ COMPUTED_STYLE_PROP(grid_auto_columns, GridAutoColumns)
|
|||
COMPUTED_STYLE_PROP(grid_auto_flow, GridAutoFlow)
|
||||
COMPUTED_STYLE_PROP(grid_auto_rows, GridAutoRows)
|
||||
COMPUTED_STYLE_PROP(grid_column_end, GridColumnEnd)
|
||||
COMPUTED_STYLE_PROP(grid_column_gap, GridColumnGap)
|
||||
COMPUTED_STYLE_PROP(grid_column_start, GridColumnStart)
|
||||
COMPUTED_STYLE_PROP(grid_row_end, GridRowEnd)
|
||||
COMPUTED_STYLE_PROP(grid_row_gap, GridRowGap)
|
||||
COMPUTED_STYLE_PROP(grid_row_start, GridRowStart)
|
||||
COMPUTED_STYLE_PROP(grid_template_areas, GridTemplateAreas)
|
||||
COMPUTED_STYLE_PROP(grid_template_columns, GridTemplateColumns)
|
||||
|
|
|
@ -8117,6 +8117,33 @@ nsRuleNode::ComputePositionData(void* aStartStruct,
|
|||
parentPos->mGridRowEnd,
|
||||
conditions);
|
||||
|
||||
// grid-column-gap
|
||||
nsStyleCoord tempCoord;
|
||||
if (SetCoord(*aRuleData->ValueForGridColumnGap(),
|
||||
tempCoord, nsStyleCoord(parentPos->mGridColumnGap,
|
||||
nsStyleCoord::CoordConstructor),
|
||||
SETCOORD_LH | SETCOORD_INITIAL_ZERO | SETCOORD_CALC_LENGTH_ONLY |
|
||||
SETCOORD_CALC_CLAMP_NONNEGATIVE | SETCOORD_UNSET_INITIAL,
|
||||
aContext, mPresContext, conditions)) {
|
||||
pos->mGridColumnGap = tempCoord.GetCoordValue();
|
||||
} else {
|
||||
MOZ_ASSERT(aRuleData->ValueForGridColumnGap()->GetUnit() == eCSSUnit_Null,
|
||||
"unexpected unit");
|
||||
}
|
||||
|
||||
// grid-row-gap
|
||||
if (SetCoord(*aRuleData->ValueForGridRowGap(),
|
||||
tempCoord, nsStyleCoord(parentPos->mGridRowGap,
|
||||
nsStyleCoord::CoordConstructor),
|
||||
SETCOORD_LH | SETCOORD_INITIAL_ZERO | SETCOORD_CALC_LENGTH_ONLY |
|
||||
SETCOORD_CALC_CLAMP_NONNEGATIVE | SETCOORD_UNSET_INITIAL,
|
||||
aContext, mPresContext, conditions)) {
|
||||
pos->mGridRowGap = tempCoord.GetCoordValue();
|
||||
} else {
|
||||
MOZ_ASSERT(aRuleData->ValueForGridRowGap()->GetUnit() == eCSSUnit_Null,
|
||||
"unexpected unit");
|
||||
}
|
||||
|
||||
// z-index
|
||||
const nsCSSValue* zIndexValue = aRuleData->ValueForZIndex();
|
||||
if (! SetCoord(*zIndexValue, pos->mZIndex, parentPos->mZIndex,
|
||||
|
|
|
@ -1496,6 +1496,8 @@ nsStylePosition::nsStylePosition(const nsStylePosition& aSource)
|
|||
, mGridColumnEnd(aSource.mGridColumnEnd)
|
||||
, mGridRowStart(aSource.mGridRowStart)
|
||||
, mGridRowEnd(aSource.mGridRowEnd)
|
||||
, mGridColumnGap(aSource.mGridColumnGap)
|
||||
, mGridRowGap(aSource.mGridRowGap)
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsStylePosition);
|
||||
}
|
||||
|
@ -1589,7 +1591,9 @@ nsStylePosition::CalcDifference(const nsStylePosition& aOther,
|
|||
if (mGridColumnStart != aOther.mGridColumnStart ||
|
||||
mGridColumnEnd != aOther.mGridColumnEnd ||
|
||||
mGridRowStart != aOther.mGridRowStart ||
|
||||
mGridRowEnd != aOther.mGridRowEnd) {
|
||||
mGridRowEnd != aOther.mGridRowEnd ||
|
||||
mGridColumnGap != aOther.mGridColumnGap ||
|
||||
mGridRowGap != aOther.mGridRowGap) {
|
||||
return NS_CombineHint(hint, nsChangeHint_AllReflowHints);
|
||||
}
|
||||
|
||||
|
|
|
@ -1490,6 +1490,8 @@ public:
|
|||
nsStyleGridLine mGridColumnEnd;
|
||||
nsStyleGridLine mGridRowStart;
|
||||
nsStyleGridLine mGridRowEnd;
|
||||
nscoord mGridColumnGap; // [reset] coord, calc
|
||||
nscoord mGridRowGap; // [reset] coord, calc
|
||||
|
||||
// FIXME: Logical-coordinate equivalents to these WidthDepends... and
|
||||
// HeightDepends... methods have been introduced (see below); we probably
|
||||
|
|
|
@ -5954,6 +5954,8 @@ if (IsCSSPropertyPrefEnabled("layout.css.grid.enabled")) {
|
|||
"grid-auto-flow",
|
||||
"grid-auto-columns",
|
||||
"grid-auto-rows",
|
||||
"grid-column-gap",
|
||||
"grid-row-gap",
|
||||
],
|
||||
initial_values: [
|
||||
"none",
|
||||
|
@ -6133,6 +6135,33 @@ if (IsCSSPropertyPrefEnabled("layout.css.grid.enabled")) {
|
|||
other_values: gridAreaOtherValues,
|
||||
invalid_values: gridAreaInvalidValues
|
||||
};
|
||||
|
||||
gCSSProperties["grid-column-gap"] = {
|
||||
domProp: "gridColumnGap",
|
||||
inherited: false,
|
||||
type: CSS_TYPE_LONGHAND,
|
||||
initial_values: [ "0" ],
|
||||
other_values: [ "2px", "1em", "calc(1px + 1em)" ],
|
||||
invalid_values: [ "-1px", "2%", "auto", "none", "1px 1px", "calc(1%)" ],
|
||||
};
|
||||
gCSSProperties["grid-row-gap"] = {
|
||||
domProp: "gridRowGap",
|
||||
inherited: false,
|
||||
type: CSS_TYPE_LONGHAND,
|
||||
initial_values: [ "0" ],
|
||||
other_values: [ "2px", "1em", "calc(1px + 1em)" ],
|
||||
invalid_values: [ "-1px", "2%", "auto", "none", "1px 1px", "calc(1%)" ],
|
||||
};
|
||||
gCSSProperties["grid-gap"] = {
|
||||
domProp: "gridGap",
|
||||
inherited: false,
|
||||
type: CSS_TYPE_TRUE_SHORTHAND,
|
||||
subproperties: [ "grid-column-gap", "grid-row-gap" ],
|
||||
initial_values: [ "0", "0 0" ],
|
||||
other_values: [ "1ch 0", "1em 1px", "calc(1px + 1ch)" ],
|
||||
invalid_values: [ "-1px", "1px -1px", "1px 1px 1px", "inherit 1px",
|
||||
"1px 1%", "1px auto" ]
|
||||
};
|
||||
}
|
||||
|
||||
if (IsCSSPropertyPrefEnabled("layout.css.display-contents.enabled")) {
|
||||
|
|
|
@ -19,6 +19,8 @@ var initial_values = {
|
|||
gridAutoFlow: "row",
|
||||
gridAutoColumns: "auto",
|
||||
gridAutoRows: "auto",
|
||||
gridRowGap: "0px",
|
||||
gridColumnGap: "0px",
|
||||
};
|
||||
|
||||
// For various specified values of the grid-template subproperties,
|
||||
|
@ -106,8 +108,37 @@ grid_test_cases = grid_template_test_cases.concat([
|
|||
gridAutoRows: "100px",
|
||||
shorthand: "row 40px / 100px",
|
||||
},
|
||||
{
|
||||
gridAutoFlow: "row",
|
||||
gridRowGap: "0px",
|
||||
shorthand: "row auto / auto",
|
||||
},
|
||||
{
|
||||
gridAutoFlow: "row",
|
||||
gridRowGap: "1px",
|
||||
shorthand: "",
|
||||
},
|
||||
{
|
||||
gridAutoFlow: "row",
|
||||
gridColumnGap: "1px",
|
||||
shorthand: "",
|
||||
},
|
||||
]);
|
||||
|
||||
var grid_important_test_cases = [
|
||||
{
|
||||
"grid-auto-flow": "row",
|
||||
"grid-row-gap": "0px",
|
||||
shorthand: "",
|
||||
},
|
||||
{
|
||||
"grid-auto-flow": "row",
|
||||
"grid-column-gap": "1px",
|
||||
shorthand: "",
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
function run_tests(test_cases, shorthand, subproperties) {
|
||||
test_cases.forEach(function(test_case) {
|
||||
test(function() {
|
||||
|
@ -122,12 +153,31 @@ function run_tests(test_cases, shorthand, subproperties) {
|
|||
});
|
||||
}
|
||||
|
||||
function run_important_tests(test_cases, shorthand, subproperties) {
|
||||
test_cases.forEach(function(test_case) {
|
||||
test(function() {
|
||||
var element = document.createElement('div');
|
||||
document.body.appendChild(element);
|
||||
subproperties.forEach(function(longhand) {
|
||||
element.style.setProperty(longhand,
|
||||
test_case[longhand] || initial_values[longhand],
|
||||
"important");
|
||||
});
|
||||
assert_equals(element.style[shorthand], test_case.shorthand);
|
||||
}, "test shorthand serialization " + JSON.stringify(test_case));
|
||||
});
|
||||
}
|
||||
|
||||
run_tests(grid_template_test_cases, "gridTemplate", [
|
||||
"gridTemplateAreas", "gridTemplateColumns", "gridTemplateRows"]);
|
||||
|
||||
run_tests(grid_test_cases, "grid", [
|
||||
"gridTemplateAreas", "gridTemplateColumns", "gridTemplateRows",
|
||||
"gridAutoFlow", "gridAutoColumns", "gridAutoRows"]);
|
||||
"gridAutoFlow", "gridAutoColumns", "gridAutoRows", "gridColumnGap", "gridRowGap"]);
|
||||
|
||||
run_important_tests(grid_important_test_cases, "grid", [
|
||||
"grid-template-areas", "grid-template-columns", "grid-template-rows",
|
||||
"grid-auto-flow", "grid-auto-columns", "grid-auto-rows", "grid-column-gap", "grid-row-gap"]);
|
||||
|
||||
</script>
|
||||
</body>
|
||||
|
|
|
@ -142,6 +142,8 @@ var supported_properties = {
|
|||
/* test_float_zeroToOne_clamped */ ],
|
||||
"font-stretch": [ test_font_stretch ],
|
||||
"font-weight": [ test_font_weight ],
|
||||
"grid-column-gap": [ test_grid_gap ],
|
||||
"grid-row-gap": [ test_grid_gap ],
|
||||
"height": [ test_length_transition, test_percent_transition,
|
||||
test_length_percent_calc_transition,
|
||||
test_length_clamped, test_percent_clamped ],
|
||||
|
@ -1601,6 +1603,14 @@ function test_font_weight(prop) {
|
|||
div.style.setProperty("transition-timing-function", "linear", "");
|
||||
}
|
||||
|
||||
function test_grid_gap(prop) {
|
||||
if (!SpecialPowers.getBoolPref("layout.css.grid.enabled")) {
|
||||
return;
|
||||
}
|
||||
test_length_transition(prop);
|
||||
test_length_clamped(prop);
|
||||
}
|
||||
|
||||
function test_pos_integer_or_auto_transition(prop) {
|
||||
div.style.setProperty("transition-property", "none", "");
|
||||
div.style.setProperty(prop, "4", "");
|
||||
|
|
Загрузка…
Ссылка в новой задаче