Diff
Modified: trunk/LayoutTests/ChangeLog (145869 => 145870)
--- trunk/LayoutTests/ChangeLog 2013-03-15 03:30:26 UTC (rev 145869)
+++ trunk/LayoutTests/ChangeLog 2013-03-15 03:37:06 UTC (rev 145870)
@@ -1,3 +1,16 @@
+2013-03-14 Xidorn Quan <quanxunz...@gmail.com>
+
+ Clickable area is incorrect for elements with border-radius
+ https://bugs.webkit.org/show_bug.cgi?id=95373
+
+ Reviewed by Simon Fraser.
+
+ This test is based on Takashi Sakamoto's work in
+ https://bugs.webkit.org/show_bug.cgi?id=95373
+
+ * fast/borders/border-radius-position-expected.txt: Added.
+ * fast/borders/border-radius-position.html: Added.
+
2013-03-14 Andreas Kling <akl...@apple.com>
REGRESSION(r145169): [Mac][WK2] http/tests/security/cross-frame-access-put.html fails.
Added: trunk/LayoutTests/fast/borders/border-radius-position-expected.txt (0 => 145870)
--- trunk/LayoutTests/fast/borders/border-radius-position-expected.txt (rev 0)
+++ trunk/LayoutTests/fast/borders/border-radius-position-expected.txt 2013-03-15 03:37:06 UTC (rev 145870)
@@ -0,0 +1,17 @@
+Test for bug 95373: https://bugs.webkit.org/show_bug.cgi?id=95373 (border-radius) when border-radius:50% there is still 'invisible' square box
+
+Click outerBox
+Click outerBox
+Click innerBox
+Click outerBox
+Click innerBox
+Click outerBox
+Click outerBox
+Click outerBox
+Click innerBox
+Click innerBox
+Click outerBox
+Click outerBox
+Click innerBox
+Click innerBox
+
Added: trunk/LayoutTests/fast/borders/border-radius-position.html (0 => 145870)
--- trunk/LayoutTests/fast/borders/border-radius-position.html (rev 0)
+++ trunk/LayoutTests/fast/borders/border-radius-position.html 2013-03-15 03:37:06 UTC (rev 145870)
@@ -0,0 +1,106 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+div#innerBox {
+ width: 200px;
+ height: 200px;
+ padding: 0px;
+ border-top-left-radius: 100px 80px;
+ border-top-right-radius: 50px 25px;
+ border-bottom-left-radius: 50px 70px;
+ border-bottom-right-radius: 70px 30px;
+ background-color: green;
+}
+
+div#outerBox {
+ width: 200px;
+ height: 200px;
+ margin: 0px;
+ padding: 100px;
+ background-color: lightgreen;
+}
+</style>
+<script>
+if (window.testRunner)
+ testRunner.dumpAsText();
+
+function log(message) {
+ var console = document.getElementById('console');
+ console.innerHTML += message + "\n";
+}
+
+function runTest() {
+ var outerBox = document.getElementById('outerBox');
+ outerBox.addEventListener('click', function(event) {
+ log("Click outerBox");
+ }, false);
+ var innerBox = document.getElementById('innerBox');
+ innerBox.addEventListener('click', function(event) {
+ log("Click innerBox");
+ event.stopPropagation();
+ }, false);
+ if (window.testRunner) {
+ var x = innerBox.offsetLeft;
+ var y = innerBox.offsetTop;
+ // top-left
+ eventSender.mouseMoveTo(x, y);
+ eventSender.mouseDown();
+ eventSender.mouseUp();
+ eventSender.mouseMoveTo(x + 25, y + 20);
+ eventSender.mouseDown();
+ eventSender.mouseUp();
+ eventSender.mouseMoveTo(x + 30, y + 24);
+ eventSender.mouseDown();
+ eventSender.mouseUp();
+ // top-right
+ eventSender.mouseMoveTo(x + 200, y);
+ eventSender.mouseDown();
+ eventSender.mouseUp();
+ eventSender.mouseMoveTo(x + 200 - 14, y + 8);
+ eventSender.mouseDown();
+ eventSender.mouseUp();
+ eventSender.mouseMoveTo(x + 200 - 8, y + 4);
+ eventSender.mouseDown();
+ eventSender.mouseUp();
+ eventSender.mouseMoveTo(x + 200 - 4, y + 2);
+ eventSender.mouseDown();
+ eventSender.mouseUp();
+ // bottom-left
+ eventSender.mouseMoveTo(x, y + 180);
+ eventSender.mouseDown();
+ eventSender.mouseUp();
+ eventSender.mouseMoveTo(x + 14, y + 166);
+ eventSender.mouseDown();
+ eventSender.mouseUp();
+ eventSender.mouseMoveTo(x + 20, y + 160);
+ eventSender.mouseDown();
+ eventSender.mouseUp();
+ // bottom-right
+ eventSender.mouseMoveTo(x + 199, y + 200);
+ eventSender.mouseDown();
+ eventSender.mouseUp();
+ eventSender.mouseMoveTo(x + 199, y + 180);
+ eventSender.mouseDown();
+ eventSender.mouseUp();
+ eventSender.mouseMoveTo(x + 199, y + 175);
+ eventSender.mouseDown();
+ eventSender.mouseUp();
+ eventSender.mouseMoveTo(x + 199, y + 170);
+ eventSender.mouseDown();
+ eventSender.mouseUp();
+ }
+}
+</script>
+</head>
+<body _onload_="runTest()">
+<div id="outerBox">
+ <div id="innerBox">
+ </div>
+</div>
+<p>Test for <i>bug 95373</i>: <a href="" (border-radius) when border-radius:50% there is still 'invisible' square box
+</p>
+<pre id="console">
+</pre>
+</body>
+</html>
Modified: trunk/Source/WebCore/ChangeLog (145869 => 145870)
--- trunk/Source/WebCore/ChangeLog 2013-03-15 03:30:26 UTC (rev 145869)
+++ trunk/Source/WebCore/ChangeLog 2013-03-15 03:37:06 UTC (rev 145870)
@@ -1,3 +1,40 @@
+2013-03-14 Xidorn Quan <quanxunz...@gmail.com>
+
+ Clickable area is incorrect for elements with border-radius
+ https://bugs.webkit.org/show_bug.cgi?id=95373
+
+ Reviewed by Simon Fraser.
+
+ As RenderBlock doesn't see rounded rect which comes from border-radius
+ in nodeAtPoint, the rounded corner seems to have an 'invisible' square
+ box which catches hits. So we added check on whether hitTestPoint also
+ intersects the rounded rect when hasBorderRadius is set.
+
+ This patch is based on Takashi Sakamoto's work in
+ https://bugs.webkit.org/show_bug.cgi?id=95373
+
+ Test: fast/borders/border-radius-position.html
+
+ * platform/graphics/FloatQuad.cpp:
+ (WebCore):
+ (WebCore::lineIntersectsCircle):
+ (WebCore::FloatQuad::intersectsCircle):
+ (WebCore::FloatQuad::intersectsEllipse):
+ * platform/graphics/FloatQuad.h:
+ (FloatQuad):
+ * platform/graphics/RoundedRect.cpp:
+ (WebCore::RoundedRect::intersectsQuad):
+ (WebCore):
+ * platform/graphics/RoundedRect.h:
+ (RoundedRect):
+ * rendering/HitTestLocation.cpp:
+ (WebCore::HitTestLocation::intersects):
+ (WebCore):
+ * rendering/HitTestLocation.h:
+ (HitTestLocation):
+ * rendering/RenderBlock.cpp:
+ (WebCore::RenderBlock::nodeAtPoint):
+
2013-03-14 Chris Fleizach <cfleiz...@apple.com>
AX: Crash when removing aria-menu item from DOM
Modified: trunk/Source/WebCore/platform/graphics/FloatQuad.cpp (145869 => 145870)
--- trunk/Source/WebCore/platform/graphics/FloatQuad.cpp 2013-03-15 03:30:26 UTC (rev 145869)
+++ trunk/Source/WebCore/platform/graphics/FloatQuad.cpp 2013-03-15 03:37:06 UTC (rev 145870)
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2008 Apple Inc. All rights reserved.
* Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2013 Xidorn Quan (quanxunz...@gmail.com)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -177,6 +178,55 @@
return true;
}
+// Tests whether the line is contained by or intersected with the circle.
+static inline bool lineIntersectsCircle(const FloatPoint& center, float radius, const FloatPoint& p0, const FloatPoint& p1)
+{
+ float x0 = p0.x() - center.x(), y0 = p0.y() - center.y();
+ float x1 = p1.x() - center.x(), y1 = p1.y() - center.y();
+ float radius2 = radius * radius;
+ if ((x0 * x0 + y0 * y0) <= radius2 || (x1 * x1 + y1 * y1) <= radius2)
+ return true;
+ if (p0 == p1)
+ return false;
+
+ float a = y0 - y1;
+ float b = x1 - x0;
+ float c = x0 * y1 - x1 * y0;
+ float distance2 = c * c / (a * a + b * b);
+ // If distance between the center point and the line > the radius,
+ // the line doesn't cross (or is contained by) the ellipse.
+ if (distance2 > radius2)
+ return false;
+
+ // The nearest point on the line is between p0 and p1?
+ float x = - a * c / (a * a + b * b);
+ float y = - b * c / (a * a + b * b);
+ return (((x0 <= x && x <= x1) || (x0 >= x && x >= x1))
+ && ((y0 <= y && y <= y1) || (y1 <= y && y <= y0)));
+}
+
+bool FloatQuad::intersectsCircle(const FloatPoint& center, float radius) const
+{
+ return containsPoint(center) // The circle may be totally contained by the quad.
+ || lineIntersectsCircle(center, radius, m_p1, m_p2)
+ || lineIntersectsCircle(center, radius, m_p2, m_p3)
+ || lineIntersectsCircle(center, radius, m_p3, m_p4)
+ || lineIntersectsCircle(center, radius, m_p4, m_p1);
+}
+
+bool FloatQuad::intersectsEllipse(const FloatPoint& center, const FloatSize& radii) const
+{
+ // Transform the ellipse to an origin-centered circle whose radius is the product of major radius and minor radius.
+ // Here we apply the same transformation to the quad.
+ FloatQuad transformedQuad(*this);
+ transformedQuad.move(-center.x(), -center.y());
+ transformedQuad.scale(radii.height(), radii.width());
+
+ FloatPoint originPoint;
+ return transformedQuad.intersectsCircle(originPoint, radii.height() * radii.width());
+
+}
+
bool FloatQuad::isCounterclockwise() const
{
// Return if the two first vectors are turning clockwise. If the quad is convex then all following vectors will turn the same way.
Modified: trunk/Source/WebCore/platform/graphics/FloatQuad.h (145869 => 145870)
--- trunk/Source/WebCore/platform/graphics/FloatQuad.h 2013-03-15 03:30:26 UTC (rev 145869)
+++ trunk/Source/WebCore/platform/graphics/FloatQuad.h 2013-03-15 03:37:06 UTC (rev 145870)
@@ -92,6 +92,11 @@
// This only works for convex quads.
bool intersectsRect(const FloatRect&) const;
+ // Test whether any part of the circle/ellipse intersects with this quad.
+ // Note that these two functions only work for convex quads.
+ bool intersectsCircle(const FloatPoint& center, float radius) const;
+ bool intersectsEllipse(const FloatPoint& center, const FloatSize& radii) const;
+
// The center of the quad. If the quad is the result of a affine-transformed rectangle this is the same as the original center transformed.
FloatPoint center() const
{
Modified: trunk/Source/WebCore/platform/graphics/RoundedRect.cpp (145869 => 145870)
--- trunk/Source/WebCore/platform/graphics/RoundedRect.cpp 2013-03-15 03:30:26 UTC (rev 145869)
+++ trunk/Source/WebCore/platform/graphics/RoundedRect.cpp 2013-03-15 03:37:06 UTC (rev 145870)
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2003, 2006, 2009 Apple Inc. All rights reserved.
* Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2013 Xidorn Quan (quanxunz...@gmail.com)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -181,4 +182,57 @@
m_radii.scale(widthRatio < heightRatio ? widthRatio : heightRatio);
}
+bool RoundedRect::intersectsQuad(const FloatQuad& quad) const
+{
+ FloatRect rect(m_rect);
+ if (!quad.intersectsRect(rect))
+ return false;
+
+ const IntSize& topLeft = m_radii.topLeft();
+ if (!topLeft.isEmpty()) {
+ FloatRect rect(m_rect.x(), m_rect.y(), topLeft.width(), topLeft.height());
+ if (quad.intersectsRect(rect)) {
+ FloatPoint center(m_rect.x() + topLeft.width(), m_rect.y() + topLeft.height());
+ FloatSize size(topLeft.width(), topLeft.height());
+ if (!quad.intersectsEllipse(center, size))
+ return false;
+ }
+ }
+
+ const IntSize& topRight = m_radii.topRight();
+ if (!topRight.isEmpty()) {
+ FloatRect rect(m_rect.maxX() - topRight.width(), m_rect.y(), topRight.width(), topRight.height());
+ if (quad.intersectsRect(rect)) {
+ FloatPoint center(m_rect.maxX() - topRight.width(), m_rect.y() + topRight.height());
+ FloatSize size(topRight.width(), topRight.height());
+ if (!quad.intersectsEllipse(center, size))
+ return false;
+ }
+ }
+
+ const IntSize& bottomLeft = m_radii.bottomLeft();
+ if (!bottomLeft.isEmpty()) {
+ FloatRect rect(m_rect.x(), m_rect.maxY() - bottomLeft.height(), bottomLeft.width(), bottomLeft.height());
+ if (quad.intersectsRect(rect)) {
+ FloatPoint center(m_rect.x() + bottomLeft.width(), m_rect.maxY() - bottomLeft.height());
+ FloatSize size(bottomLeft.width(), bottomLeft.height());
+ if (!quad.intersectsEllipse(center, size))
+ return false;
+ }
+ }
+
+ const IntSize& bottomRight = m_radii.bottomRight();
+ if (!bottomRight.isEmpty()) {
+ FloatRect rect(m_rect.maxX() - bottomRight.width(), m_rect.maxY() - bottomRight.height(), bottomRight.width(), bottomRight.height());
+ if (quad.intersectsRect(rect)) {
+ FloatPoint center(m_rect.maxX() - bottomRight.width(), m_rect.maxY() - bottomRight.height());
+ FloatSize size(bottomRight.width(), bottomRight.height());
+ if (!quad.intersectsEllipse(center, size))
+ return false;
+ }
+ }
+
+ return true;
+}
+
} // namespace WebCore
Modified: trunk/Source/WebCore/platform/graphics/RoundedRect.h (145869 => 145870)
--- trunk/Source/WebCore/platform/graphics/RoundedRect.h 2013-03-15 03:30:26 UTC (rev 145869)
+++ trunk/Source/WebCore/platform/graphics/RoundedRect.h 2013-03-15 03:37:06 UTC (rev 145870)
@@ -27,6 +27,7 @@
#ifndef RoundedRect_h
#define RoundedRect_h
+#include "FloatQuad.h"
#include "IntRect.h"
namespace WebCore {
@@ -96,6 +97,10 @@
bool isRenderable() const;
void adjustRadii();
+ // Tests whether the quad intersects any part of this rounded rectangle.
+ // This only works for convex quads.
+ bool intersectsQuad(const FloatQuad&) const;
+
private:
IntRect m_rect;
Radii m_radii;
Modified: trunk/Source/WebCore/rendering/HitTestLocation.cpp (145869 => 145870)
--- trunk/Source/WebCore/rendering/HitTestLocation.cpp 2013-03-15 03:30:26 UTC (rev 145869)
+++ trunk/Source/WebCore/rendering/HitTestLocation.cpp 2013-03-15 03:37:06 UTC (rev 145870)
@@ -180,6 +180,11 @@
return intersectsRect(rect);
}
+bool HitTestLocation::intersects(const RoundedRect& rect) const
+{
+ return rect.intersectsQuad(m_transformedRect);
+}
+
IntRect HitTestLocation::rectForPoint(const LayoutPoint& point, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding)
{
IntPoint actualPoint(flooredIntPoint(point));
Modified: trunk/Source/WebCore/rendering/HitTestLocation.h (145869 => 145870)
--- trunk/Source/WebCore/rendering/HitTestLocation.h 2013-03-15 03:30:26 UTC (rev 145869)
+++ trunk/Source/WebCore/rendering/HitTestLocation.h 2013-03-15 03:37:06 UTC (rev 145870)
@@ -26,6 +26,7 @@
#include "FloatRect.h"
#include "HitTestRequest.h"
#include "LayoutRect.h"
+#include "RoundedRect.h"
#include "TextDirection.h"
#include <wtf/Forward.h>
#include <wtf/ListHashSet.h>
@@ -78,6 +79,7 @@
bool intersects(const LayoutRect&) const;
bool intersects(const FloatRect&) const;
+ bool intersects(const RoundedRect&) const;
const FloatPoint& transformedPoint() const { return m_transformedPoint; }
const FloatQuad& transformedRect() const { return m_transformedRect; }
Modified: trunk/Source/WebCore/rendering/RenderBlock.cpp (145869 => 145870)
--- trunk/Source/WebCore/rendering/RenderBlock.cpp 2013-03-15 03:30:26 UTC (rev 145869)
+++ trunk/Source/WebCore/rendering/RenderBlock.cpp 2013-03-15 03:37:06 UTC (rev 145870)
@@ -4894,6 +4894,13 @@
LayoutRect overflowBox = visualOverflowRect();
flipForWritingMode(overflowBox);
overflowBox.moveBy(adjustedLocation);
+ if (style()->hasBorderRadius()) {
+ LayoutRect borderRect = borderBoxRect();
+ borderRect.moveBy(adjustedLocation);
+ RoundedRect border = style()->getRoundedBorderFor(borderRect, view());
+ if (!locationInContainer.intersects(border))
+ return false;
+ }
if (!locationInContainer.intersects(overflowBox))
return false;
}