summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Reck <jreck@google.com>2012-01-13 13:31:40 -0800
committerJohn Reck <jreck@google.com>2012-01-13 14:17:42 -0800
commit14be0ec9a67949d5d05e778fefe8d944a74dd486 (patch)
tree68f0dc71689c41c7cda0632028da1d9f362bbcb0
parentba81e047f713341871d6c084845963bfdc1d4aa2 (diff)
downloadexternal_webkit-14be0ec9a67949d5d05e778fefe8d944a74dd486.zip
external_webkit-14be0ec9a67949d5d05e778fefe8d944a74dd486.tar.gz
external_webkit-14be0ec9a67949d5d05e778fefe8d944a74dd486.tar.bz2
Refactor hit test object
Change-Id: I9729ca695fda4eefd3aa57d96a872010a3cfba9a
-rw-r--r--Source/WebKit/Android.mk1
-rw-r--r--Source/WebKit/android/jni/AndroidHitTestResult.cpp154
-rw-r--r--Source/WebKit/android/jni/AndroidHitTestResult.h55
-rw-r--r--Source/WebKit/android/jni/WebViewCore.cpp351
-rw-r--r--Source/WebKit/android/jni/WebViewCore.h3
5 files changed, 361 insertions, 203 deletions
diff --git a/Source/WebKit/Android.mk b/Source/WebKit/Android.mk
index fb6ee31..c715609 100644
--- a/Source/WebKit/Android.mk
+++ b/Source/WebKit/Android.mk
@@ -60,6 +60,7 @@ LOCAL_SRC_FILES += \
\
android/icu/unicode/ucnv.cpp \
\
+ android/jni/AndroidHitTestResult.cpp \
android/jni/CacheManager.cpp \
android/jni/CookieManager.cpp \
android/jni/DeviceMotionAndOrientationManager.cpp \
diff --git a/Source/WebKit/android/jni/AndroidHitTestResult.cpp b/Source/WebKit/android/jni/AndroidHitTestResult.cpp
new file mode 100644
index 0000000..fed8a67
--- /dev/null
+++ b/Source/WebKit/android/jni/AndroidHitTestResult.cpp
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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 HOLDERS ``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 OWNER OR
+ * CONTRIBUTORS 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.
+ */
+
+#define LOG_TAG "AndroidHitTestResult"
+
+#include "config.h"
+#include "AndroidHitTestResult.h"
+
+#include "Element.h"
+#include "HitTestResult.h"
+#include "KURL.h"
+#include "PlatformString.h"
+#include "WebCoreJni.h"
+
+#include <JNIHelp.h>
+#include <JNIUtility.h>
+
+namespace android {
+
+using namespace WebCore;
+
+static bool gJniInitialized = false;
+static struct JavaGlue {
+ jmethodID m_rectInit;
+
+ jmethodID m_hitTestInit;
+ jfieldID m_hitTestLinkUrl;
+ jfieldID m_hitTestAnchorText;
+ jfieldID m_hitTestImageUrl;
+ jfieldID m_hitTestAltDisplayString;
+ jfieldID m_hitTestTitle;
+ jfieldID m_hitTestEditable;
+ jfieldID m_hitTestTouchRects;
+} gJavaGlue;
+
+struct field {
+ jclass m_class;
+ const char *m_fieldName;
+ const char *m_fieldType;
+ jfieldID *m_jfield;
+};
+
+static void InitJni(JNIEnv* env)
+{
+ if (gJniInitialized)
+ return;
+
+ jclass rectClass = env->FindClass("android/graphics/Rect");
+ ALOG_ASSERT(rectClass, "Could not find android/graphics/Rect");
+ jclass hitTestClass = env->FindClass("android/webkit/WebViewCore$WebKitHitTest");
+ ALOG_ASSERT(hitTestClass, "Could not find android/webkit/WebViewCore$WebKitHitTest");
+
+ gJavaGlue.m_rectInit = env->GetMethodID(rectClass, "<init>", "(IIII)V");
+ ALOG_ASSERT(gJavaGlue.m_rectInit, "Could not find init method on Rect");
+
+ gJavaGlue.m_hitTestInit = env->GetMethodID(hitTestClass, "<init>", "()V");
+ ALOG_ASSERT(gJavaGlue.m_hitTestInit, "Could not find init method on android/webkit/WebViewCore$WebKitHitTest");
+
+ field fields[] = {
+ { hitTestClass, "mTouchRects", "[Landroid/graphics/Rect;", &gJavaGlue.m_hitTestTouchRects },
+ { hitTestClass, "mEditable", "Z", &gJavaGlue.m_hitTestEditable },
+ { hitTestClass, "mLinkUrl", "Ljava/lang/String;", &gJavaGlue.m_hitTestLinkUrl },
+ { hitTestClass, "mAnchorText", "Ljava/lang/String;", &gJavaGlue.m_hitTestAnchorText },
+ { hitTestClass, "mImageUrl", "Ljava/lang/String;", &gJavaGlue.m_hitTestImageUrl },
+ { hitTestClass, "mAltDisplayString", "Ljava/lang/String;", &gJavaGlue.m_hitTestAltDisplayString },
+ { hitTestClass, "mTitle", "Ljava/lang/String;", &gJavaGlue.m_hitTestTitle },
+ {0, 0, 0, 0},
+ };
+
+ for (int i = 0; fields[i].m_jfield; i++) {
+ field *f = &fields[i];
+ jfieldID field = env->GetFieldID(f->m_class, f->m_fieldName, f->m_fieldType);
+ ALOG_ASSERT(field, "Can't find %s", f->m_fieldName);
+ *(f->m_jfield) = field;
+ }
+
+ gJniInitialized = true;
+}
+
+AndroidHitTestResult::AndroidHitTestResult(WebCore::HitTestResult& hitTestResult)
+ : m_hitTestResult(hitTestResult)
+{
+}
+
+void setStringField(JNIEnv* env, jobject obj, jfieldID field, const String& str)
+{
+ jstring jstr = wtfStringToJstring(env, str, false);
+ env->SetObjectField(obj, field, jstr);
+ env->DeleteLocalRef(jstr);
+}
+
+// Some helper macros specific to setting hitTest fields
+#define _SET(jtype, jfield, value) env->Set ## jtype ## Field(hitTest, gJavaGlue.m_hitTest ## jfield, value)
+#define SET_BOOL(jfield, value) _SET(Boolean, jfield, value)
+#define SET_STRING(jfield, value) setStringField(env, hitTest, gJavaGlue.m_hitTest ## jfield, value)
+
+jobject AndroidHitTestResult::createJavaObject(JNIEnv* env)
+{
+ InitJni(env);
+ jclass rectClass = env->FindClass("android/graphics/Rect");
+ ALOG_ASSERT(rectClass, "Could not find android/graphics/Rect");
+ jclass hitTestClass = env->FindClass("android/webkit/WebViewCore$WebKitHitTest");
+ ALOG_ASSERT(hitTestClass, "Could not find android/webkit/WebViewCore$WebKitHitTest");
+
+ jobjectArray array = env->NewObjectArray(m_highlightRects.size(), rectClass, 0);
+ ALOG_ASSERT(array, "Could not create a Rect array");
+
+ for (size_t i = 0; i < m_highlightRects.size(); i++) {
+ jobject rect = env->NewObject(rectClass, gJavaGlue.m_rectInit,
+ m_highlightRects[i].x(), m_highlightRects[i].y(),
+ m_highlightRects[i].maxX(), m_highlightRects[i].maxY());
+ if (rect) {
+ env->SetObjectArrayElement(array, i, rect);
+ env->DeleteLocalRef(rect);
+ }
+ }
+
+ TextDirection titleTextDirection;
+ jobject hitTest = env->NewObject(hitTestClass, gJavaGlue.m_hitTestInit);
+ env->SetObjectField(hitTest, gJavaGlue.m_hitTestTouchRects, array);
+ SET_BOOL(Editable, m_hitTestResult.isContentEditable());
+ SET_STRING(LinkUrl, m_hitTestResult.absoluteLinkURL().string());
+ SET_STRING(ImageUrl, m_hitTestResult.absoluteImageURL().string());
+ SET_STRING(AltDisplayString, m_hitTestResult.altDisplayString());
+ SET_STRING(Title, m_hitTestResult.title(titleTextDirection));
+ if (m_hitTestResult.URLElement())
+ SET_STRING(AnchorText, m_hitTestResult.URLElement()->innerText());
+
+ return hitTest;
+}
+
+} /* namespace android */
diff --git a/Source/WebKit/android/jni/AndroidHitTestResult.h b/Source/WebKit/android/jni/AndroidHitTestResult.h
new file mode 100644
index 0000000..28a9ee3
--- /dev/null
+++ b/Source/WebKit/android/jni/AndroidHitTestResult.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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 HOLDERS ``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 OWNER OR
+ * CONTRIBUTORS 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 AndroidHitTestResult_h
+#define AndroidHitTestResult_h
+
+#include "HitTestResult.h"
+#include "IntRect.h"
+#include "wtf/Vector.h"
+
+#include <jni.h>
+
+namespace android {
+
+class AndroidHitTestResult
+{
+public:
+ AndroidHitTestResult(WebCore::HitTestResult&);
+ ~AndroidHitTestResult() {}
+
+ WebCore::HitTestResult& hitTestResult() { return m_hitTestResult; }
+ Vector<WebCore::IntRect>& highlightRects() { return m_highlightRects; }
+
+ jobject createJavaObject(JNIEnv*);
+
+private:
+ WebCore::HitTestResult m_hitTestResult;
+ Vector<WebCore::IntRect> m_highlightRects;
+};
+
+} // namespace android
+
+#endif // AndroidHitTestResult_h
diff --git a/Source/WebKit/android/jni/WebViewCore.cpp b/Source/WebKit/android/jni/WebViewCore.cpp
index 42e71b2..7fb10bf 100644
--- a/Source/WebKit/android/jni/WebViewCore.cpp
+++ b/Source/WebKit/android/jni/WebViewCore.cpp
@@ -29,6 +29,7 @@
#include "WebViewCore.h"
#include "AccessibilityObject.h"
+#include "AndroidHitTestResult.h"
#include "Attribute.h"
#include "BaseLayerAndroid.h"
#include "CachedNode.h"
@@ -1637,7 +1638,8 @@ void WebViewCore::updateFrameCacheIfLoading()
#endif
struct TouchNodeData {
- Node* mNode;
+ Node* mUrlNode;
+ Node* mInnerNode;
IntRect mBounds;
};
@@ -1661,135 +1663,135 @@ static IntRect getAbsoluteBoundingBox(Node* node) {
}
// get the highlight rectangles for the touch point (x, y) with the slop
-Vector<IntRect> WebViewCore::getTouchHighlightRects(int x, int y, int slop,
- Node** node, HitTestResult* hitTestResult)
+AndroidHitTestResult WebViewCore::hitTestAtPoint(int x, int y, int slop, bool doMoveMouse)
{
- Vector<IntRect> rects;
- moveMouse(m_mainFrame, x, y);
- *hitTestResult = m_mainFrame->eventHandler()->hitTestResultAtPoint(IntPoint(x, y),
+ if (doMoveMouse)
+ moveMouse(m_mainFrame, x, y);
+ HitTestResult hitTestResult = m_mainFrame->eventHandler()->hitTestResultAtPoint(IntPoint(x, y),
false, false, DontHitTestScrollbars, HitTestRequest::Active | HitTestRequest::ReadOnly, IntSize(slop, slop));
- if (!hitTestResult->innerNode() || !hitTestResult->innerNode()->inDocument()) {
+ AndroidHitTestResult androidHitResult(hitTestResult);
+ if (!hitTestResult.innerNode() || !hitTestResult.innerNode()->inDocument()) {
ALOGE("Should not happen: no in document Node found");
- return rects;
+ return androidHitResult;
}
- const ListHashSet<RefPtr<Node> >& list = hitTestResult->rectBasedTestResult();
+ const ListHashSet<RefPtr<Node> >& list = hitTestResult.rectBasedTestResult();
if (list.isEmpty()) {
ALOGE("Should not happen: no rect-based-test nodes found");
- return rects;
+ return androidHitResult;
}
- Frame* frame = hitTestResult->innerNode()->document()->frame();
+ Frame* frame = hitTestResult.innerNode()->document()->frame();
Vector<TouchNodeData> nodeDataList;
- if (hitTestResult->innerNode() != hitTestResult->innerNonSharedNode()
- && hitTestResult->innerNode()->hasTagName(WebCore::HTMLNames::areaTag)) {
- TouchNodeData newNode;
- HTMLAreaElement* area = static_cast<HTMLAreaElement*>(hitTestResult->innerNode());
- newNode.mNode = area;
- newNode.mBounds = area->computeRect(hitTestResult->innerNonSharedNode()->renderer());
- nodeDataList.append(newNode);
- } else {
- ListHashSet<RefPtr<Node> >::const_iterator last = list.end();
- for (ListHashSet<RefPtr<Node> >::const_iterator it = list.begin(); it != last; ++it) {
- // TODO: it seems reasonable to not search across the frame. Isn't it?
- // if the node is not in the same frame as the innerNode, skip it
- if (it->get()->document()->frame() != frame)
- continue;
- // traverse up the tree to find the first node that needs highlight
- bool found = false;
- Node* eventNode = it->get();
- while (eventNode) {
- RenderObject* render = eventNode->renderer();
- if (render && (render->isBody() || render->isRenderView()))
- break;
- if (eventNode->supportsFocus()
- || eventNode->hasEventListeners(eventNames().clickEvent)
- || eventNode->hasEventListeners(eventNames().mousedownEvent)
- || eventNode->hasEventListeners(eventNames().mouseupEvent)
- || eventNode->hasEventListeners(eventNames().mouseoverEvent)) {
- found = true;
- break;
- }
- // the nodes in the rectBasedTestResult() are ordered based on z-index during hit testing.
- // so do not search for the eventNode across explicit z-index border.
- // TODO: this is a hard one to call. z-index is quite complicated as its value only
- // matters when you compare two RenderLayer in the same hierarchy level. e.g. in
- // the following example, "b" is on the top as its z level is the highest. even "c"
- // has 100 as z-index, it is still below "d" as its parent has the same z-index as
- // "d" and logically before "d". Of course "a" is the lowest in the z level.
- //
- // z-index:auto "a"
- // z-index:2 "b"
- // z-index:1
- // z-index:100 "c"
- // z-index:1 "d"
- //
- // If the fat point touches everyone, the order in the list should be "b", "d", "c"
- // and "a". When we search for the event node for "b", we really don't want "a" as
- // in the z-order it is behind everything else.
- if (render && !render->style()->hasAutoZIndex())
- break;
- eventNode = eventNode->parentNode();
+ if (hitTestResult.innerNode() != hitTestResult.innerNonSharedNode()
+ && hitTestResult.innerNode()->hasTagName(WebCore::HTMLNames::areaTag)) {
+ HTMLAreaElement* area = static_cast<HTMLAreaElement*>(hitTestResult.innerNode());
+ androidHitResult.hitTestResult().setURLElement(area);
+ androidHitResult.highlightRects().append(area->computeRect(
+ hitTestResult.innerNonSharedNode()->renderer()));
+ return androidHitResult;
+ }
+ ListHashSet<RefPtr<Node> >::const_iterator last = list.end();
+ for (ListHashSet<RefPtr<Node> >::const_iterator it = list.begin(); it != last; ++it) {
+ // TODO: it seems reasonable to not search across the frame. Isn't it?
+ // if the node is not in the same frame as the innerNode, skip it
+ if (it->get()->document()->frame() != frame)
+ continue;
+ // traverse up the tree to find the first node that needs highlight
+ bool found = false;
+ Node* eventNode = it->get();
+ Node* innerNode = eventNode;
+ while (eventNode) {
+ RenderObject* render = eventNode->renderer();
+ if (render && (render->isBody() || render->isRenderView()))
+ break;
+ if (eventNode->supportsFocus()
+ || eventNode->hasEventListeners(eventNames().clickEvent)
+ || eventNode->hasEventListeners(eventNames().mousedownEvent)
+ || eventNode->hasEventListeners(eventNames().mouseupEvent)
+ || eventNode->hasEventListeners(eventNames().mouseoverEvent)) {
+ found = true;
+ break;
}
- // didn't find any eventNode, skip it
- if (!found)
- continue;
- // first quick check whether it is a duplicated node before computing bounding box
- Vector<TouchNodeData>::const_iterator nlast = nodeDataList.end();
- for (Vector<TouchNodeData>::const_iterator n = nodeDataList.begin(); n != nlast; ++n) {
- // found the same node, skip it
- if (eventNode == n->mNode) {
- found = false;
- break;
- }
+ // the nodes in the rectBasedTestResult() are ordered based on z-index during hit testing.
+ // so do not search for the eventNode across explicit z-index border.
+ // TODO: this is a hard one to call. z-index is quite complicated as its value only
+ // matters when you compare two RenderLayer in the same hierarchy level. e.g. in
+ // the following example, "b" is on the top as its z level is the highest. even "c"
+ // has 100 as z-index, it is still below "d" as its parent has the same z-index as
+ // "d" and logically before "d". Of course "a" is the lowest in the z level.
+ //
+ // z-index:auto "a"
+ // z-index:2 "b"
+ // z-index:1
+ // z-index:100 "c"
+ // z-index:1 "d"
+ //
+ // If the fat point touches everyone, the order in the list should be "b", "d", "c"
+ // and "a". When we search for the event node for "b", we really don't want "a" as
+ // in the z-order it is behind everything else.
+ if (render && !render->style()->hasAutoZIndex())
+ break;
+ eventNode = eventNode->parentNode();
+ }
+ // didn't find any eventNode, skip it
+ if (!found)
+ continue;
+ // first quick check whether it is a duplicated node before computing bounding box
+ Vector<TouchNodeData>::const_iterator nlast = nodeDataList.end();
+ for (Vector<TouchNodeData>::const_iterator n = nodeDataList.begin(); n != nlast; ++n) {
+ // found the same node, skip it
+ if (eventNode == n->mUrlNode) {
+ found = false;
+ break;
}
- if (!found)
+ }
+ if (!found)
+ continue;
+ // next check whether the node is fully covered by or fully covering another node.
+ found = false;
+ IntRect rect = getAbsoluteBoundingBox(eventNode);
+ if (rect.isEmpty()) {
+ // if the node's bounds is empty and it is not a ContainerNode, skip it.
+ if (!eventNode->isContainerNode())
continue;
- // next check whether the node is fully covered by or fully covering another node.
- found = false;
- IntRect rect = getAbsoluteBoundingBox(eventNode);
- if (rect.isEmpty()) {
- // if the node's bounds is empty and it is not a ContainerNode, skip it.
- if (!eventNode->isContainerNode())
- continue;
- // if the node's children are all positioned objects, its bounds can be empty.
- // Walk through the children to find the bounding box.
- Node* child = static_cast<const ContainerNode*>(eventNode)->firstChild();
- while (child) {
- IntRect childrect;
- if (child->renderer())
- childrect = getAbsoluteBoundingBox(child);
- if (!childrect.isEmpty()) {
- rect.unite(childrect);
- child = child->traverseNextSibling(eventNode);
- } else
- child = child->traverseNextNode(eventNode);
- }
- }
- for (int i = nodeDataList.size() - 1; i >= 0; i--) {
- TouchNodeData n = nodeDataList.at(i);
- // the new node is enclosing an existing node, skip it
- if (rect.contains(n.mBounds)) {
- found = true;
- break;
- }
- // the new node is fully inside an existing node, remove the existing node
- if (n.mBounds.contains(rect))
- nodeDataList.remove(i);
+ // if the node's children are all positioned objects, its bounds can be empty.
+ // Walk through the children to find the bounding box.
+ Node* child = static_cast<const ContainerNode*>(eventNode)->firstChild();
+ while (child) {
+ IntRect childrect;
+ if (child->renderer())
+ childrect = getAbsoluteBoundingBox(child);
+ if (!childrect.isEmpty()) {
+ rect.unite(childrect);
+ child = child->traverseNextSibling(eventNode);
+ } else
+ child = child->traverseNextNode(eventNode);
}
- if (!found) {
- TouchNodeData newNode;
- newNode.mNode = eventNode;
- newNode.mBounds = rect;
- nodeDataList.append(newNode);
+ }
+ for (int i = nodeDataList.size() - 1; i >= 0; i--) {
+ TouchNodeData n = nodeDataList.at(i);
+ // the new node is enclosing an existing node, skip it
+ if (rect.contains(n.mBounds)) {
+ found = true;
+ break;
}
+ // the new node is fully inside an existing node, remove the existing node
+ if (n.mBounds.contains(rect))
+ nodeDataList.remove(i);
}
- if (!nodeDataList.size()) {
- *node = 0;
- return rects;
+ if (!found) {
+ TouchNodeData newNode;
+ newNode.mUrlNode = eventNode;
+ newNode.mBounds = rect;
+ newNode.mInnerNode = innerNode;
+ nodeDataList.append(newNode);
}
}
+ if (!nodeDataList.size()) {
+ return androidHitResult;
+ }
// finally select the node with the largest overlap with the fat point
TouchNodeData final;
- final.mNode = 0;
+ final.mUrlNode = 0;
IntPoint docPos = frame->view()->windowToContents(m_mousePos);
IntRect testRect(docPos.x() - slop, docPos.y() - slop, 2 * slop + 1, 2 * slop + 1);
int area = 0;
@@ -1804,23 +1806,32 @@ Vector<IntRect> WebViewCore::getTouchHighlightRects(int x, int y, int slop,
}
}
// now get the node's highlight rectangles in the page coordinate system
- if (final.mNode) {
- if (final.mNode->isElementNode()) {
+ if (final.mUrlNode) {
+ if (final.mUrlNode->isElementNode()) {
// We found a URL element. Update the hitTestResult
- *node = final.mNode;
- hitTestResult->setURLElement(static_cast<Element*>(final.mNode));
+ androidHitResult.hitTestResult().setURLElement(static_cast<Element*>(final.mUrlNode));
+ } else {
+ androidHitResult.hitTestResult().setURLElement(0);
}
+ // Update innerNode and innerNonSharedNode
+ androidHitResult.hitTestResult().setInnerNode(final.mInnerNode);
+ androidHitResult.hitTestResult().setInnerNonSharedNode(final.mInnerNode);
IntPoint frameAdjust;
if (frame != m_mainFrame) {
frameAdjust = frame->view()->contentsToWindow(IntPoint());
frameAdjust.move(m_scrollOffsetX, m_scrollOffsetY);
}
- if (final.mNode->isLink() && final.mNode->renderer()) {
+ Vector<IntRect>& rects = androidHitResult.highlightRects();
+ if (final.mUrlNode->isLink() && final.mUrlNode->renderer()) {
// most of the links are inline instead of box style. So the bounding box is not
// a good representation for the highlights. Get the list of rectangles instead.
- RenderObject* render = final.mNode->renderer();
+ RenderObject* render = final.mUrlNode->renderer();
IntPoint offset = roundedIntPoint(render->localToAbsolute());
render->absoluteRects(rects, offset.x() + frameAdjust.x(), offset.y() + frameAdjust.y());
+ if (final.mInnerNode && final.mInnerNode->renderer()) {
+ final.mInnerNode->renderer()->absoluteRects(rects,
+ offset.x() + frameAdjust.x(), offset.y() + frameAdjust.y());
+ }
bool inside = false;
int distance = INT_MAX;
int newx = x, newy = y;
@@ -1868,7 +1879,7 @@ Vector<IntRect> WebViewCore::getTouchHighlightRects(int x, int y, int slop,
}
}
if (!rects.isEmpty()) {
- if (!inside) {
+ if (!inside && doMoveMouse) {
// if neither x nor y has overlap, just pick the top/left of the first rectangle
if (newx == x && newy == y) {
newx = rects[0].x();
@@ -1879,23 +1890,25 @@ Vector<IntRect> WebViewCore::getTouchHighlightRects(int x, int y, int slop,
x, y, m_mousePos.x() + m_scrollOffsetX, m_mousePos.y() + m_scrollOffsetY,
m_scrollOffsetX, m_scrollOffsetY);
}
- return rects;
+ return androidHitResult;
}
}
IntRect rect = final.mBounds;
rect.move(frameAdjust.x(), frameAdjust.y());
rects.append(rect);
- // adjust m_mousePos if it is not inside the returned highlight rectangle
- testRect.move(frameAdjust.x(), frameAdjust.y());
- testRect.intersect(rect);
- if (!testRect.contains(x, y)) {
- moveMouse(m_mainFrame, testRect.center().x(), testRect.center().y());
- DBG_NAV_LOGD("Move x/y from (%d, %d) to (%d, %d) scrollOffset is (%d, %d)",
- x, y, m_mousePos.x() + m_scrollOffsetX, m_mousePos.y() + m_scrollOffsetY,
- m_scrollOffsetX, m_scrollOffsetY);
+ if (doMoveMouse) {
+ // adjust m_mousePos if it is not inside the returned highlight rectangle
+ testRect.move(frameAdjust.x(), frameAdjust.y());
+ testRect.intersect(rect);
+ if (!testRect.contains(x, y)) {
+ moveMouse(m_mainFrame, testRect.center().x(), testRect.center().y());
+ DBG_NAV_LOGD("Move x/y from (%d, %d) to (%d, %d) scrollOffset is (%d, %d)",
+ x, y, m_mousePos.x() + m_scrollOffsetX, m_mousePos.y() + m_scrollOffsetY,
+ m_scrollOffsetX, m_scrollOffsetY);
+ }
}
}
- return rects;
+ return androidHitResult;
}
///////////////////////////////////////////////////////////////////////////////
@@ -4559,84 +4572,16 @@ static bool ValidNodeAndBounds(JNIEnv* env, jobject obj, jint nativeClass,
reinterpret_cast<Node*>(node), nativeRect);
}
-static int GetHitTestExtra(Node* node, HitTestResult& hitTestResult, WTF::String& extra)
-{
- /*
- UNKNOWN_TYPE = 0;
- PHONE_TYPE = 2;
- GEO_TYPE = 3;
- EMAIL_TYPE = 4;
- IMAGE_TYPE = 5;
- SRC_ANCHOR_TYPE = 7;
- SRC_IMAGE_ANCHOR_TYPE = 8;
- EDIT_TEXT_TYPE = 9;
- */
- if (!node)
- return 0;
- KURL imageUrl = hitTestResult.absoluteImageURL();
- if (node->isLink()) {
- if (!imageUrl.isEmpty()) {
- extra = imageUrl.string();
- return 8;
- }
- extra = hitTestResult.absoluteLinkURL();
- return 7;
-
- }
- if (!imageUrl.isEmpty()) {
- extra = imageUrl.string();
- return 5;
- }
- if (hitTestResult.isContentEditable()) {
- return 9;
- }
- return 0;
-}
-
-static jobject HitTest(JNIEnv* env, jobject obj, jint nativeClass, jint x, jint y, jint slop)
+static jobject HitTest(JNIEnv* env, jobject obj, jint nativeClass, jint x,
+ jint y, jint slop, jboolean doMoveMouse)
{
WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
if (!viewImpl)
return 0;
Node* node = 0;
- HitTestResult hitTestResult;
- Vector<IntRect> rects = viewImpl->getTouchHighlightRects(x, y, slop, &node, &hitTestResult);
- if (rects.isEmpty() && !node)
- return 0;
-
- jclass rectClass = env->FindClass("android/graphics/Rect");
- ALOG_ASSERT(rectClass, "Could not find android/graphics/Rect");
- jmethodID rectinit = env->GetMethodID(rectClass, "<init>", "(IIII)V");
- ALOG_ASSERT(rectinit, "Could not find init method on Rect");
- jobjectArray array = env->NewObjectArray(rects.size(), rectClass, 0);
- ALOG_ASSERT(array, "Could not create a Rect array");
-
- for (size_t i = 0; i < rects.size(); i++) {
- jobject rect = env->NewObject(rectClass, rectinit, rects[i].x(),
- rects[i].y(), rects[i].maxX(), rects[i].maxY());
- if (rect) {
- env->SetObjectArrayElement(array, i, rect);
- env->DeleteLocalRef(rect);
- }
- }
-
- env->DeleteLocalRef(rectClass);
-
- jclass hitTestClass = env->FindClass("android/webkit/WebViewCore$WebKitHitTest");
- ALOG_ASSERT(hitTestClass, "Could not find android/webkit/WebViewCore$WebKitHitTest");
- jmethodID hitTestInit = env->GetMethodID(hitTestClass, "<init>", "()V");
- jobject hitTest = env->NewObject(hitTestClass, hitTestInit);
- jfieldID htTouchRects = env->GetFieldID(hitTestClass, "mTouchRects", "[Landroid/graphics/Rect;");
- env->SetObjectField(hitTest, htTouchRects, array);
- jfieldID htType = env->GetFieldID(hitTestClass, "mType", "I");
- jfieldID htExtra = env->GetFieldID(hitTestClass, "mExtra", "Ljava/lang/String;");
- WTF::String extra;
- int type = GetHitTestExtra(node, hitTestResult, extra);
- env->SetIntField(hitTest, htType, type);
- jstring jextra = wtfStringToJstring(env, extra, false);
- env->SetObjectField(hitTest, htExtra, jextra);
- env->DeleteLocalRef(hitTestClass);
- return hitTest;
+ AndroidHitTestResult result = viewImpl->hitTestAtPoint(x, y, slop, doMoveMouse);
+ Vector<IntRect>& rects = result.highlightRects();
+ return result.createJavaObject(env);
}
static void AutoFillForm(JNIEnv* env, jobject obj, jint nativeClass,
@@ -4782,7 +4727,7 @@ static JNINativeMethod gJavaWebViewCoreMethods[] = {
(void*) PluginSurfaceReady },
{ "nativeValidNodeAndBounds", "(IIILandroid/graphics/Rect;)Z",
(void*) ValidNodeAndBounds },
- { "nativeHitTest", "(IIII)Landroid/webkit/WebViewCore$WebKitHitTest;",
+ { "nativeHitTest", "(IIIIZ)Landroid/webkit/WebViewCore$WebKitHitTest;",
(void*) HitTest },
{ "nativeAutoFillForm", "(II)V",
(void*) AutoFillForm },
diff --git a/Source/WebKit/android/jni/WebViewCore.h b/Source/WebKit/android/jni/WebViewCore.h
index 9e7c4af..0f38ccf 100644
--- a/Source/WebKit/android/jni/WebViewCore.h
+++ b/Source/WebKit/android/jni/WebViewCore.h
@@ -101,6 +101,7 @@ namespace android {
class CachedNode;
class CachedRoot;
class ListBoxReply;
+ class AndroidHitTestResult;
class WebCoreReply : public WebCoreRefObject {
public:
@@ -526,6 +527,8 @@ namespace android {
// return a list of rects matching the touch point (x, y) with the slop
Vector<IntRect> getTouchHighlightRects(int x, int y, int slop,
Node** node, HitTestResult* hitTestResult);
+ // This does a sloppy hit test
+ AndroidHitTestResult hitTestAtPoint(int x, int y, int slop, bool doMoveMouse = false);
// Open a file chooser for selecting a file to upload
void openFileChooser(PassRefPtr<WebCore::FileChooser> );