--- a/dom/locales/en-US/chrome/layout/css.properties
+++ b/dom/locales/en-US/chrome/layout/css.properties
@@ -101,16 +101,19 @@ PEExpectedInt=Expected an integer but fo
PEColorBadRGBContents=Expected number or percentage in rgb() but found '%1$S'.
PEColorComponentBadTerm=Expected '%2$S' but found '%1$S'.
PEColorHueEOF=hue
PEExpectedComma=Expected ',' but found '%1$S'.
PEColorSaturationEOF=saturation
PEColorLightnessEOF=lightness
PEColorOpacityEOF=opacity in color value
PEExpectedNumber=Expected a number but found '%1$S'.
+PEPositionEOF=<position>
+PEExpectedPosition=Expected <position> but found '%1$S'.
+PEExpectedRadius=Expected radius but found '%1$S'.
PEExpectedCloseParen=Expected ')' but found '%1$S'.
PEDeclEndEOF=';' or '}' to end declaration
PEParseDeclarationNoColon=Expected ':' but found '%1$S'.
PEParseDeclarationDeclExpected=Expected declaration but found '%1$S'.
PEEndOfDeclEOF=end of declaration
PEImportantEOF=important
PEExpectedImportant=Expected 'important' but found '%1$S'.
PEBadDeclEnd=Expected ';' to terminate declaration but found '%1$S'.
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -960,16 +960,17 @@ protected:
}
bool IsParsingCompoundProperty(void) const {
return mParsingCompoundProperty;
}
/* Functions for basic shapes */
bool ParseBasicShape(nsCSSValue& aValue, bool* aConsumedTokens);
bool ParsePolygonFunction(nsCSSValue& aValue);
+ bool ParseCircleOrEllipseFunction(nsCSSKeyword, nsCSSValue& aValue);
/* Functions for transform Parsing */
bool ParseSingleTransform(bool aIsPrefixed, nsCSSValue& aValue);
bool ParseFunction(nsCSSKeyword aFunction, const int32_t aAllowedTypes[],
int32_t aVariantMaskAll, uint16_t aMinElems,
uint16_t aMaxElems, nsCSSValue &aValue);
bool ParseFunctionInternals(const int32_t aVariantMask[],
int32_t aVariantMaskAll,
@@ -13839,16 +13840,73 @@ CSSParserImpl::ParsePolygonFunction(nsCS
if (numArgs > 1) {
functionArray->Item(1) = fillRuleValue;
}
return true;
}
bool
+CSSParserImpl::ParseCircleOrEllipseFunction(nsCSSKeyword aKeyword,
+ nsCSSValue& aValue)
+{
+ nsCSSValue radiusX, radiusY, position;
+ bool hasRadius = false, hasPosition = false;
+
+ int32_t mask = VARIANT_LPCALC | VARIANT_NONNEGATIVE_DIMENSION |
+ VARIANT_KEYWORD;
+ if (ParseVariant(radiusX, mask, nsCSSProps::kShapeRadiusKTable)) {
+ if (aKeyword == eCSSKeyword_ellipse) {
+ if (!ParseVariant(radiusY, mask, nsCSSProps::kShapeRadiusKTable)) {
+ REPORT_UNEXPECTED_TOKEN(PEExpectedRadius);
+ SkipUntil(')');
+ return false;
+ }
+ }
+ hasRadius = true;
+ }
+
+ if (!ExpectSymbol(')', true)) {
+ if (!GetToken(true)) {
+ REPORT_UNEXPECTED_EOF(PEPositionEOF);
+ return false;
+ }
+
+ if (mToken.mType != eCSSToken_Ident ||
+ !mToken.mIdent.LowerCaseEqualsLiteral("at") ||
+ !ParsePositionValue(position)) {
+ REPORT_UNEXPECTED_TOKEN(PEExpectedPosition);
+ SkipUntil(')');
+ return false;
+ }
+ if (!ExpectSymbol(')', true)) {
+ REPORT_UNEXPECTED_TOKEN(PEExpectedCloseParen);
+ SkipUntil(')');
+ return false;
+ }
+ hasPosition = true;
+ }
+
+ size_t count = aKeyword == eCSSKeyword_circle ? 2 : 3;
+ nsRefPtr<nsCSSValue::Array> functionArray =
+ aValue.InitFunction(aKeyword, count);
+ if (hasRadius) {
+ functionArray->Item(1) = radiusX;
+ if (aKeyword == eCSSKeyword_ellipse) {
+ functionArray->Item(2) = radiusY;
+ }
+ }
+ if (hasPosition) {
+ functionArray->Item(count) = position;
+ }
+
+ return true;
+}
+
+bool
CSSParserImpl::ParseBasicShape(nsCSSValue& aValue, bool* aConsumedTokens)
{
if (!GetToken(true)) {
return false;
}
if (mToken.mType != eCSSToken_Function) {
UngetToken();
@@ -13856,16 +13914,19 @@ CSSParserImpl::ParseBasicShape(nsCSSValu
}
// Specific shape function parsing always consumes tokens.
*aConsumedTokens = true;
nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(mToken.mIdent);
switch (keyword) {
case eCSSKeyword_polygon:
return ParsePolygonFunction(aValue);
+ case eCSSKeyword_circle:
+ case eCSSKeyword_ellipse:
+ return ParseCircleOrEllipseFunction(keyword, aValue);
default:
return false;
}
}
/* Parse a clip-path url to a <clipPath> element or a basic shape. */
bool CSSParserImpl::ParseClipPath()
{
--- a/layout/style/nsCSSProps.cpp
+++ b/layout/style/nsCSSProps.cpp
@@ -1886,16 +1886,22 @@ const KTableValue nsCSSProps::kClipShape
eCSSKeyword_border_box, NS_STYLE_CLIP_SHAPE_SIZING_BORDER,
eCSSKeyword_margin_box, NS_STYLE_CLIP_SHAPE_SIZING_MARGIN,
eCSSKeyword_fill_box, NS_STYLE_CLIP_SHAPE_SIZING_FILL,
eCSSKeyword_stroke_box, NS_STYLE_CLIP_SHAPE_SIZING_STROKE,
eCSSKeyword_view_box, NS_STYLE_CLIP_SHAPE_SIZING_VIEW,
eCSSKeyword_UNKNOWN,-1
};
+const KTableValue nsCSSProps::kShapeRadiusKTable[] = {
+ eCSSKeyword_closest_side, NS_RADIUS_CLOSEST_SIDE,
+ eCSSKeyword_farthest_side, NS_RADIUS_FARTHEST_SIDE,
+ eCSSKeyword_UNKNOWN, -1
+};
+
const KTableValue nsCSSProps::kFilterFunctionKTable[] = {
eCSSKeyword_blur, NS_STYLE_FILTER_BLUR,
eCSSKeyword_brightness, NS_STYLE_FILTER_BRIGHTNESS,
eCSSKeyword_contrast, NS_STYLE_FILTER_CONTRAST,
eCSSKeyword_grayscale, NS_STYLE_FILTER_GRAYSCALE,
eCSSKeyword_invert, NS_STYLE_FILTER_INVERT,
eCSSKeyword_opacity, NS_STYLE_FILTER_OPACITY,
eCSSKeyword_saturate, NS_STYLE_FILTER_SATURATE,
--- a/layout/style/nsCSSProps.h
+++ b/layout/style/nsCSSProps.h
@@ -532,16 +532,17 @@ public:
static const KTableValue kBorderWidthKTable[];
static const KTableValue kBoxAlignKTable[];
static const KTableValue kBoxDecorationBreakKTable[];
static const KTableValue kBoxDirectionKTable[];
static const KTableValue kBoxOrientKTable[];
static const KTableValue kBoxPackKTable[];
static const KTableValue kClipShapeSizingKTable[];
static const KTableValue kDominantBaselineKTable[];
+ static const KTableValue kShapeRadiusKTable[];
static const KTableValue kFillRuleKTable[];
static const KTableValue kFilterFunctionKTable[];
static const KTableValue kImageRenderingKTable[];
static const KTableValue kShapeRenderingKTable[];
static const KTableValue kStrokeLinecapKTable[];
static const KTableValue kStrokeLinejoinKTable[];
static const KTableValue kStrokeContextValueKTable[];
static const KTableValue kVectorEffectKTable[];
--- a/layout/style/nsCSSValue.cpp
+++ b/layout/style/nsCSSValue.cpp
@@ -847,16 +847,66 @@ nsCSSValue::AppendPolygonToString(nsCSSP
nsCSSProps::kFillRuleKTable),
aResult);
aResult.AppendLiteral(", ");
++index;
}
array->Item(index).AppendToString(aProperty, aResult, aSerialization);
}
+inline void
+nsCSSValue::AppendPositionCoordinateToString(
+ const nsCSSValue& aValue, nsCSSProperty aProperty,
+ nsAString& aResult, Serialization aSerialization) const
+{
+ if (aValue.GetUnit() == eCSSUnit_Enumerated) {
+ int32_t intValue = aValue.GetIntValue();
+ AppendASCIItoUTF16(nsCSSProps::ValueToKeyword(intValue,
+ nsCSSProps::kShapeRadiusKTable), aResult);
+ } else {
+ aValue.AppendToString(aProperty, aResult, aSerialization);
+ }
+}
+
+void
+nsCSSValue::AppendCircleOrEllipseToString(nsCSSKeyword aFunctionId,
+ nsCSSProperty aProperty,
+ nsAString& aResult,
+ Serialization aSerialization) const
+{
+ const nsCSSValue::Array* array = GetArrayValue();
+ size_t count = aFunctionId == eCSSKeyword_circle ? 2 : 3;
+ NS_ABORT_IF_FALSE(array->Count() == count + 1, "wrong number of arguments");
+
+ bool hasRadii = array->Item(1).GetUnit() != eCSSUnit_Null;
+
+ AppendPositionCoordinateToString(array->Item(1), aProperty,
+ aResult, aSerialization);
+
+ if (hasRadii && aFunctionId == eCSSKeyword_ellipse) {
+ aResult.Append(' ');
+ AppendPositionCoordinateToString(array->Item(2), aProperty,
+ aResult, aSerialization);
+ }
+
+ // Any position specified?
+ if (array->Item(count).GetUnit() != eCSSUnit_Array) {
+ NS_ABORT_IF_FALSE(array->Item(count).GetUnit() == eCSSUnit_Null,
+ "unexpected value");
+ return;
+ }
+
+ if (hasRadii) {
+ aResult.Append(' ');
+ }
+ aResult.AppendLiteral("at ");
+ array->Item(count).AppendToString(eCSSProperty_background_position,
+ aResult, aSerialization);
+}
+
void
nsCSSValue::AppendToString(nsCSSProperty aProperty, nsAString& aResult,
Serialization aSerialization) const
{
// eCSSProperty_UNKNOWN gets used for some recursive calls below.
NS_ABORT_IF_FALSE((0 <= aProperty &&
aProperty <= eCSSProperty_COUNT_no_shorthands) ||
aProperty == eCSSProperty_UNKNOWN,
@@ -986,16 +1036,22 @@ nsCSSValue::AppendToString(nsCSSProperty
nsStyleUtil::AppendEscapedCSSIdent(ident, aResult);
aResult.Append('(');
switch (functionId) {
case eCSSKeyword_polygon:
AppendPolygonToString(aProperty, aResult, aSerialization);
break;
+ case eCSSKeyword_circle:
+ case eCSSKeyword_ellipse:
+ AppendCircleOrEllipseToString(functionId, aProperty, aResult,
+ aSerialization);
+ break;
+
default: {
// Now, step through the function contents, writing each of
// them as we go.
for (size_t index = 1; index < array->Count(); ++index) {
array->Item(index).AppendToString(aProperty, aResult,
aSerialization);
/* If we're not at the final element, append a comma. */
--- a/layout/style/nsCSSValue.h
+++ b/layout/style/nsCSSValue.h
@@ -716,17 +716,24 @@ public:
private:
static const char16_t* GetBufferValue(nsStringBuffer* aBuffer) {
return static_cast<char16_t*>(aBuffer->Data());
}
void AppendPolygonToString(nsCSSProperty aProperty, nsAString& aResult,
Serialization aValueSerialization) const;
-
+ void AppendPositionCoordinateToString(const nsCSSValue& aValue,
+ nsCSSProperty aProperty,
+ nsAString& aResult,
+ Serialization aSerialization) const;
+ void AppendCircleOrEllipseToString(
+ nsCSSKeyword aFunctionId,
+ nsCSSProperty aProperty, nsAString& aResult,
+ Serialization aValueSerialization) const;
protected:
nsCSSUnit mUnit;
union {
int32_t mInt;
float mFloat;
// Note: the capacity of the buffer may exceed the length of the string.
// If we're of a string type, mString is not null.
nsStringBuffer* mString;
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -5170,51 +5170,103 @@ nsComputedDOMStyle::DoGetLightingColor()
CSSValue*
nsComputedDOMStyle::DoGetStopColor()
{
nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
SetToRGBAColor(val, StyleSVGReset()->mStopColor);
return val;
}
+inline void AppendBasicShapeTypeToString(nsStyleBasicShape::Type aType,
+ nsAutoString& aString)
+{
+ nsCSSKeyword functionName;
+ switch (aType) {
+ case nsStyleBasicShape::Type::ePolygon:
+ functionName = eCSSKeyword_polygon;
+ break;
+ case nsStyleBasicShape::Type::eCircle:
+ functionName = eCSSKeyword_circle;
+ break;
+ case nsStyleBasicShape::Type::eEllipse:
+ functionName = eCSSKeyword_ellipse;
+ break;
+ default:
+ NS_NOTREACHED("unexpected type");
+ }
+ AppendASCIItoUTF16(nsCSSKeywords::GetStringValue(functionName),
+ aString);
+}
+
CSSValue*
nsComputedDOMStyle::CreatePrimitiveValueForClipPath(
const nsStyleBasicShape* aStyleBasicShape, uint8_t aSizingBox)
{
nsDOMCSSValueList* valueList = GetROCSSValueList(false);
-
- if (aStyleBasicShape &&
- aStyleBasicShape->GetShapeType() == nsStyleBasicShape::Type::ePolygon) {
+ if (aStyleBasicShape) {
+ nsStyleBasicShape::Type type = aStyleBasicShape->GetShapeType();
// Shape function name and opening parenthesis.
nsAutoString shapeFunctionString;
- AppendASCIItoUTF16(nsCSSKeywords::GetStringValue(eCSSKeyword_polygon),
- shapeFunctionString);
+ AppendBasicShapeTypeToString(type, shapeFunctionString);
shapeFunctionString.Append('(');
- bool hasEvenOdd = aStyleBasicShape->GetFillRule() ==
- NS_STYLE_FILL_RULE_EVENODD;
- if (hasEvenOdd) {
- shapeFunctionString.AppendLiteral("evenodd");
- }
- for (size_t i = 0; i < aStyleBasicShape->Coordinates().Length(); i += 2) {
- nsAutoString coordString;
- if (i > 0 || hasEvenOdd) {
- shapeFunctionString.AppendLiteral(", ");
+ switch (type) {
+ case nsStyleBasicShape::Type::ePolygon: {
+ bool hasEvenOdd = aStyleBasicShape->GetFillRule() ==
+ NS_STYLE_FILL_RULE_EVENODD;
+ if (hasEvenOdd) {
+ shapeFunctionString.AppendLiteral("evenodd");
+ }
+ for (size_t i = 0;
+ i < aStyleBasicShape->Coordinates().Length(); i += 2) {
+ nsAutoString coordString;
+ if (i > 0 || hasEvenOdd) {
+ shapeFunctionString.AppendLiteral(", ");
+ }
+ SetCssTextToCoord(coordString,
+ aStyleBasicShape->Coordinates()[i]);
+ shapeFunctionString.Append(coordString);
+ shapeFunctionString.Append(' ');
+ SetCssTextToCoord(coordString,
+ aStyleBasicShape->Coordinates()[i + 1]);
+ shapeFunctionString.Append(coordString);
+ }
+ break;
}
- SetCssTextToCoord(coordString,
- aStyleBasicShape->Coordinates()[i]);
- shapeFunctionString.Append(coordString);
- shapeFunctionString.Append(' ');
- SetCssTextToCoord(coordString,
- aStyleBasicShape->Coordinates()[i + 1]);
- shapeFunctionString.Append(coordString);
+ case nsStyleBasicShape::Type::eCircle:
+ case nsStyleBasicShape::Type::eEllipse: {
+ const nsTArray<nsStyleCoord>& radii = aStyleBasicShape->Coordinates();
+ NS_ABORT_IF_FALSE(radii.Length() ==
+ (nsStyleBasicShape::Type::eCircle ? 1 : 2),
+ "wrong number of radii");
+ for (size_t i = 0; i < radii.Length(); ++i) {
+ nsAutoString radius;
+ nsRefPtr<nsROCSSPrimitiveValue> value = new nsROCSSPrimitiveValue;
+ bool clampNegativeCalc = true;
+ SetValueToCoord(value, radii[i], clampNegativeCalc, nullptr,
+ nsCSSProps::kShapeRadiusKTable);
+ value->GetCssText(radius);
+ shapeFunctionString.Append(radius);
+ shapeFunctionString.Append(' ');
+ }
+ shapeFunctionString.AppendLiteral("at ");
+
+ nsRefPtr<nsDOMCSSValueList> position = GetROCSSValueList(false);
+ nsAutoString positionString;
+ SetValueToPosition(aStyleBasicShape->GetPosition(), position);
+ position->GetCssText(positionString);
+ shapeFunctionString.Append(positionString);
+ break;
+ }
+ default:
+ NS_NOTREACHED("unexpected type");
}
shapeFunctionString.Append(')');
- nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
- val->SetString(shapeFunctionString);
- valueList->AppendCSSValue(val);
+ nsROCSSPrimitiveValue* functionValue = new nsROCSSPrimitiveValue;
+ functionValue->SetString(shapeFunctionString);
+ valueList->AppendCSSValue(functionValue);
}
if (aSizingBox == NS_STYLE_CLIP_SHAPE_SIZING_NOBOX) {
return valueList;
}
nsAutoString boxString;
AppendASCIItoUTF16(
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -8796,16 +8796,17 @@ nsRuleNode::SetStyleClipPathToCSSValue(n
if (!cur) {
break;
}
if (cur->mValue.GetUnit() == eCSSUnit_Function) {
nsCSSValue::Array* shapeFunction = cur->mValue.GetArrayValue();
nsCSSKeyword functionName =
(nsCSSKeyword)shapeFunction->Item(0).GetIntValue();
if (functionName == eCSSKeyword_polygon) {
+ NS_ABORT_IF_FALSE(!basicShape, "did not expect value");
basicShape = new nsStyleBasicShape(nsStyleBasicShape::ePolygon);
NS_ABORT_IF_FALSE(shapeFunction->Count() > 1,
"polygon has wrong number of arguments");
size_t j = 1;
if (shapeFunction->Item(j).GetUnit() == eCSSUnit_Enumerated) {
basicShape->SetFillRule(shapeFunction->Item(j).GetIntValue());
++j;
}
@@ -8825,16 +8826,56 @@ nsRuleNode::SetStyleClipPathToCSSValue(n
DebugOnly<bool> didSetCoordY = SetCoord(curPair->mYValue, yCoord,
nsStyleCoord(), mask,
aStyleContext, aPresContext,
aCanStoreInRuleTree);
coordinates.AppendElement(yCoord);
NS_ABORT_IF_FALSE(didSetCoordY, "unexpected y coordinate unit");
curPair = curPair->mNext;
}
+ } else if (functionName == eCSSKeyword_circle ||
+ functionName == eCSSKeyword_ellipse) {
+ nsStyleBasicShape::Type type = functionName == eCSSKeyword_circle ?
+ nsStyleBasicShape::eCircle :
+ nsStyleBasicShape::eEllipse;
+ NS_ABORT_IF_FALSE(!basicShape, "did not expect value");
+ basicShape = new nsStyleBasicShape(type);
+ int32_t mask = SETCOORD_PERCENT | SETCOORD_LENGTH |
+ SETCOORD_STORE_CALC | SETCOORD_ENUMERATED;
+ size_t count = type == nsStyleBasicShape::eCircle ? 2 : 3;
+ NS_ABORT_IF_FALSE(shapeFunction->Count() == count + 1,
+ "unexpected arguments count");
+ NS_ABORT_IF_FALSE(type == nsStyleBasicShape::eCircle ||
+ (shapeFunction->Item(1).GetUnit() == eCSSUnit_Null) ==
+ (shapeFunction->Item(2).GetUnit() == eCSSUnit_Null),
+ "ellipse should have two radii or none");
+ for (size_t j = 1; j < count; ++j) {
+ const nsCSSValue& val = shapeFunction->Item(j);
+ nsStyleCoord radius;
+ if (val.GetUnit() != eCSSUnit_Null) {
+ DebugOnly<bool> didSetRadius = SetCoord(val, radius,
+ nsStyleCoord(), mask,
+ aStyleContext,
+ aPresContext,
+ aCanStoreInRuleTree);
+ NS_ABORT_IF_FALSE(didSetRadius, "unexpected radius unit");
+ } else {
+ radius.SetIntValue(NS_RADIUS_CLOSEST_SIDE, eStyleUnit_Enumerated);
+ }
+ basicShape->Coordinates().AppendElement(radius);
+ }
+ const nsCSSValue& positionVal = shapeFunction->Item(count);
+ if (positionVal.GetUnit() == eCSSUnit_Array) {
+ ComputePositionValue(aStyleContext, positionVal,
+ basicShape->GetPosition(),
+ aCanStoreInRuleTree);
+ } else {
+ NS_ABORT_IF_FALSE(positionVal.GetUnit() == eCSSUnit_Null,
+ "expected no value");
+ }
} else {
// XXX Handle more basic shape functions later.
NS_NOTREACHED("unexpected basic shape function");
return;
}
} else if (cur->mValue.GetUnit() == eCSSUnit_Enumerated) {
int32_t type = cur->mValue.GetIntValue();
if (type > NS_STYLE_CLIP_SHAPE_SIZING_VIEW ||
--- a/layout/style/nsStyleConsts.h
+++ b/layout/style/nsStyleConsts.h
@@ -72,18 +72,18 @@ static inline mozilla::css::Side operato
#define NS_STYLE_CLIP_SHAPE_SIZING_BORDER 3
#define NS_STYLE_CLIP_SHAPE_SIZING_MARGIN 4
#define NS_STYLE_CLIP_SHAPE_SIZING_FILL 5
#define NS_STYLE_CLIP_SHAPE_SIZING_STROKE 6
#define NS_STYLE_CLIP_SHAPE_SIZING_VIEW 7
// Basic Shapes
#define NS_STYLE_BASIC_SHAPE_POLYGON 0
-//#define NS_STYLE_BASIC_SHAPE_CIRCLE 1
-//#define NS_STYLE_BASIC_SHAPE_ELLIPSE 2
+#define NS_STYLE_BASIC_SHAPE_CIRCLE 1
+#define NS_STYLE_BASIC_SHAPE_ELLIPSE 2
//#define NS_STYLE_BASIC_SHAPE_INSET 3
// box-shadow
#define NS_STYLE_BOX_SHADOW_INSET 0
// float-edge
#define NS_STYLE_FLOAT_EDGE_CONTENT 0
#define NS_STYLE_FLOAT_EDGE_MARGIN 1
@@ -150,16 +150,19 @@ static inline mozilla::css::Side operato
#define NS_STYLE_BOX_ORIENT_HORIZONTAL 0
#define NS_STYLE_BOX_ORIENT_VERTICAL 1
// orient
#define NS_STYLE_ORIENT_HORIZONTAL 0
#define NS_STYLE_ORIENT_VERTICAL 1
#define NS_STYLE_ORIENT_AUTO 2
+#define NS_RADIUS_FARTHEST_SIDE 0
+#define NS_RADIUS_CLOSEST_SIDE 1
+
// stack-sizing
#define NS_STYLE_STACK_SIZING_IGNORE 0
#define NS_STYLE_STACK_SIZING_STRETCH_TO_FIT 1
// Azimuth - See nsStyleAural
#define NS_STYLE_AZIMUTH_LEFT_SIDE 0x00
#define NS_STYLE_AZIMUTH_FAR_LEFT 0x01
#define NS_STYLE_AZIMUTH_LEFT 0x02
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -2826,65 +2826,86 @@ struct nsStyleSVG {
return mFill.mType != eStyleSVGPaintType_None && mFillOpacity > 0;
}
};
class nsStyleBasicShape MOZ_FINAL {
public:
enum Type {
// eInset,
- // eCircle,
- // eEllipse,
+ eCircle,
+ eEllipse,
ePolygon
};
explicit nsStyleBasicShape(Type type)
: mType(type)
{
+ mPosition.SetInitialPercentValues(0.5f);
}
Type GetShapeType() const { return mType; }
int32_t GetFillRule() const { return mFillRule; }
void SetFillRule(int32_t aFillRule)
{
NS_ASSERTION(mType == ePolygon, "expected polygon");
mFillRule = aFillRule;
}
+ typedef nsStyleBackground::Position Position;
+ Position& GetPosition() {
+ NS_ASSERTION(mType == eCircle || mType == eEllipse,
+ "expected circle or ellipse");
+ return mPosition;
+ }
+ const Position& GetPosition() const {
+ NS_ASSERTION(mType == eCircle || mType == eEllipse,
+ "expected circle or ellipse");
+ return mPosition;
+ }
+
+ // mCoordinates has coordinates for polygon or radii for
+ // ellipse and circle.
nsTArray<nsStyleCoord>& Coordinates()
{
- NS_ASSERTION(mType == ePolygon, "expected polygon");
+ NS_ASSERTION(mType == ePolygon || mType == eCircle || mType == eEllipse,
+ "expected polygon, circle or ellipse");
return mCoordinates;
}
const nsTArray<nsStyleCoord>& Coordinates() const
{
- NS_ASSERTION(mType == ePolygon, "expected polygon");
+ NS_ASSERTION(mType == ePolygon || mType == eCircle || mType == eEllipse,
+ "expected polygon, circle or ellipse");
return mCoordinates;
}
bool operator==(const nsStyleBasicShape& aOther) const
{
return mType == aOther.mType &&
mFillRule == aOther.mFillRule &&
- mCoordinates == aOther.mCoordinates;
+ mCoordinates == aOther.mCoordinates &&
+ mPosition == aOther.mPosition;
}
bool operator!=(const nsStyleBasicShape& aOther) const {
return !(*this == aOther);
}
NS_INLINE_DECL_REFCOUNTING(nsStyleBasicShape);
private:
~nsStyleBasicShape() {}
Type mType;
int32_t mFillRule;
+ // mCoordinates has coordinates for polygon or radii for
+ // ellipse and circle.
nsTArray<nsStyleCoord> mCoordinates;
+ Position mPosition;
};
struct nsStyleClipPath
{
nsStyleClipPath();
nsStyleClipPath(const nsStyleClipPath& aSource);
~nsStyleClipPath();
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -4617,16 +4617,49 @@ if (SpecialPowers.getBoolPref("layout.cs
"padding-box polygon( 0 20px , 30px 20% ) ",
"polygon(evenodd, 20% 20em) content-box",
"polygon(evenodd, 20vh 20em) padding-box",
"polygon(evenodd, 20vh calc(20% + 20em)) border-box",
"polygon(evenodd, 20vh 20vw) margin-box",
"polygon(evenodd, 20pt 20cm) fill-box",
"polygon(evenodd, 20ex 20pc) stroke-box",
"polygon(evenodd, 20rem 20in) view-box",
+
+ "circle()",
+ "circle(at center)",
+ "circle(at top left 20px)",
+ "circle(at bottom right)",
+ "circle(20%)",
+ "circle(300px)",
+ "circle(calc(20px + 30px))",
+ "circle(farthest-side)",
+ "circle(closest-side)",
+ "circle(closest-side at center)",
+ "circle(farthest-side at top)",
+ "circle(20px at top right)",
+ "circle(40% at 50% 100%)",
+ "circle(calc(20% + 20%) at right bottom)",
+ "circle() padding-box",
+
+ "ellipse()",
+ "ellipse(at center)",
+ "ellipse(at top left 20px)",
+ "ellipse(at bottom right)",
+ "ellipse(20% 20%)",
+ "ellipse(300px 50%)",
+ "ellipse(calc(20px + 30px) 10%)",
+ "ellipse(farthest-side closest-side)",
+ "ellipse(closest-side farthest-side)",
+ "ellipse(farthest-side farthest-side)",
+ "ellipse(closest-side closest-side)",
+ "ellipse(closest-side closest-side at center)",
+ "ellipse(20% farthest-side at top)",
+ "ellipse(20px 50% at top right)",
+ "ellipse(closest-side 40% at 50% 100%)",
+ "ellipse(calc(20% + 20%) calc(20px + 20cm) at right bottom)",
],
invalid_values: [
"url(#test) url(#tes2)",
"polygon (0 0)",
"polygon(20px, 40px)",
"border-box content-box",
"polygon(0 0) polygon(0 0)",
"polygon(nonzero 0 0)",
@@ -4651,21 +4684,57 @@ if (SpecialPowers.getBoolPref("layout.cs
"polygon(0 0) conten-box",
"polygon(0 0) polygon(0 0) farthest-corner",
"polygon(0 0) polygon(0 0) polygon(0 0)",
"border-box polygon(0, 0)",
"border-box padding-box",
"margin-box farthest-side",
"nonsense() border-box",
"border-box nonsense()",
+
+ "circle(at)",
+ "circle(at 20% 20% 30%)",
+ "circle(20px 2px at center)",
+ "circle(2at center)",
+ "circle(closest-corner)",
+ "circle(at center top closest-side)",
+ "circle(-20px)",
+ "circle(farthest-side closest-side)",
+ "circle(20% 20%)",
+ "circle(at farthest-side)",
+
+ "ellipse(at)",
+ "ellipse(at 20% 20% 30%)",
+ "ellipse(20px at center)",
+ "ellipse(-20px 20px)",
+ "ellipse(closest-corner farthest-corner)",
+ "ellipse(20px -20px)",
+ "ellipse(-20px -20px)",
+ "ellipse(farthest-side)",
+ "ellipse(20%)",
+ "ellipse(at farthest-side farthest-side)",
+
+ "polygon(at)",
+ "polygon(at 20% 20% 30%)",
+ "polygon(20px at center)",
+ "polygon(2px 2at center)",
+ "polygon(closest-corner farthest-corner)",
+ "polygon(at center top closest-side closest-side)",
+ "polygon(40% at 50% 100%)",
+ "polygon(40% farthest-side 20px at 50% 100%)",
],
unbalanced_values: [
"polygon(30% 30%",
"polygon(nonzero, 20% 20px",
"polygon(evenodd, 20px 20px",
+
+ "circle(",
+ "circle(40% at 50% 100%",
+ "ellipse(",
+ "ellipse(40% at 50% 100%",
]
};
}
if (SpecialPowers.getBoolPref("layout.css.filters.enabled")) {
gCSSProperties["filter"] = {
domProp: "filter",