diff options
Diffstat (limited to 'Source/WebCore/rendering/shapes/Shape.cpp')
-rw-r--r-- | Source/WebCore/rendering/shapes/Shape.cpp | 217 |
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 |