/Source/core/css/CSSBasicShapes.cpp
C++ | 426 lines | 337 code | 59 blank | 30 comment | 108 complexity | 0e16d1a92331301f8e96e4ecf1e8004e MD5 | raw file
Possible License(s): BSD-3-Clause, Unlicense, AGPL-1.0, Apache-2.0
- /*
- * Copyright (C) 2011 Adobe Systems Incorporated. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
- * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
- * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
- #include "config.h"
- #include "core/css/CSSBasicShapes.h"
- #include "core/css/CSSValuePair.h"
- #include "core/css/CSSValuePool.h"
- #include "platform/Length.h"
- #include "wtf/text/StringBuilder.h"
- using namespace WTF;
- namespace blink {
- DEFINE_EMPTY_DESTRUCTOR_WILL_BE_REMOVED(CSSBasicShape)
- static String buildCircleString(const String& radius, const String& centerX, const String& centerY)
- {
- 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(')');
- return result.toString();
- }
- static String serializePositionOffset(const CSSValuePair& offset, const CSSValuePair& other)
- {
- if ((toCSSPrimitiveValue(offset.first()).getValueID() == CSSValueLeft && toCSSPrimitiveValue(other.first()).getValueID() == CSSValueTop)
- || (toCSSPrimitiveValue(offset.first()).getValueID() == CSSValueTop && toCSSPrimitiveValue(other.first()).getValueID() == CSSValueLeft))
- return offset.second().cssText();
- return offset.cssText();
- }
- static PassRefPtrWillBeRawPtr<CSSValuePair> buildSerializablePositionOffset(PassRefPtrWillBeRawPtr<CSSValue> offset, CSSValueID defaultSide)
- {
- CSSValueID side = defaultSide;
- RefPtrWillBeRawPtr<CSSPrimitiveValue> amount = nullptr;
- if (!offset) {
- side = CSSValueCenter;
- } else if (offset->isPrimitiveValue() && toCSSPrimitiveValue(offset.get())->isValueID()) {
- side = toCSSPrimitiveValue(offset.get())->getValueID();
- } else if (offset->isValuePair()) {
- side = toCSSPrimitiveValue(toCSSValuePair(*offset).first()).getValueID();
- amount = &toCSSPrimitiveValue(toCSSValuePair(*offset).second());
- } else {
- amount = toCSSPrimitiveValue(offset.get());
- }
- if (side == CSSValueCenter) {
- side = defaultSide;
- amount = cssValuePool().createValue(50, CSSPrimitiveValue::UnitType::Percentage);
- } else if ((side == CSSValueRight || side == CSSValueBottom)
- && amount->isPercentage()) {
- side = defaultSide;
- amount = cssValuePool().createValue(100 - amount->getFloatValue(), CSSPrimitiveValue::UnitType::Percentage);
- } else if (amount->isLength() && !amount->getFloatValue()) {
- if (side == CSSValueRight || side == CSSValueBottom)
- amount = cssValuePool().createValue(100, CSSPrimitiveValue::UnitType::Percentage);
- else
- amount = cssValuePool().createValue(0, CSSPrimitiveValue::UnitType::Percentage);
- side = defaultSide;
- }
- return CSSValuePair::create(cssValuePool().createValue(side), amount.release(), CSSValuePair::KeepIdenticalValues);
- }
- String CSSBasicShapeCircle::cssText() const
- {
- RefPtrWillBeRawPtr<CSSValuePair> normalizedCX = buildSerializablePositionOffset(m_centerX, CSSValueLeft);
- RefPtrWillBeRawPtr<CSSValuePair> normalizedCY = buildSerializablePositionOffset(m_centerY, CSSValueTop);
- String radius;
- if (m_radius && m_radius->getValueID() != CSSValueClosestSide)
- radius = m_radius->cssText();
- return buildCircleString(radius,
- serializePositionOffset(*normalizedCX, *normalizedCY),
- serializePositionOffset(*normalizedCY, *normalizedCX));
- }
- bool CSSBasicShapeCircle::equals(const CSSBasicShape& shape) const
- {
- if (shape.type() != CSSBasicShapeCircleType)
- return false;
- const CSSBasicShapeCircle& other = toCSSBasicShapeCircle(shape);
- return compareCSSValuePtr(m_centerX, other.m_centerX)
- && compareCSSValuePtr(m_centerY, other.m_centerY)
- && compareCSSValuePtr(m_radius, other.m_radius);
- }
- DEFINE_TRACE(CSSBasicShapeCircle)
- {
- 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)
- {
- 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(')');
- return result.toString();
- }
- String CSSBasicShapeEllipse::cssText() const
- {
- RefPtrWillBeRawPtr<CSSValuePair> normalizedCX = buildSerializablePositionOffset(m_centerX, CSSValueLeft);
- RefPtrWillBeRawPtr<CSSValuePair> normalizedCY = buildSerializablePositionOffset(m_centerY, CSSValueTop);
- String radiusX;
- String radiusY;
- if (m_radiusX) {
- bool shouldSerializeRadiusXValue = m_radiusX->getValueID() != CSSValueClosestSide;
- bool shouldSerializeRadiusYValue = false;
- if (m_radiusY) {
- shouldSerializeRadiusYValue = m_radiusY->getValueID() != CSSValueClosestSide;
- if (shouldSerializeRadiusYValue)
- radiusY = m_radiusY->cssText();
- }
- if (shouldSerializeRadiusXValue || (!shouldSerializeRadiusXValue && shouldSerializeRadiusYValue))
- radiusX = m_radiusX->cssText();
- }
- return buildEllipseString(radiusX, radiusY,
- serializePositionOffset(*normalizedCX, *normalizedCY),
- serializePositionOffset(*normalizedCY, *normalizedCX));
- }
- bool CSSBasicShapeEllipse::equals(const CSSBasicShape& shape) const
- {
- if (shape.type() != CSSBasicShapeEllipseType)
- return false;
- const CSSBasicShapeEllipse& other = toCSSBasicShapeEllipse(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);
- }
- DEFINE_TRACE(CSSBasicShapeEllipse)
- {
- 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)
- {
- ASSERT(!(points.size() % 2));
- StringBuilder result;
- const char evenOddOpening[] = "polygon(evenodd, ";
- const char nonZeroOpening[] = "polygon(";
- const char commaSeparator[] = ", ";
- static_assert(sizeof(evenOddOpening) > sizeof(nonZeroOpening), "polygon string openings should be the same length");
- // Compute the required capacity in advance to reduce allocations.
- size_t length = sizeof(evenOddOpening) - 1;
- for (size_t i = 0; i < points.size(); i += 2) {
- if (i)
- length += (sizeof(commaSeparator) - 1);
- // add length of two strings, plus one for the space separator.
- length += points[i].length() + 1 + points[i + 1].length();
- }
- 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(')');
- 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);
- }
- bool CSSBasicShapePolygon::equals(const CSSBasicShape& shape) const
- {
- if (shape.type() != CSSBasicShapePolygonType)
- return false;
- const CSSBasicShapePolygon& rhs = toCSSBasicShapePolygon(shape);
- return compareCSSValueVector(m_values, rhs.m_values);
- }
- DEFINE_TRACE(CSSBasicShapePolygon)
- {
- visitor->trace(m_values);
- CSSBasicShape::trace(visitor);
- }
- static bool buildInsetRadii(Vector<String> &radii, const String& topLeftRadius, const String& topRightRadius, const String& bottomRightRadius, const String& bottomLeftRadius)
- {
- bool showBottomLeft = topRightRadius != bottomLeftRadius;
- bool showBottomRight = showBottomLeft || (bottomRightRadius != topLeftRadius);
- bool showTopRight = showBottomRight || (topRightRadius != topLeftRadius);
- radii.append(topLeftRadius);
- if (showTopRight)
- radii.append(topRightRadius);
- if (showBottomRight)
- radii.append(bottomRightRadius);
- if (showBottomLeft)
- radii.append(bottomLeftRadius);
- return radii.size() == 1 && radii[0] == "0px";
- }
- 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);
- bool showLeftArg = !left.isNull() && left != right;
- bool showBottomArg = !bottom.isNull() && (bottom != top || showLeftArg);
- bool showRightArg = !right.isNull() && (right != top || showBottomArg);
- if (showRightArg) {
- result.appendLiteral(separator);
- result.append(right);
- }
- if (showBottomArg) {
- result.appendLiteral(separator);
- result.append(bottom);
- }
- if (showLeftArg) {
- result.appendLiteral(separator);
- result.append(left);
- }
- if (!topLeftRadiusWidth.isNull() && !topLeftRadiusHeight.isNull()) {
- Vector<String> horizontalRadii;
- bool areDefaultCornerRadii = buildInsetRadii(horizontalRadii, topLeftRadiusWidth, topRightRadiusWidth, bottomRightRadiusWidth, bottomLeftRadiusWidth);
- Vector<String> verticalRadii;
- areDefaultCornerRadii &= buildInsetRadii(verticalRadii, topLeftRadiusHeight, topRightRadiusHeight, bottomRightRadiusHeight, bottomLeftRadiusHeight);
- if (!areDefaultCornerRadii) {
- result.appendLiteral(separator);
- result.appendLiteral(cornersSeparator);
- for (size_t i = 0; i < horizontalRadii.size(); ++i) {
- result.appendLiteral(separator);
- result.append(horizontalRadii[i]);
- }
- if (horizontalRadii != verticalRadii) {
- result.appendLiteral(separator);
- result.appendLiteral("/");
- for (size_t i = 0; i < verticalRadii.size(); ++i) {
- result.appendLiteral(separator);
- result.append(verticalRadii[i]);
- }
- }
- }
- }
- result.append(')');
- return result.toString();
- }
- static inline void updateCornerRadiusWidthAndHeight(const CSSValuePair* cornerRadius, String& width, String& height)
- {
- if (!cornerRadius)
- return;
- width = cornerRadius->first().cssText();
- height = cornerRadius->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 = toCSSBasicShapeInset(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);
- }
- DEFINE_TRACE(CSSBasicShapeInset)
- {
- 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);
- }
- } // namespace blink