| Index: third_party/WebKit/Source/core/paint/BoxBorderPainter.cpp
|
| diff --git a/third_party/WebKit/Source/core/paint/BoxBorderPainter.cpp b/third_party/WebKit/Source/core/paint/BoxBorderPainter.cpp
|
| index 31355c04a9bc26a4a9e38a89a2294df5336349e3..e66f7b6453a3213abcbec05bc35656e586644df0 100644
|
| --- a/third_party/WebKit/Source/core/paint/BoxBorderPainter.cpp
|
| +++ b/third_party/WebKit/Source/core/paint/BoxBorderPainter.cpp
|
| @@ -1124,7 +1124,9 @@ void BoxBorderPainter::clipBorderSidePolygon(GraphicsContext& graphicsContext,
|
| MiterType secondMiter) const {
|
| DCHECK(firstMiter != NoMiter || secondMiter != NoMiter);
|
|
|
| - FloatPoint quad[4];
|
| + FloatPoint edgeQuad[4]; // The boundary of the edge for fill
|
| + FloatPoint boundQuad1; // Point 1 of the rectilinear bounding box of EdgeQuad
|
| + FloatPoint boundQuad2; // Point 2 of the rectilinear bounding box of EdgeQuad
|
|
|
| const LayoutRect outerRect(m_outer.rect());
|
| const LayoutRect innerRect(m_inner.rect());
|
| @@ -1133,170 +1135,242 @@ void BoxBorderPainter::clipBorderSidePolygon(GraphicsContext& graphicsContext,
|
| // may draw, including areas inside the innerBorder.
|
| //
|
| // 0----------------3
|
| - // 0 \ / 0
|
| + // 3 \ / 0
|
| // |\ 1----------- 2 /|
|
| - // | 1 1 |
|
| + // | 2 1 |
|
| // | | | |
|
| // | | | |
|
| - // | 2 2 |
|
| - // |/ 1------------2 \|
|
| - // 3 / \ 3
|
| - // 0----------------3
|
| - //
|
| + // | 1 2 |
|
| + // |/ 2------------1 \|
|
| + // 0 / \ 3
|
| + // 3----------------0
|
| +
|
| + // Offset size and direction to expand clipping quad
|
| + const static float kExtensionLength = 1e-1f;
|
| + FloatSize extensionOffset;
|
| switch (side) {
|
| case BSTop:
|
| - quad[0] = FloatPoint(outerRect.minXMinYCorner());
|
| - quad[1] = FloatPoint(innerRect.minXMinYCorner());
|
| - quad[2] = FloatPoint(innerRect.maxXMinYCorner());
|
| - quad[3] = FloatPoint(outerRect.maxXMinYCorner());
|
| + edgeQuad[0] = FloatPoint(outerRect.minXMinYCorner());
|
| + edgeQuad[1] = FloatPoint(innerRect.minXMinYCorner());
|
| + edgeQuad[2] = FloatPoint(innerRect.maxXMinYCorner());
|
| + edgeQuad[3] = FloatPoint(outerRect.maxXMinYCorner());
|
| +
|
| + DCHECK(edgeQuad[0].y() == edgeQuad[3].y());
|
| + DCHECK(edgeQuad[1].y() == edgeQuad[2].y());
|
| +
|
| + boundQuad1 = FloatPoint(edgeQuad[0].x(), edgeQuad[1].y());
|
| + boundQuad2 = FloatPoint(edgeQuad[3].x(), edgeQuad[2].y());
|
| +
|
| + extensionOffset.setWidth(-kExtensionLength);
|
| + extensionOffset.setHeight(0);
|
|
|
| if (!m_inner.getRadii().topLeft().isZero()) {
|
| findIntersection(
|
| - quad[0], quad[1],
|
| - FloatPoint(quad[1].x() + m_inner.getRadii().topLeft().width(),
|
| - quad[1].y()),
|
| - FloatPoint(quad[1].x(),
|
| - quad[1].y() + m_inner.getRadii().topLeft().height()),
|
| - quad[1]);
|
| + edgeQuad[0], edgeQuad[1],
|
| + FloatPoint(edgeQuad[1].x() + m_inner.getRadii().topLeft().width(),
|
| + edgeQuad[1].y()),
|
| + FloatPoint(edgeQuad[1].x(),
|
| + edgeQuad[1].y() + m_inner.getRadii().topLeft().height()),
|
| + edgeQuad[1]);
|
| + DCHECK(boundQuad1.y() <= edgeQuad[1].y());
|
| + boundQuad1.setY(edgeQuad[1].y());
|
| + boundQuad2.setY(edgeQuad[1].y());
|
| }
|
|
|
| if (!m_inner.getRadii().topRight().isZero()) {
|
| findIntersection(
|
| - quad[3], quad[2],
|
| - FloatPoint(quad[2].x() - m_inner.getRadii().topRight().width(),
|
| - quad[2].y()),
|
| - FloatPoint(quad[2].x(),
|
| - quad[2].y() + m_inner.getRadii().topRight().height()),
|
| - quad[2]);
|
| + edgeQuad[3], edgeQuad[2],
|
| + FloatPoint(edgeQuad[2].x() - m_inner.getRadii().topRight().width(),
|
| + edgeQuad[2].y()),
|
| + FloatPoint(
|
| + edgeQuad[2].x(),
|
| + edgeQuad[2].y() + m_inner.getRadii().topRight().height()),
|
| + edgeQuad[2]);
|
| + if (boundQuad1.y() < edgeQuad[2].y()) {
|
| + boundQuad1.setY(edgeQuad[2].y());
|
| + boundQuad2.setY(edgeQuad[2].y());
|
| + }
|
| }
|
| break;
|
|
|
| case BSLeft:
|
| - quad[0] = FloatPoint(outerRect.minXMinYCorner());
|
| - quad[1] = FloatPoint(innerRect.minXMinYCorner());
|
| - quad[2] = FloatPoint(innerRect.minXMaxYCorner());
|
| - quad[3] = FloatPoint(outerRect.minXMaxYCorner());
|
| + // Swap the order of adjacent edges to allow common code
|
| + std::swap(firstMiter, secondMiter);
|
| + edgeQuad[0] = FloatPoint(outerRect.minXMaxYCorner());
|
| + edgeQuad[1] = FloatPoint(innerRect.minXMaxYCorner());
|
| + edgeQuad[2] = FloatPoint(innerRect.minXMinYCorner());
|
| + edgeQuad[3] = FloatPoint(outerRect.minXMinYCorner());
|
| +
|
| + DCHECK(edgeQuad[0].x() == edgeQuad[3].x());
|
| + DCHECK(edgeQuad[1].x() == edgeQuad[2].x());
|
| +
|
| + boundQuad1 = FloatPoint(edgeQuad[1].x(), edgeQuad[0].y());
|
| + boundQuad2 = FloatPoint(edgeQuad[2].x(), edgeQuad[3].y());
|
| +
|
| + extensionOffset.setWidth(0);
|
| + extensionOffset.setHeight(kExtensionLength);
|
|
|
| if (!m_inner.getRadii().topLeft().isZero()) {
|
| findIntersection(
|
| - quad[0], quad[1],
|
| - FloatPoint(quad[1].x() + m_inner.getRadii().topLeft().width(),
|
| - quad[1].y()),
|
| - FloatPoint(quad[1].x(),
|
| - quad[1].y() + m_inner.getRadii().topLeft().height()),
|
| - quad[1]);
|
| + edgeQuad[3], edgeQuad[2],
|
| + FloatPoint(edgeQuad[2].x() + m_inner.getRadii().topLeft().width(),
|
| + edgeQuad[2].y()),
|
| + FloatPoint(edgeQuad[2].x(),
|
| + edgeQuad[2].y() + m_inner.getRadii().topLeft().height()),
|
| + edgeQuad[2]);
|
| + DCHECK(boundQuad2.x() <= edgeQuad[2].x());
|
| + boundQuad1.setX(edgeQuad[2].x());
|
| + boundQuad2.setX(edgeQuad[2].x());
|
| }
|
|
|
| if (!m_inner.getRadii().bottomLeft().isZero()) {
|
| findIntersection(
|
| - quad[3], quad[2],
|
| - FloatPoint(quad[2].x() + m_inner.getRadii().bottomLeft().width(),
|
| - quad[2].y()),
|
| - FloatPoint(quad[2].x(),
|
| - quad[2].y() - m_inner.getRadii().bottomLeft().height()),
|
| - quad[2]);
|
| + edgeQuad[0], edgeQuad[1],
|
| + FloatPoint(
|
| + edgeQuad[1].x() + m_inner.getRadii().bottomLeft().width(),
|
| + edgeQuad[1].y()),
|
| + FloatPoint(
|
| + edgeQuad[1].x(),
|
| + edgeQuad[1].y() - m_inner.getRadii().bottomLeft().height()),
|
| + edgeQuad[1]);
|
| + if (boundQuad1.x() < edgeQuad[1].x()) {
|
| + boundQuad1.setX(edgeQuad[1].x());
|
| + boundQuad2.setX(edgeQuad[1].x());
|
| + }
|
| }
|
| break;
|
|
|
| case BSBottom:
|
| - quad[0] = FloatPoint(outerRect.minXMaxYCorner());
|
| - quad[1] = FloatPoint(innerRect.minXMaxYCorner());
|
| - quad[2] = FloatPoint(innerRect.maxXMaxYCorner());
|
| - quad[3] = FloatPoint(outerRect.maxXMaxYCorner());
|
| + // Swap the order of adjacent edges to allow common code
|
| + std::swap(firstMiter, secondMiter);
|
| + edgeQuad[0] = FloatPoint(outerRect.maxXMaxYCorner());
|
| + edgeQuad[1] = FloatPoint(innerRect.maxXMaxYCorner());
|
| + edgeQuad[2] = FloatPoint(innerRect.minXMaxYCorner());
|
| + edgeQuad[3] = FloatPoint(outerRect.minXMaxYCorner());
|
| +
|
| + DCHECK(edgeQuad[0].y() == edgeQuad[3].y());
|
| + DCHECK(edgeQuad[1].y() == edgeQuad[2].y());
|
| +
|
| + boundQuad1 = FloatPoint(edgeQuad[0].x(), edgeQuad[1].y());
|
| + boundQuad2 = FloatPoint(edgeQuad[3].x(), edgeQuad[2].y());
|
| +
|
| + extensionOffset.setWidth(kExtensionLength);
|
| + extensionOffset.setHeight(0);
|
|
|
| if (!m_inner.getRadii().bottomLeft().isZero()) {
|
| findIntersection(
|
| - quad[0], quad[1],
|
| - FloatPoint(quad[1].x() + m_inner.getRadii().bottomLeft().width(),
|
| - quad[1].y()),
|
| - FloatPoint(quad[1].x(),
|
| - quad[1].y() - m_inner.getRadii().bottomLeft().height()),
|
| - quad[1]);
|
| + edgeQuad[3], edgeQuad[2],
|
| + FloatPoint(
|
| + edgeQuad[2].x() + m_inner.getRadii().bottomLeft().width(),
|
| + edgeQuad[2].y()),
|
| + FloatPoint(
|
| + edgeQuad[2].x(),
|
| + edgeQuad[2].y() - m_inner.getRadii().bottomLeft().height()),
|
| + edgeQuad[2]);
|
| + DCHECK(boundQuad2.y() >= edgeQuad[2].y());
|
| + boundQuad1.setY(edgeQuad[2].y());
|
| + boundQuad2.setY(edgeQuad[2].y());
|
| }
|
|
|
| if (!m_inner.getRadii().bottomRight().isZero()) {
|
| findIntersection(
|
| - quad[3], quad[2],
|
| - FloatPoint(quad[2].x() - m_inner.getRadii().bottomRight().width(),
|
| - quad[2].y()),
|
| - FloatPoint(quad[2].x(),
|
| - quad[2].y() - m_inner.getRadii().bottomRight().height()),
|
| - quad[2]);
|
| + edgeQuad[0], edgeQuad[1],
|
| + FloatPoint(
|
| + edgeQuad[1].x() - m_inner.getRadii().bottomRight().width(),
|
| + edgeQuad[1].y()),
|
| + FloatPoint(
|
| + edgeQuad[1].x(),
|
| + edgeQuad[1].y() - m_inner.getRadii().bottomRight().height()),
|
| + edgeQuad[1]);
|
| + if (boundQuad1.y() > edgeQuad[1].y()) {
|
| + boundQuad1.setY(edgeQuad[1].y());
|
| + boundQuad2.setY(edgeQuad[1].y());
|
| + }
|
| }
|
| break;
|
|
|
| case BSRight:
|
| - quad[0] = FloatPoint(outerRect.maxXMinYCorner());
|
| - quad[1] = FloatPoint(innerRect.maxXMinYCorner());
|
| - quad[2] = FloatPoint(innerRect.maxXMaxYCorner());
|
| - quad[3] = FloatPoint(outerRect.maxXMaxYCorner());
|
| + edgeQuad[0] = FloatPoint(outerRect.maxXMinYCorner());
|
| + edgeQuad[1] = FloatPoint(innerRect.maxXMinYCorner());
|
| + edgeQuad[2] = FloatPoint(innerRect.maxXMaxYCorner());
|
| + edgeQuad[3] = FloatPoint(outerRect.maxXMaxYCorner());
|
| +
|
| + DCHECK(edgeQuad[0].x() == edgeQuad[3].x());
|
| + DCHECK(edgeQuad[1].x() == edgeQuad[2].x());
|
| +
|
| + boundQuad1 = FloatPoint(edgeQuad[1].x(), edgeQuad[0].y());
|
| + boundQuad2 = FloatPoint(edgeQuad[2].x(), edgeQuad[3].y());
|
| +
|
| + extensionOffset.setWidth(0);
|
| + extensionOffset.setHeight(-kExtensionLength);
|
|
|
| if (!m_inner.getRadii().topRight().isZero()) {
|
| findIntersection(
|
| - quad[0], quad[1],
|
| - FloatPoint(quad[1].x() - m_inner.getRadii().topRight().width(),
|
| - quad[1].y()),
|
| - FloatPoint(quad[1].x(),
|
| - quad[1].y() + m_inner.getRadii().topRight().height()),
|
| - quad[1]);
|
| + edgeQuad[0], edgeQuad[1],
|
| + FloatPoint(edgeQuad[1].x() - m_inner.getRadii().topRight().width(),
|
| + edgeQuad[1].y()),
|
| + FloatPoint(
|
| + edgeQuad[1].x(),
|
| + edgeQuad[1].y() + m_inner.getRadii().topRight().height()),
|
| + edgeQuad[1]);
|
| + DCHECK(boundQuad1.x() >= edgeQuad[1].x());
|
| + boundQuad1.setX(edgeQuad[1].x());
|
| + boundQuad2.setX(edgeQuad[1].x());
|
| }
|
|
|
| if (!m_inner.getRadii().bottomRight().isZero()) {
|
| findIntersection(
|
| - quad[3], quad[2],
|
| - FloatPoint(quad[2].x() - m_inner.getRadii().bottomRight().width(),
|
| - quad[2].y()),
|
| - FloatPoint(quad[2].x(),
|
| - quad[2].y() - m_inner.getRadii().bottomRight().height()),
|
| - quad[2]);
|
| + edgeQuad[3], edgeQuad[2],
|
| + FloatPoint(
|
| + edgeQuad[2].x() - m_inner.getRadii().bottomRight().width(),
|
| + edgeQuad[2].y()),
|
| + FloatPoint(
|
| + edgeQuad[2].x(),
|
| + edgeQuad[2].y() - m_inner.getRadii().bottomRight().height()),
|
| + edgeQuad[2]);
|
| + if (boundQuad1.x() > edgeQuad[2].x()) {
|
| + boundQuad1.setX(edgeQuad[2].x());
|
| + boundQuad2.setX(edgeQuad[2].x());
|
| + }
|
| }
|
| break;
|
| }
|
|
|
| if (firstMiter == secondMiter) {
|
| - clipQuad(graphicsContext, quad, firstMiter == SoftMiter);
|
| + clipQuad(graphicsContext, edgeQuad, firstMiter == SoftMiter);
|
| return;
|
| }
|
|
|
| - // If antialiasing settings for the first edge and second edge is different,
|
| - // they have to be addressed separately. We do this by breaking the quad into
|
| - // two parallelograms, made by moving quad[1] and quad[2].
|
| - float ax = quad[1].x() - quad[0].x();
|
| - float ay = quad[1].y() - quad[0].y();
|
| - float bx = quad[2].x() - quad[1].x();
|
| - float by = quad[2].y() - quad[1].y();
|
| - float cx = quad[3].x() - quad[2].x();
|
| - float cy = quad[3].y() - quad[2].y();
|
| -
|
| - const static float kEpsilon = 1e-2f;
|
| - float r1, r2;
|
| - if (fabsf(bx) < kEpsilon && fabsf(by) < kEpsilon) {
|
| - // The quad was actually a triangle.
|
| - r1 = r2 = 1.0f;
|
| - } else {
|
| - // Extend parallelogram a bit to hide calculation error
|
| - const static float kExtendFill = 1e-2f;
|
| + // If antialiasing settings for the first edge and second edge are different,
|
| + // they have to be addressed separately. We do this by applying 2 clips, one
|
| + // for each miter, with the appropriate anti-aliasing setting. Each clip uses
|
| + // 3 sides of the quad rectilinear bounding box and a 4th side aligned with
|
| + // the miter edge. We extend the clip in the miter direction to ensure overlap
|
| + // as each edge is drawn.
|
| + if (firstMiter != NoMiter) {
|
| + FloatPoint clippingQuad[4];
|
|
|
| - r1 = (-ax * by + ay * bx) / (cx * by - cy * bx) + kExtendFill;
|
| - r2 = (-cx * by + cy * bx) / (ax * by - ay * bx) + kExtendFill;
|
| - }
|
| + clippingQuad[0] = edgeQuad[0] + extensionOffset;
|
| + findIntersection(edgeQuad[0], edgeQuad[1], boundQuad1, boundQuad2,
|
| + clippingQuad[1]);
|
| + clippingQuad[1] += extensionOffset;
|
| + clippingQuad[2] = boundQuad2;
|
| + clippingQuad[3] = edgeQuad[3];
|
|
|
| - if (firstMiter != NoMiter) {
|
| - FloatPoint firstQuad[4];
|
| - firstQuad[0] = quad[0];
|
| - firstQuad[1] = quad[1];
|
| - firstQuad[2] = FloatPoint(quad[3].x() + r2 * ax, quad[3].y() + r2 * ay);
|
| - firstQuad[3] = quad[3];
|
| - clipQuad(graphicsContext, firstQuad, firstMiter == SoftMiter);
|
| + clipQuad(graphicsContext, clippingQuad, firstMiter == SoftMiter);
|
| }
|
|
|
| if (secondMiter != NoMiter) {
|
| - FloatPoint secondQuad[4];
|
| - secondQuad[0] = quad[0];
|
| - secondQuad[1] = FloatPoint(quad[0].x() - r1 * cx, quad[0].y() - r1 * cy);
|
| - secondQuad[2] = quad[2];
|
| - secondQuad[3] = quad[3];
|
| - clipQuad(graphicsContext, secondQuad, secondMiter == SoftMiter);
|
| + FloatPoint clippingQuad[4];
|
| +
|
| + clippingQuad[0] = edgeQuad[0];
|
| + clippingQuad[1] = boundQuad1;
|
| + findIntersection(edgeQuad[2], edgeQuad[3], boundQuad1, boundQuad2,
|
| + clippingQuad[2]);
|
| + clippingQuad[2] -= extensionOffset;
|
| + clippingQuad[3] = edgeQuad[3] - extensionOffset;
|
| +
|
| + clipQuad(graphicsContext, clippingQuad, secondMiter == SoftMiter);
|
| }
|
| }
|
|
|
|
|