ffe640db5d761744a4a01b6805b85c78cbb067d7
[WebKit-https.git] / Source / WebCore / rendering / ExclusionShape.cpp
1 /*
2  * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1. Redistributions of source code must retain the above
9  *    copyright notice, this list of conditions and the following
10  *    disclaimer.
11  * 2. Redistributions in binary form must reproduce the above
12  *    copyright notice, this list of conditions and the following
13  *    disclaimer in the documentation and/or other materials
14  *    provided with the distribution.
15  * 
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
20  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
21  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
27  * OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include "config.h"
31 #include "ExclusionShape.h"
32
33 #include "BasicShapeFunctions.h"
34 #include "ExclusionPolygon.h"
35 #include "ExclusionRectangle.h"
36 #include "FloatSize.h"
37 #include "LengthFunctions.h"
38 #include "WindRule.h"
39 #include <wtf/MathExtras.h>
40 #include <wtf/OwnPtr.h>
41 #include <wtf/PassOwnPtr.h>
42
43 namespace WebCore {
44
45 static PassOwnPtr<ExclusionShape> createExclusionRectangle(const FloatRect& bounds, const FloatSize& radii)
46 {
47     ASSERT(bounds.width() >= 0 && bounds.height() >= 0 && radii.width() >= 0 && radii.height() >= 0);
48     return adoptPtr(new ExclusionRectangle(bounds, radii));
49 }
50
51 static PassOwnPtr<ExclusionShape> createExclusionCircle(const FloatPoint& center, float radius)
52 {
53     ASSERT(radius >= 0);
54     return adoptPtr(new ExclusionRectangle(FloatRect(center.x() - radius, center.y() - radius, radius*2, radius*2), FloatSize(radius, radius)));
55 }
56
57 static PassOwnPtr<ExclusionShape> createExclusionEllipse(const FloatPoint& center, const FloatSize& radii)
58 {
59     ASSERT(radii.width() >= 0 && radii.height() >= 0);
60     return adoptPtr(new ExclusionRectangle(FloatRect(center.x() - radii.width(), center.y() - radii.height(), radii.width()*2, radii.height()*2), radii));
61 }
62
63 static PassOwnPtr<ExclusionShape> createExclusionPolygon(PassOwnPtr<Vector<FloatPoint> > vertices, WindRule fillRule)
64 {
65     return adoptPtr(new ExclusionPolygon(vertices, fillRule));
66 }
67
68 static inline FloatRect physicalRectToLogical(const FloatRect& rect, float logicalBoxHeight, WritingMode writingMode)
69 {
70     if (isHorizontalWritingMode(writingMode))
71         return rect;
72     if (isFlippedBlocksWritingMode(writingMode))
73         return FloatRect(rect.y(), logicalBoxHeight - rect.maxX(), rect.height(), rect.width());
74     return rect.transposedRect();
75 }
76
77 static inline FloatPoint physicalPointToLogical(const FloatPoint& point, float logicalBoxHeight, WritingMode writingMode)
78 {
79     if (isHorizontalWritingMode(writingMode))
80         return point;
81     if (isFlippedBlocksWritingMode(writingMode))
82         return FloatPoint(point.y(), logicalBoxHeight - point.x());
83     return point.transposedPoint();
84 }
85
86 static inline FloatSize physicalSizeToLogical(const FloatSize& size, WritingMode writingMode)
87 {
88     if (isHorizontalWritingMode(writingMode))
89         return size;
90     return size.transposedSize();
91 }
92
93 PassOwnPtr<ExclusionShape> ExclusionShape::createExclusionShape(const BasicShape* basicShape, const LayoutSize& logicalBoxSize, WritingMode writingMode, Length margin, Length padding)
94 {
95     ASSERT(basicShape);
96
97     bool horizontalWritingMode = isHorizontalWritingMode(writingMode);
98     float boxWidth = horizontalWritingMode ? logicalBoxSize.width() : logicalBoxSize.height();
99     float boxHeight = horizontalWritingMode ? logicalBoxSize.height() : logicalBoxSize.width();
100     OwnPtr<ExclusionShape> exclusionShape;
101
102     switch (basicShape->type()) {
103
104     case BasicShape::BasicShapeRectangleType: {
105         const BasicShapeRectangle* rectangle = static_cast<const BasicShapeRectangle*>(basicShape);
106         FloatRect bounds(
107             floatValueForLength(rectangle->x(), boxWidth),
108             floatValueForLength(rectangle->y(), boxHeight),
109             floatValueForLength(rectangle->width(), boxWidth),
110             floatValueForLength(rectangle->height(), boxHeight));
111         Length radiusXLength = rectangle->cornerRadiusX();
112         Length radiusYLength = rectangle->cornerRadiusY();
113         FloatSize cornerRadii(
114             radiusXLength.isUndefined() ? 0 : floatValueForLength(radiusXLength, boxWidth),
115             radiusYLength.isUndefined() ? 0 : floatValueForLength(radiusYLength, boxHeight));
116         FloatRect logicalBounds = physicalRectToLogical(bounds, logicalBoxSize.height(), writingMode);
117
118         exclusionShape = createExclusionRectangle(logicalBounds, physicalSizeToLogical(cornerRadii, writingMode));
119         break;
120     }
121
122     case BasicShape::BasicShapeCircleType: {
123         const BasicShapeCircle* circle = static_cast<const BasicShapeCircle*>(basicShape);
124         float centerX = floatValueForLength(circle->centerX(), boxWidth);
125         float centerY = floatValueForLength(circle->centerY(), boxHeight);
126         float radius = floatValueForLength(circle->radius(), std::min(boxHeight, boxWidth));
127         FloatPoint logicalCenter = physicalPointToLogical(FloatPoint(centerX, centerY), logicalBoxSize.height(), writingMode);
128
129         exclusionShape = createExclusionCircle(logicalCenter, radius);
130         break;
131     }
132
133     case BasicShape::BasicShapeEllipseType: {
134         const BasicShapeEllipse* ellipse = static_cast<const BasicShapeEllipse*>(basicShape);
135         float centerX = floatValueForLength(ellipse->centerX(), boxWidth);
136         float centerY = floatValueForLength(ellipse->centerY(), boxHeight);
137         float radiusX = floatValueForLength(ellipse->radiusX(), boxWidth);
138         float radiusY = floatValueForLength(ellipse->radiusY(), boxHeight);
139         FloatPoint logicalCenter = physicalPointToLogical(FloatPoint(centerX, centerY), logicalBoxSize.height(), writingMode);
140         FloatSize logicalRadii = physicalSizeToLogical(FloatSize(radiusX, radiusY), writingMode);
141
142         exclusionShape = createExclusionEllipse(logicalCenter, logicalRadii);
143         break;
144     }
145
146     case BasicShape::BasicShapePolygonType: {
147         const BasicShapePolygon* polygon = static_cast<const BasicShapePolygon*>(basicShape);
148         const Vector<Length>& values = polygon->values();
149         size_t valuesSize = values.size();
150         ASSERT(!(valuesSize % 2));
151         OwnPtr<Vector<FloatPoint> > vertices = adoptPtr(new Vector<FloatPoint>(valuesSize / 2));
152         for (unsigned i = 0; i < valuesSize; i += 2) {
153             FloatPoint vertex(
154                 floatValueForLength(values.at(i), boxWidth),
155                 floatValueForLength(values.at(i + 1), boxHeight));
156             (*vertices)[i / 2] = physicalPointToLogical(vertex, logicalBoxSize.height(), writingMode);
157         }
158
159         exclusionShape = createExclusionPolygon(vertices.release(), polygon->windRule());
160         break;
161     }
162
163     case BasicShape::BasicShapeInsetRectangleType: {
164         const BasicShapeInsetRectangle* rectangle = static_cast<const BasicShapeInsetRectangle*>(basicShape);
165         float left = floatValueForLength(rectangle->left(), boxWidth);
166         float top = floatValueForLength(rectangle->top(), boxHeight);
167         FloatRect bounds(
168             left,
169             top,
170             boxWidth - left - floatValueForLength(rectangle->right(), boxWidth),
171             boxHeight - top - floatValueForLength(rectangle->bottom(), boxHeight));
172         Length radiusXLength = rectangle->cornerRadiusX();
173         Length radiusYLength = rectangle->cornerRadiusY();
174         FloatSize cornerRadii(
175             radiusXLength.isUndefined() ? 0 : floatValueForLength(radiusXLength, boxWidth),
176             radiusYLength.isUndefined() ? 0 : floatValueForLength(radiusYLength, boxHeight));
177         FloatRect logicalBounds = physicalRectToLogical(bounds, logicalBoxSize.height(), writingMode);
178
179         exclusionShape = createExclusionRectangle(logicalBounds, physicalSizeToLogical(cornerRadii, writingMode));
180         break;
181     }
182
183     default:
184         ASSERT_NOT_REACHED();
185     }
186
187     exclusionShape->m_writingMode = writingMode;
188     exclusionShape->m_margin = floatValueForLength(margin, 0);
189     exclusionShape->m_padding = floatValueForLength(padding, 0);
190
191     return exclusionShape.release();
192 }
193
194 } // namespace WebCore