Use "= default" to denote default constructor or destructor
[WebKit-https.git] / Source / WebCore / rendering / svg / RenderSVGRect.cpp
1 /*
2  * Copyright (C) 2011 University of Szeged
3  * Copyright (C) 2011 Renata Hodovan <reni@webkit.org>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY
16  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL UNIVERSITY OF SZEGED OR
19  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 #include "config.h"
29 #include "RenderSVGRect.h"
30
31 namespace WebCore {
32
33 RenderSVGRect::RenderSVGRect(SVGRectElement& element, RenderStyle&& style)
34     : RenderSVGShape(element, WTFMove(style))
35     , m_usePathFallback(false)
36 {
37 }
38
39 RenderSVGRect::~RenderSVGRect() = default;
40
41 SVGRectElement& RenderSVGRect::rectElement() const
42 {
43     return downcast<SVGRectElement>(RenderSVGShape::graphicsElement());
44 }
45
46 void RenderSVGRect::updateShapeFromElement()
47 {
48     // Before creating a new object we need to clear the cached bounding box
49     // to avoid using garbage.
50     m_fillBoundingBox = FloatRect();
51     m_innerStrokeRect = FloatRect();
52     m_outerStrokeRect = FloatRect();
53     clearPath();
54
55     SVGLengthContext lengthContext(&rectElement());
56     FloatSize boundingBoxSize(lengthContext.valueForLength(style().width(), LengthModeWidth), lengthContext.valueForLength(style().height(), LengthModeHeight));
57
58     // Element is invalid if either dimension is negative.
59     if (boundingBoxSize.width() < 0 || boundingBoxSize.height() < 0)
60         return;
61
62     // Rendering enabled? Spec: "A value of zero disables rendering of the element."
63     if (!boundingBoxSize.isEmpty()) {
64         if (rectElement().rx().value(lengthContext) > 0 || rectElement().ry().value(lengthContext) > 0 || hasNonScalingStroke()) {
65             // Fall back to RenderSVGShape
66             RenderSVGShape::updateShapeFromElement();
67             m_usePathFallback = true;
68             return;
69         }
70         m_usePathFallback = false;
71     }
72
73     m_fillBoundingBox = FloatRect(FloatPoint(lengthContext.valueForLength(style().svgStyle().x(), LengthModeWidth),
74         lengthContext.valueForLength(style().svgStyle().y(), LengthModeHeight)),
75         boundingBoxSize);
76
77     // To decide if the stroke contains a point we create two rects which represent the inner and
78     // the outer stroke borders. A stroke contains the point, if the point is between them.
79     m_innerStrokeRect = m_fillBoundingBox;
80     m_outerStrokeRect = m_fillBoundingBox;
81
82     if (style().svgStyle().hasStroke()) {
83         float strokeWidth = this->strokeWidth();
84         m_innerStrokeRect.inflate(-strokeWidth / 2);
85         m_outerStrokeRect.inflate(strokeWidth / 2);
86     }
87
88     m_strokeBoundingBox = m_outerStrokeRect;
89
90 #if USE(CG)
91     // CoreGraphics can inflate the stroke by 1px when drawing a rectangle with antialiasing disabled at non-integer coordinates, we need to compensate.
92     if (style().svgStyle().shapeRendering() == SR_CRISPEDGES)
93         m_strokeBoundingBox.inflate(1);
94 #endif
95 }
96
97 void RenderSVGRect::fillShape(GraphicsContext& context) const
98 {
99     if (m_usePathFallback) {
100         RenderSVGShape::fillShape(context);
101         return;
102     }
103
104 #if USE(CG)
105     // FIXME: CG implementation of GraphicsContextCG::fillRect has an own
106     // shadow drawing method, which draws an extra shadow.
107     // This is a workaround for switching off the extra shadow.
108     // https://bugs.webkit.org/show_bug.cgi?id=68899
109     if (context.hasShadow()) {
110         GraphicsContextStateSaver stateSaver(context);
111         context.clearShadow();
112         context.fillRect(m_fillBoundingBox);
113         return;
114     }
115 #endif
116
117     context.fillRect(m_fillBoundingBox);
118 }
119
120 void RenderSVGRect::strokeShape(GraphicsContext& context) const
121 {
122     if (!style().hasVisibleStroke())
123         return;
124
125     if (m_usePathFallback) {
126         RenderSVGShape::strokeShape(context);
127         return;
128     }
129
130     context.strokeRect(m_fillBoundingBox, strokeWidth());
131 }
132
133 bool RenderSVGRect::shapeDependentStrokeContains(const FloatPoint& point)
134 {
135     // The optimized contains code below does not support non-smooth strokes so we need
136     // to fall back to RenderSVGShape::shapeDependentStrokeContains in these cases.
137     if (m_usePathFallback || !hasSmoothStroke()) {
138         if (!hasPath())
139             RenderSVGShape::updateShapeFromElement();
140         return RenderSVGShape::shapeDependentStrokeContains(point);
141     }
142
143     return m_outerStrokeRect.contains(point, FloatRect::InsideOrOnStroke) && !m_innerStrokeRect.contains(point, FloatRect::InsideButNotOnStroke);
144 }
145
146 bool RenderSVGRect::shapeDependentFillContains(const FloatPoint& point, const WindRule fillRule) const
147 {
148     if (m_usePathFallback)
149         return RenderSVGShape::shapeDependentFillContains(point, fillRule);
150     return m_fillBoundingBox.contains(point.x(), point.y());
151 }
152
153 bool RenderSVGRect::isRenderingDisabled() const
154 {
155     // A width or height of zero disables rendering for the element, and results in an empty bounding box.
156     return m_fillBoundingBox.isEmpty();
157 }
158
159 }