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