Bug 550426 - Add support for {background,mask}-position-{x,y}, most of the style system changes. r=dbaron

MozReview-Commit-ID: JgZIoj43aZv

--HG--
extra : rebase_source : cf90a8cf7c10ee90f4c312b7ff5c1107aa8571f2
This commit is contained in:
Markus Stange 2016-04-29 14:12:10 -04:00
Родитель 7189351aab
Коммит 1a43349a44
12 изменённых файлов: 551 добавлений и 81 удалений

Просмотреть файл

@ -201,6 +201,41 @@ Declaration::GetAuthoredValue(nsCSSProperty aProperty, nsAString& aValue) const
GetValue(aProperty, aValue, nsCSSValue::eAuthorSpecified);
}
static void
AppendSingleImageLayerPositionValue(const nsCSSValue& aPositionX,
const nsCSSValue& aPositionY,
const nsCSSProperty aTable[],
nsAString& aValue,
nsCSSValue::Serialization aSerialization)
{
// We need to make sure that we don't serialize to an invalid 3-value form.
// The 3-value form is only valid if both edges are present.
const nsCSSValue &xEdge = aPositionX.GetArrayValue()->Item(0);
const nsCSSValue &xOffset = aPositionX.GetArrayValue()->Item(1);
const nsCSSValue &yEdge = aPositionY.GetArrayValue()->Item(0);
const nsCSSValue &yOffset = aPositionY.GetArrayValue()->Item(1);
bool xHasEdge = (eCSSUnit_Enumerated == xEdge.GetUnit());
bool xHasBoth = xHasEdge && (eCSSUnit_Null != xOffset.GetUnit());
bool yHasEdge = (eCSSUnit_Enumerated == yEdge.GetUnit());
bool yHasBoth = yHasEdge && (eCSSUnit_Null != yOffset.GetUnit());
if (yHasBoth && !xHasEdge) {
// Output 4-value form by adding the x edge.
aValue.AppendLiteral("left ");
}
aPositionX.AppendToString(aTable[nsStyleImageLayers::positionX],
aValue, aSerialization);
aValue.Append(char16_t(' '));
if (xHasBoth && !yHasEdge) {
// Output 4-value form by adding the y edge.
aValue.AppendLiteral("top ");
}
aPositionY.AppendToString(aTable[nsStyleImageLayers::positionY],
aValue, aSerialization);
}
void
Declaration::GetImageLayerValue(
nsCSSCompressedDataBlock *data,
@ -221,8 +256,10 @@ Declaration::GetImageLayerValue(
data->ValueFor(aTable[nsStyleImageLayers::image])->GetListValue();
const nsCSSValuePairList *repeat =
data->ValueFor(aTable[nsStyleImageLayers::repeat])->GetPairListValue();
const nsCSSValueList *position =
data->ValueFor(aTable[nsStyleImageLayers::position])->GetListValue();
const nsCSSValueList *positionX =
data->ValueFor(aTable[nsStyleImageLayers::positionX])->GetListValue();
const nsCSSValueList *positionY =
data->ValueFor(aTable[nsStyleImageLayers::positionY])->GetListValue();
const nsCSSValueList *clip =
data->ValueFor(aTable[nsStyleImageLayers::clip])->GetListValue();
const nsCSSValueList *origin =
@ -274,8 +311,8 @@ Declaration::GetImageLayerValue(
}
aValue.Append(char16_t(' '));
position->mValue.AppendToString(aTable[nsStyleImageLayers::position],
aValue, aSerialization);
AppendSingleImageLayerPositionValue(positionX->mValue, positionY->mValue,
aTable, aValue, aSerialization);
if (size->mXValue.GetUnit() != eCSSUnit_Auto ||
size->mYValue.GetUnit() != eCSSUnit_Auto) {
@ -337,7 +374,8 @@ Declaration::GetImageLayerValue(
image = image->mNext;
repeat = repeat->mNext;
position = position->mNext;
positionX = positionX->mNext;
positionY = positionY->mNext;
clip = clip->mNext;
origin = origin->mNext;
size = size->mNext;
@ -348,7 +386,8 @@ Declaration::GetImageLayerValue(
if (!image) {
// This layer is an background layer
if (aTable == nsStyleImageLayers::kBackgroundLayerTable) {
if (repeat || position || clip || origin || size || attachment) {
if (repeat || positionX || positionY || clip || origin || size ||
attachment) {
// Uneven length lists, so can't be serialized as shorthand.
aValue.Truncate();
return;
@ -360,7 +399,8 @@ Declaration::GetImageLayerValue(
#else
MOZ_ASSERT_UNREACHABLE("Should never get here when mask-as-shorthand is disable");
#endif
if (repeat || position || clip || origin || size || composite || mode) {
if (repeat || positionX || positionY || clip || origin || size ||
composite || mode) {
// Uneven length lists, so can't be serialized as shorthand.
aValue.Truncate();
return;
@ -371,7 +411,8 @@ Declaration::GetImageLayerValue(
// This layer is an background layer
if (aTable == nsStyleImageLayers::kBackgroundLayerTable) {
if (!repeat || !position || !clip || !origin || !size || !attachment) {
if (!repeat || !positionX || !positionY || !clip || !origin || !size ||
!attachment) {
// Uneven length lists, so can't be serialized as shorthand.
aValue.Truncate();
return;
@ -383,7 +424,7 @@ Declaration::GetImageLayerValue(
#else
MOZ_ASSERT_UNREACHABLE("Should never get here when mask-as-shorthand is disable");
#endif
if (!repeat || !position || !clip || !origin || !size ||
if (!repeat || !positionX || !positionY || !clip || !origin || !size ||
!composite || !mode) {
// Uneven length lists, so can't be serialized as shorthand.
aValue.Truncate();
@ -395,6 +436,39 @@ Declaration::GetImageLayerValue(
}
}
void
Declaration::GetImageLayerPositionValue(
nsCSSCompressedDataBlock *data,
nsAString& aValue,
nsCSSValue::Serialization aSerialization,
const nsCSSProperty aTable[]) const
{
// We know from above that all subproperties were specified.
// However, we still can't represent that in the shorthand unless
// they're all lists of the same length. So if they're different
// lengths, we need to bail out.
const nsCSSValueList *positionX =
data->ValueFor(aTable[nsStyleImageLayers::positionX])->GetListValue();
const nsCSSValueList *positionY =
data->ValueFor(aTable[nsStyleImageLayers::positionY])->GetListValue();
for (;;) {
AppendSingleImageLayerPositionValue(positionX->mValue, positionY->mValue,
aTable, aValue, aSerialization);
positionX = positionX->mNext;
positionY = positionY->mNext;
if (!positionX || !positionY) {
if (positionX || positionY) {
// Uneven length lists, so can't be serialized as shorthand.
aValue.Truncate();
}
return;
}
aValue.Append(char16_t(','));
aValue.Append(char16_t(' '));
}
}
void
Declaration::GetValue(nsCSSProperty aProperty, nsAString& aValue,
nsCSSValue::Serialization aSerialization) const
@ -669,12 +743,22 @@ Declaration::GetValue(nsCSSProperty aProperty, nsAString& aValue,
nsStyleImageLayers::kBackgroundLayerTable);
break;
}
case eCSSProperty_background_position: {
GetImageLayerPositionValue(data, aValue, aSerialization,
nsStyleImageLayers::kBackgroundLayerTable);
break;
}
#ifdef MOZ_ENABLE_MASK_AS_SHORTHAND
case eCSSProperty_mask: {
GetImageLayerValue(data, aValue, aSerialization,
nsStyleImageLayers::kMaskLayerTable);
break;
}
case eCSSProperty_mask_position: {
GetImageLayerPositionValue(data, aValue, aSerialization,
nsStyleImageLayers::kMaskLayerTable);
break;
}
#endif
case eCSSProperty_font: {
// systemFont might not be present; other values are guaranteed to be

Просмотреть файл

@ -375,6 +375,11 @@ private:
nsCSSValue::Serialization aSerialization,
const nsCSSProperty aTable[]) const;
void GetImageLayerPositionValue(nsCSSCompressedDataBlock *data,
nsAString& aValue,
nsCSSValue::Serialization aSerialization,
const nsCSSProperty aTable[]) const;
public:
/**
* Returns the property at the given index in the ordered list of

Просмотреть файл

@ -865,19 +865,22 @@ protected:
nsCSSValueList* mAttachment; // A property for background layer only
nsCSSValueList* mClip;
nsCSSValueList* mOrigin;
nsCSSValueList* mPosition;
nsCSSValueList* mPositionX;
nsCSSValueList* mPositionY;
nsCSSValuePairList* mSize;
nsCSSValueList* mComposite; // A property for mask layer only
nsCSSValueList* mMode; // A property for mask layer only
ImageLayersShorthandParseState(
nsCSSValue& aColor, nsCSSValueList* aImage, nsCSSValuePairList* aRepeat,
nsCSSValueList* aAttachment, nsCSSValueList* aClip,
nsCSSValueList* aOrigin, nsCSSValueList* aPosition,
nsCSSValueList* aOrigin,
nsCSSValueList* aPositionX, nsCSSValueList* aPositionY,
nsCSSValuePairList* aSize, nsCSSValueList* aComposite,
nsCSSValueList* aMode) :
mColor(aColor), mImage(aImage), mRepeat(aRepeat),
mAttachment(aAttachment), mClip(aClip), mOrigin(aOrigin),
mPosition(aPosition), mSize(aSize), mComposite(aComposite),
mPositionX(aPositionX), mPositionY(aPositionY),
mSize(aSize), mComposite(aComposite),
mMode(aMode) {};
};
@ -888,7 +891,8 @@ protected:
bool ParseValueList(nsCSSProperty aPropID); // a single value prop-id
bool ParseImageLayerRepeat(nsCSSProperty aPropID);
bool ParseImageLayerRepeatValues(nsCSSValuePair& aValue);
bool ParseImageLayerPosition(nsCSSProperty aPropID);
bool ParseImageLayerPosition(const nsCSSProperty aTable[]);
bool ParseImageLayerPositionCoord(nsCSSProperty aPropID, bool aIsHorizontal);
// ParseBoxPositionValues parses the CSS 2.1 background-position syntax,
// which is still used by some properties. See ParsePositionValue
@ -899,7 +903,9 @@ protected:
// ParsePositionValue parses a CSS <position> value, which is used by
// the 'background-position' property.
bool ParsePositionValue(nsCSSValue& aOut);
bool ParsePositionValueSeparateCoords(nsCSSValue& aOutX, nsCSSValue& aOutY);
bool ParseImageLayerPositionCoordItem(nsCSSValue& aOut, bool aIsHorizontal);
bool ParseImageLayerSize(nsCSSProperty aPropID);
bool ParseImageLayerSizeValues(nsCSSValuePair& aOut);
bool ParseBorderColor();
@ -11426,7 +11432,11 @@ CSSParserImpl::ParsePropertyByFunction(nsCSSProperty aPropID)
case eCSSProperty_background_repeat:
return ParseImageLayerRepeat(eCSSProperty_background_repeat);
case eCSSProperty_background_position:
return ParseImageLayerPosition(eCSSProperty_background_position);
return ParseImageLayerPosition(nsStyleImageLayers::kBackgroundLayerTable);
case eCSSProperty_background_position_x:
case eCSSProperty_background_position_y:
return ParseImageLayerPositionCoord(aPropID,
aPropID == eCSSProperty_background_position_x);
case eCSSProperty_background_size:
return ParseImageLayerSize(eCSSProperty_background_size);
case eCSSProperty_border:
@ -11608,7 +11618,11 @@ CSSParserImpl::ParsePropertyByFunction(nsCSSProperty aPropID)
case eCSSProperty_mask_repeat:
return ParseImageLayerRepeat(eCSSProperty_mask_repeat);
case eCSSProperty_mask_position:
return ParseImageLayerPosition(eCSSProperty_mask_position);
return ParseImageLayerPosition(nsStyleImageLayers::kMaskLayerTable);
case eCSSProperty_mask_position_x:
case eCSSProperty_mask_position_y:
return ParseImageLayerPositionCoord(aPropID,
aPropID == eCSSProperty_mask_position_x);
case eCSSProperty_mask_size:
return ParseImageLayerSize(eCSSProperty_mask_size);
#endif
@ -11889,12 +11903,13 @@ CSSParserImpl::ParseImageLayers(const nsCSSProperty aTable[])
return true;
}
nsCSSValue image, repeat, attachment, clip, origin, position, size,
nsCSSValue image, repeat, attachment, clip, origin, positionX, positionY, size,
composite, maskMode;
ImageLayersShorthandParseState state(color, image.SetListValue(),
repeat.SetPairListValue(),
attachment.SetListValue(), clip.SetListValue(),
origin.SetListValue(), position.SetListValue(),
origin.SetListValue(),
positionX.SetListValue(), positionY.SetListValue(),
size.SetPairListValue(), composite.SetListValue(),
maskMode.SetListValue());
@ -11928,7 +11943,9 @@ CSSParserImpl::ParseImageLayers(const nsCSSProperty aTable[])
nsCSSValueList);
APPENDNEXT(nsStyleImageLayers::origin, state.mOrigin,
nsCSSValueList);
APPENDNEXT(nsStyleImageLayers::position, state.mPosition,
APPENDNEXT(nsStyleImageLayers::positionX, state.mPositionX,
nsCSSValueList);
APPENDNEXT(nsStyleImageLayers::positionY, state.mPositionY,
nsCSSValueList);
APPENDNEXT(nsStyleImageLayers::size, state.mSize,
nsCSSValuePairList);
@ -11957,7 +11974,8 @@ CSSParserImpl::ParseImageLayers(const nsCSSProperty aTable[])
APPENDVALUE(aTable[nsStyleImageLayers::repeat], repeat);
APPENDVALUE(aTable[nsStyleImageLayers::clip], clip);
APPENDVALUE(aTable[nsStyleImageLayers::origin], origin);
APPENDVALUE(aTable[nsStyleImageLayers::position], position);
APPENDVALUE(aTable[nsStyleImageLayers::positionX], positionX);
APPENDVALUE(aTable[nsStyleImageLayers::positionY], positionY);
APPENDVALUE(aTable[nsStyleImageLayers::size], size);
APPENDVALUE(aTable[nsStyleImageLayers::color], color);
APPENDVALUE(aTable[nsStyleImageLayers::attachment], attachment);
@ -12016,10 +12034,13 @@ CSSParserImpl::ParseImageLayersItem(
eCSSUnit_Enumerated);
aState.mOrigin->mValue.SetIntValue(NS_STYLE_IMAGELAYER_ORIGIN_PADDING,
eCSSUnit_Enumerated);
RefPtr<nsCSSValue::Array> positionArr = nsCSSValue::Array::Create(4);
aState.mPosition->mValue.SetArrayValue(positionArr, eCSSUnit_Array);
positionArr->Item(1).SetPercentValue(0.0f);
positionArr->Item(3).SetPercentValue(0.0f);
RefPtr<nsCSSValue::Array> positionXArr = nsCSSValue::Array::Create(2);
RefPtr<nsCSSValue::Array> positionYArr = nsCSSValue::Array::Create(2);
aState.mPositionX->mValue.SetArrayValue(positionXArr, eCSSUnit_Array);
aState.mPositionY->mValue.SetArrayValue(positionYArr, eCSSUnit_Array);
positionXArr->Item(1).SetPercentValue(0.0f);
positionYArr->Item(1).SetPercentValue(0.0f);
aState.mSize->mXValue.SetAutoValue();
aState.mSize->mYValue.SetAutoValue();
aState.mComposite->mValue.SetIntValue(NS_STYLE_MASK_COMPOSITE_ADD,
@ -12092,7 +12113,9 @@ CSSParserImpl::ParseImageLayersItem(
if (havePositionAndSize)
return false;
havePositionAndSize = true;
if (!ParsePositionValue(aState.mPosition->mValue)) {
if (!ParsePositionValueSeparateCoords(aState.mPositionX->mValue,
aState.mPositionY->mValue)) {
return false;
}
if (ExpectSymbol('/', true)) {
@ -12204,7 +12227,8 @@ CSSParserImpl::ParseImageLayersItem(
if (havePositionAndSize)
return false;
havePositionAndSize = true;
if (!ParsePositionValue(aState.mPosition->mValue)) {
if (!ParsePositionValueSeparateCoords(aState.mPositionX->mValue,
aState.mPositionY->mValue)) {
return false;
}
if (ExpectSymbol('/', true)) {
@ -12313,16 +12337,54 @@ CSSParserImpl::ParseImageLayerRepeatValues(nsCSSValuePair& aValue)
return false;
}
// This function is very similar to ParseScrollSnapCoordinate,
// ParseImageLayers, ParseImageLayerSize.
bool
CSSParserImpl::ParseImageLayerPosition(nsCSSProperty aPropID)
CSSParserImpl::ParseImageLayerPosition(const nsCSSProperty aTable[])
{
// 'initial', 'inherit' and 'unset' stand alone, no list permitted.
nsCSSValue position;
if (ParseSingleTokenVariant(position, VARIANT_INHERIT, nullptr)) {
AppendValue(aTable[nsStyleImageLayers::positionX], position);
AppendValue(aTable[nsStyleImageLayers::positionY], position);
return true;
}
nsCSSValue itemValueX;
nsCSSValue itemValueY;
if (!ParsePositionValueSeparateCoords(itemValueX, itemValueY)) {
return false;
}
nsCSSValue valueX;
nsCSSValue valueY;
nsCSSValueList* itemX = valueX.SetListValue();
nsCSSValueList* itemY = valueY.SetListValue();
for (;;) {
itemX->mValue = itemValueX;
itemY->mValue = itemValueY;
if (!ExpectSymbol(',', true)) {
break;
}
if (!ParsePositionValueSeparateCoords(itemValueX, itemValueY)) {
return false;
}
itemX->mNext = new nsCSSValueList;
itemY->mNext = new nsCSSValueList;
itemX = itemX->mNext;
itemY = itemY->mNext;
}
AppendValue(aTable[nsStyleImageLayers::positionX], valueX);
AppendValue(aTable[nsStyleImageLayers::positionY], valueY);
return true;
}
bool
CSSParserImpl::ParseImageLayerPositionCoord(nsCSSProperty aPropID, bool aIsHorizontal)
{
nsCSSValue value;
// 'initial', 'inherit' and 'unset' stand alone, no list permitted.
if (!ParseSingleTokenVariant(value, VARIANT_INHERIT, nullptr)) {
nsCSSValue itemValue;
if (!ParsePositionValue(itemValue)) {
if (!ParseImageLayerPositionCoordItem(itemValue, aIsHorizontal)) {
return false;
}
nsCSSValueList* item = value.SetListValue();
@ -12331,7 +12393,7 @@ CSSParserImpl::ParseImageLayerPosition(nsCSSProperty aPropID)
if (!ExpectSymbol(',', true)) {
break;
}
if (!ParsePositionValue(itemValue)) {
if (!ParseImageLayerPositionCoordItem(itemValue, aIsHorizontal)) {
return false;
}
item->mNext = new nsCSSValueList;
@ -12631,6 +12693,80 @@ CSSParserImpl::ParsePositionValue(nsCSSValue& aOut)
return true;
}
bool
CSSParserImpl::ParsePositionValueSeparateCoords(nsCSSValue& aOutX, nsCSSValue& aOutY)
{
nsCSSValue scratch;
if (!ParsePositionValue(scratch)) {
return false;
}
// Separate the four values into two pairs of two values for X and Y.
RefPtr<nsCSSValue::Array> valueX = nsCSSValue::Array::Create(2);
RefPtr<nsCSSValue::Array> valueY = nsCSSValue::Array::Create(2);
aOutX.SetArrayValue(valueX, eCSSUnit_Array);
aOutY.SetArrayValue(valueY, eCSSUnit_Array);
RefPtr<nsCSSValue::Array> value = scratch.GetArrayValue();
valueX->Item(0) = value->Item(0);
valueX->Item(1) = value->Item(1);
valueY->Item(0) = value->Item(2);
valueY->Item(1) = value->Item(3);
return true;
}
// Parses one item in a list of values for the 'background-position-x' or
// 'background-position-y' property. Does not support the start/end keywords.
// Spec reference: https://drafts.csswg.org/css-backgrounds-4/#propdef-background-position-x
bool
CSSParserImpl::ParseImageLayerPositionCoordItem(nsCSSValue& aOut, bool aIsHorizontal)
{
RefPtr<nsCSSValue::Array> value = nsCSSValue::Array::Create(2);
aOut.SetArrayValue(value, eCSSUnit_Array);
nsCSSValue &edge = value->Item(0),
&offset = value->Item(1);
nsCSSValue edgeOrOffset;
CSSParseResult result =
ParseVariant(edgeOrOffset, VARIANT_LPCALC | VARIANT_KEYWORD,
nsCSSProps::kImageLayerPositionKTable);
if (result != CSSParseResult::Ok) {
return false;
}
if (edgeOrOffset.GetUnit() == eCSSUnit_Enumerated) {
edge = edgeOrOffset;
// The edge can be followed by an optional offset.
result = ParseVariant(offset, VARIANT_LPCALC, nullptr);
if (result == CSSParseResult::Error) {
return false;
}
} else {
offset = edgeOrOffset;
}
// Keywords for horizontal properties cannot be vertical keywords, and
// keywords for vertical properties cannot be horizontal keywords.
// Also, if an offset is specified, the edge cannot be center.
int32_t edgeEnum =
edge.GetUnit() == eCSSUnit_Enumerated ? edge.GetIntValue() : 0;
int32_t allowedKeywords =
(aIsHorizontal ? (BG_LEFT | BG_RIGHT) : (BG_TOP | BG_BOTTOM)) |
(offset.GetUnit() == eCSSUnit_Null ? BG_CENTER : 0);
if (edgeEnum & ~allowedKeywords) {
return false;
}
NS_ASSERTION((eCSSUnit_Enumerated == edge.GetUnit() ||
eCSSUnit_Null == edge.GetUnit()) &&
eCSSUnit_Enumerated != offset.GetUnit(),
"Unexpected units");
return true;
}
// This function is very similar to ParseScrollSnapCoordinate,
// ParseImageLayers, and ParseImageLayerPosition.
bool

Просмотреть файл

@ -383,6 +383,14 @@ CSS_PROP_ALIAS(-webkit-mask-position,
mask_position,
WebkitMaskPosition,
WEBKIT_PREFIX_PREF)
CSS_PROP_ALIAS(-webkit-mask-position-x,
mask_position_x,
WebkitMaskPositionX,
WEBKIT_PREFIX_PREF)
CSS_PROP_ALIAS(-webkit-mask-position-y,
mask_position_y,
WebkitMaskPositionY,
WEBKIT_PREFIX_PREF)
CSS_PROP_ALIAS(-webkit-mask-repeat,
mask_repeat,
WebkitMaskRepeat,

Просмотреть файл

@ -567,15 +567,35 @@ CSS_PROP_BACKGROUND(
kImageLayerOriginKTable,
CSS_PROP_NO_OFFSET,
eStyleAnimType_None)
CSS_PROP_BACKGROUND(
CSS_PROP_SHORTHAND(
background-position,
background_position,
BackgroundPosition,
CSS_PROPERTY_PARSE_FUNCTION |
CSS_PROPERTY_UNITLESS_LENGTH_QUIRK,
"")
CSS_PROP_BACKGROUND(
background-position-x,
background_position_x,
BackgroundPositionX,
CSS_PROPERTY_PARSE_FUNCTION |
CSS_PROPERTY_APPLIES_TO_FIRST_LETTER_AND_FIRST_LINE |
CSS_PROPERTY_APPLIES_TO_PLACEHOLDER |
CSS_PROPERTY_VALUE_LIST_USES_COMMAS |
CSS_PROPERTY_STORES_CALC,
"",
0,
kImageLayerPositionKTable,
CSS_PROP_NO_OFFSET,
eStyleAnimType_Custom)
CSS_PROP_BACKGROUND(
background-position-y,
background_position_y,
BackgroundPositionY,
CSS_PROPERTY_PARSE_FUNCTION |
CSS_PROPERTY_APPLIES_TO_FIRST_LETTER_AND_FIRST_LINE |
CSS_PROPERTY_APPLIES_TO_PLACEHOLDER |
CSS_PROPERTY_VALUE_LIST_USES_COMMAS |
CSS_PROPERTY_UNITLESS_LENGTH_QUIRK |
CSS_PROPERTY_STORES_CALC,
"",
0,
@ -2714,10 +2734,29 @@ CSS_PROP_SVGRESET(
kImageLayerOriginKTable,
CSS_PROP_NO_OFFSET,
eStyleAnimType_None)
CSS_PROP_SVGRESET(
CSS_PROP_SHORTHAND(
mask-position,
mask_position,
MaskPosition,
CSS_PROPERTY_PARSE_FUNCTION |
CSS_PROPERTY_UNITLESS_LENGTH_QUIRK,
"")
CSS_PROP_SVGRESET(
mask-position-x,
mask_position_x,
MaskPositionX,
CSS_PROPERTY_PARSE_FUNCTION |
CSS_PROPERTY_VALUE_LIST_USES_COMMAS |
CSS_PROPERTY_STORES_CALC,
"",
0,
kImageLayerPositionKTable,
CSS_PROP_NO_OFFSET,
eStyleAnimType_Custom)
CSS_PROP_SVGRESET(
mask-position-y,
mask_position_y,
MaskPositionY,
CSS_PROPERTY_PARSE_FUNCTION |
CSS_PROPERTY_VALUE_LIST_USES_COMMAS |
CSS_PROPERTY_STORES_CALC,

Просмотреть файл

@ -2625,13 +2625,20 @@ static const nsCSSProperty gBackgroundSubpropTable[] = {
eCSSProperty_background_image,
eCSSProperty_background_repeat,
eCSSProperty_background_attachment,
eCSSProperty_background_position,
eCSSProperty_background_clip,
eCSSProperty_background_origin,
eCSSProperty_background_position_x,
eCSSProperty_background_position_y,
eCSSProperty_background_size,
eCSSProperty_UNKNOWN
};
static const nsCSSProperty gBackgroundPositionSubpropTable[] = {
eCSSProperty_background_position_x,
eCSSProperty_background_position_y,
eCSSProperty_UNKNOWN
};
static const nsCSSProperty gBorderSubpropTable[] = {
eCSSProperty_border_top_width,
eCSSProperty_border_right_width,
@ -2965,7 +2972,8 @@ static const nsCSSProperty gScrollSnapTypeSubpropTable[] = {
static const nsCSSProperty gMaskSubpropTable[] = {
eCSSProperty_mask_image,
eCSSProperty_mask_repeat,
eCSSProperty_mask_position,
eCSSProperty_mask_position_x,
eCSSProperty_mask_position_y,
eCSSProperty_mask_clip,
eCSSProperty_mask_origin,
eCSSProperty_mask_size,
@ -2973,6 +2981,11 @@ static const nsCSSProperty gMaskSubpropTable[] = {
eCSSProperty_mask_mode,
eCSSProperty_UNKNOWN
};
static const nsCSSProperty gMaskPositionSubpropTable[] = {
eCSSProperty_mask_position_x,
eCSSProperty_mask_position_y,
eCSSProperty_UNKNOWN
};
#endif
// FIXME: mask-border tables should be added when we implement
// mask-border properties.

Просмотреть файл

@ -934,7 +934,7 @@ nsCSSValue::AppendCircleOrEllipseToString(nsCSSKeyword aFunctionId,
aResult.Append(' ');
}
aResult.AppendLiteral("at ");
array->Item(count).AppendToString(eCSSProperty_background_position,
array->Item(count).AppendToString(eCSSProperty_object_position,
aResult, aSerialization);
}
@ -1549,12 +1549,12 @@ nsCSSValue::AppendToString(nsCSSProperty aProperty, nsAString& aResult,
aResult.AppendLiteral("to");
if (!(gradient->mBgPos.mXValue.GetIntValue() & NS_STYLE_IMAGELAYER_POSITION_CENTER)) {
aResult.Append(' ');
gradient->mBgPos.mXValue.AppendToString(eCSSProperty_background_position,
gradient->mBgPos.mXValue.AppendToString(eCSSProperty_background_position_x,
aResult, aSerialization);
}
if (!(gradient->mBgPos.mYValue.GetIntValue() & NS_STYLE_IMAGELAYER_POSITION_CENTER)) {
aResult.Append(' ');
gradient->mBgPos.mYValue.AppendToString(eCSSProperty_background_position,
gradient->mBgPos.mYValue.AppendToString(eCSSProperty_background_position_y,
aResult, aSerialization);
}
needSep = true;
@ -1572,12 +1572,12 @@ nsCSSValue::AppendToString(nsCSSProperty aProperty, nsAString& aResult,
aResult.AppendLiteral("at ");
}
if (gradient->mBgPos.mXValue.GetUnit() != eCSSUnit_None) {
gradient->mBgPos.mXValue.AppendToString(eCSSProperty_background_position,
gradient->mBgPos.mXValue.AppendToString(eCSSProperty_background_position_x,
aResult, aSerialization);
aResult.Append(' ');
}
if (gradient->mBgPos.mYValue.GetUnit() != eCSSUnit_None) {
gradient->mBgPos.mYValue.AppendToString(eCSSProperty_background_position,
gradient->mBgPos.mYValue.AppendToString(eCSSProperty_background_position_y,
aResult, aSerialization);
aResult.Append(' ');
}

Просмотреть файл

@ -2159,9 +2159,14 @@ nsComputedDOMStyle::DoGetImageLayerImage(const nsStyleImageLayers& aLayers)
already_AddRefed<CSSValue>
nsComputedDOMStyle::DoGetImageLayerPosition(const nsStyleImageLayers& aLayers)
{
RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
if (aLayers.mPositionXCount != aLayers.mPositionYCount) {
// No value to return. We can't express this combination of
// values as a shorthand.
return nullptr;
}
for (uint32_t i = 0, i_end = aLayers.mPositionCount; i < i_end; ++i) {
RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
for (uint32_t i = 0, i_end = aLayers.mPositionXCount; i < i_end; ++i) {
RefPtr<nsDOMCSSValueList> itemList = GetROCSSValueList(false);
SetValueToPosition(aLayers.mLayers[i].mPosition, itemList);

Просмотреть файл

@ -6627,6 +6627,9 @@ ComputePositionValue(nsStyleContext* aStyleContext,
"unexpected unit for CSS <position> value");
RefPtr<nsCSSValue::Array> positionArray = aValue.GetArrayValue();
NS_ASSERTION(positionArray->Count() == 4,
"unexpected number of values in CSS <position> value");
const nsCSSValue &xEdge = positionArray->Item(0);
const nsCSSValue &xOffset = positionArray->Item(1);
const nsCSSValue &yEdge = positionArray->Item(2);
@ -6649,19 +6652,33 @@ ComputePositionValue(nsStyleContext* aStyleContext,
aConditions);
}
template <>
struct BackgroundItemComputer<nsCSSValueList, nsStyleImageLayers::Position>
{
static void ComputeValue(nsStyleContext* aStyleContext,
const nsCSSValueList* aSpecifiedValue,
nsStyleImageLayers::Position& aComputedValue,
/* Helper function to convert the -x or -y part of a CSS <position> specified
* value into its computed-style form. */
static void
ComputePositionCoordValue(nsStyleContext* aStyleContext,
const nsCSSValue& aValue,
nsStyleImageLayers::Position::PositionCoord& aComputedValue,
RuleNodeCacheConditions& aConditions)
{
ComputePositionValue(aStyleContext, aSpecifiedValue->mValue,
aComputedValue, aConditions);
}
};
NS_ASSERTION(aValue.GetUnit() == eCSSUnit_Array,
"unexpected unit for position coord value");
RefPtr<nsCSSValue::Array> positionArray = aValue.GetArrayValue();
NS_ASSERTION(positionArray->Count() == 2,
"unexpected number of values, expecting one edge and one offset");
const nsCSSValue &edge = positionArray->Item(0);
const nsCSSValue &offset = positionArray->Item(1);
NS_ASSERTION((eCSSUnit_Enumerated == edge.GetUnit() ||
eCSSUnit_Null == edge.GetUnit()) &&
eCSSUnit_Enumerated != offset.GetUnit(),
"Invalid background position");
ComputePositionCoord(aStyleContext, edge, offset,
&aComputedValue,
aConditions);
}
struct BackgroundSizeAxis {
nsCSSValue nsCSSValuePairList::* specified;
@ -6827,6 +6844,76 @@ SetImageLayerList(nsStyleContext* aStyleContext,
aMaxItemCount = aItemCount;
}
// The same as SetImageLayerList, but for values stored in
// layer.mPosition.*aResultLocation instead of layer.*aResultLocation.
// This code is duplicated because it would be annoying to make
// SetImageLayerList generic enough to handle both cases.
static void
SetImageLayerPositionCoordList(
nsStyleContext* aStyleContext,
const nsCSSValue& aValue,
nsStyleAutoArray<nsStyleImageLayers::Layer>& aLayers,
const nsStyleAutoArray<nsStyleImageLayers::Layer>& aParentLayers,
nsStyleImageLayers::Position::PositionCoord
nsStyleImageLayers::Position::* aResultLocation,
nsStyleImageLayers::Position::PositionCoord aInitialValue,
uint32_t aParentItemCount,
uint32_t& aItemCount,
uint32_t& aMaxItemCount,
bool& aRebuild,
RuleNodeCacheConditions& aConditions)
{
switch (aValue.GetUnit()) {
case eCSSUnit_Null:
break;
case eCSSUnit_Inherit:
aRebuild = true;
aConditions.SetUncacheable();
aLayers.EnsureLengthAtLeast(aParentItemCount);
aItemCount = aParentItemCount;
for (uint32_t i = 0; i < aParentItemCount; ++i) {
aLayers[i].mPosition.*aResultLocation = aParentLayers[i].mPosition.*aResultLocation;
}
break;
case eCSSUnit_Initial:
case eCSSUnit_Unset:
aRebuild = true;
aItemCount = 1;
aLayers[0].mPosition.*aResultLocation = aInitialValue;
break;
case eCSSUnit_List:
case eCSSUnit_ListDep: {
aRebuild = true;
aItemCount = 0;
const nsCSSValueList* item = aValue.GetListValue();
do {
NS_ASSERTION(item->mValue.GetUnit() != eCSSUnit_Null &&
item->mValue.GetUnit() != eCSSUnit_Inherit &&
item->mValue.GetUnit() != eCSSUnit_Initial &&
item->mValue.GetUnit() != eCSSUnit_Unset,
"unexpected unit");
++aItemCount;
aLayers.EnsureLengthAtLeast(aItemCount);
ComputePositionCoordValue(aStyleContext, item->mValue,
aLayers[aItemCount-1].mPosition.*aResultLocation,
aConditions);
item = item->mNext;
} while (item);
break;
}
default:
MOZ_ASSERT(false, "unexpected unit");
}
if (aItemCount > aMaxItemCount)
aMaxItemCount = aItemCount;
}
template <class ComputedValueItem>
static void
SetImageLayerPairList(nsStyleContext* aStyleContext,
@ -6911,6 +6998,24 @@ FillBackgroundList(
}
}
// The same as FillBackgroundList, but for values stored in
// layer.mPosition.*aResultLocation instead of layer.*aResultLocation.
static void
FillBackgroundPositionCoordList(
nsStyleAutoArray<nsStyleImageLayers::Layer>& aLayers,
nsStyleImageLayers::Position::PositionCoord
nsStyleImageLayers::Position::* aResultLocation,
uint32_t aItemCount, uint32_t aFillCount)
{
NS_PRECONDITION(aFillCount <= aLayers.Length(), "unexpected array length");
for (uint32_t sourceLayer = 0, destLayer = aItemCount;
destLayer < aFillCount;
++sourceLayer, ++destLayer) {
aLayers[destLayer].mPosition.*aResultLocation =
aLayers[sourceLayer].mPosition.*aResultLocation;
}
}
const void*
nsRuleNode::ComputeBackgroundData(void* aStartStruct,
const nsRuleData* aRuleData,
@ -6995,15 +7100,27 @@ nsRuleNode::ComputeBackgroundData(void* aStartStruct,
bg->mImage.mOriginCount, maxItemCount, rebuild,
conditions);
// background-position: enum, length, percent (flags), inherit [pair list]
nsStyleImageLayers::Position initialPosition;
initialPosition.SetInitialPercentValues(0.0f);
SetImageLayerList(aContext, *aRuleData->ValueForBackgroundPosition(),
// background-position-x/y: enum, length, percent (flags), inherit [list]
nsStyleImageLayers::Position::PositionCoord initialPositionCoord;
initialPositionCoord.mPercent = 0.0f;
initialPositionCoord.mLength = 0;
initialPositionCoord.mHasPercent = true;
SetImageLayerPositionCoordList(
aContext, *aRuleData->ValueForBackgroundPositionX(),
bg->mImage.mLayers,
parentBG->mImage.mLayers,
&nsStyleImageLayers::Layer::mPosition,
initialPosition, parentBG->mImage.mPositionCount,
bg->mImage.mPositionCount, maxItemCount, rebuild,
&nsStyleImageLayers::Position::mXPosition,
initialPositionCoord, parentBG->mImage.mPositionXCount,
bg->mImage.mPositionXCount, maxItemCount, rebuild,
conditions);
SetImageLayerPositionCoordList(
aContext, *aRuleData->ValueForBackgroundPositionY(),
bg->mImage.mLayers,
parentBG->mImage.mLayers,
&nsStyleImageLayers::Position::mYPosition,
initialPositionCoord, parentBG->mImage.mPositionYCount,
bg->mImage.mPositionYCount, maxItemCount, rebuild,
conditions);
// background-size: enum, length, auto, inherit, initial [pair list]
@ -7041,9 +7158,12 @@ nsRuleNode::ComputeBackgroundData(void* aStartStruct,
FillBackgroundList(bg->mImage.mLayers,
&nsStyleImageLayers::Layer::mOrigin,
bg->mImage.mOriginCount, fillCount);
FillBackgroundList(bg->mImage.mLayers,
&nsStyleImageLayers::Layer::mPosition,
bg->mImage.mPositionCount, fillCount);
FillBackgroundPositionCoordList(bg->mImage.mLayers,
&nsStyleImageLayers::Position::mXPosition,
bg->mImage.mPositionXCount, fillCount);
FillBackgroundPositionCoordList(bg->mImage.mLayers,
&nsStyleImageLayers::Position::mYPosition,
bg->mImage.mPositionYCount, fillCount);
FillBackgroundList(bg->mImage.mLayers,
&nsStyleImageLayers::Layer::mSize,
bg->mImage.mSizeCount, fillCount);
@ -9792,15 +9912,27 @@ nsRuleNode::ComputeSVGResetData(void* aStartStruct,
svgReset->mMask.mOriginCount, maxItemCount, rebuild,
conditions);
// mask-position: enum, length, percent (flags), inherit [pair list]
nsStyleImageLayers::Position initialPosition;
initialPosition.SetInitialPercentValues(0.0f);
SetImageLayerList(aContext, *aRuleData->ValueForMaskPosition(),
// mask-position-x/y: enum, length, percent (flags), inherit [list]
nsStyleImageLayers::Position::PositionCoord initialPositionCoord;
initialPositionCoord.mPercent = 0.0f;
initialPositionCoord.mLength = 0;
initialPositionCoord.mHasPercent = true;
SetImageLayerPositionCoordList(
aContext, *aRuleData->ValueForMaskPositionX(),
svgReset->mMask.mLayers,
parentSVGReset->mMask.mLayers,
&nsStyleImageLayers::Layer::mPosition,
initialPosition, parentSVGReset->mMask.mPositionCount,
svgReset->mMask.mPositionCount, maxItemCount, rebuild,
&nsStyleImageLayers::Position::mXPosition,
initialPositionCoord, parentSVGReset->mMask.mPositionXCount,
svgReset->mMask.mPositionXCount, maxItemCount, rebuild,
conditions);
SetImageLayerPositionCoordList(
aContext, *aRuleData->ValueForMaskPositionY(),
svgReset->mMask.mLayers,
parentSVGReset->mMask.mLayers,
&nsStyleImageLayers::Position::mYPosition,
initialPositionCoord, parentSVGReset->mMask.mPositionYCount,
svgReset->mMask.mPositionYCount, maxItemCount, rebuild,
conditions);
// mask-size: enum, length, auto, inherit, initial [pair list]
@ -9854,9 +9986,12 @@ nsRuleNode::ComputeSVGResetData(void* aStartStruct,
FillBackgroundList(svgReset->mMask.mLayers,
&nsStyleImageLayers::Layer::mOrigin,
svgReset->mMask.mOriginCount, fillCount);
FillBackgroundList(svgReset->mMask.mLayers,
&nsStyleImageLayers::Layer::mPosition,
svgReset->mMask.mPositionCount, fillCount);
FillBackgroundPositionCoordList(svgReset->mMask.mLayers,
&nsStyleImageLayers::Position::mXPosition,
svgReset->mMask.mPositionXCount, fillCount);
FillBackgroundPositionCoordList(svgReset->mMask.mLayers,
&nsStyleImageLayers::Position::mYPosition,
svgReset->mMask.mPositionYCount, fillCount);
FillBackgroundList(svgReset->mMask.mLayers,
&nsStyleImageLayers::Layer::mSize,
svgReset->mMask.mSizeCount, fillCount);

Просмотреть файл

@ -2281,7 +2281,8 @@ const nsCSSProperty nsStyleImageLayers::kBackgroundLayerTable[] = {
eCSSProperty_background_color, // color
eCSSProperty_background_image, // image
eCSSProperty_background_repeat, // repeat
eCSSProperty_background_position, // position
eCSSProperty_background_position_x, // positionX
eCSSProperty_background_position_y, // positionY
eCSSProperty_background_clip, // clip
eCSSProperty_background_origin, // origin
eCSSProperty_background_size, // size
@ -2296,7 +2297,8 @@ const nsCSSProperty nsStyleImageLayers::kMaskLayerTable[] = {
eCSSProperty_UNKNOWN, // color
eCSSProperty_mask_image, // image
eCSSProperty_mask_repeat, // repeat
eCSSProperty_mask_position, // position
eCSSProperty_mask_position_x, // positionX
eCSSProperty_mask_position_y, // positionY
eCSSProperty_mask_clip, // clip
eCSSProperty_mask_origin, // origin
eCSSProperty_mask_size, // size
@ -2311,7 +2313,8 @@ nsStyleImageLayers::nsStyleImageLayers()
, mClipCount(1)
, mOriginCount(1)
, mRepeatCount(1)
, mPositionCount(1)
, mPositionXCount(1)
, mPositionYCount(1)
, mImageCount(1)
, mSizeCount(1)
, mMaskModeCount(1)
@ -2327,7 +2330,8 @@ nsStyleImageLayers::nsStyleImageLayers(const nsStyleImageLayers &aSource)
, mClipCount(aSource.mClipCount)
, mOriginCount(aSource.mOriginCount)
, mRepeatCount(aSource.mRepeatCount)
, mPositionCount(aSource.mPositionCount)
, mPositionXCount(aSource.mPositionXCount)
, mPositionYCount(aSource.mPositionYCount)
, mImageCount(aSource.mImageCount)
, mSizeCount(aSource.mSizeCount)
, mMaskModeCount(aSource.mMaskModeCount)
@ -2344,7 +2348,8 @@ nsStyleImageLayers::nsStyleImageLayers(const nsStyleImageLayers &aSource)
mClipCount = std::max(mClipCount, count);
mOriginCount = std::max(mOriginCount, count);
mRepeatCount = std::max(mRepeatCount, count);
mPositionCount = std::max(mPositionCount, count);
mPositionXCount = std::max(mPositionXCount, count);
mPositionYCount = std::max(mPositionYCount, count);
mImageCount = std::max(mImageCount, count);
mSizeCount = std::max(mSizeCount, count);
mMaskModeCount = std::max(mMaskModeCount, count);
@ -2394,7 +2399,8 @@ nsStyleImageLayers::CalcDifference(const nsStyleImageLayers& aOther) const
mMaskModeCount != aOther.mMaskModeCount ||
mOriginCount != aOther.mOriginCount ||
mRepeatCount != aOther.mRepeatCount ||
mPositionCount != aOther.mPositionCount ||
mPositionXCount != aOther.mPositionXCount ||
mPositionYCount != aOther.mPositionYCount ||
mSizeCount != aOther.mSizeCount) {
NS_UpdateHint(hint, nsChangeHint_NeutralChange);
}

Просмотреть файл

@ -527,7 +527,8 @@ struct nsStyleImageLayers {
color,
image,
repeat,
position,
positionX,
positionY,
clip,
origin,
size,
@ -737,7 +738,8 @@ struct nsStyleImageLayers {
mClipCount,
mOriginCount,
mRepeatCount,
mPositionCount,
mPositionXCount,
mPositionYCount,
mImageCount,
mSizeCount,
mMaskModeCount,

Просмотреть файл

@ -158,6 +158,43 @@ is(e.style.background, "", "should not have background shorthand (background-rep
e.setAttribute("style", "background-clip: border-box, padding-box, border-box; background-origin: border-box, padding-box, padding-box; background-size: cover, auto, contain, contain; background-color: blue; background-image: url(404.png), none, url(404-2.png); background-attachment: fixed, scroll, scroll; background-position: top left, center, 30px 50px; background-repeat: repeat-x, repeat, no-repeat");
is(e.style.background, "", "should not have background shorthand (background-size too long)");
// Check that we only serialize background-position when the lists (of layers) for
// the -x/-y subproperties are the same length.
e.setAttribute("style", "background-position-x: 10%, left 2em, right; background-position-y: top 2em, bottom, 10%");
is(e.style.backgroundPosition, "left 10% top 2em, left 2em bottom, right 10%", "should have background-position shorthand (both lists length 3)");
e.setAttribute("style", "background-position-x: 10%, left 2em; background-position-y: top 2em, bottom, 10%");
is(e.style.backgroundPosition, "", "should not have background-position shorthand (background-position-x too short)");
e.setAttribute("style", "background-position-x: 10%, left 2em, right; background-position-y: top 2em");
is(e.style.backgroundPosition, "", "should not have background-position shorthand (background-position-y too short)");
// Check that background-position serialization doesn't produce invalid values.
e.setAttribute("style", "background-position: 0px");
is(e.style.backgroundPosition, "0px center", "1-value form should be accepted, with implied center value for background-position-y");
e.setAttribute("style", "background-position: 0px center");
is(e.style.backgroundPosition, "0px center", "2-value form 'x-offset' 'y-edge' should be accepted, and serialize to 2-value form");
e.setAttribute("style", "background-position: left 0px center");
is(e.style.backgroundPosition, "left 0px center", "3-value form 'x-edge' 'x-offset' 'y-edge' should be accepted and serialize to 3-value form");
e.setAttribute("style", "background-position: left top 0px");
is(e.style.backgroundPosition, "left top 0px", "3-value form 'x-edge' 'y-edge' 'y-offset' should be accepted and serialize to 3-value form");
e.setAttribute("style", "background-position: left 0px top 0px");
is(e.style.backgroundPosition, "left 0px top 0px", "4-value form should be accepted and serialize to 4-value form");
e.setAttribute("style", "background-position-x: 0px; background-position-y: center");
is(e.style.backgroundPosition, "0px center", "should always serialize to 2-value form if setting -x and -y with the 1-value form");
e.setAttribute("style", "background-position-x: 0px; background-position-y: 0px");
is(e.style.backgroundPosition, "0px 0px", "should always serialize to 2-value form if setting -x and -y with the 1-value form");
e.setAttribute("style", "background-position-x: center; background-position-y: 0px");
is(e.style.backgroundPosition, "center 0px", "should always serialize to 2-value form if setting -x and -y with the 1-value form");
e.setAttribute("style", "background-position-x: left; background-position-y: top");
is(e.style.backgroundPosition, "left top", "should always serialize to 2-value form if setting -x and -y with the 1-value form");
e.setAttribute("style", "background-position-x: left 0px; background-position-y: center");
is(e.style.backgroundPosition, "left 0px center", "should always serialize to 3-value form if both -x and -y specified an edge");
e.setAttribute("style", "background-position-x: right; background-position-y: top 0px");
is(e.style.backgroundPosition, "right top 0px", "should always serialize to 3-value form if both -x and -y specified an edge");
e.setAttribute("style", "background-position-x: left 0px; background-position-y: 0px");
is(e.style.backgroundPosition, "left 0px top 0px", "should serialize to 4-value form if 3-value form would only have one edge");
e.setAttribute("style", "background-position-x: 0px; background-position-y: top 0px");
is(e.style.backgroundPosition, "left 0px top 0px", "should serialize to 4-value form if 3-value form would only have one edge");
// Check that we only serialize transition when the lists are the same length.
e.setAttribute("style", "transition-property: color, width; transition-duration: 1s, 200ms; transition-timing-function: ease-in, linear; transition-delay: 0s, 1s");
isnot(e.style.transition, "", "should have transition shorthand (lists same length)");