diff options
author | Jocelyn Turcotte <jocelyn.turcotte@digia.com> | 2014-08-08 14:30:41 +0200 |
---|---|---|
committer | Jocelyn Turcotte <jocelyn.turcotte@digia.com> | 2014-08-12 13:49:54 +0200 |
commit | ab0a50979b9eb4dfa3320eff7e187e41efedf7a9 (patch) | |
tree | 498dfb8a97ff3361a9f7486863a52bb4e26bb898 /chromium/third_party/WebKit/Source/core/rendering/shapes | |
parent | 4ce69f7403811819800e7c5ae1318b2647e778d1 (diff) |
Update Chromium to beta version 37.0.2062.68
Change-Id: I188e3b5aff1bec75566014291b654eb19f5bc8ca
Reviewed-by: Andras Becsi <andras.becsi@digia.com>
Diffstat (limited to 'chromium/third_party/WebKit/Source/core/rendering/shapes')
18 files changed, 681 insertions, 1717 deletions
diff --git a/chromium/third_party/WebKit/Source/core/rendering/shapes/BoxShape.cpp b/chromium/third_party/WebKit/Source/core/rendering/shapes/BoxShape.cpp index 86c9136ac90..bba80270c55 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/shapes/BoxShape.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/shapes/BoxShape.cpp @@ -42,14 +42,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,24 +52,14 @@ 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 { const FloatRoundedRect& marginBounds = shapeMarginBounds(); if (marginBounds.isEmpty() || !lineOverlapsShapeMarginBounds(logicalTop, logicalHeight)) return; - float y1 = logicalTop; - float y2 = logicalTop + logicalHeight; + float y1 = logicalTop.toFloat(); + float y2 = (logicalTop + logicalHeight).toFloat(); const FloatRect& rect = marginBounds.rect(); if (!marginBounds.isRounded()) { @@ -85,11 +67,25 @@ void BoxShape::getExcludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHei return; } + float topCornerMaxY = std::max<float>(marginBounds.topLeftCorner().maxY(), marginBounds.topRightCorner().maxY()); + float bottomCornerMinY = std::min<float>(marginBounds.bottomLeftCorner().y(), marginBounds.bottomRightCorner().y()); + + if (topCornerMaxY <= bottomCornerMinY && y1 <= topCornerMaxY && y2 >= bottomCornerMinY) { + result.append(LineSegment(rect.x(), rect.maxX())); + return; + } + 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); @@ -104,27 +100,11 @@ void BoxShape::getExcludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHei result.append(LineSegment(x1, x2)); } -void BoxShape::getIncludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList& result) const +void BoxShape::buildDisplayPaths(DisplayPaths& paths) const { - const FloatRoundedRect& paddingBounds = shapePaddingBounds(); - if (paddingBounds.isEmpty()) - return; - - const FloatRect& rect = paddingBounds.rect(); - if (logicalTop < rect.y() || logicalTop + logicalHeight > rect.maxY()) - return; - - // FIXME: this method is only a stub, https://bugs.webkit.org/show_bug.cgi?id=124605. - - result.append(LineSegment(rect.x(), rect.maxX())); -} - -bool BoxShape::firstIncludedIntervalLogicalTop(LayoutUnit minLogicalIntervalTop, const LayoutSize&, LayoutUnit& result) const -{ - // FIXME: this method is only a stub, https://bugs.webkit.org/show_bug.cgi?id=124606. - - result = minLogicalIntervalTop; - return true; + paths.shape.addRoundedRect(m_bounds.rect(), m_bounds.radii().topLeft(), m_bounds.radii().topRight(), m_bounds.radii().bottomLeft(), m_bounds.radii().bottomRight()); + if (shapeMargin()) + paths.marginShape.addRoundedRect(shapeMarginBounds().rect(), shapeMarginBounds().radii().topLeft(), shapeMarginBounds().radii().topRight(), shapeMarginBounds().radii().bottomLeft(), shapeMarginBounds().radii().bottomRight()); } } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/shapes/BoxShape.h b/chromium/third_party/WebKit/Source/core/rendering/shapes/BoxShape.h index 823187a7ca9..06a51489615 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/shapes/BoxShape.h +++ b/chromium/third_party/WebKit/Source/core/rendering/shapes/BoxShape.h @@ -35,7 +35,7 @@ namespace WebCore { -class BoxShape : public Shape { +class BoxShape FINAL : public Shape { public: BoxShape(const FloatRoundedRect& bounds) : Shape() @@ -44,15 +44,12 @@ public: } 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 LayoutSize& minLogicalIntervalSize, LayoutUnit&) const OVERRIDE; + virtual void buildDisplayPaths(DisplayPaths&) const OVERRIDE; private: FloatRoundedRect shapeMarginBounds() const; - FloatRoundedRect shapePaddingBounds() const; FloatRoundedRect m_bounds; }; diff --git a/chromium/third_party/WebKit/Source/core/rendering/shapes/BoxShapeTest.cpp b/chromium/third_party/WebKit/Source/core/rendering/shapes/BoxShapeTest.cpp index 9b1f50193f1..74538f391fd 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/shapes/BoxShapeTest.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/shapes/BoxShapeTest.cpp @@ -31,6 +31,8 @@ #include "core/rendering/shapes/BoxShape.h" +#include "platform/geometry/RoundedRect.h" + #include <gtest/gtest.h> namespace WebCore { @@ -39,9 +41,9 @@ class BoxShapeTest : public ::testing::Test { protected: BoxShapeTest() { } - PassOwnPtr<Shape> createBoxShape(const LayoutSize& size, float shapeMargin, float shapePadding) + PassOwnPtr<Shape> createBoxShape(const RoundedRect& bounds, float shapeMargin) { - return Shape::createLayoutBoxShape(size, TopToBottomWritingMode, Length(shapeMargin, Fixed), Length(shapePadding, Fixed)); + return Shape::createLayoutBoxShape(bounds, TopToBottomWritingMode, shapeMargin); } }; @@ -56,8 +58,10 @@ using namespace WebCore; SegmentList result; \ shapePtr->getExcludedIntervals(lineTop, lineHeight, result); \ EXPECT_EQ(1u, result.size()); \ - EXPECT_EQ(expectedLeft, result[0].logicalLeft); \ - EXPECT_EQ(expectedRight, result[0].logicalRight); \ + if (result.size() == 1u) { \ + EXPECT_FLOAT_EQ(expectedLeft, result[0].logicalLeft); \ + EXPECT_FLOAT_EQ(expectedRight, result[0].logicalRight); \ + } \ } #define TEST_NO_EXCLUDED_INTERVAL(shapePtr, lineTop, lineHeight) \ @@ -67,13 +71,21 @@ using namespace WebCore; EXPECT_EQ(0u, result.size()); \ } +/* The BoxShape is based on a 100x50 rectangle at 0,0. The shape-margin value is 10, + * so the shapeMarginBoundingBox rectangle is 120x70 at -10,-10: + * + * -10,-10 110,-10 + * +--------+ + * | | + * +--------+ + * -10,60 60,60 + */ TEST_F(BoxShapeTest, zeroRadii) { - OwnPtr<Shape> shape = createBoxShape(LayoutSize(100, 50), 10, 20); + OwnPtr<Shape> shape = createBoxShape(RoundedRect(0, 0, 100, 50), 10); EXPECT_FALSE(shape->isEmpty()); EXPECT_EQ(LayoutRect(-10, -10, 120, 70), shape->shapeMarginLogicalBoundingBox()); - EXPECT_EQ(LayoutRect(20, 20, 60, 10), shape->shapePaddingLogicalBoundingBox()); // A BoxShape's bounds include the top edge but not the bottom edge. // Similarly a "line", specified as top,height to the overlap methods, @@ -98,16 +110,34 @@ TEST_F(BoxShapeTest, zeroRadii) TEST_NO_EXCLUDED_INTERVAL(shape, -12, 2); TEST_NO_EXCLUDED_INTERVAL(shape, 60, 1); TEST_NO_EXCLUDED_INTERVAL(shape, 100, 200); +} + +/* BoxShape geometry for this test. Corner radii are in parens, x and y intercepts + * for the elliptical corners are noted. The rectangle itself is at 0,0 with width and height 100. + * + * (10, 15) x=10 x=90 (10, 20) + * (--+---------+--) + * y=15 +--| |-+ y=20 + * | | + * | | + * y=85 + -| |- + y=70 + * (--+---------+--) + * (25, 15) x=25 x=80 (20, 30) + */ +TEST_F(BoxShapeTest, getIntervals) +{ + const RoundedRect::Radii cornerRadii(IntSize(10, 15), IntSize(10, 20), IntSize(25, 15), IntSize(20, 30)); + OwnPtr<Shape> shape = createBoxShape(RoundedRect(IntRect(0, 0, 100, 100), cornerRadii), 0); + EXPECT_FALSE(shape->isEmpty()); - EXPECT_TRUE(shape->lineOverlapsShapePaddingBounds(21, 1)); - EXPECT_TRUE(shape->lineOverlapsShapePaddingBounds(20, 0)); - EXPECT_TRUE(shape->lineOverlapsShapePaddingBounds(-10, 200)); - EXPECT_TRUE(shape->lineOverlapsShapePaddingBounds(25, 35)); - EXPECT_TRUE(shape->lineOverlapsShapePaddingBounds(29, 1)); + EXPECT_EQ(LayoutRect(0, 0, 100, 100), shape->shapeMarginLogicalBoundingBox()); - EXPECT_FALSE(shape->lineOverlapsShapePaddingBounds(18, 2)); - EXPECT_FALSE(shape->lineOverlapsShapePaddingBounds(30, 1)); - EXPECT_FALSE(shape->lineOverlapsShapePaddingBounds(100, 200)); + TEST_EXCLUDED_INTERVAL(shape, 10, 95, 0, 100); + TEST_EXCLUDED_INTERVAL(shape, 5, 25, 0, 100); + TEST_EXCLUDED_INTERVAL(shape, 15, 6, 0, 100); + TEST_EXCLUDED_INTERVAL(shape, 20, 50, 0, 100); + TEST_EXCLUDED_INTERVAL(shape, 69, 5, 0, 100); + TEST_EXCLUDED_INTERVAL(shape, 85, 10, 0, 97.320511f); } } // namespace diff --git a/chromium/third_party/WebKit/Source/core/rendering/shapes/PolygonShape.cpp b/chromium/third_party/WebKit/Source/core/rendering/shapes/PolygonShape.cpp index 26ddcf3606b..98cd8367e1e 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/shapes/PolygonShape.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/shapes/PolygonShape.cpp @@ -30,70 +30,11 @@ #include "config.h" #include "core/rendering/shapes/PolygonShape.h" -#include "core/rendering/shapes/ShapeInterval.h" #include "platform/geometry/LayoutPoint.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(); @@ -110,422 +51,113 @@ 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] = flooredLayoutPoint(vertices[i]); -} - -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) -{ - OwnPtr<Vector<FloatPoint> > marginVertices = 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, outwardEdgeNormal(thisEdge) * margin); - OffsetPolygonEdge prevOffsetEdge(prevEdge, outwardEdgeNormal(prevEdge) * margin); - - 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)); -} +static inline bool overlapsYRange(const FloatRect& rect, float y1, float y2) { return !rect.isEmpty() && y2 >= y1 && y2 >= rect.y() && y1 <= rect.maxY(); } -const FloatPolygon& PolygonShape::shapePaddingBounds() const +float OffsetPolygonEdge::xIntercept(float y) const { - ASSERT(shapePadding() >= 0); - if (!shapePadding() || m_polygon.isEmpty()) - return m_polygon; + ASSERT(y >= minY() && y <= maxY()); - if (!m_paddingBounds) - m_paddingBounds = computeShapePaddingBounds(m_polygon, shapePadding(), m_polygon.fillRule()); + 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(); - return *m_paddingBounds; + return vertex1().x() + ((y - vertex1().y()) * (vertex2().x() - vertex1().x()) / (vertex2().y() - vertex1().y())); } -const FloatPolygon& PolygonShape::shapeMarginBounds() const +FloatShapeInterval OffsetPolygonEdge::clippedEdgeXRange(float y1, float y2) const { - ASSERT(shapeMargin() >= 0); - if (!shapeMargin() || m_polygon.isEmpty()) - return m_polygon; + if (!overlapsYRange(y1, y2) || (y1 == maxY() && minY() <= y1) || (y2 == minY() && maxY() >= y2)) + return FloatShapeInterval(); - if (!m_marginBounds) - m_marginBounds = computeShapeMarginBounds(m_polygon, shapeMargin(), m_polygon.fillRule()); + if (isWithinYRange(y1, y2)) + return FloatShapeInterval(minX(), maxX()); - 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); + // Clip the edge line segment to the vertical range y1,y2 and then return + // the clipped line segment's horizontal range. - 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; -} - -static inline bool appendIntervalX(float x, bool inside, FloatShapeIntervals& result) -{ - if (!inside) - result.append(FloatShapeInterval(x, x)); - else - result.last().setX2(x); - - return !inside; + 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 bool compareEdgeIntersectionX(const EdgeIntersection& intersection1, const EdgeIntersection& intersection2) +static float circleXIntercept(float y, float radius) { - float x1 = intersection1.point.x(); - float x2 = intersection2.point.x(); - return (x1 == x2) ? intersection1.type < intersection2.type : x1 < x2; + ASSERT(radius > 0); + return radius * sqrt(1 - (y * y) / (radius * radius)); } -static void computeXIntersections(const FloatPolygon& polygon, float y, bool isMinY, FloatShapeIntervals& result) +static FloatShapeInterval clippedCircleXRange(const FloatPoint& center, float radius, float y1, float y2) { - 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; + if (y1 > center.y() + radius || y2 < center.y() - radius) + return FloatShapeInterval(); - 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) +void PolygonShape::getExcludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList& result) const { - Vector<const FloatPolygonEdge*> edges; - if (!polygon.overlappingEdges(y1, y2, edges)) - return; + float y1 = logicalTop.toFloat(); + float y2 = logicalTop.toFloat() + logicalHeight.toFloat(); - EdgeIntersection intersection; - for (unsigned i = 0; i < edges.size(); ++i) { - const FloatPolygonEdge *edge = edges[i]; - float x1; - float x2; + if (m_polygon.isEmpty() || !overlapsYRange(m_polygon.boundingBox(), y1 - shapeMargin(), y2 + shapeMargin())) + return; - 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(); - } + Vector<const FloatPolygonEdge*> overlappingEdges; + if (!m_polygon.overlappingEdges(y1 - shapeMargin(), y2 + shapeMargin(), overlappingEdges)) + return; - if (edge->maxY() > y2) { - computeXIntersection(edge, y2, intersection); - x2 = intersection.point.x(); + 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 { - x2 = (edge->vertex1().y() > edge->vertex2().y()) ? edge->vertex1().x() : edge->vertex2().x(); + 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)); } - - 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) { - const FloatShapeInterval& interval = excludedIntervals[i]; - result.append(LineSegment(interval.x1(), interval.x2())); - } + if (!excludedInterval.isEmpty()) + result.append(LineSegment(excludedInterval.x1(), excludedInterval.x2())); } -void PolygonShape::getIncludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList& result) const +void PolygonShape::buildDisplayPaths(DisplayPaths& paths) const { - const FloatPolygon& polygon = shapePaddingBounds(); - if (polygon.isEmpty()) + if (!m_polygon.numberOfVertices()) 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 LayoutSize& 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))); - } - - 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 (firstFitFound) - result = LayoutUnit::fromFloatCeil(firstFitRect.y()); - return firstFitFound; + paths.shape.moveTo(m_polygon.vertexAt(0)); + for (size_t i = 1; i < m_polygon.numberOfVertices(); ++i) + paths.shape.addLineTo(m_polygon.vertexAt(i)); + paths.shape.closeSubpath(); } } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/shapes/PolygonShape.h b/chromium/third_party/WebKit/Source/core/rendering/shapes/PolygonShape.h index 38b0d8e75c7..f7171c929f4 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/shapes/PolygonShape.h +++ b/chromium/third_party/WebKit/Source/core/rendering/shapes/PolygonShape.h @@ -31,79 +31,48 @@ #define PolygonShape_h #include "core/rendering/shapes/Shape.h" +#include "core/rendering/shapes/ShapeInterval.h" #include "platform/geometry/FloatPolygon.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) - { - } - - 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 { +class PolygonShape FINAL : public Shape { WTF_MAKE_NONCOPYABLE(PolygonShape); public: PolygonShape(PassOwnPtr<Vector<FloatPoint> > vertices, WindRule fillRule) : Shape() , m_polygon(vertices, fillRule) - , m_marginBounds(nullptr) - , m_paddingBounds(nullptr) { } - virtual LayoutRect shapeMarginLogicalBoundingBox() const OVERRIDE { return static_cast<LayoutRect>(shapeMarginBounds().boundingBox()); } - virtual LayoutRect shapePaddingLogicalBoundingBox() const OVERRIDE { return static_cast<LayoutRect>(shapePaddingBounds().boundingBox()); } + virtual LayoutRect shapeMarginLogicalBoundingBox() const OVERRIDE; 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 LayoutSize& minLogicalIntervalSize, LayoutUnit&) const OVERRIDE; + virtual 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 diff --git a/chromium/third_party/WebKit/Source/core/rendering/shapes/RasterShape.cpp b/chromium/third_party/WebKit/Source/core/rendering/shapes/RasterShape.cpp index 78b00211519..8dda343bc66 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/shapes/RasterShape.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/shapes/RasterShape.cpp @@ -73,182 +73,67 @@ IntShapeInterval MarginIntervalGenerator::intervalAt(int y) const return IntShapeInterval(m_x1 - dx, m_x2 + dx); } -void RasterShapeIntervals::appendInterval(int y, int x1, int x2) +PassOwnPtr<RasterShapeIntervals> RasterShapeIntervals::computeShapeMarginIntervals(int shapeMargin) const { - 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; + int marginIntervalsSize = (offset() > shapeMargin) ? size() : size() - offset() * 2 + shapeMargin * 2; + OwnPtr<RasterShapeIntervals> result = adoptPtr(new RasterShapeIntervals(marginIntervalsSize, std::max(shapeMargin, offset()))); + MarginIntervalGenerator marginIntervalGenerator(shapeMargin); - for (int lineY = minY; lineY <= bounds().maxY() - minSize.height(); lineY++) { - Vector<int> intervalX1Values; - if (!getIntervalX1Values(lineY, lineY + minSize.height(), minSize.width(), intervalX1Values)) + for (int y = bounds().y(); y < bounds().maxY(); ++y) { + const IntShapeInterval& intervalAtY = intervalAt(y); + if (intervalAtY.isEmpty()) continue; - std::sort(intervalX1Values.begin(), intervalX1Values.end()); + marginIntervalGenerator.set(y, intervalAtY); + int marginY0 = std::max(minY(), y - shapeMargin); + int marginY1 = std::min(maxY(), y + shapeMargin + 1); - 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; - } + for (int marginY = y - 1; marginY >= marginY0; --marginY) { + if (marginY > bounds().y() && intervalAt(marginY).contains(intervalAtY)) + break; + result->intervalAt(marginY).unite(marginIntervalGenerator.intervalAt(marginY)); } - } - - return false; -} - -void RasterShapeIntervals::getIncludedIntervals(int y1, int y2, IntShapeIntervals& result) const -{ - ASSERT(y2 >= y1); - if (y1 < bounds().y() || y2 > bounds().maxY()) - return; + result->intervalAt(y).unite(marginIntervalGenerator.intervalAt(y)); - for (int y = y1; y < y2; y++) { - if (intervalsAt(y).isEmpty()) - return; + for (int marginY = y + 1; marginY < marginY1; ++marginY) { + if (marginY < bounds().maxY() && intervalAt(marginY).contains(intervalAtY)) + break; + result->intervalAt(marginY).unite(marginIntervalGenerator.intervalAt(marginY)); + } } - result = intervalsAt(y1); - for (int y = y1 + 1; y < y2 && !result.isEmpty(); y++) { - IntShapeIntervals intervals; - IntShapeInterval::intersectShapeIntervals(result, intervalsAt(y), intervals); - result.swap(intervals); - } + result->initializeBounds(); + return result.release(); } -void RasterShapeIntervals::getExcludedIntervals(int y1, int y2, IntShapeIntervals& result) const +void RasterShapeIntervals::initializeBounds() { - 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); + 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)); } } -PassOwnPtr<RasterShapeIntervals> RasterShapeIntervals::computeShapeMarginIntervals(unsigned shapeMargin) const +void RasterShapeIntervals::buildBoundsPath(Path& path) const { - OwnPtr<RasterShapeIntervals> result = adoptPtr(new RasterShapeIntervals(size(), shapeMargin)); - MarginIntervalGenerator marginIntervalGenerator(shapeMargin); - - int minY = bounds().y(); int maxY = bounds().maxY(); - - for (int y = minY; y < maxY; ++y) { - const IntShapeInterval& intervalAtY = limitIntervalAt(y); - if (intervalAtY.isEmpty()) + for (int y = bounds().y(); y < maxY; y++) { + if (intervalAt(y).isEmpty()) continue; - marginIntervalGenerator.set(y, intervalAtY); - int marginY0 = y - clampToInteger(shapeMargin); - int marginY1 = y + clampToInteger(shapeMargin); - - for (int marginY = y - 1; marginY >= marginY0; --marginY) { - if (marginY > minY && limitIntervalAt(marginY).contains(intervalAtY)) + IntShapeInterval extent = intervalAt(y); + int endY = y + 1; + for (; endY < maxY; endY++) { + if (intervalAt(endY).isEmpty() || intervalAt(endY) != extent) break; - result->uniteMarginInterval(marginY, marginIntervalGenerator.intervalAt(marginY)); - } - - result->uniteMarginInterval(y, marginIntervalGenerator.intervalAt(y)); - - for (int marginY = y + 1; marginY <= marginY1; ++marginY) { - if (marginY < maxY && limitIntervalAt(marginY).contains(intervalAtY)) - break; - result->uniteMarginInterval(marginY, marginIntervalGenerator.intervalAt(marginY)); } + path.addRect(FloatRect(extent.x1(), y, extent.width(), endY - y)); + y = endY - 1; } - - return result.release(); } const RasterShapeIntervals& RasterShape::marginIntervals() const @@ -257,58 +142,37 @@ 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()) * sqrtf(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 { const RasterShapeIntervals& intervals = marginIntervals(); if (intervals.isEmpty()) return; - IntShapeIntervals excludedIntervals; - intervals.getExcludedIntervals(logicalTop, logicalTop + logicalHeight, excludedIntervals); - appendLineSegments(excludedIntervals, result); -} - -void RasterShape::getIncludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList& result) const -{ - const RasterShapeIntervals& intervals = paddingIntervals(); - if (intervals.isEmpty()) + int y1 = logicalTop; + int y2 = logicalTop + logicalHeight; + ASSERT(y2 >= y1); + if (y2 < intervals.bounds().y() || y1 >= intervals.bounds().maxY()) return; - IntShapeIntervals includedIntervals; - intervals.getIncludedIntervals(logicalTop, logicalTop + logicalHeight, includedIntervals); - appendLineSegments(includedIntervals, result); -} + y1 = std::max(y1, intervals.bounds().y()); + y2 = std::min(y2, intervals.bounds().maxY()); + IntShapeInterval excludedInterval; -bool RasterShape::firstIncludedIntervalLogicalTop(LayoutUnit minLogicalIntervalTop, const LayoutSize& minLogicalIntervalSize, LayoutUnit& result) const -{ - const RasterShapeIntervals& intervals = paddingIntervals(); - if (intervals.isEmpty()) - return false; + for (int y = y1; y < y2; y++) + excludedInterval.unite(intervals.intervalAt(y)); - return intervals.firstIncludedIntervalY(minLogicalIntervalTop.floor(), flooredIntSize(minLogicalIntervalSize), result); + // Note: |marginIntervals()| returns end-point exclusive + // intervals. |excludedInterval.x2()| contains the left-most pixel + // offset to the right of the calculated union. + result.append(LineSegment(excludedInterval.x1(), excludedInterval.x2())); } } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/shapes/RasterShape.h b/chromium/third_party/WebKit/Source/core/rendering/shapes/RasterShape.h index 903eabb0527..0ca8d8a5ba9 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/shapes/RasterShape.h +++ b/chromium/third_party/WebKit/Source/core/rendering/shapes/RasterShape.h @@ -40,74 +40,69 @@ namespace WebCore { class RasterShapeIntervals { 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; - -private: - int size() const { return m_intervalLists.size(); } - - IntShapeIntervals& intervalsAt(int y) + IntShapeInterval& intervalAt(int y) { - ASSERT(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(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(); - } + PassOwnPtr<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) - : Shape() - , m_intervals(intervals) - , m_imageSize(imageSize) + RasterShape(PassOwnPtr<RasterShapeIntervals> intervals, const IntSize& marginRectSize) + : m_intervals(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 LayoutSize& minLogicalIntervalSize, LayoutUnit&) const OVERRIDE; + virtual void buildDisplayPaths(DisplayPaths& paths) const OVERRIDE + { + m_intervals->buildBoundsPath(paths.shape); + if (shapeMargin()) + marginIntervals().buildBoundsPath(paths.marginShape); + } private: const RasterShapeIntervals& marginIntervals() const; - const RasterShapeIntervals& paddingIntervals() const; OwnPtr<RasterShapeIntervals> m_intervals; mutable OwnPtr<RasterShapeIntervals> m_marginIntervals; - IntSize m_imageSize; + IntSize m_marginRectSize; }; } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/shapes/RectangleShape.cpp b/chromium/third_party/WebKit/Source/core/rendering/shapes/RectangleShape.cpp index efe1f69831b..eaf51424c83 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/shapes/RectangleShape.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/shapes/RectangleShape.cpp @@ -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); @@ -79,8 +59,8 @@ void RectangleShape::getExcludedIntervals(LayoutUnit logicalTop, LayoutUnit logi if (bounds.isEmpty()) return; - float y1 = logicalTop; - float y2 = logicalTop + logicalHeight; + float y1 = logicalTop.toFloat(); + float y2 = (logicalTop + logicalHeight).toFloat(); if (y2 < bounds.y() || y1 >= bounds.maxY()) return; @@ -108,112 +88,11 @@ void RectangleShape::getExcludedIntervals(LayoutUnit logicalTop, LayoutUnit logi result.append(LineSegment(x1, x2)); } -void RectangleShape::getIncludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList& result) const +void RectangleShape::buildDisplayPaths(DisplayPaths& paths) 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 LayoutSize& 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 = LayoutUnit::fromFloatCeil(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 = 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 = minY; - return true; - } - if (minIntervalHeight < bounds.height() - (2 * cornerIntercept.y())) { - result = LayoutUnit::fromFloatCeil(bounds.y() + cornerIntercept.y()); - return true; - } - } - - if (intervalOverlapsMaxCorner && (!intervalOverlapsMinCorner || !minCornerDefinesX)) { - if (intervalFitsWithinCorners || minY <= bounds.maxY() - cornerIntercept.y() - minIntervalHeight) { - result = minY; - return true; - } - } - - return false; + paths.shape.addRoundedRect(m_bounds, m_radii); + if (shapeMargin()) + paths.marginShape.addRoundedRect(shapeMarginBounds(), FloatSize(m_radii.width() + shapeMargin(), m_radii.height() + shapeMargin())); } } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/shapes/RectangleShape.h b/chromium/third_party/WebKit/Source/core/rendering/shapes/RectangleShape.h index 9a9dae5522e..d47471da48f 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/shapes/RectangleShape.h +++ b/chromium/third_party/WebKit/Source/core/rendering/shapes/RectangleShape.h @@ -39,7 +39,7 @@ namespace WebCore { -class RectangleShape : public Shape { +class RectangleShape FINAL : public Shape { public: RectangleShape(const FloatRect& bounds, const FloatSize& radii) : Shape() @@ -49,15 +49,12 @@ 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 LayoutSize& minLogicalIntervalSize, LayoutUnit&) const OVERRIDE; + virtual 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(); } diff --git a/chromium/third_party/WebKit/Source/core/rendering/shapes/Shape.cpp b/chromium/third_party/WebKit/Source/core/rendering/shapes/Shape.cpp index ffe05053133..6e382254b9a 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/shapes/Shape.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/shapes/Shape.cpp @@ -30,14 +30,16 @@ #include "config.h" #include "core/rendering/shapes/Shape.h" +#include "core/css/BasicShapeFunctions.h" #include "core/fetch/ImageResource.h" #include "core/rendering/shapes/BoxShape.h" #include "core/rendering/shapes/PolygonShape.h" #include "core/rendering/shapes/RasterShape.h" #include "core/rendering/shapes/RectangleShape.h" +#include "core/rendering/style/RenderStyle.h" #include "platform/LengthFunctions.h" -#include "platform/geometry/FloatRoundedRect.h" #include "platform/geometry/FloatSize.h" +#include "platform/graphics/GraphicsContext.h" #include "platform/graphics/ImageBuffer.h" #include "platform/graphics/WindRule.h" #include "wtf/MathExtras.h" @@ -45,18 +47,12 @@ namespace WebCore { -static PassOwnPtr<Shape> createBoxShape(const FloatRoundedRect& bounds) +static PassOwnPtr<Shape> createInsetShape(const FloatRoundedRect& bounds) { ASSERT(bounds.rect().width() >= 0 && bounds.rect().height() >= 0); return adoptPtr(new 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) { ASSERT(radius >= 0); @@ -99,55 +95,22 @@ 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) +PassOwnPtr<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(); + float boxWidth = horizontalWritingMode ? logicalBoxSize.width().toFloat() : logicalBoxSize.height().toFloat(); + float boxHeight = horizontalWritingMode ? logicalBoxSize.height().toFloat() : logicalBoxSize.width().toFloat(); 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; - } - case BasicShape::BasicShapeCircleType: { const BasicShapeCircle* circle = static_cast<const BasicShapeCircle*>(basicShape); - float centerX = floatValueForLength(circle->centerX(), boxWidth); - float centerY = floatValueForLength(circle->centerY(), boxHeight); - // This method of computing the radius is as defined in SVG - // (http://www.w3.org/TR/SVG/coords.html#Units). It bases the radius - // off of the diagonal of the box and ensures that if the box is - // square, the radius is equal to half the diagonal. - float radius = floatValueForLength(circle->radius(), sqrtf((boxWidth * boxWidth + boxHeight * boxHeight) / 2)); - FloatPoint logicalCenter = physicalPointToLogical(FloatPoint(centerX, centerY), logicalBoxSize.height(), writingMode); + FloatPoint center = floatPointForCenterCoordinate(circle->centerX(), circle->centerY(), FloatSize(boxWidth, boxHeight)); + float radius = circle->floatValueForRadiusInBox(FloatSize(boxWidth, boxHeight)); + FloatPoint logicalCenter = physicalPointToLogical(center, logicalBoxSize.height().toFloat(), writingMode); shape = createCircleShape(logicalCenter, radius); break; @@ -155,14 +118,12 @@ PassOwnPtr<Shape> Shape::createShape(const BasicShape* basicShape, const LayoutS case BasicShape::BasicShapeEllipseType: { const BasicShapeEllipse* ellipse = static_cast<const BasicShapeEllipse*>(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); + FloatPoint center = floatPointForCenterCoordinate(ellipse->centerX(), ellipse->centerY(), FloatSize(boxWidth, boxHeight)); + float radiusX = ellipse->floatValueForRadiusInBox(ellipse->radiusX(), center.x(), boxWidth); + float radiusY = ellipse->floatValueForRadiusInBox(ellipse->radiusY(), center.y(), boxHeight); + FloatPoint logicalCenter = physicalPointToLogical(center, logicalBoxSize.height().toFloat(), writingMode); + + shape = createEllipseShape(logicalCenter, FloatSize(radiusX, radiusY)); break; } @@ -176,28 +137,31 @@ PassOwnPtr<Shape> Shape::createShape(const BasicShape* basicShape, const LayoutS FloatPoint vertex( floatValueForLength(values.at(i), boxWidth), floatValueForLength(values.at(i + 1), boxHeight)); - (*vertices)[i / 2] = physicalPointToLogical(vertex, logicalBoxSize.height(), writingMode); + (*vertices)[i / 2] = physicalPointToLogical(vertex, logicalBoxSize.height().toFloat(), 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)); + case BasicShape::BasicShapeInsetType: { + const BasicShapeInset& inset = *static_cast<const BasicShapeInset*>(basicShape); + float left = floatValueForLength(inset.left(), boxWidth); + float top = floatValueForLength(inset.top(), boxHeight); + float right = floatValueForLength(inset.right(), boxWidth); + float bottom = floatValueForLength(inset.bottom(), boxHeight); + FloatRect rect(left, top, std::max<float>(boxWidth - left - right, 0), std::max<float>(boxHeight - top - bottom, 0)); + FloatRect logicalRect = physicalRectToLogical(rect, logicalBoxSize.height().toFloat(), writingMode); + + 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; } @@ -206,61 +170,60 @@ 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(); } -PassOwnPtr<Shape> Shape::createShape(const StyleImage* styleImage, float threshold, const LayoutSize&, WritingMode writingMode, Length margin, Length padding) +PassOwnPtr<Shape> Shape::createRasterShape(Image* image, float threshold, const LayoutRect& imageR, const LayoutRect& marginR, WritingMode writingMode, float margin) { - ASSERT(styleImage && styleImage->isImageResource() && styleImage->cachedImage() && styleImage->cachedImage()->image()); + IntRect imageRect = pixelSnappedIntRect(imageR); + IntRect marginRect = pixelSnappedIntRect(marginR); + OwnPtr<RasterShapeIntervals> intervals = adoptPtr(new RasterShapeIntervals(marginRect.height(), -marginRect.y())); + OwnPtr<ImageBuffer> imageBuffer = ImageBuffer::create(imageRect.size()); - Image* image = styleImage->cachedImage()->image(); - const IntSize& imageSize = image->size(); - OwnPtr<RasterShapeIntervals> intervals = adoptPtr(new RasterShapeIntervals(imageSize.height())); - OwnPtr<ImageBuffer> imageBuffer = ImageBuffer::create(imageSize); if (imageBuffer) { GraphicsContext* graphicsContext = imageBuffer->context(); - graphicsContext->drawImage(image, IntPoint()); + graphicsContext->drawImage(image, IntRect(IntPoint(), imageRect.size())); - RefPtr<Uint8ClampedArray> pixelArray = imageBuffer->getUnmultipliedImageData(IntRect(IntPoint(), imageSize)); - unsigned pixelArrayLength = pixelArray->length(); + RefPtr<Uint8ClampedArray> pixelArray = imageBuffer->getUnmultipliedImageData(IntRect(IntPoint(), imageRect.size())); unsigned pixelArrayOffset = 3; // Each pixel is four bytes: RGBA. uint8_t alphaPixelThreshold = threshold * 255; - ASSERT(static_cast<unsigned>(imageSize.width() * imageSize.height() * 4) == pixelArrayLength); + ASSERT(static_cast<unsigned>(imageRect.width() * imageRect.height() * 4) == pixelArray->length()); + + int minBufferY = std::max(0, marginRect.y() - imageRect.y()); + int maxBufferY = std::min(imageRect.height(), marginRect.maxY() - imageRect.y()); - for (int y = 0; y < imageSize.height(); ++y) { + for (int y = minBufferY; y < maxBufferY; ++y) { int startX = -1; - for (int x = 0; x < imageSize.width() && pixelArrayOffset < pixelArrayLength; ++x, pixelArrayOffset += 4) { + for (int x = 0; x < imageRect.width(); ++x, pixelArrayOffset += 4) { uint8_t alpha = pixelArray->item(pixelArrayOffset); - if ((startX == -1) && alpha > alphaPixelThreshold) { + bool alphaAboveThreshold = alpha > alphaPixelThreshold; + if (startX == -1 && alphaAboveThreshold) { startX = x; - } else if (startX != -1 && (alpha <= alphaPixelThreshold || x == imageSize.width() - 1)) { - intervals->appendInterval(y, startX, x); + } else if (startX != -1 && (!alphaAboveThreshold || x == imageRect.width() - 1)) { + int endX = alphaAboveThreshold ? x + 1 : x; + intervals->intervalAt(y + imageRect.y()).unite(IntShapeInterval(startX + imageRect.x(), endX + imageRect.x())); startX = -1; } } } } - OwnPtr<RasterShape> rasterShape = adoptPtr(new RasterShape(intervals.release(), imageSize)); + OwnPtr<RasterShape> rasterShape = adoptPtr(new RasterShape(intervals.release(), marginRect.size())); rasterShape->m_writingMode = writingMode; - rasterShape->m_margin = floatValueForLength(margin, 0); - rasterShape->m_padding = floatValueForLength(padding, 0); + rasterShape->m_margin = margin; return rasterShape.release(); } -PassOwnPtr<Shape> Shape::createLayoutBoxShape(const LayoutSize& logicalSize, WritingMode writingMode, const Length& margin, const Length& padding) +PassOwnPtr<Shape> Shape::createLayoutBoxShape(const RoundedRect& roundedRect, WritingMode writingMode, float margin) { - FloatRect rect(0, 0, logicalSize.width(), logicalSize.height()); - FloatSize radii(0, 0); - FloatRoundedRect bounds(rect, radii, radii, radii, radii); - OwnPtr<Shape> shape = createBoxShape(bounds); + FloatRect rect(0, 0, roundedRect.rect().width(), roundedRect.rect().height()); + FloatRoundedRect bounds(rect, roundedRect.radii()); + OwnPtr<Shape> shape = createInsetShape(bounds); shape->m_writingMode = writingMode; - shape->m_margin = floatValueForLength(margin, 0); - shape->m_padding = floatValueForLength(padding, 0); + shape->m_margin = margin; return shape.release(); } diff --git a/chromium/third_party/WebKit/Source/core/rendering/shapes/Shape.h b/chromium/third_party/WebKit/Source/core/rendering/shapes/Shape.h index de9aef9f99d..fb649957671 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/shapes/Shape.h +++ b/chromium/third_party/WebKit/Source/core/rendering/shapes/Shape.h @@ -33,6 +33,8 @@ #include "core/rendering/style/BasicShapes.h" #include "core/rendering/style/StyleImage.h" #include "platform/geometry/LayoutRect.h" +#include "platform/geometry/RoundedRect.h" +#include "platform/graphics/Path.h" #include "platform/text/WritingMode.h" #include "wtf/PassOwnPtr.h" #include "wtf/Vector.h" @@ -60,24 +62,25 @@ typedef Vector<LineSegment> SegmentList; class Shape { public: - static PassOwnPtr<Shape> createShape(const BasicShape*, const LayoutSize& logicalBoxSize, WritingMode, Length margin, Length padding); - static PassOwnPtr<Shape> createShape(const StyleImage*, float threshold, const LayoutSize& logicalBoxSize, WritingMode, Length margin, Length padding); - static PassOwnPtr<Shape> createLayoutBoxShape(const LayoutSize& logicalBoxSize, WritingMode, const Length& margin, const Length& padding); + struct DisplayPaths { + Path shape; + Path marginShape; + }; + static PassOwnPtr<Shape> createShape(const BasicShape*, const LayoutSize& logicalBoxSize, WritingMode, float margin); + static PassOwnPtr<Shape> createRasterShape(Image*, float threshold, const LayoutRect& imageRect, const LayoutRect& marginRect, WritingMode, float margin); + static PassOwnPtr<Shape> createLayoutBoxShape(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 LayoutSize& minLogicalIntervalSize, LayoutUnit& result) 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 @@ -89,7 +92,6 @@ private: WritingMode m_writingMode; float m_margin; - float m_padding; }; } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeInfo.cpp b/chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeInfo.cpp deleted file mode 100644 index e2668712991..00000000000 --- a/chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeInfo.cpp +++ /dev/null @@ -1,101 +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 "core/rendering/shapes/ShapeInfo.h" - -#include "core/rendering/RenderRegion.h" - -namespace WebCore { - -bool checkShapeImageOrigin(Document& document, ImageResource& imageResource) -{ - if (imageResource.isAccessAllowed(document.securityOrigin())) - return true; - - const KURL& url = imageResource.url(); - String urlString = url.isNull() ? "''" : url.elidedString(); - document.addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, "Unsafe attempt to load URL " + urlString + "."); - - return false; -} - -template<class RenderType> -const Shape* ShapeInfo<RenderType>::computedShape() const -{ - if (Shape* shape = m_shape.get()) - return shape; - - WritingMode writingMode = m_renderer->style()->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()); - m_shape = Shape::createShape(shapeValue->image(), shapeImageThreshold, m_shapeLogicalSize, writingMode, margin, padding); - break; - case ShapeValue::Box: - m_shape = Shape::createLayoutBoxShape(m_shapeLogicalSize, 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.get(); -} - -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>; -} diff --git a/chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeInfo.h b/chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeInfo.h deleted file mode 100644 index 1314f3409c1..00000000000 --- a/chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeInfo.h +++ /dev/null @@ -1,179 +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 - -#include "core/rendering/shapes/Shape.h" -#include "core/rendering/style/RenderStyle.h" -#include "core/rendering/style/ShapeValue.h" -#include "platform/LayoutUnit.h" -#include "platform/geometry/FloatRect.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, InfoType::createInfo(key)); - return result.iterator->value.get(); - } - static void removeInfo(const KeyType* key) { infoMap().remove(key); } - static InfoType* info(const KeyType* key) { return infoMap().get(key); } -private: - typedef HashMap<const KeyType*, OwnPtr<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) - { - if (shapeValue()->type() == ShapeValue::Box) { - switch (shapeValue()->layoutBox()) { - 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; - } - } else if (m_renderer->style()->boxSizing() == CONTENT_BOX) { - logicalHeight -= m_renderer->borderAndPaddingLogicalHeight(); - logicalWidth -= m_renderer->borderAndPaddingLogicalWidth(); - } - - 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 shapeContainingBlockHeight() 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; } - -protected: - ShapeInfo(const RenderType* renderer): m_renderer(renderer) { } - - const Shape* computedShape() const; - - virtual LayoutRect computedShapeLogicalBoundingBox() const = 0; - virtual ShapeValue* shapeValue() const = 0; - virtual void getIntervals(LayoutUnit, LayoutUnit, SegmentList&) const = 0; - - LayoutUnit logicalTopOffset() const - { - if (shapeValue()->type() == ShapeValue::Box) { - switch (shapeValue()->layoutBox()) { - case MarginBox: - return -m_renderer->marginBefore(); - case BorderBox: - return LayoutUnit(); - case PaddingBox: - return m_renderer->borderBefore(); - case ContentBox: - return m_renderer->borderAndPaddingBefore(); - } - } - return m_renderer->style()->boxSizing() == CONTENT_BOX ? m_renderer->borderAndPaddingBefore() : LayoutUnit(); - } - - LayoutUnit logicalLeftOffset() const - { - if (shapeValue()->type() == ShapeValue::Box) { - switch (shapeValue()->layoutBox()) { - case MarginBox: - return -m_renderer->marginStart(); - case BorderBox: - return LayoutUnit(); - case PaddingBox: - return m_renderer->borderStart(); - case ContentBox: - return m_renderer->borderAndPaddingStart(); - } - } - return (m_renderer->style()->boxSizing() == CONTENT_BOX && !m_renderer->isRenderRegion()) ? m_renderer->borderAndPaddingStart() : LayoutUnit(); - } - - LayoutUnit m_shapeLineTop; - LayoutUnit m_lineHeight; - - const RenderType* m_renderer; - -private: - mutable OwnPtr<Shape> m_shape; - LayoutSize m_shapeLogicalSize; -}; - -bool checkShapeImageOrigin(Document&, ImageResource&); - -} -#endif diff --git a/chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeInsideInfo.cpp b/chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeInsideInfo.cpp deleted file mode 100644 index 301200b19e7..00000000000 --- a/chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeInsideInfo.cpp +++ /dev/null @@ -1,121 +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 "core/rendering/shapes/ShapeInsideInfo.h" - -#include "core/rendering/InlineIterator.h" -#include "core/rendering/RenderBlock.h" - -namespace WebCore { - -LineSegmentRange::LineSegmentRange(const InlineIterator& start, const InlineIterator& end) - : start(start.root(), start.object(), start.offset()) - , end(end.root(), end.object(), 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; - case ShapeValue::Image: - return shapeValue->isImageValid() && checkShapeImageOrigin(renderer->document(), *(shapeValue->image()->cachedImage())); - case ShapeValue::Box: - case ShapeValue::Outside: - return false; - } - - return false; -} - -bool ShapeInsideInfo::updateSegmentsForLine(LayoutSize lineOffset, LayoutUnit lineHeight) -{ - 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 (!shape || m_lineHeight <= 0 || logicalLineTop() > shapeLogicalBottom()) - return false; - - LayoutUnit newLineTop; - if (shape->firstIncludedIntervalLogicalTop(m_shapeLineTop, LayoutSize(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 LayoutSize floatSize) const -{ - if (!computedShape() || !floatSize.width() || shapeLogicalBottom() < logicalLineTop()) - return 0; - - LayoutUnit firstFitPosition = 0; - if (computedShape()->firstIncludedIntervalLogicalTop(m_shapeLineTop, floatSize, firstFitPosition) && (m_shapeLineTop <= firstFitPosition)) - return firstFitPosition; - - return 0; -} - -} diff --git a/chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeInsideInfo.h b/chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeInsideInfo.h deleted file mode 100644 index 0f0f3855266..00000000000 --- a/chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeInsideInfo.h +++ /dev/null @@ -1,122 +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 - -#include "core/rendering/shapes/ShapeInfo.h" -#include "wtf/PassOwnPtr.h" -#include "wtf/Vector.h" - -namespace WebCore { - -class InlineIterator; -class RenderBlock; -class RenderObject; - -struct LineSegmentIterator { - RenderObject* root; - RenderObject* object; - unsigned offset; - LineSegmentIterator(RenderObject* 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: - static PassOwnPtr<ShapeInsideInfo> createInfo(const RenderBlock* renderer) { return adoptPtr(new ShapeInsideInfo(renderer)); } - - 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 LayoutSize) 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 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); - } - -private: - ShapeInsideInfo(const RenderBlock* renderer) - : ShapeInfo<RenderBlock> (renderer) - , m_needsLayout(false) - { } - - SegmentRangeList m_segmentRanges; - bool m_needsLayout; - SegmentList m_segments; -}; - -} -#endif diff --git a/chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeInterval.h b/chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeInterval.h index efeb7d862c0..47c20178f0f 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeInterval.h +++ b/chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeInterval.h @@ -38,29 +38,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,155 +69,34 @@ 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) - { - 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()); - 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; - } - } - } + bool operator==(const ShapeInterval<T>& other) const { return x1() == other.x1() && x2() == other.x2(); } + bool operator!=(const ShapeInterval<T>& other) const { return !operator==(other); } - static void subtractShapeIntervals(const ShapeIntervals& a, const ShapeIntervals& b, ShapeIntervals& result) + void unite(const ShapeInterval<T>& interval) { - ASSERT(shapeIntervalsAreSortedAndDisjoint(a) && shapeIntervalsAreSortedAndDisjoint(b)); - - if (a.isEmpty() || a == b) - return; - - if (b.isEmpty()) { - result.appendRange(a.begin(), a.end()); + if (interval.isUndefined()) 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(); } - bool operator!=(const ShapeInterval<T>& other) const { return !operator==(other); } - 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; diff --git a/chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeOutsideInfo.cpp b/chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeOutsideInfo.cpp index 98bea9a0a16..216d3091acf 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeOutsideInfo.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeOutsideInfo.cpp @@ -33,48 +33,269 @@ #include "core/rendering/FloatingObjects.h" #include "core/rendering/RenderBlockFlow.h" #include "core/rendering/RenderBox.h" +#include "core/rendering/RenderImage.h" +#include "platform/LengthFunctions.h" namespace WebCore { -bool ShapeOutsideInfo::isEnabledFor(const RenderBox* box) + +CSSBoxType referenceBox(const ShapeValue& shapeValue) +{ + if (shapeValue.cssBox() == BoxMissing) + 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.marginWidth(), m_renderer.marginHeight()); + else + newReferenceBoxLogicalSize.expand(m_renderer.marginHeight(), m_renderer.marginWidth()); + break; + case BorderBox: + break; + case PaddingBox: + if (isHorizontalWritingMode) + newReferenceBoxLogicalSize.shrink(m_renderer.borderWidth(), m_renderer.borderHeight()); + else + newReferenceBoxLogicalSize.shrink(m_renderer.borderHeight(), m_renderer.borderWidth()); + break; + case ContentBox: + if (isHorizontalWritingMode) + newReferenceBoxLogicalSize.shrink(m_renderer.borderAndPaddingWidth(), m_renderer.borderAndPaddingHeight()); + else + newReferenceBoxLogicalSize.shrink(m_renderer.borderAndPaddingHeight(), m_renderer.borderAndPaddingWidth()); + break; + case BoxMissing: + ASSERT_NOT_REACHED(); + break; + } + + if (m_referenceBoxLogicalSize == newReferenceBoxLogicalSize) + return; + markShapeAsDirty(); + m_referenceBoxLogicalSize = newReferenceBoxLogicalSize; +} + +static bool checkShapeImageOrigin(Document& document, const StyleImage& styleImage) { - ShapeValue* shapeValue = box->style()->shapeOutside(); - if (!box->isFloating() || !shapeValue) + if (styleImage.isGeneratedImage()) + return true; + + ASSERT(styleImage.cachedImage()); + ImageResource& imageResource = *(styleImage.cachedImage()); + if (imageResource.isAccessAllowed(document.securityOrigin())) + return true; + + const KURL& url = imageResource.url(); + String urlString = url.isNull() ? "''" : url.elidedString(); + document.addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, "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()); + return LayoutRect(marginBoxOrigin, referenceBoxLogicalSize + marginBoxSizeDelta); +} + +PassOwnPtr<Shape> ShapeOutsideInfo::createShapeForImage(StyleImage* styleImage, float shapeImageThreshold, WritingMode writingMode, float margin) const +{ + const IntSize& imageSize = m_renderer.calculateImageIntrinsicDimensions(styleImage, roundedIntSize(m_referenceBoxLogicalSize), RenderImage::ScaleByEffectiveZoom); + styleImage->setContainerSizeForRenderer(&m_renderer, imageSize, m_renderer.style()->effectiveZoom()); + + const LayoutRect& marginRect = getShapeImageMarginRect(m_renderer, m_referenceBoxLogicalSize); + const LayoutRect& imageRect = (m_renderer.isRenderImage()) + ? toRenderImage(&m_renderer)->replacedContentRect() + : LayoutRect(LayoutPoint(), imageSize); + + ASSERT(!styleImage->isPendingImage()); + 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(); + LayoutUnit maximumValue = m_renderer.containingBlock() ? m_renderer.containingBlock()->contentWidth() : LayoutUnit(); + float margin = floatValueForLength(m_renderer.style()->shapeMargin(), maximumValue.toFloat()); + + float shapeImageThreshold = style.shapeImageThreshold(); + ASSERT(style.shapeOutside()); + const ShapeValue& shapeValue = *style.shapeOutside(); + + switch (shapeValue.type()) { + case ShapeValue::Shape: + ASSERT(shapeValue.shape()); + m_shape = Shape::createShape(shapeValue.shape(), m_referenceBoxLogicalSize, writingMode, margin); + break; + case ShapeValue::Image: + ASSERT(shapeValue.isImageValid()); + m_shape = createShapeForImage(shapeValue.image(), shapeImageThreshold, writingMode, margin); + break; + case ShapeValue::Box: { + const RoundedRect& shapeRect = style.getRoundedBorderFor(LayoutRect(LayoutPoint(), m_referenceBoxLogicalSize), m_renderer.view()); + m_shape = Shape::createLayoutBoxShape(shapeRect, writingMode, margin); + break; + } + } + + ASSERT(m_shape); + return *m_shape; +} + +SegmentList ShapeOutsideInfo::computeSegmentsForLine(LayoutUnit lineTop, LayoutUnit lineHeight) const +{ + ASSERT(lineHeight >= 0); + SegmentList segments; + + computedShape().getExcludedIntervals((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; +} + +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(); +} + +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 BoxMissing: break; + } + + ASSERT_NOT_REACHED(); + return LayoutUnit(); +} + +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(); +} + +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 +{ + 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 BoxMissing: break; + } + + ASSERT_NOT_REACHED(); + return LayoutUnit(); +} + + +bool ShapeOutsideInfo::isEnabledFor(const RenderBox& box) +{ + ShapeValue* shapeValue = box.style()->shapeOutside(); + if (!box.isFloating() || !shapeValue) return false; switch (shapeValue->type()) { case ShapeValue::Shape: return shapeValue->shape(); case ShapeValue::Image: - return shapeValue->isImageValid() && checkShapeImageOrigin(box->document(), *(shapeValue->image()->cachedImage())); + return shapeValue->isImageValid() && checkShapeImageOrigin(box.document(), *(shapeValue->image())); case ShapeValue::Box: return true; - case ShapeValue::Outside: - return false; } return false; } -void ShapeOutsideInfo::updateDeltasForContainingBlockLine(const RenderBlockFlow* containingBlock, const FloatingObject* floatingObject, LayoutUnit lineTop, LayoutUnit lineHeight) +void ShapeOutsideInfo::updateDeltasForContainingBlockLine(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; + 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(); + if (isShapeDirty() || m_borderBoxLineTop != borderBoxLineTop || m_lineHeight != lineHeight) { + m_borderBoxLineTop = borderBoxLineTop; + m_referenceBoxLineTop = borderBoxLineTop - logicalTopOffset(); m_lineHeight = lineHeight; - LayoutUnit floatMarginBoxWidth = containingBlock->logicalWidthForFloat(floatingObject); + LayoutUnit floatMarginBoxWidth = containingBlock.logicalWidthForFloat(&floatingObject); if (lineOverlapsShapeBounds()) { - SegmentList segments = computeSegmentsForLine(floatRelativeLineTop, lineHeight); + SegmentList segments = computeSegmentsForLine(borderBoxLineTop, lineHeight); if (segments.size()) { - LayoutUnit rawLeftMarginBoxDelta = segments.first().logicalLeft + containingBlock->marginStartForChild(m_renderer); - m_leftMarginBoxDelta = clampTo<LayoutUnit>(rawLeftMarginBoxDelta, LayoutUnit(), floatMarginBoxWidth); + LayoutUnit logicalLeftMargin = containingBlock.style()->isLeftToRightDirection() ? containingBlock.marginStartForChild(&m_renderer) : containingBlock.marginEndForChild(&m_renderer); + LayoutUnit rawLeftMarginBoxDelta = segments.first().logicalLeft + logicalLeftMargin; + m_leftMarginBoxDelta = clampToLayoutUnit(rawLeftMarginBoxDelta, LayoutUnit(), floatMarginBoxWidth); - LayoutUnit rawRightMarginBoxDelta = segments.last().logicalRight - containingBlock->logicalWidthForChild(m_renderer) - containingBlock->marginEndForChild(m_renderer); - m_rightMarginBoxDelta = clampTo<LayoutUnit>(rawRightMarginBoxDelta, -floatMarginBoxWidth, LayoutUnit()); + LayoutUnit logicalRightMargin = containingBlock.style()->isLeftToRightDirection() ? containingBlock.marginEndForChild(&m_renderer) : containingBlock.marginStartForChild(&m_renderer); + LayoutUnit rawRightMarginBoxDelta = segments.last().logicalRight - containingBlock.logicalWidthForChild(&m_renderer) - logicalRightMargin; + m_rightMarginBoxDelta = clampToLayoutUnit(rawRightMarginBoxDelta, -floatMarginBoxWidth, LayoutUnit()); + m_lineOverlapsShape = true; return; } } @@ -82,19 +303,45 @@ void ShapeOutsideInfo::updateDeltasForContainingBlockLine(const RenderBlockFlow* // 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. - // FIXME: The latest CSS Shapes spec says that in this case, the - // content should interact with previously stacked floats on the line - // as if this outermost float did not exist. Perhaps obviously, this - // solution cannot do that, and will be revisted when that part of the - // spec is implemented. m_leftMarginBoxDelta = floatMarginBoxWidth; m_rightMarginBoxDelta = -floatMarginBoxWidth; + m_lineOverlapsShape = false; } } -ShapeValue* ShapeOutsideInfo::shapeValue() const +LayoutRect ShapeOutsideInfo::computedShapePhysicalBoundingBox() const +{ + LayoutRect physicalBoundingBox = computedShape().shapeMarginLogicalBoundingBox(); + physicalBoundingBox.setX(physicalBoundingBox.x() + logicalLeftOffset()); + + if (m_renderer.style()->isFlippedBlocksWritingMode()) + physicalBoundingBox.setY(m_renderer.logicalHeight() - physicalBoundingBox.maxY()); + else + physicalBoundingBox.setY(physicalBoundingBox.y() + logicalTopOffset()); + + if (!m_renderer.style()->isHorizontalWritingMode()) + physicalBoundingBox = physicalBoundingBox.transposedRect(); + else + physicalBoundingBox.setY(physicalBoundingBox.y() + logicalTopOffset()); + + return physicalBoundingBox; +} + +FloatPoint ShapeOutsideInfo::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 ShapeOutsideInfo::shapeToRendererSize(FloatSize size) const { - return m_renderer->style()->shapeOutside(); + if (!m_renderer.style()->isHorizontalWritingMode()) + return size.transposedSize(); + return size; } } diff --git a/chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeOutsideInfo.h b/chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeOutsideInfo.h index 82b31f65f69..36276e91fdb 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeOutsideInfo.h +++ b/chromium/third_party/WebKit/Source/core/rendering/shapes/ShapeOutsideInfo.h @@ -30,8 +30,13 @@ #ifndef ShapeOutsideInfo_h #define ShapeOutsideInfo_h -#include "core/rendering/shapes/ShapeInfo.h" +#include "core/rendering/shapes/Shape.h" +#include "core/rendering/style/RenderStyle.h" +#include "core/rendering/style/ShapeValue.h" +#include "platform/geometry/FloatRect.h" #include "platform/geometry/LayoutSize.h" +#include "wtf/OwnPtr.h" +#include "wtf/Vector.h" namespace WebCore { @@ -39,35 +44,85 @@ class RenderBlockFlow; class RenderBox; class FloatingObject; -class ShapeOutsideInfo FINAL : public ShapeInfo<RenderBox>, public MappedInfo<RenderBox, ShapeOutsideInfo> { +class ShapeOutsideInfo FINAL { + WTF_MAKE_FAST_ALLOCATED; public: + void setReferenceBoxLogicalSize(LayoutSize); + + SegmentList computeSegmentsForLine(LayoutUnit lineTop, LayoutUnit lineHeight) const; + + 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(); } + + LayoutUnit logicalLineTop() const { return m_referenceBoxLineTop + logicalTopOffset(); } + LayoutUnit logicalLineBottom() const { return m_referenceBoxLineTop + m_lineHeight + logicalTopOffset(); } + LayoutUnit leftMarginBoxDelta() const { return m_leftMarginBoxDelta; } LayoutUnit rightMarginBoxDelta() const { return m_rightMarginBoxDelta; } + bool lineOverlapsShape() const { return m_lineOverlapsShape; } - void updateDeltasForContainingBlockLine(const RenderBlockFlow*, const FloatingObject*, LayoutUnit lineTop, LayoutUnit lineHeight); + static PassOwnPtr<ShapeOutsideInfo> createInfo(const RenderBox& renderer) { return adoptPtr(new ShapeOutsideInfo(renderer)); } + static bool isEnabledFor(const RenderBox&); + void updateDeltasForContainingBlockLine(const RenderBlockFlow&, const FloatingObject&, LayoutUnit lineTop, LayoutUnit lineHeight); - static PassOwnPtr<ShapeOutsideInfo> createInfo(const RenderBox* renderer) { return adoptPtr(new ShapeOutsideInfo(renderer)); } - static bool isEnabledFor(const RenderBox*); + bool lineOverlapsShapeBounds() const + { + return computedShape().lineOverlapsShapeMarginBounds(m_referenceBoxLineTop, m_lineHeight); + } - virtual bool lineOverlapsShapeBounds() const OVERRIDE + static ShapeOutsideInfo& ensureInfo(const RenderBox& key) { - return computedShape()->lineOverlapsShapeMarginBounds(m_shapeLineTop, m_lineHeight); + InfoMap& infoMap = ShapeOutsideInfo::infoMap(); + if (ShapeOutsideInfo* info = infoMap.get(&key)) + return *info; + InfoMap::AddResult result = infoMap.add(&key, ShapeOutsideInfo::createInfo(key)); + return *result.storedValue->value; } + static void removeInfo(const RenderBox& key) { infoMap().remove(&key); } + static ShapeOutsideInfo* info(const RenderBox& key) { return infoMap().get(&key); } + + void markShapeAsDirty() { m_shape.clear(); } + bool isShapeDirty() { return !m_shape.get(); } + LayoutSize shapeSize() const { return m_referenceBoxLogicalSize; } + + LayoutRect computedShapePhysicalBoundingBox() const; + FloatPoint shapeToRendererPoint(FloatPoint) const; + FloatSize shapeToRendererSize(FloatSize) const; + const Shape& computedShape() const; protected: - virtual LayoutRect computedShapeLogicalBoundingBox() const OVERRIDE { return computedShape()->shapeMarginLogicalBoundingBox(); } - virtual ShapeValue* shapeValue() const OVERRIDE; - virtual void getIntervals(LayoutUnit lineTop, LayoutUnit lineHeight, SegmentList& segments) const OVERRIDE + ShapeOutsideInfo(const RenderBox& renderer) + : m_renderer(renderer) + , m_lineOverlapsShape(false) + { } + +private: + PassOwnPtr<Shape> createShapeForImage(StyleImage*, float shapeImageThreshold, WritingMode, float margin) const; + + LayoutUnit logicalTopOffset() const; + LayoutUnit logicalLeftOffset() const; + + typedef HashMap<const RenderBox*, OwnPtr<ShapeOutsideInfo> > InfoMap; + static InfoMap& infoMap() { - return computedShape()->getExcludedIntervals(lineTop, lineHeight, segments); + DEFINE_STATIC_LOCAL(InfoMap, staticInfoMap, ()); + return staticInfoMap; } -private: - ShapeOutsideInfo(const RenderBox* renderer) : ShapeInfo<RenderBox>(renderer) { } + LayoutUnit m_referenceBoxLineTop; + LayoutUnit m_lineHeight; + const RenderBox& m_renderer; + mutable OwnPtr<Shape> m_shape; + LayoutSize m_referenceBoxLogicalSize; LayoutUnit m_leftMarginBoxDelta; LayoutUnit m_rightMarginBoxDelta; - LayoutUnit m_lineTop; + LayoutUnit m_borderBoxLineTop; + bool m_lineOverlapsShape; }; } |