BasicShapeFunctions.cpp [plain text]
#include "config.h"
#include "BasicShapeFunctions.h"
#include "BasicShapes.h"
#include "CSSBasicShapes.h"
#include "CSSPrimitiveValueMappings.h"
#include "CSSValuePool.h"
#include "Pair.h"
#include "RenderStyle.h"
namespace WebCore {
static Ref<CSSPrimitiveValue> valueForCenterCoordinate(CSSValuePool& pool, const RenderStyle& style, const BasicShapeCenterCoordinate& center, EBoxOrient orientation)
{
if (center.direction() == BasicShapeCenterCoordinate::TopLeft)
return pool.createValue(center.length(), style);
CSSValueID keyword = orientation == HORIZONTAL ? CSSValueRight : CSSValueBottom;
return pool.createValue(Pair::create(pool.createIdentifierValue(keyword), pool.createValue(center.length(), style)));
}
static Ref<CSSPrimitiveValue> basicShapeRadiusToCSSValue(const RenderStyle& style, CSSValuePool& pool, const BasicShapeRadius& radius)
{
switch (radius.type()) {
case BasicShapeRadius::Value:
return pool.createValue(radius.value(), style);
case BasicShapeRadius::ClosestSide:
return pool.createIdentifierValue(CSSValueClosestSide);
case BasicShapeRadius::FarthestSide:
return pool.createIdentifierValue(CSSValueFarthestSide);
}
ASSERT_NOT_REACHED();
return pool.createIdentifierValue(CSSValueClosestSide);
}
Ref<CSSValue> valueForBasicShape(const RenderStyle& style, const BasicShape& basicShape)
{
CSSValuePool& pool = cssValuePool();
RefPtr<CSSBasicShape> basicShapeValue;
switch (basicShape.type()) {
case BasicShape::BasicShapeCircleType: {
const auto& circle = downcast<BasicShapeCircle>(basicShape);
auto circleValue = CSSBasicShapeCircle::create();
circleValue->setCenterX(valueForCenterCoordinate(pool, style, circle.centerX(), HORIZONTAL));
circleValue->setCenterY(valueForCenterCoordinate(pool, style, circle.centerY(), VERTICAL));
circleValue->setRadius(basicShapeRadiusToCSSValue(style, pool, circle.radius()));
basicShapeValue = circleValue.copyRef();
break;
}
case BasicShape::BasicShapeEllipseType: {
const auto& ellipse = downcast<BasicShapeEllipse>(basicShape);
auto ellipseValue = CSSBasicShapeEllipse::create();
ellipseValue->setCenterX(valueForCenterCoordinate(pool, style, ellipse.centerX(), HORIZONTAL));
ellipseValue->setCenterY(valueForCenterCoordinate(pool, style, ellipse.centerY(), VERTICAL));
ellipseValue->setRadiusX(basicShapeRadiusToCSSValue(style, pool, ellipse.radiusX()));
ellipseValue->setRadiusY(basicShapeRadiusToCSSValue(style, pool, ellipse.radiusY()));
basicShapeValue = ellipseValue.copyRef();
break;
}
case BasicShape::BasicShapePolygonType: {
const auto& polygon = downcast<BasicShapePolygon>(basicShape);
auto polygonValue = CSSBasicShapePolygon::create();
polygonValue->setWindRule(polygon.windRule());
const Vector<Length>& values = polygon.values();
for (unsigned i = 0; i < values.size(); i += 2)
polygonValue->appendPoint(pool.createValue(values.at(i), style), pool.createValue(values.at(i + 1), style));
basicShapeValue = polygonValue.copyRef();
break;
}
case BasicShape::BasicShapeInsetType: {
const auto& inset = downcast<BasicShapeInset>(basicShape);
auto insetValue = CSSBasicShapeInset::create();
insetValue->setTop(pool.createValue(inset.top(), style));
insetValue->setRight(pool.createValue(inset.right(), style));
insetValue->setBottom(pool.createValue(inset.bottom(), style));
insetValue->setLeft(pool.createValue(inset.left(), style));
insetValue->setTopLeftRadius(pool.createValue(inset.topLeftRadius(), style));
insetValue->setTopRightRadius(pool.createValue(inset.topRightRadius(), style));
insetValue->setBottomRightRadius(pool.createValue(inset.bottomRightRadius(), style));
insetValue->setBottomLeftRadius(pool.createValue(inset.bottomLeftRadius(), style));
basicShapeValue = insetValue.copyRef();
break;
}
default:
break;
}
return pool.createValue(basicShapeValue.releaseNonNull());
}
static Length convertToLength(const CSSToLengthConversionData& conversionData, CSSPrimitiveValue* value)
{
return value->convertToLength<FixedIntegerConversion | FixedFloatConversion | PercentConversion | CalculatedConversion>(conversionData);
}
static LengthSize convertToLengthSize(const CSSToLengthConversionData& conversionData, CSSPrimitiveValue* value)
{
if (!value)
return LengthSize(Length(0, Fixed), Length(0, Fixed));
Pair* pair = value->getPairValue();
return LengthSize(convertToLength(conversionData, pair->first()), convertToLength(conversionData, pair->second()));
}
static BasicShapeCenterCoordinate convertToCenterCoordinate(const CSSToLengthConversionData& conversionData, CSSPrimitiveValue* value)
{
BasicShapeCenterCoordinate::Direction direction;
Length offset = Length(0, Fixed);
CSSValueID keyword = CSSValueTop;
if (!value)
keyword = CSSValueCenter;
else if (value->isValueID())
keyword = value->getValueID();
else if (Pair* pair = value->getPairValue()) {
keyword = pair->first()->getValueID();
offset = convertToLength(conversionData, pair->second());
} else
offset = convertToLength(conversionData, value);
switch (keyword) {
case CSSValueTop:
case CSSValueLeft:
direction = BasicShapeCenterCoordinate::TopLeft;
break;
case CSSValueRight:
case CSSValueBottom:
direction = BasicShapeCenterCoordinate::BottomRight;
break;
case CSSValueCenter:
direction = BasicShapeCenterCoordinate::TopLeft;
offset = Length(50, Percent);
break;
default:
ASSERT_NOT_REACHED();
direction = BasicShapeCenterCoordinate::TopLeft;
break;
}
return BasicShapeCenterCoordinate(direction, offset);
}
static BasicShapeRadius cssValueToBasicShapeRadius(const CSSToLengthConversionData& conversionData, PassRefPtr<CSSPrimitiveValue> radius)
{
if (!radius)
return BasicShapeRadius(BasicShapeRadius::ClosestSide);
if (radius->isValueID()) {
switch (radius->getValueID()) {
case CSSValueClosestSide:
return BasicShapeRadius(BasicShapeRadius::ClosestSide);
case CSSValueFarthestSide:
return BasicShapeRadius(BasicShapeRadius::FarthestSide);
default:
ASSERT_NOT_REACHED();
break;
}
}
return BasicShapeRadius(convertToLength(conversionData, radius.get()));
}
Ref<BasicShape> basicShapeForValue(const CSSToLengthConversionData& conversionData, const CSSBasicShape* basicShapeValue)
{
RefPtr<BasicShape> basicShape;
switch (basicShapeValue->type()) {
case CSSBasicShape::CSSBasicShapeCircleType: {
const CSSBasicShapeCircle& circleValue = downcast<CSSBasicShapeCircle>(*basicShapeValue);
RefPtr<BasicShapeCircle> circle = BasicShapeCircle::create();
circle->setCenterX(convertToCenterCoordinate(conversionData, circleValue.centerX()));
circle->setCenterY(convertToCenterCoordinate(conversionData, circleValue.centerY()));
circle->setRadius(cssValueToBasicShapeRadius(conversionData, circleValue.radius()));
basicShape = circle.release();
break;
}
case CSSBasicShape::CSSBasicShapeEllipseType: {
const CSSBasicShapeEllipse& ellipseValue = downcast<CSSBasicShapeEllipse>(*basicShapeValue);
RefPtr<BasicShapeEllipse> ellipse = BasicShapeEllipse::create();
ellipse->setCenterX(convertToCenterCoordinate(conversionData, ellipseValue.centerX()));
ellipse->setCenterY(convertToCenterCoordinate(conversionData, ellipseValue.centerY()));
ellipse->setRadiusX(cssValueToBasicShapeRadius(conversionData, ellipseValue.radiusX()));
ellipse->setRadiusY(cssValueToBasicShapeRadius(conversionData, ellipseValue.radiusY()));
basicShape = ellipse.release();
break;
}
case CSSBasicShape::CSSBasicShapePolygonType: {
const CSSBasicShapePolygon& polygonValue = downcast<CSSBasicShapePolygon>(*basicShapeValue);
RefPtr<BasicShapePolygon> polygon = BasicShapePolygon::create();
polygon->setWindRule(polygonValue.windRule());
const Vector<RefPtr<CSSPrimitiveValue>>& values = polygonValue.values();
for (unsigned i = 0; i < values.size(); i += 2)
polygon->appendPoint(convertToLength(conversionData, values.at(i).get()), convertToLength(conversionData, values.at(i + 1).get()));
basicShape = polygon.release();
break;
}
case CSSBasicShape::CSSBasicShapeInsetType: {
const CSSBasicShapeInset& rectValue = downcast<CSSBasicShapeInset>(*basicShapeValue);
RefPtr<BasicShapeInset> rect = BasicShapeInset::create();
rect->setTop(convertToLength(conversionData, rectValue.top()));
rect->setRight(convertToLength(conversionData, rectValue.right()));
rect->setBottom(convertToLength(conversionData, rectValue.bottom()));
rect->setLeft(convertToLength(conversionData, rectValue.left()));
rect->setTopLeftRadius(convertToLengthSize(conversionData, rectValue.topLeftRadius()));
rect->setTopRightRadius(convertToLengthSize(conversionData, rectValue.topRightRadius()));
rect->setBottomRightRadius(convertToLengthSize(conversionData, rectValue.bottomRightRadius()));
rect->setBottomLeftRadius(convertToLengthSize(conversionData, rectValue.bottomLeftRadius()));
basicShape = rect.release();
break;
}
default:
break;
}
return basicShape.releaseNonNull();
}
float floatValueForCenterCoordinate(const BasicShapeCenterCoordinate& center, float boxDimension)
{
float offset = floatValueForLength(center.length(), boxDimension);
if (center.direction() == BasicShapeCenterCoordinate::TopLeft)
return offset;
return boxDimension - offset;
}
}