summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Source/WebCore/platform/graphics/android/GLExtras.cpp4
-rw-r--r--Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp6
-rw-r--r--Source/WebCore/platform/graphics/android/VerticalTextMap.cpp7
-rw-r--r--Source/WebCore/platform/graphics/android/android_graphics.cpp23
-rw-r--r--Source/WebCore/platform/graphics/android/android_graphics.h4
-rw-r--r--Source/WebCore/rendering/RenderLayerCompositor.cpp14
-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/JavaSharedClient.cpp47
-rw-r--r--Source/WebKit/android/jni/WebHistory.cpp475
-rw-r--r--Source/WebKit/android/jni/WebViewCore.cpp358
-rw-r--r--Source/WebKit/android/jni/WebViewCore.h3
-rw-r--r--Source/WebKit/android/plugins/ANPSoundInterface.cpp2
14 files changed, 705 insertions, 448 deletions
diff --git a/Source/WebCore/platform/graphics/android/GLExtras.cpp b/Source/WebCore/platform/graphics/android/GLExtras.cpp
index bf489c9..9ad369a 100644
--- a/Source/WebCore/platform/graphics/android/GLExtras.cpp
+++ b/Source/WebCore/platform/graphics/android/GLExtras.cpp
@@ -165,6 +165,10 @@ void GLExtras::drawRegion(const SkRegion& region, bool fill,
void GLExtras::drawCursorRings(const LayerAndroid* layer)
{
+ int layerId = layer ? layer->uniqueId() : -1;
+ if (layerId != m_ring->layerId())
+ return;
+
SkRegion region;
for (size_t i = 0; i < m_ring->rings().size(); i++) {
IntRect rect = m_ring->rings().at(i);
diff --git a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp
index fc2eddd..779eb36 100644
--- a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp
+++ b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp
@@ -588,8 +588,10 @@ bool GraphicsLayerAndroid::repaint()
RenderBox* box = layer->renderBox();
int outline = box->view()->maximalOutlineSize();
IntRect contentsRect(0, 0,
- box->borderLeft() + box->borderRight() + layer->scrollWidth(),
- box->borderTop() + box->borderBottom() + layer->scrollHeight());
+ box->borderLeft() + box->borderRight() + layer->scrollWidth()
+ + layer->verticalScrollbarWidth(),
+ box->borderTop() + box->borderBottom() + layer->scrollHeight()
+ + layer->horizontalScrollbarHeight());
contentsRect.inflate(outline);
// Update the foreground layer size.
m_foregroundLayer->setSize(contentsRect.width(), contentsRect.height());
diff --git a/Source/WebCore/platform/graphics/android/VerticalTextMap.cpp b/Source/WebCore/platform/graphics/android/VerticalTextMap.cpp
index 47c0613..42aa385 100644
--- a/Source/WebCore/platform/graphics/android/VerticalTextMap.cpp
+++ b/Source/WebCore/platform/graphics/android/VerticalTextMap.cpp
@@ -33,7 +33,6 @@
#include <wtf/RefPtr.h>
static const UChar vTextCnvTable[][2] = {
- // TODO: uncomment mappings once we add glyphs for vertical forms.
{0x0021, 0xfe15}, // exclamation mark
{0x0028, 0xfe35}, // left paren
{0x0029, 0xfe36}, // right paren
@@ -55,8 +54,7 @@ static const UChar vTextCnvTable[][2] = {
{0x2015, 0xfe31}, // horizontal bar
{0x2025, 0xfe30}, // two dot leader
{0x2026, 0xfe19}, // three dot leader
- // TODO: change the mapping 0x3001 -> 0xFE11 once Android has the glyph for 0xFE11.
- {0x3001, 0xfe10}, // Ideographic comma
+ {0x3001, 0xfe11}, // Ideographic comma
{0x3002, 0xfe12}, // Ideographic full stop
{0x3008, 0xfe3f}, // left angle bracket
{0x3009, 0xfe40}, // right angle bracket
@@ -83,8 +81,7 @@ static const UChar vTextCnvTable[][2] = {
{0xff5c, 0xfe31}, // fullwidth vertical line
{0xff5d, 0xfe38}, // full width right curly bracket
{0xff5e, 0x007c}, // tilde to vertical line
- // TODO: change the mapping 0xff64 -> 0xFE11 once Android has the glyph for 0xFE11.
- {0xff64, 0xfe10}, // halfwidth ideo comma
+ {0xff64, 0xfe11}, // halfwidth ideo comma
{0xff61, 0xfe12}, // halfwidth ideo full stop
};
diff --git a/Source/WebCore/platform/graphics/android/android_graphics.cpp b/Source/WebCore/platform/graphics/android/android_graphics.cpp
index e88c65d..57f1b41 100644
--- a/Source/WebCore/platform/graphics/android/android_graphics.cpp
+++ b/Source/WebCore/platform/graphics/android/android_graphics.cpp
@@ -37,6 +37,12 @@
namespace android {
+CursorRing::CursorRing(WebViewCore* core)
+ : m_viewImpl(core)
+ , m_layerId(-1)
+{
+}
+
// The CSS values for the inner and outer widths may be specified as fractions
#define WIDTH_SCALE 0.0625f // 1/16, to offset the scale in CSSStyleSelector
@@ -116,12 +122,27 @@ void CursorRing::setIsButton(const CachedNode* node)
bool CursorRing::setup()
{
- m_node->cursorRings(m_frame, &m_rings);
+ m_layerId = -1;
+ if (m_frame && m_root) {
+ const CachedLayer* cachedLayer = m_frame->layer(m_node);
+ if (cachedLayer) {
+ const WebCore::LayerAndroid* rootLayer = m_root->rootLayer();
+ const LayerAndroid* aLayer = cachedLayer->layer(rootLayer);
+ if (aLayer)
+ m_layerId = aLayer->uniqueId();
+ }
+ }
+ if (m_layerId == -1)
+ m_node->cursorRings(m_frame, &m_rings);
+ else
+ m_node->localCursorRings(m_frame, &m_rings);
+
if (!m_rings.size()) {
DBG_NAV_LOG("!rings.size()");
m_viewImpl->m_hasCursorBounds = false;
return false;
}
+
setIsButton(m_node);
m_bounds = m_node->bounds(m_frame);
m_viewImpl->updateCursorBounds(m_root, m_frame, m_node);
diff --git a/Source/WebCore/platform/graphics/android/android_graphics.h b/Source/WebCore/platform/graphics/android/android_graphics.h
index 60ac115..bd08a6e 100644
--- a/Source/WebCore/platform/graphics/android/android_graphics.h
+++ b/Source/WebCore/platform/graphics/android/android_graphics.h
@@ -52,12 +52,13 @@ class WebViewCore;
class CursorRing : public DrawExtra {
public:
- CursorRing(WebViewCore* core) : m_viewImpl(core) {}
+ CursorRing(WebViewCore* core);
virtual ~CursorRing() {}
virtual void draw(SkCanvas* , LayerAndroid* , IntRect* );
void setIsButton(const CachedNode* );
bool setup();
WTF::Vector<IntRect>& rings() { return m_rings; }
+ int layerId() const { return m_layerId; }
private:
friend class WebView;
friend class WebCore::GLExtras;
@@ -71,6 +72,7 @@ private:
const CachedNode* m_node;
bool m_isButton;
bool m_isPressed;
+ int m_layerId;
};
}
diff --git a/Source/WebCore/rendering/RenderLayerCompositor.cpp b/Source/WebCore/rendering/RenderLayerCompositor.cpp
index 1ef3b77..33bf2f7 100644
--- a/Source/WebCore/rendering/RenderLayerCompositor.cpp
+++ b/Source/WebCore/rendering/RenderLayerCompositor.cpp
@@ -1366,7 +1366,21 @@ bool RenderLayerCompositor::needsToBeComposited(const RenderLayer* layer) const
return false;
// The root layer always has a compositing layer, but it may not have backing.
+#if PLATFORM(ANDROID)
+ // If we do not have a root platform layer, don't use the
+ // mustOverlapCompositedLayers() as a cue that this layer needs to be
+ // composited -- the layers tree has been detached.
+ // Otherwise we can end up in a cycle where updateBacking() switches composited
+ // mode on because a layer has mustOverlapCompositedLayers() (by calling
+ // enableCompositingMode()), while computeCompositingRequirements() will
+ // (correctly) say that we do not need to be in composited mode and turns it
+ // off, rince and repeat...
+ return requiresCompositingLayer(layer)
+ || (m_rootPlatformLayer && layer->mustOverlapCompositedLayers())
+ || (inCompositingMode() && layer->isRootLayer());
+#else
return requiresCompositingLayer(layer) || layer->mustOverlapCompositedLayers() || (inCompositingMode() && layer->isRootLayer());
+#endif
}
#if PLATFORM(ANDROID)
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/JavaSharedClient.cpp b/Source/WebKit/android/jni/JavaSharedClient.cpp
index 4f40355..4d073c2 100644
--- a/Source/WebKit/android/jni/JavaSharedClient.cpp
+++ b/Source/WebKit/android/jni/JavaSharedClient.cpp
@@ -88,12 +88,12 @@ namespace android {
FileSystemClient* JavaSharedClient::gFileSystemClient = NULL;
///////////////////////////////////////////////////////////////////////////
-
+
struct FuncPtrRec {
void (*fProc)(void* payload);
void* fPayload;
};
-
+
static SkMutex gFuncPtrQMutex;
static SkDeque gFuncPtrQ(sizeof(FuncPtrRec));
@@ -105,33 +105,34 @@ namespace android {
FuncPtrRec* rec = (FuncPtrRec*)gFuncPtrQ.push_back();
rec->fProc = proc;
rec->fPayload = payload;
-
+
gFuncPtrQMutex.release();
-
+
gTimerClient->signalServiceFuncPtrQueue();
}
void JavaSharedClient::ServiceFunctionPtrQueue()
{
- for (;;) {
- void (*proc)(void*) = 0;
- void* payload = 0;
- const FuncPtrRec* rec;
-
- // we have to copy the proc/payload (if present). we do this so we
- // don't call the proc inside the mutex (possible deadlock!)
- gFuncPtrQMutex.acquire();
- rec = (const FuncPtrRec*)gFuncPtrQ.front();
- if (rec) {
- proc = rec->fProc;
- payload = rec->fPayload;
- gFuncPtrQ.pop_front();
- }
- gFuncPtrQMutex.release();
-
- if (!rec)
- break;
- proc(payload);
+ // Don't let execution block the WebViewCore thread for too long.
+ void (*proc)(void*) = 0;
+ void* payload = 0;
+ const FuncPtrRec* rec;
+
+ // we have to copy the proc/payload (if present). we do this so we
+ // don't call the proc inside the mutex (possible deadlock!)
+ gFuncPtrQMutex.acquire();
+ rec = (const FuncPtrRec*)gFuncPtrQ.front();
+ if (rec) {
+ proc = rec->fProc;
+ payload = rec->fPayload;
+ gFuncPtrQ.pop_front();
}
+ bool scheduleAdditionalCall = (gFuncPtrQ.count() > 0);
+ gFuncPtrQMutex.release();
+
+ if (rec)
+ proc(payload);
+ if (scheduleAdditionalCall)
+ gTimerClient->signalServiceFuncPtrQueue();
}
}
diff --git a/Source/WebKit/android/jni/WebHistory.cpp b/Source/WebKit/android/jni/WebHistory.cpp
index f782c37..db31429 100644
--- a/Source/WebKit/android/jni/WebHistory.cpp
+++ b/Source/WebKit/android/jni/WebHistory.cpp
@@ -24,6 +24,7 @@
*/
#define LOG_TAG "webhistory"
+#define LOG_NDEBUG 0 // enable ALOGV and ALOG_ASSERT
#include "config.h"
#include "WebHistory.h"
@@ -54,9 +55,9 @@
namespace android {
// Forward declarations
-static void write_item(WTF::Vector<char>& v, WebCore::HistoryItem* item);
-static void write_children_recursive(WTF::Vector<char>& v, WebCore::HistoryItem* parent);
-static bool read_item_recursive(WebCore::HistoryItem* child, const char** pData, int length);
+static void writeItem(WTF::Vector<char>& vector, WebCore::HistoryItem* item);
+static void writeChildrenRecursive(WTF::Vector<char>& vector, WebCore::HistoryItem* parent);
+static bool readItemRecursive(WebCore::HistoryItem* child, const char** pData, int length);
// Field ids for WebHistoryItems
struct WebHistoryItemFields {
@@ -178,7 +179,7 @@ static void WebHistoryInflate(JNIEnv* env, jobject obj, jint frame, jbyteArray d
// ptr's value. We can't pass &bytes since we have to send bytes to
// ReleaseByteArrayElements unchanged.
const char* ptr = reinterpret_cast<const char*>(bytes);
- read_item_recursive(newItem.get(), &ptr, (int)size);
+ readItemRecursive(newItem.get(), &ptr, (int)size);
env->ReleaseByteArrayElements(data, const_cast<jbyte*>(bytes), JNI_ABORT);
bridge->setActive();
@@ -194,27 +195,27 @@ static void WebHistoryInflate(JNIEnv* env, jobject obj, jint frame, jbyteArray d
// 1 char for isTargetItem.
#define HISTORY_MIN_SIZE ((int)(sizeof(unsigned) * 10 + sizeof(char)))
-jbyteArray WebHistory::Flatten(JNIEnv* env, WTF::Vector<char>& v, WebCore::HistoryItem* item)
+jbyteArray WebHistory::Flatten(JNIEnv* env, WTF::Vector<char>& vector, WebCore::HistoryItem* item)
{
if (!item)
return NULL;
// Reserve a vector of chars with an initial size of HISTORY_MIN_SIZE.
- v.reserveCapacity(HISTORY_MIN_SIZE);
+ vector.reserveCapacity(HISTORY_MIN_SIZE);
// Write the top-level history item and then write all the children
// recursively.
ALOG_ASSERT(item->bridge(), "Why don't we have a bridge object here?");
- write_item(v, item);
- write_children_recursive(v, item);
+ writeItem(vector, item);
+ writeChildrenRecursive(vector, item);
// Try to create a new java byte array.
- jbyteArray b = env->NewByteArray(v.size());
+ jbyteArray b = env->NewByteArray(vector.size());
if (!b)
return NULL;
// Write our flattened data to the java array.
- env->SetByteArrayRegion(b, 0, v.size(), (const jbyte*)v.data());
+ env->SetByteArrayRegion(b, 0, vector.size(), (const jbyte*)vector.data());
return b;
}
@@ -358,7 +359,7 @@ void WebHistory::UpdateHistoryIndex(const AutoJObject& list, int newIndex)
list.env()->CallVoidMethod(list.get(), gWebBackForwardList.mSetCurrentIndex, newIndex);
}
-static void write_string(WTF::Vector<char>& v, const WTF::String& str)
+static void writeString(WTF::Vector<char>& vector, const WTF::String& str)
{
unsigned strLen = str.length();
// Only do work if the string has data.
@@ -366,90 +367,90 @@ static void write_string(WTF::Vector<char>& v, const WTF::String& str)
// Determine how much to grow the vector. Use the worst case for utf8 to
// avoid reading the string twice. Add sizeof(unsigned) to hold the
// string length in utf8.
- unsigned vectorLen = v.size() + sizeof(unsigned);
+ unsigned vectorLen = vector.size() + sizeof(unsigned);
unsigned length = (strLen << 2) + vectorLen;
// Grow the vector. This will change the value of v.size() but we
// remember the original size above.
- v.grow(length);
+ vector.grow(length);
// Grab the position to write to.
- char* data = v.begin() + vectorLen;
+ char* data = vector.begin() + vectorLen;
// Write the actual string
int l = SkUTF16_ToUTF8(str.characters(), strLen, data);
- LOG_VERBOSE(History, "Writing string %d %.*s", l, l, data);
+ ALOGV("Writing string %d %.*s", l, l, data);
// Go back and write the utf8 length. Subtract sizeof(unsigned) from
// data to get the position to write the length.
memcpy(data - sizeof(unsigned), (char*)&l, sizeof(unsigned));
// Shrink the internal state of the vector so we match what was
// actually written.
- v.shrink(vectorLen + l);
+ vector.shrink(vectorLen + l);
} else
- v.append((char*)&strLen, sizeof(unsigned));
+ vector.append((char*)&strLen, sizeof(unsigned));
}
-static void write_item(WTF::Vector<char>& v, WebCore::HistoryItem* item)
+static void writeItem(WTF::Vector<char>& vector, WebCore::HistoryItem* item)
{
// Original url
- write_string(v, item->originalURLString());
+ writeString(vector, item->originalURLString());
// Url
- write_string(v, item->urlString());
+ writeString(vector, item->urlString());
// Title
- write_string(v, item->title());
+ writeString(vector, item->title());
// Form content type
- write_string(v, item->formContentType());
+ writeString(vector, item->formContentType());
// Form data
const WebCore::FormData* formData = item->formData();
if (formData) {
- write_string(v, formData->flattenToString());
+ writeString(vector, formData->flattenToString());
// save the identifier as it is not included in the flatten data
int64_t id = formData->identifier();
- v.append((char*)&id, sizeof(int64_t));
+ vector.append((char*)&id, sizeof(int64_t));
} else
- write_string(v, WTF::String()); // Empty constructor does not allocate a buffer.
+ writeString(vector, WTF::String()); // Empty constructor does not allocate a buffer.
// Target
- write_string(v, item->target());
+ writeString(vector, item->target());
AndroidWebHistoryBridge* bridge = item->bridge();
ALOG_ASSERT(bridge, "We should have a bridge here!");
// Screen scale
const float scale = bridge->scale();
- LOG_VERBOSE(History, "Writing scale %f", scale);
- v.append((char*)&scale, sizeof(float));
+ ALOGV("Writing scale %f", scale);
+ vector.append((char*)&scale, sizeof(float));
const float textWrapScale = bridge->textWrapScale();
- LOG_VERBOSE(History, "Writing text wrap scale %f", textWrapScale);
- v.append((char*)&textWrapScale, sizeof(float));
+ ALOGV("Writing text wrap scale %f", textWrapScale);
+ vector.append((char*)&textWrapScale, sizeof(float));
// Scroll position.
const int scrollX = item->scrollPoint().x();
- v.append((char*)&scrollX, sizeof(int));
+ vector.append((char*)&scrollX, sizeof(int));
const int scrollY = item->scrollPoint().y();
- v.append((char*)&scrollY, sizeof(int));
+ vector.append((char*)&scrollY, sizeof(int));
// Document state
const WTF::Vector<WTF::String>& docState = item->documentState();
WTF::Vector<WTF::String>::const_iterator end = docState.end();
unsigned stateSize = docState.size();
- LOG_VERBOSE(History, "Writing docState %d", stateSize);
- v.append((char*)&stateSize, sizeof(unsigned));
+ ALOGV("Writing docState %d", stateSize);
+ vector.append((char*)&stateSize, sizeof(unsigned));
for (WTF::Vector<WTF::String>::const_iterator i = docState.begin(); i != end; ++i) {
- write_string(v, *i);
+ writeString(vector, *i);
}
// Is target item
- LOG_VERBOSE(History, "Writing isTargetItem %d", item->isTargetItem());
- v.append((char)item->isTargetItem());
+ ALOGV("Writing isTargetItem %d", item->isTargetItem());
+ vector.append((char)item->isTargetItem());
// Children count
unsigned childCount = item->children().size();
- LOG_VERBOSE(History, "Writing childCount %d", childCount);
- v.append((char*)&childCount, sizeof(unsigned));
+ ALOGV("Writing childCount %d", childCount);
+ vector.append((char*)&childCount, sizeof(unsigned));
}
-static void write_children_recursive(WTF::Vector<char>& v, WebCore::HistoryItem* parent)
+static void writeChildrenRecursive(WTF::Vector<char>& vector, WebCore::HistoryItem* parent)
{
const WebCore::HistoryItemVector& children = parent->children();
WebCore::HistoryItemVector::const_iterator end = children.end();
@@ -472,111 +473,199 @@ static void write_children_recursive(WTF::Vector<char>& v, WebCore::HistoryItem*
"Somehow this item has an incorrect parent");
bridge->setParent(parentBridge);
}
- write_item(v, item);
- write_children_recursive(v, item);
+ writeItem(vector, item);
+ writeChildrenRecursive(vector, item);
}
}
-static bool read_item_recursive(WebCore::HistoryItem* newItem,
+bool readUnsigned(const char*& data, const char* end, unsigned& result, const char* dbgLabel = 0);
+bool readInt(const char*& data, const char* end, int& result, const char* dbgLabel = 0);
+bool readInt64(const char*& data, const char* end, int64_t& result, const char* dbgLabel = 0);
+bool readFloat(const char*& data, const char* end, float& result, const char* dbgLabel = 0);
+bool readBool(const char*& data, const char* end, bool& result, const char* dbgLabel = 0);
+bool readString(const char*& data, const char* end, String& result, const char* dbgLabel = 0);
+
+bool readUnsigned(const char*& data, const char* end, unsigned& result, const char* dbgLabel)
+{
+ // Check if we have enough data left to continue.
+ if ((end < data) || (static_cast<size_t>(end - data) < sizeof(unsigned))) {
+ ALOGW("\tNot enough data to read unsigned; end=%p data=%p", end, data);
+ return false;
+ }
+
+ memcpy(&result, data, sizeof(unsigned));
+ data += sizeof(unsigned);
+ if (dbgLabel)
+ ALOGV("Reading %-16s %u", dbgLabel, result);
+ return true;
+}
+
+bool readInt(const char*& data, const char* end, int& result, const char* dbgLabel)
+{
+ // Check if we have enough data left to continue.
+ if ((end < data) || (static_cast<size_t>(end - data) < sizeof(int))) {
+ ALOGW("\tNot enough data to read int; end=%p data=%p", end, data);
+ return false;
+ }
+
+ memcpy(&result, data, sizeof(int));
+ data += sizeof(int);
+ if (dbgLabel)
+ ALOGV("Reading %-16s %d", dbgLabel, result);
+ return true;
+}
+
+bool readInt64(const char*& data, const char* end, int64_t& result, const char* dbgLabel)
+{
+ // Check if we have enough data left to continue.
+ if ((end < data) || (static_cast<size_t>(end - data) < sizeof(int64_t))) {
+ ALOGW("\tNot enough data to read int64_t; end=%p data=%p", end, data);
+ return false;
+ }
+
+ memcpy(&result, data, sizeof(int64_t));
+ data += sizeof(int64_t);
+ if (dbgLabel)
+ ALOGV("Reading %-16s %ll", dbgLabel, result);
+ return true;
+}
+
+bool readFloat(const char*& data, const char* end, float& result, const char* dbgLabel)
+{
+ // Check if we have enough data left to continue.
+ if ((end < data) || (static_cast<size_t>(end - data) < sizeof(float))) {
+ ALOGW("\tNot enough data to read float; end=%p data=%p", end, data);
+ return false;
+ }
+
+ memcpy(&result, data, sizeof(float));
+ data += sizeof(float);
+ if (dbgLabel)
+ ALOGV("Reading %-16s %f", dbgLabel, result);
+ return true;
+}
+
+// Note that the return value indicates success or failure, while the result
+// parameter indicates the read value of the bool
+bool readBool(const char*& data, const char* end, bool& result, const char* dbgLabel)
+{
+ // Check if we have enough data left to continue.
+ if ((end < data) || (static_cast<size_t>(end - data) < sizeof(char))) {
+ ALOGW("\tNot enough data to read bool; end=%p data=%p", end, data);
+ return false;
+ }
+
+ char c;
+ memcpy(&c, data, sizeof(char));
+ data += sizeof(char);
+ if (dbgLabel)
+ ALOGV("Reading %-16s %d", dbgLabel, c);
+ result = c;
+
+ // Valid bool results are 0 or 1
+ if ((c != 0) && (c != 1)) {
+ ALOGW("\tInvalid value for bool; end=%p data=%p c=%u", end, data, c);
+ return false;
+ }
+
+ return true;
+}
+
+bool readString(const char*& data, const char* end, String& result, const char* dbgLabel)
+{
+ unsigned stringLength;
+ if (!readUnsigned(data, end, stringLength)) {
+ ALOGW("Not enough data to read string length; end=%p data=%p", end, data);
+ return false;
+ }
+
+ if (dbgLabel)
+ ALOGV("Reading %-16s %d %.*s", dbgLabel, stringLength, stringLength, data);
+
+ // If length was 0, there will be no string content, but still return true
+ if (!stringLength) {
+ result = String();
+ return true;
+ }
+
+ if ((end < data) || ((unsigned)(end - data) < stringLength)) {
+ ALOGW("\tNot enough data to read content; end=%p data=%p stringLength=%u", end, data, stringLength);
+ return false;
+ }
+
+ bool decodeFailed;
+ static const WebCore::TextEncoding& encoding = WebCore::UTF8Encoding();
+ result = encoding.decode(data, stringLength, true, decodeFailed);
+ if (decodeFailed) {
+ ALOGW("\tdecode failed, end=%p data=%p stringLength=%u content=\"%s\"",
+ end, data, stringLength, result.utf8().data());
+ // Although an error was reported, the previous implementation did not
+ // stop here, and debug output of the result, which looks correct, makes
+ // it unclear just what the error was.
+ }
+
+ data += stringLength;
+ return true;
+}
+
+static bool readItemRecursive(WebCore::HistoryItem* newItem,
const char** pData, int length)
{
- if (!pData || length < HISTORY_MIN_SIZE)
+ if (!pData || length < HISTORY_MIN_SIZE) {
+ ALOGW("readItemRecursive() bad params; pData=%p length=%d", pData, length);
return false;
+ }
- const WebCore::TextEncoding& e = WebCore::UTF8Encoding();
const char* data = *pData;
const char* end = data + length;
- int sizeofUnsigned = (int)sizeof(unsigned);
+ String content;
// Read the original url
- // Read the expected length of the string.
- size_t l;
- memcpy(&l, data, sizeofUnsigned);
- // Increment data pointer by the size of an unsigned int.
- data += sizeofUnsigned;
- if (l) {
- LOG_VERBOSE(History, "Original url %d %.*s", l, l, data);
- // If we have a length, check if that length exceeds the data length
- // and return null if there is not enough data.
- if (data + l < end)
- newItem->setOriginalURLString(e.decode(data, l));
- else
- return false;
- // Increment the data pointer by the length of the string.
- data += l;
- }
- // Check if we have enough data left to continue.
- if (end - data < sizeofUnsigned)
+ if (readString(data, end, content, "Original url"))
+ newItem->setOriginalURLString(content);
+ else
return false;
// Read the url
- memcpy(&l, data, sizeofUnsigned);
- data += sizeofUnsigned;
- if (l) {
- LOG_VERBOSE(History, "Url %d %.*s", l, l, data);
- if (data + l < end)
- newItem->setURLString(e.decode(data, l));
- else
- return false;
- data += l;
- }
- if (end - data < sizeofUnsigned)
+ if (readString(data, end, content, "Url"))
+ newItem->setURLString(content);
+ else
return false;
// Read the title
- memcpy(&l, data, sizeofUnsigned);
- data += sizeofUnsigned;
- if (l) {
- LOG_VERBOSE(History, "Title %d %.*s", l, l, data);
- if (data + l < end)
- newItem->setTitle(e.decode(data, l));
- else
- return false;
- data += l;
- }
- if (end - data < sizeofUnsigned)
+ if (readString(data, end, content, "Title"))
+ newItem->setTitle(content);
+ else
return false;
// Generate a new ResourceRequest object for populating form information.
+ // Read the form content type
WTF::String formContentType;
- WTF::RefPtr<WebCore::FormData> formData = NULL;
+ if (!readString(data, end, formContentType, "Content type"))
+ return false;
- // Read the form content type
- memcpy(&l, data, sizeofUnsigned);
- data += sizeofUnsigned;
- if (l) {
- LOG_VERBOSE(History, "Content type %d %.*s", l, l, data);
- if (data + l < end)
- formContentType = e.decode(data, l);
- else
- return false;
- data += l;
- }
- if (end - data < sizeofUnsigned)
+ // Read the form data size
+ unsigned formDataSize;
+ if (!readUnsigned(data, end, formDataSize, "Form data size"))
return false;
// Read the form data
- memcpy(&l, data, sizeofUnsigned);
- data += sizeofUnsigned;
- if (l) {
- LOG_VERBOSE(History, "Form data %d %.*s", l, l, data);
- if (data + l < end)
- formData = WebCore::FormData::create(data, l);
- else
+ WTF::RefPtr<WebCore::FormData> formData;
+ if (formDataSize) {
+ ALOGV("Reading Form data %d %.*s", formDataSize, formDataSize, data);
+ if ((end < data) || ((size_t)(end - data) < formDataSize)) {
+ ALOGW("\tNot enough data to read form data; returning");
return false;
- data += l;
- // Read the identifier
- {
- int64_t id;
- int size = (int)sizeof(int64_t);
- memcpy(&id, data, size);
- data += size;
- if (id)
- formData->setIdentifier(id);
}
+ formData = WebCore::FormData::create(data, formDataSize);
+ data += formDataSize;
+ // Read the identifier
+ int64_t id;
+ if (!readInt64(data, end, id, "Form id"))
+ return false;
+ if (id)
+ formData->setIdentifier(id);
}
- if (end - data < sizeofUnsigned)
- return false;
// Set up the form info
if (formData != NULL) {
@@ -588,112 +677,76 @@ static bool read_item_recursive(WebCore::HistoryItem* newItem,
}
// Read the target
- memcpy(&l, data, sizeofUnsigned);
- data += sizeofUnsigned;
- if (l) {
- LOG_VERBOSE(History, "Target %d %.*s", l, l, data);
- if (data + l < end)
- newItem->setTarget(e.decode(data, l));
- else
- return false;
- data += l;
- }
- if (end - data < sizeofUnsigned)
+ if (readString(data, end, content, "Target"))
+ newItem->setTarget(content);
+ else
return false;
AndroidWebHistoryBridge* bridge = newItem->bridge();
ALOG_ASSERT(bridge, "There should be a bridge object during inflate");
- float fValue;
+
// Read the screen scale
- memcpy(&fValue, data, sizeof(float));
- LOG_VERBOSE(History, "Screen scale %f", fValue);
- bridge->setScale(fValue);
- data += sizeof(float);
- memcpy(&fValue, data, sizeofUnsigned);
- LOG_VERBOSE(History, "Text wrap scale %f", fValue);
- bridge->setTextWrapScale(fValue);
- data += sizeof(float);
+ float fValue;
+ if (readFloat(data, end, fValue, "Screen scale"))
+ bridge->setScale(fValue);
+ else
+ return false;
- if (end - data < sizeofUnsigned)
+ // Read the text wrap scale
+ if (readFloat(data, end, fValue, "Text wrap scale"))
+ bridge->setTextWrapScale(fValue);
+ else
return false;
// Read scroll position.
- int scrollX = 0;
- memcpy(&scrollX, data, sizeofUnsigned);
- data += sizeofUnsigned;
- int scrollY = 0;
- memcpy(&scrollY, data, sizeofUnsigned);
- data += sizeofUnsigned;
- newItem->setScrollPoint(IntPoint(scrollX, scrollY));
-
- if (end - data < sizeofUnsigned)
+ int scrollX;
+ if (!readInt(data, end, scrollX, "Scroll pos x"))
+ return false;
+ int scrollY;
+ if (!readInt(data, end, scrollY, "Scroll pos y"))
return false;
+ newItem->setScrollPoint(IntPoint(scrollX, scrollY));
// Read the document state
- memcpy(&l, data, sizeofUnsigned);
- LOG_VERBOSE(History, "Document state %d", l);
- data += sizeofUnsigned;
- if (l) {
- // Check if we have enough data to at least parse the sizes of each
- // document state string.
- if (data + l * sizeofUnsigned >= end)
- return false;
+ unsigned docStateCount;
+ if (!readUnsigned(data, end, docStateCount, "Doc state count"))
+ return false;
+ if (docStateCount) {
// Create a new vector and reserve enough space for the document state.
WTF::Vector<WTF::String> docState;
- docState.reserveCapacity(l);
- while (l--) {
- // Check each time if we have enough to parse the length of the next
- // string.
- if (end - data < sizeofUnsigned)
- return false;
- int strLen;
- memcpy(&strLen, data, sizeofUnsigned);
- data += sizeofUnsigned;
- if (data + strLen < end)
- docState.append(e.decode(data, strLen));
+ docState.reserveCapacity(docStateCount);
+ while (docStateCount--) {
+ // Read a document state string
+ if (readString(data, end, content, "Document state"))
+ docState.append(content);
else
return false;
- LOG_VERBOSE(History, "\t\t%d %.*s", strLen, strLen, data);
- data += strLen;
}
newItem->setDocumentState(docState);
}
- // Check if we have enough to read the next byte
- if (data >= end)
- return false;
// Read is target item
- // Cast the value to unsigned char in order to make a negative value larger
- // than 1. A value that is not 0 or 1 is a failure.
- unsigned char c = (unsigned char)data[0];
- if (c > 1)
- return false;
- LOG_VERBOSE(History, "Target item %d", c);
- newItem->setIsTargetItem((bool)c);
- data++;
- if (end - data < sizeofUnsigned)
+ bool c;
+ if (readBool(data, end, c, "Target item"))
+ newItem->setIsTargetItem(c);
+ else
return false;
// Read the child count
- memcpy(&l, data, sizeofUnsigned);
- LOG_VERBOSE(History, "Child count %d", l);
- data += sizeofUnsigned;
+ unsigned count;
+ if (!readUnsigned(data, end, count, "Child count"))
+ return false;
*pData = data;
- if (l) {
- // Check if we have the minimum amount need to parse l children.
- if (data + l * HISTORY_MIN_SIZE >= end)
- return false;
- while (l--) {
+ if (count) {
+ while (count--) {
// No need to check the length each time because read_item_recursive
// will return null if there isn't enough data left to parse.
WTF::RefPtr<WebCore::HistoryItem> child = WebCore::HistoryItem::create();
// Set a bridge that will not call into java.
child->setBridge(new WebHistoryItem(static_cast<WebHistoryItem*>(bridge)));
// Read the child item.
- if (!read_item_recursive(child.get(), pData, end - data)) {
- child.clear();
+ if (!readItemRecursive(child.get(), pData, end - data))
return false;
- }
child->bridge()->setActive();
newItem->addChildItem(child);
}
@@ -709,83 +762,86 @@ static bool read_item_recursive(WebCore::HistoryItem* newItem,
// main thread will be incorrect and an assert will fire later.
// In conclusion, define UNIT_TEST only if you know what you are doing.
#ifdef UNIT_TEST
-static void unit_test()
+static void unitTest()
{
ALOGD("Entering history unit test!");
const char* test1 = new char[0];
WTF::RefPtr<WebCore::HistoryItem> item = WebCore::HistoryItem::create();
WebCore::HistoryItem* testItem = item.get();
testItem->setBridge(new WebHistoryItem(0));
- ALOG_ASSERT(!read_item_recursive(testItem, &test1, 0), "0 length array should fail!");
+ ALOG_ASSERT(!readItemRecursive(testItem, &test1, 0), "0 length array should fail!");
delete[] test1;
const char* test2 = new char[2];
- ALOG_ASSERT(!read_item_recursive(testItem, &test2, 2), "Small array should fail!");
+ ALOG_ASSERT(!readItemRecursive(testItem, &test2, 2), "Small array should fail!");
delete[] test2;
- ALOG_ASSERT(!read_item_recursive(testItem, NULL, HISTORY_MIN_SIZE), "Null data should fail!");
+ ALOG_ASSERT(!readItemRecursive(testItem, NULL, HISTORY_MIN_SIZE), "Null data should fail!");
// Original Url
char* test3 = new char[HISTORY_MIN_SIZE];
const char* ptr = (const char*)test3;
memset(test3, 0, HISTORY_MIN_SIZE);
*(int*)test3 = 4000;
- ALOG_ASSERT(!read_item_recursive(testItem, &ptr, HISTORY_MIN_SIZE), "4000 length originalUrl should fail!");
+ ALOG_ASSERT(!readItemRecursive(testItem, &ptr, HISTORY_MIN_SIZE), "4000 length originalUrl should fail!");
// Url
int offset = 4;
memset(test3, 0, HISTORY_MIN_SIZE);
ptr = (const char*)test3;
*(int*)(test3 + offset) = 4000;
- ALOG_ASSERT(!read_item_recursive(testItem, &ptr, HISTORY_MIN_SIZE), "4000 length url should fail!");
+ ALOG_ASSERT(!readItemRecursive(testItem, &ptr, HISTORY_MIN_SIZE), "4000 length url should fail!");
// Title
offset += 4;
memset(test3, 0, HISTORY_MIN_SIZE);
ptr = (const char*)test3;
*(int*)(test3 + offset) = 4000;
- ALOG_ASSERT(!read_item_recursive(testItem, &ptr, HISTORY_MIN_SIZE), "4000 length title should fail!");
+ ALOG_ASSERT(!readItemRecursive(testItem, &ptr, HISTORY_MIN_SIZE), "4000 length title should fail!");
// Form content type
offset += 4;
memset(test3, 0, HISTORY_MIN_SIZE);
ptr = (const char*)test3;
*(int*)(test3 + offset) = 4000;
- ALOG_ASSERT(!read_item_recursive(testItem, &ptr, HISTORY_MIN_SIZE), "4000 length contentType should fail!");
+ ALOG_ASSERT(!readItemRecursive(testItem, &ptr, HISTORY_MIN_SIZE), "4000 length contentType should fail!");
// Form data
offset += 4;
memset(test3, 0, HISTORY_MIN_SIZE);
ptr = (const char*)test3;
*(int*)(test3 + offset) = 4000;
- ALOG_ASSERT(!read_item_recursive(testItem, &ptr, HISTORY_MIN_SIZE), "4000 length form data should fail!");
+ ALOG_ASSERT(!readItemRecursive(testItem, &ptr, HISTORY_MIN_SIZE), "4000 length form data should fail!");
// Target
offset += 4;
memset(test3, 0, HISTORY_MIN_SIZE);
ptr = (const char*)test3;
*(int*)(test3 + offset) = 4000;
- ALOG_ASSERT(!read_item_recursive(testItem, &ptr, HISTORY_MIN_SIZE), "4000 length target should fail!");
- offset += 4; // Scale
+ ALOG_ASSERT(!readItemRecursive(testItem, &ptr, HISTORY_MIN_SIZE), "4000 length target should fail!");
+ offset += 4; // Screen scale
+ offset += 4; // Text wrap scale
+ offset += 4; // Scroll pos x
+ offset += 4; // Scroll pos y
// Document state
offset += 4;
memset(test3, 0, HISTORY_MIN_SIZE);
ptr = (const char*)test3;
*(int*)(test3 + offset) = 4000;
- ALOG_ASSERT(!read_item_recursive(testItem, &ptr, HISTORY_MIN_SIZE), "4000 length document state should fail!");
+ ALOG_ASSERT(!readItemRecursive(testItem, &ptr, HISTORY_MIN_SIZE), "4000 length document state should fail!");
// Is target item
offset += 1;
memset(test3, 0, HISTORY_MIN_SIZE);
ptr = (const char*)test3;
*(char*)(test3 + offset) = '!';
- ALOG_ASSERT(!read_item_recursive(testItem, &ptr, HISTORY_MIN_SIZE), "IsTargetItem should fail with ! as the value!");
+ ALOG_ASSERT(!readItemRecursive(testItem, &ptr, HISTORY_MIN_SIZE), "IsTargetItem should fail with ! as the value!");
// Child count
offset += 4;
memset(test3, 0, HISTORY_MIN_SIZE);
ptr = (const char*)test3;
*(int*)(test3 + offset) = 4000;
- ALOG_ASSERT(!read_item_recursive(testItem, &ptr, HISTORY_MIN_SIZE), "4000 kids should fail!");
- offset = 36;
+ ALOG_ASSERT(!readItemRecursive(testItem, &ptr, HISTORY_MIN_SIZE), "4000 kids should fail!");
// Test document state
+ offset = 40;
delete[] test3;
test3 = new char[HISTORY_MIN_SIZE + sizeof(unsigned)];
memset(test3, 0, HISTORY_MIN_SIZE + sizeof(unsigned));
ptr = (const char*)test3;
*(int*)(test3 + offset) = 1;
*(int*)(test3 + offset + 4) = 20;
- ALOG_ASSERT(!read_item_recursive(testItem, &ptr, HISTORY_MIN_SIZE + sizeof(unsigned)), "1 20 length document state string should fail!");
+ ALOG_ASSERT(!readItemRecursive(testItem, &ptr, HISTORY_MIN_SIZE + sizeof(unsigned)), "1 20 length document state string should fail!");
delete[] test3;
test3 = new char[HISTORY_MIN_SIZE + 2 * sizeof(unsigned)];
memset(test3, 0, HISTORY_MIN_SIZE + 2 * sizeof(unsigned));
@@ -793,8 +849,9 @@ static void unit_test()
*(int*)(test3 + offset) = 2;
*(int*)(test3 + offset + 4) = 0;
*(int*)(test3 + offset + 8) = 20;
- ALOG_ASSERT(!read_item_recursive(testItem, &ptr, HISTORY_MIN_SIZE + 2 * sizeof(unsigned) ), "2 20 length document state string should fail!");
+ ALOG_ASSERT(!readItemRecursive(testItem, &ptr, HISTORY_MIN_SIZE + 2 * sizeof(unsigned) ), "2 20 length document state string should fail!");
delete[] test3;
+ ALOGD("Leaving history unit test!");
}
#endif
@@ -818,7 +875,7 @@ int registerWebHistory(JNIEnv* env)
// Get notified of all changes to history items.
WebCore::notifyHistoryItemChanged = historyItemChanged;
#ifdef UNIT_TEST
- unit_test();
+ unitTest();
#endif
// Find WebHistoryItem, its constructor, and the update method.
jclass clazz = env->FindClass("android/webkit/WebHistoryItem");
diff --git a/Source/WebKit/android/jni/WebViewCore.cpp b/Source/WebKit/android/jni/WebViewCore.cpp
index 6737329..703f177 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"
@@ -941,7 +942,7 @@ BaseLayerAndroid* WebViewCore::recordContent(SkRegion* region, SkIPoint* point)
DBG_SET_LOG("start");
// If there is a pending style recalculation, just return.
if (m_mainFrame->document()->isPendingStyleRecalc()) {
- DBG_SET_LOGD("recordContent: pending style recalc, ignoring.");
+ DBG_SET_LOG("recordContent: pending style recalc, ignoring.");
return 0;
}
float progress = (float) m_mainFrame->page()->progress()->estimatedProgress();
@@ -1640,7 +1641,8 @@ void WebViewCore::updateFrameCacheIfLoading()
#endif
struct TouchNodeData {
- Node* mNode;
+ Node* mUrlNode;
+ Node* mInnerNode;
IntRect mBounds;
};
@@ -1664,136 +1666,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;
- m_mousePos = IntPoint(x - m_scrollOffsetX, y - m_scrollOffsetY);
- *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;
- ALOGD("innerNode: %p, %s", hitTestResult->innerNode(), hitTestResult->innerNode()->nodeName().ascii().data());
- ALOGD("innerNonSharedNode: %p, %s", hitTestResult->innerNonSharedNode(), hitTestResult->innerNonSharedNode()->nodeName().ascii().data());
- 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)) {
- 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);
- }
+ // 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 (!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;
@@ -1807,20 +1808,33 @@ Vector<IntRect> WebViewCore::getTouchHighlightRects(int x, int y, int slop,
area = a;
}
}
- *node = final.mNode;
// now get the node's highlight rectangles in the page coordinate system
- if (final.mNode) {
+ if (final.mUrlNode) {
+ if (final.mUrlNode->isElementNode()) {
+ // We found a URL element. Update the hitTestResult
+ 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,36 +1882,36 @@ 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();
newy = rects[0].y();
}
- m_mousePos.setX(newx - m_scrollOffsetX);
- m_mousePos.setY(newy - m_scrollOffsetY);
+ moveMouse(m_mainFrame, newx, newy);
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;
}
}
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)) {
- m_mousePos = testRect.center();
- m_mousePos.move(-m_scrollOffsetX, -m_scrollOffsetY);
- 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;
}
///////////////////////////////////////////////////////////////////////////////
@@ -4575,84 +4589,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,
@@ -4798,7 +4744,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 69b805c..06f6b97 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> );
diff --git a/Source/WebKit/android/plugins/ANPSoundInterface.cpp b/Source/WebKit/android/plugins/ANPSoundInterface.cpp
index a4f192f..12c9176 100644
--- a/Source/WebKit/android/plugins/ANPSoundInterface.cpp
+++ b/Source/WebKit/android/plugins/ANPSoundInterface.cpp
@@ -71,7 +71,7 @@ static void callbackProc(int event, void* user, void* info) {
src = reinterpret_cast<android::AudioTrack::Buffer*>(info);
dst.bufferData = src->raw;
dst.channelCount = src->channelCount;
- dst.format = toANPFormat(src->format);
+ dst.format = toANPFormat((audio_format_t) src->format);
dst.size = src->size;
track->mProc(kMoreData_ANPAudioEvent, track->mUser, &dst);
// return the updated size field