Changeset 201868 in webkit
- Timestamp:
- Jun 9, 2016, 9:59:17 AM (10 years ago)
- Location:
- trunk
- Files:
-
- 7 added
- 4 edited
-
LayoutTests/ChangeLog (modified) (1 diff)
-
LayoutTests/fast/borders/border-non-renderable-radius-inner-clip-expected.html (added)
-
LayoutTests/fast/borders/border-non-renderable-radius-inner-clip.html (added)
-
LayoutTests/fast/borders/border-radius-inner-clip-expected-mismatch.html (added)
-
LayoutTests/fast/borders/border-radius-inner-clip-vertical-expected-mismatch.html (added)
-
LayoutTests/fast/borders/border-radius-inner-clip-vertical.html (added)
-
LayoutTests/fast/borders/border-radius-inner-clip.html (added)
-
LayoutTests/fast/borders/resources/border-radius-helpers.js (added)
-
Source/WebCore/ChangeLog (modified) (1 diff)
-
Source/WebCore/rendering/RenderBoxModelObject.cpp (modified) (11 diffs)
-
Source/WebCore/rendering/RenderBoxModelObject.h (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r201867 r201868 1 2016-06-09 Simon Fraser <simon.fraser@apple.com> 2 3 border-radius with different width and height rendered wrong 4 https://bugs.webkit.org/show_bug.cgi?id=158300 5 <rdar://problem/26672922> 6 7 Reviewed by Zalan Bujtas. 8 9 * fast/borders/border-non-renderable-radius-inner-clip-expected.html: Added. 10 * fast/borders/border-non-renderable-radius-inner-clip.html: Added. 11 * fast/borders/border-radius-inner-clip-expected-mismatch.html: Added. 12 * fast/borders/border-radius-inner-clip-vertical-expected-mismatch.html: Added. 13 * fast/borders/border-radius-inner-clip-vertical.html: Added. 14 * fast/borders/border-radius-inner-clip.html: Added. 15 * fast/borders/resources/border-radius-helpers.js: Added. 16 (createContainer): 17 (createReferenceContainer): 18 1 19 2016-06-09 Per Arne Vollan <pvollan@apple.com> 2 20 -
trunk/Source/WebCore/ChangeLog
r201864 r201868 1 2016-06-09 Simon Fraser <simon.fraser@apple.com> 2 3 border-radius with different width and height rendered wrong 4 https://bugs.webkit.org/show_bug.cgi?id=158300 5 <rdar://problem/26672922> 6 7 Reviewed by Zalan Bujtas. 8 9 Borders with border-radius close to 100% 100% got oddly clipped. This happened because 10 of the clipping we do to achieve the diagonal corner joins; RenderBoxModelObject::clipBorderSidePolygon() 11 created trapezoids for each side, but only extended them to the center of the inner border rect. 12 This clipped out parts of these borders. 13 14 Fix by computing the trapezoids by intersecting the corner diagonal line with a line that passes 15 through the adjacent corners of the inner rect, whose intersection is always going to be inside the 16 rounded border. Also fix the quads used to do the antialiased/non-antialiased clipping, 17 by adding a point rather than moving a corner point to ensure we don't mistakenly clip out any 18 parts of the border. 19 20 Finally, improve the rendering of non-renderable cases by actually doing the diagonal 21 corner joins rather than just giving up. 22 23 Tests: fast/borders/border-non-renderable-radius-inner-clip.html 24 fast/borders/border-radius-inner-clip-vertical.html 25 fast/borders/border-radius-inner-clip.html 26 27 * rendering/RenderBoxModelObject.cpp: 28 (WebCore::calculateAdjustedInnerBorder): Moved up. 29 (WebCore::RenderBoxModelObject::paintOneBorderSide): 30 (WebCore::RenderBoxModelObject::clipBorderSidePolygon): 31 (WebCore::findInnerVertex): Deleted. 32 (WebCore::calculateSideRectIncludingInner): Deleted. 33 (WebCore::RenderBoxModelObject::clipBorderSideForComplexInnerPath): Deleted. 34 * rendering/RenderBoxModelObject.h: 35 1 36 2016-06-09 Xabier Rodriguez Calvar <calvaris@igalia.com> 2 37 -
trunk/Source/WebCore/rendering/RenderBoxModelObject.cpp
r201629 r201868 1437 1437 } 1438 1438 1439 static RoundedRect calculateAdjustedInnerBorder(const RoundedRect&innerBorder, BoxSide side) 1440 { 1441 // Expand the inner border as necessary to make it a rounded rect (i.e. radii contained within each edge). 1442 // This function relies on the fact we only get radii not contained within each edge if one of the radii 1443 // for an edge is zero, so we can shift the arc towards the zero radius corner. 1444 RoundedRect::Radii newRadii = innerBorder.radii(); 1445 LayoutRect newRect = innerBorder.rect(); 1446 1447 float overshoot; 1448 float maxRadii; 1449 1450 switch (side) { 1451 case BSTop: 1452 overshoot = newRadii.topLeft().width() + newRadii.topRight().width() - newRect.width(); 1453 if (overshoot > 0) { 1454 ASSERT(!(newRadii.topLeft().width() && newRadii.topRight().width())); 1455 newRect.setWidth(newRect.width() + overshoot); 1456 if (!newRadii.topLeft().width()) 1457 newRect.move(-overshoot, 0); 1458 } 1459 newRadii.setBottomLeft(IntSize(0, 0)); 1460 newRadii.setBottomRight(IntSize(0, 0)); 1461 maxRadii = std::max(newRadii.topLeft().height(), newRadii.topRight().height()); 1462 if (maxRadii > newRect.height()) 1463 newRect.setHeight(maxRadii); 1464 break; 1465 1466 case BSBottom: 1467 overshoot = newRadii.bottomLeft().width() + newRadii.bottomRight().width() - newRect.width(); 1468 if (overshoot > 0) { 1469 ASSERT(!(newRadii.bottomLeft().width() && newRadii.bottomRight().width())); 1470 newRect.setWidth(newRect.width() + overshoot); 1471 if (!newRadii.bottomLeft().width()) 1472 newRect.move(-overshoot, 0); 1473 } 1474 newRadii.setTopLeft(IntSize(0, 0)); 1475 newRadii.setTopRight(IntSize(0, 0)); 1476 maxRadii = std::max(newRadii.bottomLeft().height(), newRadii.bottomRight().height()); 1477 if (maxRadii > newRect.height()) { 1478 newRect.move(0, newRect.height() - maxRadii); 1479 newRect.setHeight(maxRadii); 1480 } 1481 break; 1482 1483 case BSLeft: 1484 overshoot = newRadii.topLeft().height() + newRadii.bottomLeft().height() - newRect.height(); 1485 if (overshoot > 0) { 1486 ASSERT(!(newRadii.topLeft().height() && newRadii.bottomLeft().height())); 1487 newRect.setHeight(newRect.height() + overshoot); 1488 if (!newRadii.topLeft().height()) 1489 newRect.move(0, -overshoot); 1490 } 1491 newRadii.setTopRight(IntSize(0, 0)); 1492 newRadii.setBottomRight(IntSize(0, 0)); 1493 maxRadii = std::max(newRadii.topLeft().width(), newRadii.bottomLeft().width()); 1494 if (maxRadii > newRect.width()) 1495 newRect.setWidth(maxRadii); 1496 break; 1497 1498 case BSRight: 1499 overshoot = newRadii.topRight().height() + newRadii.bottomRight().height() - newRect.height(); 1500 if (overshoot > 0) { 1501 ASSERT(!(newRadii.topRight().height() && newRadii.bottomRight().height())); 1502 newRect.setHeight(newRect.height() + overshoot); 1503 if (!newRadii.topRight().height()) 1504 newRect.move(0, -overshoot); 1505 } 1506 newRadii.setTopLeft(IntSize(0, 0)); 1507 newRadii.setBottomLeft(IntSize(0, 0)); 1508 maxRadii = std::max(newRadii.topRight().width(), newRadii.bottomRight().width()); 1509 if (maxRadii > newRect.width()) { 1510 newRect.move(newRect.width() - maxRadii, 0); 1511 newRect.setWidth(maxRadii); 1512 } 1513 break; 1514 } 1515 1516 return RoundedRect(newRect, newRadii); 1517 } 1518 1439 1519 void RenderBoxModelObject::paintOneBorderSide(GraphicsContext& graphicsContext, const RenderStyle& style, const RoundedRect& outerBorder, const RoundedRect& innerBorder, 1440 1520 const LayoutRect& sideRect, BoxSide side, BoxSide adjacentSide1, BoxSide adjacentSide2, const BorderEdge edges[], const Path* path, … … 1456 1536 if (path) { 1457 1537 GraphicsContextStateSaver stateSaver(graphicsContext); 1458 if (innerBorder.isRenderable()) 1459 clipBorderSidePolygon(graphicsContext, outerBorder, innerBorder, side, adjacentSide1StylesMatch, adjacentSide2StylesMatch); 1460 else 1461 clipBorderSideForComplexInnerPath(graphicsContext, outerBorder, innerBorder, side, edges); 1538 1539 clipBorderSidePolygon(graphicsContext, outerBorder, innerBorder, side, adjacentSide1StylesMatch, adjacentSide2StylesMatch); 1540 1541 if (!innerBorder.isRenderable()) 1542 graphicsContext.clipOutRoundedRect(FloatRoundedRect(calculateAdjustedInnerBorder(innerBorder, side))); 1543 1462 1544 float thickness = std::max(std::max(edgeToRender.widthForPainting(), adjacentEdge1.widthForPainting()), adjacentEdge2.widthForPainting()); 1463 1545 drawBoxSideFromPath(graphicsContext, outerBorder.rect(), *path, edges, edgeToRender.widthForPainting(), thickness, side, style, … … 1908 1990 } 1909 1991 1910 static void findInnerVertex(const FloatPoint& outerCorner, const FloatPoint& innerCorner, const FloatPoint& centerPoint, FloatPoint& result)1911 {1912 // If the line between outer and inner corner is towards the horizontal, intersect with a vertical line through the center,1913 // otherwise with a horizontal line through the center. The points that form this line are arbitrary (we use 0, 100).1914 // Note that if findIntersection fails, it will leave result untouched.1915 float diffInnerOuterX = fabs(innerCorner.x() - outerCorner.x());1916 float diffInnerOuterY = fabs(innerCorner.y() - outerCorner.y());1917 float diffCenterOuterX = fabs(centerPoint.x() - outerCorner.x());1918 float diffCenterOuterY = fabs(centerPoint.y() - outerCorner.y());1919 if (diffInnerOuterY * diffCenterOuterX < diffCenterOuterY * diffInnerOuterX)1920 findIntersection(outerCorner, innerCorner, FloatPoint(centerPoint.x(), 0), FloatPoint(centerPoint.x(), 100), result);1921 else1922 findIntersection(outerCorner, innerCorner, FloatPoint(0, centerPoint.y()), FloatPoint(100, centerPoint.y()), result);1923 }1924 1925 1992 void RenderBoxModelObject::clipBorderSidePolygon(GraphicsContext& graphicsContext, const RoundedRect& outerBorder, const RoundedRect& innerBorder, 1926 1993 BoxSide side, bool firstEdgeMatches, bool secondEdgeMatches) … … 1929 1996 const FloatRect& outerRect = snapRectToDevicePixels(outerBorder.rect(), deviceScaleFactor); 1930 1997 const FloatRect& innerRect = snapRectToDevicePixels(innerBorder.rect(), deviceScaleFactor); 1931 1932 FloatPoint centerPoint(innerRect.location().x() + innerRect.width() / 2, innerRect.location().y() + innerRect.height() / 2);1933 1998 1934 1999 // For each side, create a quad that encompasses all parts of that side that may draw, … … 1956 2021 1957 2022 if (!innerBorder.radii().topLeft().isZero()) 1958 findIn nerVertex(outerRect.minXMinYCorner(), innerRect.minXMinYCorner(), centerPoint, quad[1]);2023 findIntersection(outerRect.minXMinYCorner(), innerRect.minXMinYCorner(), innerRect.minXMaxYCorner(), innerRect.maxXMinYCorner(), quad[1]); 1959 2024 1960 2025 if (!innerBorder.radii().topRight().isZero()) 1961 findIn nerVertex(outerRect.maxXMinYCorner(), innerRect.maxXMinYCorner(), centerPoint, quad[2]);2026 findIntersection(outerRect.maxXMinYCorner(), innerRect.maxXMinYCorner(), innerRect.minXMinYCorner(), innerRect.maxXMaxYCorner(), quad[2]); 1962 2027 break; 1963 2028 … … 1969 2034 1970 2035 if (!innerBorder.radii().topLeft().isZero()) 1971 findIn nerVertex(outerRect.minXMinYCorner(), innerRect.minXMinYCorner(), centerPoint, quad[1]);2036 findIntersection(outerRect.minXMinYCorner(), innerRect.minXMinYCorner(), innerRect.minXMaxYCorner(), innerRect.maxXMinYCorner(), quad[1]); 1972 2037 1973 2038 if (!innerBorder.radii().bottomLeft().isZero()) 1974 findIn nerVertex(outerRect.minXMaxYCorner(), innerRect.minXMaxYCorner(), centerPoint, quad[2]);2039 findIntersection(outerRect.minXMaxYCorner(), innerRect.minXMaxYCorner(), innerRect.minXMinYCorner(), innerRect.maxXMaxYCorner(), quad[2]); 1975 2040 break; 1976 2041 … … 1982 2047 1983 2048 if (!innerBorder.radii().bottomLeft().isZero()) 1984 findIn nerVertex(outerRect.minXMaxYCorner(), innerRect.minXMaxYCorner(), centerPoint, quad[1]);2049 findIntersection(outerRect.minXMaxYCorner(), innerRect.minXMaxYCorner(), innerRect.minXMinYCorner(), innerRect.maxXMaxYCorner(), quad[1]); 1985 2050 1986 2051 if (!innerBorder.radii().bottomRight().isZero()) 1987 findIn nerVertex(outerRect.maxXMaxYCorner(), innerRect.maxXMaxYCorner(), centerPoint, quad[2]);2052 findIntersection(outerRect.maxXMaxYCorner(), innerRect.maxXMaxYCorner(), innerRect.maxXMinYCorner(), innerRect.minXMaxYCorner(), quad[2]); 1988 2053 break; 1989 2054 … … 1995 2060 1996 2061 if (!innerBorder.radii().topRight().isZero()) 1997 findIn nerVertex(outerRect.maxXMinYCorner(), innerRect.maxXMinYCorner(), centerPoint, quad[1]);2062 findIntersection(outerRect.maxXMinYCorner(), innerRect.maxXMinYCorner(), innerRect.minXMinYCorner(), innerRect.maxXMaxYCorner(), quad[1]); 1998 2063 1999 2064 if (!innerBorder.radii().bottomRight().isZero()) 2000 findIn nerVertex(outerRect.maxXMaxYCorner(), innerRect.maxXMaxYCorner(), centerPoint, quad[2]);2065 findIntersection(outerRect.maxXMaxYCorner(), innerRect.maxXMaxYCorner(), innerRect.maxXMinYCorner(), innerRect.minXMaxYCorner(), quad[2]); 2001 2066 break; 2002 2067 } … … 2016 2081 quad[0], 2017 2082 quad[1], 2083 quad[2], 2018 2084 side == BSTop || side == BSBottom ? FloatPoint(quad[3].x(), quad[2].y()) : FloatPoint(quad[2].x(), quad[3].y()), 2019 2085 quad[3] … … 2026 2092 quad[0], 2027 2093 side == BSTop || side == BSBottom ? FloatPoint(quad[0].x(), quad[1].y()) : FloatPoint(quad[1].x(), quad[0].y()), 2094 quad[1], 2028 2095 quad[2], 2029 2096 quad[3] … … 2034 2101 2035 2102 graphicsContext.setShouldAntialias(wasAntialiased); 2036 }2037 2038 static LayoutRect calculateSideRectIncludingInner(const RoundedRect& outerBorder, const BorderEdge edges[], BoxSide side)2039 {2040 LayoutRect sideRect = outerBorder.rect();2041 LayoutUnit width;2042 2043 switch (side) {2044 case BSTop:2045 width = sideRect.height() - edges[BSBottom].widthForPainting();2046 sideRect.setHeight(width);2047 break;2048 case BSBottom:2049 width = sideRect.height() - edges[BSTop].widthForPainting();2050 sideRect.shiftYEdgeTo(sideRect.maxY() - width);2051 break;2052 case BSLeft:2053 width = sideRect.width() - edges[BSRight].widthForPainting();2054 sideRect.setWidth(width);2055 break;2056 case BSRight:2057 width = sideRect.width() - edges[BSLeft].widthForPainting();2058 sideRect.shiftXEdgeTo(sideRect.maxX() - width);2059 break;2060 }2061 2062 return sideRect;2063 }2064 2065 static RoundedRect calculateAdjustedInnerBorder(const RoundedRect&innerBorder, BoxSide side)2066 {2067 // Expand the inner border as necessary to make it a rounded rect (i.e. radii contained within each edge).2068 // This function relies on the fact we only get radii not contained within each edge if one of the radii2069 // for an edge is zero, so we can shift the arc towards the zero radius corner.2070 RoundedRect::Radii newRadii = innerBorder.radii();2071 LayoutRect newRect = innerBorder.rect();2072 2073 float overshoot;2074 float maxRadii;2075 2076 switch (side) {2077 case BSTop:2078 overshoot = newRadii.topLeft().width() + newRadii.topRight().width() - newRect.width();2079 if (overshoot > 0) {2080 ASSERT(!(newRadii.topLeft().width() && newRadii.topRight().width()));2081 newRect.setWidth(newRect.width() + overshoot);2082 if (!newRadii.topLeft().width())2083 newRect.move(-overshoot, 0);2084 }2085 newRadii.setBottomLeft(IntSize(0, 0));2086 newRadii.setBottomRight(IntSize(0, 0));2087 maxRadii = std::max(newRadii.topLeft().height(), newRadii.topRight().height());2088 if (maxRadii > newRect.height())2089 newRect.setHeight(maxRadii);2090 break;2091 2092 case BSBottom:2093 overshoot = newRadii.bottomLeft().width() + newRadii.bottomRight().width() - newRect.width();2094 if (overshoot > 0) {2095 ASSERT(!(newRadii.bottomLeft().width() && newRadii.bottomRight().width()));2096 newRect.setWidth(newRect.width() + overshoot);2097 if (!newRadii.bottomLeft().width())2098 newRect.move(-overshoot, 0);2099 }2100 newRadii.setTopLeft(IntSize(0, 0));2101 newRadii.setTopRight(IntSize(0, 0));2102 maxRadii = std::max(newRadii.bottomLeft().height(), newRadii.bottomRight().height());2103 if (maxRadii > newRect.height()) {2104 newRect.move(0, newRect.height() - maxRadii);2105 newRect.setHeight(maxRadii);2106 }2107 break;2108 2109 case BSLeft:2110 overshoot = newRadii.topLeft().height() + newRadii.bottomLeft().height() - newRect.height();2111 if (overshoot > 0) {2112 ASSERT(!(newRadii.topLeft().height() && newRadii.bottomLeft().height()));2113 newRect.setHeight(newRect.height() + overshoot);2114 if (!newRadii.topLeft().height())2115 newRect.move(0, -overshoot);2116 }2117 newRadii.setTopRight(IntSize(0, 0));2118 newRadii.setBottomRight(IntSize(0, 0));2119 maxRadii = std::max(newRadii.topLeft().width(), newRadii.bottomLeft().width());2120 if (maxRadii > newRect.width())2121 newRect.setWidth(maxRadii);2122 break;2123 2124 case BSRight:2125 overshoot = newRadii.topRight().height() + newRadii.bottomRight().height() - newRect.height();2126 if (overshoot > 0) {2127 ASSERT(!(newRadii.topRight().height() && newRadii.bottomRight().height()));2128 newRect.setHeight(newRect.height() + overshoot);2129 if (!newRadii.topRight().height())2130 newRect.move(0, -overshoot);2131 }2132 newRadii.setTopLeft(IntSize(0, 0));2133 newRadii.setBottomLeft(IntSize(0, 0));2134 maxRadii = std::max(newRadii.topRight().width(), newRadii.bottomRight().width());2135 if (maxRadii > newRect.width()) {2136 newRect.move(newRect.width() - maxRadii, 0);2137 newRect.setWidth(maxRadii);2138 }2139 break;2140 }2141 2142 return RoundedRect(newRect, newRadii);2143 }2144 2145 void RenderBoxModelObject::clipBorderSideForComplexInnerPath(GraphicsContext& graphicsContext, const RoundedRect& outerBorder, const RoundedRect& innerBorder,2146 BoxSide side, const class BorderEdge edges[])2147 {2148 graphicsContext.clip(calculateSideRectIncludingInner(outerBorder, edges, side));2149 graphicsContext.clipOutRoundedRect(FloatRoundedRect(calculateAdjustedInnerBorder(innerBorder, side)));2150 2103 } 2151 2104 -
trunk/Source/WebCore/rendering/RenderBoxModelObject.h
r201040 r201868 311 311 void clipBorderSidePolygon(GraphicsContext&, const RoundedRect& outerBorder, const RoundedRect& innerBorder, 312 312 BoxSide, bool firstEdgeMatches, bool secondEdgeMatches); 313 void clipBorderSideForComplexInnerPath(GraphicsContext&, const RoundedRect&, const RoundedRect&, BoxSide, const BorderEdge[]); 313 314 314 void paintOneBorderSide(GraphicsContext&, const RenderStyle&, const RoundedRect& outerBorder, const RoundedRect& innerBorder, 315 315 const LayoutRect& sideRect, BoxSide, BoxSide adjacentSide1, BoxSide adjacentSide2, const BorderEdge[],
Note:
See TracChangeset
for help on using the changeset viewer.