This source file includes following definitions.
- DEFINE_EMPTY_DESTRUCTOR_WILL_BE_REMOVED
- serializePositionOffset
- buildSerializablePositionOffset
- cssText
- equals
- trace
- buildEllipseString
- cssText
- equals
- trace
- buildPolygonString
- cssText
- equals
- trace
- buildInsetString
- updateCornerRadiusWidthAndHeight
- cssText
- equals
- trace
#include "config.h"
#include "core/css/CSSBasicShapes.h"
#include "core/css/CSSValuePool.h"
#include "core/css/Pair.h"
#include "platform/Length.h"
#include "wtf/text/StringBuilder.h"
using namespace WTF;
namespace WebCore {
DEFINE_EMPTY_DESTRUCTOR_WILL_BE_REMOVED(CSSBasicShape)
static String buildCircleString(const String& radius, const String& centerX, const String& centerY, const String& box)
{
char at[] = "at";
char separator[] = " ";
StringBuilder result;
result.appendLiteral("circle(");
if (!radius.isNull())
result.append(radius);
if (!centerX.isNull() || !centerY.isNull()) {
if (!radius.isNull())
result.appendLiteral(separator);
result.append(at);
result.appendLiteral(separator);
result.append(centerX);
result.appendLiteral(separator);
result.append(centerY);
}
result.append(")");
if (box.length()) {
result.appendLiteral(separator);
result.append(box);
}
return result.toString();
}
static String serializePositionOffset(const Pair& offset, const Pair& other)
{
if ((offset.first()->getValueID() == CSSValueLeft && other.first()->getValueID() == CSSValueTop)
|| (offset.first()->getValueID() == CSSValueTop && other.first()->getValueID() == CSSValueLeft))
return offset.second()->cssText();
return offset.cssText();
}
static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> buildSerializablePositionOffset(PassRefPtrWillBeRawPtr<CSSPrimitiveValue> offset, CSSValueID defaultSide)
{
CSSValueID side = defaultSide;
RefPtrWillBeRawPtr<CSSPrimitiveValue> amount = nullptr;
if (!offset) {
side = CSSValueCenter;
} else if (offset->isValueID()) {
side = offset->getValueID();
} else if (Pair* pair = offset->getPairValue()) {
side = pair->first()->getValueID();
amount = pair->second();
} else {
amount = offset;
}
if (side == CSSValueCenter) {
side = defaultSide;
amount = cssValuePool().createValue(Length(50, Percent));
} else if ((side == CSSValueRight || side == CSSValueBottom)
&& amount->isPercentage()) {
side = defaultSide;
amount = cssValuePool().createValue(Length(100 - amount->getFloatValue(), Percent));
} else if (amount->isLength() && !amount->getFloatValue()) {
if (side == CSSValueRight || side == CSSValueBottom)
amount = cssValuePool().createValue(Length(100, Percent));
else
amount = cssValuePool().createValue(Length(0, Percent));
side = defaultSide;
}
return cssValuePool().createValue(Pair::create(cssValuePool().createValue(side), amount.release(), Pair::KeepIdenticalValues));
}
String CSSBasicShapeCircle::cssText() const
{
RefPtrWillBeRawPtr<CSSPrimitiveValue> normalizedCX = buildSerializablePositionOffset(m_centerX, CSSValueLeft);
RefPtrWillBeRawPtr<CSSPrimitiveValue> normalizedCY = buildSerializablePositionOffset(m_centerY, CSSValueTop);
return buildCircleString(m_radius ? m_radius->cssText() : String(),
serializePositionOffset(*normalizedCX->getPairValue(), *normalizedCY->getPairValue()),
serializePositionOffset(*normalizedCY->getPairValue(), *normalizedCX->getPairValue()),
m_referenceBox ? m_referenceBox->cssText() : String());
}
bool CSSBasicShapeCircle::equals(const CSSBasicShape& shape) const
{
if (shape.type() != CSSBasicShapeCircleType)
return false;
const CSSBasicShapeCircle& other = static_cast<const CSSBasicShapeCircle&>(shape);
return compareCSSValuePtr(m_centerX, other.m_centerX)
&& compareCSSValuePtr(m_centerY, other.m_centerY)
&& compareCSSValuePtr(m_radius, other.m_radius)
&& compareCSSValuePtr(m_referenceBox, other.m_referenceBox);
}
void CSSBasicShapeCircle::trace(Visitor* visitor)
{
visitor->trace(m_centerX);
visitor->trace(m_centerY);
visitor->trace(m_radius);
CSSBasicShape::trace(visitor);
}
static String buildEllipseString(const String& radiusX, const String& radiusY, const String& centerX, const String& centerY, const String& box)
{
char at[] = "at";
char separator[] = " ";
StringBuilder result;
result.appendLiteral("ellipse(");
bool needsSeparator = false;
if (!radiusX.isNull()) {
result.append(radiusX);
needsSeparator = true;
}
if (!radiusY.isNull()) {
if (needsSeparator)
result.appendLiteral(separator);
result.append(radiusY);
needsSeparator = true;
}
if (!centerX.isNull() || !centerY.isNull()) {
if (needsSeparator)
result.appendLiteral(separator);
result.appendLiteral(at);
result.appendLiteral(separator);
result.append(centerX);
result.appendLiteral(separator);
result.append(centerY);
}
result.append(")");
if (box.length()) {
result.appendLiteral(separator);
result.append(box);
}
return result.toString();
}
String CSSBasicShapeEllipse::cssText() const
{
RefPtrWillBeRawPtr<CSSPrimitiveValue> normalizedCX = buildSerializablePositionOffset(m_centerX, CSSValueLeft);
RefPtrWillBeRawPtr<CSSPrimitiveValue> normalizedCY = buildSerializablePositionOffset(m_centerY, CSSValueTop);
return buildEllipseString(m_radiusX ? m_radiusX->cssText() : String(),
m_radiusY ? m_radiusY->cssText() : String(),
serializePositionOffset(*normalizedCX->getPairValue(), *normalizedCY->getPairValue()),
serializePositionOffset(*normalizedCY->getPairValue(), *normalizedCX->getPairValue()),
m_referenceBox ? m_referenceBox->cssText() : String());
}
bool CSSBasicShapeEllipse::equals(const CSSBasicShape& shape) const
{
if (shape.type() != CSSBasicShapeEllipseType)
return false;
const CSSBasicShapeEllipse& other = static_cast<const CSSBasicShapeEllipse&>(shape);
return compareCSSValuePtr(m_centerX, other.m_centerX)
&& compareCSSValuePtr(m_centerY, other.m_centerY)
&& compareCSSValuePtr(m_radiusX, other.m_radiusX)
&& compareCSSValuePtr(m_radiusY, other.m_radiusY)
&& compareCSSValuePtr(m_referenceBox, other.m_referenceBox);
}
void CSSBasicShapeEllipse::trace(Visitor* visitor)
{
visitor->trace(m_centerX);
visitor->trace(m_centerY);
visitor->trace(m_radiusX);
visitor->trace(m_radiusY);
CSSBasicShape::trace(visitor);
}
static String buildPolygonString(const WindRule& windRule, const Vector<String>& points, const String& box)
{
ASSERT(!(points.size() % 2));
StringBuilder result;
const char evenOddOpening[] = "polygon(evenodd, ";
const char nonZeroOpening[] = "polygon(";
const char commaSeparator[] = ", ";
COMPILE_ASSERT(sizeof(evenOddOpening) > sizeof(nonZeroOpening), polygon_string_openings_have_same_length);
size_t length = sizeof(evenOddOpening) - 1;
for (size_t i = 0; i < points.size(); i += 2) {
if (i)
length += (sizeof(commaSeparator) - 1);
length += points[i].length() + 1 + points[i + 1].length();
}
if (!box.isEmpty())
length += box.length() + 1;
result.reserveCapacity(length);
if (windRule == RULE_EVENODD)
result.appendLiteral(evenOddOpening);
else
result.appendLiteral(nonZeroOpening);
for (size_t i = 0; i < points.size(); i += 2) {
if (i)
result.appendLiteral(commaSeparator);
result.append(points[i]);
result.append(' ');
result.append(points[i + 1]);
}
result.append(')');
if (!box.isEmpty()) {
result.append(' ');
result.append(box);
}
return result.toString();
}
String CSSBasicShapePolygon::cssText() const
{
Vector<String> points;
points.reserveInitialCapacity(m_values.size());
for (size_t i = 0; i < m_values.size(); ++i)
points.append(m_values.at(i)->cssText());
return buildPolygonString(m_windRule, points, m_referenceBox ? m_referenceBox->cssText() : String());
}
bool CSSBasicShapePolygon::equals(const CSSBasicShape& shape) const
{
if (shape.type() != CSSBasicShapePolygonType)
return false;
const CSSBasicShapePolygon& rhs = static_cast<const CSSBasicShapePolygon&>(shape);
if (!compareCSSValuePtr(m_referenceBox, rhs.m_referenceBox))
return false;
return compareCSSValueVector(m_values, rhs.m_values);
}
void CSSBasicShapePolygon::trace(Visitor* visitor)
{
visitor->trace(m_values);
CSSBasicShape::trace(visitor);
}
static String buildInsetString(const String& top, const String& right, const String& bottom, const String& left,
const String& topLeftRadiusWidth, const String& topLeftRadiusHeight,
const String& topRightRadiusWidth, const String& topRightRadiusHeight,
const String& bottomRightRadiusWidth, const String& bottomRightRadiusHeight,
const String& bottomLeftRadiusWidth, const String& bottomLeftRadiusHeight)
{
char opening[] = "inset(";
char separator[] = " ";
char cornersSeparator[] = "round";
StringBuilder result;
result.appendLiteral(opening);
result.append(top);
if (!right.isNull()) {
result.appendLiteral(separator);
result.append(right);
}
if (!bottom.isNull()) {
result.appendLiteral(separator);
result.append(bottom);
}
if (!left.isNull()) {
result.appendLiteral(separator);
result.append(left);
}
if (!topLeftRadiusWidth.isNull() && !topLeftRadiusHeight.isNull()) {
result.appendLiteral(separator);
result.appendLiteral(cornersSeparator);
result.appendLiteral(separator);
result.append(topLeftRadiusWidth);
result.appendLiteral(separator);
result.append(topRightRadiusWidth);
result.appendLiteral(separator);
result.append(bottomRightRadiusWidth);
result.appendLiteral(separator);
result.append(bottomLeftRadiusWidth);
result.appendLiteral(separator);
result.appendLiteral("/");
result.appendLiteral(separator);
result.append(topLeftRadiusHeight);
result.appendLiteral(separator);
result.append(topRightRadiusHeight);
result.appendLiteral(separator);
result.append(bottomRightRadiusHeight);
result.appendLiteral(separator);
result.append(bottomLeftRadiusHeight);
}
result.append(')');
return result.toString();
}
static inline void updateCornerRadiusWidthAndHeight(CSSPrimitiveValue* corner, String& width, String& height)
{
if (!corner)
return;
Pair* radius = corner->getPairValue();
width = radius->first() ? radius->first()->cssText() : String("0");
if (radius->second())
height = radius->second()->cssText();
}
String CSSBasicShapeInset::cssText() const
{
String topLeftRadiusWidth;
String topLeftRadiusHeight;
String topRightRadiusWidth;
String topRightRadiusHeight;
String bottomRightRadiusWidth;
String bottomRightRadiusHeight;
String bottomLeftRadiusWidth;
String bottomLeftRadiusHeight;
updateCornerRadiusWidthAndHeight(topLeftRadius(), topLeftRadiusWidth, topLeftRadiusHeight);
updateCornerRadiusWidthAndHeight(topRightRadius(), topRightRadiusWidth, topRightRadiusHeight);
updateCornerRadiusWidthAndHeight(bottomRightRadius(), bottomRightRadiusWidth, bottomRightRadiusHeight);
updateCornerRadiusWidthAndHeight(bottomLeftRadius(), bottomLeftRadiusWidth, bottomLeftRadiusHeight);
return buildInsetString(m_top ? m_top->cssText() : String(),
m_right ? m_right->cssText() : String(),
m_bottom ? m_bottom->cssText() : String(),
m_left ? m_left->cssText() : String(),
topLeftRadiusWidth,
topLeftRadiusHeight,
topRightRadiusWidth,
topRightRadiusHeight,
bottomRightRadiusWidth,
bottomRightRadiusHeight,
bottomLeftRadiusWidth,
bottomLeftRadiusHeight);
}
bool CSSBasicShapeInset::equals(const CSSBasicShape& shape) const
{
if (shape.type() != CSSBasicShapeInsetType)
return false;
const CSSBasicShapeInset& other = static_cast<const CSSBasicShapeInset&>(shape);
return compareCSSValuePtr(m_top, other.m_top)
&& compareCSSValuePtr(m_right, other.m_right)
&& compareCSSValuePtr(m_bottom, other.m_bottom)
&& compareCSSValuePtr(m_left, other.m_left)
&& compareCSSValuePtr(m_topLeftRadius, other.m_topLeftRadius)
&& compareCSSValuePtr(m_topRightRadius, other.m_topRightRadius)
&& compareCSSValuePtr(m_bottomRightRadius, other.m_bottomRightRadius)
&& compareCSSValuePtr(m_bottomLeftRadius, other.m_bottomLeftRadius);
}
void CSSBasicShapeInset::trace(Visitor* visitor)
{
visitor->trace(m_top);
visitor->trace(m_right);
visitor->trace(m_bottom);
visitor->trace(m_left);
visitor->trace(m_topLeftRadius);
visitor->trace(m_topRightRadius);
visitor->trace(m_bottomRightRadius);
visitor->trace(m_bottomLeftRadius);
CSSBasicShape::trace(visitor);
}
}