[Title] Use -webkit-clip-path shapes to clip SVG elements
[Issues] N/A
[Problem] N/A
[Solution] Cherry picked.
[Cherry-Picker] Sanghyup Lee <sh53.lee@samsung.com>
Use -webkit-clip-path shapes to clip SVG elements
https://bugs.webkit.org/show_bug.cgi?id=95620
Reviewed by Rob Buis.
Source/WebCore:
This patch adds a path segment for a BasicShape to a given Path object. This
path and it's wind rule are used to clip the context of the SVG element.
Tests: svg/clip-path/clip-path-shape-circle-1-expected.svg
svg/clip-path/clip-path-shape-circle-1.svg
svg/clip-path/clip-path-shape-circle-2-expected.svg
svg/clip-path/clip-path-shape-circle-2.svg
svg/clip-path/clip-path-shape-ellipse-1-expected.svg
svg/clip-path/clip-path-shape-ellipse-1.svg
svg/clip-path/clip-path-shape-ellipse-2-expected.svg
svg/clip-path/clip-path-shape-ellipse-2.svg
svg/clip-path/clip-path-shape-polygon-1-expected.svg
svg/clip-path/clip-path-shape-polygon-1.svg
svg/clip-path/clip-path-shape-polygon-2-expected.svg
svg/clip-path/clip-path-shape-polygon-2.svg
svg/clip-path/clip-path-shape-polygon-3-expected.svg
svg/clip-path/clip-path-shape-polygon-3.svg
svg/clip-path/clip-path-shape-rounded-rect-1-expected.svg
svg/clip-path/clip-path-shape-rounded-rect-1.svg
svg/clip-path/clip-path-shape-rounded-rect-2-expected.svg
svg/clip-path/clip-path-shape-rounded-rect-2.svg
* rendering/style/BasicShapes.cpp: Added helper functions that apply path segments to a given path.
(WebCore::BasicShapeRectangle::path):
(WebCore::BasicShapeCircle::path):
(WebCore::BasicShapeEllipse::path):
(WebCore::BasicShapePolygon::path):
* rendering/style/BasicShapes.h: Make BasicShape virtualized again, since new virtual functions were added.
(WebCore::BasicShape::~BasicShape):
(BasicShape):
(WebCore::BasicShape::windRule): Will return the wind rule of the shape - nonzero by default.
(WebCore::BasicShape::BasicShape):
(BasicShapeRectangle):
(WebCore::BasicShapeRectangle::type): Removed member variable and return type per inheriting class directly.
(WebCore::BasicShapeRectangle::BasicShapeRectangle):
(BasicShapeCircle):
(WebCore::BasicShapeCircle::type): Ditto.
(WebCore::BasicShapeCircle::BasicShapeCircle):
(BasicShapeEllipse):
(WebCore::BasicShapeEllipse::type): Ditto.
(WebCore::BasicShapeEllipse::BasicShapeEllipse):
(BasicShapePolygon):
(WebCore::BasicShapePolygon::windRule):
(WebCore::BasicShapePolygon::type): Ditto.
(WebCore::BasicShapePolygon::BasicShapePolygon):
* rendering/svg/SVGRenderingContext.cpp: If -webkit-clip-path was defined, clip the context to the shape.
Right now -webkit-clip-path overrides clip-path, so that people don't use both at the same time. Current
clip-path property will be replaced, once -webkit-clip-path gets unprefixed.
(WebCore::SVGRenderingContext::prepareToRenderSVGContent):
LayoutTests:
New tests to check behavior of -webkit-clip-path on SVG elements.
* svg/clip-path/clip-path-shape-circle-1-expected.svg: Added.
* svg/clip-path/clip-path-shape-circle-1.svg: Added.
* svg/clip-path/clip-path-shape-circle-2-expected.svg: Added.
* svg/clip-path/clip-path-shape-circle-2.svg: Added.
* svg/clip-path/clip-path-shape-ellipse-1-expected.svg: Added.
* svg/clip-path/clip-path-shape-ellipse-1.svg: Added.
* svg/clip-path/clip-path-shape-ellipse-2-expected.svg: Added.
* svg/clip-path/clip-path-shape-ellipse-2.svg: Added.
* svg/clip-path/clip-path-shape-polygon-1-expected.svg: Added.
* svg/clip-path/clip-path-shape-polygon-1.svg: Added.
* svg/clip-path/clip-path-shape-polygon-2-expected.svg: Added.
* svg/clip-path/clip-path-shape-polygon-2.svg: Added.
* svg/clip-path/clip-path-shape-polygon-3-expected.svg: Added.
* svg/clip-path/clip-path-shape-polygon-3.svg: Added.
* svg/clip-path/clip-path-shape-rounded-rect-1-expected.svg: Added.
* svg/clip-path/clip-path-shape-rounded-rect-1.svg: Added.
* svg/clip-path/clip-path-shape-rounded-rect-2-expected.svg: Added.
* svg/clip-path/clip-path-shape-rounded-rect-2.svg: Added.
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@127383
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
Conflicts:
LayoutTests/ChangeLog
Source/WebCore/ChangeLog
Change-Id: I0aabeb470a8c5915120a48745bc79747531ba8d3
--- /dev/null
+<svg xmlns="http://www.w3.org/2000/svg">
+<defs>
+ <clipPath id="clip">
+ <circle cx="100" cy="100" r="100"/>
+ </clipPath>
+</defs>
+<rect width="200" height="200" fill="green" clip-path="url(#clip)"/>
+</svg>
\ No newline at end of file
--- /dev/null
+<svg xmlns="http://www.w3.org/2000/svg">
+<rect width="200" height="200" fill="green" style="-webkit-clip-path: circle(50%, 50%, 50%)"/>
+</svg>
\ No newline at end of file
--- /dev/null
+<svg xmlns="http://www.w3.org/2000/svg">
+<defs>
+ <clipPath id="clip">
+ <circle cx="100" cy="75" r="75"/>
+ </clipPath>
+</defs>
+<rect width="200" height="150" fill="green" clip-path="url(#clip)"/>
+</svg>
\ No newline at end of file
--- /dev/null
+<svg xmlns="http://www.w3.org/2000/svg">
+<rect width="200" height="150" fill="green" style="-webkit-clip-path: circle(100px, 75px, 75px)"/>
+</svg>
\ No newline at end of file
--- /dev/null
+<svg xmlns="http://www.w3.org/2000/svg">
+<defs>
+ <clipPath id="clip">
+ <ellipse cx="100" cy="75" rx="100" ry="75"/>
+ </clipPath>
+</defs>
+<rect width="200" height="150" fill="green" clip-path="url(#clip)"/>
+</svg>
\ No newline at end of file
--- /dev/null
+<svg xmlns="http://www.w3.org/2000/svg">
+<rect width="200" height="150" fill="green" style="-webkit-clip-path: ellipse(50%, 50%, 50%, 50%)"/>
+</svg>
\ No newline at end of file
--- /dev/null
+<svg xmlns="http://www.w3.org/2000/svg">
+<defs>
+ <clipPath id="clip">
+ <ellipse cx="100" cy="75" rx="100" ry="75"/>
+ </clipPath>
+</defs>
+<rect width="200" height="150" fill="green" clip-path="url(#clip)"/>
+</svg>
\ No newline at end of file
--- /dev/null
+<svg xmlns="http://www.w3.org/2000/svg">
+<rect width="200" height="200" fill="green" style="-webkit-clip-path: ellipse(100px, 75px, 100px, 75px)"/>
+</svg>
\ No newline at end of file
--- /dev/null
+<svg xmlns="http://www.w3.org/2000/svg">
+<defs>
+ <clipPath id="clip" clip-rule="nonzero">
+ <polygon points="0,0 100,200 200,0 0,200 100,0 200,200 0,0"/>
+ </clipPath>
+</defs>
+<rect width="200" height="200" fill="green" clip-path="url(#clip)"/>
+</svg>
\ No newline at end of file
--- /dev/null
+<svg xmlns="http://www.w3.org/2000/svg">
+<rect width="200" height="200" fill="green" style="-webkit-clip-path: polygon(nonzero, 0 0, 100px 200px, 200px 0, 0 200px, 100px 0, 200px 200px, 0 0)"/>
+</svg>
\ No newline at end of file
--- /dev/null
+<svg xmlns="http://www.w3.org/2000/svg">
+<defs>
+ <clipPath id="clip" clip-rule="evenodd">
+ <polygon points="0,0 100,200 200,0 0,200 100,0 200,200 0,0"/>
+ </clipPath>
+</defs>
+<rect width="200" height="200" fill="green" clip-path="url(#clip)"/>
+</svg>
\ No newline at end of file
--- /dev/null
+<svg xmlns="http://www.w3.org/2000/svg">
+<rect width="200" height="200" fill="green" style="-webkit-clip-path: polygon(evenodd, 0 0, 100px 200px, 200px 0, 0 200px, 100px 0, 200px 200px, 0 0)"/>
+</svg>
\ No newline at end of file
--- /dev/null
+<svg xmlns="http://www.w3.org/2000/svg">
+<defs>
+ <clipPath id="clip">
+ <polygon points="0,0 100,200 200,0 0,200 100,0 200,200 0,0"/>
+ </clipPath>
+</defs>
+<rect width="200" height="200" fill="green" clip-path="url(#clip)"/>
+</svg>
\ No newline at end of file
--- /dev/null
+<svg xmlns="http://www.w3.org/2000/svg">
+<rect width="200" height="200" fill="green" style="-webkit-clip-path: polygon(0 0, 100px 200px, 200px 0, 0 200px, 100px 0, 200px 200px, 0 0)"/>
+</svg>
\ No newline at end of file
--- /dev/null
+<svg xmlns="http://www.w3.org/2000/svg">
+<defs>
+ <clipPath id="clip">
+ <rect x="20" y="20" width="160" height="160" rx="20" ry="20"/>
+ </clipPath>
+</defs>
+<rect width="200" height="200" fill="green" clip-path="url(#clip)"/>
+</svg>
\ No newline at end of file
--- /dev/null
+<svg xmlns="http://www.w3.org/2000/svg">
+<rect width="200" height="200" fill="green" style="-webkit-clip-path: rectangle(10%, 10%, 80%, 80%, 10%, 10%)"/>
+</svg>
\ No newline at end of file
--- /dev/null
+<svg xmlns="http://www.w3.org/2000/svg">
+<defs>
+ <clipPath id="clip">
+ <rect x="20" y="20" width="160" height="160" rx="20" ry="20"/>
+ </clipPath>
+</defs>
+<rect width="200" height="200" fill="green" clip-path="url(#clip)"/>
+</svg>
\ No newline at end of file
--- /dev/null
+<svg xmlns="http://www.w3.org/2000/svg">
+<rect width="200" height="200" fill="green" style="-webkit-clip-path: rectangle(20px, 20px, 160px, 160px, 20px, 20px)"/>
+</svg>
\ No newline at end of file
#include "config.h"
#include "BasicShapes.h"
+#include "FloatRect.h"
+#include "LengthFunctions.h"
+#include "Path.h"
namespace WebCore {
-void BasicShape::destroy()
+void BasicShapeRectangle::path(Path& path, const FloatRect& boundingBox)
{
- switch (m_type) {
- case BASIC_SHAPE_RECTANGLE:
- delete static_cast<BasicShapeRectangle*>(this);
- return;
- case BASIC_SHAPE_CIRCLE:
- delete static_cast<BasicShapeCircle*>(this);
- return;
- case BASIC_SHAPE_ELLIPSE:
- delete static_cast<BasicShapeEllipse*>(this);
- return;
- case BASIC_SHAPE_POLYGON:
- delete static_cast<BasicShapePolygon*>(this);
+ 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(m_cornerRadiusX.isUndefined() ? 0 : floatValueForLength(m_cornerRadiusX, boundingBox.width()),
+ m_cornerRadiusY.isUndefined() ? 0 : floatValueForLength(m_cornerRadiusY, boundingBox.height())));
+}
+
+void BasicShapeCircle::path(Path& path, const FloatRect& boundingBox)
+{
+ 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));
+}
+
+void BasicShapeEllipse::path(Path& path, const FloatRect& boundingBox)
+{
+ 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));
+}
+
+void BasicShapePolygon::path(Path& 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()),
+ floatValueForLength(m_values.at(1), boundingBox.width())));
+ for (size_t i = 2; i < length; i = i + 2) {
+ path.addLineTo(FloatPoint(floatValueForLength(m_values.at(i), boundingBox.width()),
+ floatValueForLength(m_values.at(i + 1), boundingBox.width())));
}
- ASSERT_NOT_REACHED();
+ path.closeSubpath();
}
-
}
namespace WebCore {
-class BasicShape : public WTF::RefCountedBase {
+class FloatRect;
+class Path;
+
+class BasicShape : public RefCounted<BasicShape> {
public:
+ virtual ~BasicShape() { }
+
enum Type {
BASIC_SHAPE_RECTANGLE = 1,
BASIC_SHAPE_CIRCLE = 2,
BASIC_SHAPE_ELLIPSE = 3,
BASIC_SHAPE_POLYGON = 4
};
-
- void deref()
- {
- if (derefBase())
- destroy();
- }
- Type type() const { return m_type; }
+ virtual void path(Path&, const FloatRect&) = 0;
+ virtual WindRule windRule() const { return RULE_NONZERO; }
+ virtual Type type() const = 0;
protected:
- BasicShape(Type type)
- : m_type(type)
- { }
-
-private:
- void destroy();
- Type m_type;
+ BasicShape() { }
};
class BasicShapeRectangle : public BasicShape {
void setHeight(Length height) { m_height = height; }
void setCornerRadiusX(Length radiusX) { m_cornerRadiusX = radiusX; }
void setCornerRadiusY(Length radiusY) { m_cornerRadiusY = radiusY; }
-
+
+ virtual void path(Path&, const FloatRect&);
+
+ virtual Type type() const { return BASIC_SHAPE_RECTANGLE; }
private:
BasicShapeRectangle()
- : BasicShape(BASIC_SHAPE_RECTANGLE)
- , m_cornerRadiusX(Undefined)
+ : m_cornerRadiusX(Undefined)
, m_cornerRadiusY(Undefined)
{ }
void setCenterY(Length centerY) { m_centerY = centerY; }
void setRadius(Length radius) { m_radius = radius; }
+ virtual void path(Path&, const FloatRect&);
+
+ virtual Type type() const { return BASIC_SHAPE_CIRCLE; }
private:
- BasicShapeCircle()
- : BasicShape(BASIC_SHAPE_CIRCLE)
- { }
+ BasicShapeCircle() { }
Length m_centerX;
Length m_centerY;
void setRadiusX(Length radiusX) { m_radiusX = radiusX; }
void setRadiusY(Length radiusY) { m_radiusY = radiusY; }
+ virtual void path(Path&, const FloatRect&);
+
+ virtual Type type() const { return BASIC_SHAPE_ELLIPSE; }
private:
- BasicShapeEllipse()
- : BasicShape(BASIC_SHAPE_ELLIPSE)
- { }
+ BasicShapeEllipse() { }
Length m_centerX;
Length m_centerY;
public:
static PassRefPtr<BasicShapePolygon> create() { return adoptRef(new BasicShapePolygon); }
- WindRule windRule() const { return m_windRule; }
const Vector<Length>& values() const { return m_values; }
Length getXAt(unsigned i) const { return m_values.at(2 * i); }
Length getYAt(unsigned i) const { return m_values.at(2 * i + 1); }
void setWindRule(WindRule windRule) { m_windRule = windRule; }
void appendPoint(Length x, Length y) { m_values.append(x); m_values.append(y); }
+ virtual void path(Path&, const FloatRect&);
+ virtual WindRule windRule() const { return m_windRule; }
+
+ virtual Type type() const { return BASIC_SHAPE_POLYGON; }
private:
BasicShapePolygon()
- : BasicShape(BASIC_SHAPE_POLYGON)
- , m_windRule(RULE_NONZERO)
+ : m_windRule(RULE_NONZERO)
{ }
WindRule m_windRule;
#if ENABLE(SVG)
#include "SVGRenderingContext.h"
+#include "BasicShapes.h"
#include "Frame.h"
#include "FrameView.h"
#include "RenderSVGResource.h"
}
}
+ BasicShape* clipShape = style->clipPath();
+ if (clipShape) {
+ // FIXME: Investigate if it is better to store and update a Path object in RenderStyle.
+ // https://bugs.webkit.org/show_bug.cgi?id=95619
+ Path clipPath;
+ clipShape->path(clipPath, object->objectBoundingBox());
+ m_paintInfo->context->clipPath(clipPath, clipShape->windRule());
+ }
+
SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(m_object);
if (!resources) {
#if ENABLE(FILTERS)
}
}
- if (RenderSVGResourceClipper* clipper = resources->clipper()) {
+ RenderSVGResourceClipper* clipper = resources->clipper();
+ if (!clipShape && clipper) {
if (!clipper->applyResource(m_object, style, m_paintInfo->context, ApplyToDefaultMode))
return;
}