diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/rendering/style/BasicShapes.cpp | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/WebCore/rendering/style/BasicShapes.cpp')
-rw-r--r-- | Source/WebCore/rendering/style/BasicShapes.cpp | 509 |
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); } } |