summaryrefslogtreecommitdiff
path: root/Source/WebCore/rendering/style/BasicShapes.cpp
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/rendering/style/BasicShapes.cpp
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/WebCore/rendering/style/BasicShapes.cpp')
-rw-r--r--Source/WebCore/rendering/style/BasicShapes.cpp509
1 files changed, 273 insertions, 236 deletions
diff --git a/Source/WebCore/rendering/style/BasicShapes.cpp b/Source/WebCore/rendering/style/BasicShapes.cpp
index 916402a7d..06b3e090e 100644
--- a/Source/WebCore/rendering/style/BasicShapes.cpp
+++ b/Source/WebCore/rendering/style/BasicShapes.cpp
@@ -34,9 +34,15 @@
#include "BasicShapeFunctions.h"
#include "CalculationValue.h"
#include "FloatRect.h"
+#include "FloatRoundedRect.h"
#include "LengthFunctions.h"
#include "Path.h"
#include "RenderBox.h"
+#include "SVGPathByteStream.h"
+#include "SVGPathUtilities.h"
+
+#include <wtf/NeverDestroyed.h>
+#include <wtf/TinyLRUCache.h>
namespace WebCore {
@@ -51,103 +57,105 @@ void BasicShapeCenterCoordinate::updateComputedLength()
return;
}
- OwnPtr<CalcExpressionLength> lhs = adoptPtr(new CalcExpressionLength(Length(100, Percent)));
- OwnPtr<CalcExpressionLength> rhs = adoptPtr(new CalcExpressionLength(m_length));
- OwnPtr<CalcExpressionBinaryOperation> op = adoptPtr(new CalcExpressionBinaryOperation(lhs.release(), rhs.release(), CalcSubtract));
- m_computedLength = Length(CalculationValue::create(op.release(), CalculationRangeAll));
+ auto lhs = std::make_unique<CalcExpressionLength>(Length(100, Percent));
+ auto rhs = std::make_unique<CalcExpressionLength>(m_length);
+ auto op = std::make_unique<CalcExpressionBinaryOperation>(WTFMove(lhs), WTFMove(rhs), CalcSubtract);
+ m_computedLength = Length(CalculationValue::create(WTFMove(op), ValueRangeAll));
}
-bool BasicShape::canBlend(const BasicShape* other) const
-{
- // FIXME: Support animations between different shapes in the future.
- if (type() != other->type())
- return false;
-
- // Both shapes must use the same reference box.
- if (layoutBox() != other->layoutBox())
- return false;
+struct SVGPathTranslatedByteStream {
+ SVGPathTranslatedByteStream(const FloatPoint& offset, const SVGPathByteStream& rawStream)
+ : m_offset(offset)
+ , m_rawStream(rawStream)
+ { }
+
+ bool operator==(const SVGPathTranslatedByteStream& other) const { return other.m_offset == m_offset && other.m_rawStream == m_rawStream; }
+ bool operator!=(const SVGPathTranslatedByteStream& other) const { return !(*this == other); }
+ bool isEmpty() const { return m_rawStream.isEmpty(); }
+
+ Path path() const
+ {
+ Path path;
+ buildPathFromByteStream(m_rawStream, path);
+ path.translate(toFloatSize(m_offset));
+ return path;
+ }
+
+ FloatPoint m_offset;
+ SVGPathByteStream m_rawStream;
+};
+
+struct EllipsePathPolicy : public TinyLRUCachePolicy<FloatRect, Path> {
+public:
+ static bool isKeyNull(const FloatRect& rect) { return rect.isEmpty(); }
+
+ static Path createValueForKey(const FloatRect& rect)
+ {
+ Path path;
+ path.addEllipse(rect);
+ return path;
+ }
+};
- // Just polygons with same number of vertices can be animated.
- if (type() == BasicShape::BasicShapePolygonType
- && (static_cast<const BasicShapePolygon*>(this)->values().size() != static_cast<const BasicShapePolygon*>(other)->values().size()
- || static_cast<const BasicShapePolygon*>(this)->windRule() != static_cast<const BasicShapePolygon*>(other)->windRule()))
- return false;
+struct RoundedRectPathPolicy : public TinyLRUCachePolicy<FloatRoundedRect, Path> {
+public:
+ static bool isKeyNull(const FloatRoundedRect& rect) { return rect.isEmpty(); }
- // Circles with keywords for radii coordinates cannot be animated.
- if (type() == BasicShape::BasicShapeCircleType) {
- const BasicShapeCircle* thisCircle = static_cast<const BasicShapeCircle*>(this);
- const BasicShapeCircle* otherCircle = static_cast<const BasicShapeCircle*>(other);
- if (!thisCircle->radius().canBlend(otherCircle->radius()))
- return false;
+ static Path createValueForKey(const FloatRoundedRect& rect)
+ {
+ Path path;
+ path.addRoundedRect(rect);
+ return path;
}
+};
- // Ellipses with keywords for radii coordinates cannot be animated.
- if (type() != BasicShape::BasicShapeEllipseType)
- return true;
+struct PolygonPathPolicy : public TinyLRUCachePolicy<Vector<FloatPoint>, Path> {
+public:
+ static bool isKeyNull(const Vector<FloatPoint>& points) { return !points.size(); }
- const BasicShapeEllipse* thisEllipse = static_cast<const BasicShapeEllipse*>(this);
- const BasicShapeEllipse* otherEllipse = static_cast<const BasicShapeEllipse*>(other);
- return (thisEllipse->radiusX().canBlend(otherEllipse->radiusX())
- && thisEllipse->radiusY().canBlend(otherEllipse->radiusY()));
+ static Path createValueForKey(const Vector<FloatPoint>& points) { return Path::polygonPathFromPoints(points); }
+};
+
+struct TranslatedByteStreamPathPolicy : public TinyLRUCachePolicy<SVGPathTranslatedByteStream, Path> {
+public:
+ static bool isKeyNull(const SVGPathTranslatedByteStream& stream) { return stream.isEmpty(); }
+
+ static Path createValueForKey(const SVGPathTranslatedByteStream& stream) { return stream.path(); }
+};
+
+static const Path& cachedEllipsePath(const FloatRect& rect)
+{
+ static NeverDestroyed<TinyLRUCache<FloatRect, Path, 4, EllipsePathPolicy>> cache;
+ return cache.get().get(rect);
}
-void BasicShapeRectangle::path(Path& path, const FloatRect& boundingBox)
+static const Path& cachedRoundedRectPath(const FloatRoundedRect& rect)
{
- ASSERT(path.isEmpty());
- path.addRoundedRect(
- FloatRect(
- floatValueForLength(m_x, boundingBox.width()) + boundingBox.x(),
- floatValueForLength(m_y, boundingBox.height()) + boundingBox.y(),
- floatValueForLength(m_width, boundingBox.width()),
- floatValueForLength(m_height, boundingBox.height())
- ),
- FloatSize(
- floatValueForLength(m_cornerRadiusX, boundingBox.width()),
- floatValueForLength(m_cornerRadiusY, boundingBox.height())
- )
- );
+ static NeverDestroyed<TinyLRUCache<FloatRoundedRect, Path, 4, RoundedRectPathPolicy>> cache;
+ return cache.get().get(rect);
}
-PassRefPtr<BasicShape> BasicShapeRectangle::blend(const BasicShape* other, double progress) const
+static const Path& cachedPolygonPath(const Vector<FloatPoint>& points)
{
- ASSERT(type() == other->type());
-
- const BasicShapeRectangle* o = static_cast<const BasicShapeRectangle*>(other);
- RefPtr<BasicShapeRectangle> result = BasicShapeRectangle::create();
- result->setX(m_x.blend(o->x(), progress));
- result->setY(m_y.blend(o->y(), progress));
- result->setWidth(m_width.blend(o->width(), progress));
- result->setHeight(m_height.blend(o->height(), progress));
- result->setCornerRadiusX(m_cornerRadiusX.blend(o->cornerRadiusX(), progress));
- result->setCornerRadiusY(m_cornerRadiusY.blend(o->cornerRadiusY(), progress));
- return result.release();
+ static NeverDestroyed<TinyLRUCache<Vector<FloatPoint>, Path, 4, PolygonPathPolicy>> cache;
+ return cache.get().get(points);
}
-void DeprecatedBasicShapeCircle::path(Path& path, const FloatRect& boundingBox)
+static const Path& cachedTranslatedByteStreamPath(const SVGPathByteStream& stream, const FloatPoint& offset)
{
- ASSERT(path.isEmpty());
- float diagonal = sqrtf((boundingBox.width() * boundingBox.width() + boundingBox.height() * boundingBox.height()) / 2);
- float centerX = floatValueForLength(m_centerX, boundingBox.width());
- float centerY = floatValueForLength(m_centerY, boundingBox.height());
- float radius = floatValueForLength(m_radius, diagonal);
- path.addEllipse(FloatRect(
- centerX - radius + boundingBox.x(),
- centerY - radius + boundingBox.y(),
- radius * 2,
- radius * 2
- ));
+ static NeverDestroyed<TinyLRUCache<SVGPathTranslatedByteStream, Path, 4, TranslatedByteStreamPathPolicy>> cache;
+ return cache.get().get(SVGPathTranslatedByteStream(offset, stream));
}
-PassRefPtr<BasicShape> DeprecatedBasicShapeCircle::blend(const BasicShape* other, double progress) const
+bool BasicShapeCircle::operator==(const BasicShape& other) const
{
- ASSERT(type() == other->type());
-
- const DeprecatedBasicShapeCircle* o = static_cast<const DeprecatedBasicShapeCircle*>(other);
- RefPtr<DeprecatedBasicShapeCircle> result = DeprecatedBasicShapeCircle::create();
- result->setCenterX(m_centerX.blend(o->centerX(), progress));
- result->setCenterY(m_centerY.blend(o->centerY(), progress));
- result->setRadius(m_radius.blend(o->radius(), progress));
- return result.release();
+ if (type() != other.type())
+ return false;
+
+ auto& otherCircle = downcast<BasicShapeCircle>(other);
+ return m_centerX == otherCircle.m_centerX
+ && m_centerY == otherCircle.m_centerY
+ && m_radius == otherCircle.m_radius;
}
float BasicShapeCircle::floatValueForRadiusInBox(float boxWidth, float boxHeight) const
@@ -158,239 +166,268 @@ float BasicShapeCircle::floatValueForRadiusInBox(float boxWidth, float boxHeight
float centerX = floatValueForCenterCoordinate(m_centerX, boxWidth);
float centerY = floatValueForCenterCoordinate(m_centerY, boxHeight);
+ float widthDelta = std::abs(boxWidth - centerX);
+ float heightDelta = std::abs(boxHeight - centerY);
if (m_radius.type() == BasicShapeRadius::ClosestSide)
- return std::min(std::min(centerX, boxWidth - centerX), std::min(centerY, boxHeight - centerY));
+ return std::min(std::min(std::abs(centerX), widthDelta), std::min(std::abs(centerY), heightDelta));
// If radius.type() == BasicShapeRadius::FarthestSide.
- return std::max(std::max(centerX, boxWidth - centerX), std::max(centerY, boxHeight - centerY));
+ return std::max(std::max(std::abs(centerX), widthDelta), std::max(std::abs(centerY), heightDelta));
}
-void BasicShapeCircle::path(Path& path, const FloatRect& boundingBox)
+const Path& BasicShapeCircle::path(const FloatRect& boundingBox)
{
- ASSERT(path.isEmpty());
-
float centerX = floatValueForCenterCoordinate(m_centerX, boundingBox.width());
float centerY = floatValueForCenterCoordinate(m_centerY, boundingBox.height());
float radius = floatValueForRadiusInBox(boundingBox.width(), boundingBox.height());
- path.addEllipse(FloatRect(
- centerX - radius + boundingBox.x(),
- centerY - radius + boundingBox.y(),
- radius * 2,
- radius * 2
- ));
+
+ return cachedEllipsePath(FloatRect(centerX - radius + boundingBox.x(), centerY - radius + boundingBox.y(), radius * 2, radius * 2));
}
-PassRefPtr<BasicShape> BasicShapeCircle::blend(const BasicShape* other, double progress) const
+bool BasicShapeCircle::canBlend(const BasicShape& other) const
{
- ASSERT(type() == other->type());
- const BasicShapeCircle* o = static_cast<const BasicShapeCircle*>(other);
- RefPtr<BasicShapeCircle> result = BasicShapeCircle::create();
-
- result->setCenterX(m_centerX.blend(o->centerX(), progress));
- result->setCenterY(m_centerY.blend(o->centerY(), progress));
- result->setRadius(m_radius.blend(o->radius(), progress));
- return result.release();
+ if (type() != other.type())
+ return false;
+
+ return radius().canBlend(downcast<BasicShapeCircle>(other).radius());
}
-void DeprecatedBasicShapeEllipse::path(Path& path, const FloatRect& boundingBox)
+Ref<BasicShape> BasicShapeCircle::blend(const BasicShape& other, double progress) const
{
- ASSERT(path.isEmpty());
- float centerX = floatValueForLength(m_centerX, boundingBox.width());
- float centerY = floatValueForLength(m_centerY, boundingBox.height());
- float radiusX = floatValueForLength(m_radiusX, boundingBox.width());
- float radiusY = floatValueForLength(m_radiusY, boundingBox.height());
- path.addEllipse(FloatRect(
- centerX - radiusX + boundingBox.x(),
- centerY - radiusY + boundingBox.y(),
- radiusX * 2,
- radiusY * 2
- ));
+ ASSERT(type() == other.type());
+ auto& otherCircle = downcast<BasicShapeCircle>(other);
+ auto result = BasicShapeCircle::create();
+
+ result->setCenterX(m_centerX.blend(otherCircle.centerX(), progress));
+ result->setCenterY(m_centerY.blend(otherCircle.centerY(), progress));
+ result->setRadius(m_radius.blend(otherCircle.radius(), progress));
+ return WTFMove(result);
}
-PassRefPtr<BasicShape> DeprecatedBasicShapeEllipse::blend(const BasicShape* other, double progress) const
+bool BasicShapeEllipse::operator==(const BasicShape& other) const
{
- ASSERT(type() == other->type());
-
- const DeprecatedBasicShapeEllipse* o = static_cast<const DeprecatedBasicShapeEllipse*>(other);
- RefPtr<DeprecatedBasicShapeEllipse> result = DeprecatedBasicShapeEllipse::create();
- result->setCenterX(m_centerX.blend(o->centerX(), progress));
- result->setCenterY(m_centerY.blend(o->centerY(), progress));
- result->setRadiusX(m_radiusX.blend(o->radiusX(), progress));
- result->setRadiusY(m_radiusY.blend(o->radiusY(), progress));
- return result.release();
+ if (type() != other.type())
+ return false;
+
+ auto& otherEllipse = downcast<BasicShapeEllipse>(other);
+ return m_centerX == otherEllipse.m_centerX
+ && m_centerY == otherEllipse.m_centerY
+ && m_radiusX == otherEllipse.m_radiusX
+ && m_radiusY == otherEllipse.m_radiusY;
}
float BasicShapeEllipse::floatValueForRadiusInBox(const BasicShapeRadius& radius, float center, float boxWidthOrHeight) const
{
if (radius.type() == BasicShapeRadius::Value)
- return floatValueForLength(radius.value(), boxWidthOrHeight);
+ return floatValueForLength(radius.value(), std::abs(boxWidthOrHeight));
+ float widthOrHeightDelta = std::abs(boxWidthOrHeight - center);
if (radius.type() == BasicShapeRadius::ClosestSide)
- return std::min(center, boxWidthOrHeight - center);
+ return std::min(std::abs(center), widthOrHeightDelta);
ASSERT(radius.type() == BasicShapeRadius::FarthestSide);
- return std::max(center, boxWidthOrHeight - center);
+ return std::max(std::abs(center), widthOrHeightDelta);
}
-void BasicShapeEllipse::path(Path& path, const FloatRect& boundingBox)
+const Path& BasicShapeEllipse::path(const FloatRect& boundingBox)
{
- ASSERT(path.isEmpty());
-
float centerX = floatValueForCenterCoordinate(m_centerX, boundingBox.width());
float centerY = floatValueForCenterCoordinate(m_centerY, boundingBox.height());
float radiusX = floatValueForRadiusInBox(m_radiusX, centerX, boundingBox.width());
float radiusY = floatValueForRadiusInBox(m_radiusY, centerY, boundingBox.height());
- path.addEllipse(FloatRect(
- centerX - radiusX + boundingBox.x(),
- centerY - radiusY + boundingBox.y(),
- radiusX * 2,
- radiusY * 2));
+
+ return cachedEllipsePath(FloatRect(centerX - radiusX + boundingBox.x(), centerY - radiusY + boundingBox.y(), radiusX * 2, radiusY * 2));
+}
+
+bool BasicShapeEllipse::canBlend(const BasicShape& other) const
+{
+ if (type() != other.type())
+ return false;
+
+ auto& otherEllipse = downcast<BasicShapeEllipse>(other);
+ return radiusX().canBlend(otherEllipse.radiusX()) && radiusY().canBlend(otherEllipse.radiusY());
}
-PassRefPtr<BasicShape> BasicShapeEllipse::blend(const BasicShape* other, double progress) const
+Ref<BasicShape> BasicShapeEllipse::blend(const BasicShape& other, double progress) const
{
- ASSERT(type() == other->type());
- const BasicShapeEllipse* o = static_cast<const BasicShapeEllipse*>(other);
- RefPtr<BasicShapeEllipse> result = BasicShapeEllipse::create();
-
- if (m_radiusX.type() != BasicShapeRadius::Value || o->radiusX().type() != BasicShapeRadius::Value
- || m_radiusY.type() != BasicShapeRadius::Value || o->radiusY().type() != BasicShapeRadius::Value) {
- result->setCenterX(o->centerX());
- result->setCenterY(o->centerY());
- result->setRadiusX(o->radiusX());
- result->setRadiusY(o->radiusY());
- return result;
+ ASSERT(type() == other.type());
+ auto& otherEllipse = downcast<BasicShapeEllipse>(other);
+ auto result = BasicShapeEllipse::create();
+
+ if (m_radiusX.type() != BasicShapeRadius::Value || otherEllipse.radiusX().type() != BasicShapeRadius::Value
+ || m_radiusY.type() != BasicShapeRadius::Value || otherEllipse.radiusY().type() != BasicShapeRadius::Value) {
+ result->setCenterX(otherEllipse.centerX());
+ result->setCenterY(otherEllipse.centerY());
+ result->setRadiusX(otherEllipse.radiusX());
+ result->setRadiusY(otherEllipse.radiusY());
+ return WTFMove(result);
}
- result->setCenterX(m_centerX.blend(o->centerX(), progress));
- result->setCenterY(m_centerY.blend(o->centerY(), progress));
- result->setRadiusX(m_radiusX.blend(o->radiusX(), progress));
- result->setRadiusY(m_radiusY.blend(o->radiusY(), progress));
- return result.release();
+ result->setCenterX(m_centerX.blend(otherEllipse.centerX(), progress));
+ result->setCenterY(m_centerY.blend(otherEllipse.centerY(), progress));
+ result->setRadiusX(m_radiusX.blend(otherEllipse.radiusX(), progress));
+ result->setRadiusY(m_radiusY.blend(otherEllipse.radiusY(), progress));
+ return WTFMove(result);
}
-void BasicShapePolygon::path(Path& path, const FloatRect& boundingBox)
+bool BasicShapePolygon::operator==(const BasicShape& other) const
+{
+ if (type() != other.type())
+ return false;
+
+ auto& otherPolygon = downcast<BasicShapePolygon>(other);
+ return m_windRule == otherPolygon.m_windRule
+ && m_values == otherPolygon.m_values;
+}
+
+const Path& BasicShapePolygon::path(const FloatRect& boundingBox)
{
- ASSERT(path.isEmpty());
ASSERT(!(m_values.size() % 2));
size_t length = m_values.size();
-
- if (!length)
- return;
- path.moveTo(FloatPoint(floatValueForLength(m_values.at(0), boundingBox.width()) + boundingBox.x(),
- floatValueForLength(m_values.at(1), boundingBox.height()) + boundingBox.y()));
- for (size_t i = 2; i < length; i = i + 2) {
- path.addLineTo(FloatPoint(floatValueForLength(m_values.at(i), boundingBox.width()) + boundingBox.x(),
- floatValueForLength(m_values.at(i + 1), boundingBox.height()) + boundingBox.y()));
+ Vector<FloatPoint> points(length / 2);
+ for (size_t i = 0; i < points.size(); ++i) {
+ points[i].setX(floatValueForLength(m_values.at(i * 2), boundingBox.width()) + boundingBox.x());
+ points[i].setY(floatValueForLength(m_values.at(i * 2 + 1), boundingBox.height()) + boundingBox.y());
}
- path.closeSubpath();
+
+ return cachedPolygonPath(points);
}
-PassRefPtr<BasicShape> BasicShapePolygon::blend(const BasicShape* other, double progress) const
+bool BasicShapePolygon::canBlend(const BasicShape& other) const
{
- ASSERT(type() == other->type());
+ if (type() != other.type())
+ return false;
- const BasicShapePolygon* o = static_cast<const BasicShapePolygon*>(other);
- ASSERT(m_values.size() == o->values().size());
+ auto& otherPolygon = downcast<BasicShapePolygon>(other);
+ return values().size() == otherPolygon.values().size() && windRule() == otherPolygon.windRule();
+}
+
+Ref<BasicShape> BasicShapePolygon::blend(const BasicShape& other, double progress) const
+{
+ ASSERT(type() == other.type());
+
+ auto& otherPolygon = downcast<BasicShapePolygon>(other);
+ ASSERT(m_values.size() == otherPolygon.values().size());
ASSERT(!(m_values.size() % 2));
size_t length = m_values.size();
- RefPtr<BasicShapePolygon> result = BasicShapePolygon::create();
+ auto result = BasicShapePolygon::create();
if (!length)
- return result.release();
+ return WTFMove(result);
- result->setWindRule(o->windRule());
+ result->setWindRule(otherPolygon.windRule());
for (size_t i = 0; i < length; i = i + 2) {
- result->appendPoint(m_values.at(i).blend(o->values().at(i), progress),
- m_values.at(i + 1).blend(o->values().at(i + 1), progress));
+ result->appendPoint(
+ WebCore::blend(otherPolygon.values().at(i), m_values.at(i), progress),
+ WebCore::blend(otherPolygon.values().at(i + 1), m_values.at(i + 1), progress));
}
- return result.release();
+ return WTFMove(result);
}
-void BasicShapeInsetRectangle::path(Path& path, const FloatRect& boundingBox)
+BasicShapePath::BasicShapePath(std::unique_ptr<SVGPathByteStream>&& byteStream)
+ : m_byteStream(WTFMove(byteStream))
{
- ASSERT(path.isEmpty());
- float left = floatValueForLength(m_left, boundingBox.width());
- float top = floatValueForLength(m_top, boundingBox.height());
- path.addRoundedRect(
- FloatRect(
- left + boundingBox.x(),
- top + boundingBox.y(),
- std::max<float>(boundingBox.width() - left - floatValueForLength(m_right, boundingBox.width()), 0),
- std::max<float>(boundingBox.height() - top - floatValueForLength(m_bottom, boundingBox.height()), 0)
- ),
- FloatSize(
- floatValueForLength(m_cornerRadiusX, boundingBox.width()),
- floatValueForLength(m_cornerRadiusY, boundingBox.height())
- )
- );
}
-PassRefPtr<BasicShape> BasicShapeInsetRectangle::blend(const BasicShape* other, double progress) const
+const Path& BasicShapePath::path(const FloatRect& boundingBox)
+{
+ return cachedTranslatedByteStreamPath(*m_byteStream, boundingBox.location());
+}
+
+bool BasicShapePath::operator==(const BasicShape& other) const
{
- ASSERT(type() == other->type());
-
- const BasicShapeInsetRectangle* o = static_cast<const BasicShapeInsetRectangle*>(other);
- RefPtr<BasicShapeInsetRectangle> result = BasicShapeInsetRectangle::create();
- result->setTop(m_top.blend(o->top(), progress));
- result->setRight(m_right.blend(o->right(), progress));
- result->setBottom(m_bottom.blend(o->bottom(), progress));
- result->setLeft(m_left.blend(o->left(), progress));
- result->setCornerRadiusX(m_cornerRadiusX.blend(o->cornerRadiusX(), progress));
- result->setCornerRadiusY(m_cornerRadiusY.blend(o->cornerRadiusY(), progress));
- return result.release();
+ if (type() != other.type())
+ return false;
+
+ auto& otherPath = downcast<BasicShapePath>(other);
+ return m_windRule == otherPath.m_windRule && *m_byteStream == *otherPath.m_byteStream;
+}
+
+bool BasicShapePath::canBlend(const BasicShape& other) const
+{
+ if (type() != other.type())
+ return false;
+
+ auto& otherPath = downcast<BasicShapePath>(other);
+ return windRule() == otherPath.windRule() && canBlendSVGPathByteStreams(*m_byteStream, *otherPath.pathData());
}
-void BasicShapeInset::path(Path& path, const FloatRect& boundingBox)
+Ref<BasicShape> BasicShapePath::blend(const BasicShape& from, double progress) const
+{
+ ASSERT(type() == from.type());
+
+ auto& fromPath = downcast<BasicShapePath>(from);
+
+ auto resultingPathBytes = std::make_unique<SVGPathByteStream>();
+ buildAnimatedSVGPathByteStream(*fromPath.m_byteStream, *m_byteStream, *resultingPathBytes, progress);
+
+ auto result = BasicShapePath::create(WTFMove(resultingPathBytes));
+ result->setWindRule(windRule());
+ return WTFMove(result);
+}
+
+bool BasicShapeInset::operator==(const BasicShape& other) const
+{
+ if (type() != other.type())
+ return false;
+
+ auto& otherInset = downcast<BasicShapeInset>(other);
+ return m_right == otherInset.m_right
+ && m_top == otherInset.m_top
+ && m_bottom == otherInset.m_bottom
+ && m_left == otherInset.m_left
+ && m_topLeftRadius == otherInset.m_topLeftRadius
+ && m_topRightRadius == otherInset.m_topRightRadius
+ && m_bottomRightRadius == otherInset.m_bottomRightRadius
+ && m_bottomLeftRadius == otherInset.m_bottomLeftRadius;
+}
+
+static FloatSize floatSizeForLengthSize(const LengthSize& lengthSize, const FloatRect& boundingBox)
+{
+ return { floatValueForLength(lengthSize.width, boundingBox.width()),
+ floatValueForLength(lengthSize.height, boundingBox.height()) };
+}
+
+const Path& BasicShapeInset::path(const FloatRect& boundingBox)
{
- ASSERT(path.isEmpty());
float left = floatValueForLength(m_left, boundingBox.width());
float top = floatValueForLength(m_top, boundingBox.height());
- path.addRoundedRect(
- FloatRect(
- left + boundingBox.x(),
- top + boundingBox.y(),
- std::max<float>(boundingBox.width() - left - floatValueForLength(m_right, boundingBox.width()), 0),
- std::max<float>(boundingBox.height() - top - floatValueForLength(m_bottom, boundingBox.height()), 0)
- ),
- FloatSize(
- floatValueForLength(m_topLeftRadius.width(), boundingBox.width()),
- floatValueForLength(m_topLeftRadius.height(), boundingBox.height())
- ),
- FloatSize(
- floatValueForLength(m_topRightRadius.width(), boundingBox.width()),
- floatValueForLength(m_topRightRadius.height(), boundingBox.height())
- ),
- FloatSize(
- floatValueForLength(m_bottomRightRadius.width(), boundingBox.width()),
- floatValueForLength(m_bottomRightRadius.height(), boundingBox.height())
- ),
- FloatSize(
- floatValueForLength(m_bottomLeftRadius.width(), boundingBox.width()),
- floatValueForLength(m_bottomLeftRadius.height(), boundingBox.height())
- )
- );
+ auto rect = FloatRect(left + boundingBox.x(), top + boundingBox.y(),
+ std::max<float>(boundingBox.width() - left - floatValueForLength(m_right, boundingBox.width()), 0),
+ std::max<float>(boundingBox.height() - top - floatValueForLength(m_bottom, boundingBox.height()), 0));
+ auto radii = FloatRoundedRect::Radii(floatSizeForLengthSize(m_topLeftRadius, boundingBox),
+ floatSizeForLengthSize(m_topRightRadius, boundingBox),
+ floatSizeForLengthSize(m_bottomLeftRadius, boundingBox),
+ floatSizeForLengthSize(m_bottomRightRadius, boundingBox));
+ radii.scale(calcBorderRadiiConstraintScaleFor(rect, radii));
+
+ return cachedRoundedRectPath(FloatRoundedRect(rect, radii));
+}
+
+bool BasicShapeInset::canBlend(const BasicShape& other) const
+{
+ return type() == other.type();
}
-PassRefPtr<BasicShape> BasicShapeInset::blend(const BasicShape* other, double progress) const
+Ref<BasicShape> BasicShapeInset::blend(const BasicShape& from, double progress) const
{
- ASSERT(type() == other->type());
+ ASSERT(type() == from.type());
- const BasicShapeInset* o = static_cast<const BasicShapeInset*>(other);
- RefPtr<BasicShapeInset> result = BasicShapeInset::create();
- result->setTop(m_top.blend(o->top(), progress));
- result->setRight(m_right.blend(o->right(), progress));
- result->setBottom(m_bottom.blend(o->bottom(), progress));
- result->setLeft(m_left.blend(o->left(), progress));
+ auto& fromInset = downcast<BasicShapeInset>(from);
+ auto result = BasicShapeInset::create();
+ result->setTop(WebCore::blend(fromInset.top(), top(), progress));
+ result->setRight(WebCore::blend(fromInset.right(), right(), progress));
+ result->setBottom(WebCore::blend(fromInset.bottom(), bottom(), progress));
+ result->setLeft(WebCore::blend(fromInset.left(), left(), progress));
- result->setTopLeftRadius(m_topLeftRadius.blend(o->topLeftRadius(), progress));
- result->setTopRightRadius(m_topRightRadius.blend(o->topRightRadius(), progress));
- result->setBottomRightRadius(m_bottomRightRadius.blend(o->bottomRightRadius(), progress));
- result->setBottomLeftRadius(m_bottomLeftRadius.blend(o->bottomLeftRadius(), progress));
+ result->setTopLeftRadius(WebCore::blend(fromInset.topLeftRadius(), topLeftRadius(), progress));
+ result->setTopRightRadius(WebCore::blend(fromInset.topRightRadius(), topRightRadius(), progress));
+ result->setBottomRightRadius(WebCore::blend(fromInset.bottomRightRadius(), bottomRightRadius(), progress));
+ result->setBottomLeftRadius(WebCore::blend(fromInset.bottomLeftRadius(), bottomLeftRadius(), progress));
- return result.release();
+ return WTFMove(result);
}
}