Created
February 1, 2012 17:56
-
-
Save kenchris/1718330 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/ManualTests/qt/tap-highlighting-images.html b/ManualTests/qt/tap-highlighting-images.html | |
index bbeea1a..a5e2bf8 100644 | |
--- a/ManualTests/qt/tap-highlighting-images.html | |
+++ b/ManualTests/qt/tap-highlighting-images.html | |
@@ -1,6 +1,6 @@ | |
<body style="background-color: green"> | |
<p>Two anchors, one around a pure image, the other around an image embedded in a div.</p> | |
- <a href=""><img src="../resources/apple.jpg"></a> | |
- <a href=""><div style="background-color: blue;"><img style="display: block; margin-left: auto; margin-right: auto;" src="../resources/apple.jpg"></div></a> | |
+ <a href=""><img src="../resources/apple.jpg"></a><br><br> | |
+ <a href=""><div style="width: 400px; background-color: blue;"><img style="display: block; margin-left: auto; margin-right: auto;" src="../resources/apple.jpg"></div></a> | |
</body> | |
diff --git a/Source/WebCore/page/GestureTapHighlighter.cpp b/Source/WebCore/page/GestureTapHighlighter.cpp | |
index 7548abe..2038b0a 100644 | |
--- a/Source/WebCore/page/GestureTapHighlighter.cpp | |
+++ b/Source/WebCore/page/GestureTapHighlighter.cpp | |
@@ -81,41 +81,42 @@ AffineTransform localToAbsoluteTransform(const RenderObject* o) | |
return transform; | |
} | |
-Path pathForRenderBox(RenderBox* o) | |
+inline bool contains(const LayoutRect& rect, int x) | |
{ | |
- ASSERT(o); | |
- const int rounding = 4; | |
- | |
- LayoutRect contentBox; | |
- LayoutRect paddingBox; | |
- LayoutRect borderBox; | |
- | |
- contentBox = o->contentBoxRect(); | |
- paddingBox = LayoutRect( | |
- contentBox.x() - o->paddingLeft(), | |
- contentBox.y() - o->paddingTop(), | |
- contentBox.width() + o->paddingLeft() + o->paddingRight(), | |
- contentBox.height() + o->paddingTop() + o->paddingBottom()); | |
- borderBox = LayoutRect( | |
- paddingBox.x() - o->borderLeft(), | |
- paddingBox.y() - o->borderTop(), | |
- paddingBox.width() + o->borderLeft() + o->borderRight(), | |
- paddingBox.height() + o->borderTop() + o->borderBottom()); | |
+ return !rect.isEmpty() && x >= rect.x() && x <= rect.maxX(); | |
+} | |
- FloatRect rect(borderBox); | |
- rect.inflate(rounding); | |
+inline bool strikes(const LayoutRect& a, const LayoutRect& b) | |
+{ | |
+ return !a.isEmpty() && !b.isEmpty() | |
+ && a.x() <= b.maxX() && b.x() <= a.maxX() | |
+ && a.y() <= b.maxY() && b.y() <= a.maxY(); | |
+} | |
- rect.move(toLayoutSize(ownerFrameToMainFrameOffset(o))); | |
+inline void shiftXEdgesToContainIfStrikes(LayoutRect& rect, const LayoutRect& other) | |
+{ | |
+ int leftSide = rect.x(); | |
+ int rightSide = rect.maxX(); | |
- Path path; | |
- FloatSize rounded(rounding * 1.8, rounding * 1.8); | |
- path.addRoundedRect(rect, rounded); | |
+ if (!other.isEmpty() && strikes(rect, other)) { | |
+ leftSide = std::min(leftSide, other.x()); | |
+ rightSide = std::max(rightSide, other.maxX()); | |
+ } | |
- return path; | |
+ rect.setX(leftSide); | |
+ rect.setWidth(rightSide - leftSide); | |
} | |
-void addRectWithRoundedCorners(Path& path, const LayoutRect& rect, bool topLeft, bool topRight, bool bottomLeft, bool bottomRight) | |
+inline void addHighlightRect(Path& path, const LayoutRect& rect, const LayoutRect& prev, const LayoutRect& next) | |
{ | |
+ // The rounding check depends on the rects not intersecting eachother, | |
+ // or being contained for that matter. | |
+ ASSERT(!rect.intersects(prev)); | |
+ ASSERT(!rect.intersects(next)); | |
+ | |
+ if (rect.isEmpty()) | |
+ return; | |
+ | |
const int rounding = 4; | |
FloatRect copy(rect); | |
@@ -126,62 +127,60 @@ void addRectWithRoundedCorners(Path& path, const LayoutRect& rect, bool topLeft, | |
FloatSize squared(0, 0); | |
path.addBeziersForRoundedRect(copy, | |
- topLeft ? rounded : squared, topRight ? rounded : squared, | |
- bottomLeft ? rounded : squared, bottomRight ? rounded : squared); | |
-} | |
- | |
-inline bool contains(LayoutRect rect, int x) | |
-{ | |
- return !rect.isEmpty() && x >= rect.x() && x <= rect.maxX(); | |
+ contains(prev, rect.x()) ? squared : rounded, | |
+ contains(prev, rect.maxX()) ? squared : rounded, | |
+ contains(next, rect.x()) ? squared : rounded, | |
+ contains(next, rect.maxX()) ? squared : rounded); | |
} | |
-Path pathForRenderInline(RenderInline* o) | |
+Path pathForRenderer(RenderObject* o) | |
{ | |
ASSERT(o); | |
Path path; | |
Vector<LayoutRect> rects; | |
- o->absoluteRects(rects, /* acc. offset */ ownerFrameToMainFrameOffset(o)); | |
+ o->addFocusRingRects(rects, /* acc. offset */ ownerFrameToMainFrameOffset(o)); | |
- LayoutRect first = rects.size() ? rects.first() : LayoutRect(); | |
- LayoutRect last = rects.size() > 1 ? rects.last() : LayoutRect(); | |
- LayoutRect middle; | |
+ // The basic idea is to allow up to three different boxes in order to highlight | |
+ // text with line breaks more nicer than using a bounding box. | |
+ | |
+ // Merge all center boxes (all but the first and the last). | |
+ LayoutRect mid; | |
for (int i = 1; i < rects.size() - 1; ++i) | |
- middle.uniteIfNonZero(rects.at(i)); | |
- | |
- if (!middle.isEmpty()) { | |
- int leftSide = middle.x(); | |
- int rightSide = middle.maxX(); | |
- | |
- if (!first.isEmpty()) { | |
- leftSide = std::min(leftSide, first.x()); | |
- rightSide = std::max(rightSide, first.maxX()); | |
- } | |
- if (!last.isEmpty()) { | |
- leftSide = std::min(leftSide, last.x()); | |
- rightSide = std::max(rightSide, last.maxX()); | |
- } | |
- | |
- middle.setX(leftSide); | |
- middle.setWidth(rightSide - leftSide); | |
+ mid.uniteIfNonZero(rects.at(i)); | |
+ | |
+ Vector<LayoutRect> drawableRects; | |
+ | |
+ if (!mid.isEmpty()) | |
+ drawableRects.append(mid); | |
+ | |
+ // Add the first box, but merge it with the center boxes if it intersects. | |
+ if (rects.size() && !rects.first().isEmpty()) { | |
+ if (drawableRects.size() && drawableRects.last().intersects(rects.first())) | |
+ drawableRects.last().unite(rects.first()); | |
+ else | |
+ drawableRects.prepend(rects.first()); | |
} | |
- if (!first.isEmpty()) { | |
- bool roundBottomLeft = !contains(middle, first.x()) && !contains(last, first.x()); | |
- bool roundBottomRight = !contains(middle, first.maxX()) && !contains(last, first.maxX()); | |
- addRectWithRoundedCorners(path, first, /* roundTopLeft */ true, /* roundTopRight */ true, roundBottomLeft, roundBottomRight); | |
+ // Add the last box, but merge it with the center boxes if it intersects. | |
+ if (rects.size() > 1 && !rects.last().isEmpty()) { | |
+ if (drawableRects.size() && drawableRects.last().intersects(rects.last())) | |
+ drawableRects.last().unite(rects.last()); | |
+ else | |
+ drawableRects.append(rects.last()); | |
} | |
- if (!middle.isEmpty()) { | |
- bool roundTopLeft = !contains(first, middle.x()); | |
- bool roundBottomRight = !contains(last, middle.maxX()); | |
- addRectWithRoundedCorners(path, middle, roundTopLeft, /* roundTopRight */ false, /* roundBottomLeft */ false, roundBottomRight); | |
+ // Adjust middle to boundaries of first and last. | |
+ if (drawableRects.size() == 3) { | |
+ LayoutRect& middle = drawableRects.at(1); | |
+ shiftXEdgesToContainIfStrikes(middle, drawableRects.at(0)); | |
+ shiftXEdgesToContainIfStrikes(middle, drawableRects.at(2)); | |
} | |
- if (!last.isEmpty()) { | |
- bool roundTopLeft = !contains(middle, last.x()) && !contains(first, last.x()); | |
- bool roundTopRight = !contains(middle, last.maxX()) && !contains(first, last.maxX()); | |
- addRectWithRoundedCorners(path, last, roundTopLeft, roundTopRight, /* roundBottomLeft */ true, /* roundBottomRight */ true); | |
+ for (int i = 0; i < drawableRects.size(); ++i) { | |
+ LayoutRect prev = (i - 1) >= 0 ? drawableRects.at(i - 1) : LayoutRect(); | |
+ LayoutRect next = (i + 1) < drawableRects.size() ? drawableRects.at(i + 1) : LayoutRect(); | |
+ addHighlightRect(path, drawableRects.at(i), prev, next); | |
} | |
return path; | |
@@ -199,12 +198,9 @@ Path pathForNodeHighlight(const Node* node) | |
if (!renderer || (!renderer->isBox() && !renderer->isRenderInline())) | |
return path; | |
- if (renderer->isBox()) | |
- path = pathForRenderBox(toRenderBox(renderer)); | |
- else | |
- path = pathForRenderInline(toRenderInline(renderer)); | |
- | |
+ path = pathForRenderer(renderer); | |
path.transform(localToAbsoluteTransform(renderer)); | |
+ | |
return path; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment