Replace WTF::move with WTFMove
[WebKit-https.git] / Source / WebCore / rendering / shapes / Shape.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 "Shape.h"
32
33 #include "BasicShapeFunctions.h"
34 #include "BoxShape.h"
35 #include "GraphicsContext.h"
36 #include "ImageBuffer.h"
37 #include "LengthFunctions.h"
38 #include "PolygonShape.h"
39 #include "RasterShape.h"
40 #include "RectangleShape.h"
41 #include "WindRule.h"
42
43 namespace WebCore {
44
45 static std::unique_ptr<Shape> createInsetShape(const FloatRoundedRect& bounds)
46 {
47     ASSERT(bounds.rect().width() >= 0 && bounds.rect().height() >= 0);
48     return std::make_unique<BoxShape>(bounds);
49 }
50
51 static std::unique_ptr<Shape> createCircleShape(const FloatPoint& center, float radius)
52 {
53     ASSERT(radius >= 0);
54     return std::make_unique<RectangleShape>(FloatRect(center.x() - radius, center.y() - radius, radius*2, radius*2), FloatSize(radius, radius));
55 }
56
57 static std::unique_ptr<Shape> createEllipseShape(const FloatPoint& center, const FloatSize& radii)
58 {
59     ASSERT(radii.width() >= 0 && radii.height() >= 0);
60     return std::make_unique<RectangleShape>(FloatRect(center.x() - radii.width(), center.y() - radii.height(), radii.width()*2, radii.height()*2), radii);
61 }
62
63 static std::unique_ptr<Shape> createPolygonShape(std::unique_ptr<Vector<FloatPoint>> vertices, WindRule fillRule)
64 {
65     return std::make_unique<PolygonShape>(WTFMove(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 (isFlippedWritingMode(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 (isFlippedWritingMode(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 std::unique_ptr<Shape> Shape::createShape(const BasicShape& basicShape, const LayoutSize& logicalBoxSize, WritingMode writingMode, float margin)
94 {
95     bool horizontalWritingMode = isHorizontalWritingMode(writingMode);
96     float boxWidth = horizontalWritingMode ? logicalBoxSize.width() : logicalBoxSize.height();
97     float boxHeight = horizontalWritingMode ? logicalBoxSize.height() : logicalBoxSize.width();
98     std::unique_ptr<Shape> shape;
99
100     switch (basicShape.type()) {
101
102     case BasicShape::BasicShapeCircleType: {
103         const auto& circle = downcast<BasicShapeCircle>(basicShape);
104         float centerX = floatValueForCenterCoordinate(circle.centerX(), boxWidth);
105         float centerY = floatValueForCenterCoordinate(circle.centerY(), boxHeight);
106         float radius = circle.floatValueForRadiusInBox(boxWidth, boxHeight);
107         FloatPoint logicalCenter = physicalPointToLogical(FloatPoint(centerX, centerY), logicalBoxSize.height(), writingMode);
108
109         shape = createCircleShape(logicalCenter, radius);
110         break;
111     }
112
113     case BasicShape::BasicShapeEllipseType: {
114         const auto& ellipse = downcast<BasicShapeEllipse>(basicShape);
115         float centerX = floatValueForCenterCoordinate(ellipse.centerX(), boxWidth);
116         float centerY = floatValueForCenterCoordinate(ellipse.centerY(), boxHeight);
117         float radiusX = ellipse.floatValueForRadiusInBox(ellipse.radiusX(), centerX, boxWidth);
118         float radiusY = ellipse.floatValueForRadiusInBox(ellipse.radiusY(), centerY, boxHeight);
119         FloatPoint logicalCenter = physicalPointToLogical(FloatPoint(centerX, centerY), logicalBoxSize.height(), writingMode);
120
121         shape = createEllipseShape(logicalCenter, FloatSize(radiusX, radiusY));
122         break;
123     }
124
125     case BasicShape::BasicShapePolygonType: {
126         const auto& polygon = downcast<BasicShapePolygon>(basicShape);
127         const Vector<Length>& values = polygon.values();
128         size_t valuesSize = values.size();
129         ASSERT(!(valuesSize % 2));
130         std::unique_ptr<Vector<FloatPoint>> vertices = std::make_unique<Vector<FloatPoint>>(valuesSize / 2);
131         for (unsigned i = 0; i < valuesSize; i += 2) {
132             FloatPoint vertex(
133                 floatValueForLength(values.at(i), boxWidth),
134                 floatValueForLength(values.at(i + 1), boxHeight));
135             (*vertices)[i / 2] = physicalPointToLogical(vertex, logicalBoxSize.height(), writingMode);
136         }
137
138         shape = createPolygonShape(WTFMove(vertices), polygon.windRule());
139         break;
140     }
141
142     case BasicShape::BasicShapeInsetType: {
143         const auto& inset = downcast<BasicShapeInset>(basicShape);
144         float left = floatValueForLength(inset.left(), boxWidth);
145         float top = floatValueForLength(inset.top(), boxHeight);
146         FloatRect rect(left,
147             top,
148             std::max<float>(boxWidth - left - floatValueForLength(inset.right(), boxWidth), 0),
149             std::max<float>(boxHeight - top - floatValueForLength(inset.bottom(), boxHeight), 0));
150         FloatRect logicalRect = physicalRectToLogical(rect, logicalBoxSize.height(), writingMode);
151
152         FloatSize boxSize(boxWidth, boxHeight);
153         FloatSize topLeftRadius = physicalSizeToLogical(floatSizeForLengthSize(inset.topLeftRadius(), boxSize), writingMode);
154         FloatSize topRightRadius = physicalSizeToLogical(floatSizeForLengthSize(inset.topRightRadius(), boxSize), writingMode);
155         FloatSize bottomLeftRadius = physicalSizeToLogical(floatSizeForLengthSize(inset.bottomLeftRadius(), boxSize), writingMode);
156         FloatSize bottomRightRadius = physicalSizeToLogical(floatSizeForLengthSize(inset.bottomRightRadius(), boxSize), writingMode);
157         FloatRoundedRect::Radii cornerRadii(topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius);
158
159         cornerRadii.scale(calcBorderRadiiConstraintScaleFor(logicalRect, cornerRadii));
160
161         shape = createInsetShape(FloatRoundedRect(logicalRect, cornerRadii));
162         break;
163     }
164
165     default:
166         ASSERT_NOT_REACHED();
167     }
168
169     shape->m_writingMode = writingMode;
170     shape->m_margin = margin;
171
172     return shape;
173 }
174
175 std::unique_ptr<Shape> Shape::createRasterShape(Image* image, float threshold, const LayoutRect& imageR, const LayoutRect& marginR, WritingMode writingMode, float margin)
176 {
177     ASSERT(marginR.height() >= 0);
178
179     IntRect imageRect = snappedIntRect(imageR);
180     IntRect marginRect = snappedIntRect(marginR);
181     auto intervals = std::make_unique<RasterShapeIntervals>(marginRect.height(), -marginRect.y());
182     // FIXME (149420): This buffer should not be unconditionally unaccelerated.
183     std::unique_ptr<ImageBuffer> imageBuffer = ImageBuffer::create(imageRect.size(), Unaccelerated);
184
185     if (imageBuffer) {
186         GraphicsContext& graphicsContext = imageBuffer->context();
187         if (image)
188             graphicsContext.drawImage(*image, IntRect(IntPoint(), imageRect.size()));
189
190         RefPtr<Uint8ClampedArray> pixelArray = imageBuffer->getUnmultipliedImageData(IntRect(IntPoint(), imageRect.size()));
191         unsigned pixelArrayLength = pixelArray->length();
192         unsigned pixelArrayOffset = 3; // Each pixel is four bytes: RGBA.
193         uint8_t alphaPixelThreshold = threshold * 255;
194
195         int minBufferY = std::max(0, marginRect.y() - imageRect.y());
196         int maxBufferY = std::min(imageRect.height(), marginRect.maxY() - imageRect.y());
197
198         if (static_cast<unsigned>(imageRect.width() * imageRect.height() * 4) == pixelArrayLength) {
199             for (int y = minBufferY; y < maxBufferY; ++y) {
200                 int startX = -1;
201                 for (int x = 0; x < imageRect.width(); ++x, pixelArrayOffset += 4) {
202                     uint8_t alpha = pixelArray->item(pixelArrayOffset);
203                     bool alphaAboveThreshold = alpha > alphaPixelThreshold;
204                     if (startX == -1 && alphaAboveThreshold) {
205                         startX = x;
206                     } else if (startX != -1 && (!alphaAboveThreshold || x == imageRect.width() - 1)) {
207                         // We're creating "end-point exclusive" intervals here. The value of an interval's x1 is
208                         // the first index of an above-threshold pixel for y, and the value of x2 is 1+ the index
209                         // of the last above-threshold pixel.
210                         int endX = alphaAboveThreshold ? x + 1 : x;
211                         intervals->intervalAt(y + imageRect.y()).unite(IntShapeInterval(startX + imageRect.x(), endX + imageRect.x()));
212                         startX = -1;
213                     }
214                 }
215             }
216         }
217     }
218
219     auto rasterShape = std::make_unique<RasterShape>(WTFMove(intervals), marginRect.size());
220     rasterShape->m_writingMode = writingMode;
221     rasterShape->m_margin = margin;
222     return WTFMove(rasterShape);
223 }
224
225 std::unique_ptr<Shape> Shape::createBoxShape(const RoundedRect& roundedRect, WritingMode writingMode, float margin)
226 {
227     ASSERT(roundedRect.rect().width() >= 0 && roundedRect.rect().height() >= 0);
228
229     FloatRect rect(0, 0, roundedRect.rect().width(), roundedRect.rect().height());
230     FloatRoundedRect bounds(rect, roundedRect.radii());
231     auto shape = std::make_unique<BoxShape>(bounds);
232     shape->m_writingMode = writingMode;
233     shape->m_margin = margin;
234
235     return WTFMove(shape);
236 }
237
238 } // namespace WebCore