summaryrefslogtreecommitdiff
path: root/Source/WebCore/rendering/shapes/Shape.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/rendering/shapes/Shape.cpp')
-rw-r--r--Source/WebCore/rendering/shapes/Shape.cpp217
1 files changed, 72 insertions, 145 deletions
diff --git a/Source/WebCore/rendering/shapes/Shape.cpp b/Source/WebCore/rendering/shapes/Shape.cpp
index 012324997..6832d09b8 100644
--- a/Source/WebCore/rendering/shapes/Shape.cpp
+++ b/Source/WebCore/rendering/shapes/Shape.cpp
@@ -31,55 +31,46 @@
#include "Shape.h"
#include "BasicShapeFunctions.h"
+#include "BasicShapes.h"
#include "BoxShape.h"
-#include "CachedImage.h"
-#include "FloatSize.h"
+#include "GraphicsContext.h"
#include "ImageBuffer.h"
#include "LengthFunctions.h"
#include "PolygonShape.h"
#include "RasterShape.h"
#include "RectangleShape.h"
#include "WindRule.h"
-#include <wtf/MathExtras.h>
-#include <wtf/OwnPtr.h>
-#include <wtf/PassOwnPtr.h>
namespace WebCore {
-static PassOwnPtr<Shape> createInsetShape(const FloatRoundedRect& bounds)
+static std::unique_ptr<Shape> createInsetShape(const FloatRoundedRect& bounds)
{
ASSERT(bounds.rect().width() >= 0 && bounds.rect().height() >= 0);
- return adoptPtr(new BoxShape(bounds));
+ return std::make_unique<BoxShape>(bounds);
}
-static PassOwnPtr<Shape> createRectangleShape(const FloatRect& bounds, const FloatSize& radii)
-{
- ASSERT(bounds.width() >= 0 && bounds.height() >= 0 && radii.width() >= 0 && radii.height() >= 0);
- return adoptPtr(new RectangleShape(bounds, radii));
-}
-
-static PassOwnPtr<Shape> createCircleShape(const FloatPoint& center, float radius)
+static std::unique_ptr<Shape> createCircleShape(const FloatPoint& center, float radius)
{
ASSERT(radius >= 0);
- return adoptPtr(new RectangleShape(FloatRect(center.x() - radius, center.y() - radius, radius*2, radius*2), FloatSize(radius, radius)));
+ return std::make_unique<RectangleShape>(FloatRect(center.x() - radius, center.y() - radius, radius*2, radius*2), FloatSize(radius, radius));
}
-static PassOwnPtr<Shape> createEllipseShape(const FloatPoint& center, const FloatSize& radii)
+static std::unique_ptr<Shape> createEllipseShape(const FloatPoint& center, const FloatSize& radii)
{
ASSERT(radii.width() >= 0 && radii.height() >= 0);
- return adoptPtr(new RectangleShape(FloatRect(center.x() - radii.width(), center.y() - radii.height(), radii.width()*2, radii.height()*2), radii));
+ return std::make_unique<RectangleShape>(FloatRect(center.x() - radii.width(), center.y() - radii.height(), radii.width()*2, radii.height()*2), radii);
}
-static PassOwnPtr<Shape> createPolygonShape(PassOwnPtr<Vector<FloatPoint>> vertices, WindRule fillRule)
+static std::unique_ptr<Shape> createPolygonShape(std::unique_ptr<Vector<FloatPoint>> vertices, WindRule fillRule)
{
- return adoptPtr(new PolygonShape(vertices, fillRule));
+ return std::make_unique<PolygonShape>(WTFMove(vertices), fillRule);
}
static inline FloatRect physicalRectToLogical(const FloatRect& rect, float logicalBoxHeight, WritingMode writingMode)
{
if (isHorizontalWritingMode(writingMode))
return rect;
- if (isFlippedBlocksWritingMode(writingMode))
+ if (isFlippedWritingMode(writingMode))
return FloatRect(rect.y(), logicalBoxHeight - rect.maxX(), rect.height(), rect.width());
return rect.transposedRect();
}
@@ -88,7 +79,7 @@ static inline FloatPoint physicalPointToLogical(const FloatPoint& point, float l
{
if (isHorizontalWritingMode(writingMode))
return point;
- if (isFlippedBlocksWritingMode(writingMode))
+ if (isFlippedWritingMode(writingMode))
return FloatPoint(point.y(), logicalBoxHeight - point.x());
return point.transposedPoint();
}
@@ -100,86 +91,32 @@ static inline FloatSize physicalSizeToLogical(const FloatSize& size, WritingMode
return size.transposedSize();
}
-static inline void ensureRadiiDoNotOverlap(FloatRect &bounds, FloatSize &radii)
-{
- float widthRatio = bounds.width() / (2 * radii.width());
- float heightRatio = bounds.height() / (2 * radii.height());
- float reductionRatio = std::min<float>(widthRatio, heightRatio);
- if (reductionRatio < 1) {
- radii.setWidth(reductionRatio * radii.width());
- radii.setHeight(reductionRatio * radii.height());
- }
-}
-
-PassOwnPtr<Shape> Shape::createShape(const BasicShape* basicShape, const LayoutSize& logicalBoxSize, WritingMode writingMode, Length margin, Length padding)
+std::unique_ptr<Shape> Shape::createShape(const BasicShape& basicShape, const LayoutSize& logicalBoxSize, WritingMode writingMode, float margin)
{
- ASSERT(basicShape);
-
bool horizontalWritingMode = isHorizontalWritingMode(writingMode);
float boxWidth = horizontalWritingMode ? logicalBoxSize.width() : logicalBoxSize.height();
float boxHeight = horizontalWritingMode ? logicalBoxSize.height() : logicalBoxSize.width();
- OwnPtr<Shape> shape;
-
- switch (basicShape->type()) {
-
- case BasicShape::BasicShapeRectangleType: {
- const BasicShapeRectangle& rectangle = *static_cast<const BasicShapeRectangle*>(basicShape);
- FloatRect bounds(
- floatValueForLength(rectangle.x(), boxWidth),
- floatValueForLength(rectangle.y(), boxHeight),
- floatValueForLength(rectangle.width(), boxWidth),
- floatValueForLength(rectangle.height(), boxHeight));
- FloatSize cornerRadii(
- floatValueForLength(rectangle.cornerRadiusX(), boxWidth),
- floatValueForLength(rectangle.cornerRadiusY(), boxHeight));
- ensureRadiiDoNotOverlap(bounds, cornerRadii);
- FloatRect logicalBounds = physicalRectToLogical(bounds, logicalBoxSize.height(), writingMode);
-
- shape = createRectangleShape(logicalBounds, physicalSizeToLogical(cornerRadii, writingMode));
- break;
- }
+ std::unique_ptr<Shape> shape;
- case BasicShape::DeprecatedBasicShapeCircleType: {
- const DeprecatedBasicShapeCircle* circle = static_cast<const DeprecatedBasicShapeCircle*>(basicShape);
- float centerX = floatValueForLength(circle->centerX(), boxWidth);
- float centerY = floatValueForLength(circle->centerY(), boxHeight);
- float radius = floatValueForLength(circle->radius(), sqrtf((boxWidth * boxWidth + boxHeight * boxHeight) / 2));
- FloatPoint logicalCenter = physicalPointToLogical(FloatPoint(centerX, centerY), logicalBoxSize.height(), writingMode);
-
- shape = createCircleShape(logicalCenter, radius);
- break;
- }
+ switch (basicShape.type()) {
case BasicShape::BasicShapeCircleType: {
- const BasicShapeCircle* circle = static_cast<const BasicShapeCircle*>(basicShape);
- float centerX = floatValueForCenterCoordinate(circle->centerX(), boxWidth);
- float centerY = floatValueForCenterCoordinate(circle->centerY(), boxHeight);
- float radius = circle->floatValueForRadiusInBox(boxWidth, boxHeight);
+ const auto& circle = downcast<BasicShapeCircle>(basicShape);
+ float centerX = floatValueForCenterCoordinate(circle.centerX(), boxWidth);
+ float centerY = floatValueForCenterCoordinate(circle.centerY(), boxHeight);
+ float radius = circle.floatValueForRadiusInBox(boxWidth, boxHeight);
FloatPoint logicalCenter = physicalPointToLogical(FloatPoint(centerX, centerY), logicalBoxSize.height(), writingMode);
shape = createCircleShape(logicalCenter, radius);
break;
}
- case BasicShape::DeprecatedBasicShapeEllipseType: {
- const DeprecatedBasicShapeEllipse* ellipse = static_cast<const DeprecatedBasicShapeEllipse*>(basicShape);
- float centerX = floatValueForLength(ellipse->centerX(), boxWidth);
- float centerY = floatValueForLength(ellipse->centerY(), boxHeight);
- float radiusX = floatValueForLength(ellipse->radiusX(), boxWidth);
- float radiusY = floatValueForLength(ellipse->radiusY(), boxHeight);
- FloatPoint logicalCenter = physicalPointToLogical(FloatPoint(centerX, centerY), logicalBoxSize.height(), writingMode);
- FloatSize logicalRadii = physicalSizeToLogical(FloatSize(radiusX, radiusY), writingMode);
-
- shape = createEllipseShape(logicalCenter, logicalRadii);
- break;
- }
-
case BasicShape::BasicShapeEllipseType: {
- const BasicShapeEllipse* ellipse = static_cast<const BasicShapeEllipse*>(basicShape);
- float centerX = floatValueForCenterCoordinate(ellipse->centerX(), boxWidth);
- float centerY = floatValueForCenterCoordinate(ellipse->centerY(), boxHeight);
- float radiusX = ellipse->floatValueForRadiusInBox(ellipse->radiusX(), centerX, boxWidth);
- float radiusY = ellipse->floatValueForRadiusInBox(ellipse->radiusY(), centerY, boxHeight);
+ const auto& ellipse = downcast<BasicShapeEllipse>(basicShape);
+ float centerX = floatValueForCenterCoordinate(ellipse.centerX(), boxWidth);
+ float centerY = floatValueForCenterCoordinate(ellipse.centerY(), boxHeight);
+ float radiusX = ellipse.floatValueForRadiusInBox(ellipse.radiusX(), centerX, boxWidth);
+ float radiusY = ellipse.floatValueForRadiusInBox(ellipse.radiusY(), centerY, boxHeight);
FloatPoint logicalCenter = physicalPointToLogical(FloatPoint(centerX, centerY), logicalBoxSize.height(), writingMode);
shape = createEllipseShape(logicalCenter, FloatSize(radiusX, radiusY));
@@ -187,11 +124,11 @@ PassOwnPtr<Shape> Shape::createShape(const BasicShape* basicShape, const LayoutS
}
case BasicShape::BasicShapePolygonType: {
- const BasicShapePolygon& polygon = *static_cast<const BasicShapePolygon*>(basicShape);
+ const auto& polygon = downcast<BasicShapePolygon>(basicShape);
const Vector<Length>& values = polygon.values();
size_t valuesSize = values.size();
ASSERT(!(valuesSize % 2));
- OwnPtr<Vector<FloatPoint>> vertices = adoptPtr(new Vector<FloatPoint>(valuesSize / 2));
+ std::unique_ptr<Vector<FloatPoint>> vertices = std::make_unique<Vector<FloatPoint>>(valuesSize / 2);
for (unsigned i = 0; i < valuesSize; i += 2) {
FloatPoint vertex(
floatValueForLength(values.at(i), boxWidth),
@@ -199,44 +136,30 @@ PassOwnPtr<Shape> Shape::createShape(const BasicShape* basicShape, const LayoutS
(*vertices)[i / 2] = physicalPointToLogical(vertex, logicalBoxSize.height(), writingMode);
}
- shape = createPolygonShape(vertices.release(), polygon.windRule());
- break;
- }
-
- case BasicShape::BasicShapeInsetRectangleType: {
- const BasicShapeInsetRectangle& rectangle = *static_cast<const BasicShapeInsetRectangle*>(basicShape);
- float left = floatValueForLength(rectangle.left(), boxWidth);
- float top = floatValueForLength(rectangle.top(), boxHeight);
- FloatRect bounds(
- left,
- top,
- boxWidth - left - floatValueForLength(rectangle.right(), boxWidth),
- boxHeight - top - floatValueForLength(rectangle.bottom(), boxHeight));
- FloatSize cornerRadii(
- floatValueForLength(rectangle.cornerRadiusX(), boxWidth),
- floatValueForLength(rectangle.cornerRadiusY(), boxHeight));
- ensureRadiiDoNotOverlap(bounds, cornerRadii);
- FloatRect logicalBounds = physicalRectToLogical(bounds, logicalBoxSize.height(), writingMode);
-
- shape = createRectangleShape(logicalBounds, physicalSizeToLogical(cornerRadii, writingMode));
+ shape = createPolygonShape(WTFMove(vertices), polygon.windRule());
break;
}
case BasicShape::BasicShapeInsetType: {
- const BasicShapeInset& inset = *static_cast<const BasicShapeInset*>(basicShape);
+ const auto& inset = downcast<BasicShapeInset>(basicShape);
float left = floatValueForLength(inset.left(), boxWidth);
float top = floatValueForLength(inset.top(), boxHeight);
FloatRect rect(left,
top,
- boxWidth - left - floatValueForLength(inset.right(), boxWidth),
- boxHeight - top - floatValueForLength(inset.bottom(), boxHeight));
+ std::max<float>(boxWidth - left - floatValueForLength(inset.right(), boxWidth), 0),
+ std::max<float>(boxHeight - top - floatValueForLength(inset.bottom(), boxHeight), 0));
FloatRect logicalRect = physicalRectToLogical(rect, logicalBoxSize.height(), writingMode);
- shape = createInsetShape(FloatRoundedRect(logicalRect,
- inset.topLeftRadius().floatSize(),
- inset.topRightRadius().floatSize(),
- inset.bottomLeftRadius().floatSize(),
- inset.bottomRightRadius().floatSize()));
+ FloatSize boxSize(boxWidth, boxHeight);
+ FloatSize topLeftRadius = physicalSizeToLogical(floatSizeForLengthSize(inset.topLeftRadius(), boxSize), writingMode);
+ FloatSize topRightRadius = physicalSizeToLogical(floatSizeForLengthSize(inset.topRightRadius(), boxSize), writingMode);
+ FloatSize bottomLeftRadius = physicalSizeToLogical(floatSizeForLengthSize(inset.bottomLeftRadius(), boxSize), writingMode);
+ FloatSize bottomRightRadius = physicalSizeToLogical(floatSizeForLengthSize(inset.bottomRightRadius(), boxSize), writingMode);
+ FloatRoundedRect::Radii cornerRadii(topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius);
+
+ cornerRadii.scale(calcBorderRadiiConstraintScaleFor(logicalRect, cornerRadii));
+
+ shape = createInsetShape(FloatRoundedRect(logicalRect, cornerRadii));
break;
}
@@ -245,42 +168,48 @@ PassOwnPtr<Shape> Shape::createShape(const BasicShape* basicShape, const LayoutS
}
shape->m_writingMode = writingMode;
- shape->m_margin = floatValueForLength(margin, 0);
- shape->m_padding = floatValueForLength(padding, 0);
+ shape->m_margin = margin;
- return shape.release();
+ return shape;
}
-PassOwnPtr<Shape> Shape::createRasterShape(const StyleImage& styleImage, float threshold, const LayoutRect& imageRect, const LayoutSize&, WritingMode writingMode, Length margin, Length padding)
+std::unique_ptr<Shape> Shape::createRasterShape(Image* image, float threshold, const LayoutRect& imageR, const LayoutRect& marginR, WritingMode writingMode, float margin)
{
- ASSERT(styleImage.cachedImage());
- ASSERT(styleImage.cachedImage()->hasImage());
+ ASSERT(marginR.height() >= 0);
- IntRect toRect = pixelSnappedIntRect(imageRect);
- IntSize bufferSize = toRect.size();
- IntSize rasterSize = IntSize(toRect.maxX(), toRect.maxY());
- OwnPtr<RasterShapeIntervals> intervals = adoptPtr(new RasterShapeIntervals(rasterSize.height()));
- std::unique_ptr<ImageBuffer> imageBuffer = ImageBuffer::create(bufferSize);
+ IntRect imageRect = snappedIntRect(imageR);
+ IntRect marginRect = snappedIntRect(marginR);
+ auto intervals = std::make_unique<RasterShapeIntervals>(marginRect.height(), -marginRect.y());
+ // FIXME (149420): This buffer should not be unconditionally unaccelerated.
+ std::unique_ptr<ImageBuffer> imageBuffer = ImageBuffer::create(imageRect.size(), Unaccelerated);
if (imageBuffer) {
- GraphicsContext* graphicsContext = imageBuffer->context();
- graphicsContext->drawImage(styleImage.cachedImage()->image(), ColorSpaceDeviceRGB, IntRect(IntPoint(), bufferSize));
+ GraphicsContext& graphicsContext = imageBuffer->context();
+ if (image)
+ graphicsContext.drawImage(*image, IntRect(IntPoint(), imageRect.size()));
- RefPtr<Uint8ClampedArray> pixelArray = imageBuffer->getUnmultipliedImageData(IntRect(IntPoint(), bufferSize));
+ RefPtr<Uint8ClampedArray> pixelArray = imageBuffer->getUnmultipliedImageData(IntRect(IntPoint(), imageRect.size()));
unsigned pixelArrayLength = pixelArray->length();
unsigned pixelArrayOffset = 3; // Each pixel is four bytes: RGBA.
uint8_t alphaPixelThreshold = threshold * 255;
- if (static_cast<unsigned>(bufferSize.width() * bufferSize.height() * 4) == pixelArrayLength) { // sanity check
- for (int y = 0; y < bufferSize.height(); ++y) {
+ int minBufferY = std::max(0, marginRect.y() - imageRect.y());
+ int maxBufferY = std::min(imageRect.height(), marginRect.maxY() - imageRect.y());
+
+ if ((imageRect.area() * 4).unsafeGet() == pixelArrayLength) {
+ for (int y = minBufferY; y < maxBufferY; ++y) {
int startX = -1;
- for (int x = 0; x < bufferSize.width(); ++x, pixelArrayOffset += 4) {
+ for (int x = 0; x < imageRect.width(); ++x, pixelArrayOffset += 4) {
uint8_t alpha = pixelArray->item(pixelArrayOffset);
bool alphaAboveThreshold = alpha > alphaPixelThreshold;
if (startX == -1 && alphaAboveThreshold) {
startX = x;
- } else if (startX != -1 && (!alphaAboveThreshold || x == bufferSize.width() - 1)) {
- intervals->appendInterval(y + toRect.y(), startX + toRect.x(), x + toRect.x());
+ } else if (startX != -1 && (!alphaAboveThreshold || x == imageRect.width() - 1)) {
+ // We're creating "end-point exclusive" intervals here. The value of an interval's x1 is
+ // the first index of an above-threshold pixel for y, and the value of x2 is 1+ the index
+ // of the last above-threshold pixel.
+ int endX = alphaAboveThreshold ? x + 1 : x;
+ intervals->intervalAt(y + imageRect.y()).unite(IntShapeInterval(startX + imageRect.x(), endX + imageRect.x()));
startX = -1;
}
}
@@ -288,25 +217,23 @@ PassOwnPtr<Shape> Shape::createRasterShape(const StyleImage& styleImage, float t
}
}
- OwnPtr<RasterShape> rasterShape = adoptPtr(new RasterShape(intervals.release(), rasterSize));
+ auto rasterShape = std::make_unique<RasterShape>(WTFMove(intervals), marginRect.size());
rasterShape->m_writingMode = writingMode;
- rasterShape->m_margin = floatValueForLength(margin, 0);
- rasterShape->m_padding = floatValueForLength(padding, 0);
- return rasterShape.release();
+ rasterShape->m_margin = margin;
+ return WTFMove(rasterShape);
}
-PassOwnPtr<Shape> Shape::createLayoutBoxShape(const RoundedRect& roundedRect, WritingMode writingMode, Length margin, Length padding)
+std::unique_ptr<Shape> Shape::createBoxShape(const RoundedRect& roundedRect, WritingMode writingMode, float margin)
{
ASSERT(roundedRect.rect().width() >= 0 && roundedRect.rect().height() >= 0);
FloatRect rect(0, 0, roundedRect.rect().width(), roundedRect.rect().height());
FloatRoundedRect bounds(rect, roundedRect.radii());
- OwnPtr<Shape> shape = adoptPtr(new BoxShape(bounds));
+ auto shape = std::make_unique<BoxShape>(bounds);
shape->m_writingMode = writingMode;
- shape->m_margin = floatValueForLength(margin, 0);
- shape->m_padding = floatValueForLength(padding, 0);
+ shape->m_margin = margin;
- return shape.release();
+ return WTFMove(shape);
}
} // namespace WebCore