summaryrefslogtreecommitdiff
path: root/Source/WebCore/rendering/shapes
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/rendering/shapes')
-rw-r--r--Source/WebCore/rendering/shapes/BoxShape.cpp161
-rw-r--r--Source/WebCore/rendering/shapes/BoxShape.h26
-rw-r--r--Source/WebCore/rendering/shapes/PolygonShape.cpp525
-rw-r--r--Source/WebCore/rendering/shapes/PolygonShape.h67
-rw-r--r--Source/WebCore/rendering/shapes/RasterShape.cpp254
-rw-r--r--Source/WebCore/rendering/shapes/RasterShape.h85
-rw-r--r--Source/WebCore/rendering/shapes/RectangleShape.cpp138
-rw-r--r--Source/WebCore/rendering/shapes/RectangleShape.h22
-rw-r--r--Source/WebCore/rendering/shapes/Shape.cpp217
-rw-r--r--Source/WebCore/rendering/shapes/Shape.h46
-rw-r--r--Source/WebCore/rendering/shapes/ShapeInfo.cpp128
-rw-r--r--Source/WebCore/rendering/shapes/ShapeInfo.h217
-rw-r--r--Source/WebCore/rendering/shapes/ShapeInsideInfo.cpp127
-rw-r--r--Source/WebCore/rendering/shapes/ShapeInsideInfo.h133
-rw-r--r--Source/WebCore/rendering/shapes/ShapeInterval.h175
-rw-r--r--Source/WebCore/rendering/shapes/ShapeOutsideInfo.cpp315
-rw-r--r--Source/WebCore/rendering/shapes/ShapeOutsideInfo.h119
17 files changed, 751 insertions, 2004 deletions
diff --git a/Source/WebCore/rendering/shapes/BoxShape.cpp b/Source/WebCore/rendering/shapes/BoxShape.cpp
index 25c966875..dba19e76f 100644
--- a/Source/WebCore/rendering/shapes/BoxShape.cpp
+++ b/Source/WebCore/rendering/shapes/BoxShape.cpp
@@ -12,7 +12,7 @@
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
@@ -30,10 +30,70 @@
#include "config.h"
#include "BoxShape.h"
+#include "RenderBox.h"
#include <wtf/MathExtras.h>
namespace WebCore {
+static inline LayoutUnit adjustRadiusForMarginBoxShape(LayoutUnit radius, LayoutUnit margin)
+{
+ // This algorithm is defined in the CSS Shapes specifcation
+ if (!margin)
+ return radius;
+
+ LayoutUnit ratio = radius / margin;
+ if (ratio < 1)
+ return radius + (margin * (1 + pow(ratio - 1, 3.0)));
+
+ return radius + margin;
+}
+
+static inline LayoutSize computeMarginBoxShapeRadius(const LayoutSize& radius, const LayoutSize& adjacentMargins)
+{
+ return LayoutSize(adjustRadiusForMarginBoxShape(radius.width(), adjacentMargins.width()),
+ adjustRadiusForMarginBoxShape(radius.height(), adjacentMargins.height()));
+}
+
+static inline RoundedRect::Radii computeMarginBoxShapeRadii(const RoundedRect::Radii& radii, const RenderBox& renderer)
+{
+ return RoundedRect::Radii(computeMarginBoxShapeRadius(radii.topLeft(), LayoutSize(renderer.marginLeft(), renderer.marginTop())),
+ computeMarginBoxShapeRadius(radii.topRight(), LayoutSize(renderer.marginRight(), renderer.marginTop())),
+ computeMarginBoxShapeRadius(radii.bottomLeft(), LayoutSize(renderer.marginLeft(), renderer.marginBottom())),
+ computeMarginBoxShapeRadius(radii.bottomRight(), LayoutSize(renderer.marginRight(), renderer.marginBottom())));
+}
+
+RoundedRect computeRoundedRectForBoxShape(CSSBoxType box, const RenderBox& renderer)
+{
+ const RenderStyle& style = renderer.style();
+ switch (box) {
+ case MarginBox: {
+ if (!style.hasBorderRadius())
+ return RoundedRect(renderer.marginBoxRect(), RoundedRect::Radii());
+
+ LayoutRect marginBox = renderer.marginBoxRect();
+ RoundedRect::Radii radii = computeMarginBoxShapeRadii(style.getRoundedBorderFor(renderer.borderBoxRect()).radii(), renderer);
+ radii.scale(calcBorderRadiiConstraintScaleFor(marginBox, radii));
+ return RoundedRect(marginBox, radii);
+ }
+ case PaddingBox:
+ return style.getRoundedInnerBorderFor(renderer.borderBoxRect());
+ case ContentBox:
+ return style.getRoundedInnerBorderFor(renderer.borderBoxRect(),
+ renderer.paddingTop() + renderer.borderTop(), renderer.paddingBottom() + renderer.borderBottom(),
+ renderer.paddingLeft() + renderer.borderLeft(), renderer.paddingRight() + renderer.borderRight());
+ // fill, stroke, view-box compute to border-box for HTML elements.
+ case BorderBox:
+ case Fill:
+ case Stroke:
+ case ViewBox:
+ case BoxMissing:
+ return style.getRoundedBorderFor(renderer.borderBoxRect());
+ }
+
+ ASSERT_NOT_REACHED();
+ return style.getRoundedBorderFor(renderer.borderBoxRect());
+}
+
LayoutRect BoxShape::shapeMarginLogicalBoundingBox() const
{
FloatRect marginBounds(m_bounds.rect());
@@ -42,14 +102,6 @@ LayoutRect BoxShape::shapeMarginLogicalBoundingBox() const
return static_cast<LayoutRect>(marginBounds);
}
-LayoutRect BoxShape::shapePaddingLogicalBoundingBox() const
-{
- FloatRect paddingBounds(m_bounds.rect());
- if (shapePadding() > 0)
- paddingBounds.inflate(-shapePadding());
- return static_cast<LayoutRect>(paddingBounds);
-}
-
FloatRoundedRect BoxShape::shapeMarginBounds() const
{
FloatRoundedRect marginBounds(m_bounds);
@@ -60,44 +112,36 @@ FloatRoundedRect BoxShape::shapeMarginBounds() const
return marginBounds;
}
-FloatRoundedRect BoxShape::shapePaddingBounds() const
-{
- FloatRoundedRect paddingBounds(m_bounds);
- if (shapePadding() > 0) {
- paddingBounds.inflate(-shapePadding());
- paddingBounds.expandRadii(-shapePadding());
- }
- return paddingBounds;
-}
-
-void BoxShape::getExcludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList& result) const
+LineSegment BoxShape::getExcludedInterval(LayoutUnit logicalTop, LayoutUnit logicalHeight) const
{
const FloatRoundedRect& marginBounds = shapeMarginBounds();
if (marginBounds.isEmpty() || !lineOverlapsShapeMarginBounds(logicalTop, logicalHeight))
- return;
+ return LineSegment();
float y1 = logicalTop;
float y2 = logicalTop + logicalHeight;
const FloatRect& rect = marginBounds.rect();
- if (!marginBounds.isRounded()) {
- result.append(LineSegment(rect.x(), rect.maxX()));
- return;
- }
+ if (!marginBounds.isRounded())
+ return LineSegment(rect.x(), rect.maxX());
float topCornerMaxY = std::max<float>(marginBounds.topLeftCorner().maxY(), marginBounds.topRightCorner().maxY());
float bottomCornerMinY = std::min<float>(marginBounds.bottomLeftCorner().y(), marginBounds.bottomRightCorner().y());
- if (y1 <= topCornerMaxY && y2 >= bottomCornerMinY) {
- result.append(LineSegment(rect.x(), rect.maxX()));
- return;
- }
+ if (topCornerMaxY <= bottomCornerMinY && y1 <= topCornerMaxY && y2 >= bottomCornerMinY)
+ return LineSegment(rect.x(), rect.maxX());
float x1 = rect.maxX();
float x2 = rect.x();
float minXIntercept;
float maxXIntercept;
+ if (y1 <= marginBounds.topLeftCorner().maxY() && y2 >= marginBounds.bottomLeftCorner().y())
+ x1 = rect.x();
+
+ if (y1 <= marginBounds.topRightCorner().maxY() && y2 >= marginBounds.bottomRightCorner().y())
+ x2 = rect.maxX();
+
if (marginBounds.xInterceptsAtY(y1, minXIntercept, maxXIntercept)) {
x1 = std::min<float>(x1, minXIntercept);
x2 = std::max<float>(x2, maxXIntercept);
@@ -109,65 +153,14 @@ void BoxShape::getExcludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHei
}
ASSERT(x2 >= x1);
- result.append(LineSegment(x1, x2));
-}
-
-void BoxShape::getIncludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList& result) const
-{
- const FloatRoundedRect& paddingBounds = shapePaddingBounds();
- if (paddingBounds.isEmpty())
- return;
-
- const FloatRect& rect = paddingBounds.rect();
- float y1 = logicalTop;
- float y2 = logicalTop + logicalHeight;
-
- if (y1 < rect.y() || y2 > rect.maxY())
- return;
-
- if (!paddingBounds.isRounded()) {
- result.append(LineSegment(rect.x(), rect.maxX()));
- return;
- }
-
- float x1 = rect.x();
- float x2 = rect.maxX();
- float minXIntercept;
- float maxXIntercept;
-
- if (paddingBounds.xInterceptsAtY(y1, minXIntercept, maxXIntercept)) {
- x1 = std::max<float>(x1, minXIntercept);
- x2 = std::min<float>(x2, maxXIntercept);
- }
-
- if (paddingBounds.xInterceptsAtY(y2, minXIntercept, maxXIntercept)) {
- x1 = std::max<float>(x1, minXIntercept);
- x2 = std::min<float>(x2, maxXIntercept);
- }
-
- result.append(LineSegment(x1, x2));
-}
-
-bool BoxShape::firstIncludedIntervalLogicalTop(LayoutUnit minLogicalIntervalTop, const FloatSize&, LayoutUnit& result) const
-{
- // FIXME: this method is only a stub, https://bugs.webkit.org/show_bug.cgi?id=124606.
-
- result = minLogicalIntervalTop;
- return true;
-}
-
-static void addRoundedRect(Path& path, const FloatRect& rect, const FloatRoundedRect::Radii& radii)
-{
- path.addRoundedRect(rect, radii.topLeft(), radii.topRight(), radii.bottomLeft(), radii.bottomRight(), Path::PreferBezierRoundedRect);
+ return LineSegment(x1, x2);
}
void BoxShape::buildDisplayPaths(DisplayPaths& paths) const
{
- addRoundedRect(paths.shape, m_bounds.rect(), m_bounds.radii());
- if (shapeMargin()) {
- const FloatRoundedRect& marginBounds = shapeMarginBounds();
- addRoundedRect(paths.marginShape, marginBounds.rect(), marginBounds.radii());
- }
+ paths.shape.addRoundedRect(m_bounds, Path::PreferBezierRoundedRect);
+ if (shapeMargin())
+ paths.marginShape.addRoundedRect(shapeMarginBounds(), Path::PreferBezierRoundedRect);
}
} // namespace WebCore
diff --git a/Source/WebCore/rendering/shapes/BoxShape.h b/Source/WebCore/rendering/shapes/BoxShape.h
index 975578d69..9f95fcab0 100644
--- a/Source/WebCore/rendering/shapes/BoxShape.h
+++ b/Source/WebCore/rendering/shapes/BoxShape.h
@@ -12,7 +12,7 @@
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
@@ -27,37 +27,35 @@
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef BoxShape_h
-#define BoxShape_h
+#pragma once
#include "FloatRoundedRect.h"
+#include "RenderStyleConstants.h"
#include "Shape.h"
namespace WebCore {
-class BoxShape : public Shape {
+class RenderBox;
+
+RoundedRect computeRoundedRectForBoxShape(CSSBoxType, const RenderBox&);
+
+class BoxShape final : public Shape {
public:
BoxShape(const FloatRoundedRect& bounds)
: m_bounds(bounds)
{
}
- virtual LayoutRect shapeMarginLogicalBoundingBox() const override;
- virtual LayoutRect shapePaddingLogicalBoundingBox() const override;
- virtual bool isEmpty() const override { return m_bounds.isEmpty(); }
- virtual void getExcludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList&) const override;
- virtual void getIncludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList&) const override;
- virtual bool firstIncludedIntervalLogicalTop(LayoutUnit minLogicalIntervalTop, const FloatSize& minLogicalIntervalSize, LayoutUnit&) const override;
+ LayoutRect shapeMarginLogicalBoundingBox() const override;
+ bool isEmpty() const override { return m_bounds.isEmpty(); }
+ LineSegment getExcludedInterval(LayoutUnit logicalTop, LayoutUnit logicalHeight) const override;
- virtual void buildDisplayPaths(DisplayPaths&) const override;
+ void buildDisplayPaths(DisplayPaths&) const override;
private:
FloatRoundedRect shapeMarginBounds() const;
- FloatRoundedRect shapePaddingBounds() const;
FloatRoundedRect m_bounds;
};
} // namespace WebCore
-
-#endif // BoxShape_h
diff --git a/Source/WebCore/rendering/shapes/PolygonShape.cpp b/Source/WebCore/rendering/shapes/PolygonShape.cpp
index 8e241eb14..65a5af94d 100644
--- a/Source/WebCore/rendering/shapes/PolygonShape.cpp
+++ b/Source/WebCore/rendering/shapes/PolygonShape.cpp
@@ -12,7 +12,7 @@
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
@@ -30,69 +30,10 @@
#include "config.h"
#include "PolygonShape.h"
-#include "ShapeInterval.h"
#include <wtf/MathExtras.h>
namespace WebCore {
-enum EdgeIntersectionType {
- Normal,
- VertexMinY,
- VertexMaxY,
- VertexYBoth
-};
-
-struct EdgeIntersection {
- const FloatPolygonEdge* edge;
- FloatPoint point;
- EdgeIntersectionType type;
-};
-
-static inline float leftSide(const FloatPoint& vertex1, const FloatPoint& vertex2, const FloatPoint& point)
-{
- return ((point.x() - vertex1.x()) * (vertex2.y() - vertex1.y())) - ((vertex2.x() - vertex1.x()) * (point.y() - vertex1.y()));
-}
-
-static inline bool isReflexVertex(const FloatPoint& prevVertex, const FloatPoint& vertex, const FloatPoint& nextVertex)
-{
- return leftSide(prevVertex, nextVertex, vertex) < 0;
-}
-
-static bool computeXIntersection(const FloatPolygonEdge* edgePointer, float y, EdgeIntersection& result)
-{
- const FloatPolygonEdge& edge = *edgePointer;
-
- if (edge.minY() > y || edge.maxY() < y)
- return false;
-
- const FloatPoint& vertex1 = edge.vertex1();
- const FloatPoint& vertex2 = edge.vertex2();
- float dy = vertex2.y() - vertex1.y();
-
- float intersectionX;
- EdgeIntersectionType intersectionType;
-
- if (!dy) {
- intersectionType = VertexYBoth;
- intersectionX = edge.minX();
- } else if (y == edge.minY()) {
- intersectionType = VertexMinY;
- intersectionX = (vertex1.y() < vertex2.y()) ? vertex1.x() : vertex2.x();
- } else if (y == edge.maxY()) {
- intersectionType = VertexMaxY;
- intersectionX = (vertex1.y() > vertex2.y()) ? vertex1.x() : vertex2.x();
- } else {
- intersectionType = Normal;
- intersectionX = ((y - vertex1.y()) * (vertex2.x() - vertex1.x()) / dy) + vertex1.x();
- }
-
- result.edge = edgePointer;
- result.type = intersectionType;
- result.point.set(intersectionX, y);
-
- return true;
-}
-
static inline FloatSize inwardEdgeNormal(const FloatPolygonEdge& edge)
{
FloatSize edgeDelta = edge.vertex2() - edge.vertex1();
@@ -109,438 +50,116 @@ static inline FloatSize outwardEdgeNormal(const FloatPolygonEdge& edge)
return -inwardEdgeNormal(edge);
}
-static inline void appendArc(Vector<FloatPoint>& vertices, const FloatPoint& arcCenter, float arcRadius, const FloatPoint& startArcVertex, const FloatPoint& endArcVertex, bool padding)
-{
- float startAngle = atan2(startArcVertex.y() - arcCenter.y(), startArcVertex.x() - arcCenter.x());
- float endAngle = atan2(endArcVertex.y() - arcCenter.y(), endArcVertex.x() - arcCenter.x());
- const float twoPI = piFloat * 2;
- if (startAngle < 0)
- startAngle += twoPI;
- if (endAngle < 0)
- endAngle += twoPI;
- float angle = (startAngle > endAngle) ? (startAngle - endAngle) : (startAngle + twoPI - endAngle);
- const float arcSegmentCount = 6; // An even number so that one arc vertex will be eactly arcRadius from arcCenter.
- float arcSegmentAngle = ((padding) ? -angle : twoPI - angle) / arcSegmentCount;
-
- vertices.append(startArcVertex);
- for (unsigned i = 1; i < arcSegmentCount; ++i) {
- float angle = startAngle + arcSegmentAngle * i;
- vertices.append(arcCenter + FloatPoint(cos(angle) * arcRadius, sin(angle) * arcRadius));
- }
- vertices.append(endArcVertex);
-}
-
-static inline void snapVerticesToLayoutUnitGrid(Vector<FloatPoint>& vertices)
-{
- for (unsigned i = 0; i < vertices.size(); ++i)
- vertices[i].set(LayoutUnit(vertices[i].x()).toFloat(), LayoutUnit(vertices[i].y()).toFloat());
-}
-
-static inline PassOwnPtr<FloatPolygon> computeShapePaddingBounds(const FloatPolygon& polygon, float padding, WindRule fillRule)
-{
- OwnPtr<Vector<FloatPoint>> paddedVertices = adoptPtr(new Vector<FloatPoint>());
- FloatPoint intersection;
-
- for (unsigned i = 0; i < polygon.numberOfEdges(); ++i) {
- const FloatPolygonEdge& thisEdge = polygon.edgeAt(i);
- const FloatPolygonEdge& prevEdge = thisEdge.previousEdge();
- OffsetPolygonEdge thisOffsetEdge(thisEdge, inwardEdgeNormal(thisEdge) * padding);
- OffsetPolygonEdge prevOffsetEdge(prevEdge, inwardEdgeNormal(prevEdge) * padding);
-
- if (prevOffsetEdge.intersection(thisOffsetEdge, intersection))
- paddedVertices->append(intersection);
- else if (isReflexVertex(prevEdge.vertex1(), thisEdge.vertex1(), thisEdge.vertex2()))
- appendArc(*paddedVertices, thisEdge.vertex1(), padding, prevOffsetEdge.vertex2(), thisOffsetEdge.vertex1(), true);
- }
-
- snapVerticesToLayoutUnitGrid(*paddedVertices);
- return adoptPtr(new FloatPolygon(paddedVertices.release(), fillRule));
-}
-
-static inline PassOwnPtr<FloatPolygon> computeShapeMarginBounds(const FloatPolygon& polygon, float margin, WindRule fillRule)
+float OffsetPolygonEdge::xIntercept(float y) const
{
- OwnPtr<Vector<FloatPoint>> marginVertices = adoptPtr(new Vector<FloatPoint>());
- FloatPoint intersection;
+ ASSERT(y >= minY() && y <= maxY());
- for (unsigned i = 0; i < polygon.numberOfEdges(); ++i) {
- const FloatPolygonEdge& thisEdge = polygon.edgeAt(i);
- const FloatPolygonEdge& prevEdge = thisEdge.previousEdge();
- OffsetPolygonEdge thisOffsetEdge(thisEdge, outwardEdgeNormal(thisEdge) * margin);
- OffsetPolygonEdge prevOffsetEdge(prevEdge, outwardEdgeNormal(prevEdge) * margin);
+ if (vertex1().y() == vertex2().y() || vertex1().x() == vertex2().x())
+ return minX();
+ if (y == minY())
+ return vertex1().y() < vertex2().y() ? vertex1().x() : vertex2().x();
+ if (y == maxY())
+ return vertex1().y() > vertex2().y() ? vertex1().x() : vertex2().x();
- if (prevOffsetEdge.intersection(thisOffsetEdge, intersection))
- marginVertices->append(intersection);
- else
- appendArc(*marginVertices, thisEdge.vertex1(), margin, prevOffsetEdge.vertex2(), thisOffsetEdge.vertex1(), false);
- }
-
- snapVerticesToLayoutUnitGrid(*marginVertices);
- return adoptPtr(new FloatPolygon(marginVertices.release(), fillRule));
+ return vertex1().x() + ((y - vertex1().y()) * (vertex2().x() - vertex1().x()) / (vertex2().y() - vertex1().y()));
}
-const FloatPolygon& PolygonShape::shapePaddingBounds() const
+FloatShapeInterval OffsetPolygonEdge::clippedEdgeXRange(float y1, float y2) const
{
- ASSERT(shapePadding() >= 0);
- if (!shapePadding() || m_polygon.isEmpty())
- return m_polygon;
+ if (!overlapsYRange(y1, y2) || (y1 == maxY() && minY() <= y1) || (y2 == minY() && maxY() >= y2))
+ return FloatShapeInterval();
- if (!m_paddingBounds)
- m_paddingBounds = computeShapePaddingBounds(m_polygon, shapePadding(), m_polygon.fillRule());
+ if (isWithinYRange(y1, y2))
+ return FloatShapeInterval(minX(), maxX());
- return *m_paddingBounds;
-}
+ // Clip the edge line segment to the vertical range y1,y2 and then return
+ // the clipped line segment's horizontal range.
-const FloatPolygon& PolygonShape::shapeMarginBounds() const
-{
- ASSERT(shapeMargin() >= 0);
- if (!shapeMargin() || m_polygon.isEmpty())
- return m_polygon;
-
- if (!m_marginBounds)
- m_marginBounds = computeShapeMarginBounds(m_polygon, shapeMargin(), m_polygon.fillRule());
-
- return *m_marginBounds;
-}
-
-static inline bool getVertexIntersectionVertices(const EdgeIntersection& intersection, FloatPoint& prevVertex, FloatPoint& thisVertex, FloatPoint& nextVertex)
-{
- if (intersection.type != VertexMinY && intersection.type != VertexMaxY)
- return false;
-
- ASSERT(intersection.edge && intersection.edge->polygon());
- const FloatPolygon& polygon = *(intersection.edge->polygon());
- const FloatPolygonEdge& thisEdge = *(intersection.edge);
-
- if ((intersection.type == VertexMinY && (thisEdge.vertex1().y() < thisEdge.vertex2().y()))
- || (intersection.type == VertexMaxY && (thisEdge.vertex1().y() > thisEdge.vertex2().y()))) {
- prevVertex = polygon.vertexAt(thisEdge.previousEdge().vertexIndex1());
- thisVertex = polygon.vertexAt(thisEdge.vertexIndex1());
- nextVertex = polygon.vertexAt(thisEdge.vertexIndex2());
+ FloatPoint minYVertex;
+ FloatPoint maxYVertex;
+ if (vertex1().y() < vertex2().y()) {
+ minYVertex = vertex1();
+ maxYVertex = vertex2();
} else {
- prevVertex = polygon.vertexAt(thisEdge.vertexIndex1());
- thisVertex = polygon.vertexAt(thisEdge.vertexIndex2());
- nextVertex = polygon.vertexAt(thisEdge.nextEdge().vertexIndex2());
+ minYVertex = vertex2();
+ maxYVertex = vertex1();
}
-
- return true;
+ float xForY1 = (minYVertex.y() < y1) ? xIntercept(y1) : minYVertex.x();
+ float xForY2 = (maxYVertex.y() > y2) ? xIntercept(y2) : maxYVertex.x();
+ return FloatShapeInterval(std::min(xForY1, xForY2), std::max(xForY1, xForY2));
}
-static inline bool appendIntervalX(float x, bool inside, FloatShapeIntervals& result)
+static float circleXIntercept(float y, float radius)
{
- if (!inside)
- result.append(FloatShapeInterval(x, x));
- else
- result.last().setX2(x);
-
- return !inside;
+ ASSERT(radius > 0);
+ return radius * sqrt(1 - (y * y) / (radius * radius));
}
-static bool compareEdgeIntersectionX(const EdgeIntersection& intersection1, const EdgeIntersection& intersection2)
+static FloatShapeInterval clippedCircleXRange(const FloatPoint& center, float radius, float y1, float y2)
{
- float x1 = intersection1.point.x();
- float x2 = intersection2.point.x();
- return (x1 == x2) ? intersection1.type < intersection2.type : x1 < x2;
-}
+ if (y1 >= center.y() + radius || y2 <= center.y() - radius)
+ return FloatShapeInterval();
-static void computeXIntersections(const FloatPolygon& polygon, float y, bool isMinY, FloatShapeIntervals& result)
-{
- Vector<const FloatPolygonEdge*> edges;
- if (!polygon.overlappingEdges(y, y, edges))
- return;
-
- Vector<EdgeIntersection> intersections;
- EdgeIntersection intersection;
- for (unsigned i = 0; i < edges.size(); ++i) {
- if (computeXIntersection(edges[i], y, intersection) && intersection.type != VertexYBoth)
- intersections.append(intersection);
- }
-
- if (intersections.size() < 2)
- return;
-
- std::sort(intersections.begin(), intersections.end(), WebCore::compareEdgeIntersectionX);
-
- unsigned index = 0;
- int windCount = 0;
- bool inside = false;
-
- while (index < intersections.size()) {
- const EdgeIntersection& thisIntersection = intersections[index];
- if (index + 1 < intersections.size()) {
- const EdgeIntersection& nextIntersection = intersections[index + 1];
- if ((thisIntersection.point.x() == nextIntersection.point.x()) && (thisIntersection.type == VertexMinY || thisIntersection.type == VertexMaxY)) {
- if (thisIntersection.type == nextIntersection.type) {
- // Skip pairs of intersections whose types are VertexMaxY,VertexMaxY and VertexMinY,VertexMinY.
- index += 2;
- } else {
- // Replace pairs of intersections whose types are VertexMinY,VertexMaxY or VertexMaxY,VertexMinY with one intersection.
- ++index;
- }
- continue;
- }
- }
-
- bool edgeCrossing = thisIntersection.type == Normal;
- if (!edgeCrossing) {
- FloatPoint prevVertex;
- FloatPoint thisVertex;
- FloatPoint nextVertex;
-
- if (getVertexIntersectionVertices(thisIntersection, prevVertex, thisVertex, nextVertex)) {
- if (nextVertex.y() == y)
- edgeCrossing = (isMinY) ? prevVertex.y() > y : prevVertex.y() < y;
- else if (prevVertex.y() == y)
- edgeCrossing = (isMinY) ? nextVertex.y() > y : nextVertex.y() < y;
- else
- edgeCrossing = true;
- }
- }
+ if (center.y() >= y1 && center.y() <= y2)
+ return FloatShapeInterval(center.x() - radius, center.x() + radius);
- if (edgeCrossing && polygon.fillRule() == RULE_NONZERO) {
- const FloatPolygonEdge& thisEdge = *thisIntersection.edge;
- windCount += (thisEdge.vertex2().y() > thisEdge.vertex1().y()) ? 1 : -1;
- }
-
- if (edgeCrossing && (!inside || !windCount))
- inside = appendIntervalX(thisIntersection.point.x(), inside, result);
+ // Clip the circle to the vertical range y1,y2 and return the extent of the clipped circle's
+ // projection on the X axis
- ++index;
- }
+ float xi = circleXIntercept((y2 < center.y() ? y2 : y1) - center.y(), radius);
+ return FloatShapeInterval(center.x() - xi, center.x() + xi);
}
-static bool compareX1(const FloatShapeInterval a, const FloatShapeInterval& b) { return a.x1() < b.x1(); }
-
-static void sortAndMergeShapeIntervals(FloatShapeIntervals& intervals)
+LayoutRect PolygonShape::shapeMarginLogicalBoundingBox() const
{
- std::sort(intervals.begin(), intervals.end(), compareX1);
-
- for (unsigned i = 1; i < intervals.size(); ) {
- const FloatShapeInterval& thisInterval = intervals[i];
- FloatShapeInterval& previousInterval = intervals[i - 1];
- if (thisInterval.overlaps(previousInterval)) {
- previousInterval.setX2(std::max<float>(previousInterval.x2(), thisInterval.x2()));
- intervals.remove(i);
- } else
- ++i;
- }
+ FloatRect box = m_polygon.boundingBox();
+ box.inflate(shapeMargin());
+ return LayoutRect(box);
}
-static void computeOverlappingEdgeXProjections(const FloatPolygon& polygon, float y1, float y2, FloatShapeIntervals& result)
+LineSegment PolygonShape::getExcludedInterval(LayoutUnit logicalTop, LayoutUnit logicalHeight) const
{
- Vector<const FloatPolygonEdge*> edges;
- if (!polygon.overlappingEdges(y1, y2, edges))
- return;
-
- EdgeIntersection intersection;
- for (unsigned i = 0; i < edges.size(); ++i) {
- const FloatPolygonEdge *edge = edges[i];
- float x1;
- float x2;
-
- if (edge->minY() < y1) {
- computeXIntersection(edge, y1, intersection);
- x1 = intersection.point.x();
- } else
- x1 = (edge->vertex1().y() < edge->vertex2().y()) ? edge->vertex1().x() : edge->vertex2().x();
-
- if (edge->maxY() > y2) {
- computeXIntersection(edge, y2, intersection);
- x2 = intersection.point.x();
- } else
- x2 = (edge->vertex1().y() > edge->vertex2().y()) ? edge->vertex1().x() : edge->vertex2().x();
-
- if (x1 > x2)
- std::swap(x1, x2);
-
- if (x2 > x1)
- result.append(FloatShapeInterval(x1, x2));
- }
-
- sortAndMergeShapeIntervals(result);
-}
-
-void PolygonShape::getExcludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList& result) const
-{
- const FloatPolygon& polygon = shapeMarginBounds();
- if (polygon.isEmpty())
- return;
-
float y1 = logicalTop;
float y2 = logicalTop + logicalHeight;
- FloatShapeIntervals y1XIntervals, y2XIntervals;
- computeXIntersections(polygon, y1, true, y1XIntervals);
- computeXIntersections(polygon, y2, false, y2XIntervals);
-
- FloatShapeIntervals mergedIntervals;
- FloatShapeInterval::uniteShapeIntervals(y1XIntervals, y2XIntervals, mergedIntervals);
-
- FloatShapeIntervals edgeIntervals;
- computeOverlappingEdgeXProjections(polygon, y1, y2, edgeIntervals);
-
- FloatShapeIntervals excludedIntervals;
- FloatShapeInterval::uniteShapeIntervals(mergedIntervals, edgeIntervals, excludedIntervals);
-
- for (unsigned i = 0; i < excludedIntervals.size(); ++i) {
- FloatShapeInterval interval = excludedIntervals[i];
- result.append(LineSegment(interval.x1(), interval.x2()));
- }
-}
-
-void PolygonShape::getIncludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList& result) const
-{
- const FloatPolygon& polygon = shapePaddingBounds();
- if (polygon.isEmpty())
- return;
-
- float y1 = logicalTop;
- float y2 = logicalTop + logicalHeight;
-
- FloatShapeIntervals y1XIntervals, y2XIntervals;
- computeXIntersections(polygon, y1, true, y1XIntervals);
- computeXIntersections(polygon, y2, false, y2XIntervals);
-
- FloatShapeIntervals commonIntervals;
- FloatShapeInterval::intersectShapeIntervals(y1XIntervals, y2XIntervals, commonIntervals);
-
- FloatShapeIntervals edgeIntervals;
- computeOverlappingEdgeXProjections(polygon, y1, y2, edgeIntervals);
-
- FloatShapeIntervals includedIntervals;
- FloatShapeInterval::subtractShapeIntervals(commonIntervals, edgeIntervals, includedIntervals);
-
- for (unsigned i = 0; i < includedIntervals.size(); ++i) {
- const FloatShapeInterval& interval = includedIntervals[i];
- result.append(LineSegment(interval.x1(), interval.x2()));
- }
-}
-
-static inline bool firstFitRectInPolygon(const FloatPolygon& polygon, const FloatRect& rect, unsigned offsetEdgeIndex1, unsigned offsetEdgeIndex2)
-{
- Vector<const FloatPolygonEdge*> edges;
- if (!polygon.overlappingEdges(rect.y(), rect.maxY(), edges))
- return true;
-
- for (unsigned i = 0; i < edges.size(); ++i) {
- const FloatPolygonEdge* edge = edges[i];
- if (edge->edgeIndex() != offsetEdgeIndex1 && edge->edgeIndex() != offsetEdgeIndex2 && edge->overlapsRect(rect))
- return false;
- }
-
- return true;
-}
-
-static inline bool aboveOrToTheLeft(const FloatRect& r1, const FloatRect& r2)
-{
- if (r1.y() < r2.y())
- return true;
- if (r1.y() == r2.y())
- return r1.x() < r2.x();
- return false;
-}
-
-bool PolygonShape::firstIncludedIntervalLogicalTop(LayoutUnit minLogicalIntervalTop, const FloatSize& minLogicalIntervalSize, LayoutUnit& result) const
-{
- float minIntervalTop = minLogicalIntervalTop;
- float minIntervalHeight = minLogicalIntervalSize.height();
- float minIntervalWidth = minLogicalIntervalSize.width();
-
- const FloatPolygon& polygon = shapePaddingBounds();
- const FloatRect boundingBox = polygon.boundingBox();
- if (minIntervalWidth > boundingBox.width())
- return false;
-
- float minY = std::max(boundingBox.y(), minIntervalTop);
- float maxY = minY + minIntervalHeight;
-
- if (maxY > boundingBox.maxY())
- return false;
-
- Vector<const FloatPolygonEdge*> edges;
- polygon.overlappingEdges(minIntervalTop, boundingBox.maxY(), edges);
-
- float dx = minIntervalWidth / 2;
- float dy = minIntervalHeight / 2;
- Vector<OffsetPolygonEdge> offsetEdges;
-
- for (unsigned i = 0; i < edges.size(); ++i) {
- const FloatPolygonEdge& edge = *(edges[i]);
- const FloatPoint& vertex0 = edge.previousEdge().vertex1();
- const FloatPoint& vertex1 = edge.vertex1();
- const FloatPoint& vertex2 = edge.vertex2();
- Vector<OffsetPolygonEdge> offsetEdgeBuffer;
-
- if (vertex2.y() > vertex1.y() ? vertex2.x() >= vertex1.x() : vertex1.x() >= vertex2.x()) {
- offsetEdgeBuffer.append(OffsetPolygonEdge(edge, FloatSize(dx, -dy)));
- offsetEdgeBuffer.append(OffsetPolygonEdge(edge, FloatSize(-dx, dy)));
- } else {
- offsetEdgeBuffer.append(OffsetPolygonEdge(edge, FloatSize(dx, dy)));
- offsetEdgeBuffer.append(OffsetPolygonEdge(edge, FloatSize(-dx, -dy)));
- }
-
- if (isReflexVertex(vertex0, vertex1, vertex2)) {
- if (vertex2.x() <= vertex1.x() && vertex0.x() <= vertex1.x())
- offsetEdgeBuffer.append(OffsetPolygonEdge(vertex1, FloatSize(dx, -dy), FloatSize(dx, dy)));
- else if (vertex2.x() >= vertex1.x() && vertex0.x() >= vertex1.x())
- offsetEdgeBuffer.append(OffsetPolygonEdge(vertex1, FloatSize(-dx, -dy), FloatSize(-dx, dy)));
- if (vertex2.y() <= vertex1.y() && vertex0.y() <= vertex1.y())
- offsetEdgeBuffer.append(OffsetPolygonEdge(vertex1, FloatSize(-dx, dy), FloatSize(dx, dy)));
- else if (vertex2.y() >= vertex1.y() && vertex0.y() >= vertex1.y())
- offsetEdgeBuffer.append(OffsetPolygonEdge(vertex1, FloatSize(-dx, -dy), FloatSize(dx, -dy)));
+ if (m_polygon.isEmpty() || !m_polygon.boundingBox().overlapsYRange(y1 - shapeMargin(), y2 + shapeMargin()))
+ return LineSegment();
+
+ Vector<const FloatPolygonEdge*> overlappingEdges;
+ if (!m_polygon.overlappingEdges(y1 - shapeMargin(), y2 + shapeMargin(), overlappingEdges))
+ return LineSegment();
+
+ FloatShapeInterval excludedInterval;
+ for (unsigned i = 0; i < overlappingEdges.size(); i++) {
+ const FloatPolygonEdge& edge = *(overlappingEdges[i]);
+ if (edge.maxY() == edge.minY())
+ continue;
+ if (!shapeMargin())
+ excludedInterval.unite(OffsetPolygonEdge(edge, FloatSize()).clippedEdgeXRange(y1, y2));
+ else {
+ excludedInterval.unite(OffsetPolygonEdge(edge, outwardEdgeNormal(edge) * shapeMargin()).clippedEdgeXRange(y1, y2));
+ excludedInterval.unite(OffsetPolygonEdge(edge, inwardEdgeNormal(edge) * shapeMargin()).clippedEdgeXRange(y1, y2));
+ excludedInterval.unite(clippedCircleXRange(edge.vertex1(), shapeMargin(), y1, y2));
+ excludedInterval.unite(clippedCircleXRange(edge.vertex2(), shapeMargin(), y1, y2));
}
-
- for (unsigned j = 0; j < offsetEdgeBuffer.size(); ++j)
- if (offsetEdgeBuffer[j].maxY() >= minY)
- offsetEdges.append(offsetEdgeBuffer[j]);
}
- offsetEdges.append(OffsetPolygonEdge(polygon, minIntervalTop, FloatSize(0, dy)));
-
- FloatPoint offsetEdgesIntersection;
- FloatRect firstFitRect;
- bool firstFitFound = false;
-
- for (unsigned i = 0; i < offsetEdges.size() - 1; ++i) {
- for (unsigned j = i + 1; j < offsetEdges.size(); ++j) {
- if (offsetEdges[i].intersection(offsetEdges[j], offsetEdgesIntersection)) {
- FloatPoint potentialFirstFitLocation(offsetEdgesIntersection.x() - dx, offsetEdgesIntersection.y() - dy);
- FloatRect potentialFirstFitRect(potentialFirstFitLocation, minLogicalIntervalSize);
- if ((offsetEdges[i].basis() == OffsetPolygonEdge::LineTop
- || offsetEdges[j].basis() == OffsetPolygonEdge::LineTop
- || potentialFirstFitLocation.y() >= minIntervalTop)
- && (!firstFitFound || aboveOrToTheLeft(potentialFirstFitRect, firstFitRect))
- && polygon.contains(offsetEdgesIntersection)
- && firstFitRectInPolygon(polygon, potentialFirstFitRect, offsetEdges[i].edgeIndex(), offsetEdges[j].edgeIndex())) {
- firstFitFound = true;
- firstFitRect = potentialFirstFitRect;
- }
- }
- }
- }
+ if (excludedInterval.isEmpty())
+ return LineSegment();
- if (firstFitFound)
- result = ceiledLayoutUnit(firstFitRect.y());
- return firstFitFound;
+ return LineSegment(excludedInterval.x1(), excludedInterval.x2());
}
-static void addPolygon(Path& path, const FloatPolygon& polygon)
+void PolygonShape::buildDisplayPaths(DisplayPaths& paths) const
{
- if (!polygon.numberOfVertices())
+ if (m_polygon.isEmpty())
return;
- path.moveTo(polygon.vertexAt(0));
-
- for (size_t i = 1; i < polygon.numberOfVertices(); i++)
- path.addLineTo(polygon.vertexAt(i));
+ paths.shape.moveTo(m_polygon.vertexAt(0));
+ for (unsigned i = 1; i < m_polygon.numberOfVertices(); i++)
+ paths.shape.addLineTo(m_polygon.vertexAt(i));
- path.closeSubpath();
-}
-
-void PolygonShape::buildDisplayPaths(DisplayPaths& paths) const
-{
- addPolygon(paths.shape, m_polygon);
- if (shapeMargin())
- addPolygon(paths.marginShape, shapeMarginBounds());
+ paths.shape.closeSubpath();
}
} // namespace WebCore
diff --git a/Source/WebCore/rendering/shapes/PolygonShape.h b/Source/WebCore/rendering/shapes/PolygonShape.h
index 09f714083..6d92c83d3 100644
--- a/Source/WebCore/rendering/shapes/PolygonShape.h
+++ b/Source/WebCore/rendering/shapes/PolygonShape.h
@@ -12,7 +12,7 @@
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
@@ -27,86 +27,51 @@
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef PolygonShape_h
-#define PolygonShape_h
+#pragma once
#include "FloatPolygon.h"
#include "Shape.h"
+#include "ShapeInterval.h"
namespace WebCore {
-class OffsetPolygonEdge : public VertexPair {
+class OffsetPolygonEdge final : public VertexPair {
public:
- enum Basis {
- Edge,
- Vertex,
- LineTop
- };
-
OffsetPolygonEdge(const FloatPolygonEdge& edge, const FloatSize& offset)
: m_vertex1(edge.vertex1() + offset)
, m_vertex2(edge.vertex2() + offset)
- , m_edgeIndex(edge.edgeIndex())
- , m_basis(Edge)
{
}
- OffsetPolygonEdge(const FloatPoint& reflexVertex, const FloatSize& offset1, const FloatSize& offset2)
- : m_vertex1(reflexVertex + offset1)
- , m_vertex2(reflexVertex + offset2)
- , m_edgeIndex(-1)
- , m_basis(Vertex)
- {
- }
+ const FloatPoint& vertex1() const override { return m_vertex1; }
+ const FloatPoint& vertex2() const override { return m_vertex2; }
- OffsetPolygonEdge(const FloatPolygon& polygon, float minLogicalIntervalTop, const FloatSize& offset)
- : m_vertex1(FloatPoint(polygon.boundingBox().x(), minLogicalIntervalTop) + offset)
- , m_vertex2(FloatPoint(polygon.boundingBox().maxX(), minLogicalIntervalTop) + offset)
- , m_edgeIndex(-1)
- , m_basis(LineTop)
- {
- }
-
- virtual const FloatPoint& vertex1() const override { return m_vertex1; }
- virtual const FloatPoint& vertex2() const override { return m_vertex2; }
- int edgeIndex() const { return m_edgeIndex; }
- Basis basis() const { return m_basis; }
+ bool isWithinYRange(float y1, float y2) const { return y1 <= minY() && y2 >= maxY(); }
+ bool overlapsYRange(float y1, float y2) const { return y2 >= minY() && y1 <= maxY(); }
+ float xIntercept(float y) const;
+ FloatShapeInterval clippedEdgeXRange(float y1, float y2) const;
private:
FloatPoint m_vertex1;
FloatPoint m_vertex2;
- int m_edgeIndex;
- Basis m_basis;
};
class PolygonShape : public Shape {
WTF_MAKE_NONCOPYABLE(PolygonShape);
public:
- PolygonShape(PassOwnPtr<Vector<FloatPoint>> vertices, WindRule fillRule)
- : m_polygon(vertices, fillRule)
- , m_marginBounds(nullptr)
- , m_paddingBounds(nullptr)
+ PolygonShape(std::unique_ptr<Vector<FloatPoint>> vertices, WindRule fillRule)
+ : m_polygon(WTFMove(vertices), fillRule)
{
}
- virtual LayoutRect shapeMarginLogicalBoundingBox() const override { return static_cast<LayoutRect>(shapeMarginBounds().boundingBox()); }
- virtual LayoutRect shapePaddingLogicalBoundingBox() const override { return static_cast<LayoutRect>(shapePaddingBounds().boundingBox()); }
- virtual bool isEmpty() const override { return m_polygon.isEmpty(); }
- virtual void getExcludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList&) const override;
- virtual void getIncludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList&) const override;
- virtual bool firstIncludedIntervalLogicalTop(LayoutUnit minLogicalIntervalTop, const FloatSize& minLogicalIntervalSize, LayoutUnit&) const override;
+ LayoutRect shapeMarginLogicalBoundingBox() const override;
+ bool isEmpty() const override { return m_polygon.isEmpty(); }
+ LineSegment getExcludedInterval(LayoutUnit logicalTop, LayoutUnit logicalHeight) const override;
- virtual void buildDisplayPaths(DisplayPaths&) const override;
+ void buildDisplayPaths(DisplayPaths&) const override;
private:
- const FloatPolygon& shapeMarginBounds() const;
- const FloatPolygon& shapePaddingBounds() const;
-
FloatPolygon m_polygon;
- mutable OwnPtr<FloatPolygon> m_marginBounds;
- mutable OwnPtr<FloatPolygon> m_paddingBounds;
};
} // namespace WebCore
-
-#endif // PolygonShape_h
diff --git a/Source/WebCore/rendering/shapes/RasterShape.cpp b/Source/WebCore/rendering/shapes/RasterShape.cpp
index e6a30e98d..d8aff98bc 100644
--- a/Source/WebCore/rendering/shapes/RasterShape.cpp
+++ b/Source/WebCore/rendering/shapes/RasterShape.cpp
@@ -12,7 +12,7 @@
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
@@ -73,195 +73,61 @@ IntShapeInterval MarginIntervalGenerator::intervalAt(int y) const
return IntShapeInterval(m_x1 - dx, m_x2 + dx);
}
-void RasterShapeIntervals::appendInterval(int y, int x1, int x2)
-{
- ASSERT(x2 > x1 && (intervalsAt(y).isEmpty() || x1 > intervalsAt(y).last().x2()));
- m_bounds.unite(IntRect(x1, y, x2 - x1, 1));
- intervalsAt(y).append(IntShapeInterval(x1, x2));
-}
-
-void RasterShapeIntervals::uniteMarginInterval(int y, const IntShapeInterval& interval)
-{
- ASSERT(intervalsAt(y).size() <= 1); // Each m_intervalLists entry has 0 or one interval.
-
- if (intervalsAt(y).isEmpty())
- intervalsAt(y).append(interval);
- else {
- IntShapeInterval& resultInterval = intervalsAt(y)[0];
- resultInterval.set(std::min(resultInterval.x1(), interval.x1()), std::max(resultInterval.x2(), interval.x2()));
- }
-
- m_bounds.unite(IntRect(interval.x1(), y, interval.width(), 1));
-}
-
-static inline bool shapeIntervalsContain(const IntShapeIntervals& intervals, const IntShapeInterval& interval)
-{
- for (unsigned i = 0; i < intervals.size(); i++) {
- if (intervals[i].x1() > interval.x2())
- return false;
- if (intervals[i].contains(interval))
- return true;
- }
-
- return false;
-}
-
-bool RasterShapeIntervals::contains(const IntRect& rect) const
-{
- if (!bounds().contains(rect))
- return false;
-
- const IntShapeInterval& rectInterval = IntShapeInterval(rect.x(), rect.maxX());
- for (int y = rect.y(); y < rect.maxY(); y++) {
- if (!shapeIntervalsContain(intervalsAt(y), rectInterval))
- return false;
- }
-
- return true;
-}
-
-static inline void appendX1Values(const IntShapeIntervals& intervals, int minIntervalWidth, Vector<int>& result)
-{
- for (unsigned i = 0; i < intervals.size(); i++)
- if (intervals[i].width() >= minIntervalWidth)
- result.append(intervals[i].x1());
-}
-
-bool RasterShapeIntervals::getIntervalX1Values(int y1, int y2, int minIntervalWidth, Vector<int>& result) const
-{
- ASSERT(y1 >= 0 && y2 > y1);
-
- for (int y = y1; y < y2; y++) {
- if (intervalsAt(y).isEmpty())
- return false;
- }
-
- appendX1Values(intervalsAt(y1), minIntervalWidth, result);
- for (int y = y1 + 1; y < y2; y++) {
- if (intervalsAt(y) != intervalsAt(y - 1))
- appendX1Values(intervalsAt(y), minIntervalWidth, result);
- }
-
- return true;
-}
-
-bool RasterShapeIntervals::firstIncludedIntervalY(int minY, const IntSize& minSize, LayoutUnit& result) const
-{
- minY = std::max<int>(bounds().y(), minY);
-
- ASSERT(minY >= 0 && minY < size());
-
- if (minSize.isEmpty() || minSize.width() > bounds().width())
- return false;
-
- for (int lineY = minY; lineY <= bounds().maxY() - minSize.height(); lineY++) {
- Vector<int> intervalX1Values;
- if (!getIntervalX1Values(lineY, lineY + minSize.height(), minSize.width(), intervalX1Values))
- continue;
-
- std::sort(intervalX1Values.begin(), intervalX1Values.end());
-
- IntRect firstFitRect(IntPoint(0, 0), minSize);
- for (unsigned i = 0; i < intervalX1Values.size(); i++) {
- int lineX = intervalX1Values[i];
- if (i > 0 && lineX == intervalX1Values[i - 1])
- continue;
- firstFitRect.setLocation(IntPoint(lineX, lineY));
- if (contains(firstFitRect)) {
- result = lineY;
- return true;
- }
- }
- }
-
- return false;
-}
-
-void RasterShapeIntervals::getIncludedIntervals(int y1, int y2, IntShapeIntervals& result) const
-{
- ASSERT(y2 >= y1);
-
- if (y1 < bounds().y() || y2 > bounds().maxY())
- return;
-
- for (int y = y1; y < y2; y++) {
- if (intervalsAt(y).isEmpty())
- return;
- }
-
- result = intervalsAt(y1);
- for (int y = y1 + 1; y < y2 && !result.isEmpty(); y++) {
- IntShapeIntervals intervals;
- IntShapeInterval::intersectShapeIntervals(result, intervalsAt(y), intervals);
- result.swap(intervals);
- }
-}
-
-void RasterShapeIntervals::getExcludedIntervals(int y1, int y2, IntShapeIntervals& result) const
-{
- ASSERT(y2 >= y1);
-
- if (y2 < bounds().y() || y1 >= bounds().maxY())
- return;
-
- y1 = std::max(y1, bounds().y());
- y2 = std::min(y2, bounds().maxY());
-
- result = intervalsAt(y1);
- for (int y = y1 + 1; y < y2; y++) {
- IntShapeIntervals intervals;
- IntShapeInterval::uniteShapeIntervals(result, intervalsAt(y), intervals);
- result.swap(intervals);
- }
-}
-
-// Currently limited to computing the margin boundary for shape-outside for floats, see https://bugs.webkit.org/show_bug.cgi?id=116348.
-
-PassOwnPtr<RasterShapeIntervals> RasterShapeIntervals::computeShapeMarginIntervals(unsigned shapeMargin) const
+std::unique_ptr<RasterShapeIntervals> RasterShapeIntervals::computeShapeMarginIntervals(int shapeMargin) const
{
- OwnPtr<RasterShapeIntervals> result = adoptPtr(new RasterShapeIntervals(size(), shapeMargin));
+ int marginIntervalsSize = (offset() > shapeMargin) ? size() : size() - offset() * 2 + shapeMargin * 2;
+ auto result = std::make_unique<RasterShapeIntervals>(marginIntervalsSize, std::max(shapeMargin, offset()));
MarginIntervalGenerator marginIntervalGenerator(shapeMargin);
- int minY = bounds().y();
- int maxY = bounds().maxY();
-
- for (int y = minY; y < maxY; ++y) {
- const IntShapeInterval& intervalAtY = limitIntervalAt(y);
+ for (int y = bounds().y(); y < bounds().maxY(); ++y) {
+ const IntShapeInterval& intervalAtY = intervalAt(y);
if (intervalAtY.isEmpty())
continue;
marginIntervalGenerator.set(y, intervalAtY);
- int marginY0 = y - clampToInteger(shapeMargin);
- int marginY1 = y + clampToInteger(shapeMargin);
+ int marginY0 = std::max(minY(), y - shapeMargin);
+ int marginY1 = std::min(maxY(), y + shapeMargin + 1);
for (int marginY = y - 1; marginY >= marginY0; --marginY) {
- if (marginY > minY && limitIntervalAt(marginY).contains(intervalAtY))
+ if (marginY > bounds().y() && intervalAt(marginY).contains(intervalAtY))
break;
- result->uniteMarginInterval(marginY, marginIntervalGenerator.intervalAt(marginY));
+ result->intervalAt(marginY).unite(marginIntervalGenerator.intervalAt(marginY));
}
- result->uniteMarginInterval(y, marginIntervalGenerator.intervalAt(y));
+ result->intervalAt(y).unite(marginIntervalGenerator.intervalAt(y));
- for (int marginY = y + 1; marginY <= marginY1; ++marginY) {
- if (marginY < maxY && limitIntervalAt(marginY).contains(intervalAtY))
+ for (int marginY = y + 1; marginY < marginY1; ++marginY) {
+ if (marginY < bounds().maxY() && intervalAt(marginY).contains(intervalAtY))
break;
- result->uniteMarginInterval(marginY, marginIntervalGenerator.intervalAt(marginY));
+ result->intervalAt(marginY).unite(marginIntervalGenerator.intervalAt(marginY));
}
}
- return result.release();
+ result->initializeBounds();
+ return result;
+}
+
+void RasterShapeIntervals::initializeBounds()
+{
+ m_bounds = IntRect();
+ for (int y = minY(); y < maxY(); ++y) {
+ const IntShapeInterval& intervalAtY = intervalAt(y);
+ if (intervalAtY.isEmpty())
+ continue;
+ m_bounds.unite(IntRect(intervalAtY.x1(), y, intervalAtY.width(), 1));
+ }
}
void RasterShapeIntervals::buildBoundsPath(Path& path) const
{
for (int y = bounds().y(); y < bounds().maxY(); y++) {
- if (intervalsAt(y).isEmpty())
+ if (intervalAt(y).isEmpty())
continue;
- IntShapeInterval extent = limitIntervalAt(y);
+ IntShapeInterval extent = intervalAt(y);
int endY = y + 1;
for (; endY < bounds().maxY(); endY++) {
- if (intervalsAt(endY).isEmpty() || limitIntervalAt(endY) != extent)
+ if (intervalAt(endY).isEmpty() || intervalAt(endY) != extent)
break;
}
path.addRect(FloatRect(extent.x1(), y, extent.width(), endY - y));
@@ -275,58 +141,38 @@ const RasterShapeIntervals& RasterShape::marginIntervals() const
if (!shapeMargin())
return *m_intervals;
- unsigned marginBoundaryRadius = std::min(clampToUnsigned(ceil(shapeMargin())), std::max<unsigned>(m_imageSize.width(), m_imageSize.height()));
+ int shapeMarginInt = clampToPositiveInteger(ceil(shapeMargin()));
+ int maxShapeMarginInt = std::max(m_marginRectSize.width(), m_marginRectSize.height()) * sqrt(2);
if (!m_marginIntervals)
- m_marginIntervals = m_intervals->computeShapeMarginIntervals(marginBoundaryRadius);
+ m_marginIntervals = m_intervals->computeShapeMarginIntervals(std::min(shapeMarginInt, maxShapeMarginInt));
return *m_marginIntervals;
}
-const RasterShapeIntervals& RasterShape::paddingIntervals() const
-{
- ASSERT(shapePadding() >= 0);
- if (!shapePadding())
- return *m_intervals;
-
- // FIXME: Add support for non-zero padding, see https://bugs.webkit.org/show_bug.cgi?id=116348.
- return *m_intervals;
-}
-
-static inline void appendLineSegments(const IntShapeIntervals& intervals, SegmentList& result)
-{
- for (unsigned i = 0; i < intervals.size(); i++)
- result.append(LineSegment(intervals[i].x1(), intervals[i].x2() + 1));
-}
-
-void RasterShape::getExcludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList& result) const
+LineSegment RasterShape::getExcludedInterval(LayoutUnit logicalTop, LayoutUnit logicalHeight) const
{
const RasterShapeIntervals& intervals = marginIntervals();
if (intervals.isEmpty())
- return;
+ return LineSegment();
- IntShapeIntervals excludedIntervals;
- intervals.getExcludedIntervals(logicalTop, logicalTop + logicalHeight, excludedIntervals);
- appendLineSegments(excludedIntervals, result);
-}
+ int y1 = logicalTop;
+ int y2 = logicalTop + logicalHeight;
+ ASSERT(y2 >= y1);
+ if (y2 < intervals.bounds().y() || y1 >= intervals.bounds().maxY())
+ return LineSegment();
-void RasterShape::getIncludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList& result) const
-{
- const RasterShapeIntervals& intervals = paddingIntervals();
- if (intervals.isEmpty())
- return;
+ y1 = std::max(y1, intervals.bounds().y());
+ y2 = std::min(y2, intervals.bounds().maxY());
+ IntShapeInterval excludedInterval;
- IntShapeIntervals includedIntervals;
- intervals.getIncludedIntervals(logicalTop, logicalTop + logicalHeight, includedIntervals);
- appendLineSegments(includedIntervals, result);
-}
-
-bool RasterShape::firstIncludedIntervalLogicalTop(LayoutUnit minLogicalIntervalTop, const FloatSize& minLogicalIntervalSize, LayoutUnit& result) const
-{
- const RasterShapeIntervals& intervals = paddingIntervals();
- if (intervals.isEmpty())
- return false;
+ if (y1 == y2)
+ excludedInterval = intervals.intervalAt(y1);
+ else {
+ for (int y = y1; y < y2; y++)
+ excludedInterval.unite(intervals.intervalAt(y));
+ }
- return intervals.firstIncludedIntervalY(minLogicalIntervalTop.floor(), flooredIntSize(minLogicalIntervalSize), result);
+ return LineSegment(excludedInterval.x1(), excludedInterval.x2());
}
} // namespace WebCore
diff --git a/Source/WebCore/rendering/shapes/RasterShape.h b/Source/WebCore/rendering/shapes/RasterShape.h
index c04ef15ff..23ddaf4ff 100644
--- a/Source/WebCore/rendering/shapes/RasterShape.h
+++ b/Source/WebCore/rendering/shapes/RasterShape.h
@@ -12,7 +12,7 @@
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
@@ -27,8 +27,7 @@
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef RasterShape_h
-#define RasterShape_h
+#pragma once
#include "FloatRect.h"
#include "Shape.h"
@@ -39,70 +38,59 @@
namespace WebCore {
class RasterShapeIntervals {
+ WTF_MAKE_FAST_ALLOCATED;
public:
- RasterShapeIntervals(unsigned size, unsigned shapeMargin = 0)
- : m_shapeMargin(shapeMargin)
+ RasterShapeIntervals(unsigned size, int offset = 0)
+ : m_offset(offset)
{
- m_intervalLists.resize(size + shapeMargin * 2);
+ m_intervals.resize(clampTo<int>(size));
}
+ void initializeBounds();
const IntRect& bounds() const { return m_bounds; }
bool isEmpty() const { return m_bounds.isEmpty(); }
- void appendInterval(int y, int x1, int x2);
-
- void getIncludedIntervals(int y1, int y2, IntShapeIntervals& result) const;
- void getExcludedIntervals(int y1, int y2, IntShapeIntervals& result) const;
- bool firstIncludedIntervalY(int minY, const IntSize& minSize, LayoutUnit& result) const;
- PassOwnPtr<RasterShapeIntervals> computeShapeMarginIntervals(unsigned shapeMargin) const;
-
- void buildBoundsPath(Path&) const;
-
-private:
- int size() const { return m_intervalLists.size(); }
- IntShapeIntervals& intervalsAt(int y)
+ IntShapeInterval& intervalAt(int y)
{
- ASSERT(static_cast<int>(y + m_shapeMargin) >= 0 && y + m_shapeMargin < m_intervalLists.size());
- return m_intervalLists[y + m_shapeMargin];
+ ASSERT(y + m_offset >= 0 && static_cast<unsigned>(y + m_offset) < m_intervals.size());
+ return m_intervals[y + m_offset];
}
- const IntShapeIntervals& intervalsAt(int y) const
+ const IntShapeInterval& intervalAt(int y) const
{
- ASSERT(static_cast<int>(y + m_shapeMargin) >= 0 && y + m_shapeMargin < m_intervalLists.size());
- return m_intervalLists[y + m_shapeMargin];
+ ASSERT(y + m_offset >= 0 && static_cast<unsigned>(y + m_offset) < m_intervals.size());
+ return m_intervals[y + m_offset];
}
- IntShapeInterval limitIntervalAt(int y) const
- {
- const IntShapeIntervals& intervals = intervalsAt(y);
- return intervals.size() ? IntShapeInterval(intervals[0].x1(), intervals.last().x2()) : IntShapeInterval();
- }
+ std::unique_ptr<RasterShapeIntervals> computeShapeMarginIntervals(int shapeMargin) const;
+ void buildBoundsPath(Path&) const;
+
+private:
+ int size() const { return m_intervals.size(); }
+ int offset() const { return m_offset; }
+ int minY() const { return -m_offset; }
+ int maxY() const { return -m_offset + m_intervals.size(); }
- bool contains(const IntRect&) const;
- bool getIntervalX1Values(int minY, int maxY, int minIntervalWidth, Vector<int>& result) const;
- void uniteMarginInterval(int y, const IntShapeInterval&);
IntRect m_bounds;
- Vector<IntShapeIntervals> m_intervalLists;
- unsigned m_shapeMargin;
+ Vector<IntShapeInterval> m_intervals;
+ int m_offset;
};
-class RasterShape : public Shape {
+class RasterShape final : public Shape {
WTF_MAKE_NONCOPYABLE(RasterShape);
public:
- RasterShape(PassOwnPtr<RasterShapeIntervals> intervals, const IntSize& imageSize)
- : m_intervals(intervals)
- , m_imageSize(imageSize)
+ RasterShape(std::unique_ptr<RasterShapeIntervals> intervals, const IntSize& marginRectSize)
+ : m_intervals(WTFMove(intervals))
+ , m_marginRectSize(marginRectSize)
{
+ m_intervals->initializeBounds();
}
- virtual LayoutRect shapeMarginLogicalBoundingBox() const override { return static_cast<LayoutRect>(marginIntervals().bounds()); }
- virtual LayoutRect shapePaddingLogicalBoundingBox() const override { return static_cast<LayoutRect>(paddingIntervals().bounds()); }
- virtual bool isEmpty() const override { return m_intervals->isEmpty(); }
- virtual void getExcludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList&) const override;
- virtual void getIncludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList&) const override;
- virtual bool firstIncludedIntervalLogicalTop(LayoutUnit minLogicalIntervalTop, const FloatSize& minLogicalIntervalSize, LayoutUnit&) const override;
+ LayoutRect shapeMarginLogicalBoundingBox() const override { return static_cast<LayoutRect>(marginIntervals().bounds()); }
+ bool isEmpty() const override { return m_intervals->isEmpty(); }
+ LineSegment getExcludedInterval(LayoutUnit logicalTop, LayoutUnit logicalHeight) const override;
- virtual void buildDisplayPaths(DisplayPaths& paths) const override
+ void buildDisplayPaths(DisplayPaths& paths) const override
{
m_intervals->buildBoundsPath(paths.shape);
if (shapeMargin())
@@ -111,13 +99,10 @@ public:
private:
const RasterShapeIntervals& marginIntervals() const;
- const RasterShapeIntervals& paddingIntervals() const;
- OwnPtr<RasterShapeIntervals> m_intervals;
- mutable OwnPtr<RasterShapeIntervals> m_marginIntervals;
- IntSize m_imageSize;
+ std::unique_ptr<RasterShapeIntervals> m_intervals;
+ mutable std::unique_ptr<RasterShapeIntervals> m_marginIntervals;
+ IntSize m_marginRectSize;
};
} // namespace WebCore
-
-#endif // RasterShape_h
diff --git a/Source/WebCore/rendering/shapes/RectangleShape.cpp b/Source/WebCore/rendering/shapes/RectangleShape.cpp
index 83768cc43..f3619d6a5 100644
--- a/Source/WebCore/rendering/shapes/RectangleShape.cpp
+++ b/Source/WebCore/rendering/shapes/RectangleShape.cpp
@@ -12,7 +12,7 @@
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
@@ -40,26 +40,6 @@ static inline float ellipseXIntercept(float y, float rx, float ry)
return rx * sqrt(1 - (y * y) / (ry * ry));
}
-static inline float ellipseYIntercept(float x, float rx, float ry)
-{
- ASSERT(rx > 0);
- return ry * sqrt(1 - (x * x) / (rx * rx));
-}
-
-FloatRect RectangleShape::shapePaddingBounds() const
-{
- ASSERT(shapePadding() >= 0);
- if (!shapePadding() || isEmpty())
- return m_bounds;
-
- float boundsX = x() + std::min(width() / 2, shapePadding());
- float boundsY = y() + std::min(height() / 2, shapePadding());
- float boundsWidth = std::max(0.0f, width() - shapePadding() * 2);
- float boundsHeight = std::max(0.0f, height() - shapePadding() * 2);
-
- return FloatRect(boundsX, boundsY, boundsWidth, boundsHeight);
-}
-
FloatRect RectangleShape::shapeMarginBounds() const
{
ASSERT(shapeMargin() >= 0);
@@ -73,17 +53,17 @@ FloatRect RectangleShape::shapeMarginBounds() const
return FloatRect(boundsX, boundsY, boundsWidth, boundsHeight);
}
-void RectangleShape::getExcludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList& result) const
+LineSegment RectangleShape::getExcludedInterval(LayoutUnit logicalTop, LayoutUnit logicalHeight) const
{
const FloatRect& bounds = shapeMarginBounds();
if (bounds.isEmpty())
- return;
+ return LineSegment();
float y1 = logicalTop;
float y2 = logicalTop + logicalHeight;
if (y2 < bounds.y() || y1 >= bounds.maxY())
- return;
+ return LineSegment();
float x1 = bounds.x();
float x2 = bounds.maxX();
@@ -105,115 +85,7 @@ void RectangleShape::getExcludedIntervals(LayoutUnit logicalTop, LayoutUnit logi
}
}
- result.append(LineSegment(x1, x2));
-}
-
-void RectangleShape::getIncludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList& result) const
-{
- const FloatRect& bounds = shapePaddingBounds();
- if (bounds.isEmpty())
- return;
-
- float y1 = logicalTop;
- float y2 = logicalTop + logicalHeight;
-
- if (y1 < bounds.y() || y2 > bounds.maxY())
- return;
-
- float x1 = bounds.x();
- float x2 = bounds.maxX();
-
- float paddingRadiusX = std::max(0.0f, rx() - shapePadding());
- float paddingRadiusY = std::max(0.0f, ry() - shapePadding());
-
- if (paddingRadiusX > 0) {
- bool y1InterceptsCorner = y1 < bounds.y() + paddingRadiusY;
- bool y2InterceptsCorner = y2 > bounds.maxY() - paddingRadiusY;
- float xi = 0;
-
- if (y1InterceptsCorner && y2InterceptsCorner) {
- if (y1 < bounds.height() + 2 * bounds.y() - y2) {
- float yi = y1 - bounds.y() - paddingRadiusY;
- xi = ellipseXIntercept(yi, paddingRadiusX, paddingRadiusY);
- } else {
- float yi = y2 - (bounds.maxY() - paddingRadiusY);
- xi = ellipseXIntercept(yi, paddingRadiusX, paddingRadiusY);
- }
- } else if (y1InterceptsCorner) {
- float yi = y1 - bounds.y() - paddingRadiusY;
- xi = ellipseXIntercept(yi, paddingRadiusX, paddingRadiusY);
- } else if (y2InterceptsCorner) {
- float yi = y2 - (bounds.maxY() - paddingRadiusY);
- xi = ellipseXIntercept(yi, paddingRadiusX, paddingRadiusY);
- }
-
- if (y1InterceptsCorner || y2InterceptsCorner) {
- x1 = bounds.x() + paddingRadiusX - xi;
- x2 = bounds.maxX() - paddingRadiusX + xi;
- }
- }
-
- result.append(LineSegment(x1, x2));
-}
-
-static FloatPoint cornerInterceptForWidth(float width, float widthAtIntercept, float rx, float ry)
-{
- float xi = (width - widthAtIntercept) / 2;
- float yi = ry - ellipseYIntercept(rx - xi, rx, ry);
- return FloatPoint(xi, yi);
-}
-
-bool RectangleShape::firstIncludedIntervalLogicalTop(LayoutUnit minLogicalIntervalTop, const FloatSize& minLogicalIntervalSize, LayoutUnit& result) const
-{
- float minIntervalTop = minLogicalIntervalTop;
- float minIntervalHeight = minLogicalIntervalSize.height();
- float minIntervalWidth = minLogicalIntervalSize.width();
-
- const FloatRect& bounds = shapePaddingBounds();
- if (bounds.isEmpty() || minIntervalWidth > bounds.width())
- return false;
-
- float minY = std::max(bounds.y(), minIntervalTop);
- float maxY = minY + minIntervalHeight;
-
- if (maxY > bounds.maxY())
- return false;
-
- float paddingRadiusX = std::max(0.0f, rx() - shapePadding());
- float paddingRadiusY = std::max(0.0f, ry() - shapePadding());
-
- bool intervalOverlapsMinCorner = minY < bounds.y() + paddingRadiusY;
- bool intervalOverlapsMaxCorner = maxY > bounds.maxY() - paddingRadiusY;
-
- if (!intervalOverlapsMinCorner && !intervalOverlapsMaxCorner) {
- result = ceiledLayoutUnit(minY);
- return true;
- }
-
- float centerY = bounds.y() + bounds.height() / 2;
- bool minCornerDefinesX = fabs(centerY - minY) > fabs(centerY - maxY);
- bool intervalFitsWithinCorners = minIntervalWidth + 2 * paddingRadiusX <= bounds.width();
- FloatPoint cornerIntercept = cornerInterceptForWidth(bounds.width(), minIntervalWidth, paddingRadiusX, paddingRadiusY);
-
- if (intervalOverlapsMinCorner && (!intervalOverlapsMaxCorner || minCornerDefinesX)) {
- if (intervalFitsWithinCorners || bounds.y() + cornerIntercept.y() < minY) {
- result = ceiledLayoutUnit(minY);
- return true;
- }
- if (minIntervalHeight < bounds.height() - (2 * cornerIntercept.y())) {
- result = ceiledLayoutUnit(bounds.y() + cornerIntercept.y());
- return true;
- }
- }
-
- if (intervalOverlapsMaxCorner && (!intervalOverlapsMinCorner || !minCornerDefinesX)) {
- if (intervalFitsWithinCorners || minY <= bounds.maxY() - cornerIntercept.y() - minIntervalHeight) {
- result = ceiledLayoutUnit(minY);
- return true;
- }
- }
-
- return false;
+ return LineSegment(x1, x2);
}
void RectangleShape::buildDisplayPaths(DisplayPaths& paths) const
diff --git a/Source/WebCore/rendering/shapes/RectangleShape.h b/Source/WebCore/rendering/shapes/RectangleShape.h
index 7fde5eeef..494806006 100644
--- a/Source/WebCore/rendering/shapes/RectangleShape.h
+++ b/Source/WebCore/rendering/shapes/RectangleShape.h
@@ -12,7 +12,7 @@
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
@@ -27,19 +27,17 @@
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef RectangleShape_h
-#define RectangleShape_h
+#pragma once
#include "FloatPoint.h"
#include "FloatRect.h"
#include "FloatSize.h"
#include "Shape.h"
#include <wtf/Assertions.h>
-#include <wtf/Vector.h>
namespace WebCore {
-class RectangleShape : public Shape {
+class RectangleShape final : public Shape {
public:
RectangleShape(const FloatRect& bounds, const FloatSize& radii)
: m_bounds(bounds)
@@ -47,18 +45,14 @@ public:
{
}
- virtual LayoutRect shapeMarginLogicalBoundingBox() const override { return static_cast<LayoutRect>(shapeMarginBounds()); }
- virtual LayoutRect shapePaddingLogicalBoundingBox() const override { return static_cast<LayoutRect>(shapePaddingBounds()); }
- virtual bool isEmpty() const override { return m_bounds.isEmpty(); }
- virtual void getExcludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList&) const override;
- virtual void getIncludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList&) const override;
- virtual bool firstIncludedIntervalLogicalTop(LayoutUnit minLogicalIntervalTop, const FloatSize& minLogicalIntervalSize, LayoutUnit&) const override;
+ LayoutRect shapeMarginLogicalBoundingBox() const override { return static_cast<LayoutRect>(shapeMarginBounds()); }
+ bool isEmpty() const override { return m_bounds.isEmpty(); }
+ LineSegment getExcludedInterval(LayoutUnit logicalTop, LayoutUnit logicalHeight) const override;
- virtual void buildDisplayPaths(DisplayPaths&) const override;
+ void buildDisplayPaths(DisplayPaths&) const override;
private:
FloatRect shapeMarginBounds() const;
- FloatRect shapePaddingBounds() const;
float rx() const { return m_radii.width(); }
float ry() const { return m_radii.height(); }
@@ -72,5 +66,3 @@ private:
};
} // namespace WebCore
-
-#endif // RectangleShape_h
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
diff --git a/Source/WebCore/rendering/shapes/Shape.h b/Source/WebCore/rendering/shapes/Shape.h
index ab71d5568..f810ff5ee 100644
--- a/Source/WebCore/rendering/shapes/Shape.h
+++ b/Source/WebCore/rendering/shapes/Shape.h
@@ -12,7 +12,7 @@
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
@@ -27,33 +27,37 @@
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef Shape_h
-#define Shape_h
+#pragma once
-#include "BasicShapes.h"
#include "LayoutRect.h"
#include "Path.h"
-#include "RoundedRect.h"
-#include "StyleImage.h"
#include "WritingMode.h"
-#include <wtf/PassOwnPtr.h>
-#include <wtf/Vector.h>
namespace WebCore {
struct LineSegment {
+ LineSegment()
+ : logicalLeft(0)
+ , logicalRight(0)
+ , isValid(false)
+ {
+ }
+
LineSegment(float logicalLeft, float logicalRight)
: logicalLeft(logicalLeft)
, logicalRight(logicalRight)
+ , isValid(true)
{
}
- LayoutUnit logicalLeft;
- LayoutUnit logicalRight;
+ float logicalLeft;
+ float logicalRight;
+ bool isValid;
};
-typedef Vector<LineSegment> SegmentList;
-
+class BasicShape;
+class Image;
+class RoundedRect;
// A representation of a BasicShape that enables layout code to determine how to break a line up into segments
// that will fit within or around a shape. The line is defined by a pair of logical Y coordinates and the
@@ -61,32 +65,29 @@ typedef Vector<LineSegment> SegmentList;
// physical coordinates.
class Shape {
+ WTF_MAKE_FAST_ALLOCATED;
public:
struct DisplayPaths {
Path shape;
Path marginShape;
};
- static PassOwnPtr<Shape> createShape(const BasicShape*, const LayoutSize& logicalBoxSize, WritingMode, Length margin, Length padding);
- static PassOwnPtr<Shape> createRasterShape(const StyleImage&, float threshold, const LayoutRect& imageRect, const LayoutSize& logicalBoxSize, WritingMode, Length margin, Length padding);
- static PassOwnPtr<Shape> createLayoutBoxShape(const RoundedRect&, WritingMode, Length margin, Length padding);
+ static std::unique_ptr<Shape> createShape(const BasicShape&, const LayoutSize& logicalBoxSize, WritingMode, float margin);
+ static std::unique_ptr<Shape> createRasterShape(Image*, float threshold, const LayoutRect& imageRect, const LayoutRect& marginRect, WritingMode, float margin);
+ static std::unique_ptr<Shape> createBoxShape(const RoundedRect&, WritingMode, float margin);
virtual ~Shape() { }
virtual LayoutRect shapeMarginLogicalBoundingBox() const = 0;
- virtual LayoutRect shapePaddingLogicalBoundingBox() const = 0;
virtual bool isEmpty() const = 0;
- virtual void getIncludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList&) const = 0;
- virtual void getExcludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList&) const = 0;
- virtual bool firstIncludedIntervalLogicalTop(LayoutUnit minLogicalIntervalTop, const FloatSize& minLogicalIntervalSize, LayoutUnit& result) const = 0;
+ virtual LineSegment getExcludedInterval(LayoutUnit logicalTop, LayoutUnit logicalHeight) const = 0;
+
bool lineOverlapsShapeMarginBounds(LayoutUnit lineTop, LayoutUnit lineHeight) const { return lineOverlapsBoundingBox(lineTop, lineHeight, shapeMarginLogicalBoundingBox()); }
- bool lineOverlapsShapePaddingBounds(LayoutUnit lineTop, LayoutUnit lineHeight) const { return lineOverlapsBoundingBox(lineTop, lineHeight, shapePaddingLogicalBoundingBox()); }
virtual void buildDisplayPaths(DisplayPaths&) const = 0;
protected:
float shapeMargin() const { return m_margin; }
- float shapePadding() const { return m_padding; }
private:
bool lineOverlapsBoundingBox(LayoutUnit lineTop, LayoutUnit lineHeight, const LayoutRect& rect) const
@@ -98,9 +99,6 @@ private:
WritingMode m_writingMode;
float m_margin;
- float m_padding;
};
} // namespace WebCore
-
-#endif // Shape_h
diff --git a/Source/WebCore/rendering/shapes/ShapeInfo.cpp b/Source/WebCore/rendering/shapes/ShapeInfo.cpp
deleted file mode 100644
index 5e2af92ad..000000000
--- a/Source/WebCore/rendering/shapes/ShapeInfo.cpp
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
- * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
- * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "ShapeInfo.h"
-
-#if ENABLE(CSS_SHAPES)
-
-#include "LengthFunctions.h"
-#include "RenderBlock.h"
-#include "RenderBox.h"
-#include "RenderImage.h"
-#include "RenderRegion.h"
-#include "RenderStyle.h"
-#include "Shape.h"
-
-namespace WebCore {
-
-
-bool checkShapeImageOrigin(Document& document, CachedImage& cachedImage)
-{
- if (cachedImage.isOriginClean(document.securityOrigin()))
- return true;
-
- const URL& url = cachedImage.url();
- String urlString = url.isNull() ? "''" : url.stringCenterEllipsizedToLength();
- document.addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, "Unsafe attempt to load URL " + urlString + ".");
-
- return false;
-}
-
-static LayoutRect getShapeImageRect(const StyleImage& styleImage, const RenderBox& renderBox)
-{
- if (renderBox.isRenderImage()) {
- const RenderImage& renderImage = *toRenderImage(&renderBox);
- return renderImage.replacedContentRect(renderBox.intrinsicSize());
- }
-
- ASSERT(styleImage.cachedImage());
- ASSERT(styleImage.cachedImage()->hasImage());
- return LayoutRect(LayoutPoint(), styleImage.cachedImage()->image()->size());
-}
-
-template<class RenderType>
-const Shape& ShapeInfo<RenderType>::computedShape() const
-{
- if (Shape* shape = m_shape.get())
- return *shape;
-
- WritingMode writingMode = this->writingMode();
- Length margin = m_renderer.style().shapeMargin();
- Length padding = m_renderer.style().shapePadding();
- float shapeImageThreshold = m_renderer.style().shapeImageThreshold();
- const ShapeValue* shapeValue = this->shapeValue();
- ASSERT(shapeValue);
-
- switch (shapeValue->type()) {
- case ShapeValue::Shape:
- ASSERT(shapeValue->shape());
- m_shape = Shape::createShape(shapeValue->shape(), m_shapeLogicalSize, writingMode, margin, padding);
- break;
- case ShapeValue::Image: {
- ASSERT(shapeValue->image());
- const StyleImage& styleImage = *(shapeValue->image());
- m_shape = Shape::createRasterShape(styleImage, shapeImageThreshold, getShapeImageRect(styleImage, m_renderer), m_shapeLogicalSize, writingMode, margin, padding);
- break;
- }
- case ShapeValue::Box: {
- const RoundedRect& shapeRect = m_renderer.style().getRoundedBorderFor(LayoutRect(LayoutPoint(), m_shapeLogicalSize), &(m_renderer.view()));
- m_shape = Shape::createLayoutBoxShape(shapeRect, writingMode, margin, padding);
- break;
- }
- case ShapeValue::Outside:
- // Outside should have already resolved to a different shape value
- ASSERT_NOT_REACHED();
- }
-
- ASSERT(m_shape);
- return *m_shape;
-}
-
-template<class RenderType>
-SegmentList ShapeInfo<RenderType>::computeSegmentsForLine(LayoutUnit lineTop, LayoutUnit lineHeight) const
-{
- ASSERT(lineHeight >= 0);
- SegmentList segments;
-
- getIntervals((lineTop - logicalTopOffset()), std::min(lineHeight, shapeLogicalBottom() - lineTop), segments);
-
- for (size_t i = 0; i < segments.size(); i++) {
- segments[i].logicalLeft += logicalLeftOffset();
- segments[i].logicalRight += logicalLeftOffset();
- }
-
- return segments;
-}
-
-template class ShapeInfo<RenderBlock>;
-template class ShapeInfo<RenderBox>;
-
-}
-#endif
diff --git a/Source/WebCore/rendering/shapes/ShapeInfo.h b/Source/WebCore/rendering/shapes/ShapeInfo.h
deleted file mode 100644
index f571f242e..000000000
--- a/Source/WebCore/rendering/shapes/ShapeInfo.h
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
-* Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved.
-*
-* Redistribution and use in source and binary forms, with or without
-* modification, are permitted provided that the following conditions
-* are met:
-*
-* 1. Redistributions of source code must retain the above
-* copyright notice, this list of conditions and the following
-* disclaimer.
-* 2. Redistributions in binary form must reproduce the above
-* copyright notice, this list of conditions and the following
-* disclaimer in the documentation and/or other materials
-* provided with the distribution.
-*
-* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY
-* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
-* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
-* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
-* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
-* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-* SUCH DAMAGE.
-*/
-
-#ifndef ShapeInfo_h
-#define ShapeInfo_h
-
-#if ENABLE(CSS_SHAPES)
-
-#include "FloatRect.h"
-#include "LayoutUnit.h"
-#include "RenderStyle.h"
-#include "Shape.h"
-#include "ShapeValue.h"
-#include <wtf/OwnPtr.h>
-#include <wtf/Vector.h>
-
-namespace WebCore {
-
-template<class KeyType, class InfoType>
-class MappedInfo {
-public:
- static InfoType& ensureInfo(const KeyType& key)
- {
- InfoMap& infoMap = MappedInfo<KeyType, InfoType>::infoMap();
- if (InfoType* info = infoMap.get(&key))
- return *info;
- typename InfoMap::AddResult result = infoMap.add(&key, std::make_unique<InfoType>(key));
- return *result.iterator->value;
- }
- static void removeInfo(const KeyType& key) { infoMap().remove(&key); }
- static InfoType* info(const KeyType& key) { return infoMap().get(&key); }
-
-private:
- typedef HashMap<const KeyType*, std::unique_ptr<InfoType>> InfoMap;
- static InfoMap& infoMap()
- {
- DEFINE_STATIC_LOCAL(InfoMap, staticInfoMap, ());
- return staticInfoMap;
- }
-};
-
-template<class RenderType>
-class ShapeInfo {
- WTF_MAKE_FAST_ALLOCATED;
-public:
- virtual ~ShapeInfo() { }
-
- void setShapeSize(LayoutUnit logicalWidth, LayoutUnit logicalHeight)
- {
- LayoutBox box = resolvedLayoutBox();
- switch (box) {
- case MarginBox:
- logicalHeight += m_renderer.marginLogicalHeight();
- logicalWidth += m_renderer.marginLogicalWidth();
- break;
- case BorderBox:
- break;
- case PaddingBox:
- logicalHeight -= m_renderer.borderLogicalHeight();
- logicalWidth -= m_renderer.borderLogicalWidth();
- break;
- case ContentBox:
- logicalHeight -= m_renderer.borderAndPaddingLogicalHeight();
- logicalWidth -= m_renderer.borderAndPaddingLogicalWidth();
- break;
- case BoundingBox:
- case BoxMissing:
- ASSERT_NOT_REACHED();
- break;
- }
-
- LayoutSize newLogicalSize(logicalWidth, logicalHeight);
- if (m_shapeLogicalSize == newLogicalSize)
- return;
- dirtyShapeSize();
- m_shapeLogicalSize = newLogicalSize;
- }
-
- SegmentList computeSegmentsForLine(LayoutUnit lineTop, LayoutUnit lineHeight) const;
-
- LayoutUnit shapeLogicalTop() const { return computedShapeLogicalBoundingBox().y() + logicalTopOffset(); }
- LayoutUnit shapeLogicalBottom() const { return computedShapeLogicalBoundingBox().maxY() + logicalTopOffset(); }
- LayoutUnit shapeLogicalLeft() const { return computedShapeLogicalBoundingBox().x() + logicalLeftOffset(); }
- LayoutUnit shapeLogicalRight() const { return computedShapeLogicalBoundingBox().maxX() + logicalLeftOffset(); }
- LayoutUnit shapeLogicalWidth() const { return computedShapeLogicalBoundingBox().width(); }
- LayoutUnit shapeLogicalHeight() const { return computedShapeLogicalBoundingBox().height(); }
-
- LayoutUnit logicalLineTop() const { return m_shapeLineTop + logicalTopOffset(); }
- LayoutUnit logicalLineBottom() const { return m_shapeLineTop + m_lineHeight + logicalTopOffset(); }
- LayoutUnit logicalLineBottom(LayoutUnit lineHeight) const { return m_shapeLineTop + lineHeight + logicalTopOffset(); }
-
- LayoutUnit shapeContainingBlockLogicalHeight() const { return (m_renderer.style().boxSizing() == CONTENT_BOX) ? (m_shapeLogicalSize.height() + m_renderer.borderAndPaddingLogicalHeight()) : m_shapeLogicalSize.height(); }
-
- virtual bool lineOverlapsShapeBounds() const = 0;
-
- void dirtyShapeSize() { m_shape.clear(); }
- bool shapeSizeDirty() { return !m_shape.get(); }
- const RenderType& owner() const { return m_renderer; }
- LayoutSize shapeSize() const { return m_shapeLogicalSize; }
-
- LayoutRect computedShapePhysicalBoundingBox() const
- {
- LayoutRect physicalBoundingBox = computedShapeLogicalBoundingBox();
- physicalBoundingBox.setX(physicalBoundingBox.x() + logicalLeftOffset());
- physicalBoundingBox.setY(physicalBoundingBox.y() + logicalTopOffset());
- if (m_renderer.style().isFlippedBlocksWritingMode())
- physicalBoundingBox.setY(m_renderer.logicalHeight() - physicalBoundingBox.maxY());
- if (!m_renderer.style().isHorizontalWritingMode())
- physicalBoundingBox = physicalBoundingBox.transposedRect();
- return physicalBoundingBox;
- }
-
- FloatPoint shapeToRendererPoint(FloatPoint point) const
- {
- FloatPoint result = FloatPoint(point.x() + logicalLeftOffset(), point.y() + logicalTopOffset());
- if (m_renderer.style().isFlippedBlocksWritingMode())
- result.setY(m_renderer.logicalHeight() - result.y());
- if (!m_renderer.style().isHorizontalWritingMode())
- result = result.transposedPoint();
- return result;
- }
-
- FloatSize shapeToRendererSize(FloatSize size) const
- {
- if (!m_renderer.style().isHorizontalWritingMode())
- return size.transposedSize();
- return size;
- }
-
- const Shape& computedShape() const;
-
-protected:
- explicit ShapeInfo(const RenderType& renderer)
- : m_renderer(renderer)
- {
- }
-
- virtual LayoutBox resolvedLayoutBox() const = 0;
- virtual LayoutRect computedShapeLogicalBoundingBox() const = 0;
- virtual ShapeValue* shapeValue() const = 0;
- virtual void getIntervals(LayoutUnit, LayoutUnit, SegmentList&) const = 0;
-
- virtual WritingMode writingMode() const { return m_renderer.style().writingMode(); }
-
- LayoutUnit logicalTopOffset() const
- {
- LayoutBox box = resolvedLayoutBox();
- switch (box) {
- case MarginBox: return -m_renderer.marginBefore();
- case BorderBox: return LayoutUnit();
- case PaddingBox: return m_renderer.borderBefore();
- case ContentBox: return m_renderer.borderAndPaddingBefore();
- case BoundingBox: break;
- case BoxMissing: break;
- }
- ASSERT_NOT_REACHED();
- return LayoutUnit();
- }
-
- LayoutUnit logicalLeftOffset() const
- {
- if (m_renderer.isRenderRegion())
- return LayoutUnit();
- LayoutBox box = resolvedLayoutBox();
- switch (box) {
- case MarginBox: return -m_renderer.marginStart();
- case BorderBox: return LayoutUnit();
- case PaddingBox: return m_renderer.borderStart();
- case ContentBox: return m_renderer.borderAndPaddingStart();
- case BoundingBox: break;
- case BoxMissing: break;
- }
- ASSERT_NOT_REACHED();
- return LayoutUnit();
- }
-
- LayoutUnit m_shapeLineTop;
- LayoutUnit m_lineHeight;
-
- const RenderType& m_renderer;
-
-private:
- mutable OwnPtr<Shape> m_shape;
- LayoutSize m_shapeLogicalSize;
-};
-
-bool checkShapeImageOrigin(Document&, CachedImage&);
-
-}
-#endif
-#endif
diff --git a/Source/WebCore/rendering/shapes/ShapeInsideInfo.cpp b/Source/WebCore/rendering/shapes/ShapeInsideInfo.cpp
deleted file mode 100644
index ff7e22bd9..000000000
--- a/Source/WebCore/rendering/shapes/ShapeInsideInfo.cpp
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
- * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
- * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "ShapeInsideInfo.h"
-
-#if ENABLE(CSS_SHAPES)
-
-#include "InlineIterator.h"
-#include "RenderBlock.h"
-
-namespace WebCore {
-
-LineSegmentRange::LineSegmentRange(const InlineIterator& start, const InlineIterator& end)
- : start(start.root(), start.renderer(), start.offset())
- , end(end.root(), end.renderer(), end.offset())
- {
- }
-
-bool ShapeInsideInfo::isEnabledFor(const RenderBlock& renderer)
-{
- ShapeValue* shapeValue = renderer.style().resolvedShapeInside();
- if (!shapeValue)
- return false;
-
- switch (shapeValue->type()) {
- case ShapeValue::Shape:
- return shapeValue->shape() && shapeValue->shape()->type() != BasicShape::BasicShapeInsetRectangleType && shapeValue->shape()->type() != BasicShape::BasicShapeInsetType;
- case ShapeValue::Image:
- return shapeValue->isImageValid() && checkShapeImageOrigin(renderer.document(), *(shapeValue->image()->cachedImage()));
- case ShapeValue::Box:
- return true;
- case ShapeValue::Outside:
- // Outside value must already be resolved
- break;
- }
- ASSERT_NOT_REACHED();
- return false;
-}
-
-bool ShapeInsideInfo::updateSegmentsForLine(LayoutSize lineOffset, LayoutUnit lineHeight)
-{
- m_segmentRanges.clear();
- bool result = updateSegmentsForLine(lineOffset.height(), lineHeight);
- for (size_t i = 0; i < m_segments.size(); i++) {
- m_segments[i].logicalLeft -= lineOffset.width();
- m_segments[i].logicalRight -= lineOffset.width();
- }
- return result;
-}
-
-bool ShapeInsideInfo::updateSegmentsForLine(LayoutUnit lineTop, LayoutUnit lineHeight)
-{
- ASSERT(lineHeight >= 0);
- m_shapeLineTop = lineTop - logicalTopOffset();
- m_lineHeight = lineHeight;
- m_segments.clear();
- m_segmentRanges.clear();
-
- if (lineOverlapsShapeBounds())
- m_segments = computeSegmentsForLine(lineTop, lineHeight);
-
- return m_segments.size();
-}
-
-bool ShapeInsideInfo::adjustLogicalLineTop(float minSegmentWidth)
-{
- const Shape& shape = computedShape();
- if (m_lineHeight <= 0 || logicalLineTop() > shapeLogicalBottom())
- return false;
-
- LayoutUnit newLineTop;
- if (shape.firstIncludedIntervalLogicalTop(m_shapeLineTop, FloatSize(minSegmentWidth, m_lineHeight), newLineTop)) {
- if (newLineTop > m_shapeLineTop) {
- m_shapeLineTop = newLineTop;
- return true;
- }
- }
-
- return false;
-}
-
-ShapeValue* ShapeInsideInfo::shapeValue() const
-{
- return m_renderer.style().resolvedShapeInside();
-}
-
-LayoutUnit ShapeInsideInfo::computeFirstFitPositionForFloat(const FloatSize floatSize) const
-{
- if (!floatSize.width() || shapeLogicalBottom() < logicalLineTop())
- return 0;
-
- LayoutUnit firstFitPosition = 0;
- if (computedShape().firstIncludedIntervalLogicalTop(m_shapeLineTop, floatSize, firstFitPosition) && (m_shapeLineTop <= firstFitPosition))
- return firstFitPosition;
-
- return 0;
-}
-
-}
-#endif
diff --git a/Source/WebCore/rendering/shapes/ShapeInsideInfo.h b/Source/WebCore/rendering/shapes/ShapeInsideInfo.h
deleted file mode 100644
index 77f4afa22..000000000
--- a/Source/WebCore/rendering/shapes/ShapeInsideInfo.h
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
- * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
- * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef ShapeInsideInfo_h
-#define ShapeInsideInfo_h
-
-#if ENABLE(CSS_SHAPES)
-
-#include "ShapeInfo.h"
-#include <wtf/PassOwnPtr.h>
-#include <wtf/Vector.h>
-
-namespace WebCore {
-
-class InlineIterator;
-class RenderBlock;
-class RenderElement;
-class RenderObject;
-
-struct LineSegmentIterator {
- RenderElement* root;
- RenderObject* object;
- unsigned offset;
- LineSegmentIterator(RenderElement* root, RenderObject* object, unsigned offset)
- : root(root)
- , object(object)
- , offset(offset)
- {
- }
-};
-
-struct LineSegmentRange {
- LineSegmentIterator start;
- LineSegmentIterator end;
- LineSegmentRange(const InlineIterator& start, const InlineIterator& end);
-};
-
-typedef Vector<LineSegmentRange> SegmentRangeList;
-
-class ShapeInsideInfo final : public ShapeInfo<RenderBlock> {
-public:
- ShapeInsideInfo(const RenderBlock& renderer)
- : ShapeInfo<RenderBlock>(renderer)
- , m_needsLayout(false)
- {
- }
-
- static bool isEnabledFor(const RenderBlock& renderer);
-
- bool updateSegmentsForLine(LayoutSize lineOffset, LayoutUnit lineHeight);
- bool updateSegmentsForLine(LayoutUnit lineTop, LayoutUnit lineHeight);
-
- bool hasSegments() const
- {
- return lineOverlapsShapeBounds() && m_segments.size();
- }
- const SegmentList& segments() const
- {
- ASSERT(hasSegments());
- return m_segments;
- }
- SegmentRangeList& segmentRanges() { return m_segmentRanges; }
- const SegmentRangeList& segmentRanges() const { return m_segmentRanges; }
- const LineSegment* currentSegment() const
- {
- if (!hasSegments())
- return 0;
- ASSERT(m_segmentRanges.size() < m_segments.size());
- return &m_segments[m_segmentRanges.size()];
- }
- void clearSegments() { m_segments.clear(); }
- bool adjustLogicalLineTop(float minSegmentWidth);
- LayoutUnit computeFirstFitPositionForFloat(const FloatSize) const;
-
- void setNeedsLayout(bool value) { m_needsLayout = value; }
- bool needsLayout() { return m_needsLayout; }
-
- virtual bool lineOverlapsShapeBounds() const override
- {
- return computedShape().lineOverlapsShapePaddingBounds(m_shapeLineTop, m_lineHeight);
- }
-
-protected:
- virtual LayoutBox resolvedLayoutBox() const override
- {
- if (shapeValue()->layoutBox() == BoxMissing)
- return ContentBox;
-
- return shapeValue()->layoutBox();
- }
-
-private:
- virtual LayoutRect computedShapeLogicalBoundingBox() const override { return computedShape().shapePaddingLogicalBoundingBox(); }
- virtual ShapeValue* shapeValue() const override;
- virtual void getIntervals(LayoutUnit lineTop, LayoutUnit lineHeight, SegmentList& segments) const override
- {
- return computedShape().getIncludedIntervals(lineTop, lineHeight, segments);
- }
-
- SegmentRangeList m_segmentRanges;
- bool m_needsLayout:1;
- SegmentList m_segments;
-};
-
-}
-#endif
-#endif
diff --git a/Source/WebCore/rendering/shapes/ShapeInterval.h b/Source/WebCore/rendering/shapes/ShapeInterval.h
index 476f0ce79..6cc4dab49 100644
--- a/Source/WebCore/rendering/shapes/ShapeInterval.h
+++ b/Source/WebCore/rendering/shapes/ShapeInterval.h
@@ -27,8 +27,7 @@
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef ShapeInterval_h
-#define ShapeInterval_h
+#pragma once
#include <wtf/Vector.h>
@@ -38,29 +37,27 @@ template <typename T>
class ShapeInterval {
WTF_MAKE_FAST_ALLOCATED;
public:
- ShapeInterval(T x1 = 0, T x2 = 0)
- : m_x1(x1)
- , m_x2(x2)
+ ShapeInterval()
+ : m_x1(-1)
+ , m_x2(-2)
{
- ASSERT(x2 >= x1);
+ // The initial values of m_x1,x2 don't matter (unless you're looking
+ // at them in the debugger) so long as isUndefined() is true.
+ ASSERT(isUndefined());
}
- T x1() const { return m_x1; }
- T x2() const { return m_x2; }
- T width() const { return m_x2 - m_x1; }
- bool isEmpty() const { return m_x1 == m_x2; }
-
- void setX1(T x1)
+ ShapeInterval(T x1, T x2)
+ : m_x1(x1)
+ , m_x2(x2)
{
- ASSERT(m_x2 >= x1);
- m_x1 = x1;
+ ASSERT(x2 >= x1);
}
- void setX2(T x2)
- {
- ASSERT(x2 >= m_x1);
- m_x2 = x2;
- }
+ bool isUndefined() const { return m_x2 < m_x1; }
+ T x1() const { return isUndefined() ? 0 : m_x1; }
+ T x2() const { return isUndefined() ? 0 : m_x2; }
+ T width() const { return isUndefined() ? 0 : m_x2 - m_x1; }
+ bool isEmpty() const { return isUndefined() ? true : m_x1 == m_x2; }
void set(T x1, T x2)
{
@@ -71,135 +68,26 @@ public:
bool overlaps(const ShapeInterval<T>& interval) const
{
+ if (isUndefined() || interval.isUndefined())
+ return false;
return x2() >= interval.x1() && x1() <= interval.x2();
}
bool contains(const ShapeInterval<T>& interval) const
{
+ if (isUndefined() || interval.isUndefined())
+ return false;
return x1() <= interval.x1() && x2() >= interval.x2();
}
- ShapeInterval<T> intersect(const ShapeInterval<T>& interval) const
- {
- ASSERT(overlaps(interval));
- return ShapeInterval<T>(std::max<T>(x1(), interval.x1()), std::min<T>(x2(), interval.x2()));
- }
-
- typedef Vector<ShapeInterval<T>> ShapeIntervals;
- typedef typename ShapeIntervals::const_iterator const_iterator;
- typedef typename ShapeIntervals::iterator iterator;
-
- static void uniteShapeIntervals(const ShapeIntervals& a, const ShapeIntervals& b, ShapeIntervals& result)
+ void unite(const ShapeInterval<T>& interval)
{
- ASSERT(shapeIntervalsAreSortedAndDisjoint(a) && shapeIntervalsAreSortedAndDisjoint(b));
-
- if (a.isEmpty() || a == b) {
- result.appendRange(b.begin(), b.end());
- return;
- }
-
- if (b.isEmpty()) {
- result.appendRange(a.begin(), a.end());
+ if (interval.isUndefined())
return;
- }
-
- const_iterator aNext = a.begin();
- const_iterator bNext = b.begin();
-
- while (aNext != a.end() || bNext != b.end()) {
- const_iterator next = (bNext == b.end() || (aNext != a.end() && aNext->x1() < bNext->x1())) ? aNext++ : bNext++;
- if (result.isEmpty() || !result.last().overlaps(*next))
- result.append(*next);
- else
- result.last().setX2(std::max<T>(result.last().x2(), next->x2()));
- }
- }
-
- static void intersectShapeIntervals(const ShapeIntervals& a, const ShapeIntervals& b, ShapeIntervals& result)
- {
- ASSERT(shapeIntervalsAreSortedAndDisjoint(a) && shapeIntervalsAreSortedAndDisjoint(b));
-
- if (a.isEmpty() || b.isEmpty())
- return;
-
- if (a == b) {
- result.appendRange(a.begin(), a.end());
- return;
- }
-
- const_iterator aNext = a.begin();
- const_iterator bNext = b.begin();
- const_iterator working = aNext->x1() < bNext->x1() ? aNext++ : bNext++;
-
- while (aNext != a.end() || bNext != b.end()) {
- const_iterator next = (bNext == b.end() || (aNext != a.end() && aNext->x1() < bNext->x1())) ? aNext++ : bNext++;
- if (working->overlaps(*next)) {
- result.append(working->intersect(*next));
- if (next->x2() > working->x2())
- working = next;
- } else
- working = next;
- }
- }
-
- static void subtractShapeIntervals(const ShapeIntervals& a, const ShapeIntervals& b, ShapeIntervals& result)
- {
- ASSERT(shapeIntervalsAreSortedAndDisjoint(a) && shapeIntervalsAreSortedAndDisjoint(b));
-
- if (a.isEmpty() || a == b)
- return;
-
- if (b.isEmpty()) {
- result.appendRange(a.begin(), a.end());
- return;
- }
-
- const_iterator aNext = a.begin();
- const_iterator bNext = b.begin();
- ShapeInterval<T> aValue = *aNext;
- ShapeInterval<T> bValue = *bNext;
-
- do {
- bool aIncrement = false;
- bool bIncrement = false;
-
- if (bValue.contains(aValue)) {
- aIncrement = true;
- } else if (aValue.contains(bValue)) {
- if (bValue.x1() > aValue.x1())
- result.append(ShapeInterval<T>(aValue.x1(), bValue.x1()));
- if (aValue.x2() > bValue.x2())
- aValue.setX1(bValue.x2());
- else
- aIncrement = true;
- bIncrement = true;
- } else if (aValue.overlaps(bValue)) {
- if (aValue.x1() < bValue.x1()) {
- result.append(ShapeInterval<T>(aValue.x1(), bValue.x1()));
- aIncrement = true;
- } else {
- aValue.setX1(bValue.x2());
- bIncrement = true;
- }
- } else {
- if (aValue.x1() < bValue.x1()) {
- result.append(aValue);
- aIncrement = true;
- } else
- bIncrement = true;
- }
-
- if (aIncrement && ++aNext != a.end())
- aValue = *aNext;
- if (bIncrement && ++bNext != b.end())
- bValue = *bNext;
-
- } while (aNext != a.end() && bNext != b.end());
-
- if (aNext != a.end()) {
- result.append(aValue);
- result.appendRange(++aNext, a.end());
- }
+ if (isUndefined())
+ set(interval.x1(), interval.x2());
+ else
+ set(std::min<T>(x1(), interval.x1()), std::max<T>(x2(), interval.x2()));
}
bool operator==(const ShapeInterval<T>& other) const { return x1() == other.x1() && x2() == other.x2(); }
@@ -208,15 +96,6 @@ public:
private:
T m_x1;
T m_x2;
-
- static bool shapeIntervalsAreSortedAndDisjoint(const ShapeIntervals& intervals)
- {
- for (unsigned i = 1; i < intervals.size(); i++)
- if (intervals[i - 1].x2() > intervals[i].x1())
- return false;
-
- return true;
- }
};
typedef ShapeInterval<int> IntShapeInterval;
@@ -226,5 +105,3 @@ typedef Vector<IntShapeInterval> IntShapeIntervals;
typedef Vector<FloatShapeInterval> FloatShapeIntervals;
} // namespace WebCore
-
-#endif // ShapeInterval_h
diff --git a/Source/WebCore/rendering/shapes/ShapeOutsideInfo.cpp b/Source/WebCore/rendering/shapes/ShapeOutsideInfo.cpp
index dcfa2bf33..9ce65155c 100644
--- a/Source/WebCore/rendering/shapes/ShapeOutsideInfo.cpp
+++ b/Source/WebCore/rendering/shapes/ShapeOutsideInfo.cpp
@@ -29,16 +29,263 @@
#include "config.h"
-#if ENABLE(CSS_SHAPES)
-
#include "ShapeOutsideInfo.h"
+#include "BoxShape.h"
#include "FloatingObjects.h"
+#include "LengthFunctions.h"
#include "RenderBlockFlow.h"
#include "RenderBox.h"
+#include "RenderImage.h"
+#include "RenderRegion.h"
namespace WebCore {
+LayoutRect ShapeOutsideInfo::computedShapePhysicalBoundingBox() const
+{
+ LayoutRect physicalBoundingBox = computedShape().shapeMarginLogicalBoundingBox();
+ physicalBoundingBox.setX(physicalBoundingBox.x() + logicalLeftOffset());
+ physicalBoundingBox.setY(physicalBoundingBox.y() + logicalTopOffset());
+ if (m_renderer.style().isFlippedBlocksWritingMode())
+ physicalBoundingBox.setY(m_renderer.logicalHeight() - physicalBoundingBox.maxY());
+ if (!m_renderer.style().isHorizontalWritingMode())
+ physicalBoundingBox = physicalBoundingBox.transposedRect();
+ return physicalBoundingBox;
+}
+
+FloatPoint ShapeOutsideInfo::shapeToRendererPoint(const FloatPoint& point) const
+{
+ FloatPoint result = FloatPoint(point.x() + logicalLeftOffset(), point.y() + logicalTopOffset());
+ if (m_renderer.style().isFlippedBlocksWritingMode())
+ result.setY(m_renderer.logicalHeight() - result.y());
+ if (!m_renderer.style().isHorizontalWritingMode())
+ result = result.transposedPoint();
+ return result;
+}
+
+FloatSize ShapeOutsideInfo::shapeToRendererSize(const FloatSize& size) const
+{
+ if (!m_renderer.style().isHorizontalWritingMode())
+ return size.transposedSize();
+ return size;
+}
+
+static inline CSSBoxType referenceBox(const ShapeValue& shapeValue)
+{
+ if (shapeValue.cssBox() == BoxMissing) {
+ if (shapeValue.type() == ShapeValue::Type::Image)
+ return ContentBox;
+ return MarginBox;
+ }
+ return shapeValue.cssBox();
+}
+
+void ShapeOutsideInfo::setReferenceBoxLogicalSize(LayoutSize newReferenceBoxLogicalSize)
+{
+ bool isHorizontalWritingMode = m_renderer.containingBlock()->style().isHorizontalWritingMode();
+ switch (referenceBox(*m_renderer.style().shapeOutside())) {
+ case MarginBox:
+ if (isHorizontalWritingMode)
+ newReferenceBoxLogicalSize.expand(m_renderer.horizontalMarginExtent(), m_renderer.verticalMarginExtent());
+ else
+ newReferenceBoxLogicalSize.expand(m_renderer.verticalMarginExtent(), m_renderer.horizontalMarginExtent());
+ break;
+ case BorderBox:
+ break;
+ case PaddingBox:
+ if (isHorizontalWritingMode)
+ newReferenceBoxLogicalSize.shrink(m_renderer.horizontalBorderExtent(), m_renderer.verticalBorderExtent());
+ else
+ newReferenceBoxLogicalSize.shrink(m_renderer.verticalBorderExtent(), m_renderer.horizontalBorderExtent());
+ break;
+ case ContentBox:
+ if (isHorizontalWritingMode)
+ newReferenceBoxLogicalSize.shrink(m_renderer.horizontalBorderAndPaddingExtent(), m_renderer.verticalBorderAndPaddingExtent());
+ else
+ newReferenceBoxLogicalSize.shrink(m_renderer.verticalBorderAndPaddingExtent(), m_renderer.horizontalBorderAndPaddingExtent());
+ break;
+ case Fill:
+ case Stroke:
+ case ViewBox:
+ case BoxMissing:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+
+ if (m_referenceBoxLogicalSize == newReferenceBoxLogicalSize)
+ return;
+ markShapeAsDirty();
+ m_referenceBoxLogicalSize = newReferenceBoxLogicalSize;
+}
+
+static inline bool checkShapeImageOrigin(Document& document, const StyleImage& styleImage)
+{
+ if (styleImage.isGeneratedImage())
+ return true;
+
+ ASSERT(styleImage.cachedImage());
+ CachedImage& cachedImage = *(styleImage.cachedImage());
+ if (cachedImage.isOriginClean(&document.securityOrigin()))
+ return true;
+
+ const URL& url = cachedImage.url();
+ String urlString = url.isNull() ? "''" : url.stringCenterEllipsizedToLength();
+ document.addConsoleMessage(MessageSource::Security, MessageLevel::Error, "Unsafe attempt to load URL " + urlString + ".");
+
+ return false;
+}
+
+static LayoutRect getShapeImageMarginRect(const RenderBox& renderBox, const LayoutSize& referenceBoxLogicalSize)
+{
+ LayoutPoint marginBoxOrigin(-renderBox.marginLogicalLeft() - renderBox.borderAndPaddingLogicalLeft(), -renderBox.marginBefore() - renderBox.borderBefore() - renderBox.paddingBefore());
+ LayoutSize marginBoxSizeDelta(renderBox.marginLogicalWidth() + renderBox.borderAndPaddingLogicalWidth(), renderBox.marginLogicalHeight() + renderBox.borderAndPaddingLogicalHeight());
+ LayoutSize marginRectSize(referenceBoxLogicalSize + marginBoxSizeDelta);
+ marginRectSize.clampNegativeToZero();
+ return LayoutRect(marginBoxOrigin, marginRectSize);
+}
+
+std::unique_ptr<Shape> ShapeOutsideInfo::createShapeForImage(StyleImage* styleImage, float shapeImageThreshold, WritingMode writingMode, float margin) const
+{
+ LayoutSize imageSize = m_renderer.calculateImageIntrinsicDimensions(styleImage, m_referenceBoxLogicalSize, RenderImage::ScaleByEffectiveZoom);
+ styleImage->setContainerSizeForRenderer(&m_renderer, imageSize, m_renderer.style().effectiveZoom());
+
+ const LayoutRect& marginRect = getShapeImageMarginRect(m_renderer, m_referenceBoxLogicalSize);
+ const LayoutRect& imageRect = is<RenderImage>(m_renderer)
+ ? downcast<RenderImage>(m_renderer).replacedContentRect(m_renderer.intrinsicSize())
+ : LayoutRect(LayoutPoint(), imageSize);
+
+ ASSERT(!styleImage->isPending());
+ RefPtr<Image> image = styleImage->image(const_cast<RenderBox*>(&m_renderer), imageSize);
+ return Shape::createRasterShape(image.get(), shapeImageThreshold, imageRect, marginRect, writingMode, margin);
+}
+
+const Shape& ShapeOutsideInfo::computedShape() const
+{
+ if (Shape* shape = m_shape.get())
+ return *shape;
+
+ const RenderStyle& style = m_renderer.style();
+ ASSERT(m_renderer.containingBlock());
+ const RenderStyle& containingBlockStyle = m_renderer.containingBlock()->style();
+
+ WritingMode writingMode = containingBlockStyle.writingMode();
+ float margin = floatValueForLength(m_renderer.style().shapeMargin(), m_renderer.containingBlock() ? m_renderer.containingBlock()->contentWidth() : LayoutUnit());
+ float shapeImageThreshold = style.shapeImageThreshold();
+ const ShapeValue& shapeValue = *style.shapeOutside();
+
+ switch (shapeValue.type()) {
+ case ShapeValue::Type::Shape:
+ ASSERT(shapeValue.shape());
+ m_shape = Shape::createShape(*shapeValue.shape(), m_referenceBoxLogicalSize, writingMode, margin);
+ break;
+ case ShapeValue::Type::Image:
+ ASSERT(shapeValue.isImageValid());
+ m_shape = createShapeForImage(shapeValue.image(), shapeImageThreshold, writingMode, margin);
+ break;
+ case ShapeValue::Type::Box: {
+ RoundedRect shapeRect = computeRoundedRectForBoxShape(referenceBox(shapeValue), m_renderer);
+ if (!containingBlockStyle.isHorizontalWritingMode())
+ shapeRect = shapeRect.transposedRect();
+ m_shape = Shape::createBoxShape(shapeRect, writingMode, margin);
+ break;
+ }
+ }
+
+ ASSERT(m_shape);
+ return *m_shape;
+}
+
+static inline LayoutUnit borderBeforeInWritingMode(const RenderBox& renderer, WritingMode writingMode)
+{
+ switch (writingMode) {
+ case TopToBottomWritingMode: return renderer.borderTop();
+ case BottomToTopWritingMode: return renderer.borderBottom();
+ case LeftToRightWritingMode: return renderer.borderLeft();
+ case RightToLeftWritingMode: return renderer.borderRight();
+ }
+
+ ASSERT_NOT_REACHED();
+ return renderer.borderBefore();
+}
+
+static inline LayoutUnit borderAndPaddingBeforeInWritingMode(const RenderBox& renderer, WritingMode writingMode)
+{
+ switch (writingMode) {
+ case TopToBottomWritingMode: return renderer.borderTop() + renderer.paddingTop();
+ case BottomToTopWritingMode: return renderer.borderBottom() + renderer.paddingBottom();
+ case LeftToRightWritingMode: return renderer.borderLeft() + renderer.paddingLeft();
+ case RightToLeftWritingMode: return renderer.borderRight() + renderer.paddingRight();
+ }
+
+ ASSERT_NOT_REACHED();
+ return renderer.borderAndPaddingBefore();
+}
+
+LayoutUnit ShapeOutsideInfo::logicalTopOffset() const
+{
+ switch (referenceBox(*m_renderer.style().shapeOutside())) {
+ case MarginBox: return -m_renderer.marginBefore(&m_renderer.containingBlock()->style());
+ case BorderBox: return LayoutUnit();
+ case PaddingBox: return borderBeforeInWritingMode(m_renderer, m_renderer.containingBlock()->style().writingMode());
+ case ContentBox: return borderAndPaddingBeforeInWritingMode(m_renderer, m_renderer.containingBlock()->style().writingMode());
+ case Fill: break;
+ case Stroke: break;
+ case ViewBox: break;
+ case BoxMissing: break;
+ }
+
+ ASSERT_NOT_REACHED();
+ return LayoutUnit();
+}
+
+static inline LayoutUnit borderStartWithStyleForWritingMode(const RenderBox& renderer, const RenderStyle& style)
+{
+ if (style.isHorizontalWritingMode()) {
+ if (style.isLeftToRightDirection())
+ return renderer.borderLeft();
+
+ return renderer.borderRight();
+ }
+ if (style.isLeftToRightDirection())
+ return renderer.borderTop();
+
+ return renderer.borderBottom();
+}
+
+static inline LayoutUnit borderAndPaddingStartWithStyleForWritingMode(const RenderBox& renderer, const RenderStyle& style)
+{
+ if (style.isHorizontalWritingMode()) {
+ if (style.isLeftToRightDirection())
+ return renderer.borderLeft() + renderer.paddingLeft();
+
+ return renderer.borderRight() + renderer.paddingRight();
+ }
+ if (style.isLeftToRightDirection())
+ return renderer.borderTop() + renderer.paddingTop();
+
+ return renderer.borderBottom() + renderer.paddingBottom();
+}
+
+LayoutUnit ShapeOutsideInfo::logicalLeftOffset() const
+{
+ if (m_renderer.isRenderRegion())
+ return LayoutUnit();
+
+ switch (referenceBox(*m_renderer.style().shapeOutside())) {
+ case MarginBox: return -m_renderer.marginStart(&m_renderer.containingBlock()->style());
+ case BorderBox: return LayoutUnit();
+ case PaddingBox: return borderStartWithStyleForWritingMode(m_renderer, m_renderer.containingBlock()->style());
+ case ContentBox: return borderAndPaddingStartWithStyleForWritingMode(m_renderer, m_renderer.containingBlock()->style());
+ case Fill: break;
+ case Stroke: break;
+ case ViewBox: break;
+ case BoxMissing: break;
+ }
+
+ ASSERT_NOT_REACHED();
+ return LayoutUnit();
+}
+
bool ShapeOutsideInfo::isEnabledFor(const RenderBox& box)
{
ShapeValue* shapeValue = box.style().shapeOutside();
@@ -46,64 +293,48 @@ bool ShapeOutsideInfo::isEnabledFor(const RenderBox& box)
return false;
switch (shapeValue->type()) {
- case ShapeValue::Shape:
- return shapeValue->shape();
- case ShapeValue::Image:
- return shapeValue->isImageValid() && checkShapeImageOrigin(box.document(), *(shapeValue->image()->cachedImage()));
- case ShapeValue::Box:
- return true;
- case ShapeValue::Outside:
- break;
+ case ShapeValue::Type::Shape: return shapeValue->shape();
+ case ShapeValue::Type::Image: return shapeValue->isImageValid() && checkShapeImageOrigin(box.document(), *(shapeValue->image()));
+ case ShapeValue::Type::Box: return true;
}
+
ASSERT_NOT_REACHED();
return false;
}
-void ShapeOutsideInfo::updateDeltasForContainingBlockLine(const RenderBlockFlow& containingBlock, const FloatingObject& floatingObject, LayoutUnit lineTop, LayoutUnit lineHeight)
+ShapeOutsideDeltas ShapeOutsideInfo::computeDeltasForContainingBlockLine(const RenderBlockFlow& containingBlock, const FloatingObject& floatingObject, LayoutUnit lineTop, LayoutUnit lineHeight)
{
- LayoutUnit shapeTop = containingBlock.logicalTopForFloat(&floatingObject) + std::max(LayoutUnit(), containingBlock.marginBeforeForChild(m_renderer));
- LayoutUnit floatRelativeLineTop = lineTop - shapeTop;
+ ASSERT(lineHeight >= 0);
+ LayoutUnit borderBoxTop = containingBlock.logicalTopForFloat(floatingObject) + containingBlock.marginBeforeForChild(m_renderer);
+ LayoutUnit borderBoxLineTop = lineTop - borderBoxTop;
- if (shapeSizeDirty() || m_lineTop != floatRelativeLineTop || m_lineHeight != lineHeight) {
- m_lineTop = floatRelativeLineTop;
- m_shapeLineTop = floatRelativeLineTop - logicalTopOffset();
- m_lineHeight = lineHeight;
+ if (isShapeDirty() || !m_shapeOutsideDeltas.isForLine(borderBoxLineTop, lineHeight)) {
+ LayoutUnit referenceBoxLineTop = borderBoxLineTop - logicalTopOffset();
+ LayoutUnit floatMarginBoxWidth = std::max<LayoutUnit>(LayoutUnit(), containingBlock.logicalWidthForFloat(floatingObject));
- LayoutUnit floatMarginBoxWidth = containingBlock.logicalWidthForFloat(&floatingObject);
+ if (computedShape().lineOverlapsShapeMarginBounds(referenceBoxLineTop, lineHeight)) {
+ LineSegment segment = computedShape().getExcludedInterval((borderBoxLineTop - logicalTopOffset()), std::min(lineHeight, shapeLogicalBottom() - borderBoxLineTop));
+ if (segment.isValid) {
+ LayoutUnit logicalLeftMargin = containingBlock.style().isLeftToRightDirection() ? containingBlock.marginStartForChild(m_renderer) : containingBlock.marginEndForChild(m_renderer);
+ LayoutUnit rawLeftMarginBoxDelta = segment.logicalLeft + logicalLeftOffset() + logicalLeftMargin;
+ LayoutUnit leftMarginBoxDelta = clampTo<LayoutUnit>(rawLeftMarginBoxDelta, LayoutUnit(), floatMarginBoxWidth);
- if (lineOverlapsShapeBounds()) {
- SegmentList segments = computeSegmentsForLine(floatRelativeLineTop, lineHeight);
- if (segments.size()) {
- LayoutUnit rawLeftMarginBoxDelta = segments.first().logicalLeft + containingBlock.marginStartForChild(m_renderer);
- m_leftMarginBoxDelta = clampTo<LayoutUnit>(rawLeftMarginBoxDelta, LayoutUnit(), floatMarginBoxWidth);
+ LayoutUnit logicalRightMargin = containingBlock.style().isLeftToRightDirection() ? containingBlock.marginEndForChild(m_renderer) : containingBlock.marginStartForChild(m_renderer);
+ LayoutUnit rawRightMarginBoxDelta = segment.logicalRight + logicalLeftOffset() - containingBlock.logicalWidthForChild(m_renderer) - logicalRightMargin;
+ LayoutUnit rightMarginBoxDelta = clampTo<LayoutUnit>(rawRightMarginBoxDelta, -floatMarginBoxWidth, LayoutUnit());
- LayoutUnit rawRightMarginBoxDelta = segments.last().logicalRight - containingBlock.logicalWidthForChild(m_renderer) - containingBlock.marginEndForChild(m_renderer);
- m_rightMarginBoxDelta = clampTo<LayoutUnit>(rawRightMarginBoxDelta, -floatMarginBoxWidth, LayoutUnit());
- m_lineOverlapsShape = true;
- return;
+ m_shapeOutsideDeltas = ShapeOutsideDeltas(leftMarginBoxDelta, rightMarginBoxDelta, true, borderBoxLineTop, lineHeight);
+ return m_shapeOutsideDeltas;
}
}
// Lines that do not overlap the shape should act as if the float
// wasn't there for layout purposes. So we set the deltas to remove the
// entire width of the float
- m_leftMarginBoxDelta = floatMarginBoxWidth;
- m_rightMarginBoxDelta = -floatMarginBoxWidth;
- m_lineOverlapsShape = false;
+ m_shapeOutsideDeltas = ShapeOutsideDeltas(floatMarginBoxWidth, -floatMarginBoxWidth, false, borderBoxLineTop, lineHeight);
}
-}
-ShapeValue* ShapeOutsideInfo::shapeValue() const
-{
- return m_renderer.style().shapeOutside();
+ return m_shapeOutsideDeltas;
}
-WritingMode ShapeOutsideInfo::writingMode() const
-{
- ASSERT(m_renderer.containingBlock());
- return m_renderer.containingBlock()->style().writingMode();
}
-
-}
-
-#endif
diff --git a/Source/WebCore/rendering/shapes/ShapeOutsideInfo.h b/Source/WebCore/rendering/shapes/ShapeOutsideInfo.h
index 9bdf1a280..cd94f89c0 100644
--- a/Source/WebCore/rendering/shapes/ShapeOutsideInfo.h
+++ b/Source/WebCore/rendering/shapes/ShapeOutsideInfo.h
@@ -27,68 +27,117 @@
* SUCH DAMAGE.
*/
-#ifndef ShapeOutsideInfo_h
-#define ShapeOutsideInfo_h
-
-#if ENABLE(CSS_SHAPES)
+#pragma once
#include "LayoutSize.h"
-#include "ShapeInfo.h"
+#include "Shape.h"
+#include <wtf/HashMap.h>
+#include <wtf/NeverDestroyed.h>
namespace WebCore {
class RenderBlockFlow;
class RenderBox;
+class StyleImage;
class FloatingObject;
-class ShapeOutsideInfo final : public ShapeInfo<RenderBox>, public MappedInfo<RenderBox, ShapeOutsideInfo> {
+class ShapeOutsideDeltas final {
public:
- ShapeOutsideInfo(const RenderBox& renderer)
- : ShapeInfo<RenderBox>(renderer)
- , m_lineOverlapsShape(false)
+ ShapeOutsideDeltas()
+ : m_lineOverlapsShape(false)
+ , m_isValid(false)
{
}
- static bool isEnabledFor(const RenderBox&);
+ ShapeOutsideDeltas(LayoutUnit leftMarginBoxDelta, LayoutUnit rightMarginBoxDelta, bool lineOverlapsShape, LayoutUnit borderBoxLineTop, LayoutUnit lineHeight)
+ : m_leftMarginBoxDelta(leftMarginBoxDelta)
+ , m_rightMarginBoxDelta(rightMarginBoxDelta)
+ , m_borderBoxLineTop(borderBoxLineTop)
+ , m_lineHeight(lineHeight)
+ , m_lineOverlapsShape(lineOverlapsShape)
+ , m_isValid(true)
+ {
+ }
+
+ bool isForLine(LayoutUnit borderBoxLineTop, LayoutUnit lineHeight)
+ {
+ return m_isValid && m_borderBoxLineTop == borderBoxLineTop && m_lineHeight == lineHeight;
+ }
- LayoutUnit leftMarginBoxDelta() const { return m_leftMarginBoxDelta; }
- LayoutUnit rightMarginBoxDelta() const { return m_rightMarginBoxDelta; }
- bool lineOverlapsShape() const { return m_lineOverlapsShape; }
+ bool isValid() { return m_isValid; }
+ LayoutUnit leftMarginBoxDelta() { ASSERT(m_isValid); return m_leftMarginBoxDelta; }
+ LayoutUnit rightMarginBoxDelta() { ASSERT(m_isValid); return m_rightMarginBoxDelta; }
+ bool lineOverlapsShape() { ASSERT(m_isValid); return m_lineOverlapsShape; }
- void updateDeltasForContainingBlockLine(const RenderBlockFlow&, const FloatingObject&, LayoutUnit lineTop, LayoutUnit lineHeight);
+private:
+ LayoutUnit m_leftMarginBoxDelta;
+ LayoutUnit m_rightMarginBoxDelta;
+ LayoutUnit m_borderBoxLineTop;
+ LayoutUnit m_lineHeight;
+ unsigned m_lineOverlapsShape : 1;
+ unsigned m_isValid : 1;
+};
- virtual bool lineOverlapsShapeBounds() const override
+class ShapeOutsideInfo final {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ ShapeOutsideInfo(const RenderBox& renderer)
+ : m_renderer(renderer)
{
- return computedShape().lineOverlapsShapeMarginBounds(m_shapeLineTop, m_lineHeight);
}
-protected:
- virtual LayoutBox resolvedLayoutBox() const override
+ static bool isEnabledFor(const RenderBox&);
+
+ ShapeOutsideDeltas computeDeltasForContainingBlockLine(const RenderBlockFlow&, const FloatingObject&, LayoutUnit lineTop, LayoutUnit lineHeight);
+
+ void setReferenceBoxLogicalSize(LayoutSize);
+
+ LayoutUnit shapeLogicalTop() const { return computedShape().shapeMarginLogicalBoundingBox().y() + logicalTopOffset(); }
+ LayoutUnit shapeLogicalBottom() const { return computedShape().shapeMarginLogicalBoundingBox().maxY() + logicalTopOffset(); }
+ LayoutUnit shapeLogicalLeft() const { return computedShape().shapeMarginLogicalBoundingBox().x() + logicalLeftOffset(); }
+ LayoutUnit shapeLogicalRight() const { return computedShape().shapeMarginLogicalBoundingBox().maxX() + logicalLeftOffset(); }
+ LayoutUnit shapeLogicalWidth() const { return computedShape().shapeMarginLogicalBoundingBox().width(); }
+ LayoutUnit shapeLogicalHeight() const { return computedShape().shapeMarginLogicalBoundingBox().height(); }
+
+ void markShapeAsDirty() { m_shape = nullptr; }
+ bool isShapeDirty() { return !m_shape; }
+
+ LayoutRect computedShapePhysicalBoundingBox() const;
+ FloatPoint shapeToRendererPoint(const FloatPoint&) const;
+ FloatSize shapeToRendererSize(const FloatSize&) const;
+
+ const Shape& computedShape() const;
+
+ static ShapeOutsideInfo& ensureInfo(const RenderBox& key)
{
- if (shapeValue()->layoutBox() == BoxMissing) {
- if (shapeValue()->type() == ShapeValue::Image)
- return ContentBox;
- return MarginBox;
- }
- return shapeValue()->layoutBox();
+ InfoMap& infoMap = ShapeOutsideInfo::infoMap();
+ if (ShapeOutsideInfo* info = infoMap.get(&key))
+ return *info;
+ auto result = infoMap.add(&key, std::make_unique<ShapeOutsideInfo>(key));
+ return *result.iterator->value;
}
+ static void removeInfo(const RenderBox& key) { infoMap().remove(&key); }
+ static ShapeOutsideInfo* info(const RenderBox& key) { return infoMap().get(&key); }
private:
- virtual LayoutRect computedShapeLogicalBoundingBox() const override { return computedShape().shapeMarginLogicalBoundingBox(); }
- virtual ShapeValue* shapeValue() const override;
- virtual void getIntervals(LayoutUnit lineTop, LayoutUnit lineHeight, SegmentList& segments) const override
+ std::unique_ptr<Shape> createShapeForImage(StyleImage*, float shapeImageThreshold, WritingMode, float margin) const;
+
+ LayoutUnit logicalTopOffset() const;
+ LayoutUnit logicalLeftOffset() const;
+
+ typedef HashMap<const RenderBox*, std::unique_ptr<ShapeOutsideInfo>> InfoMap;
+ static InfoMap& infoMap()
{
- return computedShape().getExcludedIntervals(lineTop, lineHeight, segments);
+ static NeverDestroyed<InfoMap> staticInfoMap;
+ return staticInfoMap;
}
- virtual WritingMode writingMode() const;
+ const RenderBox& m_renderer;
- LayoutUnit m_leftMarginBoxDelta;
- LayoutUnit m_rightMarginBoxDelta;
- LayoutUnit m_lineTop;
- bool m_lineOverlapsShape;
+ mutable std::unique_ptr<Shape> m_shape;
+ LayoutSize m_referenceBoxLogicalSize;
+
+ ShapeOutsideDeltas m_shapeOutsideDeltas;
};
}
-#endif
-#endif