Bug 1274835 - Refactor code to process basic shape from clip-path. r=heycam

This can be used in the implementation of shape-outside.

MozReview-Commit-ID: C7bd4D2Kwpm

--HG--
extra : rebase_source : fefdd869b1ede3c518e496d8b25ffa5953a7145d
This commit is contained in:
Ting-Yu Lin 2016-05-22 20:41:19 +08:00
parent 3afaab9b67
commit d06693b2f0
4 changed files with 242 additions and 210 deletions

View File

@ -5886,84 +5886,94 @@ nsComputedDOMStyle::BasicShapeRadiiToString(nsAString& aCssText,
aCssText.Append(verticalString);
}
already_AddRefed<CSSValue>
nsComputedDOMStyle::CreatePrimitiveValueForBasicShape(
const nsStyleBasicShape* aStyleBasicShape)
{
MOZ_ASSERT(aStyleBasicShape, "Expect a valid basic shape pointer!");
nsStyleBasicShape::Type type = aStyleBasicShape->GetShapeType();
// Shape function name and opening parenthesis.
nsAutoString shapeFunctionString;
AppendASCIItoUTF16(nsCSSKeywords::GetStringValue(
aStyleBasicShape->GetShapeTypeName()),
shapeFunctionString);
shapeFunctionString.Append('(');
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;
}
case nsStyleBasicShape::Type::eCircle:
case nsStyleBasicShape::Type::eEllipse: {
const nsTArray<nsStyleCoord>& radii = aStyleBasicShape->Coordinates();
MOZ_ASSERT(radii.Length() ==
(type == nsStyleBasicShape::Type::eCircle ? 1 : 2),
"wrong number of radii");
for (size_t i = 0; i < radii.Length(); ++i) {
nsAutoString radius;
RefPtr<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 ");
RefPtr<nsDOMCSSValueList> position = GetROCSSValueList(false);
nsAutoString positionString;
SetValueToPosition(aStyleBasicShape->GetPosition(), position);
position->GetCssText(positionString);
shapeFunctionString.Append(positionString);
break;
}
case nsStyleBasicShape::Type::eInset: {
BoxValuesToString(shapeFunctionString, aStyleBasicShape->Coordinates());
if (aStyleBasicShape->HasRadius()) {
shapeFunctionString.AppendLiteral(" round ");
nsAutoString radiiString;
BasicShapeRadiiToString(radiiString, aStyleBasicShape->GetRadius());
shapeFunctionString.Append(radiiString);
}
break;
}
default:
NS_NOTREACHED("unexpected type");
}
shapeFunctionString.Append(')');
RefPtr<nsROCSSPrimitiveValue> functionValue = new nsROCSSPrimitiveValue;
functionValue->SetString(shapeFunctionString);
return functionValue.forget();
}
already_AddRefed<CSSValue>
nsComputedDOMStyle::CreatePrimitiveValueForClipPath(
const nsStyleBasicShape* aStyleBasicShape, uint8_t aSizingBox)
{
RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
if (aStyleBasicShape) {
nsStyleBasicShape::Type type = aStyleBasicShape->GetShapeType();
// Shape function name and opening parenthesis.
nsAutoString shapeFunctionString;
AppendASCIItoUTF16(nsCSSKeywords::GetStringValue(
aStyleBasicShape->GetShapeTypeName()),
shapeFunctionString);
shapeFunctionString.Append('(');
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;
}
case nsStyleBasicShape::Type::eCircle:
case nsStyleBasicShape::Type::eEllipse: {
const nsTArray<nsStyleCoord>& radii = aStyleBasicShape->Coordinates();
MOZ_ASSERT(radii.Length() ==
(type == nsStyleBasicShape::Type::eCircle ? 1 : 2),
"wrong number of radii");
for (size_t i = 0; i < radii.Length(); ++i) {
nsAutoString radius;
RefPtr<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 ");
RefPtr<nsDOMCSSValueList> position = GetROCSSValueList(false);
nsAutoString positionString;
SetValueToPosition(aStyleBasicShape->GetPosition(), position);
position->GetCssText(positionString);
shapeFunctionString.Append(positionString);
break;
}
case nsStyleBasicShape::Type::eInset: {
BoxValuesToString(shapeFunctionString, aStyleBasicShape->Coordinates());
if (aStyleBasicShape->HasRadius()) {
shapeFunctionString.AppendLiteral(" round ");
nsAutoString radiiString;
BasicShapeRadiiToString(radiiString, aStyleBasicShape->GetRadius());
shapeFunctionString.Append(radiiString);
}
break;
}
default:
NS_NOTREACHED("unexpected type");
}
shapeFunctionString.Append(')');
RefPtr<nsROCSSPrimitiveValue> functionValue = new nsROCSSPrimitiveValue;
functionValue->SetString(shapeFunctionString);
valueList->AppendCSSValue(functionValue.forget());
valueList->AppendCSSValue(
CreatePrimitiveValueForBasicShape(aStyleBasicShape));
}
if (aSizingBox == NS_STYLE_CLIP_SHAPE_SIZING_NOBOX) {

View File

@ -643,9 +643,12 @@ private:
already_AddRefed<CSSValue> CreatePrimitiveValueForStyleFilter(
const nsStyleFilter& aStyleFilter);
// Helper function for computing basic shape styles.
already_AddRefed<CSSValue> CreatePrimitiveValueForClipPath(
const nsStyleBasicShape* aStyleBasicShape, uint8_t aSizingBox);
// Helper function for computing basic shape styles.
already_AddRefed<CSSValue> CreatePrimitiveValueForBasicShape(
const nsStyleBasicShape* aStyleBasicShape);
void BoxValuesToString(nsAString& aString,
const nsTArray<nsStyleCoord>& aBoxValues);
void BasicShapeRadiiToString(nsAString& aCssText,

View File

@ -9522,6 +9522,155 @@ nsRuleNode::ComputeSVGData(void* aStartStruct,
COMPUTE_END_INHERITED(SVG, svg)
}
already_AddRefed<nsStyleBasicShape>
nsRuleNode::GetStyleBasicShapeFromCSSValue(const nsCSSValue& aValue,
nsStyleContext* aStyleContext,
nsPresContext* aPresContext,
RuleNodeCacheConditions& aConditions)
{
RefPtr<nsStyleBasicShape> basicShape;
nsCSSValue::Array* shapeFunction = aValue.GetArrayValue();
nsCSSKeyword functionName =
(nsCSSKeyword)shapeFunction->Item(0).GetIntValue();
if (functionName == eCSSKeyword_polygon) {
MOZ_ASSERT(!basicShape, "did not expect value");
basicShape = new nsStyleBasicShape(nsStyleBasicShape::ePolygon);
MOZ_ASSERT(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;
}
const int32_t mask = SETCOORD_PERCENT | SETCOORD_LENGTH |
SETCOORD_STORE_CALC;
const nsCSSValuePairList* curPair =
shapeFunction->Item(j).GetPairListValue();
nsTArray<nsStyleCoord>& coordinates = basicShape->Coordinates();
while (curPair) {
nsStyleCoord xCoord, yCoord;
DebugOnly<bool> didSetCoordX = SetCoord(curPair->mXValue, xCoord,
nsStyleCoord(), mask,
aStyleContext, aPresContext,
aConditions);
coordinates.AppendElement(xCoord);
MOZ_ASSERT(didSetCoordX, "unexpected x coordinate unit");
DebugOnly<bool> didSetCoordY = SetCoord(curPair->mYValue, yCoord,
nsStyleCoord(), mask,
aStyleContext, aPresContext,
aConditions);
coordinates.AppendElement(yCoord);
MOZ_ASSERT(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;
MOZ_ASSERT(!basicShape, "did not expect value");
basicShape = new nsStyleBasicShape(type);
const int32_t mask = SETCOORD_PERCENT | SETCOORD_LENGTH |
SETCOORD_STORE_CALC | SETCOORD_ENUMERATED;
size_t count = type == nsStyleBasicShape::eCircle ? 2 : 3;
MOZ_ASSERT(shapeFunction->Count() == count + 1,
"unexpected arguments count");
MOZ_ASSERT(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,
aConditions);
MOZ_ASSERT(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(),
aConditions);
} else {
MOZ_ASSERT(positionVal.GetUnit() == eCSSUnit_Null,
"expected no value");
}
} else if (functionName == eCSSKeyword_inset) {
MOZ_ASSERT(!basicShape, "did not expect value");
basicShape = new nsStyleBasicShape(nsStyleBasicShape::eInset);
MOZ_ASSERT(shapeFunction->Count() == 6,
"inset function has wrong number of arguments");
MOZ_ASSERT(shapeFunction->Item(1).GetUnit() != eCSSUnit_Null,
"no shape arguments defined");
const int32_t mask = SETCOORD_PERCENT | SETCOORD_LENGTH |
SETCOORD_STORE_CALC;
nsTArray<nsStyleCoord>& coords = basicShape->Coordinates();
for (size_t j = 1; j <= 4; ++j) {
const nsCSSValue& val = shapeFunction->Item(j);
nsStyleCoord inset;
// Fill missing values to get 4 at the end.
if (val.GetUnit() == eCSSUnit_Null) {
if (j == 4) {
inset = coords[1];
} else {
MOZ_ASSERT(j != 1, "first argument not specified");
inset = coords[0];
}
} else {
DebugOnly<bool> didSetInset = SetCoord(val, inset,
nsStyleCoord(), mask,
aStyleContext, aPresContext,
aConditions);
MOZ_ASSERT(didSetInset, "unexpected inset unit");
}
coords.AppendElement(inset);
}
nsStyleCorners& insetRadius = basicShape->GetRadius();
if (shapeFunction->Item(5).GetUnit() == eCSSUnit_Array) {
nsCSSValue::Array* radiiArray = shapeFunction->Item(5).GetArrayValue();
NS_FOR_CSS_FULL_CORNERS(corner) {
int cx = NS_FULL_TO_HALF_CORNER(corner, false);
int cy = NS_FULL_TO_HALF_CORNER(corner, true);
const nsCSSValue& radius = radiiArray->Item(corner);
nsStyleCoord coordX, coordY;
DebugOnly<bool> didSetRadii = SetPairCoords(radius, coordX, coordY,
nsStyleCoord(),
nsStyleCoord(), mask,
aStyleContext,
aPresContext,
aConditions);
MOZ_ASSERT(didSetRadii, "unexpected radius unit");
insetRadius.Set(cx, coordX);
insetRadius.Set(cy, coordY);
}
} else {
MOZ_ASSERT(shapeFunction->Item(5).GetUnit() == eCSSUnit_Null,
"unexpected value");
// Initialize border-radius
nsStyleCoord zero;
zero.SetCoordValue(0);
NS_FOR_CSS_HALF_CORNERS(j) {
insetRadius.Set(j, zero);
}
}
} else {
NS_NOTREACHED("unexpected basic shape function");
}
return basicShape.forget();
}
void
nsRuleNode::SetStyleClipPathToCSSValue(nsStyleClipPath* aStyleClipPath,
const nsCSSValue* aValue,
@ -9548,143 +9697,8 @@ nsRuleNode::SetStyleClipPathToCSSValue(nsStyleClipPath* aStyleClipPath,
}
sizingBox = (uint8_t)type;
} else if (array->Item(i).GetUnit() == eCSSUnit_Function) {
nsCSSValue::Array* shapeFunction = array->Item(i).GetArrayValue();
nsCSSKeyword functionName =
(nsCSSKeyword)shapeFunction->Item(0).GetIntValue();
if (functionName == eCSSKeyword_polygon) {
MOZ_ASSERT(!basicShape, "did not expect value");
basicShape = new nsStyleBasicShape(nsStyleBasicShape::ePolygon);
MOZ_ASSERT(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;
}
const int32_t mask = SETCOORD_PERCENT | SETCOORD_LENGTH |
SETCOORD_STORE_CALC;
const nsCSSValuePairList* curPair =
shapeFunction->Item(j).GetPairListValue();
nsTArray<nsStyleCoord>& coordinates = basicShape->Coordinates();
while (curPair) {
nsStyleCoord xCoord, yCoord;
DebugOnly<bool> didSetCoordX = SetCoord(curPair->mXValue, xCoord,
nsStyleCoord(), mask,
aStyleContext, aPresContext,
aConditions);
coordinates.AppendElement(xCoord);
MOZ_ASSERT(didSetCoordX, "unexpected x coordinate unit");
DebugOnly<bool> didSetCoordY = SetCoord(curPair->mYValue, yCoord,
nsStyleCoord(), mask,
aStyleContext, aPresContext,
aConditions);
coordinates.AppendElement(yCoord);
MOZ_ASSERT(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;
MOZ_ASSERT(!basicShape, "did not expect value");
basicShape = new nsStyleBasicShape(type);
const int32_t mask = SETCOORD_PERCENT | SETCOORD_LENGTH |
SETCOORD_STORE_CALC | SETCOORD_ENUMERATED;
size_t count = type == nsStyleBasicShape::eCircle ? 2 : 3;
MOZ_ASSERT(shapeFunction->Count() == count + 1,
"unexpected arguments count");
MOZ_ASSERT(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,
aConditions);
MOZ_ASSERT(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(),
aConditions);
} else {
MOZ_ASSERT(positionVal.GetUnit() == eCSSUnit_Null,
"expected no value");
}
} else if (functionName == eCSSKeyword_inset) {
MOZ_ASSERT(!basicShape, "did not expect value");
basicShape = new nsStyleBasicShape(nsStyleBasicShape::eInset);
MOZ_ASSERT(shapeFunction->Count() == 6,
"inset function has wrong number of arguments");
MOZ_ASSERT(shapeFunction->Item(1).GetUnit() != eCSSUnit_Null,
"no shape arguments defined");
const int32_t mask = SETCOORD_PERCENT | SETCOORD_LENGTH |
SETCOORD_STORE_CALC;
nsTArray<nsStyleCoord>& coords = basicShape->Coordinates();
for (size_t j = 1; j <= 4; ++j) {
const nsCSSValue& val = shapeFunction->Item(j);
nsStyleCoord inset;
// Fill missing values to get 4 at the end.
if (val.GetUnit() == eCSSUnit_Null) {
if (j == 4) {
inset = coords[1];
} else {
MOZ_ASSERT(j != 1, "first argument not specified");
inset = coords[0];
}
} else {
DebugOnly<bool> didSetInset = SetCoord(val, inset,
nsStyleCoord(), mask,
aStyleContext, aPresContext,
aConditions);
MOZ_ASSERT(didSetInset, "unexpected inset unit");
}
coords.AppendElement(inset);
}
nsStyleCorners& insetRadius = basicShape->GetRadius();
if (shapeFunction->Item(5).GetUnit() == eCSSUnit_Array) {
nsCSSValue::Array* radiiArray = shapeFunction->Item(5).GetArrayValue();
NS_FOR_CSS_FULL_CORNERS(corner) {
int cx = NS_FULL_TO_HALF_CORNER(corner, false);
int cy = NS_FULL_TO_HALF_CORNER(corner, true);
const nsCSSValue& radius = radiiArray->Item(corner);
nsStyleCoord coordX, coordY;
DebugOnly<bool> didSetRadii = SetPairCoords(radius, coordX, coordY,
nsStyleCoord(),
nsStyleCoord(), mask,
aStyleContext,
aPresContext,
aConditions);
MOZ_ASSERT(didSetRadii, "unexpected radius unit");
insetRadius.Set(cx, coordX);
insetRadius.Set(cy, coordY);
}
} else {
MOZ_ASSERT(shapeFunction->Item(5).GetUnit() == eCSSUnit_Null,
"unexpected value");
// Initialize border-radius
nsStyleCoord zero;
zero.SetCoordValue(0);
NS_FOR_CSS_HALF_CORNERS(j) {
insetRadius.Set(j, zero);
}
}
} else {
NS_NOTREACHED("unexpected basic shape function");
return;
}
basicShape = GetStyleBasicShapeFromCSSValue(array->Item(i), aStyleContext,
aPresContext, aConditions);
} else {
NS_NOTREACHED("unexpected value");
return;

View File

@ -788,6 +788,11 @@ protected:
nsStyleContext* aContext,
bool aIsBoxShadow,
mozilla::RuleNodeCacheConditions& aConditions);
already_AddRefed<nsStyleBasicShape>
GetStyleBasicShapeFromCSSValue(const nsCSSValue& aValue,
nsStyleContext* aStyleContext,
nsPresContext* aPresContext,
mozilla::RuleNodeCacheConditions& aConditions);
bool SetStyleFilterToCSSValue(nsStyleFilter* aStyleFilter,
const nsCSSValue& aValue,
nsStyleContext* aStyleContext,