summaryrefslogtreecommitdiffstats
path: root/Source/WebKit/android
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebKit/android')
-rw-r--r--Source/WebKit/android/AndroidLog.h36
-rw-r--r--Source/WebKit/android/RenderSkinAndroid.cpp13
-rw-r--r--Source/WebKit/android/RenderSkinAndroid.h4
-rw-r--r--Source/WebKit/android/RenderSkinButton.cpp105
-rw-r--r--Source/WebKit/android/RenderSkinButton.h55
-rw-r--r--Source/WebKit/android/RenderSkinCombo.cpp213
-rw-r--r--Source/WebKit/android/RenderSkinCombo.h62
-rw-r--r--Source/WebKit/android/RenderSkinMediaButton.cpp15
-rw-r--r--Source/WebKit/android/RenderSkinMediaButton.h2
-rw-r--r--Source/WebKit/android/RenderSkinNinePatch.cpp16
-rw-r--r--Source/WebKit/android/RenderSkinNinePatch.h2
-rw-r--r--Source/WebKit/android/RenderSkinRadio.cpp113
-rw-r--r--Source/WebKit/android/TimeCounter.cpp198
-rw-r--r--Source/WebKit/android/TimeCounter.h120
-rw-r--r--Source/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp32
-rw-r--r--Source/WebKit/android/WebCoreSupport/ChromiumIncludes.h49
-rw-r--r--Source/WebKit/android/WebCoreSupport/EditorClientAndroid.cpp18
-rw-r--r--Source/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp59
-rw-r--r--Source/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.h12
-rw-r--r--Source/WebKit/android/WebCoreSupport/MediaPlayerPrivateAndroid.cpp57
-rw-r--r--Source/WebKit/android/WebCoreSupport/MemoryUsage.cpp4
-rw-r--r--Source/WebKit/android/WebCoreSupport/PlatformBridge.cpp57
-rw-r--r--Source/WebKit/android/WebCoreSupport/ResourceLoaderAndroid.cpp9
-rw-r--r--Source/WebKit/android/WebCoreSupport/UrlInterceptResponse.cpp64
-rw-r--r--Source/WebKit/android/WebCoreSupport/V8Counters.cpp116
-rw-r--r--Source/WebKit/android/WebCoreSupport/V8Counters.h77
-rw-r--r--Source/WebKit/android/WebCoreSupport/WebCache.cpp17
-rw-r--r--Source/WebKit/android/WebCoreSupport/WebCache.h3
-rw-r--r--Source/WebKit/android/WebCoreSupport/WebCookieJar.cpp35
-rw-r--r--Source/WebKit/android/WebCoreSupport/WebCookieJar.h9
-rw-r--r--Source/WebKit/android/WebCoreSupport/WebRequest.cpp37
-rw-r--r--Source/WebKit/android/WebCoreSupport/WebRequest.h1
-rw-r--r--Source/WebKit/android/WebCoreSupport/WebUrlLoaderClient.cpp9
-rw-r--r--Source/WebKit/android/WebCoreSupport/WebViewClientError.cpp1
-rw-r--r--Source/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.cpp2
-rw-r--r--Source/WebKit/android/benchmark/Android.mk41
-rw-r--r--Source/WebKit/android/benchmark/Intercept.cpp190
-rw-r--r--Source/WebKit/android/benchmark/Intercept.h82
-rw-r--r--Source/WebKit/android/benchmark/MyJavaVM.cpp130
-rw-r--r--Source/WebKit/android/benchmark/MyJavaVM.h34
-rw-r--r--Source/WebKit/android/benchmark/main.cpp65
-rw-r--r--Source/WebKit/android/content/PhoneEmailDetector.cpp383
-rw-r--r--Source/WebKit/android/content/PhoneEmailDetector.h81
-rw-r--r--Source/WebKit/android/content/address_detector.cpp945
-rw-r--r--Source/WebKit/android/content/address_detector.h132
-rw-r--r--Source/WebKit/android/content/content_detector.cpp99
-rw-r--r--Source/WebKit/android/content/content_detector.h110
-rw-r--r--Source/WebKit/android/jni/AndroidHitTestResult.cpp269
-rw-r--r--Source/WebKit/android/jni/AndroidHitTestResult.h (renamed from Source/WebKit/android/RenderSkinRadio.h)56
-rw-r--r--Source/WebKit/android/jni/CacheManager.cpp6
-rw-r--r--Source/WebKit/android/jni/CookieManager.cpp47
-rw-r--r--Source/WebKit/android/jni/DeviceMotionAndOrientationManager.cpp10
-rw-r--r--Source/WebKit/android/jni/DeviceMotionAndOrientationManager.h2
-rwxr-xr-xSource/WebKit/android/jni/GeolocationPermissionsBridge.cpp4
-rw-r--r--Source/WebKit/android/jni/JavaBridge.cpp38
-rw-r--r--Source/WebKit/android/jni/JavaSharedClient.cpp47
-rw-r--r--Source/WebKit/android/jni/JniUtil.cpp58
-rw-r--r--Source/WebKit/android/jni/MIMETypeRegistry.cpp4
-rwxr-xr-xSource/WebKit/android/jni/MockGeolocation.cpp2
-rw-r--r--Source/WebKit/android/jni/PicturePile.cpp301
-rw-r--r--Source/WebKit/android/jni/PicturePile.h121
-rw-r--r--Source/WebKit/android/jni/PictureSet.cpp1236
-rw-r--r--Source/WebKit/android/jni/PictureSet.h145
-rw-r--r--Source/WebKit/android/jni/ViewStateSerializer.cpp197
-rw-r--r--Source/WebKit/android/jni/WebCoreFrameBridge.cpp660
-rw-r--r--Source/WebKit/android/jni/WebCoreFrameBridge.h14
-rw-r--r--Source/WebKit/android/jni/WebCoreJni.cpp41
-rw-r--r--Source/WebKit/android/jni/WebCoreJni.h6
-rw-r--r--Source/WebKit/android/jni/WebCoreJniOnLoad.cpp174
-rw-r--r--Source/WebKit/android/jni/WebCoreResourceLoader.cpp352
-rw-r--r--Source/WebKit/android/jni/WebCoreResourceLoader.h78
-rw-r--r--Source/WebKit/android/jni/WebCoreViewBridge.h2
-rw-r--r--Source/WebKit/android/jni/WebFrameView.cpp49
-rw-r--r--Source/WebKit/android/jni/WebFrameView.h2
-rw-r--r--Source/WebKit/android/jni/WebHistory.cpp754
-rw-r--r--Source/WebKit/android/jni/WebHistory.h32
-rw-r--r--Source/WebKit/android/jni/WebIconDatabase.cpp57
-rw-r--r--Source/WebKit/android/jni/WebIconDatabase.h2
-rw-r--r--Source/WebKit/android/jni/WebSettings.cpp153
-rw-r--r--Source/WebKit/android/jni/WebStorage.cpp6
-rw-r--r--Source/WebKit/android/jni/WebViewCore.cpp3303
-rw-r--r--Source/WebKit/android/jni/WebViewCore.h366
-rw-r--r--Source/WebKit/android/nav/CacheBuilder.cpp3194
-rw-r--r--Source/WebKit/android/nav/CacheBuilder.h297
-rw-r--r--Source/WebKit/android/nav/CachedColor.cpp58
-rw-r--r--Source/WebKit/android/nav/CachedColor.h87
-rw-r--r--Source/WebKit/android/nav/CachedDebug.h72
-rw-r--r--Source/WebKit/android/nav/CachedFrame.cpp1511
-rw-r--r--Source/WebKit/android/nav/CachedFrame.h287
-rw-r--r--Source/WebKit/android/nav/CachedHistory.cpp183
-rw-r--r--Source/WebKit/android/nav/CachedHistory.h89
-rw-r--r--Source/WebKit/android/nav/CachedInput.cpp100
-rw-r--r--Source/WebKit/android/nav/CachedInput.h115
-rw-r--r--Source/WebKit/android/nav/CachedLayer.cpp221
-rw-r--r--Source/WebKit/android/nav/CachedLayer.h86
-rw-r--r--Source/WebKit/android/nav/CachedNode.cpp431
-rw-r--r--Source/WebKit/android/nav/CachedNode.h245
-rw-r--r--Source/WebKit/android/nav/CachedNodeType.h56
-rw-r--r--Source/WebKit/android/nav/CachedPrefix.h53
-rw-r--r--Source/WebKit/android/nav/CachedRoot.cpp1815
-rw-r--r--Source/WebKit/android/nav/CachedRoot.h142
-rw-r--r--Source/WebKit/android/nav/DrawExtra.cpp96
-rw-r--r--Source/WebKit/android/nav/DrawExtra.h38
-rw-r--r--Source/WebKit/android/nav/FindCanvas.cpp700
-rw-r--r--Source/WebKit/android/nav/FindCanvas.h259
-rw-r--r--Source/WebKit/android/nav/SelectText.cpp1931
-rw-r--r--Source/WebKit/android/nav/SelectText.h97
-rw-r--r--Source/WebKit/android/nav/WebView.cpp2718
-rw-r--r--Source/WebKit/android/plugins/ANPSoundInterface.cpp8
-rw-r--r--Source/WebKit/android/plugins/ANPSurfaceInterface.cpp16
-rw-r--r--Source/WebKit/android/plugins/PluginWidgetAndroid.cpp7
-rw-r--r--Source/WebKit/android/smoke/MessageThread.cpp2
-rw-r--r--Source/WebKit/android/wds/Command.cpp2
-rw-r--r--Source/WebKit/android/wds/Connection.cpp2
-rw-r--r--Source/WebKit/android/wds/DebugServer.cpp16
-rw-r--r--Source/WebKit/android/wds/client/AdbConnection.cpp24
-rw-r--r--Source/WebKit/android/wds/client/ClientUtils.h2
-rw-r--r--Source/WebKit/android/wds/client/main.cpp16
118 files changed, 6627 insertions, 20857 deletions
diff --git a/Source/WebKit/android/AndroidLog.h b/Source/WebKit/android/AndroidLog.h
index 3d3eaaa..f034d35 100644
--- a/Source/WebKit/android/AndroidLog.h
+++ b/Source/WebKit/android/AndroidLog.h
@@ -26,17 +26,25 @@
#ifndef AndroidLog_h
#define AndroidLog_h
+#ifndef LOG_TAG
+#define LOG_TAG __FILE__
+#endif
+
+#include <cutils/log.h>
+#include <utils/Trace.h>
+#include <wtf/CurrentTime.h>
+
#ifdef ANDROID_DOM_LOGGING
#include <stdio.h>
extern FILE* gDomTreeFile;
#define DOM_TREE_LOG_FILE "/sdcard/domTree.txt"
#define DUMP_DOM_LOGD(...) { if (gDomTreeFile) \
- fprintf(gDomTreeFile, __VA_ARGS__); else LOGD(__VA_ARGS__); }
+ fprintf(gDomTreeFile, __VA_ARGS__); else ALOGD(__VA_ARGS__); }
extern FILE* gRenderTreeFile;
#define RENDER_TREE_LOG_FILE "/sdcard/renderTree.txt"
#define DUMP_RENDER_LOGD(...) { if (gRenderTreeFile) \
- fprintf(gRenderTreeFile, __VA_ARGS__); else LOGD(__VA_ARGS__); }
+ fprintf(gRenderTreeFile, __VA_ARGS__); else ALOGD(__VA_ARGS__); }
#else
#define DUMP_DOM_LOGD(...) ((void)0)
#define DUMP_RENDER_LOGD(...) ((void)0)
@@ -45,4 +53,28 @@ extern FILE* gRenderTreeFile;
#define DISPLAY_TREE_LOG_FILE "/sdcard/displayTree.txt"
#define LAYERS_TREE_LOG_FILE "/sdcard/layersTree.plist"
+#define FLOAT_RECT_FORMAT "[x=%.2f,y=%.2f,w=%.2f,h=%.2f]"
+#define FLOAT_RECT_ARGS(fr) fr.x(), fr.y(), fr.width(), fr.height()
+#define INT_RECT_FORMAT "[x=%d,y=%d,w=%d,h=%d]"
+#define INT_RECT_ARGS(ir) ir.x(), ir.y(), ir.width(), ir.height()
+
+#define TRACE_METHOD() android::ScopedTrace __st(ATRACE_TAG_WEBVIEW, __func__);
+
+#define TIME_METHOD() MethodTimer __method_timer(__func__)
+class MethodTimer {
+public:
+ MethodTimer(const char* name)
+ : m_methodName(name)
+ {
+ m_startTime = currentTimeMS();
+ }
+ virtual ~MethodTimer() {
+ double duration = currentTimeMS() - m_startTime;
+ ALOGD("%s took %.2fms", m_methodName, duration);
+ }
+private:
+ const char* m_methodName;
+ double m_startTime;
+};
+
#endif // AndroidLog_h
diff --git a/Source/WebKit/android/RenderSkinAndroid.cpp b/Source/WebKit/android/RenderSkinAndroid.cpp
index 4a9ce68..9529624 100644
--- a/Source/WebKit/android/RenderSkinAndroid.cpp
+++ b/Source/WebKit/android/RenderSkinAndroid.cpp
@@ -27,14 +27,11 @@
#include "config.h"
#include "RenderSkinAndroid.h"
-#include "RenderSkinButton.h"
-#include "RenderSkinCombo.h"
#include "RenderSkinMediaButton.h"
-#include "RenderSkinRadio.h"
#include "SkImageDecoder.h"
-#include <utils/AssetManager.h>
-#include <utils/Asset.h>
+#include <androidfw/AssetManager.h>
+#include <androidfw/Asset.h>
namespace WebCore {
@@ -43,7 +40,6 @@ RenderSkinAndroid::Resolution RenderSkinAndroid::s_drawableResolution = RenderSk
RenderSkinAndroid::~RenderSkinAndroid()
{
- delete m_button;
}
RenderSkinAndroid::RenderSkinAndroid(String drawableDirectory)
{
@@ -56,7 +52,6 @@ RenderSkinAndroid::RenderSkinAndroid(String drawableDirectory)
s_drawableDirectory = drawableDirectory;
}
- m_button = new RenderSkinButton(drawableDirectory);
}
bool RenderSkinAndroid::DecodeBitmap(android::AssetManager* am, const char* fileName, SkBitmap* bitmap)
@@ -65,14 +60,14 @@ bool RenderSkinAndroid::DecodeBitmap(android::AssetManager* am, const char* file
if (!asset) {
asset = am->openNonAsset(fileName, android::Asset::ACCESS_BUFFER);
if (!asset) {
- LOGD("RenderSkinAndroid: File \"%s\" not found.\n", fileName);
+ ALOGD("RenderSkinAndroid: File \"%s\" not found.\n", fileName);
return false;
}
}
bool success = SkImageDecoder::DecodeMemory(asset->getBuffer(false), asset->getLength(), bitmap);
if (!success) {
- LOGD("RenderSkinAndroid: Failed to decode %s\n", fileName);
+ ALOGD("RenderSkinAndroid: Failed to decode %s\n", fileName);
}
delete asset;
diff --git a/Source/WebKit/android/RenderSkinAndroid.h b/Source/WebKit/android/RenderSkinAndroid.h
index bbc327d..1d3820d 100644
--- a/Source/WebKit/android/RenderSkinAndroid.h
+++ b/Source/WebKit/android/RenderSkinAndroid.h
@@ -36,7 +36,6 @@ class SkBitmap;
namespace WebCore {
class Node;
-class RenderSkinButton;
class RenderSkinAndroid
{
@@ -69,12 +68,9 @@ public:
static String DrawableDirectory() { return s_drawableDirectory; }
static Resolution DrawableResolution() { return s_drawableResolution; }
- RenderSkinButton* renderSkinButton() const { return m_button; }
-
private:
static String s_drawableDirectory;
static Resolution s_drawableResolution;
- RenderSkinButton* m_button;
};
} // WebCore
diff --git a/Source/WebKit/android/RenderSkinButton.cpp b/Source/WebKit/android/RenderSkinButton.cpp
deleted file mode 100644
index 11e2fa8..0000000
--- a/Source/WebKit/android/RenderSkinButton.cpp
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright 2006, 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 "WebCore"
-
-#include "config.h"
-#include "android_graphics.h"
-#include "Document.h"
-#include "IntRect.h"
-#include "Node.h"
-#include "RenderSkinButton.h"
-#include "RenderSkinNinePatch.h"
-#include "SkCanvas.h"
-#include "SkNinePatch.h"
-#include "SkRect.h"
-#include <utils/Asset.h>
-#include <utils/AssetManager.h>
-#include <utils/Debug.h>
-#include <utils/Log.h>
-#include <utils/ResourceTypes.h>
-#include <wtf/text/CString.h>
-
-extern android::AssetManager* globalAssetManager();
-
-static const char* gFiles[] = {
- "btn_default_disabled_holo.9.png",
- "btn_default_normal_holo.9.png",
- "btn_default_focused_holo.9.png",
- "btn_default_pressed_holo.9.png"
- };
-
-namespace WebCore {
-
-RenderSkinButton::RenderSkinButton(String drawableDirectory)
- : m_decoded(false)
- , m_decodingAttempted(false)
- , m_drawableDirectory(drawableDirectory)
-{
- // Ensure our enums properly line up with our arrays.
- android::CompileTimeAssert<(RenderSkinAndroid::kDisabled == 0)> a1;
- android::CompileTimeAssert<(RenderSkinAndroid::kNormal == 1)> a2;
- android::CompileTimeAssert<(RenderSkinAndroid::kFocused == 2)> a3;
- android::CompileTimeAssert<(RenderSkinAndroid::kPressed == 3)> a4;
-}
-
-void RenderSkinButton::decode()
-{
- m_decodingAttempted = true;
-
- android::AssetManager* am = globalAssetManager();
-
- for (size_t i = 0; i < 4; i++) {
- String path = m_drawableDirectory;
- path.append(String(gFiles[i]));
- if (!RenderSkinNinePatch::decodeAsset(am, path.utf8().data(), &m_buttons[i])) {
- m_decoded = false;
- LOGE("RenderSkinButton::decode: button assets failed to decode\n\tWebView buttons will not draw");
- return;
- }
- }
- m_decoded = true;
-}
-
-void RenderSkinButton::draw(SkCanvas* canvas, const IntRect& r,
- RenderSkinAndroid::State newState)
-{
- if (!m_decodingAttempted)
- decode();
-
- // If we failed to decode, do nothing. This way the browser still works,
- // and webkit will still draw the label and layout space for us.
- if (!m_decoded) {
- return;
- }
-
- // Ensure that the state is within the valid range of our array.
- SkASSERT(static_cast<unsigned>(newState) <
- static_cast<unsigned>(RenderSkinAndroid::kNumStates));
-
- RenderSkinNinePatch::DrawNinePatch(canvas, SkRect(r), m_buttons[newState]);
-}
-
-} //WebCore
diff --git a/Source/WebKit/android/RenderSkinButton.h b/Source/WebKit/android/RenderSkinButton.h
deleted file mode 100644
index 83c57dd..0000000
--- a/Source/WebKit/android/RenderSkinButton.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright 2006, 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 RenderSkinButton_h
-#define RenderSkinButton_h
-
-#include "RenderSkinAndroid.h"
-#include "RenderSkinNinePatch.h"
-
-class SkCanvas;
-
-namespace WebCore {
-class IntRect;
-
-class RenderSkinButton {
-public:
- RenderSkinButton(String drawableDirectory);
- /**
- * Draw the skin to the canvas, using the rectangle for its bounds and the
- * State to determine which skin to use, i.e. focused or not focused.
- */
- void draw(SkCanvas* , const IntRect& , RenderSkinAndroid::State);
-
- void decode();
-private:
- bool m_decoded;
- bool m_decodingAttempted;
- NinePatch m_buttons[4];
- String m_drawableDirectory;
-};
-
-} // WebCore
-#endif
diff --git a/Source/WebKit/android/RenderSkinCombo.cpp b/Source/WebKit/android/RenderSkinCombo.cpp
deleted file mode 100644
index 1711cfa..0000000
--- a/Source/WebKit/android/RenderSkinCombo.cpp
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * Copyright 2006, 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.
- */
-
-#include "config.h"
-#include "RenderSkinCombo.h"
-
-#include "Document.h"
-#include "Element.h"
-#include "Node.h"
-#include "NodeRenderStyle.h"
-#include "RenderStyle.h"
-#include "SkCanvas.h"
-#include "SkNinePatch.h"
-#include <utils/AssetManager.h>
-#include <wtf/text/CString.h>
-
-extern android::AssetManager* globalAssetManager();
-
-namespace WebCore {
-
-// Indicates if the entire asset is being drawn, or if the border is being
-// excluded and just the arrow drawn.
-enum BorderStyle {
- FullAsset,
- NoBorder,
- BorderStyleCount // Keep at the end.
-};
-
-// There are 2.5 different concepts of a 'border' here, which results
-// in rather a lot of magic constants.
-
-// Firstly, we have the extra padding that webkit needs to know about,
-// which defines how much bigger this element is made by the
-// asset. This is actually a bit broader than the actual border on the
-// asset, to make things look less cramped. The border is the same
-// width on all sides, except on the right when it's significantly
-// wider to allow for the arrow.
-const int RenderSkinCombo::arrowMargin[ResolutionCount] = {
- 16, // Medium resolution
- 25, // High resolution
- 34 // Extra high resolution
-};
-const int RenderSkinCombo::padMargin[ResolutionCount] = {
- 1, // Medium resolution
- 1, // High resolution
- 1 // Extra high resolution
-};
-
-namespace {
-// Then we have the borders used for the 9-patch stretch. The
-// rectangle at the centre of these borders is entirely below and to
-// the left of the arrow in the asset. Hence the border widths are the
-// same for the bottom and left, but are different for the top. The
-// right hand border width happens to be the same as arrowMargin
-// defined above.
-const int stretchMargin[RenderSkinAndroid::ResolutionCount] = { // border width for the bottom and left of the 9-patch
- 2, // Medium resolution
- 2, // High resolution
- 3 // Extra high resolution
-
-};
-const int stretchTop[RenderSkinAndroid::ResolutionCount] = { // border width for the top of the 9-patch
- 16, // Medium resolution
- 23, // High resolution
- 32 // Extra high resolution
-};
-
-// Finally, if the border is defined by the CSS, we only draw the
-// arrow and not the border. We do this by drawing the relevant subset
-// of the bitmap, which must now be precisely determined by what's in
-// the asset with no extra padding to make things look properly
-// spaced. The border to remove at the top, right and bottom of the
-// image is the same as stretchMargin above, but we need to know the width
-// of the arrow.
-const int arrowWidth[RenderSkinAndroid::ResolutionCount] = {
- 18, // Medium resolution
- 27, // High resolution
- 36 // Extra high resolution
-};
-
-// scale factors for various resolutions
-const float scaleFactor[RenderSkinAndroid::ResolutionCount] = {
- 1.0f, // medium res
- 1.5f, // high res
- 2.0f // extra high res
-};
-
-// Store the calculated 9 patch margins for each border style.
-SkIRect margin[BorderStyleCount];
-
-SkBitmap bitmaps[2][BorderStyleCount]; // Collection of assets for a combo box - 2 states (enabled/disabled)
-bool isDecodingAttempted = false; // True if we've tried to decode the assets
-bool isDecoded = false; // True if all assets were decoded
-
-} // namespace
-
-int RenderSkinCombo::minHeight() {
- return SkScalarRound(stretchTop[RenderSkinAndroid::DrawableResolution()]
- / scaleFactor[RenderSkinAndroid::DrawableResolution()]);
-}
-
-void RenderSkinCombo::Decode()
-{
- if (isDecodingAttempted)
- return;
-
- isDecodingAttempted = true;
- isDecoded = false;
-
- android::AssetManager* am = globalAssetManager();
-
- String drawableDirectory = RenderSkinAndroid::DrawableDirectory();
- Resolution res = RenderSkinAndroid::DrawableResolution();
-
- isDecoded = RenderSkinAndroid::DecodeBitmap(am, (drawableDirectory + "combobox_nohighlight.png").utf8().data(), &bitmaps[kNormal][FullAsset]);
- isDecoded &= RenderSkinAndroid::DecodeBitmap(am, (drawableDirectory + "combobox_disabled.png").utf8().data(), &bitmaps[kDisabled][FullAsset]);
-
- int width = bitmaps[kNormal][FullAsset].width();
- int height = bitmaps[kNormal][FullAsset].height();
- SkIRect subset;
- subset.set(width - arrowWidth[res], 0, width, height);
- bitmaps[kNormal][FullAsset].extractSubset(&bitmaps[kNormal][NoBorder], subset);
- bitmaps[kDisabled][FullAsset].extractSubset(&bitmaps[kDisabled][NoBorder], subset);
-
- // Calculate 9 patch margins.
- SkIRect fullAssetMargin;
- fullAssetMargin.fLeft = stretchMargin[res];
- fullAssetMargin.fTop = stretchMargin[res];
- fullAssetMargin.fRight = arrowMargin[res] + stretchMargin[res];
- fullAssetMargin.fBottom = stretchTop[res];
-
- SkIRect noBorderMargin;
- noBorderMargin.fLeft = 0;
- noBorderMargin.fTop = stretchTop[res];
- noBorderMargin.fRight = 0;
- noBorderMargin.fBottom = stretchMargin[res];
-
- margin[FullAsset] = fullAssetMargin;
- margin[NoBorder] = noBorderMargin;
-}
-
-bool RenderSkinCombo::Draw(SkCanvas* canvas, Node* element, int x, int y, int width, int height)
-{
- if (!isDecodingAttempted)
- Decode();
-
- if (!isDecoded)
- return true;
-
- int resolution = RenderSkinAndroid::DrawableResolution();
- State state = (element->isElementNode() && static_cast<Element*>(element)->isEnabledFormControl()) ? kNormal : kDisabled;
- height = std::max(height, (stretchMargin[resolution] * 2));
-
- SkRect bounds;
- BorderStyle drawBorder = FullAsset;
-
- bounds.set(SkIntToScalar(x+1), SkIntToScalar(y+1), SkIntToScalar(x + width-1), SkIntToScalar(y + height-1));
- RenderStyle* style = element->renderStyle();
- SkPaint paint;
- paint.setColor(style->visitedDependentColor(CSSPropertyBackgroundColor).rgb());
- canvas->drawRect(bounds, paint);
-
- bounds.set(SkIntToScalar(x), SkIntToScalar(y), SkIntToScalar(x + width), SkIntToScalar(y + height));
-
- // If this is an appearance where RenderTheme::paint returns true
- // without doing anything, this means that
- // RenderBox::PaintBoxDecorationWithSize will end up painting the
- // border, so we shouldn't paint a border here.
- if (style->appearance() == MenulistButtonPart ||
- style->appearance() == ListboxPart ||
- style->appearance() == TextFieldPart ||
- style->appearance() == TextAreaPart) {
- bounds.fLeft += SkIntToScalar(width - RenderSkinCombo::extraWidth());
- bounds.fRight -= SkIntToScalar(style->borderRightWidth());
- bounds.fTop += SkIntToScalar(style->borderTopWidth());
- bounds.fBottom -= SkIntToScalar(style->borderBottomWidth());
- drawBorder = NoBorder;
- }
- float scale = scaleFactor[resolution];
- bounds.fLeft = bounds.fLeft * scale;
- bounds.fRight = bounds.fRight * scale;
- bounds.fTop = bounds.fTop * scale;
- bounds.fBottom = bounds.fBottom * scale;
- int count = canvas->save();
- canvas->scale(1.0f / scale, 1.0f / scale);
- SkNinePatch::DrawNine(canvas, bounds, bitmaps[state][drawBorder], margin[drawBorder]);
- canvas->restoreToCount(count);
- return false;
-}
-
-} // namspace WebCore
diff --git a/Source/WebKit/android/RenderSkinCombo.h b/Source/WebKit/android/RenderSkinCombo.h
deleted file mode 100644
index a11faac..0000000
--- a/Source/WebKit/android/RenderSkinCombo.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright 2006, 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 RenderSkinCombo_h
-#define RenderSkinCombo_h
-
-#include "RenderSkinAndroid.h"
-#include "SkRect.h"
-
-class SkCanvas;
-
-namespace WebCore {
-
-// This is very similar to RenderSkinButton - maybe they should be the same class?
-class RenderSkinCombo : public RenderSkinAndroid
-{
-public:
-
- static void Decode();
- /**
- * Draw the provided Node on the SkCanvas, using the dimensions provided by
- * x,y,w,h. Return true if we did not draw, and WebKit needs to draw it,
- * false otherwise.
- */
- static bool Draw(SkCanvas* , Node* , int x, int y, int w, int h);
-
- // The image is wider than the RenderObject, so this accounts for that.
- static int extraWidth() { return arrowMargin[RenderSkinAndroid::DrawableResolution()]; }
- static int minHeight();
- static int padding() { return padMargin[RenderSkinAndroid::DrawableResolution()]; }
-
-
-private:
- const static int arrowMargin[ResolutionCount];
- const static int padMargin[ResolutionCount];
-};
-
-} // WebCore
-
-#endif
diff --git a/Source/WebKit/android/RenderSkinMediaButton.cpp b/Source/WebKit/android/RenderSkinMediaButton.cpp
index ef4b313..b3aa57d 100644
--- a/Source/WebKit/android/RenderSkinMediaButton.cpp
+++ b/Source/WebKit/android/RenderSkinMediaButton.cpp
@@ -36,7 +36,7 @@
#include "SkCanvas.h"
#include "SkNinePatch.h"
#include "SkRect.h"
-#include <utils/AssetManager.h>
+#include <androidfw/AssetManager.h>
#include <utils/Debug.h>
#include <utils/Log.h>
#include <wtf/text/CString.h>
@@ -82,19 +82,22 @@ void RenderSkinMediaButton::Decode()
String path = drawableDirectory + gFiles[i].name;
if (!RenderSkinAndroid::DecodeBitmap(am, path.utf8().data(), &gButton[i])) {
gDecodingFailed = true;
- LOGD("RenderSkinButton::Init: button assets failed to decode\n\tBrowser buttons will not draw");
+ ALOGD("RenderSkinButton::Init: button assets failed to decode\n\tBrowser buttons will not draw");
break;
}
}
}
void RenderSkinMediaButton::Draw(SkCanvas* canvas, const IntRect& r, int buttonType,
- bool translucent, RenderObject* o)
+ bool translucent, RenderObject* o, bool drawBackground)
{
if (!gDecoded) {
Decode();
}
+ if (!canvas)
+ return;
+
// If we failed to decode, do nothing. This way the browser still works,
// and webkit will still draw the label and layout space for us.
if (gDecodingFailed)
@@ -102,7 +105,6 @@ void RenderSkinMediaButton::Draw(SkCanvas* canvas, const IntRect& r, int buttonT
bool drawsNinePatch = false;
bool drawsImage = true;
- bool drawsBackgroundColor = true;
int ninePatchIndex = 0;
int imageIndex = 0;
@@ -136,13 +138,11 @@ void RenderSkinMediaButton::Draw(SkCanvas* canvas, const IntRect& r, int buttonT
case SPINNER_INNER:
case VIDEO:
{
- drawsBackgroundColor = false;
imageIndex = buttonType + 1;
break;
}
case BACKGROUND_SLIDER:
{
- drawsBackgroundColor = false;
drawsImage = false;
break;
}
@@ -155,7 +155,6 @@ void RenderSkinMediaButton::Draw(SkCanvas* canvas, const IntRect& r, int buttonT
}
case SLIDER_THUMB:
{
- drawsBackgroundColor = false;
imageMargin = 0;
imageIndex = buttonType + 1;
break;
@@ -164,7 +163,7 @@ void RenderSkinMediaButton::Draw(SkCanvas* canvas, const IntRect& r, int buttonT
return;
}
- if (drawsBackgroundColor) {
+ if (drawBackground) {
canvas->drawRect(r, paint);
}
diff --git a/Source/WebKit/android/RenderSkinMediaButton.h b/Source/WebKit/android/RenderSkinMediaButton.h
index d8b7c8d..484b90c 100644
--- a/Source/WebKit/android/RenderSkinMediaButton.h
+++ b/Source/WebKit/android/RenderSkinMediaButton.h
@@ -42,7 +42,7 @@ public:
* State to determine which skin to use, i.e. focused or not focused.
*/
static void Draw(SkCanvas* , const IntRect& , int buttonType, bool translucent = false,
- RenderObject* o = 0);
+ RenderObject* o = 0, bool drawBackground = true);
/**
* Button types
*/
diff --git a/Source/WebKit/android/RenderSkinNinePatch.cpp b/Source/WebKit/android/RenderSkinNinePatch.cpp
index faa9dc4..9ef0b4a 100644
--- a/Source/WebKit/android/RenderSkinNinePatch.cpp
+++ b/Source/WebKit/android/RenderSkinNinePatch.cpp
@@ -16,18 +16,18 @@
#include "config.h"
-#include "RenderSkinNinePatch.h"
#include "NinePatchPeeker.h"
+#include "RenderSkinNinePatch.h"
#include "SkCanvas.h"
#include "SkImageDecoder.h"
#include "SkNinePatch.h"
#include "SkRect.h"
#include "SkStream.h"
#include "SkTemplates.h"
-#include <utils/Asset.h>
-#include <utils/AssetManager.h>
+#include <androidfw/Asset.h>
+#include <androidfw/AssetManager.h>
+#include <androidfw/ResourceTypes.h>
#include <utils/Log.h>
-#include <utils/ResourceTypes.h>
class SkPaint;
class SkRegion;
@@ -53,7 +53,7 @@ bool RenderSkinNinePatch::decodeAsset(AssetManager* am, const char* filename, Ni
SkImageDecoder* decoder = SkImageDecoder::Factory(&stream);
if (!decoder) {
asset->close();
- LOGE("RenderSkinNinePatch::Failed to create an image decoder");
+ ALOGE("RenderSkinNinePatch::Failed to create an image decoder");
return false;
}
@@ -68,13 +68,13 @@ bool RenderSkinNinePatch::decodeAsset(AssetManager* am, const char* filename, Ni
decoder->setPeeker(&peeker);
if (!decoder->decode(&stream, &ninepatch->m_bitmap, prefConfig, mode, true)) {
asset->close();
- LOGE("RenderSkinNinePatch::Failed to decode nine patch asset");
+ ALOGE("RenderSkinNinePatch::Failed to decode nine patch asset");
return false;
}
asset->close();
- if (!peeker.fPatchIsValid) {
- LOGE("RenderSkinNinePatch::Patch data not valid");
+ if (!peeker.fPatch) {
+ ALOGE("RenderSkinNinePatch::Patch data not valid");
return false;
}
void** data = &ninepatch->m_serializedPatchData;
diff --git a/Source/WebKit/android/RenderSkinNinePatch.h b/Source/WebKit/android/RenderSkinNinePatch.h
index e4db260..8cda795 100644
--- a/Source/WebKit/android/RenderSkinNinePatch.h
+++ b/Source/WebKit/android/RenderSkinNinePatch.h
@@ -18,7 +18,7 @@
#define RenderSkinNinePatch_h
#include "SkBitmap.h"
-#include "utils/Asset.h"
+#include "androidfw/Asset.h"
namespace android {
class AssetManager;
diff --git a/Source/WebKit/android/RenderSkinRadio.cpp b/Source/WebKit/android/RenderSkinRadio.cpp
deleted file mode 100644
index 3c29818..0000000
--- a/Source/WebKit/android/RenderSkinRadio.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright 2006, 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.
- */
-
-#include "config.h"
-#include "RenderSkinRadio.h"
-
-#include "android_graphics.h"
-#include "Document.h"
-#include "Element.h"
-#include "InputElement.h"
-#include "IntRect.h"
-#include "Node.h"
-#include "RenderSkinAndroid.h"
-#include "SkBitmap.h"
-#include "SkCanvas.h"
-#include "SkRect.h"
-#include <utils/AssetManager.h>
-#include <wtf/text/CString.h>
-
-extern android::AssetManager* globalAssetManager();
-
-static const char* checks[] = { "btn_check_off_holo.png",
- "btn_check_on_holo.png",
- "btn_radio_off_holo.png",
- "btn_radio_on_holo.png"};
-// Matches the width of the bitmap
-static SkScalar s_bitmapWidth;
-
-namespace WebCore {
-
-static SkBitmap s_bitmap[4];
-static bool s_decodingAttempted = false;
-static bool s_decoded = false;
-
-void RenderSkinRadio::Decode() {
- if (s_decodingAttempted)
- return;
-
- s_decodingAttempted = true;
- s_decoded = false;
-
- android::AssetManager* am = globalAssetManager();
- String drawableDir = RenderSkinAndroid::DrawableDirectory();
- for (int i = 0; i < 4; i++) {
- String path = drawableDir + checks[i];
- if (!RenderSkinAndroid::DecodeBitmap(am, path.utf8().data(), &s_bitmap[i]))
- return;
- }
- s_decoded = true;
- s_bitmapWidth = SkIntToScalar(s_bitmap[0].width());
-}
-
-void RenderSkinRadio::Draw(SkCanvas* canvas, Node* element, const IntRect& ir,
- bool isCheckBox)
-{
- if (!element)
- return;
-
- if (!s_decodingAttempted)
- Decode();
-
- if (!s_decoded)
- return;
-
- SkRect r(ir);
- // Set up a paint to with filtering to look better.
- SkPaint paint;
- paint.setFlags(SkPaint::kFilterBitmap_Flag);
- int saveScaleCount = 0;
-
- if (!element->isElementNode() ||
- !static_cast<Element*>(element)->isEnabledFormControl()) {
- paint.setAlpha(0x80);
- }
- SkScalar width = r.width();
- SkScalar scale = SkScalarDiv(width, s_bitmapWidth);
- saveScaleCount = canvas->save();
- canvas->translate(r.fLeft, r.fTop);
- canvas->scale(scale, scale);
-
- bool checked = false;
- if (InputElement* inputElement = element->toInputElement()) {
- checked = inputElement->isChecked();
- }
-
- canvas->drawBitmap(s_bitmap[checked + 2*(!isCheckBox)],
- 0, 0, &paint);
- canvas->restoreToCount(saveScaleCount);
-}
-
-} //WebCore
diff --git a/Source/WebKit/android/TimeCounter.cpp b/Source/WebKit/android/TimeCounter.cpp
deleted file mode 100644
index 2393f8a..0000000
--- a/Source/WebKit/android/TimeCounter.cpp
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * Copyright 2009, 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 "WebCore"
-
-#include "config.h"
-#include "TimeCounter.h"
-
-#include "MemoryCache.h"
-#include "KURL.h"
-#include "Node.h"
-#include "SystemTime.h"
-#include "StyleBase.h"
-#include <sys/time.h>
-#include <time.h>
-#include <utils/Log.h>
-#include <wtf/CurrentTime.h>
-#include <wtf/text/CString.h>
-
-#if USE(JSC)
-#include "JSDOMWindow.h"
-#include <runtime/JSGlobalObject.h>
-#include <runtime/JSLock.h>
-#endif
-
-using namespace WebCore;
-using namespace WTF;
-using namespace JSC;
-
-namespace android {
-
-uint32_t getThreadMsec()
-{
-#if defined(HAVE_POSIX_CLOCKS)
- struct timespec tm;
-
- clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tm);
- return tm.tv_sec * 1000LL + tm.tv_nsec / 1000000;
-#else
- struct timeval now;
- struct timezone zone;
-
- gettimeofday(&now, &zone);
- return now.tv_sec * 1000LL + now.tv_usec / 1000;
-#endif
-}
-
-#ifdef ANDROID_INSTRUMENT
-
-static double sStartTotalTime;
-static uint32_t sStartThreadTime;
-static double sLastTotalTime;
-static uint32_t sLastThreadTime;
-
-uint32_t TimeCounter::sStartWebCoreThreadTime;
-uint32_t TimeCounter::sEndWebCoreThreadTime;
-bool TimeCounter::sRecordWebCoreTime;
-uint32_t TimeCounter::sTotalTimeUsed[TimeCounter::TotalTimeCounterCount];
-uint32_t TimeCounter::sLastTimeUsed[TimeCounter::TotalTimeCounterCount];
-uint32_t TimeCounter::sCounter[TimeCounter::TotalTimeCounterCount];
-uint32_t TimeCounter::sLastCounter[TimeCounter::TotalTimeCounterCount];
-uint32_t TimeCounter::sStartTime[TimeCounter::TotalTimeCounterCount];
-
-int QemuTracerAuto::reentry_count = 0;
-
-static const char* timeCounterNames[] = {
- "css parsing",
- "javascript",
- "javascript init",
- "javascript parsing",
- "javascript execution",
- "calculate style",
- "Java callback (frame bridge)",
- "parsing (may include calcStyle, Java callback or inline script execution)",
- "layout",
- "native 1 (frame bridge)",
- "native 2 (resource load)",
- "native 3 (shared timer)",
- "build nav (webview core)",
- "record content (webview core)",
- "native 4 (webview core)",
- "draw content (webview ui)",
-};
-
-void TimeCounter::record(enum Type type, const char* functionName)
-{
- recordNoCounter(type, functionName);
- sCounter[type]++;
-}
-
-void TimeCounter::recordNoCounter(enum Type type, const char* functionName)
-{
- uint32_t time = sEndWebCoreThreadTime = getThreadMsec();
- uint32_t elapsed = time - sStartTime[type];
- sTotalTimeUsed[type] += elapsed;
- if (elapsed > 1000)
- LOGW("***** %s() used %d ms\n", functionName, elapsed);
-}
-
-void TimeCounter::report(const KURL& url, int live, int dead, size_t arenaSize)
-{
- String urlString = url;
- int totalTime = static_cast<int>((currentTime() - sStartTotalTime) * 1000);
- int threadTime = getThreadMsec() - sStartThreadTime;
- LOGD("*-* Total load time: %d ms, thread time: %d ms for %s\n",
- totalTime, threadTime, urlString.utf8().data());
- for (Type type = (Type) 0; type < TotalTimeCounterCount; type
- = (Type) (type + 1)) {
- char scratch[256];
- int index = sprintf(scratch, "*-* Total %s time: %d ms",
- timeCounterNames[type], sTotalTimeUsed[type]);
- if (sCounter[type] > 0)
- sprintf(&scratch[index], " called %d times", sCounter[type]);
- LOGD("%s", scratch);
- }
- LOGD("Current cache has %d bytes live and %d bytes dead", live, dead);
- LOGD("Current render arena takes %d bytes", arenaSize);
-#if USE(JSC)
- JSLock lock(false);
- Heap::Statistics jsHeapStatistics = JSDOMWindow::commonJSGlobalData()->heap.statistics();
- LOGD("Current JavaScript heap size is %d and has %d bytes free",
- jsHeapStatistics.size, jsHeapStatistics.free);
-#endif
- LOGD("Current CSS styles use %d bytes", StyleBase::reportStyleSize());
- LOGD("Current DOM nodes use %d bytes", WebCore::Node::reportDOMNodesSize());
-}
-
-void TimeCounter::reportNow()
-{
- double current = currentTime();
- uint32_t currentThread = getThreadMsec();
- int elapsedTime = static_cast<int>((current - sLastTotalTime) * 1000);
- int elapsedThreadTime = currentThread - sLastThreadTime;
- LOGD("*-* Elapsed time: %d ms, ui thread time: %d ms, webcore thread time:"
- " %d ms\n", elapsedTime, elapsedThreadTime, sEndWebCoreThreadTime -
- sStartWebCoreThreadTime);
- for (Type type = (Type) 0; type < TotalTimeCounterCount; type
- = (Type) (type + 1)) {
- if (sTotalTimeUsed[type] == sLastTimeUsed[type])
- continue;
- char scratch[256];
- int index = sprintf(scratch, "*-* Diff %s time: %d ms",
- timeCounterNames[type], sTotalTimeUsed[type] - sLastTimeUsed[type]);
- if (sCounter[type] > sLastCounter[type])
- sprintf(&scratch[index], " called %d times", sCounter[type]
- - sLastCounter[type]);
- LOGD("%s", scratch);
- }
- memcpy(sLastTimeUsed, sTotalTimeUsed, sizeof(sTotalTimeUsed));
- memcpy(sLastCounter, sCounter, sizeof(sCounter));
- sLastTotalTime = current;
- sLastThreadTime = currentThread;
- sRecordWebCoreTime = true;
-}
-
-void TimeCounter::reset() {
- bzero(sTotalTimeUsed, sizeof(sTotalTimeUsed));
- bzero(sCounter, sizeof(sCounter));
- LOGD("*-* Start browser instrument\n");
- sStartTotalTime = currentTime();
- sStartThreadTime = getThreadMsec();
-}
-
-void TimeCounter::start(enum Type type)
-{
- uint32_t time = getThreadMsec();
- if (sRecordWebCoreTime) {
- sStartWebCoreThreadTime = time;
- sRecordWebCoreTime = false;
- }
- sStartTime[type] = time;
-}
-
-#endif // ANDROID_INSTRUMENT
-
-}
diff --git a/Source/WebKit/android/TimeCounter.h b/Source/WebKit/android/TimeCounter.h
deleted file mode 100644
index ecede27..0000000
--- a/Source/WebKit/android/TimeCounter.h
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright 2009, 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 TimeCounter_h
-#define TimeCounter_h
-
-#include "hardware_legacy/qemu_tracing.h"
-
-namespace WebCore {
-
-class KURL;
-
-}
-
-namespace android {
-
-uint32_t getThreadMsec();
-
-#ifdef ANDROID_INSTRUMENT
-
-class TimeCounter {
-public:
- enum Type {
- // function base counters
- CSSParseTimeCounter,
- JavaScriptTimeCounter,
- JavaScriptInitTimeCounter,
- JavaScriptParseTimeCounter,
- JavaScriptExecuteTimeCounter,
- CalculateStyleTimeCounter,
- JavaCallbackTimeCounter,
- ParsingTimeCounter,
- LayoutTimeCounter,
- // file base counters
- NativeCallbackTimeCounter, // WebCoreFrameBridge.cpp
- ResourceTimeCounter, // WebCoreResourceLoader.cpp
- SharedTimerTimeCounter, // JavaBridge.cpp
- WebViewCoreBuildNavTimeCounter,
- WebViewCoreRecordTimeCounter,
- WebViewCoreTimeCounter, // WebViewCore.cpp
- WebViewUIDrawTimeCounter,
- TotalTimeCounterCount
- };
-
- static void record(enum Type type, const char* functionName);
- static void recordNoCounter(enum Type type, const char* functionName);
- static void report(const WebCore::KURL& , int live, int dead, size_t arenaSize);
- static void reportNow();
- static void reset();
- static void start(enum Type type);
-private:
- static uint32_t sStartWebCoreThreadTime;
- static uint32_t sEndWebCoreThreadTime;
- static bool sRecordWebCoreTime;
- static uint32_t sTotalTimeUsed[TotalTimeCounterCount];
- static uint32_t sLastTimeUsed[TotalTimeCounterCount];
- static uint32_t sCounter[TotalTimeCounterCount];
- static uint32_t sLastCounter[TotalTimeCounterCount];
- static uint32_t sStartTime[TotalTimeCounterCount];
- friend class TimeCounterAuto;
-};
-
-class TimeCounterAuto {
-public:
- TimeCounterAuto(TimeCounter::Type type) :
- m_type(type), m_startTime(getThreadMsec()) {}
- ~TimeCounterAuto() {
- uint32_t time = getThreadMsec();
- TimeCounter::sEndWebCoreThreadTime = time;
- TimeCounter::sTotalTimeUsed[m_type] += time - m_startTime;
- TimeCounter::sCounter[m_type]++;
- }
-private:
- TimeCounter::Type m_type;
- uint32_t m_startTime;
-};
-
-class QemuTracerAuto {
-public:
- QemuTracerAuto() {
- if (!reentry_count)
- qemu_start_tracing();
- reentry_count++;
- }
-
- ~QemuTracerAuto() {
- reentry_count--;
- if (!reentry_count)
- qemu_stop_tracing();
- }
-private:
- static int reentry_count;
-};
-#endif // ANDROID_INSTRUMENT
-
-}
-
-#endif
diff --git a/Source/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp b/Source/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp
index ab5fcb0..907dc3c 100644
--- a/Source/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp
+++ b/Source/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp
@@ -95,7 +95,7 @@ void ChromeClientAndroid::scheduleCompositingLayerSync()
m_needsLayerSync = true;
WebViewCore* webViewCore = WebViewCore::getWebViewCore(m_webFrame->page()->mainFrame()->view());
if (webViewCore)
- webViewCore->layersDraw();
+ webViewCore->contentDraw();
}
void ChromeClientAndroid::setNeedsOneShotDrawingSynchronization()
@@ -161,8 +161,15 @@ void ChromeClientAndroid::focus()
}
void ChromeClientAndroid::unfocus() { notImplemented(); }
-bool ChromeClientAndroid::canTakeFocus(FocusDirection) { notImplemented(); return false; }
-void ChromeClientAndroid::takeFocus(FocusDirection) { notImplemented(); }
+bool ChromeClientAndroid::canTakeFocus(FocusDirection direction)
+{
+ return android::WebViewCore::getWebViewCore(m_webFrame->page()->mainFrame()->view())->chromeCanTakeFocus(direction);
+}
+
+void ChromeClientAndroid::takeFocus(FocusDirection direction)
+{
+ android::WebViewCore::getWebViewCore(m_webFrame->page()->mainFrame()->view())->chromeTakeFocus(direction);
+}
void ChromeClientAndroid::focusedNodeChanged(Node* node)
{
@@ -181,10 +188,10 @@ Page* ChromeClientAndroid::createWindow(Frame* frame, const FrameLoadRequest&,
return frame->page();
#endif
- const WebCoreViewBridge* bridge = frame->view()->platformWidget();
+ FloatRect window = windowRect();
bool dialog = features.dialog || !features.resizable
- || (features.heightSet && features.height < bridge->height()
- && features.widthSet && features.width < bridge->width())
+ || (features.heightSet && features.height < window.height()
+ && features.widthSet && features.width < window.width())
|| (!features.menuBarVisible && !features.statusBarVisible
&& !features.toolBarVisible && !features.locationBarVisible
&& !features.scrollbarsVisible);
@@ -231,11 +238,7 @@ void ChromeClientAndroid::addMessageToConsole(MessageSource, MessageType, Messag
android::WebViewCore::getWebViewCore(m_webFrame->page()->mainFrame()->view())->addMessageToConsole(message, lineNumber, sourceID, msgLevel);
}
-void ChromeClientAndroid::formDidBlur(const WebCore::Node* node)
-{
- android::WebViewCore::getWebViewCore(m_webFrame->page()->mainFrame()->view())->formDidBlur(node);
-}
-
+void ChromeClientAndroid::formDidBlur(const WebCore::Node* node) { notImplemented(); }
bool ChromeClientAndroid::canRunBeforeUnloadConfirmPanel() { return true; }
bool ChromeClientAndroid::runBeforeUnloadConfirmPanel(const String& message, Frame* frame) {
String url = frame->document()->documentURI();
@@ -298,7 +301,7 @@ bool ChromeClientAndroid::shouldInterruptJavaScript() {
KeyboardUIMode ChromeClientAndroid::keyboardUIMode()
{
- return KeyboardAccessDefault;
+ return KeyboardAccessTabsToLinks;
}
IntRect ChromeClientAndroid::windowResizerRect() const { return IntRect(0, 0, 0, 0); }
@@ -638,6 +641,11 @@ void ChromeClientAndroid::enterFullscreenForNode(Node* node)
void ChromeClientAndroid::exitFullscreenForNode(Node* node)
{
+ FrameView* frameView = m_webFrame->page()->mainFrame()->view();
+ android::WebViewCore* core = android::WebViewCore::getWebViewCore(frameView);
+ if (core)
+ core->exitFullscreenVideo();
+ return;
}
#endif
diff --git a/Source/WebKit/android/WebCoreSupport/ChromiumIncludes.h b/Source/WebKit/android/WebCoreSupport/ChromiumIncludes.h
index 022511a..1c898a0 100644
--- a/Source/WebKit/android/WebCoreSupport/ChromiumIncludes.h
+++ b/Source/WebKit/android/WebCoreSupport/ChromiumIncludes.h
@@ -23,31 +23,46 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+// All source files wishing to include Chromium headers must include this file
+// and must not incude Chromium headers directly.
+
#ifndef ChromiumIncludes_h
#define ChromiumIncludes_h
#include "config.h"
-// Include all external/chromium files in this file so the problems with the LOG
-// and LOG_ASSERT defines can be handled in one place.
-
-// Undefine LOG and LOG_ASSERT before including chrome code, and if they were
-// defined attempt to set the macros to the Android logging macros (which are
-// the only ones that actually log).
-
+// Both WebKit and Chromium define LOG. In AOSP, the framework also defines
+// LOG. To avoid conflicts, we undefine LOG before including Chromium code,
+// then define it back to the WebKit macro.
#ifdef LOG
-#define LOG_WAS_DEFINED LOG
+#define LOG_WAS_DEFINED
#undef LOG
#endif
-#ifdef LOG_ASSERT
-#define LOG_ASSERT_WAS_DEFINED LOG_ASSERT
+// In AOSP, the framework still uses LOG_ASSERT (as well as ALOG_ASSERT), which
+// conflicts with Chromium's LOG_ASSERT. So we undefine LOG_ASSERT to allow the
+// Chromium implementation to be picked up. We also redefine ALOG_ASSERT to the
+// underlying framework implementation without using LOG_ASSERT.
+// TODO: Remove this once LOG_ASSERT is removed from the framework in AOSP.
#undef LOG_ASSERT
+#undef ALOG_ASSERT
+// Copied from log.h.
+#define ALOG_ASSERT(cond, ...) LOG_FATAL_IF(!(cond), ## __VA_ARGS__)
+
+// Chromium won't build without NDEBUG set, so we set it for all source files
+// that use Chromium code. This means that if NDEBUG was previously unset, we
+// have to redefine ASSERT() to a no-op, as this is enabled in debug builds.
+// Unfortunately, ASSERT() is defined from config.h, so we can't get in first.
+#ifndef NDEBUG
+#define NDEBUG 1
+#undef ASSERT
+#define ASSERT(assertion) (void(0))
#endif
#include <android/net/android_network_library_impl.h>
#include <android/jni/jni_utils.h>
#include <base/callback.h>
+#include <base/lazy_instance.h>
#include <base/memory/ref_counted.h>
#include <base/message_loop_proxy.h>
#include <base/openssl_util.h>
@@ -100,13 +115,15 @@
#endif
#undef LOG
-#if defined(LOG_WAS_DEFINED) && defined(LOG_PRI)
-#define LOG(priority, tag, ...) LOG_PRI(ANDROID_##priority, tag, __VA_ARGS__)
+// If LOG was defined, restore it to the WebKit macro.
+#ifdef LOG_WAS_DEFINED
+// If LOG was defined, JOIN_LOG_CHANNEL_WITH_PREFIX must be too.
+// Copied from Assertions.h.
+#if LOG_DISABLED
+#define LOG(channel, ...) ((void)0)
+#else
+#define LOG(channel, ...) WTFLog(&JOIN_LOG_CHANNEL_WITH_PREFIX(LOG_CHANNEL_PREFIX, channel), __VA_ARGS__)
#endif
-
-#undef LOG_ASSERT
-#if defined(LOG_ASSERT_WAS_DEFINED) && defined(LOG_FATAL_IF)
-#define LOG_ASSERT(cond, ...) LOG_FATAL_IF(!(cond), ## __VA_ARGS__)
#endif
#endif
diff --git a/Source/WebKit/android/WebCoreSupport/EditorClientAndroid.cpp b/Source/WebKit/android/WebCoreSupport/EditorClientAndroid.cpp
index 785f0a8..042c227 100644
--- a/Source/WebKit/android/WebCoreSupport/EditorClientAndroid.cpp
+++ b/Source/WebKit/android/WebCoreSupport/EditorClientAndroid.cpp
@@ -228,8 +228,22 @@ void EditorClientAndroid::checkGrammarOfString(unsigned short const*, int, WTF::
void EditorClientAndroid::checkSpellingOfString(unsigned short const*, int, int*, int*) {}
String EditorClientAndroid::getAutoCorrectSuggestionForMisspelledWord(const String&) { return String(); }
void EditorClientAndroid::textFieldDidEndEditing(Element*) {}
-void EditorClientAndroid::textDidChangeInTextArea(Element*) {}
-void EditorClientAndroid::textDidChangeInTextField(Element*) {}
+void EditorClientAndroid::textDidChangeInTextArea(Element* element)
+{
+ Frame* frame = m_page->focusController()->focusedOrMainFrame();
+ if (!frame || !frame->view())
+ return;
+ WebViewCore* webViewCore = WebViewCore::getWebViewCore(frame->view());
+ webViewCore->updateTextSizeAndScroll(element);
+}
+void EditorClientAndroid::textDidChangeInTextField(Element* element)
+{
+ Frame* frame = m_page->focusController()->focusedOrMainFrame();
+ if (!frame || !frame->view())
+ return;
+ WebViewCore* webViewCore = WebViewCore::getWebViewCore(frame->view());
+ webViewCore->updateTextSizeAndScroll(element);
+}
void EditorClientAndroid::textFieldDidBeginEditing(Element*) {}
void EditorClientAndroid::ignoreWordInSpellDocument(String const&) {}
diff --git a/Source/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp b/Source/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp
index 0be31eb..ac5cd9d 100644
--- a/Source/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp
+++ b/Source/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp
@@ -70,7 +70,6 @@
#include "SkRect.h"
#include "TextEncoding.h"
#include "WebCoreFrameBridge.h"
-#include "WebCoreResourceLoader.h"
#include "WebHistory.h"
#include "WebIconDatabase.h"
#include "WebFrameView.h"
@@ -79,7 +78,7 @@
#include "autofill/WebAutofill.h"
#include "android_graphics.h"
-#include <utils/AssetManager.h>
+#include <androidfw/AssetManager.h>
#include <wtf/text/CString.h>
#define verifiedOk() // Verified that we don't need to implement this.
@@ -267,11 +266,11 @@ void FrameLoaderClientAndroid::dispatchDidReceiveIcon() {
// There is a bug in webkit where cancelling an icon load is treated as a
// failure. When this is fixed, we can ASSERT again that we have an icon.
if (icon) {
- LOGV("Received icon (%p) for %s", icon,
+ ALOGV("Received icon (%p) for %s", icon,
url.utf8().data());
m_webFrame->didReceiveIcon(icon);
} else {
- LOGV("Icon data for %s unavailable, registering for notification...",
+ ALOGV("Icon data for %s unavailable, registering for notification...",
url.utf8().data());
registerForIconNotification();
}
@@ -423,7 +422,9 @@ void FrameLoaderClientAndroid::dispatchDidFirstLayout() {
// so that about:blank will update the screen.
if (!m_frame->tree()->parent()) {
// Only need to notify Java side for the top frame
- WebViewCore::getWebViewCore(m_frame->view())->didFirstLayout();
+ WebViewCore* core = WebViewCore::getWebViewCore(m_frame->view());
+ if (core)
+ core->didFirstLayout();
}
}
@@ -946,11 +947,11 @@ void FrameLoaderClientAndroid::transitionToCommittedForNewPage() {
Retain(webViewCore);
// Save the old WebFrameView's bounds and apply them to the new WebFrameView
- WebFrameView* oldWebFrameView = static_cast<WebFrameView*> (m_frame->view()->platformWidget());
- IntRect bounds = oldWebFrameView->getBounds();
- IntRect visBounds = oldWebFrameView->getVisibleBounds();
- IntRect windowBounds = oldWebFrameView->getWindowBounds();
- WebCore::FrameView* oldFrameView = oldWebFrameView->view();
+ RefPtr<WebCore::FrameView> oldFrameView = m_frame->view();
+ WebFrameView* oldWebFrameView = static_cast<WebFrameView*> (oldFrameView->platformWidget());
+ IntRect bounds;
+ if (oldWebFrameView)
+ bounds = oldWebFrameView->getBounds();
const float oldZoomFactor = oldFrameView->frame()->textZoomFactor();
m_frame->createView(bounds.size(), oldFrameView->baseBackgroundColor(), oldFrameView->isTransparent(),
oldFrameView->fixedLayoutSize(), oldFrameView->useFixedLayout());
@@ -958,21 +959,19 @@ void FrameLoaderClientAndroid::transitionToCommittedForNewPage() {
m_frame->setTextZoomFactor(oldZoomFactor);
}
- // Create a new WebFrameView for the new FrameView
- WebFrameView* newFrameView = new WebFrameView(m_frame->view(), webViewCore);
-
-#if ENABLE(ANDROID_OVERFLOW_SCROLL)
-#else
- webViewCore->clearContent();
-#endif
-
- newFrameView->setLocation(bounds.x(), bounds.y());
- newFrameView->setSize(bounds.width(), bounds.height());
- newFrameView->setVisibleSize(visBounds.width(), visBounds.height());
- newFrameView->setWindowBounds(windowBounds.x(), windowBounds.y(), windowBounds.width(), windowBounds.height());
- // newFrameView attaches itself to FrameView which Retains the reference, so
- // call Release for newFrameView
- Release(newFrameView);
+ if (oldWebFrameView) {
+ IntRect visBounds = oldWebFrameView->getVisibleBounds();
+ IntRect windowBounds = oldWebFrameView->getWindowBounds();
+ // Create a new WebFrameView for the new FrameView
+ WebFrameView* newFrameView = new WebFrameView(m_frame->view(), webViewCore);
+ newFrameView->setLocation(bounds.x(), bounds.y());
+ newFrameView->setSize(bounds.width(), bounds.height());
+ newFrameView->setVisibleSize(visBounds.width(), visBounds.height());
+ newFrameView->setWindowBounds(windowBounds.x(), windowBounds.y(), windowBounds.width(), windowBounds.height());
+ // newFrameView attaches itself to FrameView which Retains the reference, so
+ // call Release for newFrameView
+ Release(newFrameView);
+ }
// WebFrameView Retains webViewCore, so call Release for webViewCore
Release(webViewCore);
@@ -1008,15 +1007,11 @@ WTF::PassRefPtr<WebCore::Frame> FrameLoaderClientAndroid::createFrame(const KURL
newFrame->tree()->setName(name);
// Create a new FrameView and WebFrameView for the child frame to draw into.
RefPtr<FrameView> frameView = FrameView::create(newFrame);
- WebFrameView* webFrameView = new WebFrameView(frameView.get(),
- WebViewCore::getWebViewCore(parent->view()));
- // frameView Retains webFrameView, so call Release for webFrameView
- Release(webFrameView);
// Attach the frameView to the newFrame.
newFrame->setView(frameView);
newFrame->init();
newFrame->selection()->setFocused(true);
- LOGV("::WebCore:: createSubFrame returning %p", newFrame);
+ ALOGV("::WebCore:: createSubFrame returning %p", newFrame);
// The creation of the frame may have run arbitrary JavaScript that removed it from the page already.
if (!pFrame->page())
@@ -1331,8 +1326,8 @@ void FrameLoaderClientAndroid::dispatchDidClearWindowObjectInWorld(DOMWrapperWor
return;
ASSERT(m_frame);
- LOGV("::WebCore:: windowObjectCleared called on frame %p for %s\n",
- m_frame, m_frame->loader()->url().string().ascii().data());
+ ALOGV("::WebCore:: windowObjectCleared called on frame %p for %s\n",
+ m_frame, m_frame->document()->url().string().ascii().data());
m_webFrame->windowObjectCleared(m_frame);
}
diff --git a/Source/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.h b/Source/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.h
index 2464c58..6eb4745 100644
--- a/Source/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.h
+++ b/Source/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.h
@@ -26,7 +26,6 @@
#ifndef FrameLoaderClientAndroid_h
#define FrameLoaderClientAndroid_h
-#include "CacheBuilder.h"
#include "FrameLoaderClient.h"
#include "ResourceResponse.h"
#include "WebIconDatabase.h"
@@ -200,14 +199,12 @@ namespace android {
virtual void documentElementAvailable();
virtual void didPerformFirstNavigation() const;
-#if USE(V8)
- // TODO(benm): Implement
+ // TODO: Implement
virtual void didCreateScriptContextForFrame() { }
virtual void didDestroyScriptContextForFrame() { }
virtual void didCreateIsolatedScriptContext() { }
- virtual bool allowScriptExtension(const String& extensionName, int extensionGroup) { return false; }
-#endif
+ virtual bool allowScriptExtension(const String& extensionName, int extensionGroup) { return false; }
virtual void registerForIconNotification(bool listen = true);
@@ -218,9 +215,6 @@ namespace android {
// WebIconDatabaseClient api
virtual void didAddIconForPageUrl(const String& pageUrl);
- // FIXME: this doesn't really go here, but it's better than Frame
- CacheBuilder& getCacheBuilder() { return m_cacheBuilder; }
-
void enableOnDemandPlugins() { m_onDemandPluginsEnabled = true; }
void dispatchDidChangeIcons();
@@ -229,7 +223,6 @@ namespace android {
virtual void didSaveToPageCache() { }
virtual void didRestoreFromPageCache() { }
private:
- CacheBuilder m_cacheBuilder;
Frame* m_frame;
WebFrame* m_webFrame;
PluginManualLoader* m_manualLoader;
@@ -265,7 +258,6 @@ namespace android {
ErrorFileNotFound = -14,
ErrorTooManyRequests = -15
};
- friend class CacheBuilder;
};
}
diff --git a/Source/WebKit/android/WebCoreSupport/MediaPlayerPrivateAndroid.cpp b/Source/WebKit/android/WebCoreSupport/MediaPlayerPrivateAndroid.cpp
index 339e91b..1607b0e 100644
--- a/Source/WebKit/android/WebCoreSupport/MediaPlayerPrivateAndroid.cpp
+++ b/Source/WebKit/android/WebCoreSupport/MediaPlayerPrivateAndroid.cpp
@@ -29,10 +29,6 @@
#if ENABLE(VIDEO)
#include "BaseLayerAndroid.h"
-#include "DocumentLoader.h"
-#include "Frame.h"
-#include "FrameLoader.h"
-#include "FrameView.h"
#include "GraphicsContext.h"
#include "SkiaUtils.h"
#include "TilesManager.h"
@@ -168,6 +164,19 @@ void MediaPlayerPrivate::onEnded()
m_networkState = MediaPlayer::Idle;
}
+void MediaPlayerPrivate::onRequestPlay()
+{
+ play();
+}
+
+void MediaPlayerPrivate::onRestoreState()
+{
+ if (!m_paused) {
+ //Kick off a JNI call to start the video.
+ play();
+ }
+}
+
void MediaPlayerPrivate::onPaused()
{
m_paused = true;
@@ -211,11 +220,6 @@ public:
if (!env || !m_url.length() || !m_glue->m_javaProxy)
return;
- // We only play video fullscreen on Android, so stop sites playing fullscreen video in the onload handler.
- Frame* frame = m_player->frameView()->frame();
- if (frame && !frame->loader()->documentLoader()->wasOnloadHandled())
- return;
-
m_paused = false;
m_player->playbackStateChanged();
@@ -256,7 +260,9 @@ public:
if (!m_poster || (!m_poster->getPixels() && !m_poster->pixelRef()))
return;
- SkCanvas* canvas = ctxt->platformContext()->mCanvas;
+ SkCanvas* canvas = ctxt->platformContext()->getCanvas();
+ if (!canvas)
+ return;
// We paint with the following rules in mind:
// - only downscale the poster, never upscale
// - maintain the natural aspect ratio of the poster
@@ -293,7 +299,8 @@ public:
m_player->durationChanged();
m_player->sizeChanged();
TilesManager::instance()->videoLayerManager()->updateVideoLayerSize(
- m_player->platformLayer()->uniqueId(), width*height);
+ m_player->platformLayer()->uniqueId(), width * height,
+ width / (float)height);
}
virtual bool hasAudio() const { return false; } // do not display the audio UI
@@ -534,6 +541,14 @@ static void OnEnded(JNIEnv* env, jobject obj, int pointer)
}
}
+static void OnRequestPlay(JNIEnv* env, jobject obj, int pointer)
+{
+ if (pointer) {
+ WebCore::MediaPlayerPrivate* player = reinterpret_cast<WebCore::MediaPlayerPrivate*>(pointer);
+ player->onRequestPlay();
+ }
+}
+
static void OnPaused(JNIEnv* env, jobject obj, int pointer)
{
if (pointer) {
@@ -570,6 +585,15 @@ static void OnTimeupdate(JNIEnv* env, jobject obj, int position, int pointer)
}
}
+static void OnRestoreState(JNIEnv* env, jobject obj, int pointer)
+{
+ if (pointer) {
+ WebCore::MediaPlayerPrivate* player = reinterpret_cast<WebCore::MediaPlayerPrivate*>(pointer);
+ player->onRestoreState();
+ }
+}
+
+
// This is called on the UI thread only.
// The video layers are composited on the webkit thread and then copied over
// to the UI thread with the same ID. For rendering, we are only using the
@@ -593,14 +617,9 @@ static bool SendSurfaceTexture(JNIEnv* env, jobject obj, jobject surfTex,
BaseLayerAndroid* layerImpl = reinterpret_cast<BaseLayerAndroid*>(baseLayer);
if (!layerImpl)
return false;
- if (!layerImpl->countChildren())
- return false;
- LayerAndroid* compositedRoot = static_cast<LayerAndroid*>(layerImpl->getChild(0));
- if (!compositedRoot)
- return false;
VideoLayerAndroid* videoLayer =
- static_cast<VideoLayerAndroid*>(compositedRoot->findById(videoLayerId));
+ static_cast<VideoLayerAndroid*>(layerImpl->findById(videoLayerId));
if (!videoLayer)
return false;
@@ -632,6 +651,8 @@ static JNINativeMethod g_MediaPlayerMethods[] = {
(void*) OnPaused },
{ "nativeOnPosterFetched", "(Landroid/graphics/Bitmap;I)V",
(void*) OnPosterFetched },
+ { "nativeOnRestoreState", "(I)V",
+ (void*) OnRestoreState },
{ "nativeSendSurfaceTexture", "(Landroid/graphics/SurfaceTexture;IIII)Z",
(void*) SendSurfaceTexture },
{ "nativeOnTimeupdate", "(II)V",
@@ -645,6 +666,8 @@ static JNINativeMethod g_MediaAudioPlayerMethods[] = {
(void*) OnEnded },
{ "nativeOnPrepared", "(IIII)V",
(void*) OnPrepared },
+ { "nativeOnRequestPlay", "(I)V",
+ (void*) OnRequestPlay },
{ "nativeOnTimeupdate", "(II)V",
(void*) OnTimeupdate },
};
diff --git a/Source/WebKit/android/WebCoreSupport/MemoryUsage.cpp b/Source/WebKit/android/WebCoreSupport/MemoryUsage.cpp
index 32cdebf..592fad3 100644
--- a/Source/WebKit/android/WebCoreSupport/MemoryUsage.cpp
+++ b/Source/WebKit/android/WebCoreSupport/MemoryUsage.cpp
@@ -29,9 +29,7 @@
#include <malloc.h>
#include <wtf/CurrentTime.h>
-#if USE(V8)
#include <v8.h>
-#endif // USE(V8)
using namespace WTF;
@@ -59,12 +57,10 @@ int MemoryUsageCache::getCachedMemoryUsage(bool forceFresh)
struct mallinfo minfo = mallinfo();
m_cachedMemoryUsage = (minfo.hblkhd + minfo.arena) >> 20;
-#if USE(V8)
v8::HeapStatistics stat;
v8::V8::GetHeapStatistics(&stat);
unsigned v8Usage = stat.total_heap_size() >> 20;
m_cachedMemoryUsage += v8Usage;
-#endif // USE(V8)
m_cacheTime = currentTimeMS();
return m_cachedMemoryUsage;
diff --git a/Source/WebKit/android/WebCoreSupport/PlatformBridge.cpp b/Source/WebKit/android/WebCoreSupport/PlatformBridge.cpp
index 27fe208..9b8aac8 100644
--- a/Source/WebKit/android/WebCoreSupport/PlatformBridge.cpp
+++ b/Source/WebKit/android/WebCoreSupport/PlatformBridge.cpp
@@ -35,18 +35,22 @@
#include "KeyGeneratorClient.h"
#include "MemoryUsage.h"
#include "PluginView.h"
+#include "RenderLayer.h"
+#include "RenderView.h"
#include "Settings.h"
#include "WebCookieJar.h"
#include "WebRequestContext.h"
#include "WebViewCore.h"
#include "npruntime.h"
-#include <surfaceflinger/SurfaceComposerClient.h>
+#include <gui/SurfaceComposerClient.h>
#include <ui/DisplayInfo.h>
#include <ui/PixelFormat.h>
#include <wtf/android/AndroidThreading.h>
#include <wtf/MainThread.h>
+#include <algorithm>
+
using namespace android;
namespace WebCore {
@@ -71,62 +75,40 @@ String PlatformBridge::getSignedPublicKeyAndChallengeString(unsigned index, cons
void PlatformBridge::setCookies(const Document* document, const KURL& url, const String& value)
{
-#if USE(CHROME_NETWORK_STACK)
std::string cookieValue(value.utf8().data());
GURL cookieGurl(url.string().utf8().data());
bool isPrivateBrowsing = document->settings() && document->settings()->privateBrowsingEnabled();
- WebCookieJar::get(isPrivateBrowsing)->cookieStore()->SetCookie(cookieGurl, cookieValue);
-#else
- CookieClient* client = JavaSharedClient::GetCookieClient();
- if (!client)
- return;
-
- client->setCookies(url, value);
-#endif
+ WebCookieJar* cookieJar = WebCookieJar::get(isPrivateBrowsing);
+ if (cookieJar->allowCookies())
+ cookieJar->cookieStore()->SetCookie(cookieGurl, cookieValue);
}
String PlatformBridge::cookies(const Document* document, const KURL& url)
{
-#if USE(CHROME_NETWORK_STACK)
GURL cookieGurl(url.string().utf8().data());
bool isPrivateBrowsing = document->settings() && document->settings()->privateBrowsingEnabled();
- std::string cookies = WebCookieJar::get(isPrivateBrowsing)->cookieStore()->GetCookies(cookieGurl);
- String cookieString(cookies.c_str());
+ WebCookieJar* cookieJar = WebCookieJar::get(isPrivateBrowsing);
+ String cookieString;
+ if (cookieJar->allowCookies()) {
+ std::string cookies = cookieJar->cookieStore()->GetCookies(cookieGurl);
+ cookieString = cookies.c_str();
+ }
return cookieString;
-#else
- CookieClient* client = JavaSharedClient::GetCookieClient();
- if (!client)
- return String();
-
- return client->cookies(url);
-#endif
}
bool PlatformBridge::cookiesEnabled(const Document* document)
{
-#if USE(CHROME_NETWORK_STACK)
bool isPrivateBrowsing = document->settings() && document->settings()->privateBrowsingEnabled();
return WebCookieJar::get(isPrivateBrowsing)->allowCookies();
-#else
- CookieClient* client = JavaSharedClient::GetCookieClient();
- if (!client)
- return false;
-
- return client->cookiesEnabled();
-#endif
}
NPObject* PlatformBridge::pluginScriptableObject(Widget* widget)
{
-#if USE(V8)
if (!widget->isPluginView())
return 0;
PluginView* pluginView = static_cast<PluginView*>(widget);
return pluginView->getNPObject();
-#else
- return 0;
-#endif
}
bool PlatformBridge::isWebViewPaused(const WebCore::FrameView* frameView)
@@ -175,15 +157,11 @@ int PlatformBridge::screenHeightInDocCoord(const WebCore::FrameView* frameView)
String PlatformBridge::computeDefaultLanguage()
{
-#if USE(CHROME_NETWORK_STACK)
String acceptLanguages = WebRequestContext::acceptLanguage();
size_t length = acceptLanguages.find(',');
if (length == std::string::npos)
length = acceptLanguages.length();
return acceptLanguages.substring(0, length);
-#else
- return "en";
-#endif
}
void PlatformBridge::updateViewport(FrameView* frameView)
@@ -199,10 +177,15 @@ void PlatformBridge::updateTextfield(FrameView* frameView, Node* nodePtr, bool c
}
void PlatformBridge::setScrollPosition(ScrollView* scrollView, int x, int y) {
+ FrameView* frameView = scrollView->frameView();
+ if (!frameView) return;
// Check to make sure the view is the main FrameView.
android::WebViewCore *webViewCore = android::WebViewCore::getWebViewCore(scrollView);
- if (webViewCore->mainFrame()->view() == scrollView)
+ if (webViewCore->mainFrame()->view() == scrollView) {
+ x = std::max(0, std::min(frameView->contentsWidth(), x));
+ y = std::max(0, std::min(frameView->contentsHeight(), y));
webViewCore->scrollTo(x, y);
+ }
}
int PlatformBridge::lowMemoryUsageMB()
diff --git a/Source/WebKit/android/WebCoreSupport/ResourceLoaderAndroid.cpp b/Source/WebKit/android/WebCoreSupport/ResourceLoaderAndroid.cpp
index 7f54810..92c39b8 100644
--- a/Source/WebKit/android/WebCoreSupport/ResourceLoaderAndroid.cpp
+++ b/Source/WebKit/android/WebCoreSupport/ResourceLoaderAndroid.cpp
@@ -29,7 +29,6 @@
#include "Frame.h"
#include "FrameLoaderClientAndroid.h"
#include "WebCoreFrameBridge.h"
-#include "WebCoreResourceLoader.h"
#include "WebUrlLoader.h"
#include "WebViewCore.h"
@@ -42,18 +41,13 @@ PassRefPtr<ResourceLoaderAndroid> ResourceLoaderAndroid::start(
{
// Called on main thread
FrameLoaderClientAndroid* clientAndroid = static_cast<FrameLoaderClientAndroid*>(client);
-#if USE(CHROME_NETWORK_STACK)
WebViewCore* webViewCore = WebViewCore::getWebViewCore(clientAndroid->getFrame()->view());
bool isMainFrame = !(clientAndroid->getFrame()->tree() && clientAndroid->getFrame()->tree()->parent());
return WebUrlLoader::start(client, handle, request, isMainResource, isMainFrame, isSync, webViewCore->webRequestContext());
-#else
- return clientAndroid->webFrame()->startLoadingResource(handle, request, isMainResource, isSync);
-#endif
}
bool ResourceLoaderAndroid::willLoadFromCache(const WebCore::KURL& url, int64_t identifier)
{
-#if USE(CHROME_NETWORK_STACK)
// This method is used to determine if a POST request can be repeated from
// cache, but you cannot really know until you actually try to read from the
// cache. Even if we checked now, something else could come along and wipe
@@ -63,9 +57,6 @@ bool ResourceLoaderAndroid::willLoadFromCache(const WebCore::KURL& url, int64_t
// reload. Then in FrameLoaderClientImpl::dispatchWillSendRequest, we
// fix-up the cache policy of the request to force a load from the cache.
return true;
-#else
- return WebCoreResourceLoader::willLoadFromCache(url, identifier);
-#endif
}
}
diff --git a/Source/WebKit/android/WebCoreSupport/UrlInterceptResponse.cpp b/Source/WebKit/android/WebCoreSupport/UrlInterceptResponse.cpp
index 77e3c32..d846daf 100644
--- a/Source/WebKit/android/WebCoreSupport/UrlInterceptResponse.cpp
+++ b/Source/WebKit/android/WebCoreSupport/UrlInterceptResponse.cpp
@@ -30,6 +30,7 @@
#include "UrlInterceptResponse.h"
#include "WebCoreJni.h"
+#include <ScopedLocalRef.h>
#include <utils/Log.h>
namespace android {
@@ -38,15 +39,14 @@ class JavaInputStreamWrapper {
public:
JavaInputStreamWrapper(JNIEnv* env, jobject inputStream)
: m_inputStream(env->NewGlobalRef(inputStream))
- , m_buffer(0) {
- LOG_ALWAYS_FATAL_IF(!inputStream);
- jclass inputStreamClass = env->FindClass("java/io/InputStream");
- LOG_ALWAYS_FATAL_IF(!inputStreamClass);
- m_read = env->GetMethodID(inputStreamClass, "read", "([B)I");
+ , m_buffer(NULL) {
+ LOG_ALWAYS_FATAL_IF(!m_inputStream);
+ ScopedLocalRef<jclass> inputStreamClass(env, env->FindClass("java/io/InputStream"));
+ LOG_ALWAYS_FATAL_IF(!inputStreamClass.get());
+ m_read = env->GetMethodID(inputStreamClass.get(), "read", "([B)I");
LOG_ALWAYS_FATAL_IF(!m_read);
- m_close = env->GetMethodID(inputStreamClass, "close", "()V");
+ m_close = env->GetMethodID(inputStreamClass.get(), "close", "()V");
LOG_ALWAYS_FATAL_IF(!m_close);
- env->DeleteLocalRef(inputStreamClass);
}
~JavaInputStreamWrapper() {
@@ -63,10 +63,10 @@ public:
JNIEnv* env = JSC::Bindings::getJNIEnv();
// Initialize our read buffer to the capacity of out.
if (!m_buffer) {
- m_buffer = env->NewByteArray(out->capacity());
- m_buffer = (jbyteArray) env->NewGlobalRef(m_buffer);
+ ScopedLocalRef<jbyteArray> buffer_local(env, env->NewByteArray(out->capacity()));
+ m_buffer = static_cast<jbyteArray>(env->NewGlobalRef(buffer_local.get()));
}
- int size = (int) env->CallIntMethod(m_inputStream, m_read, m_buffer);
+ int size = env->CallIntMethod(m_inputStream, m_read, m_buffer);
if (checkException(env) || size < 0)
return;
// Copy from m_buffer to out.
@@ -82,40 +82,32 @@ private:
};
UrlInterceptResponse::UrlInterceptResponse(JNIEnv* env, jobject response) {
- jclass javaResponse = env->FindClass("android/webkit/WebResourceResponse");
- LOG_ALWAYS_FATAL_IF(!javaResponse);
- jfieldID mimeType = env->GetFieldID(javaResponse, "mMimeType",
- "Ljava/lang/String;");
+ ScopedLocalRef<jclass> javaResponse(env, env->FindClass("android/webkit/WebResourceResponse"));
+ LOG_ALWAYS_FATAL_IF(!javaResponse.get());
+ jfieldID mimeType = env->GetFieldID(javaResponse.get(), "mMimeType", "Ljava/lang/String;");
LOG_ALWAYS_FATAL_IF(!mimeType);
- jfieldID encoding = env->GetFieldID(javaResponse, "mEncoding",
- "Ljava/lang/String;");
+ jfieldID encoding = env->GetFieldID(javaResponse.get(), "mEncoding", "Ljava/lang/String;");
LOG_ALWAYS_FATAL_IF(!encoding);
- jfieldID inputStream = env->GetFieldID(javaResponse, "mInputStream",
- "Ljava/io/InputStream;");
+ jfieldID inputStream = env->GetFieldID(javaResponse.get(), "mInputStream", "Ljava/io/InputStream;");
LOG_ALWAYS_FATAL_IF(!inputStream);
- jobject stream = env->GetObjectField(response, inputStream);
- if (stream)
- m_inputStream.set(new JavaInputStreamWrapper(env, stream));
+ ScopedLocalRef<jobject> stream(env, env->GetObjectField(response, inputStream));
+ if (stream.get())
+ m_inputStream.set(new JavaInputStreamWrapper(env, stream.get()));
- jstring mimeStr = (jstring) env->GetObjectField(response, mimeType);
- jstring encodingStr = (jstring) env->GetObjectField(response, encoding);
+ ScopedLocalRef<jstring> mimeStr(env, static_cast<jstring>(env->GetObjectField(response, mimeType)));
+ ScopedLocalRef<jstring> encodingStr(env, static_cast<jstring>(env->GetObjectField(response, encoding)));
- if (mimeStr) {
- const char* s = env->GetStringUTFChars(mimeStr, NULL);
- m_mimeType.assign(s, env->GetStringUTFLength(mimeStr));
- env->ReleaseStringUTFChars(mimeStr, s);
+ if (mimeStr.get()) {
+ const char* s = env->GetStringUTFChars(mimeStr.get(), NULL);
+ m_mimeType.assign(s, env->GetStringUTFLength(mimeStr.get()));
+ env->ReleaseStringUTFChars(mimeStr.get(), s);
}
- if (encodingStr) {
- const char* s = env->GetStringUTFChars(encodingStr, NULL);
- m_encoding.assign(s, env->GetStringUTFLength(encodingStr));
- env->ReleaseStringUTFChars(encodingStr, s);
+ if (encodingStr.get()) {
+ const char* s = env->GetStringUTFChars(encodingStr.get(), NULL);
+ m_encoding.assign(s, env->GetStringUTFLength(encodingStr.get()));
+ env->ReleaseStringUTFChars(encodingStr.get(), s);
}
-
- env->DeleteLocalRef(javaResponse);
- env->DeleteLocalRef(stream);
- env->DeleteLocalRef(mimeStr);
- env->DeleteLocalRef(encodingStr);
}
UrlInterceptResponse::~UrlInterceptResponse() {
diff --git a/Source/WebKit/android/WebCoreSupport/V8Counters.cpp b/Source/WebKit/android/WebCoreSupport/V8Counters.cpp
deleted file mode 100644
index d164f9a..0000000
--- a/Source/WebKit/android/WebCoreSupport/V8Counters.cpp
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright 2010, 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.
- */
-
-
-#ifdef ANDROID_INSTRUMENT
-
-#define LOG_TAG "WebCore"
-
-#include "config.h"
-#include "V8Counters.h"
-
-#include "NotImplemented.h"
-#include <utils/Log.h>
-#include <wtf/text/CString.h>
-#include <wtf/text/StringHash.h>
-
-#if USE(V8)
-
-namespace WebCore {
-
-V8Counters::Counter::Counter(bool isHistogram)
- : m_count(0), m_sampleTotal(0), m_isHistogram(isHistogram) { }
-
-void V8Counters::Counter::addSample(int sample)
-{
- m_count++;
- m_sampleTotal += sample;
-}
-
-HashMap<String, V8Counters::Counter*> V8Counters::m_counters;
-
-// static
-int* V8Counters::counterForName(const char* name)
-{
- Counter* counter = m_counters.get(name);
- if (!counter) {
- counter = new Counter(false);
- m_counters.add(name, counter);
- }
- return *counter;
-}
-
-// static
-void* V8Counters::createHistogram(const char* name, int min, int max,
- size_t buckets)
-{
- Counter* counter = new Counter(true);
- m_counters.add(name, counter);
- return counter;
-}
-
-// static
-void V8Counters::addHistogramSample(void* histogram, int sample)
-{
- Counter* counter = reinterpret_cast<Counter*>(histogram);
- counter->addSample(sample);
-}
-
-// static
-void V8Counters::initCounters()
-{
- static bool isInitialized = false;
- if (!isInitialized) {
- v8::V8::SetCounterFunction(counterForName);
- v8::V8::SetCreateHistogramFunction(createHistogram);
- v8::V8::SetAddHistogramSampleFunction(addHistogramSample);
- isInitialized = true;
- }
-}
-
-// static
-void V8Counters::dumpCounters()
-{
- LOGD("+----------------------------------------+-------------+\n");
- LOGD("| Name | Value |\n");
- LOGD("+----------------------------------------+-------------+\n");
- typedef HashMap<String, V8Counters::Counter*>::iterator CounterIterator;
- for (CounterIterator iter = m_counters.begin(); iter != m_counters.end(); ++iter) {
- Counter* counter = iter->second;
- if (counter->isHistogram()) {
- LOGD("| c:%-36s | %11i |\n", iter->first.latin1().data(), counter->count());
- LOGD("| t:%-36s | %11i |\n", iter->first.latin1().data(), counter->sampleTotal());
- } else {
- LOGD("| %-38s | %11i |\n", iter->first.latin1().data(), counter->count());
- }
- }
- LOGD("+----------------------------------------+-------------+\n");
-}
-
-}
-
-#endif // ANDROID_INSTRUMENT
-
-#endif // USE(V8)
diff --git a/Source/WebKit/android/WebCoreSupport/V8Counters.h b/Source/WebKit/android/WebCoreSupport/V8Counters.h
deleted file mode 100644
index 499b856..0000000
--- a/Source/WebKit/android/WebCoreSupport/V8Counters.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright 2010, 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 V8Counters_h
-#define V8Counters_h
-
-#if USE(V8)
-
-#ifdef ANDROID_INSTRUMENT
-
-#include <PlatformString.h>
-#include <v8.h>
-#include <wtf/HashMap.h>
-
-namespace WebCore {
-
-class V8Counters {
-public:
- // Counter callbacks, see v8.h
- static int* counterForName(const char* name);
-
- static void* createHistogram(const char* name,
- int min,
- int max,
- size_t buckets);
-
- static void addHistogramSample(void* histogram, int sample);
-
- static void initCounters();
- static void dumpCounters();
-private:
- class Counter {
- public:
- Counter(bool isHistogram);
-
- int count() { return m_count; }
- int sampleTotal() { return m_sampleTotal; }
- bool isHistogram() { return m_isHistogram; }
- void addSample(int32_t sample);
-
- operator int*() { return &m_count; }
- private:
- int m_count;
- int m_sampleTotal;
- bool m_isHistogram;
- };
-
- static HashMap<String, Counter*> m_counters;
-};
-
-}
-
-#endif // ANDROID_INSTRUMENT
-#endif // USE(V8)
-#endif // V8Counters_h
diff --git a/Source/WebKit/android/WebCoreSupport/WebCache.cpp b/Source/WebKit/android/WebCoreSupport/WebCache.cpp
index 9b505ee..82e3b27 100644
--- a/Source/WebKit/android/WebCoreSupport/WebCache.cpp
+++ b/Source/WebKit/android/WebCoreSupport/WebCache.cpp
@@ -30,7 +30,7 @@
#include "WebCoreJni.h"
#include "WebRequestContext.h"
#include "WebUrlLoaderClient.h"
-
+#include "net/http/http_network_session.h"
#include <wtf/text/CString.h>
using namespace WTF;
@@ -131,6 +131,21 @@ void WebCache::clear()
thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this, &WebCache::clearImpl));
}
+void WebCache::certTrustChanged()
+{
+ base::Thread* thread = WebUrlLoaderClient::ioThread();
+ if (thread)
+ thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this, &WebCache::certTrustChangedImpl));
+}
+
+void WebCache::certTrustChangedImpl()
+{
+ net::HttpNetworkSession* session = m_cache->GetSession();
+ if (session)
+ session->cert_verifier()->ClearCache();
+ m_cache->CloseAllConnections();
+}
+
void WebCache::closeIdleConnections()
{
base::Thread* thread = WebUrlLoaderClient::ioThread();
diff --git a/Source/WebKit/android/WebCoreSupport/WebCache.h b/Source/WebKit/android/WebCoreSupport/WebCache.h
index c3b623d..ad57d88 100644
--- a/Source/WebKit/android/WebCoreSupport/WebCache.h
+++ b/Source/WebKit/android/WebCoreSupport/WebCache.h
@@ -48,7 +48,7 @@ public:
net::HttpCache* cache() { return m_cache.get(); }
net::ProxyConfigServiceAndroid* proxy() { return m_proxyConfigService; }
void closeIdleConnections();
-
+ void certTrustChanged();
private:
WebCache(bool isPrivateBrowsing);
@@ -60,6 +60,7 @@ private:
// For closeIdleConnections
void closeIdleImpl();
+ void certTrustChangedImpl();
// For getEntry()
void getEntryImpl();
diff --git a/Source/WebKit/android/WebCoreSupport/WebCookieJar.cpp b/Source/WebKit/android/WebCoreSupport/WebCookieJar.cpp
index 1dc4637..0af3cc2 100644
--- a/Source/WebKit/android/WebCoreSupport/WebCookieJar.cpp
+++ b/Source/WebKit/android/WebCoreSupport/WebCookieJar.cpp
@@ -98,7 +98,7 @@ static std::string databaseDirectory(bool isPrivateBrowsing)
return databaseFilePath;
}
-scoped_refptr<WebCookieJar>* instance(bool isPrivateBrowsing)
+static scoped_refptr<WebCookieJar>* instance(bool isPrivateBrowsing)
{
static scoped_refptr<WebCookieJar> regularInstance;
static scoped_refptr<WebCookieJar> privateInstance;
@@ -127,10 +127,16 @@ void WebCookieJar::cleanup(bool isPrivateBrowsing)
}
WebCookieJar::WebCookieJar(const std::string& databaseFilePath)
- : m_allowCookies(true)
-{
+ : m_cookieStoreInitialized(false)
+ , m_databaseFilePath(databaseFilePath)
+ , m_allowCookies(true) {}
+
+void WebCookieJar::initCookieStore() {
+ MutexLocker lock(m_cookieStoreInitializeMutex);
+ if (m_cookieStoreInitialized)
+ return;
// Setup the permissions for the file
- const char* cDatabasePath = databaseFilePath.c_str();
+ const char* cDatabasePath = m_databaseFilePath.c_str();
mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
if (access(cDatabasePath, F_OK) == 0)
chmod(cDatabasePath, mode);
@@ -140,9 +146,10 @@ WebCookieJar::WebCookieJar(const std::string& databaseFilePath)
close(fd);
}
- FilePath cookiePath(databaseFilePath.c_str());
+ FilePath cookiePath(cDatabasePath);
m_cookieDb = new SQLitePersistentCookieStore(cookiePath);
m_cookieStore = new net::CookieMonster(m_cookieDb.get(), 0);
+ m_cookieStoreInitialized = true;
}
bool WebCookieJar::allowCookies()
@@ -157,13 +164,6 @@ void WebCookieJar::setAllowCookies(bool allow)
m_allowCookies = allow;
}
-int WebCookieJar::getNumCookiesInDatabase()
-{
- if (!m_cookieStore)
- return 0;
- return m_cookieStore->GetCookieMonster()->GetAllCookies().size();
-}
-
// From CookiePolicy in chromium
int WebCookieJar::CanGetCookies(const GURL&, const GURL&) const
{
@@ -178,6 +178,17 @@ int WebCookieJar::CanSetCookie(const GURL&, const GURL&, const std::string&) con
return m_allowCookies ? net::OK : net::ERR_ACCESS_DENIED;
}
+net::CookieStore* WebCookieJar::cookieStore()
+{
+ initCookieStore();
+ return m_cookieStore.get();
+}
+
+int WebCookieJar::getNumCookiesInDatabase()
+{
+ return cookieStore()->GetCookieMonster()->GetAllCookies().size();
+}
+
class FlushSemaphore : public base::RefCounted<FlushSemaphore>
{
public:
diff --git a/Source/WebKit/android/WebCoreSupport/WebCookieJar.h b/Source/WebKit/android/WebCoreSupport/WebCookieJar.h
index b6490af..7ade9d0 100644
--- a/Source/WebKit/android/WebCoreSupport/WebCookieJar.h
+++ b/Source/WebKit/android/WebCoreSupport/WebCookieJar.h
@@ -55,9 +55,10 @@ public:
static bool acceptFileSchemeCookies();
static void setAcceptFileSchemeCookies(bool);
+ // TODO
// Instead of this it would probably be better to add the cookie methods
// here so the rest of WebKit doesn't have to know about Chromium classes
- net::CookieStore* cookieStore() { return m_cookieStore.get(); }
+ net::CookieStore* cookieStore();
net::CookiePolicy* cookiePolicy() { return this; }
// Get the number of cookies that have actually been saved to flash.
@@ -66,7 +67,13 @@ public:
private:
WebCookieJar(const std::string& databaseFilePath);
+ void initCookieStore();
+private:
+ bool m_cookieStoreInitialized;
+ WTF::Mutex m_cookieStoreInitializeMutex;
+
+ const std::string m_databaseFilePath;
scoped_refptr<SQLitePersistentCookieStore> m_cookieDb;
scoped_refptr<net::CookieStore> m_cookieStore;
bool m_allowCookies;
diff --git a/Source/WebKit/android/WebCoreSupport/WebRequest.cpp b/Source/WebKit/android/WebCoreSupport/WebRequest.cpp
index 90b0939..9d16378 100644
--- a/Source/WebKit/android/WebCoreSupport/WebRequest.cpp
+++ b/Source/WebKit/android/WebCoreSupport/WebRequest.cpp
@@ -30,6 +30,7 @@
#include "MainThread.h"
#include "UrlInterceptResponse.h"
#include "WebCoreFrameBridge.h"
+#include "WebCoreJni.h"
#include "WebRequestContext.h"
#include "WebResourceRequest.h"
#include "WebUrlLoaderClient.h"
@@ -38,7 +39,7 @@
#include <cutils/log.h>
#include <openssl/x509.h>
#include <string>
-#include <utils/AssetManager.h>
+#include <androidfw/AssetManager.h>
extern android::AssetManager* globalAssetManager();
@@ -58,12 +59,28 @@ while (0)
namespace android {
namespace {
- const int kInitialReadBufSize = 32768;
+const int kInitialReadBufSize = 32768;
+const char* kXRequestedWithHeader = "X-Requested-With";
+
+struct RequestPackageName {
+ std::string value;
+ RequestPackageName();
+};
+
+RequestPackageName::RequestPackageName() {
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ jclass bridgeClass = env->FindClass("android/webkit/JniUtil");
+ jmethodID method = env->GetStaticMethodID(bridgeClass, "getPackageName", "()Ljava/lang/String;");
+ value = jstringToStdString(env, static_cast<jstring>(env->CallStaticObjectMethod(bridgeClass, method)));
+ env->DeleteLocalRef(bridgeClass);
+}
+
+base::LazyInstance<RequestPackageName> s_packageName(base::LINKER_INITIALIZED);
+
}
WebRequest::WebRequest(WebUrlLoaderClient* loader, const WebResourceRequest& webResourceRequest)
: m_urlLoader(loader)
- , m_androidUrl(false)
, m_url(webResourceRequest.url())
, m_userAgent(webResourceRequest.userAgent())
, m_loadState(Created)
@@ -79,6 +96,7 @@ WebRequest::WebRequest(WebUrlLoaderClient* loader, const WebResourceRequest& web
m_request = new net::URLRequest(gurl, this);
m_request->SetExtraRequestHeaders(webResourceRequest.requestHeaders());
+ m_request->SetExtraRequestHeaderByName(kXRequestedWithHeader, s_packageName.Get().value, false);
m_request->set_referrer(webResourceRequest.referrer());
m_request->set_method(webResourceRequest.method());
m_request->set_load_flags(webResourceRequest.loadFlags());
@@ -89,7 +107,6 @@ WebRequest::WebRequest(WebUrlLoaderClient* loader, const WebResourceRequest& web
WebRequest::WebRequest(WebUrlLoaderClient* loader, const WebResourceRequest& webResourceRequest, UrlInterceptResponse* intercept)
: m_urlLoader(loader)
, m_interceptResponse(intercept)
- , m_androidUrl(true)
, m_url(webResourceRequest.url())
, m_userAgent(webResourceRequest.userAgent())
, m_loadState(Created)
@@ -274,15 +291,9 @@ void WebRequest::handleInterceptedURL()
// Get the MIME type from the URL. "text/html" is a last resort, hopefully overridden.
std::string mimeType("text/html");
if (mime == "") {
- // Gmail appends the MIME to the end of the URL, with a ? separator.
- size_t mimeTypeIndex = m_url.find_last_of('?');
- if (mimeTypeIndex != std::string::npos) {
- mimeType.assign(m_url.begin() + mimeTypeIndex + 1, m_url.end());
- } else {
- // Get the MIME type from the file extension, if any.
- FilePath path(m_url);
- net::GetMimeTypeFromFile(path, &mimeType);
- }
+ // Get the MIME type from the file extension, if any.
+ FilePath path(m_url);
+ net::GetMimeTypeFromFile(path, &mimeType);
} else {
// Set from the intercept response.
mimeType = mime;
diff --git a/Source/WebKit/android/WebCoreSupport/WebRequest.h b/Source/WebKit/android/WebCoreSupport/WebRequest.h
index 285e577..d9054e9 100644
--- a/Source/WebKit/android/WebCoreSupport/WebRequest.h
+++ b/Source/WebKit/android/WebCoreSupport/WebRequest.h
@@ -107,7 +107,6 @@ private:
OwnPtr<net::URLRequest> m_request;
scoped_refptr<net::IOBuffer> m_networkBuffer;
scoped_ptr<UrlInterceptResponse> m_interceptResponse;
- bool m_androidUrl;
std::string m_url;
std::string m_userAgent;
LoadState m_loadState;
diff --git a/Source/WebKit/android/WebCoreSupport/WebUrlLoaderClient.cpp b/Source/WebKit/android/WebCoreSupport/WebUrlLoaderClient.cpp
index 43037ab..5df0ed2 100644
--- a/Source/WebKit/android/WebCoreSupport/WebUrlLoaderClient.cpp
+++ b/Source/WebKit/android/WebCoreSupport/WebUrlLoaderClient.cpp
@@ -37,6 +37,7 @@
#include "WebRequest.h"
#include "WebResourceRequest.h"
+#include <utils/Log.h>
#include <wtf/text/CString.h>
using base::Lock;
@@ -156,11 +157,11 @@ WebUrlLoaderClient::WebUrlLoaderClient(WebFrame* webFrame, WebCore::ResourceHand
break;
#if ENABLE(BLOB)
case FormDataElement::encodedBlob:
- LOG_ASSERT(false, "Unexpected use of FormDataElement::encodedBlob");
+ ALOG_ASSERT(false, "Unexpected use of FormDataElement::encodedBlob");
break;
#endif // ENABLE(BLOB)
default:
- LOG_ASSERT(false, "Unexpected default case in WebUrlLoaderClient.cpp");
+ ALOG_ASSERT(false, "Unexpected default case in WebUrlLoaderClient.cpp");
break;
}
}
@@ -199,7 +200,7 @@ bool WebUrlLoaderClient::start(bool isMainResource, bool isMainFrame, bool sync,
syncCondition()->TimedWait(base::TimeDelta::FromSeconds(kCallbackWaitingTime));
if (m_queue.empty()) {
- LOGE("Synchronous request timed out after %d seconds for the %dth try, URL: %s",
+ ALOGE("Synchronous request timed out after %d seconds for the %dth try, URL: %s",
kCallbackWaitingTime, num_timeout, m_request->getUrl().c_str());
num_timeout++;
if (num_timeout >= kMaxNumTimeout) {
@@ -253,7 +254,7 @@ void WebUrlLoaderClient::downloadFile()
if (!m_isCertMimeType)
cancel();
} else {
- LOGE("Unexpected call to downloadFile() before didReceiveResponse(). URL: %s", m_request->getUrl().c_str());
+ ALOGE("Unexpected call to downloadFile() before didReceiveResponse(). URL: %s", m_request->getUrl().c_str());
// TODO: Turn off asserts crashing before release
// http://b/issue?id=2951985
CRASH();
diff --git a/Source/WebKit/android/WebCoreSupport/WebViewClientError.cpp b/Source/WebKit/android/WebCoreSupport/WebViewClientError.cpp
index 260c76e..1857e9c 100644
--- a/Source/WebKit/android/WebCoreSupport/WebViewClientError.cpp
+++ b/Source/WebKit/android/WebCoreSupport/WebViewClientError.cpp
@@ -79,6 +79,7 @@ WebViewClientError ToWebViewClientError(net::Error error) {
case ERR_CONNECTION_ABORTED:
case ERR_CONNECTION_FAILED:
case ERR_SOCKET_NOT_CONNECTED:
+ case ERR_CACHE_MISS:
return ERROR_CONNECT;
case ERR_ADDRESS_INVALID:
diff --git a/Source/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.cpp b/Source/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.cpp
index e837244..2969252 100644
--- a/Source/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.cpp
+++ b/Source/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.cpp
@@ -562,7 +562,7 @@ void FormManager::ExtractForms(Frame* frame) {
ResetFrame(frame);
- WTF::PassRefPtr<HTMLCollection> web_forms = frame->document()->forms();
+ WTF::RefPtr<HTMLCollection> web_forms = frame->document()->forms();
for (size_t i = 0; i < web_forms->length(); ++i) {
// Owned by |form_elements|.
diff --git a/Source/WebKit/android/benchmark/Android.mk b/Source/WebKit/android/benchmark/Android.mk
deleted file mode 100644
index 5b189e1..0000000
--- a/Source/WebKit/android/benchmark/Android.mk
+++ /dev/null
@@ -1,41 +0,0 @@
-##
-##
-## Copyright 2009, 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 APPLE COMPUTER, INC. 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.
-##
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
- main.cpp
-
-# Pull the webkit definitions from the base webkit makefile.
-LOCAL_SHARED_LIBRARIES := libwebcore $(WEBKIT_SHARED_LIBRARIES)
-LOCAL_LDLIBS := $(WEBKIT_LDLIBS)
-
-LOCAL_MODULE := webcore_test
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_EXECUTABLE)
diff --git a/Source/WebKit/android/benchmark/Intercept.cpp b/Source/WebKit/android/benchmark/Intercept.cpp
deleted file mode 100644
index deffac2..0000000
--- a/Source/WebKit/android/benchmark/Intercept.cpp
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Copyright 2009, 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 APPLE COMPUTER, INC. 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 "webcore_test"
-#include "config.h"
-
-#include "Base64.h"
-#include "HTTPParsers.h"
-#include "Intercept.h"
-#include "ResourceHandle.h"
-#include "ResourceHandleClient.h"
-#include "ResourceRequest.h"
-#include "ResourceResponse.h"
-#include "TextEncoding.h"
-
-#include <utils/Log.h>
-#include <wtf/HashMap.h>
-#include <wtf/text/CString.h>
-#include <wtf/text/StringHash.h>
-
-PassRefPtr<WebCore::ResourceLoaderAndroid> MyResourceLoader::create(
- ResourceHandle* handle, String url)
-{
- return adoptRef<WebCore::ResourceLoaderAndroid>(
- new MyResourceLoader(handle, url));
-}
-
-void MyResourceLoader::handleRequest()
-{
- if (protocolIs(m_url, "data"))
- loadData(m_url.substring(5)); // 5 for data:
- else if (protocolIs(m_url, "file"))
- loadFile(m_url.substring(7)); // 7 for file://
-}
-
-void MyResourceLoader::loadData(const String& data)
-{
- LOGD("Loading data (%s) ...", data.latin1().data());
- ResourceHandleClient* client = m_handle->client();
- int index = data.find(',');
- if (index == -1) {
- client->cannotShowURL(m_handle);
- return;
- }
-
- String mediaType = data.substring(0, index);
- String base64 = data.substring(index + 1);
-
- bool decode = mediaType.endsWith(";base64", false);
- if (decode)
- mediaType = mediaType.left(mediaType.length() - 7); // 7 for base64;
-
- if (mediaType.isEmpty())
- mediaType = "text/plain;charset=US-ASCII";
-
- String mimeType = extractMIMETypeFromMediaType(mediaType);
- String charset = extractCharsetFromMediaType(mediaType);
-
- ResourceResponse response;
- response.setMimeType(mimeType);
-
- if (decode) {
- base64 = decodeURLEscapeSequences(base64);
- response.setTextEncodingName(charset);
- client->didReceiveResponse(m_handle, response);
-
- // FIXME: This is annoying. WebCore's Base64 decoder chokes on spaces.
- // That is correct with strict decoding but html authors (particularly
- // the acid3 authors) put spaces in the data which should be ignored.
- // Remove them here before sending to the decoder.
- Vector<char> in;
- CString str = base64.latin1();
- const char* chars = str.data();
- unsigned i = 0;
- while (i < str.length()) {
- char c = chars[i];
- // Don't send spaces or control characters.
- if (c != ' ' && c != '\n' && c != '\t' && c != '\b'
- && c != '\f' && c != '\r')
- in.append(chars[i]);
- i++;
- }
- Vector<char> out;
- if (base64Decode(in, out) && out.size() > 0)
- client->didReceiveData(m_handle, out.data(), out.size(), 0);
- } else {
- base64 = decodeURLEscapeSequences(base64, TextEncoding(charset));
- response.setTextEncodingName("UTF-16");
- client->didReceiveResponse(m_handle, response);
- if (base64.length() > 0)
- client->didReceiveData(m_handle, (const char*)base64.characters(),
- base64.length() * sizeof(UChar), 0);
- }
- client->didFinishLoading(m_handle, 0);
-}
-static String mimeTypeForExtension(const String& file)
-{
- static HashMap<String, String, CaseFoldingHash> extensionToMime;
- if (extensionToMime.isEmpty()) {
- extensionToMime.set("txt", "text/plain");
- extensionToMime.set("html", "text/html");
- extensionToMime.set("htm", "text/html");
- extensionToMime.set("png", "image/png");
- extensionToMime.set("jpeg", "image/jpeg");
- extensionToMime.set("jpg", "image/jpeg");
- extensionToMime.set("gif", "image/gif");
- extensionToMime.set("ico", "image/x-icon");
- extensionToMime.set("js", "text/javascript");
- }
- int dot = file.reverseFind('.');
- String mime("text/plain");
- if (dot != -1) {
- String ext = file.substring(dot + 1);
- if (extensionToMime.contains(ext))
- mime = extensionToMime.get(ext);
- }
- return mime;
-}
-
-void MyResourceLoader::loadFile(const String& file)
-{
- LOGD("Loading file (%s) ...", file.latin1().data());
- FILE* f = fopen(file.latin1().data(), "r");
- ResourceHandleClient* client = m_handle->client();
- if (!f) {
- client->didFail(m_handle,
- ResourceError("", -14, file, "Could not open file"));
- } else {
- ResourceResponse response;
- response.setTextEncodingName("utf-8");
- response.setMimeType(mimeTypeForExtension(file));
- client->didReceiveResponse(m_handle, response);
- char buf[512];
- while (true) {
- int res = fread(buf, 1, sizeof(buf), f);
- if (res <= 0)
- break;
- client->didReceiveData(m_handle, buf, res, 0);
- }
- fclose(f);
- client->didFinishLoading(m_handle, 0);
- }
-}
-
-PassRefPtr<WebCore::ResourceLoaderAndroid> MyWebFrame::startLoadingResource(
- ResourceHandle* handle, const ResourceRequest& req, bool ignore,
- bool ignore2)
-{
- RefPtr<WebCore::ResourceLoaderAndroid> loader =
- MyResourceLoader::create(handle, req.url().string());
- m_requests.append(loader);
- if (!m_timer.isActive())
- m_timer.startOneShot(0);
- return loader.release();
-}
-
-void MyWebFrame::timerFired(Timer<MyWebFrame>*)
-{
- LOGD("Handling requests...");
- Vector<RefPtr<WebCore::ResourceLoaderAndroid> > reqs;
- reqs.swap(m_requests);
- Vector<RefPtr<WebCore::ResourceLoaderAndroid> >::iterator i = reqs.begin();
- Vector<RefPtr<WebCore::ResourceLoaderAndroid> >::iterator end = reqs.end();
- for (; i != end; i++)
- static_cast<MyResourceLoader*>((*i).get())->handleRequest();
-
- LOGD("...done");
-}
diff --git a/Source/WebKit/android/benchmark/Intercept.h b/Source/WebKit/android/benchmark/Intercept.h
deleted file mode 100644
index 6694dba..0000000
--- a/Source/WebKit/android/benchmark/Intercept.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright 2009, 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 APPLE COMPUTER, INC. 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 Intercept_h
-#define Intercept_h
-
-#include "MyJavaVM.h"
-#include "PlatformString.h"
-#include "Timer.h"
-#include "WebCoreFrameBridge.h"
-#include "WebCoreResourceLoader.h"
-#include <JNIUtility.h>
-#include <wtf/Vector.h>
-
-namespace WebCore {
- class Page;
- class ResourceHandle;
- class ResourceRequest;
-}
-
-using namespace android;
-using namespace WebCore;
-using namespace WTF;
-
-class MyResourceLoader : public WebCoreResourceLoader {
-public:
- static PassRefPtr<WebCore::ResourceLoaderAndroid> create(
- ResourceHandle* handle, String url);
- void handleRequest();
-
-private:
- MyResourceLoader(ResourceHandle* handle, String url)
- : WebCoreResourceLoader(JSC::Bindings::getJNIEnv(), MY_JOBJECT)
- , m_handle(handle)
- , m_url(url) {}
-
- void loadData(const String&);
- void loadFile(const String&);
- ResourceHandle* m_handle;
- String m_url;
-};
-
-class MyWebFrame : public WebFrame {
-public:
- MyWebFrame(Page* page)
- : WebFrame(JSC::Bindings::getJNIEnv(), MY_JOBJECT, MY_JOBJECT, page)
- , m_timer(this, &MyWebFrame::timerFired) {}
-
- virtual PassRefPtr<WebCore::ResourceLoaderAndroid> startLoadingResource(
- ResourceHandle* handle, const ResourceRequest& req, bool, bool);
-
- virtual bool canHandleRequest(const ResourceRequest&) { return true; }
-
-private:
- void timerFired(Timer<MyWebFrame>*);
- Vector<RefPtr<WebCore::ResourceLoaderAndroid> > m_requests;
- Timer<MyWebFrame> m_timer;
-};
-
-#endif
diff --git a/Source/WebKit/android/benchmark/MyJavaVM.cpp b/Source/WebKit/android/benchmark/MyJavaVM.cpp
deleted file mode 100644
index 574c745..0000000
--- a/Source/WebKit/android/benchmark/MyJavaVM.cpp
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright 2009, 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 APPLE COMPUTER, INC. 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.
- */
-
-#include "config.h"
-#include "MyJavaVM.h"
-
-#include <JNIUtility.h>
-#include <jni.h>
-
-static JNIEnv* s_env;
-static JavaVM* s_jvm;
-
-// JavaVM functions
-jint vm_attachCurrentThread(JavaVM*, JNIEnv** env, void*) {
- *env = s_env;
- return JNI_OK;
-}
-
-// JNIEnv functions
-jobject env_callObjectMethodV(JNIEnv*, jobject, jmethodID, va_list) {
- return MY_JOBJECT;
-}
-void env_callVoidMethodV(JNIEnv*, jobject, jmethodID, va_list) {}
-void env_deleteRef(JNIEnv*, jobject) {}
-jboolean env_exceptionCheck(JNIEnv*) {
- return false;
-}
-jclass env_findClass(JNIEnv*, const char*) {
- return (jclass) 1;
-}
-jbyte* env_getByteArrayElements(JNIEnv*, jbyteArray, jboolean*) {
- return NULL;
-}
-jmethodID env_getMethodID(JNIEnv*, jclass, const char*, const char*) {
- return (jmethodID) 1;
-}
-jclass env_getObjectClass(JNIEnv*, jobject) {
- return (jclass) 1;
-}
-static const char* s_fakeString = "Fake Java String";
-const jchar* env_getStringChars(JNIEnv*, jstring, jboolean* isCopy) {
- if (isCopy)
- *isCopy = false;
- return (const jchar*)s_fakeString;
-}
-jsize env_getStringLength(JNIEnv*, jstring) {
- return sizeof(s_fakeString) - 1;
-}
-jbyteArray env_newByteArray(JNIEnv*, jsize) {
- return (jbyteArray) 1;
-}
-jobject env_newRef(JNIEnv*, jobject obj) {
- return obj;
-}
-jobject env_newObjectV(JNIEnv*, jclass, jmethodID, va_list) {
- return MY_JOBJECT;
-}
-jstring env_newString(JNIEnv*, const jchar*, jsize) {
- return (jstring) 1;
-}
-void env_releaseByteArrayElements(JNIEnv*, jbyteArray, jbyte*, jint) {}
-void env_releaseStringChars(JNIEnv*, jstring, const jchar*) {}
-void env_setByteArrayRegion(JNIEnv*, jbyteArray, jsize, jsize, const jbyte*) {}
-void env_setIntField(JNIEnv*, jobject, jfieldID, jint) {}
-
-void InitializeJavaVM() {
- // First, create the fake vm
- s_jvm = new JavaVM;
- JNIInvokeInterface* i = new JNIInvokeInterface;
- memset(i, 0, sizeof(JNIInvokeInterface));
- s_jvm->functions = i;
-
- // Now, assign the functions of the vm to our fake ones.
- i->AttachCurrentThread = vm_attachCurrentThread;
-
- // Create the fake env next
- s_env = new JNIEnv;
- JNINativeInterface* n = new JNINativeInterface;
- memset(n, 0, sizeof(JNINativeInterface));
- s_env->functions = n;
-
- // Point the functions we care about to out fake ones.
- n->CallObjectMethodV = env_callObjectMethodV;
- n->CallVoidMethodV = env_callVoidMethodV;
- n->DeleteLocalRef = env_deleteRef;
- n->DeleteGlobalRef = env_deleteRef;
- n->DeleteWeakGlobalRef = env_deleteRef;
- n->ExceptionCheck = env_exceptionCheck;
- n->FindClass = env_findClass;
- n->GetByteArrayElements = env_getByteArrayElements;
- n->GetMethodID = env_getMethodID;
- n->GetObjectClass = env_getObjectClass;
- n->GetStringChars = env_getStringChars;
- n->GetStringLength = env_getStringLength;
- n->NewByteArray = env_newByteArray;
- n->NewLocalRef = env_newRef;
- n->NewGlobalRef = env_newRef;
- n->NewWeakGlobalRef = env_newRef;
- n->NewObjectV = env_newObjectV;
- n->NewString = env_newString;
- n->ReleaseByteArrayElements = env_releaseByteArrayElements;
- n->ReleaseStringChars = env_releaseStringChars;
- n->SetByteArrayRegion = env_setByteArrayRegion;
- n->SetIntField = env_setIntField;
-
- // Tell WebCore about the vm
- JSC::Bindings::setJavaVM(s_jvm);
-}
diff --git a/Source/WebKit/android/benchmark/MyJavaVM.h b/Source/WebKit/android/benchmark/MyJavaVM.h
deleted file mode 100644
index 3092161..0000000
--- a/Source/WebKit/android/benchmark/MyJavaVM.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright 2009, 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 APPLE COMPUTER, INC. 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 MyJavaVM_h
-#define MyJavaVM_h
-
-// Make it 1 just to appease any assertions or checks for valid objects
-#define MY_JOBJECT ((jobject) 1)
-
-void InitializeJavaVM();
-
-#endif
diff --git a/Source/WebKit/android/benchmark/main.cpp b/Source/WebKit/android/benchmark/main.cpp
deleted file mode 100644
index fcb797d..0000000
--- a/Source/WebKit/android/benchmark/main.cpp
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright 2009, 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 APPLE COMPUTER, INC. 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 "webcore_test"
-
-#include <stdlib.h>
-#include <string.h>
-#include <getopt.h>
-#include <utils/Log.h>
-
-namespace android {
-extern void benchmark(const char*, int, int ,int);
-}
-
-int main(int argc, char** argv) {
- int width = 800;
- int height = 600;
- int reloadCount = 0;
- while (true) {
- int c = getopt(argc, argv, "d:r:");
- if (c == -1)
- break;
- else if (c == 'd') {
- char* x = strchr(optarg, 'x');
- if (x) {
- width = atoi(optarg);
- height = atoi(x + 1);
- LOGD("Rendering page at %dx%d", width, height);
- }
- } else if (c == 'r') {
- reloadCount = atoi(optarg);
- if (reloadCount < 0)
- reloadCount = 0;
- LOGD("Reloading %d times", reloadCount);
- }
- }
- if (optind >= argc) {
- LOGE("Please supply a file to read\n");
- return 1;
- }
-
- android::benchmark(argv[optind], reloadCount, width, height);
-}
diff --git a/Source/WebKit/android/content/PhoneEmailDetector.cpp b/Source/WebKit/android/content/PhoneEmailDetector.cpp
new file mode 100644
index 0000000..ca97a71
--- /dev/null
+++ b/Source/WebKit/android/content/PhoneEmailDetector.cpp
@@ -0,0 +1,383 @@
+/*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 APPLE AND ITS CONTRIBUTORS "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 APPLE OR ITS 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.
+ */
+
+#include "config.h"
+
+#undef WEBKIT_IMPLEMENTATION
+#undef LOG
+
+#include "base/utf_string_conversions.h"
+#include "net/base/escape.h"
+#include "PhoneEmailDetector.h"
+#include "Settings.h"
+#include "WebString.h"
+
+#define LOG_TAG "PhoneNumberDetector"
+#include <cutils/log.h>
+
+#define PHONE_PATTERN "(200) /-.\\ 100 -. 0000"
+
+static const char kTelSchemaPrefix[] = "tel:";
+static const char kEmailSchemaPrefix[] = "mailto:";
+
+void FindReset(FindState* state);
+void FindResetNumber(FindState* state);
+FoundState FindPartialNumber(const UChar* chars, unsigned length,
+ FindState* s);
+struct FindState;
+
+static FoundState FindPartialEMail(const UChar* , unsigned length, FindState* );
+static bool IsDomainChar(UChar ch);
+static bool IsMailboxChar(UChar ch);
+
+PhoneEmailDetector::PhoneEmailDetector()
+ : m_foundResult(FOUND_NONE)
+{
+}
+
+bool PhoneEmailDetector::IsEnabled(const WebKit::WebHitTestInfo& hit_test)
+{
+ WebCore::Settings* settings = GetSettings(hit_test);
+ if (!settings)
+ return false;
+ m_isPhoneDetectionEnabled = settings->formatDetectionTelephone();
+ m_isEmailDetectionEnabled = settings->formatDetectionEmail();
+ return m_isEmailDetectionEnabled || m_isPhoneDetectionEnabled;
+}
+
+bool PhoneEmailDetector::FindContent(const string16::const_iterator& begin,
+ const string16::const_iterator& end,
+ size_t* start_pos,
+ size_t* end_pos)
+{
+ FindReset(&m_findState);
+ m_foundResult = FOUND_NONE;
+ if (m_isPhoneDetectionEnabled)
+ m_foundResult = FindPartialNumber(begin, end - begin, &m_findState);
+ if (m_foundResult == FOUND_COMPLETE)
+ m_prefix = kTelSchemaPrefix;
+ else {
+ FindReset(&m_findState);
+ if (m_isEmailDetectionEnabled)
+ m_foundResult = FindPartialEMail(begin, end - begin, &m_findState);
+ m_prefix = kEmailSchemaPrefix;
+ }
+ *start_pos = m_findState.mStartResult;
+ *end_pos = m_findState.mEndResult;
+ return m_foundResult == FOUND_COMPLETE;
+}
+
+std::string PhoneEmailDetector::GetContentText(const WebKit::WebRange& range)
+{
+ if (m_foundResult == FOUND_COMPLETE) {
+ if (m_prefix == kTelSchemaPrefix)
+ return UTF16ToUTF8(m_findState.mStore);
+ else
+ return UTF16ToUTF8(range.toPlainText());
+ }
+ return std::string();
+}
+
+GURL PhoneEmailDetector::GetIntentURL(const std::string& content_text)
+{
+ return GURL(m_prefix +
+ EscapeQueryParamValue(content_text, true));
+}
+
+void FindReset(FindState* state)
+{
+ memset(state, 0, sizeof(FindState));
+ state->mCurrent = ' ';
+ FindResetNumber(state);
+}
+
+void FindResetNumber(FindState* state)
+{
+ state->mOpenParen = false;
+ state->mPattern = (char*) PHONE_PATTERN;
+ state->mStorePtr = state->mStore;
+}
+
+FoundState FindPartialNumber(const UChar* chars, unsigned length,
+ FindState* s)
+{
+ char* pattern = s->mPattern;
+ UChar* store = s->mStorePtr;
+ const UChar* start = chars;
+ const UChar* end = chars + length;
+ const UChar* lastDigit = 0;
+ string16 search16(chars, length);
+ std::string searchSpace = UTF16ToUTF8(search16);
+ do {
+ bool initialized = s->mInitialized;
+ while (chars < end) {
+ if (initialized == false) {
+ s->mBackTwo = s->mBackOne;
+ s->mBackOne = s->mCurrent;
+ }
+ UChar ch = s->mCurrent = *chars;
+ do {
+ char patternChar = *pattern;
+ switch (patternChar) {
+ case '2':
+ if (initialized == false) {
+ s->mStartResult = chars - start;
+ initialized = true;
+ }
+ case '0':
+ case '1':
+ if (ch < patternChar || ch > '9')
+ goto resetPattern;
+ *store++ = ch;
+ pattern++;
+ lastDigit = chars;
+ goto nextChar;
+ case '\0':
+ if (WTF::isASCIIDigit(ch) == false) {
+ *store = '\0';
+ goto checkMatch;
+ }
+ goto resetPattern;
+ case ' ':
+ if (ch == patternChar)
+ goto nextChar;
+ break;
+ case '(':
+ if (ch == patternChar) {
+ s->mStartResult = chars - start;
+ initialized = true;
+ s->mOpenParen = true;
+ }
+ goto commonPunctuation;
+ case ')':
+ if ((ch == patternChar) ^ s->mOpenParen)
+ goto resetPattern;
+ default:
+ commonPunctuation:
+ if (ch == patternChar) {
+ pattern++;
+ goto nextChar;
+ }
+ }
+ } while (++pattern); // never false
+ nextChar:
+ chars++;
+ }
+ break;
+resetPattern:
+ if (s->mContinuationNode)
+ return FOUND_NONE;
+ FindResetNumber(s);
+ pattern = s->mPattern;
+ store = s->mStorePtr;
+ } while (++chars < end);
+checkMatch:
+ if (WTF::isASCIIDigit(s->mBackOne != '1' ? s->mBackOne : s->mBackTwo)) {
+ return FOUND_NONE;
+ }
+ *store = '\0';
+ s->mStorePtr = store;
+ s->mPattern = pattern;
+ s->mEndResult = lastDigit - start + 1;
+ char pState = pattern[0];
+ return pState == '\0' ? FOUND_COMPLETE : pState == '(' || (WTF::isASCIIDigit(pState) && WTF::isASCIIDigit(pattern[-1])) ?
+ FOUND_NONE : FOUND_PARTIAL;
+}
+
+FoundState FindPartialEMail(const UChar* chars, unsigned length,
+ FindState* s)
+{
+ // the following tables were generated by tests/browser/focusNavigation/BrowserDebug.cpp
+ // hand-edit at your own risk
+ static const int domainTwoLetter[] = {
+ 0x02df797c, // a followed by: [cdefgilmnoqrstuwxz]
+ 0x036e73fb, // b followed by: [abdefghijmnorstvwyz]
+ 0x03b67ded, // c followed by: [acdfghiklmnorsuvxyz]
+ 0x02005610, // d followed by: [ejkmoz]
+ 0x001e00d4, // e followed by: [ceghrstu]
+ 0x00025700, // f followed by: [ijkmor]
+ 0x015fb9fb, // g followed by: [abdefghilmnpqrstuwy]
+ 0x001a3400, // h followed by: [kmnrtu]
+ 0x000f7818, // i followed by: [delmnoqrst]
+ 0x0000d010, // j followed by: [emop]
+ 0x0342b1d0, // k followed by: [eghimnprwyz]
+ 0x013e0507, // l followed by: [abcikrstuvy]
+ 0x03fffccd, // m followed by: [acdghklmnopqrstuvwxyz]
+ 0x0212c975, // n followed by: [acefgilopruz]
+ 0x00001000, // o followed by: [m]
+ 0x014e3cf1, // p followed by: [aefghklmnrstwy]
+ 0x00000001, // q followed by: [a]
+ 0x00504010, // r followed by: [eouw]
+ 0x032a7fdf, // s followed by: [abcdeghijklmnortvyz]
+ 0x026afeec, // t followed by: [cdfghjklmnoprtvwz]
+ 0x03041441, // u followed by: [agkmsyz]
+ 0x00102155, // v followed by: [aceginu]
+ 0x00040020, // w followed by: [fs]
+ 0x00000000, // x
+ 0x00180010, // y followed by: [etu]
+ 0x00401001, // z followed by: [amw]
+ };
+
+ static char const* const longDomainNames[] = {
+ "\x03" "ero" "\x03" "rpa", // aero, arpa
+ "\x02" "iz", // biz
+ "\x02" "at" "\x02" "om" "\x03" "oop", // cat, com, coop
+ NULL, // d
+ "\x02" "du", // edu
+ NULL, // f
+ "\x02" "ov", // gov
+ NULL, // h
+ "\x03" "nfo" "\x02" "nt", // info, int
+ "\x03" "obs", // jobs
+ NULL, // k
+ NULL, // l
+ "\x02" "il" "\x03" "obi" "\x05" "useum", // mil, mobi, museum
+ "\x03" "ame" "\x02" "et", // name, net
+ "\x02" "rg", // , org
+ "\x02" "ro", // pro
+ NULL, // q
+ NULL, // r
+ NULL, // s
+ "\x05" "ravel", // travel
+ NULL, // u
+ NULL, // v
+ NULL, // w
+ NULL, // x
+ NULL, // y
+ NULL, // z
+ };
+
+ const UChar* start = chars;
+ const UChar* end = chars + length;
+ while (chars < end) {
+ UChar ch = *chars++;
+ if (ch != '@')
+ continue;
+ const UChar* atLocation = chars - 1;
+ // search for domain
+ ch = *chars++ | 0x20; // convert uppercase to lower
+ if (ch < 'a' || ch > 'z')
+ continue;
+ while (chars < end) {
+ ch = *chars++;
+ if (IsDomainChar(ch) == false)
+ goto nextAt;
+ if (ch != '.')
+ continue;
+ UChar firstLetter = *chars++ | 0x20; // first letter of the domain
+ if (chars >= end)
+ return FOUND_NONE; // only one letter; must be at least two
+ firstLetter -= 'a';
+ if (firstLetter > 'z' - 'a')
+ continue; // non-letter followed '.'
+ int secondLetterMask = domainTwoLetter[firstLetter];
+ ch = *chars | 0x20; // second letter of the domain
+ ch -= 'a';
+ if (ch >= 'z' - 'a')
+ continue;
+ bool secondMatch = (secondLetterMask & 1 << ch) != 0;
+ const char* wordMatch = longDomainNames[firstLetter];
+ int wordIndex = 0;
+ while (wordMatch != NULL) {
+ int len = *wordMatch++;
+ char match;
+ do {
+ match = wordMatch[wordIndex];
+ if (match < 0x20)
+ goto foundDomainStart;
+ if (chars[wordIndex] != match)
+ break;
+ wordIndex++;
+ } while (true);
+ wordMatch += len;
+ if (*wordMatch == '\0')
+ break;
+ wordIndex = 0;
+ }
+ if (secondMatch) {
+ wordIndex = 1;
+ foundDomainStart:
+ chars += wordIndex;
+ if (chars < end) {
+ ch = *chars;
+ if (ch != '.') {
+ if (IsDomainChar(ch))
+ goto nextDot;
+ } else if (chars + 1 < end && IsDomainChar(chars[1]))
+ goto nextDot;
+ }
+ // found domain. Search backwards from '@' for beginning of email address
+ s->mEndResult = chars - start;
+ chars = atLocation;
+ if (chars <= start)
+ goto nextAt;
+ ch = *--chars;
+ if (ch == '.')
+ goto nextAt; // mailbox can't end in period
+ do {
+ if (IsMailboxChar(ch) == false) {
+ chars++;
+ break;
+ }
+ if (chars == start)
+ break;
+ ch = *--chars;
+ } while (true);
+ UChar firstChar = *chars;
+ if (firstChar == '.' || firstChar == '@') // mailbox can't start with period or be empty
+ goto nextAt;
+ s->mStartResult = chars - start;
+ return FOUND_COMPLETE;
+ }
+ nextDot:
+ ;
+ }
+nextAt:
+ chars = atLocation + 1;
+ }
+ return FOUND_NONE;
+}
+
+bool IsDomainChar(UChar ch)
+{
+ static const unsigned body[] = {0x03ff6000, 0x07fffffe, 0x07fffffe}; // 0-9 . - A-Z a-z
+ ch -= 0x20;
+ if (ch > 'z' - 0x20)
+ return false;
+ return (body[ch >> 5] & 1 << (ch & 0x1f)) != 0;
+}
+
+bool IsMailboxChar(UChar ch)
+{
+ // According to http://en.wikipedia.org/wiki/Email_address
+ // ! # $ % & ' * + - . / 0-9 = ?
+ // A-Z ^ _
+ // ` a-z { | } ~
+ static const unsigned body[] = {0xa3ffecfa, 0xc7fffffe, 0x7fffffff};
+ ch -= 0x20;
+ if (ch > '~' - 0x20)
+ return false;
+ return (body[ch >> 5] & 1 << (ch & 0x1f)) != 0;
+}
diff --git a/Source/WebKit/android/content/PhoneEmailDetector.h b/Source/WebKit/android/content/PhoneEmailDetector.h
new file mode 100644
index 0000000..74ff5b1
--- /dev/null
+++ b/Source/WebKit/android/content/PhoneEmailDetector.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 APPLE AND ITS CONTRIBUTORS "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 APPLE OR ITS 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.
+ */
+
+#include "content/content_detector.h"
+#include "PlatformString.h"
+
+#define NAVIGATION_MAX_PHONE_LENGTH 14
+
+struct FindState {
+ int mStartResult;
+ int mEndResult;
+ char* mPattern;
+ UChar mStore[NAVIGATION_MAX_PHONE_LENGTH + 1];
+ UChar* mStorePtr;
+ UChar mBackOne;
+ UChar mBackTwo;
+ UChar mCurrent;
+ bool mOpenParen;
+ bool mInitialized;
+ bool mContinuationNode;
+};
+
+enum FoundState {
+ FOUND_NONE,
+ FOUND_PARTIAL,
+ FOUND_COMPLETE
+};
+
+// Searches for phone numbers (US only) or email addresses based off of the navcache code
+class PhoneEmailDetector : public ContentDetector {
+public:
+ PhoneEmailDetector();
+ virtual ~PhoneEmailDetector() {}
+
+private:
+ // Implementation of ContentDetector.
+ virtual bool FindContent(const string16::const_iterator& begin,
+ const string16::const_iterator& end,
+ size_t* start_pos,
+ size_t* end_pos);
+
+ virtual std::string GetContentText(const WebKit::WebRange& range);
+ virtual GURL GetIntentURL(const std::string& content_text);
+ virtual size_t GetMaximumContentLength() {
+ return NAVIGATION_MAX_PHONE_LENGTH * 4;
+ }
+ virtual bool IsEnabled(const WebKit::WebHitTestInfo& hit_test) OVERRIDE;
+
+ DISALLOW_COPY_AND_ASSIGN(PhoneEmailDetector);
+
+ FindState m_findState;
+ FoundState m_foundResult;
+ const char* m_prefix;
+ // TODO: This shouldn't be done like this. PhoneEmailDetector should be
+ // refactored into two pieces and follow the IsEnabled style. This will
+ // only work because we always call IsEnabled before FindContent
+ bool m_isPhoneDetectionEnabled;
+ bool m_isEmailDetectionEnabled;
+};
diff --git a/Source/WebKit/android/content/address_detector.cpp b/Source/WebKit/android/content/address_detector.cpp
new file mode 100644
index 0000000..f6657d9
--- /dev/null
+++ b/Source/WebKit/android/content/address_detector.cpp
@@ -0,0 +1,945 @@
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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.
+ */
+
+#include "config.h"
+
+// Magic pretend-to-be-a-chromium-build flags
+#undef WEBKIT_IMPLEMENTATION
+#undef LOG
+
+#include "content/address_detector.h"
+
+#include <bitset>
+
+#include "base/utf_string_conversions.h"
+#include "net/base/escape.h"
+#include "Settings.h"
+#include "WebString.h"
+
+#include <wtf/HashSet.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/text/StringHash.h>
+#include <wtf/text/WTFString.h>
+
+namespace {
+
+// Prefix used for geographical address intent URIs.
+static const char kAddressSchemaPrefix[] = "geo:0,0?q=";
+
+// Maximum text length to be searched for address detection.
+static const size_t kMaxAddressLength = 500;
+
+// Minimum number of words in an address after the house number
+// before a state is expected to be found.
+// A value too high can miss short addresses.
+const size_t kMinAddressWords = 3;
+
+// Maximum number of words allowed in an address between the house number
+// and the state, both not included.
+const size_t kMaxAddressWords = 12;
+
+// Maximum number of lines allowed in an address between the house number
+// and the state, both not included.
+const size_t kMaxAddressLines = 5;
+
+// Maximum length allowed for any address word between the house number
+// and the state, both not included.
+const size_t kMaxAddressNameWordLength = 25;
+
+// Maximum number of words after the house number in which the location name
+// should be found.
+const size_t kMaxLocationNameDistance = 4;
+
+// Number of digits for a valid zip code.
+const size_t kZipDigits = 5;
+
+// Number of digits for a valid zip code in the Zip Plus 4 format.
+const size_t kZipPlus4Digits = 9;
+
+// Maximum number of digits of a house number, including possible hyphens.
+const size_t kMaxHouseDigits = 5;
+
+// Additional characters used as new line delimiters.
+const char16 kNewlineDelimiters[] = {
+ ',',
+ '*',
+ 0x2022, // Unicode bullet
+ 0,
+};
+
+char16 SafePreviousChar(const string16::const_iterator& it,
+ const string16::const_iterator& begin) {
+ if (it == begin)
+ return ' ';
+ return *(it - 1);
+}
+
+char16 SafeNextChar(const string16::const_iterator& it,
+ const string16::const_iterator& end) {
+ if (it == end)
+ return ' ';
+ return *(it + 1);
+}
+
+bool WordLowerCaseEqualsASCII(string16::const_iterator word_begin,
+ string16::const_iterator word_end, const char* ascii_to_match) {
+ for (string16::const_iterator it = word_begin; it != word_end;
+ ++it, ++ascii_to_match) {
+ if (!*ascii_to_match || base::ToLowerASCII(*it) != *ascii_to_match)
+ return false;
+ }
+ return *ascii_to_match == 0 || *ascii_to_match == ' ';
+}
+
+bool LowerCaseEqualsASCIIWithPlural(string16::const_iterator word_begin,
+ string16::const_iterator word_end, const char* ascii_to_match,
+ bool allow_plural) {
+ for (string16::const_iterator it = word_begin; it != word_end;
+ ++it, ++ascii_to_match) {
+ if (!*ascii_to_match && allow_plural && *it == 's' && it + 1 == word_end)
+ return true;
+
+ if (!*ascii_to_match || base::ToLowerASCII(*it) != *ascii_to_match)
+ return false;
+ }
+ return *ascii_to_match == 0;
+}
+
+} // anonymous namespace
+
+
+AddressDetector::AddressDetector() {
+}
+
+AddressDetector::~AddressDetector() {
+}
+
+std::string AddressDetector::GetContentText(const WebKit::WebRange& range) {
+ // Get the address and replace unicode bullets with commas.
+ string16 address_16 = CollapseWhitespace(range.toPlainText(), false);
+ std::replace(address_16.begin(), address_16.end(),
+ static_cast<char16>(0x2022), static_cast<char16>(','));
+ return UTF16ToUTF8(address_16);
+}
+
+GURL AddressDetector::GetIntentURL(const std::string& content_text) {
+ return GURL(kAddressSchemaPrefix +
+ EscapeQueryParamValue(content_text, true));
+}
+
+size_t AddressDetector::GetMaximumContentLength() {
+ return kMaxAddressLength;
+}
+
+bool AddressDetector::IsEnabled(const WebKit::WebHitTestInfo& hit_test) {
+ WebCore::Settings* settings = GetSettings(hit_test);
+ return settings && settings->formatDetectionAddress();
+}
+
+bool AddressDetector::FindContent(const string16::const_iterator& begin,
+ const string16::const_iterator& end, size_t* start_pos, size_t* end_pos) {
+ HouseNumberParser house_number_parser;
+
+ // Keep going through the input string until a potential house number is
+ // detected. Start tokenizing the following words to find a valid
+ // street name within a word range. Then, find a state name followed
+ // by a valid zip code for that state. Also keep a look for any other
+ // possible house numbers to continue from in case of no match and for
+ // state names not followed by a zip code (e.g. New York, NY 10000).
+ const string16 newline_delimiters = kNewlineDelimiters;
+ const string16 delimiters = kWhitespaceUTF16 + newline_delimiters;
+ for (string16::const_iterator it = begin; it != end; ) {
+ Word house_number;
+ if (!house_number_parser.Parse(it, end, &house_number))
+ return false;
+
+ String16Tokenizer tokenizer(house_number.end, end, delimiters);
+ tokenizer.set_options(String16Tokenizer::RETURN_DELIMS);
+
+ std::vector<Word> words;
+ words.push_back(house_number);
+
+ bool found_location_name = false;
+ bool continue_on_house_number = true;
+ size_t next_house_number_word = 0;
+ size_t num_lines = 1;
+
+ // Don't include the house number in the word count.
+ size_t next_word = 1;
+ for (; next_word <= kMaxAddressWords + 1; ++next_word) {
+
+ // Extract a new word from the tokenizer.
+ if (next_word == words.size()) {
+ do {
+ if (!tokenizer.GetNext())
+ return false;
+
+ // Check the number of address lines.
+ if (tokenizer.token_is_delim() && newline_delimiters.find(
+ *tokenizer.token_begin()) != string16::npos) {
+ ++num_lines;
+ }
+ } while (tokenizer.token_is_delim());
+
+ if (num_lines > kMaxAddressLines)
+ break;
+
+ words.push_back(Word(tokenizer.token_begin(), tokenizer.token_end()));
+ }
+
+ // Check the word length. If too long, don't try to continue from
+ // the next house number as no address can hold this word.
+ const Word& current_word = words[next_word];
+ DCHECK_GT(std::distance(current_word.begin, current_word.end), 0);
+ size_t current_word_length = std::distance(
+ current_word.begin, current_word.end);
+ if (current_word_length > kMaxAddressNameWordLength) {
+ continue_on_house_number = false;
+ break;
+ }
+
+ // Check if the new word is a valid house number.
+ // This is used to properly resume parsing in case the maximum number
+ // of words is exceeded.
+ if (next_house_number_word == 0 &&
+ house_number_parser.Parse(current_word.begin, current_word.end, NULL)) {
+ next_house_number_word = next_word;
+ continue;
+ }
+
+ // Look for location names in the words after the house number.
+ // A range limitation is introduced to avoid matching
+ // anything that starts with a number before a legitimate address.
+ if (next_word <= kMaxLocationNameDistance &&
+ IsValidLocationName(current_word)) {
+ found_location_name = true;
+ continue;
+ }
+
+ // Don't count the house number.
+ if (next_word > kMinAddressWords) {
+ // Looking for the state is likely to add new words to the list while
+ // checking for multi-word state names.
+ size_t state_first_word = next_word;
+ size_t state_last_word, state_index;
+ if (FindStateStartingInWord(&words, state_first_word, &state_last_word,
+ &tokenizer, &state_index)) {
+
+ // A location name should have been found at this point.
+ if (!found_location_name)
+ break;
+
+ // Explicitly exclude "et al", as "al" is a valid state code.
+ if (current_word_length == 2 && words.size() > 2) {
+ const Word& previous_word = words[state_first_word - 1];
+ if (previous_word.end - previous_word.begin == 2 &&
+ LowerCaseEqualsASCII(previous_word.begin, previous_word.end,
+ "et") &&
+ LowerCaseEqualsASCII(current_word.begin, current_word.end,
+ "al"))
+ break;
+ }
+
+ // Extract one more word from the tokenizer if not already available.
+ size_t zip_word = state_last_word + 1;
+ if (zip_word == words.size()) {
+ do {
+ if (!tokenizer.GetNext()) {
+ // Zip is optional
+ *start_pos = words[0].begin - begin;
+ *end_pos = words[state_last_word].end - begin;
+ return true;
+ }
+ } while (tokenizer.token_is_delim());
+ words.push_back(Word(tokenizer.token_begin(),
+ tokenizer.token_end()));
+ }
+
+ // Check the parsing validity and state range of the zip code.
+ next_word = state_last_word;
+ if (!IsZipValid(words[zip_word], state_index))
+ continue;
+
+ *start_pos = words[0].begin - begin;
+ *end_pos = words[zip_word].end - begin;
+ return true;
+ }
+ }
+ }
+
+ // Avoid skipping too many words because of a non-address number
+ // at the beginning of the contents to parse.
+ if (continue_on_house_number && next_house_number_word > 0) {
+ it = words[next_house_number_word].begin;
+ } else {
+ DCHECK(!words.empty());
+ next_word = std::min(next_word, words.size() - 1);
+ it = words[next_word].end;
+ }
+ }
+
+ return false;
+}
+
+bool AddressDetector::HouseNumberParser::IsPreDelimiter(
+ char16 character) {
+ return character == ':' || IsPostDelimiter(character);
+}
+
+bool AddressDetector::HouseNumberParser::IsPostDelimiter(
+ char16 character) {
+ return IsWhitespace(character) || strchr(",\"'", character);
+}
+
+void AddressDetector::HouseNumberParser::RestartOnNextDelimiter() {
+ ResetState();
+ for (; it_ != end_ && !IsPreDelimiter(*it_); ++it_) {}
+}
+
+void AddressDetector::HouseNumberParser::AcceptChars(size_t num_chars) {
+ size_t offset = std::min(static_cast<size_t>(std::distance(it_, end_)),
+ num_chars);
+ it_ += offset;
+ result_chars_ += offset;
+}
+
+void AddressDetector::HouseNumberParser::SkipChars(size_t num_chars) {
+ it_ += std::min(static_cast<size_t>(std::distance(it_, end_)), num_chars);
+}
+
+void AddressDetector::HouseNumberParser::ResetState() {
+ num_digits_ = 0;
+ result_chars_ = 0;
+}
+
+bool AddressDetector::HouseNumberParser::CheckFinished(Word* word) const {
+ // There should always be a number after a hyphen.
+ if (result_chars_ == 0 || SafePreviousChar(it_, begin_) == '-')
+ return false;
+
+ if (word) {
+ word->begin = it_ - result_chars_;
+ word->end = it_;
+ }
+ return true;
+}
+
+bool AddressDetector::HouseNumberParser::Parse(
+ const string16::const_iterator& begin,
+ const string16::const_iterator& end, Word* word) {
+ it_ = begin_ = begin;
+ end_ = end;
+ ResetState();
+
+ // Iterations only used as a fail-safe against any buggy infinite loops.
+ size_t iterations = 0;
+ size_t max_iterations = end - begin + 1;
+ for (; it_ != end_ && iterations < max_iterations; ++iterations) {
+
+ // Word finished case.
+ if (IsPostDelimiter(*it_)) {
+ if (CheckFinished(word))
+ return true;
+ else if (result_chars_)
+ ResetState();
+
+ SkipChars(1);
+ continue;
+ }
+
+ // More digits. There should be no more after a letter was found.
+ if (IsAsciiDigit(*it_)) {
+ if (num_digits_ >= kMaxHouseDigits) {
+ RestartOnNextDelimiter();
+ } else {
+ AcceptChars(1);
+ ++num_digits_;
+ }
+ continue;
+ }
+
+ if (IsAsciiAlpha(*it_)) {
+ // Handle special case 'one'.
+ if (result_chars_ == 0) {
+ if (it_ + 3 <= end_ && LowerCaseEqualsASCII(it_, it_ + 3, "one"))
+ AcceptChars(3);
+ else
+ RestartOnNextDelimiter();
+ continue;
+ }
+
+ // There should be more than 1 character because of result_chars.
+ DCHECK_GT(result_chars_, 0U);
+ DCHECK_NE(it_, begin_);
+ char16 previous = SafePreviousChar(it_, begin_);
+ if (IsAsciiDigit(previous)) {
+ // Check cases like '12A'.
+ char16 next = SafeNextChar(it_, end_);
+ if (IsPostDelimiter(next)) {
+ AcceptChars(1);
+ continue;
+ }
+
+ // Handle cases like 12a, 1st, 2nd, 3rd, 7th.
+ if (IsAsciiAlpha(next)) {
+ char16 last_digit = previous;
+ char16 first_letter = base::ToLowerASCII(*it_);
+ char16 second_letter = base::ToLowerASCII(next);
+ bool is_teen = SafePreviousChar(it_ - 1, begin_) == '1' &&
+ num_digits_ == 2;
+
+ switch (last_digit - '0') {
+ case 1:
+ if ((first_letter == 's' && second_letter == 't') ||
+ (first_letter == 't' && second_letter == 'h' && is_teen)) {
+ AcceptChars(2);
+ continue;
+ }
+ break;
+
+ case 2:
+ if ((first_letter == 'n' && second_letter == 'd') ||
+ (first_letter == 't' && second_letter == 'h' && is_teen)) {
+ AcceptChars(2);
+ continue;
+ }
+ break;
+
+ case 3:
+ if ((first_letter == 'r' && second_letter == 'd') ||
+ (first_letter == 't' && second_letter == 'h' && is_teen)) {
+ AcceptChars(2);
+ continue;
+ }
+ break;
+
+ case 0:
+ // Explicitly exclude '0th'.
+ if (num_digits_ == 1)
+ break;
+
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ if (first_letter == 't' && second_letter == 'h') {
+ AcceptChars(2);
+ continue;
+ }
+ break;
+
+ default:
+ NOTREACHED();
+ }
+ }
+ }
+
+ RestartOnNextDelimiter();
+ continue;
+ }
+
+ if (*it_ == '-' && num_digits_ > 0) {
+ AcceptChars(1);
+ ++num_digits_;
+ continue;
+ }
+
+ RestartOnNextDelimiter();
+ SkipChars(1);
+ }
+
+ if (iterations >= max_iterations)
+ return false;
+
+ return CheckFinished(word);
+}
+
+bool AddressDetector::FindStateStartingInWord(WordList* words,
+ size_t state_first_word, size_t* state_last_word,
+ String16Tokenizer* tokenizer, size_t* state_index) {
+
+ // Bitmasks containing the allowed suffixes for 2-letter state codes.
+ static const int state_two_letter_suffix[23] = {
+ 0x02060c00, // A followed by: [KLRSZ].
+ 0x00000000, // B.
+ 0x00084001, // C followed by: [AOT].
+ 0x00000014, // D followed by: [CE].
+ 0x00000000, // E.
+ 0x00001800, // F followed by: [LM].
+ 0x00100001, // G followed by: [AU].
+ 0x00000100, // H followed by: [I].
+ 0x00002809, // I followed by: [ADLN].
+ 0x00000000, // J.
+ 0x01040000, // K followed by: [SY].
+ 0x00000001, // L followed by: [A].
+ 0x000ce199, // M followed by: [ADEHINOPST].
+ 0x0120129c, // N followed by: [CDEHJMVY].
+ 0x00020480, // O followed by: [HKR].
+ 0x00420001, // P followed by: [ARW].
+ 0x00000000, // Q.
+ 0x00000100, // R followed by: [I].
+ 0x0000000c, // S followed by: [CD].
+ 0x00802000, // T followed by: [NX].
+ 0x00080000, // U followed by: [T].
+ 0x00080101, // V followed by: [AIT].
+ 0x01200101 // W followed by: [AIVY].
+ };
+
+ // Accumulative number of states for the 2-letter code indexed by the first.
+ static const int state_two_letter_accumulative[24] = {
+ 0, 5, 5, 8, 10, 10, 12, 14,
+ 15, 19, 19, 21, 22, 32, 40, 43,
+ 46, 46, 47, 49, 51, 52, 55, 59
+ };
+
+ // State names sorted alphabetically with their lengths.
+ // There can be more than one possible name for a same state if desired.
+ static const struct StateNameInfo {
+ const char* string;
+ char first_word_length;
+ char length;
+ char state_index; // Relative to two-character code alphabetical order.
+ } state_names[59] = {
+ { "alabama", 7, 7, 1 }, { "alaska", 6, 6, 0 },
+ { "american samoa", 8, 14, 3 }, { "arizona", 7, 7, 4 },
+ { "arkansas", 8, 8, 2 },
+ { "california", 10, 10, 5 }, { "colorado", 8, 8, 6 },
+ { "connecticut", 11, 11, 7 }, { "delaware", 8, 8, 9 },
+ { "district of columbia", 8, 20, 8 },
+ { "federated states of micronesia", 9, 30, 11 }, { "florida", 7, 7, 10 },
+ { "guam", 4, 4, 13 }, { "georgia", 7, 7, 12 },
+ { "hawaii", 6, 6, 14 },
+ { "idaho", 5, 5, 16 }, { "illinois", 8, 8, 17 }, { "indiana", 7, 7, 18 },
+ { "iowa", 4, 4, 15 },
+ { "kansas", 6, 6, 19 }, { "kentucky", 8, 8, 20 },
+ { "louisiana", 9, 9, 21 },
+ { "maine", 5, 5, 24 }, { "marshall islands", 8, 16, 25 },
+ { "maryland", 8, 8, 23 }, { "massachusetts", 13, 13, 22 },
+ { "michigan", 8, 8, 26 }, { "minnesota", 9, 9, 27 },
+ { "mississippi", 11, 11, 30 }, { "missouri", 8, 8, 28 },
+ { "montana", 7, 7, 31 },
+ { "nebraska", 8, 8, 34 }, { "nevada", 6, 6, 38 },
+ { "new hampshire", 3, 13, 35 }, { "new jersey", 3, 10, 36 },
+ { "new mexico", 3, 10, 37 }, { "new york", 3, 8, 39 },
+ { "north carolina", 5, 14, 32 }, { "north dakota", 5, 12, 33 },
+ { "northern mariana islands", 8, 24, 29 },
+ { "ohio", 4, 4, 40 }, { "oklahoma", 8, 8, 41 }, { "oregon", 6, 6, 42 },
+ { "palau", 5, 5, 45 }, { "pennsylvania", 12, 12, 43 },
+ { "puerto rico", 6, 11, 44 },
+ { "rhode island", 5, 5, 46 },
+ { "south carolina", 5, 14, 47 }, { "south dakota", 5, 12, 48 },
+ { "tennessee", 9, 9, 49 }, { "texas", 5, 5, 50 },
+ { "utah", 4, 4, 51 },
+ { "vermont", 7, 7, 54 }, { "virgin islands", 6, 14, 53 },
+ { "virginia", 8, 8, 52 },
+ { "washington", 10, 10, 55 }, { "west virginia", 4, 13, 57 },
+ { "wisconsin", 9, 9, 56 }, { "wyoming", 7, 7, 58 }
+ };
+
+ // Accumulative number of states for sorted names indexed by the first letter.
+ // Required a different one since there are codes that don't share their
+ // first letter with the name of their state (MP = Northern Mariana Islands).
+ static const int state_names_accumulative[24] = {
+ 0, 5, 5, 8, 10, 10, 12, 14,
+ 15, 19, 19, 21, 22, 31, 40, 43,
+ 46, 46, 47, 49, 51, 52, 55, 59
+ };
+
+ DCHECK_EQ(state_names_accumulative[arraysize(state_names_accumulative) - 1],
+ static_cast<int>(ARRAYSIZE_UNSAFE(state_names)));
+
+ const Word& first_word = words->at(state_first_word);
+ int length = first_word.end - first_word.begin;
+ if (length < 2 || !IsAsciiAlpha(*first_word.begin))
+ return false;
+
+ // No state names start with x, y, z.
+ char16 first_letter = base::ToLowerASCII(*first_word.begin);
+ if (first_letter > 'w')
+ return false;
+
+ DCHECK(first_letter >= 'a');
+ int first_index = first_letter - 'a';
+
+ // Look for two-letter state names.
+ if (length == 2 && IsAsciiAlpha(*(first_word.begin + 1))) {
+ char16 second_letter = base::ToLowerASCII(*(first_word.begin + 1));
+ DCHECK(second_letter >= 'a');
+
+ int second_index = second_letter - 'a';
+ if (!(state_two_letter_suffix[first_index] & (1 << second_index)))
+ return false;
+
+ std::bitset<32> previous_suffixes = state_two_letter_suffix[first_index] &
+ ((1 << second_index) - 1);
+ *state_last_word = state_first_word;
+ *state_index = state_two_letter_accumulative[first_index] +
+ previous_suffixes.count();
+ return true;
+ }
+
+ // Look for full state names by their first letter. Discard by length.
+ for (int state = state_names_accumulative[first_index];
+ state < state_names_accumulative[first_index + 1]; ++state) {
+ if (state_names[state].first_word_length != length)
+ continue;
+
+ bool state_match = false;
+ size_t state_word = state_first_word;
+ for (int pos = 0; true; ) {
+ if (!WordLowerCaseEqualsASCII(words->at(state_word).begin,
+ words->at(state_word).end, &state_names[state].string[pos]))
+ break;
+
+ pos += words->at(state_word).end - words->at(state_word).begin + 1;
+ if (pos >= state_names[state].length) {
+ state_match = true;
+ break;
+ }
+
+ // Ran out of words, extract more from the tokenizer.
+ if (++state_word == words->size()) {
+ do {
+ if (!tokenizer->GetNext())
+ break;
+ } while (tokenizer->token_is_delim());
+ words->push_back(Word(tokenizer->token_begin(), tokenizer->token_end()));
+ }
+ }
+
+ if (state_match) {
+ *state_last_word = state_word;
+ *state_index = state_names[state].state_index;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool AddressDetector::IsZipValid(const Word& word, size_t state_index) {
+ size_t length = word.end - word.begin;
+ if (length != kZipDigits && length != kZipPlus4Digits + 1)
+ return false;
+
+ for (string16::const_iterator it = word.begin; it != word.end; ++it) {
+ size_t pos = it - word.begin;
+ if (IsAsciiDigit(*it) || (*it == '-' && pos == kZipDigits))
+ continue;
+ return false;
+ }
+ return IsZipValidForState(word, state_index);
+}
+
+bool AddressDetector::IsZipValidForState(const Word& word, size_t state_index)
+{
+ enum USState {
+ AP = -4, // AP (military base in the Pacific)
+ AA = -3, // AA (military base inside the US)
+ AE = -2, // AE (military base outside the US)
+ XX = -1, // (not in use)
+ AK = 0, // AK Alaska
+ AL = 1, // AL Alabama
+ AR = 2, // AR Arkansas
+ AS = 3, // AS American Samoa
+ AZ = 4, // AZ Arizona
+ CA = 5, // CA California
+ CO = 6, // CO Colorado
+ CT = 7, // CT Connecticut
+ DC = 8, // DC District of Columbia
+ DE = 9, // DE Delaware
+ FL = 10, // FL Florida
+ FM = 11, // FM Federated States of Micronesia
+ GA = 12, // GA Georgia
+ GU = 13, // GU Guam
+ HI = 14, // HI Hawaii
+ IA = 15, // IA Iowa
+ ID = 16, // ID Idaho
+ IL = 17, // IL Illinois
+ IN = 18, // IN Indiana
+ KS = 19, // KS Kansas
+ KY = 20, // KY Kentucky
+ LA = 21, // LA Louisiana
+ MA = 22, // MA Massachusetts
+ MD = 23, // MD Maryland
+ ME = 24, // ME Maine
+ MH = 25, // MH Marshall Islands
+ MI = 26, // MI Michigan
+ MN = 27, // MN Minnesota
+ MO = 28, // MO Missouri
+ MP = 29, // MP Northern Mariana Islands
+ MS = 30, // MS Mississippi
+ MT = 31, // MT Montana
+ NC = 32, // NC North Carolina
+ ND = 33, // ND North Dakota
+ NE = 34, // NE Nebraska
+ NH = 35, // NH New Hampshire
+ NJ = 36, // NJ New Jersey
+ NM = 37, // NM New Mexico
+ NV = 38, // NV Nevada
+ NY = 39, // NY New York
+ OH = 40, // OH Ohio
+ OK = 41, // OK Oklahoma
+ OR = 42, // OR Oregon
+ PA = 43, // PA Pennsylvania
+ PR = 44, // PR Puerto Rico
+ PW = 45, // PW Palau
+ RI = 46, // RI Rhode Island
+ SC = 47, // SC South Carolina
+ SD = 48, // SD South Dakota
+ TN = 49, // TN Tennessee
+ TX = 50, // TX Texas
+ UT = 51, // UT Utah
+ VA = 52, // VA Virginia
+ VI = 53, // VI Virgin Islands
+ VT = 54, // VT Vermont
+ WA = 55, // WA Washington
+ WI = 56, // WI Wisconsin
+ WV = 57, // WV West Virginia
+ WY = 58, // WY Wyoming
+ };
+
+ static const USState stateForZipPrefix[] = {
+ // 0 1 2 3 4 5 6 7 8 9
+ XX, XX, XX, XX, XX, NY, PR, PR, VI, PR, // 000-009
+ MA, MA, MA, MA, MA, MA, MA, MA, MA, MA, // 010-019
+ MA, MA, MA, MA, MA, MA, MA, MA, RI, RI, // 020-029
+ NH, NH, NH, NH, NH, NH, NH, NH, NH, ME, // 030-039
+ ME, ME, ME, ME, ME, ME, ME, ME, ME, ME, // 040-049
+ VT, VT, VT, VT, VT, MA, VT, VT, VT, VT, // 050-059
+ CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, // 060-069
+ NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, // 070-079
+ NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, NJ, // 080-089
+ AE, AE, AE, AE, AE, AE, AE, AE, AE, XX, // 090-099
+ NY, NY, NY, NY, NY, NY, NY, NY, NY, NY, // 100-109
+ NY, NY, NY, NY, NY, NY, NY, NY, NY, NY, // 110-119
+ NY, NY, NY, NY, NY, NY, NY, NY, NY, NY, // 120-129
+ NY, NY, NY, NY, NY, NY, NY, NY, NY, NY, // 130-139
+ NY, NY, NY, NY, NY, NY, NY, NY, NY, NY, // 140-149
+ PA, PA, PA, PA, PA, PA, PA, PA, PA, PA, // 150-159
+ PA, PA, PA, PA, PA, PA, PA, PA, PA, PA, // 160-169
+ PA, PA, PA, PA, PA, PA, PA, PA, PA, PA, // 170-179
+ PA, PA, PA, PA, PA, PA, PA, PA, PA, PA, // 180-189
+ PA, PA, PA, PA, PA, PA, PA, DE, DE, DE, // 190-199
+ DC, VA, DC, DC, DC, DC, MD, MD, MD, MD, // 200-209
+ MD, MD, MD, XX, MD, MD, MD, MD, MD, MD, // 210-219
+ VA, VA, VA, VA, VA, VA, VA, VA, VA, VA, // 220-229
+ VA, VA, VA, VA, VA, VA, VA, VA, VA, VA, // 230-239
+ VA, VA, VA, VA, VA, VA, VA, WV, WV, WV, // 240-249
+ WV, WV, WV, WV, WV, WV, WV, WV, WV, WV, // 250-259
+ WV, WV, WV, WV, WV, WV, WV, WV, WV, XX, // 260-269
+ NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, // 270-279
+ NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, // 280-289
+ SC, SC, SC, SC, SC, SC, SC, SC, SC, SC, // 290-299
+ GA, GA, GA, GA, GA, GA, GA, GA, GA, GA, // 300-309
+ GA, GA, GA, GA, GA, GA, GA, GA, GA, GA, // 310-319
+ FL, FL, FL, FL, FL, FL, FL, FL, FL, FL, // 320-329
+ FL, FL, FL, FL, FL, FL, FL, FL, FL, FL, // 330-339
+ AA, FL, FL, XX, FL, XX, FL, FL, XX, FL, // 340-349
+ AL, AL, AL, XX, AL, AL, AL, AL, AL, AL, // 350-359
+ AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, // 360-369
+ TN, TN, TN, TN, TN, TN, TN, TN, TN, TN, // 370-379
+ TN, TN, TN, TN, TN, TN, MS, MS, MS, MS, // 380-389
+ MS, MS, MS, MS, MS, MS, MS, MS, GA, GA, // 390-399
+ KY, KY, KY, KY, KY, KY, KY, KY, KY, KY, // 400-409
+ KY, KY, KY, KY, KY, KY, KY, KY, KY, XX, // 410-419
+ KY, KY, KY, KY, KY, KY, KY, KY, XX, XX, // 420-429
+ OH, OH, OH, OH, OH, OH, OH, OH, OH, OH, // 430-439
+ OH, OH, OH, OH, OH, OH, OH, OH, OH, OH, // 440-449
+ OH, OH, OH, OH, OH, OH, OH, OH, OH, OH, // 450-459
+ IN, IN, IN, IN, IN, IN, IN, IN, IN, IN, // 460-469
+ IN, IN, IN, IN, IN, IN, IN, IN, IN, IN, // 470-479
+ MI, MI, MI, MI, MI, MI, MI, MI, MI, MI, // 480-489
+ MI, MI, MI, MI, MI, MI, MI, MI, MI, MI, // 490-499
+ IA, IA, IA, IA, IA, IA, IA, IA, IA, IA, // 500-509
+ IA, IA, IA, IA, IA, IA, IA, XX, XX, XX, // 510-519
+ IA, IA, IA, IA, IA, IA, IA, IA, IA, XX, // 520-529
+ WI, WI, WI, XX, WI, WI, XX, WI, WI, WI, // 530-539
+ WI, WI, WI, WI, WI, WI, WI, WI, WI, WI, // 540-549
+ MN, MN, XX, MN, MN, MN, MN, MN, MN, MN, // 550-559
+ MN, MN, MN, MN, MN, MN, MN, MN, XX, DC, // 560-569
+ SD, SD, SD, SD, SD, SD, SD, SD, XX, XX, // 570-579
+ ND, ND, ND, ND, ND, ND, ND, ND, ND, XX, // 580-589
+ MT, MT, MT, MT, MT, MT, MT, MT, MT, MT, // 590-599
+ IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, // 600-609
+ IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, // 610-619
+ IL, XX, IL, IL, IL, IL, IL, IL, IL, IL, // 620-629
+ MO, MO, XX, MO, MO, MO, MO, MO, MO, MO, // 630-639
+ MO, MO, XX, XX, MO, MO, MO, MO, MO, MO, // 640-649
+ MO, MO, MO, MO, MO, MO, MO, MO, MO, XX, // 650-659
+ KS, KS, KS, XX, KS, KS, KS, KS, KS, KS, // 660-669
+ KS, KS, KS, KS, KS, KS, KS, KS, KS, KS, // 670-679
+ NE, NE, XX, NE, NE, NE, NE, NE, NE, NE, // 680-689
+ NE, NE, NE, NE, XX, XX, XX, XX, XX, XX, // 690-699
+ LA, LA, XX, LA, LA, LA, LA, LA, LA, XX, // 700-709
+ LA, LA, LA, LA, LA, XX, AR, AR, AR, AR, // 710-719
+ AR, AR, AR, AR, AR, AR, AR, AR, AR, AR, // 720-729
+ OK, OK, XX, TX, OK, OK, OK, OK, OK, OK, // 730-739
+ OK, OK, XX, OK, OK, OK, OK, OK, OK, OK, // 740-749
+ TX, TX, TX, TX, TX, TX, TX, TX, TX, TX, // 750-759
+ TX, TX, TX, TX, TX, TX, TX, TX, TX, TX, // 760-769
+ TX, XX, TX, TX, TX, TX, TX, TX, TX, TX, // 770-779
+ TX, TX, TX, TX, TX, TX, TX, TX, TX, TX, // 780-789
+ TX, TX, TX, TX, TX, TX, TX, TX, TX, TX, // 790-799
+ CO, CO, CO, CO, CO, CO, CO, CO, CO, CO, // 800-809
+ CO, CO, CO, CO, CO, CO, CO, XX, XX, XX, // 810-819
+ WY, WY, WY, WY, WY, WY, WY, WY, WY, WY, // 820-829
+ WY, WY, ID, ID, ID, ID, ID, ID, ID, XX, // 830-839
+ UT, UT, UT, UT, UT, UT, UT, UT, XX, XX, // 840-849
+ AZ, AZ, AZ, AZ, XX, AZ, AZ, AZ, XX, AZ, // 850-859
+ AZ, XX, XX, AZ, AZ, AZ, XX, XX, XX, XX, // 860-869
+ NM, NM, NM, NM, NM, NM, XX, NM, NM, NM, // 870-879
+ NM, NM, NM, NM, NM, TX, XX, XX, XX, NV, // 880-889
+ NV, NV, XX, NV, NV, NV, XX, NV, NV, XX, // 890-899
+ CA, CA, CA, CA, CA, CA, CA, CA, CA, XX, // 900-909
+ CA, CA, CA, CA, CA, CA, CA, CA, CA, CA, // 910-919
+ CA, CA, CA, CA, CA, CA, CA, CA, CA, XX, // 920-929
+ CA, CA, CA, CA, CA, CA, CA, CA, CA, CA, // 930-939
+ CA, CA, CA, CA, CA, CA, CA, CA, CA, CA, // 940-949
+ CA, CA, CA, CA, CA, CA, CA, CA, CA, CA, // 950-959
+ CA, CA, AP, AP, AP, AP, AP, HI, HI, GU, // 960-969
+ OR, OR, OR, OR, OR, OR, OR, OR, OR, OR, // 970-979
+ WA, WA, WA, WA, WA, WA, WA, XX, WA, WA, // 980-989
+ WA, WA, WA, WA, WA, AK, AK, AK, AK, AK, // 990-999
+ };
+
+ if (!word.begin || !word.end || (word.end - word.begin) < 3)
+ return false;
+ const char16* zipPtr = word.begin;
+ if (zipPtr[0] < '0' || zipPtr[0] > '9' ||
+ zipPtr[1] < '0' || zipPtr[1] > '9' ||
+ zipPtr[2] < '0' || zipPtr[2] > '9')
+ return false;
+
+ int zip = zipPtr[0] - '0';
+ zip *= 10;
+ zip += zipPtr[1] - '0';
+ zip *= 10;
+ zip += zipPtr[2] - '0';
+ return stateForZipPrefix[zip] == (int) state_index;
+}
+
+static const char* s_rawStreetSuffixes[] = {
+ "allee", "alley", "ally", "aly",
+ "anex", "annex", "anx", "arc", "arcade", "av", "ave", "aven", "avenu",
+ "avenue", "avn", "avnue", "bayoo", "bayou", "bch", "beach", "bend",
+ "bg", "bgs", "blf", "blfs", "bluf", "bluff", "bluffs", "blvd", "bnd",
+ "bot", "bottm", "bottom", "boul", "boulevard", "boulv", "br", "branch",
+ "brdge", "brg", "bridge", "brk", "brks", "brnch", "brook", "brooks",
+ "btm", "burg", "burgs", "byp", "bypa", "bypas", "bypass", "byps", "byu",
+ "camp", "canyn", "canyon", "cape", "causeway", "causway", "cen", "cent",
+ "center", "centers", "centr", "centre", "cir", "circ", "circl",
+ "circle", "circles", "cirs", "ck", "clb", "clf", "clfs", "cliff",
+ "cliffs", "club", "cmn", "cmp", "cnter", "cntr", "cnyn", "common",
+ "cor", "corner", "corners", "cors", "course", "court", "courts", "cove",
+ "coves", "cp", "cpe", "cr", "crcl", "crcle", "crecent", "creek", "cres",
+ "crescent", "cresent", "crest", "crk", "crossing", "crossroad",
+ "crscnt", "crse", "crsent", "crsnt", "crssing", "crssng", "crst", "crt",
+ "cswy", "ct", "ctr", "ctrs", "cts", "curv", "curve", "cv", "cvs", "cyn",
+ "dale", "dam", "div", "divide", "dl", "dm", "dr", "driv", "drive",
+ "drives", "drs", "drv", "dv", "dvd", "est", "estate", "estates", "ests",
+ "exp", "expr", "express", "expressway", "expw", "expy", "ext",
+ "extension", "extensions", "extn", "extnsn", "exts", "fall", "falls",
+ "ferry", "field", "fields", "flat", "flats", "fld", "flds", "fls",
+ "flt", "flts", "ford", "fords", "forest", "forests", "forg", "forge",
+ "forges", "fork", "forks", "fort", "frd", "frds", "freeway", "freewy",
+ "frg", "frgs", "frk", "frks", "frry", "frst", "frt", "frway", "frwy",
+ "fry", "ft", "fwy", "garden", "gardens", "gardn", "gateway", "gatewy",
+ "gatway", "gdn", "gdns", "glen", "glens", "gln", "glns", "grden",
+ "grdn", "grdns", "green", "greens", "grn", "grns", "grov", "grove",
+ "groves", "grv", "grvs", "gtway", "gtwy", "harb", "harbor", "harbors",
+ "harbr", "haven", "havn", "hbr", "hbrs", "height", "heights", "hgts",
+ "highway", "highwy", "hill", "hills", "hiway", "hiwy", "hl", "hllw",
+ "hls", "hollow", "hollows", "holw", "holws", "hrbor", "ht", "hts",
+ "hvn", "hway", "hwy", "inlet", "inlt", "is", "island", "islands",
+ "isle", "isles", "islnd", "islnds", "iss", "jct", "jction", "jctn",
+ "jctns", "jcts", "junction", "junctions", "junctn", "juncton", "key",
+ "keys", "knl", "knls", "knol", "knoll", "knolls", "ky", "kys", "la",
+ "lake", "lakes", "land", "landing", "lane", "lanes", "lck", "lcks",
+ "ldg", "ldge", "lf", "lgt", "lgts", "light", "lights", "lk", "lks",
+ "ln", "lndg", "lndng", "loaf", "lock", "locks", "lodg", "lodge", "loop",
+ "loops", "mall", "manor", "manors", "mdw", "mdws", "meadow", "meadows",
+ "medows", "mews", "mill", "mills", "mission", "missn", "ml", "mls",
+ "mnr", "mnrs", "mnt", "mntain", "mntn", "mntns", "motorway", "mount",
+ "mountain", "mountains", "mountin", "msn", "mssn", "mt", "mtin", "mtn",
+ "mtns", "mtwy", "nck", "neck", "opas", "orch", "orchard", "orchrd",
+ "oval", "overpass", "ovl", "park", "parks", "parkway", "parkways",
+ "parkwy", "pass", "passage", "path", "paths", "pike", "pikes", "pine",
+ "pines", "pk", "pkway", "pkwy", "pkwys", "pky", "pl", "place", "plain",
+ "plaines", "plains", "plaza", "pln", "plns", "plz", "plza", "pne",
+ "pnes", "point", "points", "port", "ports", "pr", "prairie", "prarie",
+ "prk", "prr", "prt", "prts", "psge", "pt", "pts", "rad", "radial",
+ "radiel", "radl", "ramp", "ranch", "ranches", "rapid", "rapids", "rd",
+ "rdg", "rdge", "rdgs", "rds", "real", "rest", "ridge", "ridges", "riv", "river",
+ "rivr", "rnch", "rnchs", "road", "roads", "route", "row", "rpd", "rpds",
+ "rst", "rte", "rue", "run", "rvr", "shl", "shls", "shoal", "shoals",
+ "shoar", "shoars", "shore", "shores", "shr", "shrs", "skwy", "skyway",
+ "smt", "spg", "spgs", "spng", "spngs", "spring", "springs", "sprng",
+ "sprngs", "spur", "spurs", "sq", "sqr", "sqre", "sqrs", "sqs", "squ",
+ "square", "squares", "st", "sta", "station", "statn", "stn", "str",
+ "stra", "strav", "strave", "straven", "stravenue", "stravn", "stream",
+ "street", "streets", "streme", "strm", "strt", "strvn", "strvnue",
+ "sts", "sumit", "sumitt", "summit", "ter", "terr", "terrace",
+ "throughway", "tpk", "tpke", "tr", "trace", "traces", "track", "tracks",
+ "trafficway", "trail", "trails", "trak", "trce", "trfy", "trk", "trks",
+ "trl", "trls", "trnpk", "trpk", "trwy", "tunel", "tunl", "tunls",
+ "tunnel", "tunnels", "tunnl", "turnpike", "turnpk", "un", "underpass",
+ "union", "unions", "uns", "upas", "valley", "valleys", "vally", "vdct",
+ "via", "viadct", "viaduct", "view", "views", "vill", "villag",
+ "village", "villages", "ville", "villg", "villiage", "vis", "vist",
+ "vista", "vl", "vlg", "vlgs", "vlly", "vly", "vlys", "vst", "vsta",
+ "vw", "vws", "walk", "walks", "wall", "way", "ways", "well", "wells",
+ "wl", "wls", "wy", "xing", "xrd",
+ 0,
+};
+
+bool AddressDetector::IsValidLocationName(const Word& word) {
+ using namespace WTF;
+ static HashSet<String> streetNames;
+ if (!streetNames.size()) {
+ const char** suffixes = s_rawStreetSuffixes;
+ while (const char* suffix = *suffixes) {
+ int index = suffix[0] - 'a';
+ streetNames.add(suffix);
+ suffixes++;
+ }
+ }
+ char16 first_letter = base::ToLowerASCII(*word.begin);
+ if (first_letter > 'z' || first_letter < 'a')
+ return false;
+ int index = first_letter - 'a';
+ int length = std::distance(word.begin, word.end);
+ if (*word.end == '.')
+ length--;
+ String value(word.begin, length);
+ return streetNames.contains(value.lower());
+}
diff --git a/Source/WebKit/android/content/address_detector.h b/Source/WebKit/android/content/address_detector.h
new file mode 100644
index 0000000..6dc4ce8
--- /dev/null
+++ b/Source/WebKit/android/content/address_detector.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 CONTENT_RENDERER_ANDROID_ADDRESS_DETECTOR_H_
+#define CONTENT_RENDERER_ANDROID_ADDRESS_DETECTOR_H_
+#pragma once
+
+#include "build/build_config.h" // Needed for OS_ANDROID
+
+#if defined(OS_ANDROID)
+
+#include <vector>
+
+#include "base/string_tokenizer.h"
+#include "base/string_util.h"
+#include "content/content_detector.h"
+
+// Finds a geographical address (currently US only) in the given text string.
+class AddressDetector : public ContentDetector {
+ public:
+ AddressDetector();
+ virtual ~AddressDetector();
+
+ // Implementation of ContentDetector.
+ virtual bool FindContent(const string16::const_iterator& begin,
+ const string16::const_iterator& end,
+ size_t* start_pos,
+ size_t* end_pos) OVERRIDE;
+
+ private:
+ friend class AddressDetectorTest;
+
+ virtual std::string GetContentText(const WebKit::WebRange& range) OVERRIDE;
+ virtual GURL GetIntentURL(const std::string& content_text) OVERRIDE;
+ virtual size_t GetMaximumContentLength() OVERRIDE;
+ virtual bool IsEnabled(const WebKit::WebHitTestInfo& hit_test) OVERRIDE;
+
+ // Internal structs and classes. Required to be visible by the unit tests.
+ struct Word {
+ string16::const_iterator begin;
+ string16::const_iterator end;
+
+ Word() {}
+ Word(const string16::const_iterator& begin_it,
+ const string16::const_iterator& end_it)
+ : begin(begin_it),
+ end(end_it) {
+ DCHECK(begin_it <= end_it);
+ }
+ };
+
+ class HouseNumberParser {
+ public:
+ HouseNumberParser() {}
+
+ bool Parse(const string16::const_iterator& begin,
+ const string16::const_iterator& end,
+ Word* word);
+
+ private:
+ static inline bool IsPreDelimiter(char16 character);
+ static inline bool IsPostDelimiter(char16 character);
+ inline void RestartOnNextDelimiter();
+
+ inline bool CheckFinished(Word* word) const;
+ inline void AcceptChars(size_t num_chars);
+ inline void SkipChars(size_t num_chars);
+ inline void ResetState();
+
+ // Iterators to the beginning, current position and ending of the string
+ // being currently parsed.
+ string16::const_iterator begin_;
+ string16::const_iterator it_;
+ string16::const_iterator end_;
+
+ // Number of digits found in the current result candidate.
+ size_t num_digits_;
+
+ // Number of characters previous to the current iterator that belong
+ // to the current result candidate.
+ size_t result_chars_;
+
+ DISALLOW_COPY_AND_ASSIGN(HouseNumberParser);
+ };
+
+ typedef std::vector<Word> WordList;
+ typedef StringTokenizerT<string16, string16::const_iterator>
+ String16Tokenizer;
+
+ static bool FindStateStartingInWord(WordList* words,
+ size_t state_first_word,
+ size_t* state_last_word,
+ String16Tokenizer* tokenizer,
+ size_t* state_index);
+
+ static bool IsValidLocationName(const Word& word);
+ static bool IsZipValid(const Word& word, size_t state_index);
+ static bool IsZipValidForState(const Word& word, size_t state_index);
+
+ DISALLOW_COPY_AND_ASSIGN(AddressDetector);
+};
+
+#endif // defined(OS_ANDROID)
+
+#endif // CONTENT_RENDERER_ANDROID_ADDRESS_DETECTOR_H_
diff --git a/Source/WebKit/android/content/content_detector.cpp b/Source/WebKit/android/content/content_detector.cpp
new file mode 100644
index 0000000..e423207
--- /dev/null
+++ b/Source/WebKit/android/content/content_detector.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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.
+ */
+
+#include "config.h"
+
+// Magic pretend-to-be-a-chromium-build flags
+#undef WEBKIT_IMPLEMENTATION
+#undef LOG
+
+#include "content/content_detector.h"
+
+#include "public/android/WebDOMTextContentWalker.h"
+#include "public/android/WebHitTestInfo.h"
+
+#include "Document.h"
+#include "Node.h"
+#include "Page.h"
+#include "Settings.h"
+
+using WebKit::WebDOMTextContentWalker;
+using WebKit::WebRange;
+
+ContentDetector::Result ContentDetector::FindTappedContent(
+ const WebKit::WebHitTestInfo& hit_test) {
+ if (!IsEnabled(hit_test))
+ return Result();
+ WebKit::WebRange range = FindContentRange(hit_test);
+ if (range.isNull())
+ return Result();
+
+ std::string text = GetContentText(range);
+ GURL intent_url = GetIntentURL(text);
+ return Result(range, text, intent_url);
+}
+
+WebRange ContentDetector::FindContentRange(
+ const WebKit::WebHitTestInfo& hit_test) {
+ WebDOMTextContentWalker content_walker(hit_test, GetMaximumContentLength());
+ string16 content = content_walker.content();
+ if (content.empty())
+ return WebRange();
+
+ size_t selected_offset = content_walker.hitOffsetInContent();
+ for (size_t start_offset = 0; start_offset < content.length();) {
+ size_t relative_start, relative_end;
+ if (!FindContent(content.begin() + start_offset,
+ content.end(), &relative_start, &relative_end)) {
+ break;
+ } else {
+ size_t content_start = start_offset + relative_start;
+ size_t content_end = start_offset + relative_end;
+ DCHECK(content_end <= content.length());
+
+ if (selected_offset >= content_start && selected_offset < content_end) {
+ WebRange range = content_walker.contentOffsetsToRange(
+ content_start, content_end);
+ DCHECK(!range.isNull());
+ return range;
+ } else {
+ start_offset += relative_end;
+ }
+ }
+ }
+
+ return WebRange();
+}
+
+WebCore::Settings* ContentDetector::GetSettings(const WebKit::WebHitTestInfo& hit_test) {
+ if (!hit_test.node() || !hit_test.node()->document())
+ return 0;
+ return hit_test.node()->document()->page()->settings();
+}
diff --git a/Source/WebKit/android/content/content_detector.h b/Source/WebKit/android/content/content_detector.h
new file mode 100644
index 0000000..270928d
--- /dev/null
+++ b/Source/WebKit/android/content/content_detector.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 CONTENT_RENDERER_ANDROID_CONTENT_DETECTOR_H_
+#define CONTENT_RENDERER_ANDROID_CONTENT_DETECTOR_H_
+#pragma once
+
+#include "build/build_config.h" // Needed for OS_ANDROID
+
+#if defined(OS_ANDROID)
+
+#include "base/string_util.h"
+#include "googleurl/src/gurl.h"
+#include "public/WebRange.h"
+
+namespace WebKit {
+class WebHitTestInfo;
+}
+
+namespace WebCore {
+class Settings;
+}
+
+// Base class for text-based content detectors.
+class ContentDetector {
+ public:
+
+ // Holds the content detection results.
+ struct Result {
+ bool valid; // Flag indicating if the result is valid.
+ WebKit::WebRange range; // Range describing the content boundaries.
+ std::string text; // Processed text of the content.
+ GURL intent_url; // URL of the intent that should process this content.
+
+ Result() : valid(false) {}
+
+ Result(const WebKit::WebRange& range,
+ const std::string& text,
+ const GURL& intent_url)
+ : valid(true),
+ range(range),
+ text(text),
+ intent_url(intent_url) {}
+ };
+
+ virtual ~ContentDetector() {}
+
+ // Returns a WebKit range delimiting the contents found around the tapped
+ // position. If no content is found a null range will be returned.
+ Result FindTappedContent(const WebKit::WebHitTestInfo& hit_test);
+
+ protected:
+ // Parses the input string defined by the begin/end iterators returning true
+ // if the desired content is found. The start and end positions relative to
+ // the input iterators are returned in start_pos and end_pos.
+ // The end position is assumed to be non-inclusive.
+ virtual bool FindContent(const string16::const_iterator& begin,
+ const string16::const_iterator& end,
+ size_t* start_pos,
+ size_t* end_pos) = 0;
+
+ virtual bool IsEnabled(const WebKit::WebHitTestInfo& hit_test) = 0;
+ WebCore::Settings* GetSettings(const WebKit::WebHitTestInfo& hit_test);
+
+ // Extracts and processes the text of the detected content.
+ virtual std::string GetContentText(const WebKit::WebRange& range) = 0;
+
+ // Returns the intent URL that should process the content, if any.
+ virtual GURL GetIntentURL(const std::string& content_text) = 0;
+
+ // Returns the maximum length of text to be extracted around the tapped
+ // position in order to search for content.
+ virtual size_t GetMaximumContentLength() = 0;
+
+ ContentDetector() {}
+ WebKit::WebRange FindContentRange(const WebKit::WebHitTestInfo& hit_test);
+
+ DISALLOW_COPY_AND_ASSIGN(ContentDetector);
+};
+
+#endif // defined(OS_ANDROID)
+
+#endif // CONTENT_RENDERER_ANDROID_CONTENT_DETECTOR_H_
diff --git a/Source/WebKit/android/jni/AndroidHitTestResult.cpp b/Source/WebKit/android/jni/AndroidHitTestResult.cpp
new file mode 100644
index 0000000..a135c42
--- /dev/null
+++ b/Source/WebKit/android/jni/AndroidHitTestResult.cpp
@@ -0,0 +1,269 @@
+/*
+ * 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 "content/address_detector.h"
+#include "content/PhoneEmailDetector.h"
+#include "android/WebHitTestInfo.h"
+#include "Document.h"
+#include "Element.h"
+#include "Frame.h"
+#include "HitTestResult.h"
+#include "KURL.h"
+#include "LayerAndroid.h"
+#include "PlatformString.h"
+#include "Range.h"
+#include "RenderLayer.h"
+#include "RenderLayerBacking.h"
+#include "RenderObject.h"
+#include "WebCoreJni.h"
+#include "WebViewCore.h"
+
+#include <cutils/log.h>
+#include <JNIHelp.h>
+#include <JNIUtility.h>
+
+namespace android {
+
+using namespace WebCore;
+
+static bool gJniInitialized = false;
+static struct {
+ jmethodID m_Init;
+ jfieldID m_LinkUrl;
+ jfieldID m_AnchorText;
+ jfieldID m_ImageUrl;
+ jfieldID m_AltDisplayString;
+ jfieldID m_Title;
+ jfieldID m_Editable;
+ jfieldID m_TouchRects;
+ jfieldID m_TapHighlightColor;
+ jfieldID m_EnclosingParentRects;
+ jfieldID m_HasFocus;
+ jfieldID m_IntentUrl;
+} gHitTestGlue;
+
+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");
+
+ gHitTestGlue.m_Init = env->GetMethodID(hitTestClass, "<init>", "()V");
+ ALOG_ASSERT(gHitTestGlue.m_Init, "Could not find init method on android/webkit/WebViewCore$WebKitHitTest");
+
+ field fields[] = {
+ { hitTestClass, "mTouchRects", "[Landroid/graphics/Rect;", &gHitTestGlue.m_TouchRects },
+ { hitTestClass, "mEditable", "Z", &gHitTestGlue.m_Editable },
+ { hitTestClass, "mLinkUrl", "Ljava/lang/String;", &gHitTestGlue.m_LinkUrl },
+ { hitTestClass, "mIntentUrl", "Ljava/lang/String;", &gHitTestGlue.m_IntentUrl },
+ { hitTestClass, "mAnchorText", "Ljava/lang/String;", &gHitTestGlue.m_AnchorText },
+ { hitTestClass, "mImageUrl", "Ljava/lang/String;", &gHitTestGlue.m_ImageUrl },
+ { hitTestClass, "mAltDisplayString", "Ljava/lang/String;", &gHitTestGlue.m_AltDisplayString },
+ { hitTestClass, "mTitle", "Ljava/lang/String;", &gHitTestGlue.m_Title },
+ { hitTestClass, "mTapHighlightColor", "I", &gHitTestGlue.m_TapHighlightColor },
+ { hitTestClass, "mEnclosingParentRects", "[Landroid/graphics/Rect;", &gHitTestGlue.m_EnclosingParentRects },
+ { hitTestClass, "mHasFocus", "Z", &gHitTestGlue.m_HasFocus },
+ {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(WebViewCore* webViewCore, WebCore::HitTestResult& hitTestResult)
+ : m_webViewCore(webViewCore)
+ , m_hitTestResult(hitTestResult)
+{
+ buildHighlightRects();
+}
+
+void AndroidHitTestResult::setURLElement(Element* element)
+{
+ m_hitTestResult.setURLElement(element);
+ buildHighlightRects();
+}
+
+void AndroidHitTestResult::buildHighlightRects()
+{
+ m_highlightRects.clear();
+ Node* node = m_hitTestResult.URLElement();
+ if (!node || !node->renderer())
+ node = m_hitTestResult.innerNode();
+ if (!node || !node->renderer())
+ return;
+ if (!WebViewCore::nodeIsClickableOrFocusable(node))
+ return;
+ Frame* frame = node->document()->frame();
+ IntPoint frameOffset = m_webViewCore->convertGlobalContentToFrameContent(IntPoint(), frame);
+ RenderObject* renderer = node->renderer();
+ Vector<FloatQuad> quads;
+ if (renderer->isInline())
+ renderer->absoluteFocusRingQuads(quads);
+ if (!quads.size())
+ renderer->absoluteQuads(quads); // No fancy rings, grab a bounding box
+ for (size_t i = 0; i < quads.size(); i++) {
+ IntRect boundingBox = quads[i].enclosingBoundingBox();
+ boundingBox.move(-frameOffset.x(), -frameOffset.y());
+ m_highlightRects.append(boundingBox);
+ }
+}
+
+void AndroidHitTestResult::searchContentDetectors()
+{
+ AddressDetector address;
+ PhoneEmailDetector phoneEmail;
+ Node* node = m_hitTestResult.innerNode();
+ if (!node || !node->isTextNode())
+ return;
+ if (!m_hitTestResult.absoluteLinkURL().isEmpty())
+ return;
+ WebKit::WebHitTestInfo webHitTest(m_hitTestResult);
+ m_searchResult = address.FindTappedContent(webHitTest);
+ if (!m_searchResult.valid) {
+ m_searchResult = phoneEmail.FindTappedContent(webHitTest);
+ }
+ if (m_searchResult.valid) {
+ m_highlightRects.clear();
+ RefPtr<Range> range = (PassRefPtr<Range>) m_searchResult.range;
+ range->textRects(m_highlightRects, true);
+ }
+}
+
+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);
+}
+
+void setStringField(JNIEnv* env, jobject obj, jfieldID field, const GURL& url)
+{
+ jstring jstr = stdStringToJstring(env, url.spec(), false);
+ env->SetObjectField(obj, field, jstr);
+ env->DeleteLocalRef(jstr);
+}
+
+void setRectArray(JNIEnv* env, jobject obj, jfieldID field, Vector<IntRect> &rects)
+{
+ jobjectArray array = intRectVectorToRectArray(env, rects);
+ env->SetObjectField(obj, field, array);
+ env->DeleteLocalRef(array);
+}
+
+// Some helper macros specific to setting hitTest fields
+#define _SET(jtype, jfield, value) env->Set ## jtype ## Field(hitTest, gHitTestGlue.m_ ## jfield, value)
+#define SET_BOOL(jfield, value) _SET(Boolean, jfield, value)
+#define SET_STRING(jfield, value) setStringField(env, hitTest, gHitTestGlue.m_ ## jfield, value)
+#define SET_INT(jfield, value) _SET(Int, jfield, value)
+
+jobject AndroidHitTestResult::createJavaObject(JNIEnv* env)
+{
+ InitJni(env);
+ jclass hitTestClass = env->FindClass("android/webkit/WebViewCore$WebKitHitTest");
+ ALOG_ASSERT(hitTestClass, "Could not find android/webkit/WebViewCore$WebKitHitTest");
+
+ jobject hitTest = env->NewObject(hitTestClass, gHitTestGlue.m_Init);
+ setRectArray(env, hitTest, gHitTestGlue.m_TouchRects, m_highlightRects);
+
+ Vector<IntRect> rects = enclosingParentRects(m_hitTestResult.innerNode());
+ setRectArray(env, hitTest, gHitTestGlue.m_EnclosingParentRects, rects);
+
+ SET_BOOL(Editable, m_hitTestResult.isContentEditable());
+ SET_STRING(LinkUrl, m_hitTestResult.absoluteLinkURL().string());
+ if (m_searchResult.valid)
+ SET_STRING(IntentUrl, m_searchResult.intent_url);
+ SET_STRING(ImageUrl, m_hitTestResult.absoluteImageURL().string());
+ SET_STRING(AltDisplayString, m_hitTestResult.altDisplayString());
+ TextDirection titleTextDirection;
+ SET_STRING(Title, m_hitTestResult.title(titleTextDirection));
+ if (m_hitTestResult.URLElement()) {
+ Element* urlElement = m_hitTestResult.URLElement();
+ SET_STRING(AnchorText, urlElement->innerText());
+ if (urlElement->renderer()) {
+ SET_INT(TapHighlightColor,
+ urlElement->renderer()->style()->tapHighlightColor().rgb());
+ }
+ }
+ Node* focusedNode = m_webViewCore->focusedFrame()->document()->focusedNode();
+ SET_BOOL(HasFocus,
+ focusedNode == m_hitTestResult.URLElement()
+ || focusedNode == m_hitTestResult.innerNode()
+ || focusedNode == m_hitTestResult.innerNonSharedNode());
+
+ env->DeleteLocalRef(hitTestClass);
+
+ return hitTest;
+}
+
+Vector<IntRect> AndroidHitTestResult::enclosingParentRects(Node* node)
+{
+ int count = 0;
+ int lastX = 0;
+ Vector<IntRect> rects;
+
+ while (node && count < 5) {
+ RenderObject* render = node->renderer();
+ if (!render || render->isBody())
+ break;
+
+ IntPoint frameOffset = m_webViewCore->convertGlobalContentToFrameContent(IntPoint(),
+ node->document()->frame());
+ IntRect rect = render->absoluteBoundingBoxRect();
+ rect.move(-frameOffset.x(), -frameOffset.y());
+ if (count == 0 || rect.x() != lastX) {
+ rects.append(rect);
+ lastX = rect.x();
+ count++;
+ }
+
+ node = node->parentNode();
+ }
+
+ return rects;
+}
+
+} /* namespace android */
diff --git a/Source/WebKit/android/RenderSkinRadio.h b/Source/WebKit/android/jni/AndroidHitTestResult.h
index 34101cf..5bbfc6b 100644
--- a/Source/WebKit/android/RenderSkinRadio.h
+++ b/Source/WebKit/android/jni/AndroidHitTestResult.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2006, The Android Open Source Project
+ * 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
@@ -23,39 +23,45 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef RenderSkinRadio_h
-#define RenderSkinRadio_h
+#ifndef AndroidHitTestResult_h
+#define AndroidHitTestResult_h
-#include "PlatformString.h"
+#include "content/content_detector.h"
+#include "Element.h"
+#include "HitTestResult.h"
+#include "IntRect.h"
+#include "wtf/Vector.h"
-class SkCanvas;
+#include <jni.h>
namespace android {
- class AssetManager;
-}
-namespace WebCore {
+class WebViewCore;
-class Node;
-class IntRect;
-
-/* RenderSkin for a radio button or a checkbox
- */
-class RenderSkinRadio
+class AndroidHitTestResult
{
public:
- static void SetDrawableDirectory(String drawableDirectory);
+ AndroidHitTestResult(WebViewCore*, WebCore::HitTestResult&);
+ ~AndroidHitTestResult() {}
+
+ WebCore::HitTestResult& hitTestResult() { return m_hitTestResult; }
+ Vector<WebCore::IntRect>& highlightRects() { return m_highlightRects; }
- // Perform lazy decoding the first time this a radio/checkbox is needed.
- static void Decode();
+ void setURLElement(WebCore::Element* element);
+ void buildHighlightRects();
+ void searchContentDetectors();
- /**
- * Draw the element to the canvas at the specified size and location.
- * param isCheckBox If true, draws a checkbox. Else, draw a radio button.
- */
- static void Draw(SkCanvas* canvas, Node* element, const IntRect&,
- bool isCheckBox);
+ jobject createJavaObject(JNIEnv*);
+
+private:
+ Vector<WebCore::IntRect> enclosingParentRects(WebCore::Node* node);
+
+ WebViewCore* m_webViewCore;
+ WebCore::HitTestResult m_hitTestResult;
+ Vector<WebCore::IntRect> m_highlightRects;
+ ContentDetector::Result m_searchResult;
};
-} // WebCore
-#endif
+} // namespace android
+
+#endif // AndroidHitTestResult_h
diff --git a/Source/WebKit/android/jni/CacheManager.cpp b/Source/WebKit/android/jni/CacheManager.cpp
index f600d00..b34776d 100644
--- a/Source/WebKit/android/jni/CacheManager.cpp
+++ b/Source/WebKit/android/jni/CacheManager.cpp
@@ -25,8 +25,6 @@
#include "config.h"
-#if USE(CHROME_NETWORK_STACK)
-
#include "ChromiumIncludes.h"
#include "WebCache.h"
#include "WebCoreJni.h"
@@ -133,12 +131,10 @@ int registerCacheManager(JNIEnv* env)
{
#ifndef NDEBUG
jclass cacheManager = env->FindClass(javaCacheManagerClass);
- LOG_ASSERT(cacheManager, "Unable to find class");
+ ALOG_ASSERT(cacheManager, "Unable to find class");
env->DeleteLocalRef(cacheManager);
#endif
return jniRegisterNativeMethods(env, javaCacheManagerClass, gCacheManagerMethods, NELEM(gCacheManagerMethods));
}
} // namespace android
-
-#endif // USE(CHROME_NETWORK_STACK)
diff --git a/Source/WebKit/android/jni/CookieManager.cpp b/Source/WebKit/android/jni/CookieManager.cpp
index f8c2dee..5db1e16 100644
--- a/Source/WebKit/android/jni/CookieManager.cpp
+++ b/Source/WebKit/android/jni/CookieManager.cpp
@@ -35,54 +35,35 @@ using namespace net;
namespace android {
-// JNI for android.webkit.CookieManager
-static const char* javaCookieManagerClass = "android/webkit/CookieManager";
+// JNI for android.webkit.CookieManagerClassic
+static const char* javaCookieManagerClass = "android/webkit/CookieManagerClassic";
static bool acceptCookie(JNIEnv*, jobject)
{
-#if USE(CHROME_NETWORK_STACK)
// This is a static method which gets the cookie policy for all WebViews. We
// always apply the same configuration to the contexts for both regular and
// private browsing, so expect the same result here.
bool regularAcceptCookies = WebCookieJar::get(false)->allowCookies();
ASSERT(regularAcceptCookies == WebCookieJar::get(true)->allowCookies());
return regularAcceptCookies;
-#else
- // The Android HTTP stack is implemented Java-side.
- ASSERT_NOT_REACHED();
- return false;
-#endif
}
static jstring getCookie(JNIEnv* env, jobject, jstring url, jboolean privateBrowsing)
{
-#if USE(CHROME_NETWORK_STACK)
GURL gurl(jstringToStdString(env, url));
CookieOptions options;
options.set_include_httponly();
std::string cookies = WebCookieJar::get(privateBrowsing)->cookieStore()->GetCookieMonster()->GetCookiesWithOptions(gurl, options);
return stdStringToJstring(env, cookies);
-#else
- // The Android HTTP stack is implemented Java-side.
- ASSERT_NOT_REACHED();
- return jstring();
-#endif
}
static bool hasCookies(JNIEnv*, jobject, jboolean privateBrowsing)
{
-#if USE(CHROME_NETWORK_STACK)
return WebCookieJar::get(privateBrowsing)->getNumCookiesInDatabase() > 0;
-#else
- // The Android HTTP stack is implemented Java-side.
- ASSERT_NOT_REACHED();
- return false;
-#endif
}
static void removeAllCookie(JNIEnv*, jobject)
{
-#if USE(CHROME_NETWORK_STACK)
WebCookieJar::get(false)->cookieStore()->GetCookieMonster()->DeleteAll(true);
// This will lazily create a new private browsing context. However, if the
// context doesn't already exist, there's no need to create it, as cookies
@@ -94,84 +75,62 @@ static void removeAllCookie(JNIEnv*, jobject)
// The Java code removes cookies directly from the backing database, so we do the same,
// but with a NULL callback so it's asynchronous.
WebCookieJar::get(true)->cookieStore()->GetCookieMonster()->FlushStore(NULL);
-#endif
}
static void removeExpiredCookie(JNIEnv*, jobject)
{
-#if USE(CHROME_NETWORK_STACK)
// This simply forces a GC. The getters delete expired cookies so won't return expired cookies anyway.
WebCookieJar::get(false)->cookieStore()->GetCookieMonster()->GetAllCookies();
WebCookieJar::get(true)->cookieStore()->GetCookieMonster()->GetAllCookies();
-#endif
}
static void removeSessionCookies(WebCookieJar* cookieJar)
{
-#if USE(CHROME_NETWORK_STACK)
CookieMonster* cookieMonster = cookieJar->cookieStore()->GetCookieMonster();
CookieList cookies = cookieMonster->GetAllCookies();
for (CookieList::const_iterator iter = cookies.begin(); iter != cookies.end(); ++iter) {
if (iter->IsSessionCookie())
cookieMonster->DeleteCanonicalCookie(*iter);
}
-#endif
}
static void removeSessionCookie(JNIEnv*, jobject)
{
-#if USE(CHROME_NETWORK_STACK)
removeSessionCookies(WebCookieJar::get(false));
removeSessionCookies(WebCookieJar::get(true));
-#endif
}
static void setAcceptCookie(JNIEnv*, jobject, jboolean accept)
{
-#if USE(CHROME_NETWORK_STACK)
// This is a static method which configures the cookie policy for all
// WebViews, so we configure the contexts for both regular and private
// browsing.
WebCookieJar::get(false)->setAllowCookies(accept);
WebCookieJar::get(true)->setAllowCookies(accept);
-#endif
}
static void setCookie(JNIEnv* env, jobject, jstring url, jstring value, jboolean privateBrowsing)
{
-#if USE(CHROME_NETWORK_STACK)
GURL gurl(jstringToStdString(env, url));
std::string line(jstringToStdString(env, value));
CookieOptions options;
options.set_include_httponly();
WebCookieJar::get(privateBrowsing)->cookieStore()->GetCookieMonster()->SetCookieWithOptions(gurl, line, options);
-#endif
}
static void flushCookieStore(JNIEnv*, jobject)
{
-#if USE(CHROME_NETWORK_STACK)
WebCookieJar::flush();
-#endif
}
static bool acceptFileSchemeCookies(JNIEnv*, jobject)
{
-#if USE(CHROME_NETWORK_STACK)
return WebCookieJar::acceptFileSchemeCookies();
-#else
- // File scheme cookies are always accepted with the Android HTTP stack.
- return true;
-#endif
}
static void setAcceptFileSchemeCookies(JNIEnv*, jobject, jboolean accept)
{
-#if USE(CHROME_NETWORK_STACK)
WebCookieJar::setAcceptFileSchemeCookies(accept);
-#else
- // File scheme cookies are always accepted with the Android HTTP stack.
-#endif
}
static JNINativeMethod gCookieManagerMethods[] = {
@@ -192,7 +151,7 @@ int registerCookieManager(JNIEnv* env)
{
#ifndef NDEBUG
jclass cookieManager = env->FindClass(javaCookieManagerClass);
- LOG_ASSERT(cookieManager, "Unable to find class");
+ ALOG_ASSERT(cookieManager, "Unable to find class");
env->DeleteLocalRef(cookieManager);
#endif
return jniRegisterNativeMethods(env, javaCookieManagerClass, gCookieManagerMethods, NELEM(gCookieManagerMethods));
diff --git a/Source/WebKit/android/jni/DeviceMotionAndOrientationManager.cpp b/Source/WebKit/android/jni/DeviceMotionAndOrientationManager.cpp
index 8beb372..b69c2af 100644
--- a/Source/WebKit/android/jni/DeviceMotionAndOrientationManager.cpp
+++ b/Source/WebKit/android/jni/DeviceMotionAndOrientationManager.cpp
@@ -46,7 +46,7 @@ DeviceMotionAndOrientationManager::DeviceMotionAndOrientationManager(WebViewCore
{
}
-void DeviceMotionAndOrientationManager::useMock()
+void DeviceMotionAndOrientationManager::setUseMock()
{
m_useMock = true;
}
@@ -124,9 +124,9 @@ static WebViewCore* getWebViewCore(JNIEnv* env, jobject webViewCoreObject)
return reinterpret_cast<WebViewCore*>(env->GetIntField(webViewCoreObject, nativeClassField));
}
-static void useMock(JNIEnv* env, jobject, jobject webViewCoreObject)
+static void setUseMock(JNIEnv* env, jobject, jobject webViewCoreObject)
{
- getWebViewCore(env, webViewCoreObject)->deviceMotionAndOrientationManager()->useMock();
+ getWebViewCore(env, webViewCoreObject)->deviceMotionAndOrientationManager()->setUseMock();
}
static void onMotionChange(JNIEnv* env, jobject, jobject webViewCoreObject, bool canProvideX, double x, bool canProvideY, double y, bool canProvideZ, double z, double interval)
@@ -151,7 +151,7 @@ static void onOrientationChange(JNIEnv* env, jobject, jobject webViewCoreObject,
}
static JNINativeMethod gDeviceMotionAndOrientationManagerMethods[] = {
- { "nativeUseMock", "(Landroid/webkit/WebViewCore;)V", (void*) useMock },
+ { "nativeSetUseMock", "(Landroid/webkit/WebViewCore;)V", (void*) setUseMock },
{ "nativeOnMotionChange", "(Landroid/webkit/WebViewCore;ZDZDZDD)V", (void*) onMotionChange },
{ "nativeSetMockOrientation", "(Landroid/webkit/WebViewCore;ZDZDZD)V", (void*) setMockOrientation },
{ "nativeOnOrientationChange", "(Landroid/webkit/WebViewCore;ZDZDZD)V", (void*) onOrientationChange }
@@ -161,7 +161,7 @@ int registerDeviceMotionAndOrientationManager(JNIEnv* env)
{
#ifndef NDEBUG
jclass deviceMotionAndOrientationManager = env->FindClass(javaDeviceMotionAndOrientationManagerClass);
- LOG_ASSERT(deviceMotionAndOrientationManager, "Unable to find class");
+ ALOG_ASSERT(deviceMotionAndOrientationManager, "Unable to find class");
env->DeleteLocalRef(deviceMotionAndOrientationManager);
#endif
diff --git a/Source/WebKit/android/jni/DeviceMotionAndOrientationManager.h b/Source/WebKit/android/jni/DeviceMotionAndOrientationManager.h
index 44463c1..cc6821d 100644
--- a/Source/WebKit/android/jni/DeviceMotionAndOrientationManager.h
+++ b/Source/WebKit/android/jni/DeviceMotionAndOrientationManager.h
@@ -46,7 +46,7 @@ class DeviceMotionAndOrientationManager {
public:
DeviceMotionAndOrientationManager(WebViewCore*);
- void useMock();
+ void setUseMock();
void setMockMotion(PassRefPtr<WebCore::DeviceMotionData>);
void onMotionChange(PassRefPtr<WebCore::DeviceMotionData>);
void setMockOrientation(PassRefPtr<WebCore::DeviceOrientation>);
diff --git a/Source/WebKit/android/jni/GeolocationPermissionsBridge.cpp b/Source/WebKit/android/jni/GeolocationPermissionsBridge.cpp
index a366601..295b347 100755
--- a/Source/WebKit/android/jni/GeolocationPermissionsBridge.cpp
+++ b/Source/WebKit/android/jni/GeolocationPermissionsBridge.cpp
@@ -99,10 +99,10 @@ static JNINativeMethod gGeolocationPermissionsMethods[] = {
int registerGeolocationPermissions(JNIEnv* env)
{
- const char* kGeolocationPermissionsClass = "android/webkit/GeolocationPermissions";
+ const char* kGeolocationPermissionsClass = "android/webkit/GeolocationPermissionsClassic";
#ifndef NDEBUG
jclass geolocationPermissions = env->FindClass(kGeolocationPermissionsClass);
- LOG_ASSERT(geolocationPermissions, "Unable to find class");
+ ALOG_ASSERT(geolocationPermissions, "Unable to find class");
env->DeleteLocalRef(geolocationPermissions);
#endif
diff --git a/Source/WebKit/android/jni/JavaBridge.cpp b/Source/WebKit/android/jni/JavaBridge.cpp
index 68eb367..9f89ccd 100644
--- a/Source/WebKit/android/jni/JavaBridge.cpp
+++ b/Source/WebKit/android/jni/JavaBridge.cpp
@@ -41,9 +41,6 @@
#include "PluginDatabase.h"
#include "Timer.h"
#include "TimerClient.h"
-#ifdef ANDROID_INSTRUMENT
-#include "TimeCounter.h"
-#endif
#include "WebCache.h"
#include "WebCoreJni.h"
@@ -148,15 +145,15 @@ JavaBridge::JavaBridge(JNIEnv* env, jobject obj)
mResolveFilePathForContentUri = env->GetMethodID(clazz, "resolveFilePathForContentUri", "(Ljava/lang/String;)Ljava/lang/String;");
env->DeleteLocalRef(clazz);
- LOG_ASSERT(mSetSharedTimer, "Could not find method setSharedTimer");
- LOG_ASSERT(mStopSharedTimer, "Could not find method stopSharedTimer");
- LOG_ASSERT(mSetCookies, "Could not find method setCookies");
- LOG_ASSERT(mCookies, "Could not find method cookies");
- LOG_ASSERT(mCookiesEnabled, "Could not find method cookiesEnabled");
- LOG_ASSERT(mGetPluginDirectories, "Could not find method getPluginDirectories");
- LOG_ASSERT(mGetPluginSharedDataDirectory, "Could not find method getPluginSharedDataDirectory");
- LOG_ASSERT(mGetKeyStrengthList, "Could not find method getKeyStrengthList");
- LOG_ASSERT(mGetSignedPublicKey, "Could not find method getSignedPublicKey");
+ ALOG_ASSERT(mSetSharedTimer, "Could not find method setSharedTimer");
+ ALOG_ASSERT(mStopSharedTimer, "Could not find method stopSharedTimer");
+ ALOG_ASSERT(mSetCookies, "Could not find method setCookies");
+ ALOG_ASSERT(mCookies, "Could not find method cookies");
+ ALOG_ASSERT(mCookiesEnabled, "Could not find method cookiesEnabled");
+ ALOG_ASSERT(mGetPluginDirectories, "Could not find method getPluginDirectories");
+ ALOG_ASSERT(mGetPluginSharedDataDirectory, "Could not find method getPluginSharedDataDirectory");
+ ALOG_ASSERT(mGetKeyStrengthList, "Could not find method getKeyStrengthList");
+ ALOG_ASSERT(mGetSignedPublicKey, "Could not find method getSignedPublicKey");
JavaSharedClient::SetTimerClient(this);
JavaSharedClient::SetCookieClient(this);
@@ -283,7 +280,7 @@ JavaBridge::getPluginSharedDataDirectory()
void
JavaBridge::setSharedTimerCallback(void (*f)())
{
- LOG_ASSERT(!sSharedTimerFiredCallback || sSharedTimerFiredCallback==f,
+ ALOG_ASSERT(!sSharedTimerFiredCallback || sSharedTimerFiredCallback==f,
"Shared timer callback may already be set or null!");
sSharedTimerFiredCallback = f;
@@ -363,8 +360,8 @@ void JavaBridge::Finalize(JNIEnv* env, jobject obj)
{
JavaBridge* javaBridge = (JavaBridge*)
(env->GetIntField(obj, gJavaBridge_ObjectID));
- LOG_ASSERT(javaBridge, "Finalize should not be called twice for the same java bridge!");
- LOGV("webcore_javabridge::nativeFinalize(%p)\n", javaBridge);
+ ALOG_ASSERT(javaBridge, "Finalize should not be called twice for the same java bridge!");
+ ALOGV("webcore_javabridge::nativeFinalize(%p)\n", javaBridge);
delete javaBridge;
env->SetIntField(obj, gJavaBridge_ObjectID, 0);
}
@@ -373,16 +370,7 @@ void JavaBridge::Finalize(JNIEnv* env, jobject obj)
void JavaBridge::SharedTimerFired(JNIEnv* env, jobject)
{
if (sSharedTimerFiredCallback)
- {
-#ifdef ANDROID_INSTRUMENT
- TimeCounter::start(TimeCounter::SharedTimerTimeCounter);
-#endif
- SkAutoMemoryUsageProbe mup("JavaBridge::sharedTimerFired");
sSharedTimerFiredCallback();
-#ifdef ANDROID_INSTRUMENT
- TimeCounter::record(TimeCounter::SharedTimerTimeCounter, __FUNCTION__);
-#endif
- }
}
void JavaBridge::SetCacheSize(JNIEnv* env, jobject obj, jint bytes)
@@ -481,12 +469,10 @@ void JavaBridge::RemovePackageName(JNIEnv* env, jobject obj, jstring packageName
void JavaBridge::UpdateProxy(JNIEnv* env, jobject obj, jstring newProxy, jstring newExList)
{
-#if USE(CHROME_NETWORK_STACK)
std::string proxy = jstringToStdString(env, newProxy);
std::string exList = jstringToStdString(env, newExList);
WebCache::get(false)->proxy()->UpdateProxySettings(proxy, exList);
WebCache::get(true)->proxy()->UpdateProxySettings(proxy, exList);
-#endif
}
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/JniUtil.cpp b/Source/WebKit/android/jni/JniUtil.cpp
deleted file mode 100644
index ee1e3f9..0000000
--- a/Source/WebKit/android/jni/JniUtil.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2010, 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.
- */
-
-#include "config.h"
-
-#include "ChromiumIncludes.h"
-#include <JNIHelp.h>
-
-namespace android {
-
-static const char* javaJniUtilClass = "android/webkit/JniUtil";
-
-static bool useChromiumHttpStack(JNIEnv*, jobject)
-{
-#if USE(CHROME_NETWORK_STACK)
- return true;
-#else
- return false;
-#endif
-}
-
-static JNINativeMethod gJniUtilMethods[] = {
- { "nativeUseChromiumHttpStack", "()Z", (void*) useChromiumHttpStack },
-};
-
-int registerJniUtil(JNIEnv* env)
-{
-#ifndef NDEBUG
- jclass jniUtil = env->FindClass(javaJniUtilClass);
- LOG_ASSERT(jniUtil, "Unable to find class");
- env->DeleteLocalRef(jniUtil);
-#endif
- return jniRegisterNativeMethods(env, javaJniUtilClass, gJniUtilMethods, NELEM(gJniUtilMethods));
-}
-
-} // namespace android
diff --git a/Source/WebKit/android/jni/MIMETypeRegistry.cpp b/Source/WebKit/android/jni/MIMETypeRegistry.cpp
index cbfef6c..2734aeb 100644
--- a/Source/WebKit/android/jni/MIMETypeRegistry.cpp
+++ b/Source/WebKit/android/jni/MIMETypeRegistry.cpp
@@ -44,11 +44,11 @@ String MIMETypeRegistry::getMIMETypeForExtension(const String& ext)
ASSERT(isMainThread());
JNIEnv* env = JSC::Bindings::getJNIEnv();
jclass mimeClass = env->FindClass("android/webkit/MimeTypeMap");
- LOG_ASSERT(mimeClass, "Could not find class MimeTypeMap");
+ ALOG_ASSERT(mimeClass, "Could not find class MimeTypeMap");
jmethodID mimeTypeFromExtension = env->GetStaticMethodID(mimeClass,
"mimeTypeFromExtension",
"(Ljava/lang/String;)Ljava/lang/String;");
- LOG_ASSERT(mimeTypeFromExtension,
+ ALOG_ASSERT(mimeTypeFromExtension,
"Could not find method mimeTypeFromExtension");
jstring extString = wtfStringToJstring(env, ext);
jobject mimeType = env->CallStaticObjectMethod(mimeClass,
diff --git a/Source/WebKit/android/jni/MockGeolocation.cpp b/Source/WebKit/android/jni/MockGeolocation.cpp
index 1370715..250953f 100755
--- a/Source/WebKit/android/jni/MockGeolocation.cpp
+++ b/Source/WebKit/android/jni/MockGeolocation.cpp
@@ -74,7 +74,7 @@ int registerMockGeolocation(JNIEnv* env)
{
#ifndef NDEBUG
jclass mockGeolocation = env->FindClass(javaMockGeolocationClass);
- LOG_ASSERT(mockGeolocation, "Unable to find class");
+ ALOG_ASSERT(mockGeolocation, "Unable to find class");
env->DeleteLocalRef(mockGeolocation);
#endif
diff --git a/Source/WebKit/android/jni/PicturePile.cpp b/Source/WebKit/android/jni/PicturePile.cpp
new file mode 100644
index 0000000..ccdfa59
--- /dev/null
+++ b/Source/WebKit/android/jni/PicturePile.cpp
@@ -0,0 +1,301 @@
+/*
+ * 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 "PicturePile"
+#define LOG_NDEBUG 1
+
+#include "config.h"
+#include "PicturePile.h"
+
+#include "AndroidLog.h"
+#include "FloatRect.h"
+#include "GraphicsContext.h"
+#include "PlatformGraphicsContextSkia.h"
+#include "SkCanvas.h"
+#include "SkNWayCanvas.h"
+#include "SkPicture.h"
+#include "SkPixelRef.h"
+#include "SkRect.h"
+#include "SkRegion.h"
+
+#define ENABLE_PRERENDERED_INVALS true
+#define MAX_OVERLAP_COUNT 2
+#define MAX_OVERLAP_AREA .7
+
+namespace WebCore {
+
+static SkIRect toSkIRect(const IntRect& rect) {
+ return SkIRect::MakeXYWH(rect.x(), rect.y(), rect.width(), rect.height());
+}
+
+static IntRect extractClipBounds(SkCanvas* canvas, const IntSize& size) {
+ SkRect clip;
+ canvas->getClipBounds(&clip);
+ clip.intersect(0, 0, size.width(), size.height());
+ return enclosingIntRect(clip);
+}
+
+PicturePile::PicturePile(const PicturePile& other)
+ : m_size(other.m_size)
+ , m_pile(other.m_pile)
+ , m_webkitInvals(other.m_webkitInvals)
+{
+}
+
+PicturePile::PicturePile(SkPicture* picture)
+{
+ m_size = IntSize(picture->width(), picture->height());
+ PictureContainer pc(IntRect(0, 0, m_size.width(), m_size.height()));
+ pc.picture = picture;
+ pc.dirty = false;
+ m_pile.append(pc);
+}
+
+void PicturePile::draw(SkCanvas* canvas)
+{
+ /* Loop down recursively, subtracting the previous clip from the SkRegion,
+ * stopping when the SkRegion is empty. This will still draw back-to-front,
+ * but it will clip out anything obscured. For performance reasons we use
+ * the rect bounds of the SkRegion for the clip, so this still can't be
+ * used for translucent surfaces
+ */
+ TRACE_METHOD();
+ IntRect clipBounds = extractClipBounds(canvas, m_size);
+ SkRegion clipRegion(toSkIRect(clipBounds));
+ drawWithClipRecursive(canvas, clipRegion, m_pile.size() - 1);
+}
+
+void PicturePile::clearPrerenders()
+{
+ for (size_t i = 0; i < m_pile.size(); i++)
+ m_pile[i].prerendered.clear();
+}
+
+void PicturePile::drawWithClipRecursive(SkCanvas* canvas, SkRegion& clipRegion,
+ int index)
+{
+ // TODO: Add some debug visualizations of this
+ if (index < 0 || clipRegion.isEmpty())
+ return;
+ PictureContainer& pc = m_pile[index];
+ IntRect intersection = clipRegion.getBounds();
+ intersection.intersect(pc.area);
+ if (pc.picture && !intersection.isEmpty()) {
+ clipRegion.op(intersection, SkRegion::kDifference_Op);
+ drawWithClipRecursive(canvas, clipRegion, index - 1);
+ int saved = canvas->save();
+ canvas->clipRect(intersection);
+ canvas->translate(pc.area.x(), pc.area.y());
+ canvas->drawPicture(*pc.picture);
+ canvas->restoreToCount(saved);
+ } else
+ drawWithClipRecursive(canvas, clipRegion, index - 1);
+}
+
+// Used by WebViewCore
+void PicturePile::invalidate(const IntRect& dirtyRect)
+{
+ // This will typically happen if the document has been resized but we haven't
+ // drawn yet. As the first draw after a size change will do a full inval anyway,
+ // don't bother tracking individual rects
+ // TODO: Instead of clipping here, we should take the invals as given
+ // and when the size changes just inval the deltas. This prevents a full
+ // redraw for a page that grows
+ IntRect inval = dirtyRect;
+ inval.intersect(IntRect(0, 0, m_size.width(), m_size.height()));
+ if (inval.isEmpty()) {
+ ALOGV("Rejecting inval " INT_RECT_FORMAT, INT_RECT_ARGS(dirtyRect));
+ return;
+ }
+ // TODO: Support multiple non-intersecting webkit invals
+ if (m_webkitInvals.size())
+ m_webkitInvals[0].unite(inval);
+ else
+ m_webkitInvals.append(inval);
+}
+
+void PicturePile::setSize(const IntSize& size)
+{
+ if (m_size == size)
+ return;
+ m_size = size;
+ // TODO: See above about just adding invals for new content
+ m_pile.clear();
+ m_webkitInvals.clear();
+ if (!size.isEmpty()) {
+ IntRect area(0, 0, size.width(), size.height());
+ m_webkitInvals.append(area);
+ m_pile.append(area);
+ }
+}
+
+void PicturePile::updatePicturesIfNeeded(PicturePainter* painter)
+{
+ applyWebkitInvals();
+ for (size_t i = 0; i < m_pile.size(); i++) {
+ PictureContainer& pc = m_pile[i];
+ if (pc.dirty)
+ updatePicture(painter, pc);
+ }
+}
+
+void PicturePile::updatePicture(PicturePainter* painter, PictureContainer& pc)
+{
+ /* The ref counting here is a bit unusual. What happens is begin/end recording
+ * will ref/unref the recording canvas. However, 'canvas' might be pointing
+ * at an SkNWayCanvas instead of the recording canvas, which needs to be
+ * unref'd. Thus what we do is ref the recording canvas so that we can
+ * always unref whatever canvas we have at the end.
+ */
+ TRACE_METHOD();
+ SkPicture* picture = new SkPicture();
+ SkCanvas* canvas = picture->beginRecording(pc.area.width(), pc.area.height(),
+ SkPicture::kUsePathBoundsForClip_RecordingFlag);
+ SkSafeRef(canvas);
+ canvas->translate(-pc.area.x(), -pc.area.y());
+ IntRect drawArea = pc.area;
+ if (pc.prerendered.get()) {
+ SkCanvas* prerender = painter->createPrerenderCanvas(pc.prerendered.get());
+ if (!prerender) {
+ ALOGV("Failed to create prerendered for " INT_RECT_FORMAT,
+ INT_RECT_ARGS(pc.prerendered->area));
+ pc.prerendered.clear();
+ } else {
+ drawArea.unite(pc.prerendered->area);
+ SkNWayCanvas* nwayCanvas = new SkNWayCanvas(drawArea.width(), drawArea.height());
+ nwayCanvas->translate(-drawArea.x(), -drawArea.y());
+ nwayCanvas->addCanvas(canvas);
+ nwayCanvas->addCanvas(prerender);
+ SkSafeUnref(canvas);
+ SkSafeUnref(prerender);
+ canvas = nwayCanvas;
+ }
+ }
+ WebCore::PlatformGraphicsContextSkia pgc(canvas);
+ WebCore::GraphicsContext gc(&pgc);
+ ALOGV("painting picture: " INT_RECT_FORMAT, INT_RECT_ARGS(drawArea));
+ painter->paintContents(&gc, drawArea);
+ SkSafeUnref(canvas);
+ picture->endRecording();
+
+ SkSafeUnref(pc.picture);
+ pc.picture = picture;
+ pc.dirty = false;
+}
+
+void PicturePile::reset()
+{
+ m_size = IntSize(0,0);
+ m_pile.clear();
+ m_webkitInvals.clear();
+}
+
+void PicturePile::applyWebkitInvals()
+{
+ m_dirtyRegion.setEmpty();
+ if (!m_webkitInvals.size())
+ return;
+ // Build the invals (TODO: Support multiple inval regions)
+ IntRect inval = m_webkitInvals[0];
+ m_dirtyRegion.setRect(toSkIRect(inval));
+ for (size_t i = 1; i < m_webkitInvals.size(); i++) {
+ inval.unite(m_webkitInvals[i]);
+ m_dirtyRegion.op(toSkIRect(m_webkitInvals[i]), SkRegion::kUnion_Op);
+ }
+ m_webkitInvals.clear();
+ ALOGV("Webkit inval: " INT_RECT_FORMAT, INT_RECT_ARGS(inval));
+ if (inval.isEmpty())
+ return;
+
+ // Find the overlaps
+ Vector<int> overlaps;
+ for (size_t i = 0; i < m_pile.size(); i++) {
+ PictureContainer& pc = m_pile[i];
+ if (pc.area.contains(inval)) {
+ if (pc.dirty) {
+ ALOGV("Found already dirty intersection");
+ return;
+ }
+ if (pc.area == inval) {
+ appendToPile(inval);
+ return;
+ }
+ // Don't count the base surface as an overlap
+ if (pc.area.size() != m_size)
+ overlaps.append(i);
+ } else if (pc.area.intersects(inval))
+ overlaps.append(i);
+ }
+
+ if (overlaps.size() >= MAX_OVERLAP_COUNT) {
+ ALOGV("Exceeds overlap count");
+ IntRect overlap = inval;
+ for (int i = (int) overlaps.size() - 1; i >= 0; i--) {
+ overlap.unite(m_pile[overlaps[i]].area);
+ m_pile.remove(overlaps[i]);
+ }
+ float overlapArea = overlap.width() * overlap.height();
+ float totalArea = m_size.width() * m_size.height();
+ if (overlapArea / totalArea > MAX_OVERLAP_AREA)
+ overlap = IntRect(0, 0, m_size.width(), m_size.height());
+ appendToPile(overlap, inval);
+ return;
+ }
+
+ // Append!
+ appendToPile(inval);
+}
+
+void PicturePile::appendToPile(const IntRect& inval, const IntRect& originalInval)
+{
+ ALOGV("Adding inval " INT_RECT_FORMAT " for original inval " INT_RECT_FORMAT,
+ INT_RECT_ARGS(inval), INT_RECT_ARGS(originalInval));
+ // Remove any entries this obscures
+ for (int i = (int) m_pile.size() - 1; i >= 0; i--) {
+ if (inval.contains(m_pile[i].area))
+ m_pile.remove(i);
+ }
+ PictureContainer container(inval);
+ if (ENABLE_PRERENDERED_INVALS) {
+ container.prerendered = PrerenderedInval::create(originalInval.isEmpty()
+ ? inval : originalInval);
+ }
+ m_pile.append(container);
+}
+
+PrerenderedInval* PicturePile::prerenderedInvalForArea(const IntRect& area)
+{
+ for (int i = (int) m_pile.size() - 1; i >= 0; i--) {
+ if (m_pile[i].area.intersects(area)) {
+ RefPtr<PrerenderedInval> inval = m_pile[i].prerendered;
+ if (inval.get() && inval->area.contains(area))
+ return inval.get();
+ return 0;
+ }
+ }
+ return 0;
+}
+
+} // namespace WebCore
diff --git a/Source/WebKit/android/jni/PicturePile.h b/Source/WebKit/android/jni/PicturePile.h
new file mode 100644
index 0000000..b28a792
--- /dev/null
+++ b/Source/WebKit/android/jni/PicturePile.h
@@ -0,0 +1,121 @@
+/*
+ * 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 PicturePile_h
+#define PicturePile_h
+
+#include "IntRect.h"
+#include "IntSize.h"
+#include "PrerenderedInval.h"
+#include "SkBitmap.h"
+#include "SkRegion.h"
+#include "SkRefCnt.h"
+
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/ThreadSafeRefCounted.h>
+#include <wtf/Vector.h>
+
+class SkPicture;
+class SkCanvas;
+
+namespace WebCore {
+
+class GraphicsContext;
+
+class PicturePainter {
+public:
+ virtual void paintContents(GraphicsContext* gc, IntRect& dirty) = 0;
+ virtual SkCanvas* createPrerenderCanvas(PrerenderedInval* prerendered)
+ {
+ return 0;
+ }
+ virtual ~PicturePainter() {}
+};
+
+class PictureContainer {
+public:
+ SkPicture* picture;
+ IntRect area;
+ bool dirty;
+ RefPtr<PrerenderedInval> prerendered;
+
+ PictureContainer(const IntRect& area)
+ : picture(0)
+ , area(area)
+ , dirty(true)
+ {}
+
+ PictureContainer(const PictureContainer& other)
+ : picture(other.picture)
+ , area(other.area)
+ , dirty(other.dirty)
+ , prerendered(other.prerendered)
+ {
+ SkSafeRef(picture);
+ }
+
+ ~PictureContainer()
+ {
+ SkSafeUnref(picture);
+ }
+};
+
+class PicturePile {
+public:
+ PicturePile() {}
+ PicturePile(const PicturePile& other);
+ PicturePile(SkPicture* picture);
+
+ const IntSize& size() { return m_size; }
+
+ void clearPrerenders();
+
+ // used by PicturePileLayerContents
+ void draw(SkCanvas* canvas);
+
+ // Used by WebViewCore
+ void invalidate(const IntRect& dirtyRect);
+ void setSize(const IntSize& size);
+ void updatePicturesIfNeeded(PicturePainter* painter);
+ void reset();
+ SkRegion& dirtyRegion() { return m_dirtyRegion; }
+ PrerenderedInval* prerenderedInvalForArea(const IntRect& area);
+
+private:
+ void applyWebkitInvals();
+ void updatePicture(PicturePainter* painter, PictureContainer& container);
+ void appendToPile(const IntRect& inval, const IntRect& originalInval = IntRect());
+ void drawWithClipRecursive(SkCanvas* canvas, SkRegion& clipRegion, int index);
+
+ IntSize m_size;
+ Vector<PictureContainer> m_pile;
+ Vector<IntRect> m_webkitInvals;
+ SkRegion m_dirtyRegion;
+};
+
+} // namespace android
+
+#endif // PicturePile_h
diff --git a/Source/WebKit/android/jni/PictureSet.cpp b/Source/WebKit/android/jni/PictureSet.cpp
deleted file mode 100644
index 4d9d16c..0000000
--- a/Source/WebKit/android/jni/PictureSet.cpp
+++ /dev/null
@@ -1,1236 +0,0 @@
-/*
- * Copyright 2008, 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_NDEBUG 0
-#define LOG_TAG "pictureset"
-
-//#include <config.h>
-#include "CachedPrefix.h"
-#include "android_graphics.h"
-#include "PictureSet.h"
-#include "SkBounder.h"
-#include "SkCanvas.h"
-#include "SkPicture.h"
-#include "SkRect.h"
-#include "SkRegion.h"
-#include "SkStream.h"
-#include "TimeCounter.h"
-
-#define MAX_DRAW_TIME 100
-#define MIN_SPLITTABLE 400
-#define MAX_ADDITIONAL_AREA 0.65
-#define MAX_ADDITIONAL_PICTURES 32
-
-#define BUCKET_SIZE 1024
-#define MAX_BUCKET_COUNT_X 16
-#define MAX_BUCKET_COUNT_Y 64
-
-#include <wtf/CurrentTime.h>
-
-#include <cutils/log.h>
-#include <wtf/text/CString.h>
-
-#undef XLOGC
-#define XLOGC(...) android_printLog(ANDROID_LOG_DEBUG, "PictureSet", __VA_ARGS__)
-
-#ifdef DEBUG
-
-#undef XLOG
-#define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "PictureSet", __VA_ARGS__)
-
-#else
-
-#undef XLOG
-#define XLOG(...)
-
-#endif // DEBUG
-
-#if PICTURE_SET_DEBUG
-class MeasureStream : public SkWStream {
-public:
- MeasureStream() : mTotal(0) {}
- virtual bool write(const void* , size_t size) {
- mTotal += size;
- return true;
- }
- size_t mTotal;
-};
-#endif
-
-namespace android {
-
-PictureSet::PictureSet() :
-#ifdef FAST_PICTURESET
- mBucketSizeX(BUCKET_SIZE), mBucketSizeY(BUCKET_SIZE),
- mBucketCountX(0), mBucketCountY(0),
-#endif
- mHeight(0), mWidth(0)
-{
- setDimensions(0, 0);
- mBaseArea = mAdditionalArea = 0;
-}
-
-PictureSet::PictureSet(SkPicture* picture) :
-#ifdef FAST_PICTURESET
- mBucketSizeX(BUCKET_SIZE), mBucketSizeY(BUCKET_SIZE),
- mBucketCountX(0), mBucketCountY(0),
-#endif
- mHeight(0), mWidth(0)
-{
- mBaseArea = mAdditionalArea = 0;
- if (!picture) {
- setDimensions(0, 0);
- return;
- }
- setDimensions(picture->width(), picture->height());
- mBaseArea = mWidth * mHeight;
-#ifdef FAST_PICTURESET
- SkIRect area;
- area.set(0, 0, mWidth, mHeight);
- splitAdd(area);
- WTF::Vector<Bucket*>* buckets = bucketsToUpdate();
- for (unsigned int i = 0; i < buckets->size(); i++) {
- Bucket* bucket = (*buckets)[i];
- for (unsigned int j = 0; j < bucket->size(); j++) {
- BucketPicture& bucketPicture = (*bucket)[j];
- const SkIRect& inval = bucketPicture.mRealArea;
- SkPicture *splitPicture = new SkPicture();
- SkCanvas *canvas = splitPicture->beginRecording(
- inval.width(), inval.height(),
- SkPicture::kUsePathBoundsForClip_RecordingFlag);
- canvas->translate(-inval.fLeft, -inval.fTop);
- picture->draw(canvas);
- splitPicture->endRecording();
- SkSafeUnref(bucketPicture.mPicture);
- bucketPicture.mPicture = splitPicture;
- }
- }
- buckets->clear();
-#else
- Pictures pictureAndBounds;
- pictureAndBounds.mPicture = picture;
- SkSafeRef(pictureAndBounds.mPicture);
- pictureAndBounds.mEmpty = false;
- pictureAndBounds.mArea.setRect(0, 0, mWidth, mHeight);
- pictureAndBounds.mSplit = false;
- pictureAndBounds.mBase = true;
- pictureAndBounds.mElapsed = 0;
- pictureAndBounds.mWroteElapsed = false;
- mPictures.append(pictureAndBounds);
-#endif // FAST_PICTURESET
-}
-
-PictureSet::~PictureSet()
-{
- clear();
-}
-
-#ifdef FAST_PICTURESET
-#else
-void PictureSet::add(const Pictures* temp)
-{
- Pictures pictureAndBounds = *temp;
- SkSafeRef(pictureAndBounds.mPicture);
- pictureAndBounds.mWroteElapsed = false;
- mPictures.append(pictureAndBounds);
-}
-#endif // FAST_PICTURESET
-
-void PictureSet::add(const SkRegion& area, SkPicture* picture,
- uint32_t elapsed, bool split)
-{
- if (area.isRect()) {
-#ifdef FAST_PICTURESET
- splitAdd(area.getBounds());
-#else
- add(area, picture, elapsed, split, false);
-#endif // FAST_PICTURESET
- } else {
- SkRegion::Iterator cliperator(area);
- while (!cliperator.done()) {
- SkIRect ir = cliperator.rect();
-#ifdef FAST_PICTURESET
- splitAdd(ir);
-#else
- SkRegion newArea;
- newArea.setRect(ir);
- add(newArea, picture, elapsed, split, false);
-#endif // FAST_PICTURESET
- cliperator.next();
- }
- }
-}
-
-#ifdef FAST_PICTURESET
-
-Bucket* PictureSet::getBucket(int x, int y)
-{
- // only create buckets for valid, positive coordinates, ignore and return
- // NULL otherwise
- if (x < 0 || y < 0)
- return 0;
-
- BucketPosition position(x+1, y+1);
- if (!mBuckets.contains(position)) {
- XLOG("PictureSet::getBucket(%d, %d) adding new bucket", x, y);
- Bucket* bucket = new Bucket();
- mBuckets.add(position, bucket);
- }
- return mBuckets.get(position);
-}
-
-void PictureSet::displayBucket(Bucket* bucket)
-{
- BucketPicture* first = bucket->begin();
- BucketPicture* last = bucket->end();
- for (BucketPicture* current = first; current != last; current++) {
- XLOGC("- in %x, bucketPicture %d,%d,%d,%d - %dx%d, picture: %x, base: %x",
- bucket,
- current->mArea.fLeft,
- current->mArea.fTop,
- current->mArea.fRight,
- current->mArea.fBottom,
- current->mArea.width(),
- current->mArea.height(),
- current->mPicture,
- current->mBase);
- }
-}
-
-void PictureSet::displayBuckets()
-{
- XLOGC("\n\n****** DISPLAY BUCKETS ON PictureSet %x ******", this);
- for (BucketMap::iterator iter = mBuckets.begin(); iter != mBuckets.end(); ++iter) {
- XLOGC("\n*** Bucket %x for %d, %d", iter->second, iter->first.first, iter->first.second);
- displayBucket(iter->second);
- }
- XLOGC("\n****** END OF DISPLAY BUCKETS ******\n\n");
-}
-
-// When we receive an inval in a Bucket, we try to see if we intersect with
-// existing invals/pictures in the Bucket.
-void PictureSet::addToBucket(Bucket* bucket, int dx, int dy, SkIRect& rect)
-{
- bool resetBase = false;
-
- SkIRect totalArea = rect;
- BucketPicture* first = bucket->begin();
- BucketPicture* last = bucket->end();
-
- // If the inval covers a large area of the base inval, let's repaint the
- // entire bucket.
- if (rect.width() * rect.height() > MAX_ADDITIONAL_AREA * mBucketSizeX * mBucketSizeY)
- resetBase = true;
-
- // let's gather all the BucketPicture intersecting with the new invalidated
- // area, collect their area and remove their picture
- for (BucketPicture* current = first; current != last; current++) {
- bool remove = resetBase;
- bool intersect = false;
-
- if (!remove)
- intersect = SkIRect::Intersects(current->mArea, rect);
- // If the current picture is not a base, and we intersect, remove it
- if (!remove && !current->mBase && intersect)
- remove = true;
- // If the current picture is a base, check if the new inval completely
- // contains the base, and if so remove it.
- if (!remove && current->mBase && rect.contains(current->mArea))
- remove = true;
- // If the current picture is a base and it intersects,
- // also check that it fully covers the bucket -- otherwise,
- // let's aggregate it with the new inval.
- if (!remove && current->mBase && intersect
- && (current->mArea.width() < mBucketSizeX || current->mArea.height() < mBucketSizeY)) {
- remove = true;
- }
-
- if (remove) {
- totalArea.join(current->mArea);
- current->mBase = false;
- current->mArea.setEmpty();
- SkSafeUnref(current->mPicture);
- current->mPicture = 0;
- }
- }
-
- // Now, let's add the new BucketPicture to the list, with the correct
- // area that needs to be repainted
- SkRegion region;
- SkIRect area = totalArea;
- area.offset(dx, dy);
- BucketPicture picture = { 0, totalArea, area, false };
-
- bucket->append(picture);
-
- first = bucket->begin();
- last = bucket->end();
-
- bool clearUp = false;
- if (last - first > MAX_ADDITIONAL_PICTURES) {
- // too many pictures in the bucket, let's collapse
- clearUp = true;
- }
-
- float bucketBaseArea = 0;
- float bucketAdditionalArea = 0;
- for (BucketPicture* current = first; current != last; current++) {
- float area = current->mArea.width() * current->mArea.height();
- if (current->mBase)
- bucketBaseArea += area;
- else
- bucketAdditionalArea += area;
- }
-
- if (bucketBaseArea > 0 && bucketBaseArea * MAX_ADDITIONAL_AREA <= bucketAdditionalArea) {
- // additional area too large, not worth maintaining
- clearUp = true;
- }
-
- // To clear things up, we just need to mark the pictures' area as empty
- // We only keep the base surface.
- if (clearUp) {
- for (BucketPicture* current = first; current != last; current++) {
- if (!current->mBase)
- current->mArea.setEmpty();
- SkSafeUnref(current->mPicture);
- current->mPicture = 0;
- }
- }
-
- // let's do a pass to collapse out empty areas
- BucketPicture* writer = first;
- for (BucketPicture* current = first; current != last; current++) {
- if (current && current->mArea.isEmpty())
- continue;
- *writer++ = *current;
- }
-
- bucket->shrink(writer - first);
-
- // let's recompute the bases
- first = bucket->begin();
- last = bucket->end();
- SkRegion drawn;
- drawn.setEmpty();
- for (BucketPicture* current = first; current != last; current++) {
- if (drawn.contains(current->mArea) == false) {
- current->mBase = true;
- }
- drawn.op(current->mArea, SkRegion::kUnion_Op);
- }
-}
-
-void PictureSet::gatherBucketsForArea(WTF::Vector<Bucket*>& list, const SkIRect& rect)
-{
- XLOG("\n--- gatherBucketsForArea for rect %d, %d, %d, %d (%d x %d)",
- rect.fLeft, rect.fTop, rect.fRight, rect.fBottom,
- rect.width(), rect.height());
-
- if (!mBucketSizeX || !mBucketSizeY) {
- XLOGC("PictureSet::gatherBucketsForArea() called with bad bucket size: x=%d y=%d",
- mBucketSizeX, mBucketSizeY);
- return;
- }
-
- int x = rect.fLeft;
- int y = rect.fTop;
- int firstTileX = rect.fLeft / mBucketSizeX;
- int firstTileY = rect.fTop / mBucketSizeY;
- int lastTileX = rect.fRight / mBucketSizeX;
- int lastTileY = rect.fBottom / mBucketSizeY;
-
- for (int i = firstTileX; i <= lastTileX; i++) {
- for (int j = firstTileY; j <= lastTileY; j++) {
- Bucket* bucket = getBucket(i, j);
- XLOG("gather bucket %x for %d, %d", bucket, i+1, j+1);
- if (bucket)
- list.append(bucket);
- }
- }
-}
-
-// When we receive a new inval rect, we first find the Buckets that intersect
-// with it; then we split the original inval into a serie of invals (one for
-// each Bucket we intersect with). We then send that inval to the Bucket.
-void PictureSet::splitAdd(const SkIRect& rect)
-{
- XLOG("\n--- splitAdd for rect %d, %d, %d, %d (%d x %d)",
- rect.fLeft, rect.fTop, rect.fRight, rect.fBottom,
- rect.width(), rect.height());
-
- if (!mBucketSizeX || !mBucketSizeY) {
- XLOGC("PictureSet::splitAdd() called with bad bucket size: x=%d y=%d",
- mBucketSizeX, mBucketSizeY);
- return;
- }
-
- // TODO: reuse gatherBucketsForArea() (change Bucket to be a class)
- int x = rect.fLeft;
- int y = rect.fTop;
- int firstTileX = rect.fLeft / mBucketSizeX;
- int firstTileY = rect.fTop / mBucketSizeY;
- int lastTileX = rect.fRight / mBucketSizeX;
- int lastTileY = rect.fBottom / mBucketSizeY;
-
- XLOG("--- firstTile(%d, %d) lastTile(%d, %d)",
- firstTileX, firstTileY,
- lastTileX, lastTileY);
-
- for (int i = firstTileX; i <= lastTileX; i++) {
- for (int j = firstTileY; j <= lastTileY; j++) {
- Bucket* bucket = getBucket(i, j);
- if (!bucket)
- continue;
-
- SkIRect newRect;
- int deltaX = i * mBucketSizeX;
- int deltaY = j * mBucketSizeY;
- int left = (i == firstTileX) ? rect.fLeft - deltaX : 0;
- int top = (j == firstTileY) ? rect.fTop - deltaY : 0;
- int right = (i == lastTileX) ? rect.fRight % mBucketSizeX : mBucketSizeX;
- int bottom = (j == lastTileY) ? rect.fBottom % mBucketSizeY : mBucketSizeY;
-
- newRect.set(left, top, right, bottom);
- addToBucket(bucket, deltaX, deltaY, newRect);
- mUpdatedBuckets.append(bucket);
- }
- }
-
- XLOG("--- splitAdd DONE\n");
-}
-
-#endif // FAST_PICTURESET
-
-// This function is used to maintain the list of Pictures.
-// Pictures contain an SkPicture covering a specific area; some
-// Pictures are "base" Pictures -- i.e. there is no Pictures
-// underneath them.
-// The idea here is to keep a balance between the number of Pictures
-// we have (more Pictures slow us down) and the area of Pictures that
-// need to be repainted (obviously, smaller areas are better).
-// To do so, we try to not update/repaint the base pictures -- by
-// construction, they usually cover a large area (the entire page).
-// We only reset a base picture if the new invalidated area entirely
-// contains it.
-// Most of the time we thus work on smaller pictures on top of the
-// base ones; We compute the total area of all pictures intersecting
-// with the passed invalidated area (as they would need to be invalidated),
-// and use that as the basis for the correct area we want to invalidate
-// (we then can simply delete the pictures we intersect with).
-// In addition, we do a couple of things to limit the total number of pictures
-// we keep in the list:
-// - if the total area of additional textures reach 65% of the base pictures,
-// we delete the additional pictures and mark the base pictures as
-// needing a full repaint
-// - we limit the number of pictures to 32 -- above that, we do the same
-// things (deleting additional pictures + full repaint of base pictures)
-#ifdef FAST_PICTURESET
-#else
-void PictureSet::add(const SkRegion& area, SkPicture* picture,
- uint32_t elapsed, bool split, bool empty)
-{
- bool checkForNewBases = false;
-
- Pictures* first = mPictures.begin();
- Pictures* last = mPictures.end();
-#ifdef DEBUG
- XLOG("--- before adding the new inval ---");
- for (Pictures* working = mPictures.begin(); working != mPictures.end(); working++) {
- SkIRect currentArea = working->mArea.getBounds();
- XLOG("picture %d (%d, %d, %d, %d - %d x %d) (isRect? %c) base: %c",
- working - first,
- currentArea.fLeft, currentArea.fTop, currentArea.fRight, currentArea.fBottom,
- currentArea.width(), currentArea.height(),
- working->mArea.isRect() ? 'Y' : 'N',
- working->mBase ? 'Y' : 'N');
- }
- XLOG("----------------------------------");
-#endif
-
- // let's gather all the Pictures intersecting with the new invalidated
- // area, collect their area and remove their picture
- SkIRect totalArea = area.getBounds();
- for (Pictures* working = first; working != last; working++) {
- SkIRect inval = area.getBounds();
- bool remove = false;
- if (!working->mBase && working->mArea.intersects(inval))
- remove = true;
- if (working->mBase) {
- SkIRect baseArea = working->mArea.getBounds();
- if (area.contains(baseArea)) {
- remove = true;
- checkForNewBases = true;
- }
- }
-
- if (remove) {
- SkIRect currentArea = working->mArea.getBounds();
- if (working->mBase)
- mBaseArea -= currentArea.width() * currentArea.height();
- else
- mAdditionalArea -= currentArea.width() * currentArea.height();
-
- totalArea.join(currentArea);
- XLOG("picture %d (%d, %d, %d, %d - %d x %d) (isRect? %c) intersects with the new inval area (%d, %d, %d, %d - %d x %d) (isRect? %c, we remove it",
- working - first,
- currentArea.fLeft, currentArea.fTop, currentArea.fRight, currentArea.fBottom,
- currentArea.width(), currentArea.height(),
- working->mArea.isRect() ? 'Y' : 'N',
- inval.fLeft, inval.fTop, inval.fRight, inval.fBottom,
- inval.width(), inval.height(),
- area.isRect() ? 'Y' : 'N');
- working->mArea.setEmpty();
- SkSafeUnref(working->mPicture);
- working->mPicture = 0;
- }
- }
-
- // Now we can add the new Picture to the list, with the correct area
- // that need to be repainted
- SkRegion collect;
- collect.setRect(totalArea);
- Pictures pictureAndBounds = {collect, 0, collect.getBounds(),
- elapsed, split, false, false, empty};
-
-#ifdef FAST_PICTURESET
- if (mPictures.size() == 0)
- checkForNewBases = true;
-#endif
-
- mPictures.append(pictureAndBounds);
- mAdditionalArea += totalArea.width() * totalArea.height();
- last = mPictures.end();
- first = mPictures.begin();
-
- // Then, let's see if we have to clear up the pictures in order to keep
- // the total number of pictures under our limit
- bool clearUp = false;
- if (last - first > MAX_ADDITIONAL_PICTURES) {
- XLOG("--- too many pictures, only keeping the bases : %d", last - first);
- clearUp = true;
- }
-
- if (!clearUp) {
- if (mBaseArea > 0 && mBaseArea * MAX_ADDITIONAL_AREA <= mAdditionalArea) {
- XLOG("+++ the sum of the additional area is > %.2f\% of the base Area (%.2f (%.2f) <= %.2f",
- MAX_ADDITIONAL_AREA * 100, mBaseArea * 0.65, mBaseArea, mAdditionalArea);
- clearUp = true;
- }
- }
-
- if (clearUp) {
- for (Pictures* working = mPictures.begin(); working != mPictures.end(); working++) {
- if (!working->mBase)
- working->mArea.setEmpty();
- SkSafeUnref(working->mPicture);
- working->mPicture = 0;
- }
- }
-
-#ifdef DEBUG
- XLOG("--- after adding the new inval, but before collapsing ---");
- for (Pictures* working = mPictures.begin(); working != mPictures.end(); working++) {
- SkIRect currentArea = working->mArea.getBounds();
- XLOG("picture %d (%d, %d, %d, %d - %d x %d) (isRect? %c) base: %c",
- working - first,
- currentArea.fLeft, currentArea.fTop, currentArea.fRight, currentArea.fBottom,
- currentArea.width(), currentArea.height(),
- working->mArea.isRect() ? 'Y' : 'N',
- working->mBase ? 'Y' : 'N');
- }
- XLOG("----------------------------------");
- XLOG("let's collapse...");
-#endif
-
- // Finally, let's do a pass to collapse out empty regions
- Pictures* writer = first;
- for (Pictures* working = first; working != last; working++) {
- if (working && working->mArea.isEmpty())
- continue;
- *writer++ = *working;
- }
- XLOG("shiking of %d elements", writer - first);
- mPictures.shrink(writer - first);
-
-#ifdef DEBUG
- XLOG("--- after adding the new inval ---");
- for (Pictures* working = mPictures.begin(); working != mPictures.end(); working++) {
- SkIRect currentArea = working->mArea.getBounds();
- XLOG("picture %d (%d, %d, %d, %d - %d x %d) (isRect? %c) base: %c picture %x",
- working - first,
- currentArea.fLeft, currentArea.fTop, currentArea.fRight, currentArea.fBottom,
- currentArea.width(), currentArea.height(),
- working->mArea.isRect() ? 'Y' : 'N',
- working->mBase ? 'Y' : 'N', working->mPicture);
- }
- XLOG("----------------------------------");
-#endif
-
- // Base pictures might have been removed/added -- let's recompute them
- SkRegion drawn;
- if (checkForNewBases) {
- drawn.setEmpty();
- Pictures* last = mPictures.end();
- XLOG("checkForNewBases...");
- for (Pictures* working = mPictures.begin(); working != last; working++) {
- SkRegion& area = working->mArea;
- const SkIRect& a = area.getBounds();
- if (drawn.contains(working->mArea) == false) {
- working->mBase = true;
- float area = a.width() * a.height();
- mBaseArea += area;
- mAdditionalArea -= area;
- }
- drawn.op(working->mArea, SkRegion::kUnion_Op);
- }
- }
-}
-#endif // FAST_PICTURESET
-
-void PictureSet::setDimensions(int width, int height, SkRegion* inval)
-{
- // Note that setDimensions() may be called by our ctor and should behave accordingly
- if (mWidth == width && mHeight == height)
- return;
- DBG_SET_LOGD("%p old:(w=%d,h=%d) new:(w=%d,h=%d)", this,
- mWidth, mHeight, width, height);
- bool clearCache = false;
- if (inval) {
- if (mWidth == width && height > mHeight) { // only grew vertically
- SkIRect rect;
- rect.set(0, mHeight, width, height);
- inval->op(rect, SkRegion::kUnion_Op);
- } else {
- clearCache = true;
- inval->setRect(0, 0, width, height);
- }
- }
-#ifdef FAST_PICTURESET
- // First figure out how large each bucket would be if we used all of the buckets
- int tmpSizeX = (width + MAX_BUCKET_COUNT_X - 1) / MAX_BUCKET_COUNT_X;
- int tmpSizeY = (height + MAX_BUCKET_COUNT_Y - 1) / MAX_BUCKET_COUNT_Y;
-
- // Then round the bucket size up to the nearest chunk
- int bucketSizeX = ((tmpSizeX - 1) / BUCKET_SIZE + 1) * BUCKET_SIZE;
- int bucketSizeY = ((tmpSizeY - 1) / BUCKET_SIZE + 1) * BUCKET_SIZE;
-
- int bucketCountX = (width + bucketSizeX - 1) / bucketSizeX;
- int bucketCountY = (height + bucketSizeY - 1) / bucketSizeY;
-
- // Clear the cache if the horizontal bucket count changed or the vertical
- // count shrank
- if (bucketCountX != mBucketCountX || bucketCountY < mBucketCountY)
- clearCache = true;
-
- // Or if the bucket size changed
- if (bucketSizeX != mBucketSizeX || bucketSizeY != mBucketSizeY)
- clearCache = true;
-
- XLOG("old width=%d height=%d bucketSizeX=%d bucketSizeY=%d bucketCountX=%d bucketCountY=%d clearCache=%d",
- mWidth, mHeight, mBucketSizeX, mBucketSizeY, mBucketCountX, mBucketCountY, clearCache);
- XLOG("new width=%d height=%d bucketSizeX=%d bucketSizeY=%d bucketCountX=%d bucketCountY=%d clearCache=%d",
- width, height, bucketSizeX, bucketSizeY, bucketCountX, bucketCountY, clearCache);
-#endif
- if (clearCache)
- clear();
- mWidth = width;
- mHeight = height;
-#ifdef FAST_PICTURESET
- mBucketSizeX = bucketSizeX;
- mBucketSizeY = bucketSizeY;
- mBucketCountX = bucketCountX;
- mBucketCountY = bucketCountY;
-#endif
-}
-
-void PictureSet::clear()
-{
- DBG_SET_LOG("");
-#ifdef FAST_PICTURESET
- for (BucketMap::iterator iter = mBuckets.begin(); iter != mBuckets.end(); ++iter) {
- Bucket* bucket = iter->second;
- BucketPicture* first = bucket->begin();
- BucketPicture* last = bucket->end();
- for (BucketPicture* current = first; current != last; current++) {
- SkSafeUnref(current->mPicture);
- current->mPicture = 0;
- }
- bucket->clear();
- }
- mBuckets.clear();
- mBucketSizeX = mBucketSizeY = BUCKET_SIZE;
-#else
- Pictures* last = mPictures.end();
- for (Pictures* working = mPictures.begin(); working != last; working++) {
- working->mArea.setEmpty();
- SkSafeUnref(working->mPicture);
- }
- mPictures.clear();
-#endif // FAST_PICTURESET
- mWidth = mHeight = 0;
-}
-
-bool PictureSet::draw(SkCanvas* canvas)
-{
-#ifdef FAST_PICTURESET
- XLOG("PictureSet %x draw on canvas %x", this, canvas);
- SkRect bounds;
- if (canvas->getClipBounds(&bounds) == false)
- return false;
- SkIRect irect;
- bounds.roundOut(&irect);
-
- WTF::Vector<Bucket*> list;
- gatherBucketsForArea(list, irect);
-
- XLOG("PictureSet draw on canvas %x, we have %d buckets", canvas, list.size());
- for (unsigned int i = 0; i < list.size(); i++) {
- Bucket* bucket = list[i];
- XLOG("We paint using bucket %x with %d pictures", bucket, bucket->size());
- for (unsigned int j = 0; j < bucket->size(); j++) {
- BucketPicture& picture = bucket->at(j);
- if (!picture.mPicture)
- continue;
- int saved = canvas->save();
- SkRect pathBounds;
- pathBounds.set(picture.mRealArea);
- XLOG("[%d/%d] draw on canvas with clip %d, %d, %d, %d - %d x %d",
- j, bucket->size(),
- picture.mRealArea.fLeft,
- picture.mRealArea.fTop,
- picture.mRealArea.fRight,
- picture.mRealArea.fBottom,
- picture.mRealArea.width(),
- picture.mRealArea.height());
- canvas->clipRect(pathBounds);
- canvas->translate(pathBounds.fLeft, pathBounds.fTop);
- canvas->save();
- canvas->drawPicture(*picture.mPicture);
- canvas->restoreToCount(saved);
- }
- }
- return false;
-
-#else
-
- validate(__FUNCTION__);
- Pictures* first = mPictures.begin();
- Pictures* last = mPictures.end();
- Pictures* working;
- SkRect bounds;
- if (canvas->getClipBounds(&bounds) == false)
- return false;
- SkIRect irect;
- bounds.roundOut(&irect);
- for (working = last; working != first; ) {
- --working;
- if (working->mArea.contains(irect)) {
-#if PICTURE_SET_DEBUG
- const SkIRect& b = working->mArea.getBounds();
- DBG_SET_LOGD("contains working->mArea={%d,%d,%d,%d}"
- " irect={%d,%d,%d,%d}", b.fLeft, b.fTop, b.fRight, b.fBottom,
- irect.fLeft, irect.fTop, irect.fRight, irect.fBottom);
-#endif
- first = working;
- break;
- }
- }
- DBG_SET_LOGD("%p first=%d last=%d", this, first - mPictures.begin(),
- last - mPictures.begin());
- uint32_t maxElapsed = 0;
- for (working = first; working != last; working++) {
- const SkRegion& area = working->mArea;
- if (area.quickReject(irect)) {
-#if PICTURE_SET_DEBUG
- const SkIRect& b = area.getBounds();
- DBG_SET_LOGD("[%d] %p quickReject working->mArea={%d,%d,%d,%d}"
- " irect={%d,%d,%d,%d}", working - first, working,
- b.fLeft, b.fTop, b.fRight, b.fBottom,
- irect.fLeft, irect.fTop, irect.fRight, irect.fBottom);
-#endif
- working->mElapsed = 0;
- continue;
- }
- int saved = canvas->save();
- SkRect pathBounds;
- if (area.isComplex()) {
- SkPath pathClip;
- area.getBoundaryPath(&pathClip);
- canvas->clipPath(pathClip);
- pathBounds = pathClip.getBounds();
- } else {
- pathBounds.set(area.getBounds());
- canvas->clipRect(pathBounds);
- }
- canvas->translate(pathBounds.fLeft, pathBounds.fTop);
- canvas->save();
- uint32_t startTime = getThreadMsec();
- canvas->drawPicture(*working->mPicture);
- size_t elapsed = working->mElapsed = getThreadMsec() - startTime;
- working->mWroteElapsed = true;
- if (maxElapsed < elapsed && (pathBounds.width() >= MIN_SPLITTABLE ||
- pathBounds.height() >= MIN_SPLITTABLE))
- maxElapsed = elapsed;
- canvas->restoreToCount(saved);
-#define DRAW_TEST_IMAGE 01
-#if DRAW_TEST_IMAGE && PICTURE_SET_DEBUG
- SkColor color = 0x3f000000 | (0xffffff & (unsigned) working);
- canvas->drawColor(color);
- SkPaint paint;
- color ^= 0x00ffffff;
- paint.setColor(color);
- char location[256];
- for (int x = area.getBounds().fLeft & ~0x3f;
- x < area.getBounds().fRight; x += 0x40) {
- for (int y = area.getBounds().fTop & ~0x3f;
- y < area.getBounds().fBottom; y += 0x40) {
- int len = snprintf(location, sizeof(location) - 1, "(%d,%d)", x, y);
- canvas->drawText(location, len, x, y, paint);
- }
- }
-#endif
- DBG_SET_LOGD("[%d] %p working->mArea={%d,%d,%d,%d} elapsed=%d base=%s",
- working - first, working,
- area.getBounds().fLeft, area.getBounds().fTop,
- area.getBounds().fRight, area.getBounds().fBottom,
- working->mElapsed, working->mBase ? "true" : "false");
- }
- // dump(__FUNCTION__);
- return maxElapsed >= MAX_DRAW_TIME;
-#endif // FAST_PICTURESET
-}
-
-void PictureSet::dump(const char* label) const
-{
-#if PICTURE_SET_DUMP
- DBG_SET_LOGD("%p %s (%d) (w=%d,h=%d)", this, label, mPictures.size(),
- mWidth, mHeight);
- const Pictures* last = mPictures.end();
- for (const Pictures* working = mPictures.begin(); working != last; working++) {
- const SkIRect& bounds = working->mArea.getBounds();
- const SkIRect& unsplit = working->mUnsplit;
- MeasureStream measure;
- if (working->mPicture != NULL)
- working->mPicture->serialize(&measure);
- LOGD(" [%d]"
- " mArea.bounds={%d,%d,r=%d,b=%d}"
- " mPicture=%p"
- " mUnsplit={%d,%d,r=%d,b=%d}"
- " mElapsed=%d"
- " mSplit=%s"
- " mWroteElapsed=%s"
- " mBase=%s"
- " pict-size=%d",
- working - mPictures.begin(),
- bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom,
- working->mPicture,
- unsplit.fLeft, unsplit.fTop, unsplit.fRight, unsplit.fBottom,
- working->mElapsed, working->mSplit ? "true" : "false",
- working->mWroteElapsed ? "true" : "false",
- working->mBase ? "true" : "false",
- measure.mTotal);
- }
-#endif
-}
-
-class IsEmptyBounder : public SkBounder {
- virtual bool onIRect(const SkIRect& rect) {
- return false;
- }
-};
-
-class IsEmptyCanvas : public SkCanvas {
-public:
- IsEmptyCanvas(SkBounder* bounder, SkPicture* picture) :
- mPicture(picture), mEmpty(true) {
- setBounder(bounder);
- }
-
- void notEmpty() {
- mEmpty = false;
- mPicture->abortPlayback();
- }
-
- virtual bool clipPath(const SkPath&, SkRegion::Op) {
- // this can be expensive to actually do, and doesn't affect the
- // question of emptiness, so we make it a no-op
- return true;
- }
-
- virtual void commonDrawBitmap(const SkBitmap& bitmap, const SkIRect* rect,
- const SkMatrix& , const SkPaint& ) {
- if (bitmap.width() <= 1 || bitmap.height() <= 1)
- return;
- DBG_SET_LOGD("abort {%d,%d}", bitmap.width(), bitmap.height());
- notEmpty();
- }
-
- virtual void drawPaint(const SkPaint& paint) {
- }
-
- virtual void drawPath(const SkPath& , const SkPaint& paint) {
- DBG_SET_LOG("abort");
- notEmpty();
- }
-
- virtual void drawPoints(PointMode , size_t , const SkPoint [],
- const SkPaint& paint) {
- }
-
- virtual void drawRect(const SkRect& , const SkPaint& paint) {
- // wait for visual content
- if (paint.getColor() != SK_ColorWHITE)
- notEmpty();
- }
-
- virtual void drawSprite(const SkBitmap& , int , int ,
- const SkPaint* paint = NULL) {
- DBG_SET_LOG("abort");
- notEmpty();
- }
-
- virtual void drawText(const void* , size_t byteLength, SkScalar ,
- SkScalar , const SkPaint& paint) {
- DBG_SET_LOGD("abort %d", byteLength);
- notEmpty();
- }
-
- virtual void drawPosText(const void* , size_t byteLength,
- const SkPoint [], const SkPaint& paint) {
- DBG_SET_LOGD("abort %d", byteLength);
- notEmpty();
- }
-
- virtual void drawPosTextH(const void* , size_t byteLength,
- const SkScalar [], SkScalar ,
- const SkPaint& paint) {
- DBG_SET_LOGD("abort %d", byteLength);
- notEmpty();
- }
-
- virtual void drawTextOnPath(const void* , size_t byteLength,
- const SkPath& , const SkMatrix* ,
- const SkPaint& paint) {
- DBG_SET_LOGD("abort %d", byteLength);
- notEmpty();
- }
-
- virtual void drawPicture(SkPicture& picture) {
- SkCanvas::drawPicture(picture);
- }
-
- SkPicture* mPicture;
- bool mEmpty;
-};
-
-bool PictureSet::emptyPicture(SkPicture* picture) const
-{
- IsEmptyBounder isEmptyBounder;
- IsEmptyCanvas checker(&isEmptyBounder, picture);
- SkBitmap bitmap;
- bitmap.setConfig(SkBitmap::kARGB_8888_Config, mWidth, mHeight);
- checker.setBitmapDevice(bitmap);
- checker.drawPicture(*picture);
- return checker.mEmpty;
-}
-
-bool PictureSet::isEmpty() const
-{
-#ifdef FAST_PICTURESET
- // For now, just assume the pictureset is *not* empty
- // if the hashmap contains something
- for (BucketMap::const_iterator iter = mBuckets.begin(); iter != mBuckets.end(); ++iter) {
- if (iter->second->size() > 0)
- return false;
- }
- return true;
-#else
- const Pictures* last = mPictures.end();
- for (const Pictures* working = mPictures.begin(); working != last; working++) {
- if (!working->mEmpty)
- return false;
- }
- return true;
-#endif // FAST_PICTURESET
-}
-
-void PictureSet::set(const PictureSet& src)
-{
- DBG_SET_LOGD("start %p src=%p", this, &src);
- clear();
- setDimensions(src.mWidth, src.mHeight);
-#ifdef FAST_PICTURESET
- XLOG("\n--- set picture ---");
- for (BucketMap::const_iterator iter = src.mBuckets.begin();
- iter != src.mBuckets.end(); ++iter) {
- Bucket* sourceBucket = iter->second;
- Bucket* targetBucket = getBucket(iter->first.first-1, iter->first.second-1);
- BucketPicture* first = sourceBucket->begin();
- BucketPicture* last = sourceBucket->end();
- XLOG("set from bucket %x (%d, %d), %d pictures", sourceBucket,
- iter->first.first, iter->first.second, sourceBucket->size());
- for (BucketPicture* current = first; current != last; current++) {
- XLOG("set picture %x from bucket %x in bucket %x (%d, %d)",
- current->mPicture, sourceBucket, targetBucket,
- iter->first.first, iter->first.second);
- SkSafeRef(current->mPicture);
- BucketPicture picture = { current->mPicture, current->mArea,
- current->mRealArea, current->mBase };
- targetBucket->append(picture);
- }
- }
- XLOG("--- DONE set picture ---\n");
-#else
- const Pictures* last = src.mPictures.end();
- for (const Pictures* working = src.mPictures.begin(); working != last; working++)
- add(working);
- // dump(__FUNCTION__);
- validate(__FUNCTION__);
- DBG_SET_LOG("end");
-#endif // FAST_PICTURESET
-}
-
-#ifdef FAST_PICTURESET
-#else
-
-bool PictureSet::reuseSubdivided(const SkRegion& inval)
-{
- validate(__FUNCTION__);
-
- if (inval.isComplex())
- return false;
- Pictures* working, * last = mPictures.end();
- const SkIRect& invalBounds = inval.getBounds();
- bool steal = false;
- for (working = mPictures.begin(); working != last; working++) {
- if (working->mSplit && invalBounds == working->mUnsplit) {
- steal = true;
- continue;
- }
- if (steal == false)
- continue;
- SkRegion temp = SkRegion(inval);
- temp.op(working->mArea, SkRegion::kIntersect_Op);
- if (temp.isEmpty() || temp == working->mArea)
- continue;
- return false;
- }
- if (steal == false)
- return false;
- for (working = mPictures.begin(); working != last; working++) {
- if ((working->mSplit == false || invalBounds != working->mUnsplit) &&
- inval.contains(working->mArea) == false)
- continue;
- SkSafeUnref(working->mPicture);
- working->mPicture = NULL;
- }
- return true;
-}
-
-void PictureSet::setDrawTimes(const PictureSet& src)
-{
- validate(__FUNCTION__);
- if (mWidth != src.mWidth || mHeight != src.mHeight)
- return;
- Pictures* last = mPictures.end();
- Pictures* working = mPictures.begin();
- if (working == last)
- return;
- const Pictures* srcLast = src.mPictures.end();
- const Pictures* srcWorking = src.mPictures.begin();
- for (; srcWorking != srcLast; srcWorking++) {
- if (srcWorking->mWroteElapsed == false)
- continue;
- while ((srcWorking->mArea != working->mArea ||
- srcWorking->mPicture != working->mPicture)) {
- if (++working == last)
- return;
- }
- DBG_SET_LOGD("%p [%d] [%d] {%d,%d,r=%d,b=%d} working->mElapsed=%d <- %d",
- this, working - mPictures.begin(), srcWorking - src.mPictures.begin(),
- working->mArea.getBounds().fLeft, working->mArea.getBounds().fTop,
- working->mArea.getBounds().fRight, working->mArea.getBounds().fBottom,
- working->mElapsed, srcWorking->mElapsed);
- working->mElapsed = srcWorking->mElapsed;
- }
-}
-
-void PictureSet::setPicture(size_t i, SkPicture* p)
-{
- SkSafeUnref(mPictures[i].mPicture);
- mPictures[i].mPicture = p;
- mPictures[i].mEmpty = emptyPicture(p);
-}
-
-void PictureSet::split(PictureSet* out) const
-{
- dump(__FUNCTION__);
- DBG_SET_LOGD("%p", this);
- SkIRect totalBounds;
- out->mWidth = mWidth;
- out->mHeight = mHeight;
- totalBounds.set(0, 0, mWidth, mHeight);
- SkRegion* total = new SkRegion(totalBounds);
- const Pictures* last = mPictures.end();
- const Pictures* working;
- uint32_t balance = 0;
- int multiUnsplitFastPictures = 0; // > 1 has more than 1
- for (working = mPictures.begin(); working != last; working++) {
- if (working->mElapsed >= MAX_DRAW_TIME || working->mSplit)
- continue;
- if (++multiUnsplitFastPictures > 1)
- break;
- }
- for (working = mPictures.begin(); working != last; working++) {
- uint32_t elapsed = working->mElapsed;
- if (elapsed < MAX_DRAW_TIME) {
- bool split = working->mSplit;
- DBG_SET_LOGD("elapsed=%d working=%p total->getBounds()="
- "{%d,%d,r=%d,b=%d} split=%s", elapsed, working,
- total->getBounds().fLeft, total->getBounds().fTop,
- total->getBounds().fRight, total->getBounds().fBottom,
- split ? "true" : "false");
- if (multiUnsplitFastPictures <= 1 || split) {
- total->op(working->mArea, SkRegion::kDifference_Op);
- out->add(working->mArea, working->mPicture, elapsed, split,
- working->mEmpty);
- } else if (balance < elapsed)
- balance = elapsed;
- continue;
- }
- total->op(working->mArea, SkRegion::kDifference_Op);
- const SkIRect& bounds = working->mArea.getBounds();
- int width = bounds.width();
- int height = bounds.height();
- int across = 1;
- int down = 1;
- while (height >= MIN_SPLITTABLE || width >= MIN_SPLITTABLE) {
- if (height >= width) {
- height >>= 1;
- down <<= 1;
- } else {
- width >>= 1;
- across <<= 1 ;
- }
- if ((elapsed >>= 1) < MAX_DRAW_TIME)
- break;
- }
- width = bounds.width();
- height = bounds.height();
- int top = bounds.fTop;
- for (int indexY = 0; indexY < down; ) {
- int bottom = bounds.fTop + height * ++indexY / down;
- int left = bounds.fLeft;
- for (int indexX = 0; indexX < across; ) {
- int right = bounds.fLeft + width * ++indexX / across;
- SkIRect cBounds;
- cBounds.set(left, top, right, bottom);
- out->add(SkRegion(cBounds), (across | down) != 1 ? NULL :
- working->mPicture, elapsed, true,
- (across | down) != 1 ? false : working->mEmpty);
- left = right;
- }
- top = bottom;
- }
- }
- DBG_SET_LOGD("%p w=%d h=%d total->isEmpty()=%s multiUnsplitFastPictures=%d",
- this, mWidth, mHeight, total->isEmpty() ? "true" : "false",
- multiUnsplitFastPictures);
- if (!total->isEmpty() && multiUnsplitFastPictures > 1)
- out->add(*total, NULL, balance, false, false);
- delete total;
- validate(__FUNCTION__);
- out->dump("split-out");
-}
-
-#endif // FAST_PICTURESET
-
-bool PictureSet::validate(const char* funct) const
-{
-#ifdef FAST_PICTURESET
- return true;
-#else
- bool valid = true;
-#if PICTURE_SET_VALIDATE
- SkRegion all;
- const Pictures* first = mPictures.begin();
- for (const Pictures* working = mPictures.end(); working != first; ) {
- --working;
- const SkPicture* pict = working->mPicture;
- const SkRegion& area = working->mArea;
- const SkIRect& bounds = area.getBounds();
- bool localValid = false;
- if (working->mUnsplit.isEmpty())
- LOGD("%s working->mUnsplit.isEmpty()", funct);
- else if (working->mUnsplit.contains(bounds) == false)
- LOGD("%s working->mUnsplit.contains(bounds) == false", funct);
- else if (working->mElapsed >= 1000)
- LOGD("%s working->mElapsed >= 1000", funct);
- else if ((working->mSplit & 0xfe) != 0)
- LOGD("%s (working->mSplit & 0xfe) != 0", funct);
- else if ((working->mWroteElapsed & 0xfe) != 0)
- LOGD("%s (working->mWroteElapsed & 0xfe) != 0", funct);
- else if (pict != NULL) {
- int pictWidth = pict->width();
- int pictHeight = pict->height();
- if (pictWidth < bounds.width())
- LOGD("%s pictWidth=%d < bounds.width()=%d", funct, pictWidth, bounds.width());
- else if (pictHeight < bounds.height())
- LOGD("%s pictHeight=%d < bounds.height()=%d", funct, pictHeight, bounds.height());
- else if (working->mArea.isEmpty())
- LOGD("%s working->mArea.isEmpty()", funct);
- else
- localValid = true;
- } else
- localValid = true;
- working->mArea.validate();
- if (localValid == false) {
- if (all.contains(area) == true)
- LOGD("%s all.contains(area) == true", funct);
- else
- localValid = true;
- }
- valid &= localValid;
- all.op(area, SkRegion::kUnion_Op);
- }
- const SkIRect& allBounds = all.getBounds();
- if (valid) {
- valid = false;
- if (allBounds.width() != mWidth)
- LOGD("%s allBounds.width()=%d != mWidth=%d", funct, allBounds.width(), mWidth);
- else if (allBounds.height() != mHeight)
- LOGD("%s allBounds.height()=%d != mHeight=%d", funct, allBounds.height(), mHeight);
- else
- valid = true;
- }
- while (valid == false)
- ;
-#endif
- return valid;
-#endif // FAST_PICTURESET
-}
-
-} /* namespace android */
diff --git a/Source/WebKit/android/jni/PictureSet.h b/Source/WebKit/android/jni/PictureSet.h
deleted file mode 100644
index fe47361..0000000
--- a/Source/WebKit/android/jni/PictureSet.h
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright 2008, 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 PictureSet_h
-#define PictureSet_h
-
-#define PICTURE_SET_DUMP 0
-#define PICTURE_SET_DEBUG 0
-#define PICTURE_SET_VALIDATE 0
-
-#if PICTURE_SET_DEBUG
-#define DBG_SET_LOG(message) LOGD("%s %s", __FUNCTION__, message)
-#define DBG_SET_LOGD(format, ...) LOGD("%s " format, __FUNCTION__, __VA_ARGS__)
-#define DEBUG_SET_UI_LOGD(...) LOGD(__VA_ARGS__)
-#else
-#define DBG_SET_LOG(message) ((void)0)
-#define DBG_SET_LOGD(format, ...) ((void)0)
-#define DEBUG_SET_UI_LOGD(...) ((void)0)
-#endif
-
-#include "jni.h"
-#include "SkRegion.h"
-#include <wtf/Vector.h>
-#include <wtf/HashMap.h>
-
-// #define FAST_PICTURESET // use a hierarchy of pictures
-
-class SkCanvas;
-class SkPicture;
-class SkIRect;
-
-namespace android {
-
-#ifdef FAST_PICTURESET
- struct BucketPicture {
- SkPicture* mPicture;
- SkIRect mArea;
- SkIRect mRealArea;
- bool mBase;
- };
-
- typedef std::pair<int, int> BucketPosition;
- typedef WTF::Vector<BucketPicture> Bucket;
- typedef WTF::HashMap<BucketPosition , Bucket* > BucketMap;
-#endif
-
- class PictureSet {
- public:
- PictureSet();
- PictureSet(const PictureSet& src) { set(src); }
- PictureSet(SkPicture* picture);
- virtual ~PictureSet();
-
-#ifdef FAST_PICTURESET
- void displayBucket(Bucket* bucket);
- void displayBuckets();
- WTF::Vector<Bucket*>* bucketsToUpdate() { return &mUpdatedBuckets; }
- Bucket* getBucket(int x, int y);
- void addToBucket(Bucket* bucket, int dx, int dy, SkIRect& rect);
- void gatherBucketsForArea(WTF::Vector<Bucket*>& list, const SkIRect& rect);
- void splitAdd(const SkIRect& rect);
-#endif
-
- void add(const SkRegion& area, SkPicture* picture,
- uint32_t elapsed, bool split);
-
- // Update mWidth/mHeight, and adds any additional inval region
- void setDimensions(int width, int height, SkRegion* inval = 0);
- void clear();
- bool draw(SkCanvas* );
- static PictureSet* GetNativePictureSet(JNIEnv* env, jobject jpic);
- int height() const { return mHeight; }
- bool isEmpty() const; // returns true if empty or only trivial content
- void set(const PictureSet& );
-
-#ifdef FAST_PICTURESET
-#else
- void add(const SkRegion& area, SkPicture* picture,
- uint32_t elapsed, bool split, bool empty);
- const SkIRect& bounds(size_t i) const {
- return mPictures[i].mArea.getBounds(); }
- bool reuseSubdivided(const SkRegion& );
- void setPicture(size_t i, SkPicture* p);
- void setDrawTimes(const PictureSet& );
- size_t size() const { return mPictures.size(); }
- void split(PictureSet* result) const;
- bool upToDate(size_t i) const { return mPictures[i].mPicture != NULL; }
-#endif
- int width() const { return mWidth; }
- void dump(const char* label) const;
- bool validate(const char* label) const;
- private:
- bool emptyPicture(SkPicture* ) const; // true if no text, images, paths
-
-#ifdef FAST_PICTURESET
- BucketMap mBuckets;
- WTF::Vector<Bucket*> mUpdatedBuckets;
- int mBucketSizeX;
- int mBucketSizeY;
- int mBucketCountX;
- int mBucketCountY;
-#else
- struct Pictures {
- SkRegion mArea;
- SkPicture* mPicture;
- SkIRect mUnsplit;
- uint32_t mElapsed;
- bool mSplit : 8;
- bool mWroteElapsed : 8;
- bool mBase : 8; // true if nothing is drawn underneath this
- bool mEmpty : 8; // true if the picture only draws white
- };
- void add(const Pictures* temp);
- WTF::Vector<Pictures> mPictures;
-#endif
- float mBaseArea;
- float mAdditionalArea;
- int mHeight;
- int mWidth;
- };
-}
-
-#endif
diff --git a/Source/WebKit/android/jni/ViewStateSerializer.cpp b/Source/WebKit/android/jni/ViewStateSerializer.cpp
index 6b473f5..02ddca6 100644
--- a/Source/WebKit/android/jni/ViewStateSerializer.cpp
+++ b/Source/WebKit/android/jni/ViewStateSerializer.cpp
@@ -23,15 +23,23 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#define LOG_TAG "ViewStateSerializer"
+#define LOG_NDEBUG 1
+
#include "config.h"
#include "BaseLayerAndroid.h"
#include "CreateJavaOutputStreamAdaptor.h"
+#include "FixedPositioning.h"
#include "ImagesManager.h"
+#include "IFrameContentLayerAndroid.h"
+#include "IFrameLayerAndroid.h"
#include "Layer.h"
#include "LayerAndroid.h"
-#include "PictureSet.h"
+#include "LayerContent.h"
+#include "PictureLayerContent.h"
#include "ScrollableLayerAndroid.h"
+#include "SkFlattenable.h"
#include "SkPicture.h"
#include "TilesManager.h"
@@ -39,24 +47,13 @@
#include <JNIHelp.h>
#include <jni.h>
-#ifdef DEBUG
-
-#undef XLOG
-#define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "ViewStateSerializer", __VA_ARGS__)
-
-#else
-
-#undef XLOG
-#define XLOG(...)
-
-#endif // DEBUG
-
namespace android {
enum LayerTypes {
LTNone = 0,
LTLayerAndroid = 1,
LTScrollableLayerAndroid = 2,
+ LTFixedLayerAndroid = 3
};
static bool nativeSerializeViewState(JNIEnv* env, jobject, jint jbaseLayer,
@@ -72,16 +69,14 @@ static bool nativeSerializeViewState(JNIEnv* env, jobject, jint jbaseLayer,
#else
stream->write32(0);
#endif
- SkPicture picture;
- PictureSet* content = baseLayer->content();
- baseLayer->drawCanvas(picture.beginRecording(content->width(), content->height(),
- SkPicture::kUsePathBoundsForClip_RecordingFlag));
- picture.endRecording();
if (!stream)
return false;
- picture.serialize(stream);
+ if (baseLayer->content())
+ baseLayer->content()->serialize(stream);
+ else
+ return false;
int childCount = baseLayer->countChildren();
- XLOG("BaseLayer has %d child(ren)", childCount);
+ ALOGV("BaseLayer has %d child(ren)", childCount);
stream->write32(childCount);
for (int i = 0; i < childCount; i++) {
LayerAndroid* layer = static_cast<LayerAndroid*>(baseLayer->getChild(i));
@@ -91,23 +86,28 @@ static bool nativeSerializeViewState(JNIEnv* env, jobject, jint jbaseLayer,
return true;
}
-static BaseLayerAndroid* nativeDeserializeViewState(JNIEnv* env, jobject, jobject jstream,
- jbyteArray jstorage)
+static BaseLayerAndroid* nativeDeserializeViewState(JNIEnv* env, jobject, jint version,
+ jobject jstream, jbyteArray jstorage)
{
SkStream* stream = CreateJavaInputStreamAdaptor(env, jstream, jstorage);
if (!stream)
return 0;
- BaseLayerAndroid* layer = new BaseLayerAndroid();
Color color = stream->readU32();
-#if USE(ACCELERATED_COMPOSITING)
- layer->setBackgroundColor(color);
-#endif
SkPicture* picture = new SkPicture(stream);
- layer->setContent(picture);
+ PictureLayerContent* content = new PictureLayerContent(picture);
+
+ BaseLayerAndroid* layer = new BaseLayerAndroid(content);
+ layer->setBackgroundColor(color);
+
+ SkRegion dirtyRegion;
+ dirtyRegion.setRect(0, 0, content->width(), content->height());
+ layer->markAsDirty(dirtyRegion);
+
+ SkSafeUnref(content);
SkSafeUnref(picture);
int childCount = stream->readS32();
for (int i = 0; i < childCount; i++) {
- LayerAndroid* childLayer = deserializeLayer(stream);
+ LayerAndroid* childLayer = deserializeLayer(version, stream);
if (childLayer)
layer->addChild(childLayer);
}
@@ -242,20 +242,20 @@ void readTransformationMatrix(SkStream *stream, TransformationMatrix& matrix)
void serializeLayer(LayerAndroid* layer, SkWStream* stream)
{
if (!layer) {
- XLOG("NULL layer!");
+ ALOGV("NULL layer!");
stream->write8(LTNone);
return;
}
if (layer->isMedia() || layer->isVideo()) {
- XLOG("Layer isn't supported for serialization: isMedia: %s, isVideo: %s",
+ ALOGV("Layer isn't supported for serialization: isMedia: %s, isVideo: %s",
layer->isMedia() ? "true" : "false",
layer->isVideo() ? "true" : "false");
stream->write8(LTNone);
return;
}
- LayerTypes type = layer->contentIsScrollable()
- ? LTScrollableLayerAndroid
- : LTLayerAndroid;
+ LayerTypes type = LTLayerAndroid;
+ if (layer->contentIsScrollable())
+ type = LTScrollableLayerAndroid;
stream->write8(type);
// Start with Layer fields
@@ -272,20 +272,43 @@ void serializeLayer(LayerAndroid* layer, SkWStream* stream)
// Next up, LayerAndroid fields
stream->writeBool(layer->m_haveClip);
- stream->writeBool(layer->m_isFixed);
+ stream->writeBool(layer->isPositionFixed());
stream->writeBool(layer->m_backgroundColorSet);
- stream->writeBool(layer->m_isIframe);
- writeSkLength(stream, layer->m_fixedLeft);
- writeSkLength(stream, layer->m_fixedTop);
- writeSkLength(stream, layer->m_fixedRight);
- writeSkLength(stream, layer->m_fixedBottom);
- writeSkLength(stream, layer->m_fixedMarginLeft);
- writeSkLength(stream, layer->m_fixedMarginTop);
- writeSkLength(stream, layer->m_fixedMarginRight);
- writeSkLength(stream, layer->m_fixedMarginBottom);
- writeSkRect(stream, layer->m_fixedRect);
- stream->write32(layer->m_renderLayerPos.x());
- stream->write32(layer->m_renderLayerPos.y());
+ stream->writeBool(layer->isIFrame());
+
+ // With the current LayerAndroid hierarchy, LayerAndroid doesn't have
+ // those fields anymore. Let's keep the current serialization format for
+ // now and output blank fields... not great, but probably better than
+ // dealing with multiple versions.
+ if (layer->fixedPosition()) {
+ FixedPositioning* fixedPosition = layer->fixedPosition();
+ writeSkLength(stream, fixedPosition->m_fixedLeft);
+ writeSkLength(stream, fixedPosition->m_fixedTop);
+ writeSkLength(stream, fixedPosition->m_fixedRight);
+ writeSkLength(stream, fixedPosition->m_fixedBottom);
+ writeSkLength(stream, fixedPosition->m_fixedMarginLeft);
+ writeSkLength(stream, fixedPosition->m_fixedMarginTop);
+ writeSkLength(stream, fixedPosition->m_fixedMarginRight);
+ writeSkLength(stream, fixedPosition->m_fixedMarginBottom);
+ writeSkRect(stream, fixedPosition->m_fixedRect);
+ stream->write32(fixedPosition->m_renderLayerPos.x());
+ stream->write32(fixedPosition->m_renderLayerPos.y());
+ } else {
+ SkLength length;
+ SkRect rect;
+ writeSkLength(stream, length); // fixedLeft
+ writeSkLength(stream, length); // fixedTop
+ writeSkLength(stream, length); // fixedRight
+ writeSkLength(stream, length); // fixedBottom
+ writeSkLength(stream, length); // fixedMarginLeft
+ writeSkLength(stream, length); // fixedMarginTop
+ writeSkLength(stream, length); // fixedMarginRight
+ writeSkLength(stream, length); // fixedMarginBottom
+ writeSkRect(stream, rect); // fixedRect
+ stream->write32(0); // renderLayerPos.x()
+ stream->write32(0); // renderLayerPos.y()
+ }
+
stream->writeBool(layer->m_backfaceVisibility);
stream->writeBool(layer->m_visible);
stream->write32(layer->m_backgroundColor);
@@ -305,10 +328,10 @@ void serializeLayer(LayerAndroid* layer, SkWStream* stream)
stream->write32(buffer.size());
buffer.writeToStream(stream);
}
- bool hasRecordingPicture = layer->m_recordingPicture != 0;
+ bool hasRecordingPicture = layer->m_content != 0 && !layer->m_content->isEmpty();
stream->writeBool(hasRecordingPicture);
if (hasRecordingPicture)
- layer->m_recordingPicture->serialize(stream);
+ layer->m_content->serialize(stream);
// TODO: support m_animations (maybe?)
stream->write32(0); // placeholder for m_animations.size();
writeTransformationMatrix(stream, layer->m_transform);
@@ -327,7 +350,7 @@ void serializeLayer(LayerAndroid* layer, SkWStream* stream)
serializeLayer(layer->getChild(i), stream);
}
-LayerAndroid* deserializeLayer(SkStream* stream)
+LayerAndroid* deserializeLayer(int version, SkStream* stream)
{
int type = stream->readU8();
if (type == LTNone)
@@ -339,7 +362,7 @@ LayerAndroid* deserializeLayer(SkStream* stream)
else if (type == LTScrollableLayerAndroid)
layer = new ScrollableLayerAndroid((RenderLayer*) 0);
else {
- XLOG("Unexpected layer type: %d, aborting!", type);
+ ALOGV("Unexpected layer type: %d, aborting!", type);
return 0;
}
@@ -354,20 +377,55 @@ LayerAndroid* deserializeLayer(SkStream* stream)
// LayerAndroid fields
layer->m_haveClip = stream->readBool();
- layer->m_isFixed = stream->readBool();
+
+ // Keep the legacy serialization/deserialization format...
+ bool isFixed = stream->readBool();
+
layer->m_backgroundColorSet = stream->readBool();
- layer->m_isIframe = stream->readBool();
- layer->m_fixedLeft = readSkLength(stream);
- layer->m_fixedTop = readSkLength(stream);
- layer->m_fixedRight = readSkLength(stream);
- layer->m_fixedBottom = readSkLength(stream);
- layer->m_fixedMarginLeft = readSkLength(stream);
- layer->m_fixedMarginTop = readSkLength(stream);
- layer->m_fixedMarginRight = readSkLength(stream);
- layer->m_fixedMarginBottom = readSkLength(stream);
- layer->m_fixedRect = readSkRect(stream);
- layer->m_renderLayerPos.setX(stream->readS32());
- layer->m_renderLayerPos.setY(stream->readS32());
+
+ bool isIframe = stream->readBool();
+ // If we are a scrollable layer android, we are an iframe content
+ if (isIframe && type == LTScrollableLayerAndroid) {
+ IFrameContentLayerAndroid* iframeContent = new IFrameContentLayerAndroid(*layer);
+ layer->unref();
+ layer = iframeContent;
+ } else if (isIframe) { // otherwise we are just the iframe (we use it to compute offset)
+ IFrameLayerAndroid* iframe = new IFrameLayerAndroid(*layer);
+ layer->unref();
+ layer = iframe;
+ }
+
+ if (isFixed) {
+ FixedPositioning* fixedPosition = new FixedPositioning(layer);
+
+ fixedPosition->m_fixedLeft = readSkLength(stream);
+ fixedPosition->m_fixedTop = readSkLength(stream);
+ fixedPosition->m_fixedRight = readSkLength(stream);
+ fixedPosition->m_fixedBottom = readSkLength(stream);
+ fixedPosition->m_fixedMarginLeft = readSkLength(stream);
+ fixedPosition->m_fixedMarginTop = readSkLength(stream);
+ fixedPosition->m_fixedMarginRight = readSkLength(stream);
+ fixedPosition->m_fixedMarginBottom = readSkLength(stream);
+ fixedPosition->m_fixedRect = readSkRect(stream);
+ fixedPosition->m_renderLayerPos.setX(stream->readS32());
+ fixedPosition->m_renderLayerPos.setY(stream->readS32());
+
+ layer->setFixedPosition(fixedPosition);
+ } else {
+ // Not a fixed element, bypass the values in the stream
+ readSkLength(stream); // fixedLeft
+ readSkLength(stream); // fixedTop
+ readSkLength(stream); // fixedRight
+ readSkLength(stream); // fixedBottom
+ readSkLength(stream); // fixedMarginLeft
+ readSkLength(stream); // fixedMarginTop
+ readSkLength(stream); // fixedMarginRight
+ readSkLength(stream); // fixedMarginBottom
+ readSkRect(stream); // fixedRect
+ stream->readS32(); // renderLayerPos.x()
+ stream->readS32(); // renderLayerPos.y()
+ }
+
layer->m_backfaceVisibility = stream->readBool();
layer->m_visible = stream->readBool();
layer->m_backgroundColor = stream->readU32();
@@ -388,7 +446,11 @@ LayerAndroid* deserializeLayer(SkStream* stream)
}
bool hasRecordingPicture = stream->readBool();
if (hasRecordingPicture) {
- layer->m_recordingPicture = new SkPicture(stream);
+ SkPicture* picture = new SkPicture(stream);
+ PictureLayerContent* content = new PictureLayerContent(picture);
+ layer->setContent(content);
+ SkSafeUnref(content);
+ SkSafeUnref(picture);
}
int animationCount = stream->readU32(); // TODO: Support (maybe?)
readTransformationMatrix(stream, layer->m_transform);
@@ -404,12 +466,11 @@ LayerAndroid* deserializeLayer(SkStream* stream)
}
int childCount = stream->readU32();
for (int i = 0; i < childCount; i++) {
- LayerAndroid *childLayer = deserializeLayer(stream);
+ LayerAndroid *childLayer = deserializeLayer(version, stream);
if (childLayer)
layer->addChild(childLayer);
}
- layer->needsRepaint();
- XLOG("Created layer with id %d", layer->uniqueId());
+ ALOGV("Created layer with id %d", layer->uniqueId());
return layer;
}
@@ -419,7 +480,7 @@ LayerAndroid* deserializeLayer(SkStream* stream)
static JNINativeMethod gSerializerMethods[] = {
{ "nativeSerializeViewState", "(ILjava/io/OutputStream;[B)Z",
(void*) nativeSerializeViewState },
- { "nativeDeserializeViewState", "(Ljava/io/InputStream;[B)I",
+ { "nativeDeserializeViewState", "(ILjava/io/InputStream;[B)I",
(void*) nativeDeserializeViewState },
};
diff --git a/Source/WebKit/android/jni/WebCoreFrameBridge.cpp b/Source/WebKit/android/jni/WebCoreFrameBridge.cpp
index d53ddb6..4ce3d8e 100644
--- a/Source/WebKit/android/jni/WebCoreFrameBridge.cpp
+++ b/Source/WebKit/android/jni/WebCoreFrameBridge.cpp
@@ -60,6 +60,8 @@
#include "IconDatabase.h"
#include "Image.h"
#include "InspectorClientAndroid.h"
+#include "JavaNPObjectV8.h"
+#include "JavaInstanceJobjectV8.h"
#include "KURL.h"
#include "Page.h"
#include "PageCache.h"
@@ -81,7 +83,6 @@
#include "WebArchiveAndroid.h"
#include "WebCache.h"
#include "WebCoreJni.h"
-#include "WebCoreResourceLoader.h"
#include "WebHistory.h"
#include "WebIconDatabase.h"
#include "WebFrameView.h"
@@ -99,30 +100,13 @@
#include <android_runtime/android_util_AssetManager.h>
#include <openssl/x509.h>
#include <utils/misc.h>
-#include <utils/AssetManager.h>
+#include <androidfw/AssetManager.h>
#include <wtf/CurrentTime.h>
#include <wtf/Platform.h>
#include <wtf/text/AtomicString.h>
#include <wtf/text/CString.h>
#include <wtf/text/StringBuilder.h>
-#if USE(JSC)
-#include "GCController.h"
-#include "JSDOMWindow.h"
-#include "JavaInstanceJSC.h"
-#include <runtime_object.h>
-#include <runtime_root.h>
-#include <runtime/JSLock.h>
-#elif USE(V8)
-#include "JavaNPObjectV8.h"
-#include "JavaInstanceJobjectV8.h"
-#include "V8Counters.h"
-#endif // USE(JSC)
-
-#ifdef ANDROID_INSTRUMENT
-#include "TimeCounter.h"
-#endif
-
#if ENABLE(WEB_AUTOFILL)
#include "autofill/WebAutofill.h"
#endif
@@ -244,8 +228,6 @@ WebFrame::WebFrame(JNIEnv* env, jobject obj, jobject historyList, WebCore::Page*
mJavaFrame = new JavaBrowserFrame;
mJavaFrame->mObj = env->NewWeakGlobalRef(obj);
mJavaFrame->mHistoryList = env->NewWeakGlobalRef(historyList);
- mJavaFrame->mStartLoadingResource = env->GetMethodID(clazz, "startLoadingResource",
- "(ILjava/lang/String;Ljava/lang/String;Ljava/util/HashMap;[BJIZZZLjava/lang/String;Ljava/lang/String;)Landroid/webkit/LoadListener;");
mJavaFrame->mMaybeSavePassword = env->GetMethodID(clazz, "maybeSavePassword",
"([BLjava/lang/String;Ljava/lang/String;)V");
mJavaFrame->mShouldInterceptRequest =
@@ -301,41 +283,39 @@ WebFrame::WebFrame(JNIEnv* env, jobject obj, jobject historyList, WebCore::Page*
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
env->DeleteLocalRef(clazz);
- LOG_ASSERT(mJavaFrame->mStartLoadingResource, "Could not find method startLoadingResource");
- LOG_ASSERT(mJavaFrame->mMaybeSavePassword, "Could not find method maybeSavePassword");
- LOG_ASSERT(mJavaFrame->mShouldInterceptRequest, "Could not find method shouldInterceptRequest");
- LOG_ASSERT(mJavaFrame->mLoadStarted, "Could not find method loadStarted");
- LOG_ASSERT(mJavaFrame->mTransitionToCommitted, "Could not find method transitionToCommitted");
- LOG_ASSERT(mJavaFrame->mLoadFinished, "Could not find method loadFinished");
- LOG_ASSERT(mJavaFrame->mReportError, "Could not find method reportError");
- LOG_ASSERT(mJavaFrame->mSetTitle, "Could not find method setTitle");
- LOG_ASSERT(mJavaFrame->mWindowObjectCleared, "Could not find method windowObjectCleared");
- LOG_ASSERT(mJavaFrame->mSetProgress, "Could not find method setProgress");
- LOG_ASSERT(mJavaFrame->mDidReceiveIcon, "Could not find method didReceiveIcon");
- LOG_ASSERT(mJavaFrame->mDidReceiveTouchIconUrl, "Could not find method didReceiveTouchIconUrl");
- LOG_ASSERT(mJavaFrame->mUpdateVisitedHistory, "Could not find method updateVisitedHistory");
- LOG_ASSERT(mJavaFrame->mHandleUrl, "Could not find method handleUrl");
- LOG_ASSERT(mJavaFrame->mCreateWindow, "Could not find method createWindow");
- LOG_ASSERT(mJavaFrame->mCloseWindow, "Could not find method closeWindow");
- LOG_ASSERT(mJavaFrame->mDecidePolicyForFormResubmission, "Could not find method decidePolicyForFormResubmission");
- LOG_ASSERT(mJavaFrame->mRequestFocus, "Could not find method requestFocus");
- LOG_ASSERT(mJavaFrame->mGetRawResFilename, "Could not find method getRawResFilename");
- LOG_ASSERT(mJavaFrame->mDensity, "Could not find method density");
- LOG_ASSERT(mJavaFrame->mGetFileSize, "Could not find method getFileSize");
- LOG_ASSERT(mJavaFrame->mGetFile, "Could not find method getFile");
- LOG_ASSERT(mJavaFrame->mDidReceiveAuthenticationChallenge, "Could not find method didReceiveAuthenticationChallenge");
- LOG_ASSERT(mJavaFrame->mReportSslCertError, "Could not find method reportSslCertError");
- LOG_ASSERT(mJavaFrame->mRequestClientCert, "Could not find method requestClientCert");
- LOG_ASSERT(mJavaFrame->mDownloadStart, "Could not find method downloadStart");
- LOG_ASSERT(mJavaFrame->mDidReceiveData, "Could not find method didReceiveData");
- LOG_ASSERT(mJavaFrame->mDidFinishLoading, "Could not find method didFinishLoading");
- LOG_ASSERT(mJavaFrame->mSetCertificate, "Could not find method setCertificate");
- LOG_ASSERT(mJavaFrame->mShouldSaveFormData, "Could not find method shouldSaveFormData");
- LOG_ASSERT(mJavaFrame->mSaveFormData, "Could not find method saveFormData");
- LOG_ASSERT(mJavaFrame->mAutoLogin, "Could not find method autoLogin");
+ ALOG_ASSERT(mJavaFrame->mMaybeSavePassword, "Could not find method maybeSavePassword");
+ ALOG_ASSERT(mJavaFrame->mShouldInterceptRequest, "Could not find method shouldInterceptRequest");
+ ALOG_ASSERT(mJavaFrame->mLoadStarted, "Could not find method loadStarted");
+ ALOG_ASSERT(mJavaFrame->mTransitionToCommitted, "Could not find method transitionToCommitted");
+ ALOG_ASSERT(mJavaFrame->mLoadFinished, "Could not find method loadFinished");
+ ALOG_ASSERT(mJavaFrame->mReportError, "Could not find method reportError");
+ ALOG_ASSERT(mJavaFrame->mSetTitle, "Could not find method setTitle");
+ ALOG_ASSERT(mJavaFrame->mWindowObjectCleared, "Could not find method windowObjectCleared");
+ ALOG_ASSERT(mJavaFrame->mSetProgress, "Could not find method setProgress");
+ ALOG_ASSERT(mJavaFrame->mDidReceiveIcon, "Could not find method didReceiveIcon");
+ ALOG_ASSERT(mJavaFrame->mDidReceiveTouchIconUrl, "Could not find method didReceiveTouchIconUrl");
+ ALOG_ASSERT(mJavaFrame->mUpdateVisitedHistory, "Could not find method updateVisitedHistory");
+ ALOG_ASSERT(mJavaFrame->mHandleUrl, "Could not find method handleUrl");
+ ALOG_ASSERT(mJavaFrame->mCreateWindow, "Could not find method createWindow");
+ ALOG_ASSERT(mJavaFrame->mCloseWindow, "Could not find method closeWindow");
+ ALOG_ASSERT(mJavaFrame->mDecidePolicyForFormResubmission, "Could not find method decidePolicyForFormResubmission");
+ ALOG_ASSERT(mJavaFrame->mRequestFocus, "Could not find method requestFocus");
+ ALOG_ASSERT(mJavaFrame->mGetRawResFilename, "Could not find method getRawResFilename");
+ ALOG_ASSERT(mJavaFrame->mDensity, "Could not find method density");
+ ALOG_ASSERT(mJavaFrame->mGetFileSize, "Could not find method getFileSize");
+ ALOG_ASSERT(mJavaFrame->mGetFile, "Could not find method getFile");
+ ALOG_ASSERT(mJavaFrame->mDidReceiveAuthenticationChallenge, "Could not find method didReceiveAuthenticationChallenge");
+ ALOG_ASSERT(mJavaFrame->mReportSslCertError, "Could not find method reportSslCertError");
+ ALOG_ASSERT(mJavaFrame->mRequestClientCert, "Could not find method requestClientCert");
+ ALOG_ASSERT(mJavaFrame->mDownloadStart, "Could not find method downloadStart");
+ ALOG_ASSERT(mJavaFrame->mDidReceiveData, "Could not find method didReceiveData");
+ ALOG_ASSERT(mJavaFrame->mDidFinishLoading, "Could not find method didFinishLoading");
+ ALOG_ASSERT(mJavaFrame->mSetCertificate, "Could not find method setCertificate");
+ ALOG_ASSERT(mJavaFrame->mShouldSaveFormData, "Could not find method shouldSaveFormData");
+ ALOG_ASSERT(mJavaFrame->mSaveFormData, "Could not find method saveFormData");
+ ALOG_ASSERT(mJavaFrame->mAutoLogin, "Could not find method autoLogin");
mUserAgent = WTF::String();
- mUserInitiatedAction = false;
mBlockNetworkLoads = false;
m_renderSkins = 0;
}
@@ -362,14 +342,14 @@ WebFrame* WebFrame::getWebFrame(const WebCore::Frame* frame)
static jobject createJavaMapFromHTTPHeaders(JNIEnv* env, const WebCore::HTTPHeaderMap& map)
{
jclass mapClass = env->FindClass("java/util/HashMap");
- LOG_ASSERT(mapClass, "Could not find HashMap class!");
+ ALOG_ASSERT(mapClass, "Could not find HashMap class!");
jmethodID init = env->GetMethodID(mapClass, "<init>", "(I)V");
- LOG_ASSERT(init, "Could not find constructor for HashMap");
+ ALOG_ASSERT(init, "Could not find constructor for HashMap");
jobject hashMap = env->NewObject(mapClass, init, map.size());
- LOG_ASSERT(hashMap, "Could not create a new HashMap");
+ ALOG_ASSERT(hashMap, "Could not create a new HashMap");
jmethodID put = env->GetMethodID(mapClass, "put",
"(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
- LOG_ASSERT(put, "Could not find put method on HashMap");
+ ALOG_ASSERT(put, "Could not find put method on HashMap");
WebCore::HTTPHeaderMap::const_iterator end = map.end();
for (WebCore::HTTPHeaderMap::const_iterator i = map.begin(); i != end; ++i) {
@@ -416,104 +396,10 @@ private:
int m_size;
};
-PassRefPtr<WebCore::ResourceLoaderAndroid>
-WebFrame::startLoadingResource(WebCore::ResourceHandle* loader,
- const WebCore::ResourceRequest& request,
- bool mainResource,
- bool synchronous)
-{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
-#endif
- LOGV("::WebCore:: startLoadingResource(%p, %s)",
- loader, request.url().string().latin1().data());
-
- JNIEnv* env = getJNIEnv();
- AutoJObject javaFrame = mJavaFrame->frame(env);
- if (!javaFrame.get())
- return 0;
-
- WTF::String method = request.httpMethod();
- WebCore::HTTPHeaderMap headers = request.httpHeaderFields();
-
- WTF::String urlStr = request.url().string();
- int colon = urlStr.find(':');
- bool allLower = true;
- for (int index = 0; index < colon; index++) {
- UChar ch = urlStr[index];
- if (!WTF::isASCIIAlpha(ch))
- break;
- allLower &= WTF::isASCIILower(ch);
- if (index == colon - 1 && !allLower) {
- urlStr = urlStr.substring(0, colon).lower()
- + urlStr.substring(colon);
- }
- }
- LOGV("%s lower=%s", __FUNCTION__, urlStr.latin1().data());
- jstring jUrlStr = wtfStringToJstring(env, urlStr);
- jstring jMethodStr = NULL;
- if (!method.isEmpty())
- jMethodStr = wtfStringToJstring(env, method);
- WebCore::FormData* formdata = request.httpBody();
- jbyteArray jPostDataStr = getPostData(request);
- jobject jHeaderMap = createJavaMapFromHTTPHeaders(env, headers);
-
- // Convert the WebCore Cache Policy to a WebView Cache Policy.
- int cacheMode = 0; // WebSettings.LOAD_NORMAL
- switch (request.cachePolicy()) {
- case WebCore::ReloadIgnoringCacheData:
- cacheMode = 2; // WebSettings.LOAD_NO_CACHE
- break;
- case WebCore::ReturnCacheDataDontLoad:
- cacheMode = 3; // WebSettings.LOAD_CACHE_ONLY
- break;
- case WebCore::ReturnCacheDataElseLoad:
- cacheMode = 1; // WebSettings.LOAD_CACHE_ELSE_NETWORK
- break;
- case WebCore::UseProtocolCachePolicy:
- default:
- break;
- }
-
- LOGV("::WebCore:: startLoadingResource %s with cacheMode %d", urlStr.ascii().data(), cacheMode);
-
- ResourceHandleInternal* loaderInternal = loader->getInternal();
- jstring jUsernameString = loaderInternal->m_user.isEmpty() ?
- NULL : wtfStringToJstring(env, loaderInternal->m_user);
- jstring jPasswordString = loaderInternal->m_pass.isEmpty() ?
- NULL : wtfStringToJstring(env, loaderInternal->m_pass);
-
- bool isUserGesture = UserGestureIndicator::processingUserGesture();
- jobject jLoadListener =
- env->CallObjectMethod(javaFrame.get(), mJavaFrame->mStartLoadingResource,
- (int)loader, jUrlStr, jMethodStr, jHeaderMap,
- jPostDataStr, formdata ? formdata->identifier(): 0,
- cacheMode, mainResource, isUserGesture,
- synchronous, jUsernameString, jPasswordString);
-
- env->DeleteLocalRef(jUrlStr);
- env->DeleteLocalRef(jMethodStr);
- env->DeleteLocalRef(jPostDataStr);
- env->DeleteLocalRef(jHeaderMap);
- env->DeleteLocalRef(jUsernameString);
- env->DeleteLocalRef(jPasswordString);
- if (checkException(env))
- return 0;
-
- PassRefPtr<WebCore::ResourceLoaderAndroid> h;
- if (jLoadListener)
- h = WebCoreResourceLoader::create(env, jLoadListener);
- env->DeleteLocalRef(jLoadListener);
- return h;
-}
-
UrlInterceptResponse*
WebFrame::shouldInterceptRequest(const WTF::String& url)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
-#endif
- LOGV("::WebCore:: shouldInterceptRequest(%s)", url.latin1().data());
+ ALOGV("::WebCore:: shouldInterceptRequest(%s)", url.latin1().data());
JNIEnv* env = getJNIEnv();
AutoJObject javaFrame = mJavaFrame->frame(env);
@@ -534,10 +420,7 @@ void
WebFrame::reportError(int errorCode, const WTF::String& description,
const WTF::String& failingUrl)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
-#endif
- LOGV("::WebCore:: reportError(%d, %s)", errorCode, description.ascii().data());
+ ALOGV("::WebCore:: reportError(%d, %s)", errorCode, description.ascii().data());
JNIEnv* env = getJNIEnv();
AutoJObject javaFrame = mJavaFrame->frame(env);
if (!javaFrame.get())
@@ -553,7 +436,6 @@ WebFrame::reportError(int errorCode, const WTF::String& description,
WTF::String
WebFrame::convertIDNToUnicode(const WebCore::KURL& url) {
WTF::String converted = url.string();
-#if USE(CHROME_NETWORK_STACK)
const WTF::String host = url.host();
if (host.find("xn--") == notFound) // no punycode IDN found.
return converted;
@@ -566,16 +448,12 @@ WebFrame::convertIDNToUnicode(const WebCore::KURL& url) {
newUrl.setHost(convertedHost);
converted = newUrl.string();
}
-#endif
return converted;
}
void
WebFrame::loadStarted(WebCore::Frame* frame)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
-#endif
JNIEnv* env = getJNIEnv();
AutoJObject javaFrame = mJavaFrame->frame(env);
if (!javaFrame.get())
@@ -589,7 +467,7 @@ WebFrame::loadStarted(WebCore::Frame* frame)
const WebCore::KURL& url = documentLoader->url();
if (url.isEmpty())
return;
- LOGV("::WebCore:: loadStarted %s", url.string().ascii().data());
+ ALOGV("::WebCore:: loadStarted %s", url.string().ascii().data());
bool isMainFrame = (!frame->tree() || !frame->tree()->parent());
WebCore::FrameLoadType loadType = frame->loader()->loadType();
@@ -609,7 +487,7 @@ WebFrame::loadStarted(WebCore::Frame* frame)
WebCore::Image* icon = WebCore::iconDatabase().synchronousIconForPageURL(urlString, WebCore::IntSize(16, 16));
if (icon)
favicon = webcoreImageToJavaBitmap(env, icon);
- LOGV("favicons", "Starting load with icon %p for %s", icon, url.string().utf8().data());
+ ALOGV("favicons", "Starting load with icon %p for %s", icon, url.string().utf8().data());
}
jstring urlStr = wtfStringToJstring(env, urlString);
@@ -633,9 +511,6 @@ WebFrame::loadStarted(WebCore::Frame* frame)
void
WebFrame::transitionToCommitted(WebCore::Frame* frame)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
-#endif
JNIEnv* env = getJNIEnv();
AutoJObject javaFrame = mJavaFrame->frame(env);
if (!javaFrame.get())
@@ -650,9 +525,6 @@ WebFrame::transitionToCommitted(WebCore::Frame* frame)
void
WebFrame::didFinishLoad(WebCore::Frame* frame)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
-#endif
JNIEnv* env = getJNIEnv();
AutoJObject javaFrame = mJavaFrame->frame(env);
if (!javaFrame.get())
@@ -667,7 +539,7 @@ WebFrame::didFinishLoad(WebCore::Frame* frame)
const WebCore::KURL& url = documentLoader->url();
if (url.isEmpty())
return;
- LOGV("::WebCore:: didFinishLoad %s", url.string().ascii().data());
+ ALOGV("::WebCore:: didFinishLoad %s", url.string().ascii().data());
bool isMainFrame = (!frame->tree() || !frame->tree()->parent());
WebCore::FrameLoadType loadType = loader->loadType();
@@ -681,10 +553,7 @@ WebFrame::didFinishLoad(WebCore::Frame* frame)
void
WebFrame::addHistoryItem(WebCore::HistoryItem* item)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
-#endif
- LOGV("::WebCore:: addHistoryItem");
+ ALOGV("::WebCore:: addHistoryItem");
JNIEnv* env = getJNIEnv();
WebHistory::AddItem(mJavaFrame->history(env), item);
}
@@ -692,10 +561,7 @@ WebFrame::addHistoryItem(WebCore::HistoryItem* item)
void
WebFrame::removeHistoryItem(int index)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
-#endif
- LOGV("::WebCore:: removeHistoryItem at %d", index);
+ ALOGV("::WebCore:: removeHistoryItem at %d", index);
JNIEnv* env = getJNIEnv();
WebHistory::RemoveItem(mJavaFrame->history(env), index);
}
@@ -703,10 +569,7 @@ WebFrame::removeHistoryItem(int index)
void
WebFrame::updateHistoryIndex(int newIndex)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
-#endif
- LOGV("::WebCore:: updateHistoryIndex to %d", newIndex);
+ ALOGV("::WebCore:: updateHistoryIndex to %d", newIndex);
JNIEnv* env = getJNIEnv();
WebHistory::UpdateHistoryIndex(mJavaFrame->history(env), newIndex);
}
@@ -714,11 +577,8 @@ WebFrame::updateHistoryIndex(int newIndex)
void
WebFrame::setTitle(const WTF::String& title)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
-#endif
#ifndef NDEBUG
- LOGV("setTitle(%s)", title.ascii().data());
+ ALOGV("setTitle(%s)", title.ascii().data());
#endif
JNIEnv* env = getJNIEnv();
AutoJObject javaFrame = mJavaFrame->frame(env);
@@ -735,10 +595,7 @@ WebFrame::setTitle(const WTF::String& title)
void
WebFrame::windowObjectCleared(WebCore::Frame* frame)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
-#endif
- LOGV("::WebCore:: windowObjectCleared");
+ ALOGV("::WebCore:: windowObjectCleared");
JNIEnv* env = getJNIEnv();
AutoJObject javaFrame = mJavaFrame->frame(env);
if (!javaFrame.get())
@@ -751,9 +608,6 @@ WebFrame::windowObjectCleared(WebCore::Frame* frame)
void
WebFrame::setProgress(float newProgress)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
-#endif
JNIEnv* env = getJNIEnv();
AutoJObject javaFrame = mJavaFrame->frame(env);
if (!javaFrame.get())
@@ -773,10 +627,7 @@ WebFrame::userAgentForURL(const WebCore::KURL* url)
void
WebFrame::didReceiveIcon(WebCore::Image* icon)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
-#endif
- LOG_ASSERT(icon, "DidReceiveIcon called without an image!");
+ ALOG_ASSERT(icon, "DidReceiveIcon called without an image!");
JNIEnv* env = getJNIEnv();
AutoJObject javaFrame = mJavaFrame->frame(env);
if (!javaFrame.get())
@@ -794,9 +645,6 @@ WebFrame::didReceiveIcon(WebCore::Image* icon)
void
WebFrame::didReceiveTouchIconURL(const WTF::String& url, bool precomposed)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
-#endif
JNIEnv* env = getJNIEnv();
AutoJObject javaFrame = mJavaFrame->frame(env);
if (!javaFrame.get())
@@ -812,9 +660,6 @@ WebFrame::didReceiveTouchIconURL(const WTF::String& url, bool precomposed)
void
WebFrame::updateVisitedHistory(const WebCore::KURL& url, bool reload)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
-#endif
JNIEnv* env = getJNIEnv();
AutoJObject javaFrame = mJavaFrame->frame(env);
if (!javaFrame.get())
@@ -831,9 +676,6 @@ WebFrame::updateVisitedHistory(const WebCore::KURL& url, bool reload)
bool
WebFrame::canHandleRequest(const WebCore::ResourceRequest& request)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
-#endif
JNIEnv* env = getJNIEnv();
AutoJObject javaFrame = mJavaFrame->frame(env);
if (!javaFrame.get())
@@ -874,9 +716,6 @@ WebFrame::shouldSaveFormData()
WebCore::Frame*
WebFrame::createWindow(bool dialog, bool userGesture)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
-#endif
JNIEnv* env = getJNIEnv();
AutoJObject javaFrame = mJavaFrame->frame(env);
if (!javaFrame.get())
@@ -890,9 +729,6 @@ WebFrame::createWindow(bool dialog, bool userGesture)
void
WebFrame::requestFocus() const
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
-#endif
JNIEnv* env = getJNIEnv();
AutoJObject javaFrame = mJavaFrame->frame(env);
if (!javaFrame.get())
@@ -904,9 +740,6 @@ WebFrame::requestFocus() const
void
WebFrame::closeWindow(WebViewCore* webViewCore)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
-#endif
assert(webViewCore);
JNIEnv* env = getJNIEnv();
AutoJObject javaFrame = mJavaFrame->frame(env);
@@ -925,9 +758,6 @@ struct PolicyFunctionWrapper {
void
WebFrame::decidePolicyForFormResubmission(WebCore::FramePolicyFunction func)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
-#endif
JNIEnv* env = getJNIEnv();
AutoJObject javaFrame = mJavaFrame->frame(env);
if (!javaFrame.get())
@@ -961,13 +791,9 @@ WebFrame::density() const
return dpi;
}
-#if USE(CHROME_NETWORK_STACK)
void
WebFrame::didReceiveAuthenticationChallenge(WebUrlLoaderClient* client, const std::string& host, const std::string& realm, bool useCachedCredentials, bool suppressDialog)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
-#endif
JNIEnv* env = getJNIEnv();
AutoJObject javaFrame = mJavaFrame->frame(env);
if (!javaFrame.get())
@@ -985,9 +811,6 @@ WebFrame::didReceiveAuthenticationChallenge(WebUrlLoaderClient* client, const st
void
WebFrame::reportSslCertError(WebUrlLoaderClient* client, int error, const std::string& cert, const std::string& url)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
-#endif
JNIEnv* env = getJNIEnv();
AutoJObject javaFrame = mJavaFrame->frame(env);
if (!javaFrame.get())
@@ -1008,9 +831,6 @@ WebFrame::reportSslCertError(WebUrlLoaderClient* client, int error, const std::s
void
WebFrame::requestClientCert(WebUrlLoaderClient* client, const std::string& hostAndPort)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
-#endif
JNIEnv* env = getJNIEnv();
int jHandle = reinterpret_cast<int>(client);
@@ -1024,9 +844,6 @@ WebFrame::requestClientCert(WebUrlLoaderClient* client, const std::string& hostA
void
WebFrame::downloadStart(const std::string& url, const std::string& userAgent, const std::string& contentDisposition, const std::string& mimetype, long long contentLength)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
-#endif
JNIEnv* env = getJNIEnv();
AutoJObject javaFrame = mJavaFrame->frame(env);
if (!javaFrame.get())
@@ -1047,9 +864,6 @@ WebFrame::downloadStart(const std::string& url, const std::string& userAgent, co
void
WebFrame::didReceiveData(const char* data, int size) {
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
-#endif
JNIEnv* env = getJNIEnv();
AutoJObject javaFrame = mJavaFrame->frame(env);
if (!javaFrame.get())
@@ -1064,9 +878,6 @@ WebFrame::didReceiveData(const char* data, int size) {
void
WebFrame::didFinishLoading() {
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
-#endif
JNIEnv* env = getJNIEnv();
AutoJObject javaFrame = mJavaFrame->frame(env);
if (!javaFrame.get())
@@ -1078,9 +889,6 @@ WebFrame::didFinishLoading() {
void WebFrame::setCertificate(const std::string& cert)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
-#endif
JNIEnv* env = getJNIEnv();
AutoJObject javaFrame = mJavaFrame->frame(env);
if (!javaFrame.get())
@@ -1094,13 +902,9 @@ void WebFrame::setCertificate(const std::string& cert)
checkException(env);
}
-#endif // USE(CHROME_NETWORK_STACK)
void WebFrame::autoLogin(const std::string& loginHeader)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimerCoutner::JavaCallbackTimeCounter);
-#endif
JNIEnv* env = getJNIEnv();
AutoJObject javaFrame = mJavaFrame->frame(env);
if (!javaFrame.get())
@@ -1174,7 +978,7 @@ void WebFrame::maybeSavePassword(WebCore::Frame* frame, const WebCore::ResourceR
bool WebFrame::getUsernamePasswordFromDom(WebCore::Frame* frame, WTF::String& username, WTF::String& password)
{
bool found = false;
- WTF::PassRefPtr<WebCore::HTMLCollection> form = frame->document()->forms();
+ WTF::RefPtr<WebCore::HTMLCollection> form = frame->document()->forms();
WebCore::Node* node = form->firstItem();
while (node && !found && !node->namespaceURI().isNull() &&
!node->namespaceURI().isEmpty()) {
@@ -1271,13 +1075,10 @@ jbyteArray WebFrame::getPostData(const WebCore::ResourceRequest& request)
static void CallPolicyFunction(JNIEnv* env, jobject obj, jint func, jint decision)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
-#endif
WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
- LOG_ASSERT(pFrame, "nativeCallPolicyFunction must take a valid frame pointer!");
+ ALOG_ASSERT(pFrame, "nativeCallPolicyFunction must take a valid frame pointer!");
PolicyFunctionWrapper* pFunc = (PolicyFunctionWrapper*)func;
- LOG_ASSERT(pFunc, "nativeCallPolicyFunction must take a valid function pointer!");
+ ALOG_ASSERT(pFunc, "nativeCallPolicyFunction must take a valid function pointer!");
// If we are resending the form then we should reset the multiple submission protection.
if (decision == WebCore::PolicyUse)
@@ -1290,17 +1091,9 @@ static void CreateFrame(JNIEnv* env, jobject obj, jobject javaview, jobject jAss
{
ScriptController::initializeThreading();
-#if USE(CHROME_NETWORK_STACK)
// needs to be called before any other chromium code
initChromium();
-#endif
-#ifdef ANDROID_INSTRUMENT
-#if USE(V8)
- V8Counters::initCounters();
-#endif
- TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
-#endif
// Create a new page
ChromeClientAndroid* chromeC = new ChromeClientAndroid;
EditorClientAndroid* editorC = new EditorClientAndroid;
@@ -1362,7 +1155,7 @@ static void CreateFrame(JNIEnv* env, jobject obj, jobject javaview, jobject jAss
WebCore::SecurityOrigin::setLocalLoadPolicy(
WebCore::SecurityOrigin::AllowLocalLoadsForLocalAndSubstituteData);
- LOGV("::WebCore:: createFrame %p", frame);
+ ALOGV("::WebCore:: createFrame %p", frame);
// Set the mNativeFrame field in Frame
SET_NATIVE_FRAME(env, obj, (int)frame);
@@ -1370,7 +1163,7 @@ static void CreateFrame(JNIEnv* env, jobject obj, jobject javaview, jobject jAss
String directory = webFrame->getRawResourceFilename(
WebCore::PlatformBridge::DrawableDir);
if (directory.isEmpty())
- LOGE("Can't find the drawable directory");
+ ALOGE("Can't find the drawable directory");
else {
// Initialize our skinning classes
webFrame->setRenderSkins(new WebCore::RenderSkinAndroid(directory));
@@ -1384,13 +1177,10 @@ static void CreateFrame(JNIEnv* env, jobject obj, jobject javaview, jobject jAss
static void DestroyFrame(JNIEnv* env, jobject obj)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
-#endif
WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
- LOG_ASSERT(pFrame, "nativeDestroyFrame must take a valid frame pointer!");
+ ALOG_ASSERT(pFrame, "nativeDestroyFrame must take a valid frame pointer!");
- LOGV("::WebCore:: deleting frame %p", pFrame);
+ ALOGV("::WebCore:: deleting frame %p", pFrame);
WebCore::FrameView* view = pFrame->view();
view->ref();
@@ -1415,11 +1205,8 @@ static void DestroyFrame(JNIEnv* env, jobject obj)
static void LoadUrl(JNIEnv *env, jobject obj, jstring url, jobject headers)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
-#endif
WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
- LOG_ASSERT(pFrame, "nativeLoadUrl must take a valid frame pointer!");
+ ALOG_ASSERT(pFrame, "nativeLoadUrl must take a valid frame pointer!");
WTF::String webcoreUrl = jstringToWtfString(env, url);
WebCore::KURL kurl(WebCore::KURL(), webcoreUrl);
@@ -1463,17 +1250,14 @@ static void LoadUrl(JNIEnv *env, jobject obj, jstring url, jobject headers)
env->DeleteLocalRef(set);
env->DeleteLocalRef(mapClass);
}
- LOGV("LoadUrl %s", kurl.string().latin1().data());
+ ALOGV("LoadUrl %s", kurl.string().latin1().data());
pFrame->loader()->load(request, false);
}
static void PostUrl(JNIEnv *env, jobject obj, jstring url, jbyteArray postData)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
-#endif
WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
- LOG_ASSERT(pFrame, "nativePostUrl must take a valid frame pointer!");
+ ALOG_ASSERT(pFrame, "nativePostUrl must take a valid frame pointer!");
WebCore::KURL kurl(WebCore::KURL(), jstringToWtfString(env, url));
WebCore::ResourceRequest request(kurl);
@@ -1491,7 +1275,7 @@ static void PostUrl(JNIEnv *env, jobject obj, jstring url, jbyteArray postData)
env->ReleaseByteArrayElements(postData, bytes, 0);
}
- LOGV("PostUrl %s", kurl.string().latin1().data());
+ ALOGV("PostUrl %s", kurl.string().latin1().data());
WebCore::FrameLoadRequest frameRequest(pFrame->document()->securityOrigin(), request);
pFrame->loader()->loadFrameRequest(frameRequest, false, false, 0, 0, WebCore::SendReferrer);
}
@@ -1499,22 +1283,19 @@ static void PostUrl(JNIEnv *env, jobject obj, jstring url, jbyteArray postData)
static void LoadData(JNIEnv *env, jobject obj, jstring baseUrl, jstring data,
jstring mimeType, jstring encoding, jstring failUrl)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
-#endif
WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
- LOG_ASSERT(pFrame, "nativeLoadData must take a valid frame pointer!");
+ ALOG_ASSERT(pFrame, "nativeLoadData must take a valid frame pointer!");
// Setup the resource request
WebCore::ResourceRequest request(jstringToWtfString(env, baseUrl));
// Setup the substituteData
- const char* dataStr = env->GetStringUTFChars(data, NULL);
- WTF::PassRefPtr<WebCore::SharedBuffer> sharedBuffer =
+ WTF::CString cData = jstringToWtfString(env, data).utf8();
+ const char* dataStr = cData.data();
+ WTF::RefPtr<WebCore::SharedBuffer> sharedBuffer =
WebCore::SharedBuffer::create();
- LOG_ASSERT(dataStr, "nativeLoadData has a null data string.");
- sharedBuffer->append(dataStr, strlen(dataStr));
- env->ReleaseStringUTFChars(data, dataStr);
+ ALOG_ASSERT(dataStr, "nativeLoadData has a null data string.");
+ sharedBuffer->append(dataStr, strlen(dataStr)); // copy dataStr
WebCore::SubstituteData substituteData(sharedBuffer,
jstringToWtfString(env, mimeType), jstringToWtfString(env, encoding),
@@ -1526,12 +1307,9 @@ static void LoadData(JNIEnv *env, jobject obj, jstring baseUrl, jstring data,
static void StopLoading(JNIEnv *env, jobject obj)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
-#endif
WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
- LOG_ASSERT(pFrame, "nativeStopLoading must take a valid frame pointer!");
- LOGV("::WebCore:: stopLoading %p", pFrame);
+ ALOG_ASSERT(pFrame, "nativeStopLoading must take a valid frame pointer!");
+ ALOGV("::WebCore:: stopLoading %p", pFrame);
// Stop loading the page and do not send an unload event
pFrame->loader()->stopForUserCancel();
@@ -1579,7 +1357,7 @@ static jstring SaveWebArchive(JNIEnv *env, jobject obj, jstring basename, jboole
{
#if ENABLE(WEB_ARCHIVE)
WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
- LOG_ASSERT(pFrame, "nativeSaveWebArchive must take a valid frame pointer!");
+ ALOG_ASSERT(pFrame, "nativeSaveWebArchive must take a valid frame pointer!");
String mimeType = pFrame->loader()->documentLoader()->mainResource()->mimeType();
if ((mimeType != "text/html") && (mimeType != "application/xhtml+xml"))
return NULL;
@@ -1597,7 +1375,7 @@ static jstring SaveWebArchive(JNIEnv *env, jobject obj, jstring basename, jboole
}
if (filename.isNull() || filename.isEmpty()) {
- LOGD("saveWebArchive: Failed to select a filename to save.");
+ ALOGD("saveWebArchive: Failed to select a filename to save.");
releaseCharactersForJStringInEnv(env, basename, basenameNative);
return NULL;
}
@@ -1605,7 +1383,7 @@ static jstring SaveWebArchive(JNIEnv *env, jobject obj, jstring basename, jboole
const int noCompression = 0;
xmlTextWriterPtr writer = xmlNewTextWriterFilename(filename.utf8().data(), noCompression);
if (writer == NULL) {
- LOGD("saveWebArchive: Failed to initialize xml writer.");
+ ALOGD("saveWebArchive: Failed to initialize xml writer.");
releaseCharactersForJStringInEnv(env, basename, basenameNative);
return NULL;
}
@@ -1626,11 +1404,8 @@ static jstring SaveWebArchive(JNIEnv *env, jobject obj, jstring basename, jboole
static jstring ExternalRepresentation(JNIEnv *env, jobject obj)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
-#endif
WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
- LOG_ASSERT(pFrame, "android_webcore_nativeExternalRepresentation must take a valid frame pointer!");
+ ALOG_ASSERT(pFrame, "android_webcore_nativeExternalRepresentation must take a valid frame pointer!");
// Request external representation of the render tree
WTF::String renderDump = WebCore::externalRepresentation(pFrame);
@@ -1661,11 +1436,8 @@ static StringBuilder FrameAsText(WebCore::Frame *pFrame, jboolean dumpChildFrame
static jstring DocumentAsText(JNIEnv *env, jobject obj)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
-#endif
WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
- LOG_ASSERT(pFrame, "android_webcore_nativeDocumentAsText must take a valid frame pointer!");
+ ALOG_ASSERT(pFrame, "android_webcore_nativeDocumentAsText must take a valid frame pointer!");
WTF::String renderDump = FrameAsText(pFrame, false /* dumpChildFrames */).toString();
return wtfStringToJstring(env, renderDump);
@@ -1673,11 +1445,8 @@ static jstring DocumentAsText(JNIEnv *env, jobject obj)
static jstring ChildFramesAsText(JNIEnv *env, jobject obj)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
-#endif
WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
- LOG_ASSERT(pFrame, "android_webcore_nativeDocumentAsText must take a valid frame pointer!");
+ ALOG_ASSERT(pFrame, "android_webcore_nativeDocumentAsText must take a valid frame pointer!");
StringBuilder renderDumpBuilder;
for (unsigned i = 0; i < pFrame->tree()->childCount(); ++i) {
@@ -1689,11 +1458,8 @@ static jstring ChildFramesAsText(JNIEnv *env, jobject obj)
static void Reload(JNIEnv *env, jobject obj, jboolean allowStale)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
-#endif
WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
- LOG_ASSERT(pFrame, "nativeReload must take a valid frame pointer!");
+ ALOG_ASSERT(pFrame, "nativeReload must take a valid frame pointer!");
WebCore::FrameLoader* loader = pFrame->loader();
if (allowStale) {
@@ -1709,11 +1475,8 @@ static void Reload(JNIEnv *env, jobject obj, jboolean allowStale)
static void GoBackOrForward(JNIEnv *env, jobject obj, jint pos)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
-#endif
WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
- LOG_ASSERT(pFrame, "nativeGoBackOrForward must take a valid frame pointer!");
+ ALOG_ASSERT(pFrame, "nativeGoBackOrForward must take a valid frame pointer!");
if (pos == 1)
pFrame->page()->goForward();
@@ -1725,11 +1488,8 @@ static void GoBackOrForward(JNIEnv *env, jobject obj, jint pos)
static jobject StringByEvaluatingJavaScriptFromString(JNIEnv *env, jobject obj, jstring script)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
-#endif
WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
- LOG_ASSERT(pFrame, "stringByEvaluatingJavaScriptFromString must take a valid frame pointer!");
+ ALOG_ASSERT(pFrame, "stringByEvaluatingJavaScriptFromString must take a valid frame pointer!");
WebCore::ScriptValue value =
pFrame->script()->executeScript(jstringToWtfString(env, script), true);
@@ -1743,32 +1503,16 @@ static jobject StringByEvaluatingJavaScriptFromString(JNIEnv *env, jobject obj,
// Wrap the JavaInstance used when binding custom javascript interfaces. Use a
// weak reference so that the gc can collect the WebView. Override virtualBegin
// and virtualEnd and swap the weak reference for the real object.
-#if USE(JSC)
-class WeakJavaInstance : public JavaInstance {
-#elif USE(V8)
class WeakJavaInstance : public JavaInstanceJobject {
-#endif
public:
-#if USE(JSC)
- static PassRefPtr<WeakJavaInstance> create(jobject obj, PassRefPtr<RootObject> root)
- {
- return adoptRef(new WeakJavaInstance(obj, root));
- }
-#elif USE(V8)
static PassRefPtr<WeakJavaInstance> create(jobject obj)
{
return adoptRef(new WeakJavaInstance(obj));
}
-#endif
private:
-#if USE(JSC)
- WeakJavaInstance(jobject instance, PassRefPtr<RootObject> rootObject)
- : JavaInstance(instance, rootObject)
-#elif USE(V8)
WeakJavaInstance(jobject instance)
: JavaInstanceJobject(instance)
-#endif
, m_beginEndDepth(0)
{
JNIEnv* env = getJNIEnv();
@@ -1780,7 +1524,7 @@ private:
}
~WeakJavaInstance()
{
- LOG_ASSERT(!m_beginEndDepth, "Unbalanced calls to WeakJavaInstance::begin() / end()");
+ ALOG_ASSERT(!m_beginEndDepth, "Unbalanced calls to WeakJavaInstance::begin() / end()");
JNIEnv* env = getJNIEnv();
// The JavaInstance destructor attempts to delete the global ref stored
// in m_instance. Since we replaced it in our constructor with a weak
@@ -1818,11 +1562,7 @@ private:
}
private:
-#if USE(JSC)
- typedef JavaInstance INHERITED;
-#elif USE(V8)
typedef JavaInstanceJobject INHERITED;
-#endif
jweak m_weakRef;
// The current depth of nested calls to virtualBegin and virtualEnd.
int m_beginEndDepth;
@@ -1831,42 +1571,17 @@ private:
static void AddJavascriptInterface(JNIEnv *env, jobject obj, jint nativeFramePointer,
jobject javascriptObj, jstring interfaceName)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
-#endif
WebCore::Frame* pFrame = 0;
if (nativeFramePointer == 0)
pFrame = GET_NATIVE_FRAME(env, obj);
else
pFrame = (WebCore::Frame*)nativeFramePointer;
- LOG_ASSERT(pFrame, "nativeAddJavascriptInterface must take a valid frame pointer!");
+ ALOG_ASSERT(pFrame, "nativeAddJavascriptInterface must take a valid frame pointer!");
JavaVM* vm;
env->GetJavaVM(&vm);
- LOGV("::WebCore:: addJSInterface: %p", pFrame);
-
-#if USE(JSC)
- // Copied from qwebframe.cpp
- JSC::JSLock lock(JSC::SilenceAssertionsOnly);
- WebCore::JSDOMWindow *window = WebCore::toJSDOMWindow(pFrame, mainThreadNormalWorld());
- if (window) {
- RootObject *root = pFrame->script()->bindingRootObject();
- setJavaVM(vm);
- // Add the binding to JS environment
- JSC::ExecState* exec = window->globalExec();
- JSC::JSObject* addedObject = WeakJavaInstance::create(javascriptObj,
- root)->createRuntimeObject(exec);
- const jchar* s = env->GetStringChars(interfaceName, NULL);
- if (s) {
- // Add the binding name to the window's table of child objects.
- JSC::PutPropertySlot slot;
- window->put(exec, JSC::Identifier(exec, (const UChar *)s,
- env->GetStringLength(interfaceName)), addedObject, slot);
- env->ReleaseStringChars(interfaceName, s);
- checkException(env);
- }
- }
-#elif USE(V8)
+ ALOGV("::WebCore:: addJSInterface: %p", pFrame);
+
if (pFrame) {
RefPtr<JavaInstance> addedObject = WeakJavaInstance::create(javascriptObj);
const char* name = getCharactersFromJStringInEnv(env, interfaceName);
@@ -1887,24 +1602,6 @@ static void AddJavascriptInterface(JNIEnv *env, jobject obj, jint nativeFramePoi
NPN_ReleaseObject(npObject);
releaseCharactersForJString(interfaceName, name);
}
-#endif
-
-}
-
-static void SetCacheDisabled(JNIEnv *env, jobject obj, jboolean disabled)
-{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
-#endif
- WebCore::memoryCache()->setDisabled(disabled);
-}
-
-static jboolean CacheDisabled(JNIEnv *env, jobject obj)
-{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
-#endif
- return WebCore::memoryCache()->disabled();
}
static void ClearWebCoreCache()
@@ -1926,59 +1623,32 @@ static void ClearWebCoreCache()
static void ClearWebViewCache()
{
-#if USE(CHROME_NETWORK_STACK)
WebCache::get(false /*privateBrowsing*/)->clear();
-#else
- // The Android network stack provides a WebView cache in CacheManager.java.
- // Clearing this is handled entirely Java-side.
-#endif
}
static void ClearCache(JNIEnv *env, jobject obj)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
-#if USE(JSC)
- JSC::JSLock lock(false);
- JSC::Heap::Statistics jsHeapStatistics = WebCore::JSDOMWindow::commonJSGlobalData()->heap.statistics();
- LOGD("About to gc and JavaScript heap size is %d and has %d bytes free",
- jsHeapStatistics.size, jsHeapStatistics.free);
-#endif // USE(JSC)
- LOGD("About to clear cache and current cache has %d bytes live and %d bytes dead",
- memoryCache()->getLiveSize(), memoryCache()->getDeadSize());
-#endif // ANDROID_INSTRUMENT
ClearWebCoreCache();
ClearWebViewCache();
-#if USE(JSC)
- // force JavaScript to GC when clear cache
- WebCore::gcController().garbageCollectSoon();
-#elif USE(V8)
WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
pFrame->script()->lowMemoryNotification();
-#endif // USE(JSC)
}
static jboolean DocumentHasImages(JNIEnv *env, jobject obj)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
-#endif
WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
- LOG_ASSERT(pFrame, "DocumentHasImages must take a valid frame pointer!");
+ ALOG_ASSERT(pFrame, "DocumentHasImages must take a valid frame pointer!");
return pFrame->document()->images()->length() > 0;
}
static jboolean HasPasswordField(JNIEnv *env, jobject obj)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
-#endif
WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
- LOG_ASSERT(pFrame, "HasPasswordField must take a valid frame pointer!");
+ ALOG_ASSERT(pFrame, "HasPasswordField must take a valid frame pointer!");
bool found = false;
- WTF::PassRefPtr<WebCore::HTMLCollection> form = pFrame->document()->forms();
+ WTF::RefPtr<WebCore::HTMLCollection> form = pFrame->document()->forms();
WebCore::Node* node = form->firstItem();
// Null/Empty namespace means that node is not created in HTMLFormElement
// class, but just normal Element class.
@@ -2001,11 +1671,8 @@ static jboolean HasPasswordField(JNIEnv *env, jobject obj)
static jobjectArray GetUsernamePassword(JNIEnv *env, jobject obj)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
-#endif
WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
- LOG_ASSERT(pFrame, "GetUsernamePassword must take a valid frame pointer!");
+ ALOG_ASSERT(pFrame, "GetUsernamePassword must take a valid frame pointer!");
jobjectArray strArray = NULL;
WTF::String username;
WTF::String password;
@@ -2022,16 +1689,13 @@ static jobjectArray GetUsernamePassword(JNIEnv *env, jobject obj)
static void SetUsernamePassword(JNIEnv *env, jobject obj,
jstring username, jstring password)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
-#endif
WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
- LOG_ASSERT(pFrame, "SetUsernamePassword must take a valid frame pointer!");
+ ALOG_ASSERT(pFrame, "SetUsernamePassword must take a valid frame pointer!");
WebCore::HTMLInputElement* usernameEle = NULL;
WebCore::HTMLInputElement* passwordEle = NULL;
bool found = false;
- WTF::PassRefPtr<WebCore::HTMLCollection> form = pFrame->document()->forms();
+ WTF::RefPtr<WebCore::HTMLCollection> form = pFrame->document()->forms();
WebCore::Node* node = form->firstItem();
while (node && !found && !node->namespaceURI().isNull() &&
!node->namespaceURI().isEmpty()) {
@@ -2071,14 +1735,14 @@ WebFrame::saveFormData(HTMLFormElement* form)
if (form->autoComplete()) {
JNIEnv* env = getJNIEnv();
jclass mapClass = env->FindClass("java/util/HashMap");
- LOG_ASSERT(mapClass, "Could not find HashMap class!");
+ ALOG_ASSERT(mapClass, "Could not find HashMap class!");
jmethodID init = env->GetMethodID(mapClass, "<init>", "(I)V");
- LOG_ASSERT(init, "Could not find constructor for HashMap");
+ ALOG_ASSERT(init, "Could not find constructor for HashMap");
jobject hashMap = env->NewObject(mapClass, init, 1);
- LOG_ASSERT(hashMap, "Could not create a new HashMap");
+ ALOG_ASSERT(hashMap, "Could not create a new HashMap");
jmethodID put = env->GetMethodID(mapClass, "put",
"(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
- LOG_ASSERT(put, "Could not find put method on HashMap");
+ ALOG_ASSERT(put, "Could not find put method on HashMap");
WTF::Vector<WebCore::FormAssociatedElement*> elements = form->associatedElements();
size_t size = elements.size();
for (size_t i = 0; i < size; i++) {
@@ -2093,7 +1757,7 @@ WebFrame::saveFormData(HTMLFormElement* form)
const WTF::AtomicString& name = input->name();
jstring key = wtfStringToJstring(env, name);
jstring val = wtfStringToJstring(env, value);
- LOG_ASSERT(key && val, "name or value not set");
+ ALOG_ASSERT(key && val, "name or value not set");
env->CallObjectMethod(hashMap, put, key, val);
env->DeleteLocalRef(key);
env->DeleteLocalRef(val);
@@ -2109,11 +1773,8 @@ WebFrame::saveFormData(HTMLFormElement* form)
static void OrientationChanged(JNIEnv *env, jobject obj, int orientation)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
-#endif
WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
- LOGV("Sending orientation: %d", orientation);
+ ALOGV("Sending orientation: %d", orientation);
pFrame->sendOrientationChangeEvent(orientation);
}
@@ -2126,8 +1787,9 @@ static jboolean GetShouldStartScrolledRight(JNIEnv *env, jobject obj,
if (document) {
RenderStyle* style = document->renderer()->style();
WritingMode writingMode = style->writingMode();
- LOG_ASSERT(writingMode != WebCore::BottomToTopWritingMode,
- "BottomToTopWritingMode isn't supported");
+ ALOG_ASSERT(writingMode != WebCore::BottomToTopWritingMode,
+ "BottomToTopWritingMode isn't possible in any "
+ "language and cannot be specified in w3c writing-mode.");
if (writingMode == WebCore::RightToLeftWritingMode)
startScrolledRight = true; // vertical-rl pages start scrolled right
else if (writingMode == WebCore::TopToBottomWritingMode)
@@ -2136,8 +1798,6 @@ static jboolean GetShouldStartScrolledRight(JNIEnv *env, jobject obj,
return startScrolledRight;
}
-#if USE(CHROME_NETWORK_STACK)
-
static void AuthenticationProceed(JNIEnv *env, jobject obj, int handle, jstring jUsername, jstring jPassword)
{
WebUrlLoaderClient* client = reinterpret_cast<WebUrlLoaderClient*>(handle);
@@ -2164,39 +1824,12 @@ static void SslCertErrorCancel(JNIEnv *env, jobject obj, int handle, int cert_er
client->cancelSslCertError(cert_error);
}
-static void SslClientCert(JNIEnv *env, jobject obj, int handle, jbyteArray pkey, jobjectArray chain)
+static scoped_refptr<net::X509Certificate> getX509Cert(JNIEnv *env, jobjectArray chain)
{
- WebUrlLoaderClient* client = reinterpret_cast<WebUrlLoaderClient*>(handle);
- if (pkey == NULL || chain == NULL) {
- client->sslClientCert(NULL, NULL);
- return;
- }
-
- // Based on Android's NativeCrypto_SSL_use_PrivateKey
- ScopedByteArrayRO pkeyBytes(env, pkey);
- if (pkeyBytes.get() == NULL) {
- client->sslClientCert(NULL, NULL);
- return;
- }
-
- base::ScopedOpenSSL<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free> pkcs8;
- const unsigned char* pkeyChars = reinterpret_cast<const unsigned char*>(pkeyBytes.get());
- pkcs8.reset(d2i_PKCS8_PRIV_KEY_INFO(NULL, &pkeyChars, pkeyBytes.size()));
- if (!pkcs8.get()) {
- client->sslClientCert(NULL, NULL);
- return;
- }
- base::ScopedOpenSSL<EVP_PKEY, EVP_PKEY_free> privateKey(EVP_PKCS82PKEY(pkcs8.get()));
- if (!privateKey.get()) {
- client->sslClientCert(NULL, NULL);
- return;
- }
-
// Based on Android's NativeCrypto_SSL_use_certificate
int length = env->GetArrayLength(chain);
if (length == 0) {
- client->sslClientCert(NULL, NULL);
- return;
+ return NULL;
}
base::ScopedOpenSSL<X509, X509_free> first;
@@ -2205,20 +1838,17 @@ static void SslClientCert(JNIEnv *env, jobject obj, int handle, jbyteArray pkey,
ScopedLocalRef<jbyteArray> cert(env,
reinterpret_cast<jbyteArray>(env->GetObjectArrayElement(chain, i)));
if (cert.get() == NULL) {
- client->sslClientCert(NULL, NULL);
- return;
+ return NULL;
}
ScopedByteArrayRO certBytes(env, cert.get());
if (certBytes.get() == NULL) {
- client->sslClientCert(NULL, NULL);
- return;
+ return NULL;
}
const char* data = reinterpret_cast<const char*>(certBytes.get());
int length = certBytes.size();
X509* x509 = net::X509Certificate::CreateOSCertHandleFromBytes(data, length);
if (x509 == NULL) {
- client->sslClientCert(NULL, NULL);
- return;
+ return NULL;
}
if (i == 0) {
first.reset(x509);
@@ -2231,44 +1861,62 @@ static void SslClientCert(JNIEnv *env, jobject obj, int handle, jbyteArray pkey,
for (size_t i = 0; i < rest.size(); i++) {
certChain[i] = rest[i]->get();
}
- net::X509Certificate* certificate
- = net::X509Certificate::CreateFromHandle(first.get(),
- net::X509Certificate::SOURCE_FROM_NETWORK,
- certChain);
- if (certificate == NULL) {
- client->sslClientCert(NULL, NULL);
- return;
- }
- client->sslClientCert(privateKey.release(), certificate);
-}
-
-#else
-
-static void AuthenticationProceed(JNIEnv *env, jobject obj, int handle, jstring jUsername, jstring jPassword)
-{
- LOGW("Chromium authentication API called, but libchromium is not available");
+ return net::X509Certificate::CreateFromHandle(first.get(),
+ net::X509Certificate::SOURCE_FROM_NETWORK,
+ certChain);
}
-static void AuthenticationCancel(JNIEnv *env, jobject obj, int handle)
+static void SslClientCertPKCS8(JNIEnv *env, jobject obj, int handle, jbyteArray pkey, jobjectArray chain)
{
- LOGW("Chromium authentication API called, but libchromium is not available");
-}
+ WebUrlLoaderClient* client = reinterpret_cast<WebUrlLoaderClient*>(handle);
+ if (pkey == NULL || chain == NULL) {
+ client->sslClientCert(NULL, NULL);
+ return;
+ }
-static void SslCertErrorProceed(JNIEnv *env, jobject obj, int handle)
-{
- LOGW("Chromium SSL API called, but libchromium is not available");
-}
+ // Based on Android's NativeCrypto_SSL_use_PrivateKey
+ ScopedByteArrayRO pkeyBytes(env, pkey);
+ if (pkeyBytes.get() == NULL) {
+ client->sslClientCert(NULL, NULL);
+ return;
+ }
-static void SslCertErrorCancel(JNIEnv *env, jobject obj, int handle, int cert_error)
-{
- LOGW("Chromium SSL API called, but libchromium is not available");
+ base::ScopedOpenSSL<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free> pkcs8;
+ const unsigned char* pkeyChars = reinterpret_cast<const unsigned char*>(pkeyBytes.get());
+ pkcs8.reset(d2i_PKCS8_PRIV_KEY_INFO(NULL, &pkeyChars, pkeyBytes.size()));
+ if (!pkcs8.get()) {
+ client->sslClientCert(NULL, NULL);
+ return;
+ }
+ base::ScopedOpenSSL<EVP_PKEY, EVP_PKEY_free> privateKey(EVP_PKCS82PKEY(pkcs8.get()));
+ if (!privateKey.get()) {
+ client->sslClientCert(NULL, NULL);
+ return;
+ }
+ scoped_refptr<net::X509Certificate> certificate = getX509Cert(env, chain);
+ if (certificate == NULL) {
+ client->sslClientCert(NULL, NULL);
+ return;
+ }
+ client->sslClientCert(privateKey.release(), certificate);
}
-static void SslClientCert(JNIEnv *env, jobject obj, int handle, jbyteArray privateKey, jobjectArray chain)
+static void SslClientCertCtx(JNIEnv *env, jobject obj, int handle, jint ctx, jobjectArray chain)
{
- LOGW("Chromium SSL API called, but libchromium is not available");
+ WebUrlLoaderClient* client = reinterpret_cast<WebUrlLoaderClient*>(handle);
+ EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(static_cast<uintptr_t>(ctx));
+ if (pkey == NULL || chain == NULL) {
+ client->sslClientCert(NULL, NULL);
+ return;
+ }
+ scoped_refptr<net::X509Certificate> certificate = getX509Cert(env, chain);
+ if (certificate == NULL) {
+ client->sslClientCert(NULL, NULL);
+ return;
+ }
+ CRYPTO_add(&pkey->references, 1, CRYPTO_LOCK_EVP_PKEY);
+ client->sslClientCert(pkey, certificate);
}
-#endif // USE(CHROME_NETWORK_STACK)
// ----------------------------------------------------------------------------
@@ -2308,10 +1956,6 @@ static JNINativeMethod gBrowserFrameNativeMethods[] = {
{ "stringByEvaluatingJavaScriptFromString",
"(Ljava/lang/String;)Ljava/lang/String;",
(void*) StringByEvaluatingJavaScriptFromString },
- { "setCacheDisabled", "(Z)V",
- (void*) SetCacheDisabled },
- { "cacheDisabled", "()Z",
- (void*) CacheDisabled },
{ "clearCache", "()V",
(void*) ClearCache },
{ "documentHasImages", "()Z",
@@ -2332,8 +1976,10 @@ static JNINativeMethod gBrowserFrameNativeMethods[] = {
(void*) SslCertErrorProceed },
{ "nativeSslCertErrorCancel", "(II)V",
(void*) SslCertErrorCancel },
+ { "nativeSslClientCert", "(II[[B)V",
+ (void*) SslClientCertCtx },
{ "nativeSslClientCert", "(I[B[[B)V",
- (void*) SslClientCert },
+ (void*) SslClientCertPKCS8 },
{ "nativeGetShouldStartScrolledRight", "(I)Z",
(void*) GetShouldStartScrolledRight },
};
@@ -2341,9 +1987,9 @@ static JNINativeMethod gBrowserFrameNativeMethods[] = {
int registerWebFrame(JNIEnv* env)
{
jclass clazz = env->FindClass("android/webkit/BrowserFrame");
- LOG_ASSERT(clazz, "Cannot find BrowserFrame");
+ ALOG_ASSERT(clazz, "Cannot find BrowserFrame");
gFrameField = env->GetFieldID(clazz, "mNativeFrame", "I");
- LOG_ASSERT(gFrameField, "Cannot find mNativeFrame on BrowserFrame");
+ ALOG_ASSERT(gFrameField, "Cannot find mNativeFrame on BrowserFrame");
env->DeleteLocalRef(clazz);
return jniRegisterNativeMethods(env, "android/webkit/BrowserFrame",
diff --git a/Source/WebKit/android/jni/WebCoreFrameBridge.h b/Source/WebKit/android/jni/WebCoreFrameBridge.h
index eaee63c..30c1d83 100644
--- a/Source/WebKit/android/jni/WebCoreFrameBridge.h
+++ b/Source/WebKit/android/jni/WebCoreFrameBridge.h
@@ -64,10 +64,6 @@ class WebFrame : public WebCoreRefObject {
// helper function
static WebFrame* getWebFrame(const WebCore::Frame* frame);
- virtual PassRefPtr<WebCore::ResourceLoaderAndroid> startLoadingResource(WebCore::ResourceHandle*,
- const WebCore::ResourceRequest& request, bool mainResource,
- bool synchronous);
-
UrlInterceptResponse* shouldInterceptRequest(const WTF::String& url);
void reportError(int errorCode, const WTF::String& description,
@@ -117,7 +113,6 @@ class WebFrame : public WebCoreRefObject {
float density() const;
-#if USE(CHROME_NETWORK_STACK)
void didReceiveAuthenticationChallenge(WebUrlLoaderClient*, const std::string& host, const std::string& realm, bool useCachedCredentials, bool suppressDialog);
void reportSslCertError(WebUrlLoaderClient* client, int cert_error, const std::string& cert, const std::string& url);
void requestClientCert(WebUrlLoaderClient* client, const std::string& hostAndPort);
@@ -125,7 +120,6 @@ class WebFrame : public WebCoreRefObject {
void didReceiveData(const char* data, int size);
void didFinishLoading();
void setCertificate(const std::string& cert);
-#endif
void maybeSavePassword(WebCore::Frame* frame, const WebCore::ResourceRequest& request);
@@ -134,13 +128,6 @@ class WebFrame : public WebCoreRefObject {
// application.
void autoLogin(const std::string& loginHeader);
- /**
- * When the user initiates a click, we set mUserInitiatedAction to true.
- * If a load happens due to this click, then we ask the application if it wants
- * to override the load. Otherwise, we attempt to load the resource internally.
- */
- void setUserInitiatedAction(bool userInitiatedAction) { mUserInitiatedAction = userInitiatedAction; }
-
WebCore::Page* page() const { return mPage; }
// Currently used only by the chrome net stack. A similar field is used by
@@ -169,7 +156,6 @@ class WebFrame : public WebCoreRefObject {
WebCore::Page* mPage;
WTF::String mUserAgent;
bool mBlockNetworkLoads;
- bool mUserInitiatedAction;
WebCore::RenderSkinAndroid* m_renderSkins;
};
diff --git a/Source/WebKit/android/jni/WebCoreJni.cpp b/Source/WebKit/android/jni/WebCoreJni.cpp
index 2a07999..72ded59 100644
--- a/Source/WebKit/android/jni/WebCoreJni.cpp
+++ b/Source/WebKit/android/jni/WebCoreJni.cpp
@@ -26,7 +26,9 @@
#define LOG_TAG "webcoreglue"
#include "config.h"
+#include "IntRect.h"
#include "WebCoreJni.h"
+#include "wtf/Vector.h"
#include "NotImplemented.h"
#include <JNIUtility.h>
@@ -38,7 +40,7 @@ namespace android {
AutoJObject getRealObject(JNIEnv* env, jobject obj)
{
jobject real = env->NewLocalRef(obj);
- LOG_ASSERT(real, "The real object has been deleted!");
+ ALOG_ASSERT(real, "The real object has been deleted!");
return AutoJObject(env, real);
}
@@ -50,7 +52,7 @@ bool checkException(JNIEnv* env)
{
if (env->ExceptionCheck() != 0)
{
- LOGE("*** Uncaught exception returned from Java call!\n");
+ ALOGE("*** Uncaught exception returned from Java call!\n");
env->ExceptionDescribe();
return true;
}
@@ -77,8 +79,6 @@ jstring wtfStringToJstring(JNIEnv* env, const WTF::String& str, bool validOnZero
return length || validOnZeroLength ? env->NewString(str.characters(), length) : 0;
}
-
-#if USE(CHROME_NETWORK_STACK)
string16 jstringToString16(JNIEnv* env, jstring jstr)
{
if (!jstr || !env)
@@ -112,6 +112,37 @@ jstring stdStringToJstring(JNIEnv* env, const std::string& str, bool validOnZero
return !str.empty() || validOnZeroLength ? env->NewStringUTF(str.c_str()) : 0;
}
-#endif
+jobject intRectToRect(JNIEnv* env, const WebCore::IntRect& rect)
+{
+ 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");
+ jobject jrect = env->NewObject(rectClass, rectInit, rect.x(), rect.y(),
+ rect.maxX(), rect.maxY());
+ env->DeleteLocalRef(rectClass);
+ return jrect;
+}
+
+jobjectArray intRectVectorToRectArray(JNIEnv* env, Vector<WebCore::IntRect>& rects)
+{
+ 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);
+ return array;
+}
}
diff --git a/Source/WebKit/android/jni/WebCoreJni.h b/Source/WebKit/android/jni/WebCoreJni.h
index 0f77cc6..e8cc6ea 100644
--- a/Source/WebKit/android/jni/WebCoreJni.h
+++ b/Source/WebKit/android/jni/WebCoreJni.h
@@ -27,6 +27,7 @@
#define WebCoreJni_h
#include "ChromiumIncludes.h"
+#include "IntRect.h"
#include "PlatformString.h"
#include <jni.h>
@@ -81,7 +82,6 @@ WTF::String jstringToWtfString(JNIEnv*, jstring);
// an empty WTF String returns 0.
jstring wtfStringToJstring(JNIEnv*, const WTF::String&, bool validOnZeroLength = false);
-#if USE(CHROME_NETWORK_STACK)
string16 jstringToString16(JNIEnv*, jstring);
std::string jstringToStdString(JNIEnv*, jstring);
@@ -89,8 +89,10 @@ std::string jstringToStdString(JNIEnv*, jstring);
// passing in an empty std::string will result in an empty jstring. Otherwise
// an empty std::string returns 0.
jstring stdStringToJstring(JNIEnv*, const std::string&, bool validOnZeroLength = false);
-#endif
+jobjectArray intRectVectorToRectArray(JNIEnv*, Vector<WebCore::IntRect>&);
+
+jobject intRectToRect(JNIEnv* env, const WebCore::IntRect& rect);
}
#endif
diff --git a/Source/WebKit/android/jni/WebCoreJniOnLoad.cpp b/Source/WebKit/android/jni/WebCoreJniOnLoad.cpp
index bb71bf5..ec052f1 100644
--- a/Source/WebKit/android/jni/WebCoreJniOnLoad.cpp
+++ b/Source/WebKit/android/jni/WebCoreJniOnLoad.cpp
@@ -62,8 +62,6 @@
#include "WebCoreViewBridge.h"
#include "WebFrameView.h"
#include "WebViewCore.h"
-#include "benchmark/Intercept.h"
-#include "benchmark/MyJavaVM.h"
#include <JNIUtility.h>
#include <jni.h>
@@ -75,7 +73,6 @@ namespace android {
extern int registerWebFrame(JNIEnv*);
extern int registerJavaBridge(JNIEnv*);
-extern int registerJniUtil(JNIEnv*);
extern int registerResourceLoader(JNIEnv*);
extern int registerWebViewCore(JNIEnv*);
extern int registerWebHistory(JNIEnv*);
@@ -94,9 +91,7 @@ extern int registerMediaPlayerVideo(JNIEnv*);
#endif
extern int registerDeviceMotionAndOrientationManager(JNIEnv*);
extern int registerCookieManager(JNIEnv*);
-#if USE(CHROME_NETWORK_STACK)
extern int registerCacheManager(JNIEnv*);
-#endif
}
@@ -107,13 +102,11 @@ struct RegistrationMethod {
static RegistrationMethod gWebCoreRegMethods[] = {
{ "JavaBridge", android::registerJavaBridge },
- { "JniUtil", android::registerJniUtil },
{ "WebFrame", android::registerWebFrame },
- { "WebCoreResourceLoader", android::registerResourceLoader },
{ "WebViewCore", android::registerWebViewCore },
{ "WebHistory", android::registerWebHistory },
{ "WebIconDatabase", android::registerWebIconDatabase },
- { "WebSettings", android::registerWebSettings },
+ { "WebSettingsClassic", android::registerWebSettings },
#if ENABLE(DATABASE)
{ "WebStorage", android::registerWebStorage },
#endif
@@ -127,9 +120,7 @@ static RegistrationMethod gWebCoreRegMethods[] = {
#endif
{ "DeviceMotionAndOrientationManager", android::registerDeviceMotionAndOrientationManager },
{ "CookieManager", android::registerCookieManager },
-#if USE(CHROME_NETWORK_STACK)
{ "CacheManager", android::registerCacheManager },
-#endif
};
EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved)
@@ -141,16 +132,16 @@ EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved)
jint result = -1;
if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
- LOGE("GetEnv failed!");
+ ALOGE("GetEnv failed!");
return result;
}
- LOG_ASSERT(env, "Could not retrieve the env!");
+ ALOG_ASSERT(env, "Could not retrieve the env!");
const RegistrationMethod* method = gWebCoreRegMethods;
const RegistrationMethod* end = method + sizeof(gWebCoreRegMethods)/sizeof(RegistrationMethod);
while (method != end) {
if (method->func(env) < 0) {
- LOGE("%s registration failed!", method->name);
+ ALOGE("%s registration failed!", method->name);
return result;
}
method++;
@@ -162,160 +153,3 @@ EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved)
return JNI_VERSION_1_4;
}
-
-class MyJavaSharedClient : public TimerClient, public CookieClient {
-public:
- MyJavaSharedClient() : m_hasTimer(false) {}
- virtual void setSharedTimer(long long timemillis) { m_hasTimer = true; }
- virtual void stopSharedTimer() { m_hasTimer = false; }
- virtual void setSharedTimerCallback(void (*f)()) { m_func = f; }
- virtual void signalServiceFuncPtrQueue() {}
-
- // Cookie methods that do nothing.
- virtual void setCookies(const KURL&, const String&) {}
- virtual String cookies(const KURL&) { return ""; }
- virtual bool cookiesEnabled() { return false; }
-
- bool m_hasTimer;
- void (*m_func)();
-};
-
-static void historyItemChanged(HistoryItem* i) {
- if (i->bridge())
- i->bridge()->updateHistoryItem(i);
-}
-
-namespace android {
-
-EXPORT void benchmark(const char* url, int reloadCount, int width, int height) {
- ScriptController::initializeThreading();
-
- // Setting this allows data: urls to load from a local file.
- SecurityOrigin::setLocalLoadPolicy(SecurityOrigin::AllowLocalLoadsForAll);
-
- // Create the fake JNIEnv and JavaVM
- InitializeJavaVM();
-
- // The real function is private to libwebcore but we know what it does.
- notifyHistoryItemChanged = historyItemChanged;
-
- // Implement the shared timer callback
- MyJavaSharedClient client;
- JavaSharedClient::SetTimerClient(&client);
- JavaSharedClient::SetCookieClient(&client);
-
- // Create the page with all the various clients
- ChromeClientAndroid* chrome = new ChromeClientAndroid;
- EditorClientAndroid* editor = new EditorClientAndroid;
- DeviceMotionClientAndroid* deviceMotion = new DeviceMotionClientAndroid;
- DeviceOrientationClientAndroid* deviceOrientation = new DeviceOrientationClientAndroid;
- WebCore::Page::PageClients pageClients;
- pageClients.chromeClient = chrome;
- pageClients.contextMenuClient = new ContextMenuClientAndroid;
- pageClients.editorClient = editor;
- pageClients.dragClient = new DragClientAndroid;
- pageClients.inspectorClient = new InspectorClientAndroid;
- pageClients.deviceMotionClient = deviceMotion;
- pageClients.deviceOrientationClient = deviceOrientation;
- WebCore::Page* page = new WebCore::Page(pageClients);
- editor->setPage(page);
-
- // Create MyWebFrame that intercepts network requests
- MyWebFrame* webFrame = new MyWebFrame(page);
- webFrame->setUserAgent("Performance testing"); // needs to be non-empty
- chrome->setWebFrame(webFrame);
- // ChromeClientAndroid maintains the reference.
- Release(webFrame);
-
- // Create the Frame and the FrameLoaderClient
- FrameLoaderClientAndroid* loader = new FrameLoaderClientAndroid(webFrame);
- RefPtr<Frame> frame = Frame::create(page, NULL, loader);
- loader->setFrame(frame.get());
-
- // Build our View system, resize it to the given dimensions and release our
- // references. Note: We keep a referenec to frameView so we can layout and
- // draw later without risk of it being deleted.
- WebViewCore* webViewCore = new WebViewCore(JSC::Bindings::getJNIEnv(),
- MY_JOBJECT, frame.get());
- RefPtr<FrameView> frameView = FrameView::create(frame.get());
- WebFrameView* webFrameView = new WebFrameView(frameView.get(), webViewCore);
- frame->setView(frameView);
- frameView->resize(width, height);
- Release(webViewCore);
- Release(webFrameView);
-
- // Initialize the frame and turn of low-bandwidth display (it fails an
- // assertion in the Cache code)
- frame->init();
- frame->selection()->setFocused(true);
- frame->page()->focusController()->setFocused(true);
-
- deviceMotion->setWebViewCore(webViewCore);
- deviceOrientation->setWebViewCore(webViewCore);
-
- // Set all the default settings the Browser normally uses.
- Settings* s = frame->settings();
-#ifdef ANDROID_LAYOUT
- s->setLayoutAlgorithm(Settings::kLayoutNormal); // Normal layout for now
-#endif
- s->setStandardFontFamily("sans-serif");
- s->setFixedFontFamily("monospace");
- s->setSansSerifFontFamily("sans-serif");
- s->setSerifFontFamily("serif");
- s->setCursiveFontFamily("cursive");
- s->setFantasyFontFamily("fantasy");
- s->setMinimumFontSize(8);
- s->setMinimumLogicalFontSize(8);
- s->setDefaultFontSize(16);
- s->setDefaultFixedFontSize(13);
- s->setLoadsImagesAutomatically(true);
- s->setJavaScriptEnabled(true);
- s->setDefaultTextEncodingName("latin1");
- s->setPluginsEnabled(false);
- s->setShrinksStandaloneImagesToFit(false);
-#ifdef ANDROID_LAYOUT
- s->setUseWideViewport(false);
-#endif
-
- // Finally, load the actual data
- ResourceRequest req(url);
- frame->loader()->load(req, false);
-
- do {
- // Layout the page and service the timer
- frame->view()->layout();
- while (client.m_hasTimer) {
- client.m_func();
- JavaSharedClient::ServiceFunctionPtrQueue();
- }
- JavaSharedClient::ServiceFunctionPtrQueue();
-
- // Layout more if needed.
- while (frame->view()->needsLayout())
- frame->view()->layout();
- JavaSharedClient::ServiceFunctionPtrQueue();
-
- if (reloadCount)
- frame->loader()->reload(true);
- } while (reloadCount--);
-
- // Draw into an offscreen bitmap
- SkBitmap bmp;
- bmp.setConfig(SkBitmap::kARGB_8888_Config, width, height);
- bmp.allocPixels();
- SkCanvas canvas(bmp);
- PlatformGraphicsContext ctx(&canvas);
- GraphicsContext gc(&ctx);
- frame->view()->paintContents(&gc, IntRect(0, 0, width, height));
-
- // Write the bitmap to the sdcard
- SkImageEncoder* enc = SkImageEncoder::Create(SkImageEncoder::kPNG_Type);
- enc->encodeFile("/sdcard/webcore_test.png", bmp, 100);
- delete enc;
-
- // Tear down the world.
- frame->loader()->detachFromParent();
- delete page;
-}
-
-} // namespace android
diff --git a/Source/WebKit/android/jni/WebCoreResourceLoader.cpp b/Source/WebKit/android/jni/WebCoreResourceLoader.cpp
deleted file mode 100644
index f9acc97..0000000
--- a/Source/WebKit/android/jni/WebCoreResourceLoader.cpp
+++ /dev/null
@@ -1,352 +0,0 @@
-/*
- * Copyright 2006, 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 "webcoreglue"
-
-#include "config.h"
-#include "WebCoreResourceLoader.h"
-
-#include "ResourceError.h"
-#include "ResourceHandle.h"
-#include "ResourceHandleClient.h"
-#include "ResourceHandleInternal.h"
-#include "ResourceResponse.h"
-#include "SkUtils.h"
-#ifdef ANDROID_INSTRUMENT
-#include "TimeCounter.h"
-#endif
-#include "WebCoreJni.h"
-
-#include <JNIHelp.h>
-#include <JNIUtility.h>
-#include <SkTypes.h>
-#include <stdlib.h>
-#include <utils/misc.h>
-#include <wtf/Platform.h>
-#include <wtf/text/CString.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-static struct resourceloader_t {
- jfieldID mObject;
- jmethodID mCancelMethodID;
- jmethodID mDownloadFileMethodID;
- jmethodID mWillLoadFromCacheMethodID;
- jmethodID mPauseLoadMethodID;
-} gResourceLoader;
-
-// ----------------------------------------------------------------------------
-
-#define GET_NATIVE_HANDLE(env, obj) ((WebCore::ResourceHandle*)env->GetIntField(obj, gResourceLoader.mObject))
-#define SET_NATIVE_HANDLE(env, obj, handle) (env->SetIntField(obj, gResourceLoader.mObject, handle))
-
-//-----------------------------------------------------------------------------
-// ResourceLoadHandler
-
-PassRefPtr<WebCore::ResourceLoaderAndroid> WebCoreResourceLoader::create(JNIEnv *env, jobject jLoadListener)
-{
- return adoptRef<WebCore::ResourceLoaderAndroid>(new WebCoreResourceLoader(env, jLoadListener));
-}
-
-WebCoreResourceLoader::WebCoreResourceLoader(JNIEnv *env, jobject jLoadListener)
- : mPausedLoad(false)
-{
- mJLoader = env->NewGlobalRef(jLoadListener);
-}
-
-WebCoreResourceLoader::~WebCoreResourceLoader()
-{
- JNIEnv* env = JSC::Bindings::getJNIEnv();
- SET_NATIVE_HANDLE(env, mJLoader, 0);
- env->DeleteGlobalRef(mJLoader);
- mJLoader = 0;
-}
-
-void WebCoreResourceLoader::cancel()
-{
- JNIEnv* env = JSC::Bindings::getJNIEnv();
- env->CallVoidMethod(mJLoader, gResourceLoader.mCancelMethodID);
- checkException(env);
-}
-
-void WebCoreResourceLoader::downloadFile()
-{
- JNIEnv* env = JSC::Bindings::getJNIEnv();
- env->CallVoidMethod(mJLoader, gResourceLoader.mDownloadFileMethodID);
- checkException(env);
-}
-
-void WebCoreResourceLoader::pauseLoad(bool pause)
-{
- if (mPausedLoad == pause)
- return;
-
- mPausedLoad = pause;
- JNIEnv* env = JSC::Bindings::getJNIEnv();
- env->CallVoidMethod(mJLoader, gResourceLoader.mPauseLoadMethodID, pause);
- checkException(env);
-}
-
-/*
-* This static method is called to check to see if a POST response is in
-* the cache. This may be slow, but is only used during a navigation to
-* a POST response.
-*/
-bool WebCoreResourceLoader::willLoadFromCache(const WebCore::KURL& url, int64_t identifier)
-{
- JNIEnv* env = JSC::Bindings::getJNIEnv();
- WTF::String urlStr = url.string();
- jstring jUrlStr = wtfStringToJstring(env, urlStr);
- jclass resourceLoader = env->FindClass("android/webkit/LoadListener");
- bool val = env->CallStaticBooleanMethod(resourceLoader, gResourceLoader.mWillLoadFromCacheMethodID, jUrlStr, identifier);
- checkException(env);
- env->DeleteLocalRef(resourceLoader);
- env->DeleteLocalRef(jUrlStr);
-
- return val;
-}
-
-// ----------------------------------------------------------------------------
-void WebCoreResourceLoader::SetResponseHeader(JNIEnv* env, jobject obj, jint nativeResponse, jstring key, jstring val)
-{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::ResourceTimeCounter);
-#endif
-
- WebCore::ResourceResponse* response = (WebCore::ResourceResponse*)nativeResponse;
- LOG_ASSERT(response, "nativeSetResponseHeader must take a valid response pointer!");
-
- LOG_ASSERT(key, "How did a null value become a key?");
- if (val)
- response->setHTTPHeaderField(jstringToWtfString(env, key), jstringToWtfString(env, val));
-}
-
-jint WebCoreResourceLoader::CreateResponse(JNIEnv* env, jobject obj, jstring url, jint statusCode,
- jstring statusText, jstring mimeType, jlong expectedLength,
- jstring encoding)
-{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::ResourceTimeCounter);
-#endif
- LOG_ASSERT(url, "Must have a url in the response!");
- WebCore::KURL kurl(WebCore::ParsedURLString, jstringToWtfString(env, url));
- WTF::String encodingStr;
- WTF::String mimeTypeStr;
- if (mimeType) {
- mimeTypeStr = jstringToWtfString(env, mimeType);
- LOGV("Response setMIMEType: %s", mimeTypeStr.latin1().data());
- }
- if (encoding) {
- encodingStr = jstringToWtfString(env, encoding);
- LOGV("Response setTextEncodingName: %s", encodingStr.latin1().data());
- }
- WebCore::ResourceResponse* response = new WebCore::ResourceResponse(
- kurl, mimeTypeStr, (long long)expectedLength,
- encodingStr, WTF::String());
- response->setHTTPStatusCode(statusCode);
- if (statusText) {
- WTF::String status = jstringToWtfString(env, statusText);
- response->setHTTPStatusText(status);
- LOGV("Response setStatusText: %s", status.latin1().data());
- }
- return (int)response;
-}
-
-void WebCoreResourceLoader::ReceivedResponse(JNIEnv* env, jobject obj, jint nativeResponse)
-{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::ResourceTimeCounter);
-#endif
- WebCore::ResourceHandle* handle = GET_NATIVE_HANDLE(env, obj);
- LOG_ASSERT(handle, "nativeReceivedResponse must take a valid handle!");
- // ResourceLoader::didFail() can set handle to be NULL, we need to check
- if (!handle)
- return;
-
- WebCore::ResourceResponse* response = (WebCore::ResourceResponse*)nativeResponse;
- LOG_ASSERT(response, "nativeReceivedResponse must take a valid resource pointer!");
- handle->client()->didReceiveResponse(handle, *response);
- // As the client makes a copy of the response, delete it here.
- delete response;
-}
-
-void WebCoreResourceLoader::AddData(JNIEnv* env, jobject obj, jbyteArray dataArray, jint length)
-{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::ResourceTimeCounter);
-#endif
- LOGV("webcore_resourceloader data(%d)", length);
-
- WebCore::ResourceHandle* handle = GET_NATIVE_HANDLE(env, obj);
- LOG_ASSERT(handle, "nativeAddData must take a valid handle!");
- // ResourceLoader::didFail() can set handle to be NULL, we need to check
- if (!handle)
- return;
-
- SkAutoMemoryUsageProbe mup("android_webcore_resourceloader_nativeAddData");
-
- bool result = false;
- jbyte * data = env->GetByteArrayElements(dataArray, NULL);
-
- LOG_ASSERT(handle->client(), "Why do we not have a client?");
- handle->client()->didReceiveData(handle, (const char *)data, length, length);
- env->ReleaseByteArrayElements(dataArray, data, JNI_ABORT);
-}
-
-void WebCoreResourceLoader::Finished(JNIEnv* env, jobject obj)
-{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::ResourceTimeCounter);
-#endif
- LOGV("webcore_resourceloader finished");
- WebCore::ResourceHandle* handle = GET_NATIVE_HANDLE(env, obj);
- LOG_ASSERT(handle, "nativeFinished must take a valid handle!");
- // ResourceLoader::didFail() can set handle to be NULL, we need to check
- if (!handle)
- return;
-
- LOG_ASSERT(handle->client(), "Why do we not have a client?");
- handle->client()->didFinishLoading(handle, 0);
-}
-
-jstring WebCoreResourceLoader::RedirectedToUrl(JNIEnv* env, jobject obj,
- jstring baseUrl, jstring redirectTo, jint nativeResponse)
-{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::ResourceTimeCounter);
-#endif
- LOGV("webcore_resourceloader redirectedToUrl");
- WebCore::ResourceHandle* handle = GET_NATIVE_HANDLE(env, obj);
- LOG_ASSERT(handle, "nativeRedirectedToUrl must take a valid handle!");
- // ResourceLoader::didFail() can set handle to be NULL, we need to check
- if (!handle)
- return NULL;
-
- LOG_ASSERT(handle->client(), "Why do we not have a client?");
- WebCore::ResourceRequest r = handle->firstRequest();
- WebCore::KURL url(WebCore::KURL(WebCore::ParsedURLString, jstringToWtfString(env, baseUrl)),
- jstringToWtfString(env, redirectTo));
- WebCore::ResourceResponse* response = (WebCore::ResourceResponse*)nativeResponse;
- // If the url fails to resolve the relative path, return null.
- if (url.protocol().isEmpty()) {
- delete response;
- return NULL;
- } else {
- // Ensure the protocol is lowercase.
- url.setProtocol(url.protocol().lower());
- }
- // Set the url after updating the protocol.
- r.setURL(url);
- if (r.httpMethod() == "POST") {
- r.setHTTPMethod("GET");
- r.clearHTTPReferrer();
- r.setHTTPBody(0);
- r.setHTTPContentType("");
- }
- handle->client()->willSendRequest(handle, r, *response);
- delete response;
- return wtfStringToJstring(env, url.string());
-}
-
-void WebCoreResourceLoader::Error(JNIEnv* env, jobject obj, jint id, jstring description,
- jstring failingUrl)
-{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::ResourceTimeCounter);
-#endif
- LOGV("webcore_resourceloader error");
- WebCore::ResourceHandle* handle = GET_NATIVE_HANDLE(env, obj);
- LOG_ASSERT(handle, "nativeError must take a valid handle!");
- // ResourceLoader::didFail() can set handle to be NULL, we need to check
- if (!handle)
- return;
-
- handle->client()->didFail(handle, WebCore::ResourceError("", id,
- jstringToWtfString(env, failingUrl), jstringToWtfString(env, description)));
-}
-
-// ----------------------------------------------------------------------------
-
-/*
- * JNI registration.
- */
-static JNINativeMethod gResourceloaderMethods[] = {
- /* name, signature, funcPtr */
- { "nativeSetResponseHeader", "(ILjava/lang/String;Ljava/lang/String;)V",
- (void*) WebCoreResourceLoader::SetResponseHeader },
- { "nativeCreateResponse", "(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;JLjava/lang/String;)I",
- (void*) WebCoreResourceLoader::CreateResponse },
- { "nativeReceivedResponse", "(I)V",
- (void*) WebCoreResourceLoader::ReceivedResponse },
- { "nativeAddData", "([BI)V",
- (void*) WebCoreResourceLoader::AddData },
- { "nativeFinished", "()V",
- (void*) WebCoreResourceLoader::Finished },
- { "nativeRedirectedToUrl", "(Ljava/lang/String;Ljava/lang/String;I)Ljava/lang/String;",
- (void*) WebCoreResourceLoader::RedirectedToUrl },
- { "nativeError", "(ILjava/lang/String;Ljava/lang/String;)V",
- (void*) WebCoreResourceLoader::Error }
-};
-
-int registerResourceLoader(JNIEnv* env)
-{
- jclass resourceLoader = env->FindClass("android/webkit/LoadListener");
- LOG_FATAL_IF(resourceLoader == NULL,
- "Unable to find class android/webkit/LoadListener");
-
- gResourceLoader.mObject =
- env->GetFieldID(resourceLoader, "mNativeLoader", "I");
- LOG_FATAL_IF(gResourceLoader.mObject == NULL,
- "Unable to find android/webkit/LoadListener.mNativeLoader");
-
- gResourceLoader.mCancelMethodID =
- env->GetMethodID(resourceLoader, "cancel", "()V");
- LOG_FATAL_IF(gResourceLoader.mCancelMethodID == NULL,
- "Could not find method cancel on LoadListener");
-
- gResourceLoader.mDownloadFileMethodID =
- env->GetMethodID(resourceLoader, "downloadFile", "()V");
- LOG_FATAL_IF(gResourceLoader.mDownloadFileMethodID == NULL,
- "Could not find method downloadFile on LoadListener");
-
- gResourceLoader.mPauseLoadMethodID =
- env->GetMethodID(resourceLoader, "pauseLoad", "(Z)V");
- LOG_FATAL_IF(gResourceLoader.mPauseLoadMethodID == NULL,
- "Could not find method pauseLoad on LoadListener");
-
- gResourceLoader.mWillLoadFromCacheMethodID =
- env->GetStaticMethodID(resourceLoader, "willLoadFromCache", "(Ljava/lang/String;J)Z");
- LOG_FATAL_IF(gResourceLoader.mWillLoadFromCacheMethodID == NULL,
- "Could not find static method willLoadFromCache on LoadListener");
-
- env->DeleteLocalRef(resourceLoader);
-
- return jniRegisterNativeMethods(env, "android/webkit/LoadListener",
- gResourceloaderMethods, NELEM(gResourceloaderMethods));
-}
-
-} /* namespace android */
diff --git a/Source/WebKit/android/jni/WebCoreResourceLoader.h b/Source/WebKit/android/jni/WebCoreResourceLoader.h
deleted file mode 100644
index 0e34a5b..0000000
--- a/Source/WebKit/android/jni/WebCoreResourceLoader.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright 2006, 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 WebCoreResourceLoader_h
-#define WebCoreResourceLoader_h
-
-#include <KURL.h>
-#include <ResourceLoaderAndroid.h>
-#include <jni.h>
-
-namespace android {
-
-class WebCoreResourceLoader : public WebCore::ResourceLoaderAndroid
-{
-public:
- static PassRefPtr<WebCore::ResourceLoaderAndroid> create(JNIEnv *env, jobject jLoadListener);
- virtual ~WebCoreResourceLoader();
-
- /**
- * Call to java to cancel the current load.
- */
- virtual void cancel();
-
- /**
- * Call to java to download the current load rather than feed it
- * back to WebCore
- */
- virtual void downloadFile();
-
- virtual void pauseLoad(bool);
-
- /**
- * Call to java to find out if this URL is in the cache
- */
- static bool willLoadFromCache(const WebCore::KURL& url, int64_t identifier);
-
- // Native jni functions
- static void SetResponseHeader(JNIEnv*, jobject, jint, jstring, jstring);
- static jint CreateResponse(JNIEnv*, jobject, jstring, jint, jstring,
- jstring, jlong, jstring);
- static void ReceivedResponse(JNIEnv*, jobject, jint);
- static void AddData(JNIEnv*, jobject, jbyteArray, jint);
- static void Finished(JNIEnv*, jobject);
- static jstring RedirectedToUrl(JNIEnv*, jobject, jstring, jstring, jint);
- static void Error(JNIEnv*, jobject, jint, jstring, jstring);
-
-protected:
- WebCoreResourceLoader(JNIEnv *env, jobject jLoadListener);
-private:
- jobject mJLoader;
- bool mPausedLoad;
-};
-
-} // end namespace android
-
-#endif
diff --git a/Source/WebKit/android/jni/WebCoreViewBridge.h b/Source/WebKit/android/jni/WebCoreViewBridge.h
index b04a0f9..cca4ca5 100644
--- a/Source/WebKit/android/jni/WebCoreViewBridge.h
+++ b/Source/WebKit/android/jni/WebCoreViewBridge.h
@@ -48,7 +48,7 @@ public:
virtual ~WebCoreViewBridge() { }
- virtual void draw(WebCore::GraphicsContext* ctx,
+ virtual void draw(WebCore::GraphicsContext* ctx,
const WebCore::IntRect& rect) = 0;
const WebCore::IntRect& getBounds() const
diff --git a/Source/WebKit/android/jni/WebFrameView.cpp b/Source/WebKit/android/jni/WebFrameView.cpp
index 8e5eac4..10e31dc 100644
--- a/Source/WebKit/android/jni/WebFrameView.cpp
+++ b/Source/WebKit/android/jni/WebFrameView.cpp
@@ -54,51 +54,16 @@ WebFrameView::~WebFrameView() {
Release(mWebViewCore);
}
-void WebFrameView::draw(WebCore::GraphicsContext* ctx, const WebCore::IntRect& rect) {
+void WebFrameView::draw(WebCore::GraphicsContext* gc, const WebCore::IntRect& rect) {
WebCore::Frame* frame = mFrameView->frame();
- if (NULL == frame->contentRenderer()) {
- // We only do this if there is nothing else to draw.
- // If there is a renderer, it will fill the bg itself, so we don't want to
- // double-draw (slow)
- SkCanvas* canvas = ctx->platformContext()->mCanvas;
- canvas->drawColor(SK_ColorWHITE);
- } else if (frame->tree()->parent()) {
- // Note: this code was moved from FrameLoaderClientAndroid
- //
- // For subframe, create a new translated rect from the given rectangle.
- WebCore::IntRect transRect(rect);
- // In Frame::markAllMatchesForText(), it does a fake paint. So we need
- // to handle the case where platformContext() is null. However, we still
- // want to call paint, since WebKit must have called the paint for a reason.
- SkCanvas* canvas = ctx->platformContext() ? ctx->platformContext()->mCanvas : NULL;
- if (canvas) {
- const WebCore::IntRect& bounds = getBounds();
-
- // Grab the intersection of transRect and the frame's bounds.
- transRect.intersect(bounds);
- if (transRect.isEmpty())
- return;
-
- // Move the transRect into the frame's local coordinates.
- transRect.move(-bounds.x(), -bounds.y());
-
- // Translate the canvas, add a clip.
- canvas->save();
- canvas->translate(SkIntToScalar(bounds.x()), SkIntToScalar(bounds.y()));
- canvas->clipRect(transRect);
- }
- mFrameView->paintContents(ctx, transRect);
- if (canvas)
- canvas->restore();
- } else {
- mFrameView->paintContents(ctx, rect);
+ if (frame->contentRenderer())
+ mFrameView->paintContents(gc, rect);
+ else {
+ // FIXME: I'm not entirely sure this ever happens or is needed
+ gc->setFillColor(WebCore::Color::white, WebCore::ColorSpaceDeviceRGB);
+ gc->fillRect(rect);
}
}
-void WebFrameView::setView(WebCore::FrameView* frameView) {
- mFrameView = frameView;
- mFrameView->setPlatformWidget(this);
-}
-
} // namespace android
diff --git a/Source/WebKit/android/jni/WebFrameView.h b/Source/WebKit/android/jni/WebFrameView.h
index 117b603..ac81afe 100644
--- a/Source/WebKit/android/jni/WebFrameView.h
+++ b/Source/WebKit/android/jni/WebFrameView.h
@@ -47,8 +47,6 @@ namespace android {
return mWebViewCore;
}
- void setView(WebCore::FrameView* frameView);
-
WebCore::FrameView* view() const {
return mFrameView;
}
diff --git a/Source/WebKit/android/jni/WebHistory.cpp b/Source/WebKit/android/jni/WebHistory.cpp
index aa74b81..b6972e4 100644
--- a/Source/WebKit/android/jni/WebHistory.cpp
+++ b/Source/WebKit/android/jni/WebHistory.cpp
@@ -28,6 +28,7 @@
#include "config.h"
#include "WebHistory.h"
+#include "AndroidLog.h"
#include "BackForwardList.h"
#include "BackForwardListImpl.h"
#include "DocumentLoader.h"
@@ -35,6 +36,7 @@
#include "FrameLoader.h"
#include "FrameLoaderClientAndroid.h"
#include "FrameTree.h"
+#include "GraphicsJNI.h"
#include "HistoryItem.h"
#include "IconDatabase.h"
#include "Page.h"
@@ -54,16 +56,13 @@
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 {
jmethodID mInit;
- jmethodID mUpdate;
- jfieldID mTitle;
- jfieldID mUrl;
} gWebHistoryItem;
struct WebBackForwardListFields {
@@ -78,7 +77,7 @@ struct WebBackForwardListFields {
static void WebHistoryClose(JNIEnv* env, jobject obj, jint frame)
{
- LOG_ASSERT(frame, "Close needs a valid Frame pointer!");
+ ALOG_ASSERT(frame, "Close needs a valid Frame pointer!");
WebCore::Frame* pFrame = (WebCore::Frame*)frame;
WebCore::BackForwardListImpl* list = static_cast<WebCore::BackForwardListImpl*>(pFrame->page()->backForwardList());
@@ -145,7 +144,7 @@ static void WebHistoryClose(JNIEnv* env, jobject obj, jint frame)
static void WebHistoryRestoreIndex(JNIEnv* env, jobject obj, jint frame, jint index)
{
- LOG_ASSERT(frame, "RestoreState needs a valid Frame pointer!");
+ ALOG_ASSERT(frame, "RestoreState needs a valid Frame pointer!");
WebCore::Frame* pFrame = (WebCore::Frame*)frame;
WebCore::Page* page = pFrame->page();
WebCore::HistoryItem* currentItem =
@@ -156,10 +155,10 @@ static void WebHistoryRestoreIndex(JNIEnv* env, jobject obj, jint frame, jint in
page->goToItem(currentItem, FrameLoadTypeIndexedBackForward);
}
-static void WebHistoryInflate(JNIEnv* env, jobject obj, jint frame, jbyteArray data)
+static jint WebHistoryInflate(JNIEnv* env, jobject obj, jint frame, jbyteArray data)
{
- LOG_ASSERT(frame, "Inflate needs a valid frame pointer!");
- LOG_ASSERT(data, "Inflate needs a valid data pointer!");
+ ALOG_ASSERT(frame, "Inflate needs a valid frame pointer!");
+ ALOG_ASSERT(data, "Inflate needs a valid data pointer!");
// Get the actual bytes and the length from the java array.
const jbyte* bytes = env->GetByteArrayElements(data, NULL);
@@ -168,7 +167,7 @@ static void WebHistoryInflate(JNIEnv* env, jobject obj, jint frame, jbyteArray d
// Inflate the history tree into one HistoryItem or null if the inflation
// failed.
RefPtr<WebCore::HistoryItem> newItem = WebCore::HistoryItem::create();
- WebHistoryItem* bridge = new WebHistoryItem(env, obj, newItem.get());
+ WebHistoryItem* bridge = new WebHistoryItem(newItem.get());
newItem->setBridge(bridge);
// Inflate the item recursively. If it fails, that is ok. We'll have an
@@ -178,7 +177,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();
@@ -188,49 +187,110 @@ static void WebHistoryInflate(JNIEnv* env, jobject obj, jint frame, jbyteArray d
// Update the item.
bridge->updateHistoryItem(newItem.get());
+ // Ref here because Java expects to adopt the reference, and as such will not
+ // call ref on it. However, setBridge has also adopted the reference
+ // TODO: This is confusing as hell, clean up ownership and have setBridge
+ // take a RefPtr instead of a raw ptr and calling adoptRef on it
+ bridge->ref();
+ return reinterpret_cast<jint>(bridge);
+}
+
+static void WebHistoryRef(JNIEnv* env, jobject obj, jint ptr)
+{
+ if (ptr)
+ reinterpret_cast<WebHistoryItem*>(ptr)->ref();
+}
+
+static void WebHistoryUnref(JNIEnv* env, jobject obj, jint ptr)
+{
+ if (ptr)
+ reinterpret_cast<WebHistoryItem*>(ptr)->deref();
+}
+
+static jobject WebHistoryGetTitle(JNIEnv* env, jobject obj, jint ptr)
+{
+ if (!ptr)
+ return 0;
+ WebHistoryItem* item = reinterpret_cast<WebHistoryItem*>(ptr);
+ MutexLocker locker(item->m_lock);
+ return wtfStringToJstring(env, item->m_title, false);
+}
+
+static jobject WebHistoryGetUrl(JNIEnv* env, jobject obj, jint ptr)
+{
+ if (!ptr)
+ return 0;
+ WebHistoryItem* item = reinterpret_cast<WebHistoryItem*>(ptr);
+ MutexLocker locker(item->m_lock);
+ return wtfStringToJstring(env, item->m_url, false);
+}
+
+static jobject WebHistoryGetOriginalUrl(JNIEnv* env, jobject obj, jint ptr)
+{
+ if (!ptr)
+ return 0;
+ WebHistoryItem* item = reinterpret_cast<WebHistoryItem*>(ptr);
+ MutexLocker locker(item->m_lock);
+ return wtfStringToJstring(env, item->m_originalUrl, false);
+}
+
+static jobject WebHistoryGetFlattenedData(JNIEnv* env, jobject obj, jint ptr)
+{
+ if (!ptr)
+ return 0;
+
+ WebHistoryItem* item = reinterpret_cast<WebHistoryItem*>(ptr);
+ MutexLocker locker(item->m_lock);
+
+ if (!item->m_dataCached) {
+ // Try to create a new java byte array.
+ jbyteArray b = env->NewByteArray(item->m_data.size());
+ if (!b)
+ return NULL;
+
+ // Write our flattened data to the java array.
+ env->SetByteArrayRegion(b, 0, item->m_data.size(),
+ (const jbyte*)item->m_data.data());
+ item->m_dataCached = env->NewGlobalRef(b);
+ env->DeleteLocalRef(b);
+ }
+ return item->m_dataCached;
+}
+
+static jobject WebHistoryGetFavicon(JNIEnv* env, jobject obj, jint ptr)
+{
+ if (!ptr)
+ return 0;
+ WebHistoryItem* item = reinterpret_cast<WebHistoryItem*>(ptr);
+ MutexLocker locker(item->m_lock);
+ if (!item->m_faviconCached && item->m_favicon) {
+ jobject favicon = GraphicsJNI::createBitmap(env,
+ item->m_favicon,
+ false, NULL);
+ item->m_favicon = 0; // Framework now owns the pointer
+ item->m_faviconCached = env->NewGlobalRef(favicon);
+ env->DeleteLocalRef(favicon);
+ }
+ return item->m_faviconCached;
}
// 6 empty strings + no document state + children count + 2 scales = 10 unsigned values
// 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)
+void WebHistory::Flatten(JNIEnv* env, WTF::Vector<char>& vector, WebCore::HistoryItem* item)
{
if (!item)
- return NULL;
+ return;
// 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.
- LOG_ASSERT(item->bridge(), "Why don't we have a bridge object here?");
- write_item(v, item);
- write_children_recursive(v, item);
-
- // Try to create a new java byte array.
- jbyteArray b = env->NewByteArray(v.size());
- if (!b)
- return NULL;
-
- // Write our flattened data to the java array.
- env->SetByteArrayRegion(b, 0, v.size(), (const jbyte*)v.data());
- return b;
-}
-
-WebHistoryItem::WebHistoryItem(JNIEnv* env, jobject obj,
- WebCore::HistoryItem* item) : WebCore::AndroidWebHistoryBridge(item) {
- m_object = env->NewWeakGlobalRef(obj);
- m_parent = 0;
-}
-
-WebHistoryItem::~WebHistoryItem() {
- if (m_object) {
- JNIEnv* env = JSC::Bindings::getJNIEnv();
- if (!env)
- return;
- env->DeleteWeakGlobalRef(m_object);
- }
+ ALOG_ASSERT(item->bridge(), "Why don't we have a bridge object here?");
+ writeItem(vector, item);
+ writeChildrenRecursive(vector, item);
}
void WebHistoryItem::updateHistoryItem(WebCore::HistoryItem* item) {
@@ -246,7 +306,7 @@ void WebHistoryItem::updateHistoryItem(WebCore::HistoryItem* item) {
// if the parent only has one ref, it is from this WebHistoryItem.
// This means that the matching WebCore::HistoryItem has been freed.
// This can happen during clear().
- LOGW("Can't updateHistoryItem as the top HistoryItem is gone");
+ ALOGW("Can't updateHistoryItem as the top HistoryItem is gone");
return;
}
while (webItem->parent())
@@ -256,7 +316,7 @@ void WebHistoryItem::updateHistoryItem(WebCore::HistoryItem* item) {
// If a HistoryItem only exists for page cache, it is possible that
// the parent HistoryItem destroyed before the child HistoryItem. If
// it happens, skip updating.
- LOGW("Can't updateHistoryItem as the top HistoryItem is gone");
+ ALOGW("Can't updateHistoryItem as the top HistoryItem is gone");
return;
}
}
@@ -264,23 +324,15 @@ void WebHistoryItem::updateHistoryItem(WebCore::HistoryItem* item) {
if (!env)
return;
- // Don't do anything if the item has been gc'd already
- AutoJObject realItem = getRealObject(env, webItem->m_object);
- if (!realItem.get())
- return;
+ MutexLocker locker(webItem->m_lock);
+ // TODO: Figure out if we can't just use item->urlString() instead...
const WTF::String urlString = WebFrame::convertIDNToUnicode(item->url());
- jstring urlStr = NULL;
- if (!urlString.isNull())
- urlStr = wtfStringToJstring(env, urlString);
+ webItem->m_url = urlString.threadsafeCopy();
const WTF::String originalUrlString = WebFrame::convertIDNToUnicode(item->originalURL());
- jstring originalUrlStr = NULL;
- if (!originalUrlString.isNull())
- originalUrlStr = wtfStringToJstring(env, originalUrlString);
+ webItem->m_originalUrl = originalUrlString.threadsafeCopy();
const WTF::String& titleString = item->title();
- jstring titleStr = NULL;
- if (!titleString.isNull())
- titleStr = wtfStringToJstring(env, titleString);
+ webItem->m_title = titleString.threadsafeCopy();
// Try to get the favicon from the history item. For some pages like Grand
// Prix, there are history items with anchors. If the icon fails for the
@@ -294,24 +346,41 @@ void WebHistoryItem::updateHistoryItem(WebCore::HistoryItem* item) {
// FIXME: This method should not be used from outside WebCore and will be removed.
// http://trac.webkit.org/changeset/81484
WebCore::Image* icon = WebCore::iconDatabase().synchronousIconForPageURL(url, WebCore::IntSize(16, 16));
+ delete webItem->m_favicon;
+ webItem->m_favicon = webcoreImageToSkBitmap(icon);
+ if (webItem->m_faviconCached) {
+ env->DeleteGlobalRef(webItem->m_faviconCached);
+ webItem->m_faviconCached = 0;
+ }
- if (icon)
- favicon = webcoreImageToJavaBitmap(env, icon);
-
- WTF::Vector<char> data;
- jbyteArray array = WebHistory::Flatten(env, data, item);
- env->CallVoidMethod(realItem.get(), gWebHistoryItem.mUpdate, urlStr,
- originalUrlStr, titleStr, favicon, array);
- env->DeleteLocalRef(urlStr);
- env->DeleteLocalRef(originalUrlStr);
- env->DeleteLocalRef(titleStr);
- if (favicon)
- env->DeleteLocalRef(favicon);
- env->DeleteLocalRef(array);
+ webItem->m_data.clear();
+ WebHistory::Flatten(env, webItem->m_data, item);
+ if (webItem->m_dataCached) {
+ env->DeleteGlobalRef(webItem->m_dataCached);
+ webItem->m_dataCached = 0;
+ }
+}
+
+WebHistoryItem::~WebHistoryItem()
+{
+ delete m_favicon;
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ if (!env) {
+ ALOGW("Failed to get JNIEnv*! Potential memory leak!");
+ return;
+ }
+ if (m_faviconCached) {
+ env->DeleteGlobalRef(m_faviconCached);
+ m_faviconCached = 0;
+ }
+ if (m_dataCached) {
+ env->DeleteGlobalRef(m_dataCached);
+ m_dataCached = 0;
+ }
}
static void historyItemChanged(WebCore::HistoryItem* item) {
- LOG_ASSERT(item, "historyItemChanged called with a null item");
+ ALOG_ASSERT(item, "historyItemChanged called with a null item");
if (item->bridge())
item->bridge()->updateHistoryItem(item);
@@ -319,21 +388,21 @@ static void historyItemChanged(WebCore::HistoryItem* item) {
void WebHistory::AddItem(const AutoJObject& list, WebCore::HistoryItem* item)
{
- LOG_ASSERT(item, "newItem must take a valid HistoryItem!");
+ ALOG_ASSERT(item, "newItem must take a valid HistoryItem!");
// Item already added. Should only happen when we are inflating the list.
if (item->bridge() || !list.get())
return;
JNIEnv* env = list.env();
- // Allocate a blank WebHistoryItem
- jclass clazz = env->FindClass("android/webkit/WebHistoryItem");
- jobject newItem = env->NewObject(clazz, gWebHistoryItem.mInit);
- env->DeleteLocalRef(clazz);
-
// Create the bridge, make it active, and attach it to the item.
- WebHistoryItem* bridge = new WebHistoryItem(env, newItem, item);
+ WebHistoryItem* bridge = new WebHistoryItem(item);
bridge->setActive();
item->setBridge(bridge);
+ // Allocate a blank WebHistoryItem
+ jclass clazz = env->FindClass("android/webkit/WebHistoryItem");
+ jobject newItem = env->NewObject(clazz, gWebHistoryItem.mInit,
+ reinterpret_cast<int>(bridge));
+ env->DeleteLocalRef(clazz);
// Update the history item which will flatten the data and call update on
// the java item.
@@ -358,7 +427,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,96 +435,96 @@ 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);
- LOGV("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();
- LOG_ASSERT(bridge, "We should have a bridge here!");
+ ALOG_ASSERT(bridge, "We should have a bridge here!");
// Screen scale
const float scale = bridge->scale();
- LOGV("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();
- LOGV("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();
- LOGV("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
- LOGV("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();
- LOGV("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();
for (WebCore::HistoryItemVector::const_iterator i = children.begin(); i != end; ++i) {
WebCore::HistoryItem* item = (*i).get();
- LOG_ASSERT(parent->bridge(),
+ ALOG_ASSERT(parent->bridge(),
"The parent item should have a bridge object!");
if (!item->bridge()) {
WebHistoryItem* bridge = new WebHistoryItem(static_cast<WebHistoryItem*>(parent->bridge()));
@@ -467,116 +536,223 @@ static void write_children_recursive(WTF::Vector<char>& v, WebCore::HistoryItem*
// parent must not have a parent bridge.
WebHistoryItem* bridge = static_cast<WebHistoryItem*>(item->bridge());
WebHistoryItem* parentBridge = static_cast<WebHistoryItem*>(parent->bridge());
- LOG_ASSERT(parentBridge->parent() == 0 ||
+ ALOG_ASSERT(parentBridge->parent() == 0 ||
bridge->parent() == parentBridge,
"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);
+ }
+}
+
+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; tag=\"%s\" end=%p data=%p",
+ dbgLabel ? dbgLabel : "<no tag>", 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("Not enough data to read int; tag=\"%s\" end=%p data=%p",
+ dbgLabel ? dbgLabel : "<no tag>", end, data);
+ return false;
}
+
+ memcpy(&result, data, sizeof(int));
+ data += sizeof(int);
+ if (dbgLabel)
+ ALOGV("Reading %-16s %d", dbgLabel, result);
+ return true;
}
-static bool read_item_recursive(WebCore::HistoryItem* newItem,
+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("Not enough data to read int64_t; tag=\"%s\" end=%p data=%p",
+ dbgLabel ? dbgLabel : "<no tag>", 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("Not enough data to read float; tag=\"%s\" end=%p data=%p",
+ dbgLabel ? dbgLabel : "<no tag>", 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("Not enough data to read bool; tag=\"%s\" end=%p data=%p",
+ dbgLabel ? dbgLabel : "<no tag>", 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("Invalid value for bool; tag=\"%s\" end=%p data=%p c=%u",
+ dbgLabel ? dbgLabel : "<no tag>", 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; tag=\"%s\" end=%p data=%p",
+ dbgLabel ? dbgLabel : "<no tag>", 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("Not enough data to read content; tag=\"%s\" end=%p data=%p stringLength=%u",
+ dbgLabel ? dbgLabel : "<no tag>", end, data, stringLength);
+ return false;
+ }
+
+ const unsigned MAX_REASONABLE_STRING_LENGTH = 10000;
+ if (stringLength > MAX_REASONABLE_STRING_LENGTH) {
+ ALOGW("String length is suspiciously large (>%d); tag=\"%s\" end=%p data=%p stringLength=%u",
+ MAX_REASONABLE_STRING_LENGTH, dbgLabel ? dbgLabel : "<no tag>",
+ end, data, stringLength);
+ }
+
+ bool decodeFailed = false;
+ static const WebCore::TextEncoding& encoding = WebCore::UTF8Encoding();
+ result = encoding.decode(data, stringLength, true, decodeFailed);
+ if (decodeFailed) {
+ ALOGW("Decode failed, tag=\"%s\" end=%p data=%p stringLength=%u content=\"%s\"",
+ dbgLabel ? dbgLabel : "<no tag>", end, data, stringLength,
+ result.utf8().data());
+ return false;
+ }
+
+ if (stringLength > MAX_REASONABLE_STRING_LENGTH) {
+ ALOGW("\tdecodeFailed=%d (flag is ignored) content=\"%s\"",
+ decodeFailed, result.utf8().data());
+ }
+
+ 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.
- unsigned l;
- memcpy(&l, data, sizeofUnsigned);
- // Increment data pointer by the size of an unsigned int.
- data += sizeofUnsigned;
- if (l) {
- LOGV("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) {
- LOGV("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) {
- LOGV("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::PassRefPtr<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) {
- LOGV("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) {
- LOGV("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 +764,76 @@ static bool read_item_recursive(WebCore::HistoryItem* newItem,
}
// Read the target
- memcpy(&l, data, sizeofUnsigned);
- data += sizeofUnsigned;
- if (l) {
- LOGV("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();
- LOG_ASSERT(bridge, "There should be a bridge object during inflate");
- float fValue;
+ ALOG_ASSERT(bridge, "There should be a bridge object during inflate");
+
// Read the screen scale
- memcpy(&fValue, data, sizeof(float));
- LOGV("Screen scale %f", fValue);
- bridge->setScale(fValue);
- data += sizeof(float);
- memcpy(&fValue, data, sizeofUnsigned);
- LOGV("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);
- LOGV("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;
- LOGV("\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;
- LOGV("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);
- LOGV("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::PassRefPtr<WebCore::HistoryItem> child = WebCore::HistoryItem::create();
+ 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 +849,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()
{
- LOGD("Entering history unit test!");
+ 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));
- LOG_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];
- LOG_ASSERT(!read_item_recursive(testItem, &test2, 2), "Small array should fail!");
+ ALOG_ASSERT(!readItemRecursive(testItem, &test2, 2), "Small array should fail!");
delete[] test2;
- LOG_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;
- LOG_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;
- LOG_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;
- LOG_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;
- LOG_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;
- LOG_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;
- LOG_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;
- LOG_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) = '!';
- LOG_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;
- LOG_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;
- LOG_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 +936,9 @@ static void unit_test()
*(int*)(test3 + offset) = 2;
*(int*)(test3 + offset + 4) = 0;
*(int*)(test3 + offset + 8) = 20;
- LOG_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
@@ -809,8 +953,22 @@ static JNINativeMethod gWebBackForwardListMethods[] = {
};
static JNINativeMethod gWebHistoryItemMethods[] = {
- { "inflate", "(I[B)V",
- (void*) WebHistoryInflate }
+ { "inflate", "(I[B)I",
+ (void*) WebHistoryInflate },
+ { "nativeRef", "(I)V",
+ (void*) WebHistoryRef },
+ { "nativeUnref", "(I)V",
+ (void*) WebHistoryUnref },
+ { "nativeGetTitle", "(I)Ljava/lang/String;",
+ (void*) WebHistoryGetTitle },
+ { "nativeGetUrl", "(I)Ljava/lang/String;",
+ (void*) WebHistoryGetUrl },
+ { "nativeGetOriginalUrl", "(I)Ljava/lang/String;",
+ (void*) WebHistoryGetOriginalUrl },
+ { "nativeGetFlattenedData", "(I)[B",
+ (void*) WebHistoryGetFlattenedData },
+ { "nativeGetFavicon", "(I)Landroid/graphics/Bitmap;",
+ (void*) WebHistoryGetFavicon },
};
int registerWebHistory(JNIEnv* env)
@@ -818,35 +976,27 @@ 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");
- LOG_ASSERT(clazz, "Unable to find class android/webkit/WebHistoryItem");
- gWebHistoryItem.mInit = env->GetMethodID(clazz, "<init>", "()V");
- LOG_ASSERT(gWebHistoryItem.mInit, "Could not find WebHistoryItem constructor");
- gWebHistoryItem.mUpdate = env->GetMethodID(clazz, "update",
- "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Landroid/graphics/Bitmap;[B)V");
- LOG_ASSERT(gWebHistoryItem.mUpdate, "Could not find method update in WebHistoryItem");
-
- // Find the field ids for mTitle and mUrl.
- gWebHistoryItem.mTitle = env->GetFieldID(clazz, "mTitle", "Ljava/lang/String;");
- LOG_ASSERT(gWebHistoryItem.mTitle, "Could not find field mTitle in WebHistoryItem");
- gWebHistoryItem.mUrl = env->GetFieldID(clazz, "mUrl", "Ljava/lang/String;");
- LOG_ASSERT(gWebHistoryItem.mUrl, "Could not find field mUrl in WebHistoryItem");
+ ALOG_ASSERT(clazz, "Unable to find class android/webkit/WebHistoryItem");
+ gWebHistoryItem.mInit = env->GetMethodID(clazz, "<init>", "(I)V");
+ ALOG_ASSERT(gWebHistoryItem.mInit, "Could not find WebHistoryItem constructor");
+
env->DeleteLocalRef(clazz);
// Find the WebBackForwardList object and method.
clazz = env->FindClass("android/webkit/WebBackForwardList");
- LOG_ASSERT(clazz, "Unable to find class android/webkit/WebBackForwardList");
+ ALOG_ASSERT(clazz, "Unable to find class android/webkit/WebBackForwardList");
gWebBackForwardList.mAddHistoryItem = env->GetMethodID(clazz, "addHistoryItem",
"(Landroid/webkit/WebHistoryItem;)V");
- LOG_ASSERT(gWebBackForwardList.mAddHistoryItem, "Could not find method addHistoryItem");
+ ALOG_ASSERT(gWebBackForwardList.mAddHistoryItem, "Could not find method addHistoryItem");
gWebBackForwardList.mRemoveHistoryItem = env->GetMethodID(clazz, "removeHistoryItem",
"(I)V");
- LOG_ASSERT(gWebBackForwardList.mRemoveHistoryItem, "Could not find method removeHistoryItem");
+ ALOG_ASSERT(gWebBackForwardList.mRemoveHistoryItem, "Could not find method removeHistoryItem");
gWebBackForwardList.mSetCurrentIndex = env->GetMethodID(clazz, "setCurrentIndex", "(I)V");
- LOG_ASSERT(gWebBackForwardList.mSetCurrentIndex, "Could not find method setCurrentIndex");
+ ALOG_ASSERT(gWebBackForwardList.mSetCurrentIndex, "Could not find method setCurrentIndex");
env->DeleteLocalRef(clazz);
int result = jniRegisterNativeMethods(env, "android/webkit/WebBackForwardList",
diff --git a/Source/WebKit/android/jni/WebHistory.h b/Source/WebKit/android/jni/WebHistory.h
index fc0b340..e89959c 100644
--- a/Source/WebKit/android/jni/WebHistory.h
+++ b/Source/WebKit/android/jni/WebHistory.h
@@ -28,8 +28,12 @@
#include "AndroidWebHistoryBridge.h"
+#include "PlatformString.h"
+#include "SkBitmap.h"
+
#include <jni.h>
#include <wtf/RefCounted.h>
+#include <wtf/Threading.h>
#include <wtf/Vector.h>
namespace android {
@@ -38,7 +42,7 @@ class AutoJObject;
class WebHistory {
public:
- static jbyteArray Flatten(JNIEnv*, WTF::Vector<char>&, WebCore::HistoryItem*);
+ static void Flatten(JNIEnv*, WTF::Vector<char>&, WebCore::HistoryItem*);
static void AddItem(const AutoJObject&, WebCore::HistoryItem*);
static void RemoveItem(const AutoJObject&, int);
static void UpdateHistoryIndex(const AutoJObject&, int);
@@ -51,16 +55,36 @@ class WebHistoryItem : public WebCore::AndroidWebHistoryBridge {
public:
WebHistoryItem(WebHistoryItem* parent)
: WebCore::AndroidWebHistoryBridge(0)
+ , m_favicon(0)
+ , m_faviconCached(0)
+ , m_dataCached(0)
, m_parent(parent)
- , m_object(NULL) { }
- WebHistoryItem(JNIEnv*, jobject, WebCore::HistoryItem*);
+ {}
+ WebHistoryItem(WebCore::HistoryItem* item)
+ : WebCore::AndroidWebHistoryBridge(item)
+ , m_favicon(0)
+ , m_faviconCached(0)
+ , m_dataCached(0)
+ , m_parent(0)
+ {}
~WebHistoryItem();
void updateHistoryItem(WebCore::HistoryItem* item);
void setParent(WebHistoryItem* parent) { m_parent = parent; }
WebHistoryItem* parent() const { return m_parent.get(); }
+
+ // TODO: This is ugly. Really the whole bindings of WebHistoryItem needs to be
+ // cleaned up, but this will do for now
+ WTF::Mutex m_lock;
+ String m_url;
+ String m_originalUrl;
+ String m_title;
+ SkBitmap* m_favicon;
+ WTF::Vector<char> m_data;
+ jobject m_faviconCached;
+ jobject m_dataCached;
+
private:
RefPtr<WebHistoryItem> m_parent;
- jweak m_object;
};
};
diff --git a/Source/WebKit/android/jni/WebIconDatabase.cpp b/Source/WebKit/android/jni/WebIconDatabase.cpp
index d5f8947..e9219df 100644
--- a/Source/WebKit/android/jni/WebIconDatabase.cpp
+++ b/Source/WebKit/android/jni/WebIconDatabase.cpp
@@ -50,18 +50,31 @@
namespace android {
-jobject webcoreImageToJavaBitmap(JNIEnv* env, WebCore::Image* icon)
+SkBitmap* webcoreImageToSkBitmap(WebCore::Image* icon)
{
if (!icon)
- return NULL;
- SkBitmap bm;
+ return 0;
WebCore::SharedBuffer* buffer = icon->data();
- if (!buffer || !SkImageDecoder::DecodeMemory(buffer->data(), buffer->size(),
- &bm, SkBitmap::kNo_Config,
- SkImageDecoder::kDecodePixels_Mode))
- return NULL;
+ if (!buffer)
+ return 0;
+ SkBitmap* bm = new SkBitmap;
+ if (!SkImageDecoder::DecodeMemory(buffer->data(), buffer->size(), bm,
+ SkBitmap::kNo_Config,
+ SkImageDecoder::kDecodePixels_Mode)
+ || bm->isNull() || !bm->width() || !bm->height()
+ || bm->config() == SkBitmap::kNo_Config) {
+ delete bm;
+ return 0;
+ }
+ return bm;
+}
- return GraphicsJNI::createBitmap(env, new SkBitmap(bm), false, NULL);
+jobject webcoreImageToJavaBitmap(JNIEnv* env, WebCore::Image* icon)
+{
+ SkBitmap* bm = webcoreImageToSkBitmap(icon);
+ if (!bm)
+ return 0;
+ return GraphicsJNI::createBitmap(env, bm, false, NULL);
}
static WebIconDatabase* gIconDatabaseClient = new WebIconDatabase();
@@ -168,7 +181,7 @@ static void Open(JNIEnv* env, jobject obj, jstring path)
return;
iconDb.setEnabled(true);
iconDb.setClient(gIconDatabaseClient);
- LOG_ASSERT(path, "No path given to nativeOpen");
+ ALOG_ASSERT(path, "No path given to nativeOpen");
WTF::String pathStr = jstringToWtfString(env, path);
WTF::CString fullPath = WebCore::pathByAppendingComponent(pathStr,
WebCore::IconDatabase::defaultDatabaseFilename()).utf8();
@@ -185,12 +198,12 @@ static void Open(JNIEnv* env, jobject obj, jstring path)
}
}
if (didSetPermissions) {
- LOGV("Opening WebIconDatabase file '%s'", pathStr.latin1().data());
+ ALOGV("Opening WebIconDatabase file '%s'", pathStr.latin1().data());
bool res = iconDb.open(pathStr, WebCore::IconDatabase::defaultDatabaseFilename());
if (!res)
- LOGE("Open failed!");
+ ALOGE("Open failed!");
} else
- LOGE("Failed to set permissions on '%s'", fullPath.data());
+ ALOGE("Failed to set permissions on '%s'", fullPath.data());
}
static void Close(JNIEnv* env, jobject obj)
@@ -200,37 +213,37 @@ static void Close(JNIEnv* env, jobject obj)
static void RemoveAllIcons(JNIEnv* env, jobject obj)
{
- LOGV("Removing all icons");
+ ALOGV("Removing all icons");
WebCore::iconDatabase().removeAllIcons();
}
static jobject IconForPageUrl(JNIEnv* env, jobject obj, jstring url)
{
- LOG_ASSERT(url, "No url given to iconForPageUrl");
+ ALOG_ASSERT(url, "No url given to iconForPageUrl");
WTF::String urlStr = jstringToWtfString(env, url);
// FIXME: This method should not be used from outside WebCore and will be removed.
// http://trac.webkit.org/changeset/81484
WebCore::Image* icon = WebCore::iconDatabase().synchronousIconForPageURL(urlStr, WebCore::IntSize(16, 16));
- LOGV("Retrieving icon for '%s' %p", urlStr.latin1().data(), icon);
+ ALOGV("Retrieving icon for '%s' %p", urlStr.latin1().data(), icon);
return webcoreImageToJavaBitmap(env, icon);
}
static void RetainIconForPageUrl(JNIEnv* env, jobject obj, jstring url)
{
- LOG_ASSERT(url, "No url given to retainIconForPageUrl");
+ ALOG_ASSERT(url, "No url given to retainIconForPageUrl");
WTF::String urlStr = jstringToWtfString(env, url);
- LOGV("Retaining icon for '%s'", urlStr.latin1().data());
+ ALOGV("Retaining icon for '%s'", urlStr.latin1().data());
WebCore::iconDatabase().retainIconForPageURL(urlStr);
}
static void ReleaseIconForPageUrl(JNIEnv* env, jobject obj, jstring url)
{
- LOG_ASSERT(url, "No url given to releaseIconForPageUrl");
+ ALOG_ASSERT(url, "No url given to releaseIconForPageUrl");
WTF::String urlStr = jstringToWtfString(env, url);
- LOGV("Releasing icon for '%s'", urlStr.latin1().data());
+ ALOGV("Releasing icon for '%s'", urlStr.latin1().data());
WebCore::iconDatabase().releaseIconForPageURL(urlStr);
}
@@ -255,12 +268,12 @@ static JNINativeMethod gWebIconDatabaseMethods[] = {
int registerWebIconDatabase(JNIEnv* env)
{
#ifndef NDEBUG
- jclass webIconDatabase = env->FindClass("android/webkit/WebIconDatabase");
- LOG_ASSERT(webIconDatabase, "Unable to find class android.webkit.WebIconDatabase");
+ jclass webIconDatabase = env->FindClass("android/webkit/WebIconDatabaseClassic");
+ ALOG_ASSERT(webIconDatabase, "Unable to find class android.webkit.WebIconDatabaseClassic");
env->DeleteLocalRef(webIconDatabase);
#endif
- return jniRegisterNativeMethods(env, "android/webkit/WebIconDatabase",
+ return jniRegisterNativeMethods(env, "android/webkit/WebIconDatabaseClassic",
gWebIconDatabaseMethods, NELEM(gWebIconDatabaseMethods));
}
diff --git a/Source/WebKit/android/jni/WebIconDatabase.h b/Source/WebKit/android/jni/WebIconDatabase.h
index 3011b9f..7b7c937 100644
--- a/Source/WebKit/android/jni/WebIconDatabase.h
+++ b/Source/WebKit/android/jni/WebIconDatabase.h
@@ -28,6 +28,7 @@
#include "IconDatabaseClient.h"
#include "PlatformString.h"
+#include "SkBitmap.h"
#include "utils/threads.h"
#include <jni.h>
#include <wtf/Vector.h>
@@ -73,6 +74,7 @@ namespace android {
bool mDeliveryRequested;
};
+ SkBitmap* webcoreImageToSkBitmap(WebCore::Image* icon);
jobject webcoreImageToJavaBitmap(JNIEnv* env, WebCore::Image* icon);
};
diff --git a/Source/WebKit/android/jni/WebSettings.cpp b/Source/WebKit/android/jni/WebSettings.cpp
index dd847e8..467da3d 100644
--- a/Source/WebKit/android/jni/WebSettings.cpp
+++ b/Source/WebKit/android/jni/WebSettings.cpp
@@ -49,9 +49,7 @@
#include "Settings.h"
#include "WebCoreFrameBridge.h"
#include "WebCoreJni.h"
-#if USE(V8)
#include "WorkerContextExecutionProxy.h"
-#endif
#include "WebRequestContext.h"
#include "WebViewCore.h"
@@ -122,6 +120,9 @@ struct FieldIds {
mGeolocationEnabled = env->GetFieldID(clazz, "mGeolocationEnabled", "Z");
mGeolocationDatabasePath = env->GetFieldID(clazz, "mGeolocationDatabasePath", "Ljava/lang/String;");
mXSSAuditorEnabled = env->GetFieldID(clazz, "mXSSAuditorEnabled", "Z");
+#if ENABLE(LINK_PREFETCH)
+ mLinkPrefetchEnabled = env->GetFieldID(clazz, "mLinkPrefetchEnabled", "Z");
+#endif
mJavaScriptCanOpenWindowsAutomatically = env->GetFieldID(clazz,
"mJavaScriptCanOpenWindowsAutomatically", "Z");
mUseWideViewport = env->GetFieldID(clazz, "mUseWideViewport", "Z");
@@ -134,8 +135,8 @@ struct FieldIds {
mPageCacheCapacity = env->GetFieldID(clazz, "mPageCacheCapacity", "I");
#if ENABLE(WEB_AUTOFILL)
mAutoFillEnabled = env->GetFieldID(clazz, "mAutoFillEnabled", "Z");
- mAutoFillProfile = env->GetFieldID(clazz, "mAutoFillProfile", "Landroid/webkit/WebSettings$AutoFillProfile;");
- jclass autoFillProfileClass = env->FindClass("android/webkit/WebSettings$AutoFillProfile");
+ mAutoFillProfile = env->GetFieldID(clazz, "mAutoFillProfile", "Landroid/webkit/WebSettingsClassic$AutoFillProfile;");
+ jclass autoFillProfileClass = env->FindClass("android/webkit/WebSettingsClassic$AutoFillProfile");
mAutoFillProfileFullName = env->GetFieldID(autoFillProfileClass, "mFullName", "Ljava/lang/String;");
mAutoFillProfileEmailAddress = env->GetFieldID(autoFillProfileClass, "mEmailAddress", "Ljava/lang/String;");
mAutoFillProfileCompanyName = env->GetFieldID(autoFillProfileClass, "mCompanyName", "Ljava/lang/String;");
@@ -148,57 +149,57 @@ struct FieldIds {
mAutoFillProfilePhoneNumber = env->GetFieldID(autoFillProfileClass, "mPhoneNumber", "Ljava/lang/String;");
env->DeleteLocalRef(autoFillProfileClass);
#endif
-#if USE(CHROME_NETWORK_STACK)
mOverrideCacheMode = env->GetFieldID(clazz, "mOverrideCacheMode", "I");
-#endif
-
- LOG_ASSERT(mLayoutAlgorithm, "Could not find field mLayoutAlgorithm");
- LOG_ASSERT(mTextSize, "Could not find field mTextSize");
- LOG_ASSERT(mStandardFontFamily, "Could not find field mStandardFontFamily");
- LOG_ASSERT(mFixedFontFamily, "Could not find field mFixedFontFamily");
- LOG_ASSERT(mSansSerifFontFamily, "Could not find field mSansSerifFontFamily");
- LOG_ASSERT(mSerifFontFamily, "Could not find field mSerifFontFamily");
- LOG_ASSERT(mCursiveFontFamily, "Could not find field mCursiveFontFamily");
- LOG_ASSERT(mFantasyFontFamily, "Could not find field mFantasyFontFamily");
- LOG_ASSERT(mDefaultTextEncoding, "Could not find field mDefaultTextEncoding");
- LOG_ASSERT(mGetUserAgentString, "Could not find method getUserAgentString");
- LOG_ASSERT(mGetAcceptLanguage, "Could not find method getAcceptLanguage");
- LOG_ASSERT(mMinimumFontSize, "Could not find field mMinimumFontSize");
- LOG_ASSERT(mMinimumLogicalFontSize, "Could not find field mMinimumLogicalFontSize");
- LOG_ASSERT(mDefaultFontSize, "Could not find field mDefaultFontSize");
- LOG_ASSERT(mDefaultFixedFontSize, "Could not find field mDefaultFixedFontSize");
- LOG_ASSERT(mLoadsImagesAutomatically, "Could not find field mLoadsImagesAutomatically");
+ mPasswordEchoEnabled = env->GetFieldID(clazz, "mPasswordEchoEnabled", "Z");
+
+ ALOG_ASSERT(mLayoutAlgorithm, "Could not find field mLayoutAlgorithm");
+ ALOG_ASSERT(mTextSize, "Could not find field mTextSize");
+ ALOG_ASSERT(mStandardFontFamily, "Could not find field mStandardFontFamily");
+ ALOG_ASSERT(mFixedFontFamily, "Could not find field mFixedFontFamily");
+ ALOG_ASSERT(mSansSerifFontFamily, "Could not find field mSansSerifFontFamily");
+ ALOG_ASSERT(mSerifFontFamily, "Could not find field mSerifFontFamily");
+ ALOG_ASSERT(mCursiveFontFamily, "Could not find field mCursiveFontFamily");
+ ALOG_ASSERT(mFantasyFontFamily, "Could not find field mFantasyFontFamily");
+ ALOG_ASSERT(mDefaultTextEncoding, "Could not find field mDefaultTextEncoding");
+ ALOG_ASSERT(mGetUserAgentString, "Could not find method getUserAgentString");
+ ALOG_ASSERT(mGetAcceptLanguage, "Could not find method getAcceptLanguage");
+ ALOG_ASSERT(mMinimumFontSize, "Could not find field mMinimumFontSize");
+ ALOG_ASSERT(mMinimumLogicalFontSize, "Could not find field mMinimumLogicalFontSize");
+ ALOG_ASSERT(mDefaultFontSize, "Could not find field mDefaultFontSize");
+ ALOG_ASSERT(mDefaultFixedFontSize, "Could not find field mDefaultFixedFontSize");
+ ALOG_ASSERT(mLoadsImagesAutomatically, "Could not find field mLoadsImagesAutomatically");
#ifdef ANDROID_BLOCK_NETWORK_IMAGE
- LOG_ASSERT(mBlockNetworkImage, "Could not find field mBlockNetworkImage");
+ ALOG_ASSERT(mBlockNetworkImage, "Could not find field mBlockNetworkImage");
#endif
- LOG_ASSERT(mBlockNetworkLoads, "Could not find field mBlockNetworkLoads");
- LOG_ASSERT(mJavaScriptEnabled, "Could not find field mJavaScriptEnabled");
- LOG_ASSERT(mAllowUniversalAccessFromFileURLs,
+ ALOG_ASSERT(mBlockNetworkLoads, "Could not find field mBlockNetworkLoads");
+ ALOG_ASSERT(mJavaScriptEnabled, "Could not find field mJavaScriptEnabled");
+ ALOG_ASSERT(mAllowUniversalAccessFromFileURLs,
"Could not find field mAllowUniversalAccessFromFileURLs");
- LOG_ASSERT(mAllowFileAccessFromFileURLs,
+ ALOG_ASSERT(mAllowFileAccessFromFileURLs,
"Could not find field mAllowFileAccessFromFileURLs");
- LOG_ASSERT(mPluginState, "Could not find field mPluginState");
+ ALOG_ASSERT(mPluginState, "Could not find field mPluginState");
#if ENABLE(OFFLINE_WEB_APPLICATIONS)
- LOG_ASSERT(mAppCacheEnabled, "Could not find field mAppCacheEnabled");
- LOG_ASSERT(mAppCachePath, "Could not find field mAppCachePath");
- LOG_ASSERT(mAppCacheMaxSize, "Could not find field mAppCacheMaxSize");
+ ALOG_ASSERT(mAppCacheEnabled, "Could not find field mAppCacheEnabled");
+ ALOG_ASSERT(mAppCachePath, "Could not find field mAppCachePath");
+ ALOG_ASSERT(mAppCacheMaxSize, "Could not find field mAppCacheMaxSize");
#endif
#if ENABLE(WORKERS)
- LOG_ASSERT(mWorkersEnabled, "Could not find field mWorkersEnabled");
+ ALOG_ASSERT(mWorkersEnabled, "Could not find field mWorkersEnabled");
#endif
- LOG_ASSERT(mJavaScriptCanOpenWindowsAutomatically,
+ ALOG_ASSERT(mJavaScriptCanOpenWindowsAutomatically,
"Could not find field mJavaScriptCanOpenWindowsAutomatically");
- LOG_ASSERT(mUseWideViewport, "Could not find field mUseWideViewport");
- LOG_ASSERT(mSupportMultipleWindows, "Could not find field mSupportMultipleWindows");
- LOG_ASSERT(mShrinksStandaloneImagesToFit, "Could not find field mShrinksStandaloneImagesToFit");
- LOG_ASSERT(mMaximumDecodedImageSize, "Could not find field mMaximumDecodedImageSize");
- LOG_ASSERT(mUseDoubleTree, "Could not find field mUseDoubleTree");
- LOG_ASSERT(mPageCacheCapacity, "Could not find field mPageCacheCapacity");
+ ALOG_ASSERT(mUseWideViewport, "Could not find field mUseWideViewport");
+ ALOG_ASSERT(mSupportMultipleWindows, "Could not find field mSupportMultipleWindows");
+ ALOG_ASSERT(mShrinksStandaloneImagesToFit, "Could not find field mShrinksStandaloneImagesToFit");
+ ALOG_ASSERT(mMaximumDecodedImageSize, "Could not find field mMaximumDecodedImageSize");
+ ALOG_ASSERT(mUseDoubleTree, "Could not find field mUseDoubleTree");
+ ALOG_ASSERT(mPageCacheCapacity, "Could not find field mPageCacheCapacity");
+ ALOG_ASSERT(mPasswordEchoEnabled, "Could not find field mPasswordEchoEnabled");
jclass enumClass = env->FindClass("java/lang/Enum");
- LOG_ASSERT(enumClass, "Could not find Enum class!");
+ ALOG_ASSERT(enumClass, "Could not find Enum class!");
mOrdinal = env->GetMethodID(enumClass, "ordinal", "()I");
- LOG_ASSERT(mOrdinal, "Could not find method ordinal");
+ ALOG_ASSERT(mOrdinal, "Could not find method ordinal");
env->DeleteLocalRef(enumClass);
}
@@ -257,6 +258,9 @@ struct FieldIds {
jfieldID mGeolocationEnabled;
jfieldID mGeolocationDatabasePath;
jfieldID mXSSAuditorEnabled;
+#if ENABLE(LINK_PREFETCH)
+ jfieldID mLinkPrefetchEnabled;
+#endif
#if ENABLE(DATABASE) || ENABLE(DOM_STORAGE)
jfieldID mDatabasePath;
jfieldID mDatabasePathHasBeenSet;
@@ -275,9 +279,8 @@ struct FieldIds {
jfieldID mAutoFillProfileCountry;
jfieldID mAutoFillProfilePhoneNumber;
#endif
-#if USE(CHROME_NETWORK_STACK)
jfieldID mOverrideCacheMode;
-#endif
+ jfieldID mPasswordEchoEnabled;
};
static struct FieldIds* gFieldIds;
@@ -323,7 +326,7 @@ public:
static void Sync(JNIEnv* env, jobject obj, jint frame)
{
WebCore::Frame* pFrame = (WebCore::Frame*)frame;
- LOG_ASSERT(pFrame, "%s must take a valid frame pointer!", __FUNCTION__);
+ ALOG_ASSERT(pFrame, "%s must take a valid frame pointer!", __FUNCTION__);
WebCore::Settings* s = pFrame->settings();
if (!s)
return;
@@ -339,7 +342,7 @@ public:
pFrame->document()->styleSelectorChanged(WebCore::RecalcStyleImmediately);
if (pFrame->document()->renderer()) {
recursiveCleanupForFullLayout(pFrame->document()->renderer());
- LOG_ASSERT(pFrame->view(), "No view for this frame when trying to relayout");
+ ALOG_ASSERT(pFrame->view(), "No view for this frame when trying to relayout");
pFrame->view()->layout();
// FIXME: This call used to scroll the page to put the focus into view.
// It worked on the WebViewCore, but now scrolling is done outside of the
@@ -377,7 +380,6 @@ public:
str = (jstring)env->CallObjectMethod(obj, gFieldIds->mGetUserAgentString);
WebFrame::getWebFrame(pFrame)->setUserAgent(jstringToWtfString(env, str));
-#if USE(CHROME_NETWORK_STACK)
WebViewCore::getWebViewCore(pFrame->view())->setWebRequestContextUserAgent();
jint cacheMode = env->GetIntField(obj, gFieldIds->mOverrideCacheMode);
@@ -385,7 +387,6 @@ public:
str = (jstring)env->CallObjectMethod(obj, gFieldIds->mGetAcceptLanguage);
WebRequestContext::setAcceptLanguage(jstringToWtfString(env, str));
-#endif
jint size = env->GetIntField(obj, gFieldIds->mMinimumFontSize);
s->setMinimumFontSize(size);
@@ -423,6 +424,11 @@ public:
flag = env->GetBooleanField(obj, gFieldIds->mAllowFileAccessFromFileURLs);
s->setAllowFileAccessFromFileURLs(flag);
+ // Hyperlink auditing (the ping attribute) has similar privacy
+ // considerations as does the running of JavaScript, so to keep the UI
+ // simpler, we leverage the same setting.
+ s->setHyperlinkAuditingEnabled(flag);
+
// ON = 0
// ON_DEMAND = 1
// OFF = 2
@@ -434,22 +440,38 @@ public:
#endif
#if ENABLE(OFFLINE_WEB_APPLICATIONS)
- flag = env->GetBooleanField(obj, gFieldIds->mAppCacheEnabled);
- s->setOfflineWebApplicationCacheEnabled(flag);
- str = (jstring)env->GetObjectField(obj, gFieldIds->mAppCachePath);
- if (str) {
- String path = jstringToWtfString(env, str);
- if (path.length() && cacheStorage().cacheDirectory().isNull()) {
- cacheStorage().setCacheDirectory(path);
+ // We only enable AppCache if it's been enabled with a call to
+ // setAppCacheEnabled() and if a valid path has been supplied to
+ // setAppCachePath(). Note that the path is applied to all WebViews
+ // whereas enabling is applied per WebView.
+
+ // WebCore asserts that the path is only set once. Since the path is
+ // shared between WebViews, we can't do the required checks to guard
+ // against this in the Java WebSettings.
+ bool isPathValid = false;
+ if (cacheStorage().cacheDirectory().isNull()) {
+ str = static_cast<jstring>(env->GetObjectField(obj, gFieldIds->mAppCachePath));
+ // Check for non-null string as an optimization, as this is the common case.
+ if (str) {
+ String path = jstringToWtfString(env, str);
+ ALOG_ASSERT(!path.empty(), "Java side should never send empty string for AppCache path");
// This database is created on the first load. If the file
// doesn't exist, we create it and set its permissions. The
// filename must match that in ApplicationCacheStorage.cpp.
String filename = pathByAppendingComponent(path, "ApplicationCache.db");
- int fd = open(filename.utf8().data(), O_CREAT | O_EXCL, permissionFlags660);
- if (fd >= 0)
+ int fd = open(filename.utf8().data(), O_CREAT, permissionFlags660);
+ if (fd >= 0) {
close(fd);
+ cacheStorage().setCacheDirectory(path);
+ isPathValid = true;
+ }
}
- }
+ } else
+ isPathValid = true;
+
+ flag = env->GetBooleanField(obj, gFieldIds->mAppCacheEnabled);
+ s->setOfflineWebApplicationCacheEnabled(flag && isPathValid);
+
jlong maxsize = env->GetLongField(obj, gFieldIds->mAppCacheMaxSize);
cacheStorage().setMaximumSize(maxsize);
#endif
@@ -547,6 +569,11 @@ public:
flag = env->GetBooleanField(obj, gFieldIds->mXSSAuditorEnabled);
s->setXSSAuditorEnabled(flag);
+#if ENABLE(LINK_PREFETCH)
+ flag = env->GetBooleanField(obj, gFieldIds->mLinkPrefetchEnabled);
+ s->setLinkPrefetchEnabled(flag);
+#endif
+
size = env->GetIntField(obj, gFieldIds->mPageCacheCapacity);
if (size > 0) {
s->setUsesPageCache(true);
@@ -585,6 +612,10 @@ public:
// This is required to enable the XMLTreeViewer when loading an XML document that
// has no style attached to it. http://trac.webkit.org/changeset/79799
s->setDeveloperExtrasEnabled(true);
+ s->setSpatialNavigationEnabled(true);
+ bool echoPassword = env->GetBooleanField(obj,
+ gFieldIds->mPasswordEchoEnabled);
+ s->setPasswordEchoEnabled(echoPassword);
}
};
@@ -600,11 +631,11 @@ static JNINativeMethod gWebSettingsMethods[] = {
int registerWebSettings(JNIEnv* env)
{
- jclass clazz = env->FindClass("android/webkit/WebSettings");
- LOG_ASSERT(clazz, "Unable to find class WebSettings!");
+ jclass clazz = env->FindClass("android/webkit/WebSettingsClassic");
+ ALOG_ASSERT(clazz, "Unable to find class WebSettingsClassic!");
gFieldIds = new FieldIds(env, clazz);
env->DeleteLocalRef(clazz);
- return jniRegisterNativeMethods(env, "android/webkit/WebSettings",
+ return jniRegisterNativeMethods(env, "android/webkit/WebSettingsClassic",
gWebSettingsMethods, NELEM(gWebSettingsMethods));
}
diff --git a/Source/WebKit/android/jni/WebStorage.cpp b/Source/WebKit/android/jni/WebStorage.cpp
index 9ce207d..66a3517 100644
--- a/Source/WebKit/android/jni/WebStorage.cpp
+++ b/Source/WebKit/android/jni/WebStorage.cpp
@@ -174,12 +174,12 @@ static JNINativeMethod gWebStorageMethods[] = {
int registerWebStorage(JNIEnv* env)
{
#ifndef NDEBUG
- jclass webStorage = env->FindClass("android/webkit/WebStorage");
- LOG_ASSERT(webStorage, "Unable to find class android.webkit.WebStorage");
+ jclass webStorage = env->FindClass("android/webkit/WebStorageClassic");
+ ALOG_ASSERT(webStorage, "Unable to find class android.webkit.WebStorageClassic");
env->DeleteLocalRef(webStorage);
#endif
- return jniRegisterNativeMethods(env, "android/webkit/WebStorage",
+ return jniRegisterNativeMethods(env, "android/webkit/WebStorageClassic",
gWebStorageMethods, NELEM(gWebStorageMethods));
}
diff --git a/Source/WebKit/android/jni/WebViewCore.cpp b/Source/WebKit/android/jni/WebViewCore.cpp
index 1b53a6e..f17e573 100644
--- a/Source/WebKit/android/jni/WebViewCore.cpp
+++ b/Source/WebKit/android/jni/WebViewCore.cpp
@@ -29,10 +29,9 @@
#include "WebViewCore.h"
#include "AccessibilityObject.h"
+#include "AndroidHitTestResult.h"
#include "Attribute.h"
-#include "BaseLayerAndroid.h"
-#include "CachedNode.h"
-#include "CachedRoot.h"
+#include "content/address_detector.h"
#include "Chrome.h"
#include "ChromeClientAndroid.h"
#include "ChromiumIncludes.h"
@@ -43,6 +42,7 @@
#include "CSSValueKeywords.h"
#include "DatabaseTracker.h"
#include "Document.h"
+#include "DocumentMarkerController.h"
#include "DOMWindow.h"
#include "DOMSelection.h"
#include "Element.h"
@@ -53,6 +53,7 @@
#include "ExceptionCode.h"
#include "FocusController.h"
#include "Font.h"
+#include "FontCache.h"
#include "Frame.h"
#include "FrameLoader.h"
#include "FrameLoaderClientAndroid.h"
@@ -61,6 +62,7 @@
#include "Geolocation.h"
#include "GraphicsContext.h"
#include "GraphicsJNI.h"
+#include "GraphicsOperationCollection.h"
#include "HTMLAnchorElement.h"
#include "HTMLAreaElement.h"
#include "HTMLElement.h"
@@ -78,6 +80,7 @@
#include "HitTestRequest.h"
#include "HitTestResult.h"
#include "InlineTextBox.h"
+#include "KeyboardEvent.h"
#include "MemoryUsage.h"
#include "NamedNodeMap.h"
#include "Navigator.h"
@@ -85,6 +88,8 @@
#include "NodeList.h"
#include "Page.h"
#include "PageGroup.h"
+#include "PictureLayerContent.h"
+#include "PicturePileLayerContent.h"
#include "PlatformKeyboardEvent.h"
#include "PlatformString.h"
#include "PluginWidgetAndroid.h"
@@ -93,6 +98,7 @@
#include "ProgressTracker.h"
#include "Range.h"
#include "RenderBox.h"
+#include "RenderImage.h"
#include "RenderInline.h"
#include "RenderLayer.h"
#include "RenderPart.h"
@@ -103,38 +109,43 @@
#include "ResourceRequest.h"
#include "RuntimeEnabledFeatures.h"
#include "SchemeRegistry.h"
+#include "ScopedLocalRef.h"
+#include "ScriptController.h"
#include "SelectionController.h"
+#include "SelectText.h"
#include "Settings.h"
#include "SkANP.h"
#include "SkTemplates.h"
#include "SkTDArray.h"
#include "SkTypes.h"
#include "SkCanvas.h"
+#include "SkGraphics.h"
#include "SkPicture.h"
#include "SkUtils.h"
#include "Text.h"
+#include "TextIterator.h"
+#include "TilesManager.h"
#include "TypingCommand.h"
#include "WebCache.h"
#include "WebCoreFrameBridge.h"
+#include "WebCoreJni.h"
#include "WebFrameView.h"
#include "WindowsKeyboardCodes.h"
#include "android_graphics.h"
#include "autofill/WebAutofill.h"
#include "htmlediting.h"
#include "markup.h"
+#include "visible_units.h"
#include <JNIHelp.h>
#include <JNIUtility.h>
-#include <ui/KeycodeLabels.h>
+#include <androidfw/KeycodeLabels.h>
+#include <cutils/properties.h>
+#include <v8.h>
#include <wtf/CurrentTime.h>
#include <wtf/text/AtomicString.h>
-#include <wtf/text/StringImpl.h>
-
-#if USE(V8)
-#include "ScriptController.h"
-#include "V8Counters.h"
#include <wtf/text/CString.h>
-#endif
+#include <wtf/text/StringImpl.h>
#if DEBUG_NAV_UI
#include "SkTime.h"
@@ -153,34 +164,85 @@ FILE* gDomTreeFile = 0;
FILE* gRenderTreeFile = 0;
#endif
-#ifdef ANDROID_INSTRUMENT
-#include "TimeCounter.h"
-#endif
+#include "BaseLayerAndroid.h"
#if USE(ACCELERATED_COMPOSITING)
#include "GraphicsLayerAndroid.h"
#include "RenderLayerCompositor.h"
#endif
-#if USE(V8)
-#include <v8.h>
-#endif
+#define FOREGROUND_TIMER_INTERVAL 0.004 // 4ms
+#define BACKGROUND_TIMER_INTERVAL 1.0 // 1s
-// In some cases, too many invalidations passed to the UI will slow us down.
-// Limit ourselves to 32 rectangles, past this just send the area bounds to the UI.
-// see WebViewCore::recordPictureSet().
-#define MAX_INVALIDATIONS 32
+// How many ms to wait for the scroll to "settle" before we will consider doing
+// prerenders
+#define PRERENDER_AFTER_SCROLL_DELAY 750
-/* We pass this flag when recording the actual content, so that we don't spend
- time actually regionizing complex path clips, when all we really want to do
- is record them.
- */
-#define PICT_RECORD_FLAGS SkPicture::kUsePathBoundsForClip_RecordingFlag
+#define TOUCH_FLAG_HIT_HANDLER 0x1
+#define TOUCH_FLAG_PREVENT_DEFAULT 0x2
////////////////////////////////////////////////////////////////////////////////////////////////
namespace android {
+// Copied from CacheBuilder, not sure if this is needed/correct
+IntRect getAreaRect(const HTMLAreaElement* area)
+{
+ Node* node = area->document();
+ while ((node = node->traverseNextNode()) != NULL) {
+ RenderObject* renderer = node->renderer();
+ if (renderer && renderer->isRenderImage()) {
+ RenderImage* image = static_cast<RenderImage*>(renderer);
+ HTMLMapElement* map = image->imageMap();
+ if (map) {
+ Node* n;
+ for (n = map->firstChild(); n;
+ n = n->traverseNextNode(map)) {
+ if (n == area) {
+ if (area->isDefault())
+ return image->absoluteBoundingBoxRect();
+ return area->computeRect(image);
+ }
+ }
+ }
+ }
+ }
+ return IntRect();
+}
+
+// Copied from CacheBuilder, not sure if this is needed/correct
+// TODO: See if this is even needed (I suspect not), and if not remove it
+bool validNode(Frame* startFrame, void* matchFrame,
+ void* matchNode)
+{
+ if (matchFrame == startFrame) {
+ if (matchNode == NULL)
+ return true;
+ Node* node = startFrame->document();
+ while (node != NULL) {
+ if (node == matchNode) {
+ const IntRect& rect = node->hasTagName(HTMLNames::areaTag) ?
+ getAreaRect(static_cast<HTMLAreaElement*>(node)) : node->getRect();
+ // Consider nodes with empty rects that are not at the origin
+ // to be valid, since news.google.com has valid nodes like this
+ if (rect.x() == 0 && rect.y() == 0 && rect.isEmpty())
+ return false;
+ return true;
+ }
+ node = node->traverseNextNode();
+ }
+ return false;
+ }
+ Frame* child = startFrame->tree()->firstChild();
+ while (child) {
+ bool result = validNode(child, matchFrame, matchNode);
+ if (result)
+ return result;
+ child = child->tree()->nextSibling();
+ }
+ return false;
+}
+
static SkTDArray<WebViewCore*> gInstanceList;
void WebViewCore::addInstance(WebViewCore* inst) {
@@ -189,7 +251,7 @@ void WebViewCore::addInstance(WebViewCore* inst) {
void WebViewCore::removeInstance(WebViewCore* inst) {
int index = gInstanceList.find(inst);
- LOG_ASSERT(index >= 0, "RemoveInstance inst not found");
+ ALOG_ASSERT(index >= 0, "RemoveInstance inst not found");
if (index >= 0) {
gInstanceList.removeShuffle(index);
}
@@ -242,8 +304,6 @@ bool WebViewCore::isSupportedMediaMimeType(const WTF::String& mimeType) {
// ----------------------------------------------------------------------------
-#define GET_NATIVE_VIEW(env, obj) ((WebViewCore*)env->GetIntField(obj, gWebViewCoreFields.m_nativeClass))
-
// Field ids for WebViewCore
struct WebViewCoreFields {
jfieldID m_nativeClass;
@@ -254,7 +314,6 @@ struct WebViewCoreFields {
jfieldID m_viewportMaximumScale;
jfieldID m_viewportUserScalable;
jfieldID m_viewportDensityDpi;
- jfieldID m_webView;
jfieldID m_drawIsPaused;
jfieldID m_lowMemoryUsageMb;
jfieldID m_highMemoryUsageMb;
@@ -267,7 +326,6 @@ struct WebViewCore::JavaGlue {
jweak m_obj;
jmethodID m_scrollTo;
jmethodID m_contentDraw;
- jmethodID m_layersDraw;
jmethodID m_requestListBox;
jmethodID m_openFileChooser;
jmethodID m_requestSingleListBox;
@@ -276,17 +334,18 @@ struct WebViewCore::JavaGlue {
jmethodID m_jsPrompt;
jmethodID m_jsUnload;
jmethodID m_jsInterrupt;
+ jmethodID m_getWebView;
jmethodID m_didFirstLayout;
jmethodID m_updateViewport;
jmethodID m_sendNotifyProgressFinished;
jmethodID m_sendViewInvalidate;
jmethodID m_updateTextfield;
jmethodID m_updateTextSelection;
+ jmethodID m_updateTextSizeAndScroll;
jmethodID m_clearTextEntry;
jmethodID m_restoreScale;
jmethodID m_needTouchEvents;
jmethodID m_requestKeyboard;
- jmethodID m_requestKeyboardWithSelection;
jmethodID m_exceededDatabaseQuota;
jmethodID m_reachedMaxAppCacheSize;
jmethodID m_populateVisitedLinks;
@@ -295,7 +354,7 @@ struct WebViewCore::JavaGlue {
jmethodID m_getDeviceMotionService;
jmethodID m_getDeviceOrientationService;
jmethodID m_addMessageToConsole;
- jmethodID m_formDidBlur;
+ jmethodID m_focusNodeChanged;
jmethodID m_getPluginClass;
jmethodID m_showFullScreenPlugin;
jmethodID m_hideFullScreenPlugin;
@@ -305,14 +364,17 @@ struct WebViewCore::JavaGlue {
jmethodID m_destroySurface;
jmethodID m_getContext;
jmethodID m_keepScreenOn;
- jmethodID m_sendFindAgain;
jmethodID m_showRect;
jmethodID m_centerFitRect;
jmethodID m_setScrollbarModes;
jmethodID m_setInstallableWebApp;
jmethodID m_enterFullscreenForVideoLayer;
+ jmethodID m_exitFullscreenVideo;
jmethodID m_setWebTextViewAutoFillable;
jmethodID m_selectAt;
+ jmethodID m_initEditField;
+ jmethodID m_chromeCanTakeFocus;
+ jmethodID m_chromeTakeFocus;
AutoJObject object(JNIEnv* env) {
// We hold a weak reference to the Java WebViewCore to avoid memeory
// leaks due to circular references when WebView.destroy() is not
@@ -325,6 +387,23 @@ struct WebViewCore::JavaGlue {
}
};
+struct WebViewCore::TextFieldInitDataGlue {
+ jmethodID m_constructor;
+ jfieldID m_fieldPointer;
+ jfieldID m_text;
+ jfieldID m_type;
+ jfieldID m_isSpellCheckEnabled;
+ jfieldID m_isTextFieldNext;
+ jfieldID m_isTextFieldPrev;
+ jfieldID m_isAutoCompleteEnabled;
+ jfieldID m_name;
+ jfieldID m_label;
+ jfieldID m_maxLength;
+ jfieldID m_contentBounds;
+ jfieldID m_nodeLayerId;
+ jfieldID m_contentRect;
+};
+
/*
* WebViewCore Implementation
*/
@@ -332,58 +411,37 @@ struct WebViewCore::JavaGlue {
static jmethodID GetJMethod(JNIEnv* env, jclass clazz, const char name[], const char signature[])
{
jmethodID m = env->GetMethodID(clazz, name, signature);
- LOG_ASSERT(m, "Could not find method %s", name);
+ ALOG_ASSERT(m, "Could not find method %s", name);
return m;
}
-Mutex WebViewCore::gFrameCacheMutex;
-Mutex WebViewCore::gCursorBoundsMutex;
-
WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* mainframe)
- : m_frameCacheKit(0)
- , m_navPictureKit(0)
- , m_moveGeneration(0)
- , m_touchGeneration(0)
+ : m_touchGeneration(0)
, m_lastGeneration(0)
- , m_updatedFrameCache(true)
- , m_findIsUp(false)
- , m_hasCursorBounds(false)
- , m_cursorBounds(WebCore::IntRect(0, 0, 0, 0))
- , m_cursorHitBounds(WebCore::IntRect(0, 0, 0, 0))
- , m_cursorFrame(0)
- , m_cursorLocation(WebCore::IntPoint(0, 0))
- , m_cursorNode(0)
, m_javaGlue(new JavaGlue)
+ , m_textFieldInitDataGlue(new TextFieldInitDataGlue)
, m_mainFrame(mainframe)
, m_popupReply(0)
- , m_lastFocused(0)
- , m_lastFocusedBounds(WebCore::IntRect(0,0,0,0))
- , m_blurringNodePointer(0)
- , m_lastFocusedSelStart(0)
- , m_lastFocusedSelEnd(0)
, m_blockTextfieldUpdates(false)
, m_focusBoundsChanged(false)
, m_skipContentDraw(false)
, m_textGeneration(0)
- , m_temp(0)
- , m_tempPict(0)
, m_maxXScroll(320/4)
, m_maxYScroll(240/4)
, m_scrollOffsetX(0)
, m_scrollOffsetY(0)
, m_mousePos(WebCore::IntPoint(0,0))
- , m_frameCacheOutOfDate(true)
- , m_progressDone(false)
, m_screenWidth(320)
, m_screenHeight(240)
, m_textWrapWidth(320)
, m_scale(1.0f)
- , m_domtree_version(0)
- , m_check_domtree_version(true)
, m_groupForVisitedLinks(0)
, m_isPaused(false)
, m_cacheMode(0)
- , m_shouldPaintCaret(true)
+ , m_fullscreenVideoMode(false)
+ , m_matchCount(0)
+ , m_activeMatchIndex(0)
+ , m_activeMatch(0)
, m_pluginInvalTimer(this, &WebViewCore::pluginInvalTimerFired)
, m_screenOnCounter(0)
, m_currentNodeDomNavigationAxis(0)
@@ -391,36 +449,35 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m
#if ENABLE(TOUCH_EVENTS)
, m_forwardingTouchEvents(false)
#endif
-#if USE(CHROME_NETWORK_STACK)
, m_webRequestContext(0)
-#endif
+ , m_prerenderEnabled(false)
{
- LOG_ASSERT(m_mainFrame, "Uh oh, somehow a frameview was made without an initial frame!");
+ ALOG_ASSERT(m_mainFrame, "Uh oh, somehow a frameview was made without an initial frame!");
jclass clazz = env->GetObjectClass(javaWebViewCore);
m_javaGlue->m_obj = env->NewWeakGlobalRef(javaWebViewCore);
m_javaGlue->m_scrollTo = GetJMethod(env, clazz, "contentScrollTo", "(IIZZ)V");
m_javaGlue->m_contentDraw = GetJMethod(env, clazz, "contentDraw", "()V");
- m_javaGlue->m_layersDraw = GetJMethod(env, clazz, "layersDraw", "()V");
m_javaGlue->m_requestListBox = GetJMethod(env, clazz, "requestListBox", "([Ljava/lang/String;[I[I)V");
- m_javaGlue->m_openFileChooser = GetJMethod(env, clazz, "openFileChooser", "(Ljava/lang/String;)Ljava/lang/String;");
+ m_javaGlue->m_openFileChooser = GetJMethod(env, clazz, "openFileChooser", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
m_javaGlue->m_requestSingleListBox = GetJMethod(env, clazz, "requestListBox", "([Ljava/lang/String;[II)V");
m_javaGlue->m_jsAlert = GetJMethod(env, clazz, "jsAlert", "(Ljava/lang/String;Ljava/lang/String;)V");
m_javaGlue->m_jsConfirm = GetJMethod(env, clazz, "jsConfirm", "(Ljava/lang/String;Ljava/lang/String;)Z");
m_javaGlue->m_jsPrompt = GetJMethod(env, clazz, "jsPrompt", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
m_javaGlue->m_jsUnload = GetJMethod(env, clazz, "jsUnload", "(Ljava/lang/String;Ljava/lang/String;)Z");
m_javaGlue->m_jsInterrupt = GetJMethod(env, clazz, "jsInterrupt", "()Z");
+ m_javaGlue->m_getWebView = GetJMethod(env, clazz, "getWebView", "()Landroid/webkit/WebView;");
m_javaGlue->m_didFirstLayout = GetJMethod(env, clazz, "didFirstLayout", "(Z)V");
m_javaGlue->m_updateViewport = GetJMethod(env, clazz, "updateViewport", "()V");
m_javaGlue->m_sendNotifyProgressFinished = GetJMethod(env, clazz, "sendNotifyProgressFinished", "()V");
m_javaGlue->m_sendViewInvalidate = GetJMethod(env, clazz, "sendViewInvalidate", "(IIII)V");
m_javaGlue->m_updateTextfield = GetJMethod(env, clazz, "updateTextfield", "(IZLjava/lang/String;I)V");
- m_javaGlue->m_updateTextSelection = GetJMethod(env, clazz, "updateTextSelection", "(IIII)V");
+ m_javaGlue->m_updateTextSelection = GetJMethod(env, clazz, "updateTextSelection", "(IIIII)V");
+ m_javaGlue->m_updateTextSizeAndScroll = GetJMethod(env, clazz, "updateTextSizeAndScroll", "(IIIII)V");
m_javaGlue->m_clearTextEntry = GetJMethod(env, clazz, "clearTextEntry", "()V");
m_javaGlue->m_restoreScale = GetJMethod(env, clazz, "restoreScale", "(FF)V");
m_javaGlue->m_needTouchEvents = GetJMethod(env, clazz, "needTouchEvents", "(Z)V");
m_javaGlue->m_requestKeyboard = GetJMethod(env, clazz, "requestKeyboard", "(Z)V");
- m_javaGlue->m_requestKeyboardWithSelection = GetJMethod(env, clazz, "requestKeyboardWithSelection", "(IIII)V");
m_javaGlue->m_exceededDatabaseQuota = GetJMethod(env, clazz, "exceededDatabaseQuota", "(Ljava/lang/String;Ljava/lang/String;JJ)V");
m_javaGlue->m_reachedMaxAppCacheSize = GetJMethod(env, clazz, "reachedMaxAppCacheSize", "(J)V");
m_javaGlue->m_populateVisitedLinks = GetJMethod(env, clazz, "populateVisitedLinks", "()V");
@@ -429,7 +486,7 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m
m_javaGlue->m_getDeviceMotionService = GetJMethod(env, clazz, "getDeviceMotionService", "()Landroid/webkit/DeviceMotionService;");
m_javaGlue->m_getDeviceOrientationService = GetJMethod(env, clazz, "getDeviceOrientationService", "()Landroid/webkit/DeviceOrientationService;");
m_javaGlue->m_addMessageToConsole = GetJMethod(env, clazz, "addMessageToConsole", "(Ljava/lang/String;ILjava/lang/String;I)V");
- m_javaGlue->m_formDidBlur = GetJMethod(env, clazz, "formDidBlur", "(I)V");
+ m_javaGlue->m_focusNodeChanged = GetJMethod(env, clazz, "focusNodeChanged", "(ILandroid/webkit/WebViewCore$WebKitHitTest;)V");
m_javaGlue->m_getPluginClass = GetJMethod(env, clazz, "getPluginClass", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Class;");
m_javaGlue->m_showFullScreenPlugin = GetJMethod(env, clazz, "showFullScreenPlugin", "(Landroid/webkit/ViewManager$ChildView;II)V");
m_javaGlue->m_hideFullScreenPlugin = GetJMethod(env, clazz, "hideFullScreenPlugin", "()V");
@@ -439,20 +496,40 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m
m_javaGlue->m_destroySurface = GetJMethod(env, clazz, "destroySurface", "(Landroid/webkit/ViewManager$ChildView;)V");
m_javaGlue->m_getContext = GetJMethod(env, clazz, "getContext", "()Landroid/content/Context;");
m_javaGlue->m_keepScreenOn = GetJMethod(env, clazz, "keepScreenOn", "(Z)V");
- m_javaGlue->m_sendFindAgain = GetJMethod(env, clazz, "sendFindAgain", "()V");
m_javaGlue->m_showRect = GetJMethod(env, clazz, "showRect", "(IIIIIIFFFF)V");
m_javaGlue->m_centerFitRect = GetJMethod(env, clazz, "centerFitRect", "(IIII)V");
m_javaGlue->m_setScrollbarModes = GetJMethod(env, clazz, "setScrollbarModes", "(II)V");
m_javaGlue->m_setInstallableWebApp = GetJMethod(env, clazz, "setInstallableWebApp", "()V");
#if ENABLE(VIDEO)
m_javaGlue->m_enterFullscreenForVideoLayer = GetJMethod(env, clazz, "enterFullscreenForVideoLayer", "(ILjava/lang/String;)V");
+ m_javaGlue->m_exitFullscreenVideo = GetJMethod(env, clazz, "exitFullscreenVideo", "()V");
#endif
m_javaGlue->m_setWebTextViewAutoFillable = GetJMethod(env, clazz, "setWebTextViewAutoFillable", "(ILjava/lang/String;)V");
m_javaGlue->m_selectAt = GetJMethod(env, clazz, "selectAt", "(II)V");
+ m_javaGlue->m_initEditField = GetJMethod(env, clazz, "initEditField", "(IIILandroid/webkit/WebViewCore$TextFieldInitData;)V");
+ m_javaGlue->m_chromeCanTakeFocus = GetJMethod(env, clazz, "chromeCanTakeFocus", "(I)Z");
+ m_javaGlue->m_chromeTakeFocus = GetJMethod(env, clazz, "chromeTakeFocus", "(I)V");
env->DeleteLocalRef(clazz);
env->SetIntField(javaWebViewCore, gWebViewCoreFields.m_nativeClass, (jint)this);
+ jclass tfidClazz = env->FindClass("android/webkit/WebViewCore$TextFieldInitData");
+ m_textFieldInitDataGlue->m_fieldPointer = env->GetFieldID(tfidClazz, "mFieldPointer", "I");
+ m_textFieldInitDataGlue->m_text = env->GetFieldID(tfidClazz, "mText", "Ljava/lang/String;");
+ m_textFieldInitDataGlue->m_type = env->GetFieldID(tfidClazz, "mType", "I");
+ m_textFieldInitDataGlue->m_isSpellCheckEnabled = env->GetFieldID(tfidClazz, "mIsSpellCheckEnabled", "Z");
+ m_textFieldInitDataGlue->m_isTextFieldNext = env->GetFieldID(tfidClazz, "mIsTextFieldNext", "Z");
+ m_textFieldInitDataGlue->m_isTextFieldPrev = env->GetFieldID(tfidClazz, "mIsTextFieldPrev", "Z");
+ m_textFieldInitDataGlue->m_isAutoCompleteEnabled = env->GetFieldID(tfidClazz, "mIsAutoCompleteEnabled", "Z");
+ m_textFieldInitDataGlue->m_name = env->GetFieldID(tfidClazz, "mName", "Ljava/lang/String;");
+ m_textFieldInitDataGlue->m_label = env->GetFieldID(tfidClazz, "mLabel", "Ljava/lang/String;");
+ m_textFieldInitDataGlue->m_maxLength = env->GetFieldID(tfidClazz, "mMaxLength", "I");
+ m_textFieldInitDataGlue->m_contentBounds = env->GetFieldID(tfidClazz, "mContentBounds", "Landroid/graphics/Rect;");
+ m_textFieldInitDataGlue->m_nodeLayerId = env->GetFieldID(tfidClazz, "mNodeLayerId", "I");
+ m_textFieldInitDataGlue->m_contentRect = env->GetFieldID(tfidClazz, "mContentRect", "Landroid/graphics/Rect;");
+ m_textFieldInitDataGlue->m_constructor = GetJMethod(env, tfidClazz, "<init>", "()V");
+ env->DeleteLocalRef(tfidClazz);
+
PageGroup::setShouldTrackVisitedLinks(true);
clearContent();
@@ -463,22 +540,23 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m
WebViewCore::addInstance(this);
-#if USE(CHROME_NETWORK_STACK)
AndroidNetworkLibraryImpl::InitWithApplicationContext(env, 0);
-#endif
-#if USE(V8)
+ // increase the font cache size beyond the standard system setting
+ SkGraphics::SetFontCacheLimit(1572864); // 1572864 bytes == 1.5 MB
+
// Static initialisation of certain important V8 static data gets performed at system startup when
// libwebcore gets loaded. We now need to associate the WebCore thread with V8 to complete
// initialisation.
v8::V8::Initialize();
-#endif
// Configure any RuntimeEnabled features that we need to change from their default now.
// See WebCore/bindings/generic/RuntimeEnabledFeatures.h
// HTML5 History API
RuntimeEnabledFeatures::setPushStateEnabled(true);
+ if (m_mainFrame)
+ m_mainFrame->settings()->setMinDOMTimerInterval(FOREGROUND_TIMER_INTERVAL);
}
WebViewCore::~WebViewCore()
@@ -494,24 +572,40 @@ WebViewCore::~WebViewCore()
m_javaGlue->m_obj = 0;
}
delete m_javaGlue;
- delete m_frameCacheKit;
- delete m_navPictureKit;
}
WebViewCore* WebViewCore::getWebViewCore(const WebCore::FrameView* view)
{
- return getWebViewCore(static_cast<const WebCore::ScrollView*>(view));
+ if (!view)
+ return 0;
+ if (view->platformWidget())
+ return static_cast<WebFrameView*>(view->platformWidget())->webViewCore();
+ Frame* frame = view->frame();
+ while (Frame* parent = frame->tree()->parent())
+ frame = parent;
+ WebFrameView* webFrameView = 0;
+ if (frame && frame->view())
+ webFrameView = static_cast<WebFrameView*>(frame->view()->platformWidget());
+ if (!webFrameView)
+ return 0;
+ return webFrameView->webViewCore();
}
WebViewCore* WebViewCore::getWebViewCore(const WebCore::ScrollView* view)
{
if (!view)
return 0;
-
- WebFrameView* webFrameView = static_cast<WebFrameView*>(view->platformWidget());
- if (!webFrameView)
- return 0;
- return webFrameView->webViewCore();
+ if (view->platformWidget())
+ return static_cast<WebFrameView*>(view->platformWidget())->webViewCore();
+ const FrameView* frameView = 0;
+ if (view->isFrameView())
+ frameView = static_cast<const FrameView*>(view);
+ else {
+ frameView = static_cast<const FrameView*>(view->root());
+ if (!frameView)
+ return 0;
+ }
+ return getWebViewCore(frameView);
}
static bool layoutIfNeededRecursive(WebCore::Frame* f)
@@ -522,84 +616,35 @@ static bool layoutIfNeededRecursive(WebCore::Frame* f)
WebCore::FrameView* v = f->view();
if (!v)
return true;
-
- if (v->needsLayout())
- v->layout(f->tree()->parent());
-
- WebCore::Frame* child = f->tree()->firstChild();
- bool success = true;
- while (child) {
- success &= layoutIfNeededRecursive(child);
- child = child->tree()->nextSibling();
- }
-
- return success && !v->needsLayout();
-}
-
-CacheBuilder& WebViewCore::cacheBuilder()
-{
- return FrameLoaderClientAndroid::get(m_mainFrame)->getCacheBuilder();
+ v->updateLayoutAndStyleIfNeededRecursive();
+ return !v->needsLayout();
}
WebCore::Node* WebViewCore::currentFocus()
{
- return cacheBuilder().currentFocus();
+ return focusedFrame()->document()->focusedNode();
}
-void WebViewCore::recordPicture(SkPicture* picture)
+void WebViewCore::layout()
{
- // if there is no document yet, just return
- if (!m_mainFrame->document()) {
- DBG_NAV_LOG("no document");
- return;
- }
- // Call layout to ensure that the contentWidth and contentHeight are correct
- if (!layoutIfNeededRecursive(m_mainFrame)) {
- DBG_NAV_LOG("layout failed");
- return;
- }
- // draw into the picture's recording canvas
- WebCore::FrameView* view = m_mainFrame->view();
- DBG_NAV_LOGD("view=(w=%d,h=%d)", view->contentsWidth(),
- view->contentsHeight());
- SkAutoPictureRecord arp(picture, view->contentsWidth(),
- view->contentsHeight(), PICT_RECORD_FLAGS);
- SkAutoMemoryUsageProbe mup(__FUNCTION__);
-
- WebCore::PlatformGraphicsContext pgc(arp.getRecordingCanvas());
- WebCore::GraphicsContext gc(&pgc);
- view->platformWidget()->draw(&gc, WebCore::IntRect(0, 0,
- view->contentsWidth(), view->contentsHeight()));
-}
+ TRACE_METHOD();
-void WebViewCore::recordPictureSet(PictureSet* content)
-{
// if there is no document yet, just return
if (!m_mainFrame->document()) {
- DBG_SET_LOG("!m_mainFrame->document()");
- return;
- }
- if (m_addInval.isEmpty()) {
- DBG_SET_LOG("m_addInval.isEmpty()");
+ ALOGV("!m_mainFrame->document()");
return;
}
+
// Call layout to ensure that the contentWidth and contentHeight are correct
// it's fine for layout to gather invalidates, but defeat sending a message
// back to java to call webkitDraw, since we're already in the middle of
// doing that
- m_skipContentDraw = true;
bool success = layoutIfNeededRecursive(m_mainFrame);
- m_skipContentDraw = false;
// We may be mid-layout and thus cannot draw.
if (!success)
return;
- { // collect WebViewCoreRecordTimeCounter after layoutIfNeededRecursive
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::WebViewCoreRecordTimeCounter);
-#endif
-
// if the webkit page dimensions changed, discard the pictureset and redraw.
WebCore::FrameView* view = m_mainFrame->view();
int width = view->contentsWidth();
@@ -650,6 +695,8 @@ void WebViewCore::recordPictureSet(PictureSet* content)
// If the new total is larger than the content, resize the view to include
// all the content.
if (!contentRect.contains(total)) {
+ // TODO: Does this ever happen? Is this needed now that we don't flatten
+ // frames?
// Resize the view to change the overflow clip.
view->resize(total.fRight, total.fBottom);
@@ -658,159 +705,27 @@ void WebViewCore::recordPictureSet(PictureSet* content)
view->forceLayout();
// Relayout similar to above
- m_skipContentDraw = true;
- bool success = layoutIfNeededRecursive(m_mainFrame);
- m_skipContentDraw = false;
- if (!success)
- return;
-
- // Set the computed content width
- width = view->contentsWidth();
- height = view->contentsHeight();
+ layoutIfNeededRecursive(m_mainFrame);
}
+}
- if (cacheBuilder().pictureSetDisabled())
- content->clear();
-
-#if USE(ACCELERATED_COMPOSITING)
- // The invals are not always correct when the content size has changed. For
- // now, let's just reset the inval so that it invalidates the entire content
- // -- the pictureset will be fully repainted, tiles will be marked dirty and
- // will have to be repainted.
-
- // FIXME: the webkit invals ought to have been enough...
- if (content->width() != width || content->height() != height) {
- SkIRect r;
- r.fLeft = 0;
- r.fTop = 0;
- r.fRight = width;
- r.fBottom = height;
- m_addInval.setRect(r);
- }
-#endif
-
- content->setDimensions(width, height, &m_addInval);
-
- // Add the current inval rects to the PictureSet, and rebuild it.
- content->add(m_addInval, 0, 0, false);
+void WebViewCore::recordPicturePile()
+{
+ // if the webkit page dimensions changed, discard the pictureset and redraw.
+ WebCore::FrameView* view = m_mainFrame->view();
+ int width = view ? view->contentsWidth() : 0;
+ int height = view ? view->contentsHeight() : 0;
- // If we have too many invalidations, just get the area bounds
- SkRegion::Iterator iterator(m_addInval);
- int nbInvals = 0;
- while (!iterator.done()) {
- iterator.next();
- nbInvals++;
- if (nbInvals > MAX_INVALIDATIONS)
- break;
- }
- if (nbInvals > MAX_INVALIDATIONS) {
- SkIRect r = m_addInval.getBounds();
- m_addInval.setRect(r);
- }
+ m_content.setSize(IntSize(width, height));
// Rebuild the pictureset (webkit repaint)
- rebuildPictureSet(content);
- } // WebViewCoreRecordTimeCounter
-
- WebCore::Node* oldFocusNode = currentFocus();
- m_frameCacheOutOfDate = true;
- WebCore::IntRect oldBounds;
- int oldSelStart = 0;
- int oldSelEnd = 0;
- if (oldFocusNode) {
- oldBounds = oldFocusNode->getRect();
- RenderObject* renderer = oldFocusNode->renderer();
- if (renderer && (renderer->isTextArea() || renderer->isTextField())) {
- WebCore::RenderTextControl* rtc =
- static_cast<WebCore::RenderTextControl*>(renderer);
- oldSelStart = rtc->selectionStart();
- oldSelEnd = rtc->selectionEnd();
- }
- } else
- oldBounds = WebCore::IntRect(0,0,0,0);
- unsigned latestVersion = 0;
- if (m_check_domtree_version) {
- // as domTreeVersion only increment, we can just check the sum to see
- // whether we need to update the frame cache
- for (Frame* frame = m_mainFrame; frame; frame = frame->tree()->traverseNext()) {
- const Document* doc = frame->document();
- latestVersion += doc->domTreeVersion() + doc->styleVersion();
- }
- }
- DBG_NAV_LOGD("m_lastFocused=%p oldFocusNode=%p"
- " m_lastFocusedBounds={%d,%d,%d,%d} oldBounds={%d,%d,%d,%d}"
- " m_lastFocusedSelection={%d,%d} oldSelection={%d,%d}"
- " m_check_domtree_version=%s latestVersion=%d m_domtree_version=%d",
- m_lastFocused, oldFocusNode,
- m_lastFocusedBounds.x(), m_lastFocusedBounds.y(),
- m_lastFocusedBounds.width(), m_lastFocusedBounds.height(),
- oldBounds.x(), oldBounds.y(), oldBounds.width(), oldBounds.height(),
- m_lastFocusedSelStart, m_lastFocusedSelEnd, oldSelStart, oldSelEnd,
- m_check_domtree_version ? "true" : "false",
- latestVersion, m_domtree_version);
- if (m_lastFocused == oldFocusNode && m_lastFocusedBounds == oldBounds
- && m_lastFocusedSelStart == oldSelStart
- && m_lastFocusedSelEnd == oldSelEnd
- && !m_findIsUp
- && (!m_check_domtree_version || latestVersion == m_domtree_version))
- {
- return;
- }
- m_focusBoundsChanged |= m_lastFocused == oldFocusNode
- && m_lastFocusedBounds != oldBounds;
- m_lastFocused = oldFocusNode;
- m_lastFocusedBounds = oldBounds;
- m_lastFocusedSelStart = oldSelStart;
- m_lastFocusedSelEnd = oldSelEnd;
- m_domtree_version = latestVersion;
- DBG_NAV_LOG("call updateFrameCache");
- updateFrameCache();
- if (m_findIsUp) {
- LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
- JNIEnv* env = JSC::Bindings::getJNIEnv();
- AutoJObject javaObject = m_javaGlue->object(env);
- if (javaObject.get()) {
- env->CallVoidMethod(javaObject.get(), m_javaGlue->m_sendFindAgain);
- checkException(env);
- }
- }
-}
-
-// note: updateCursorBounds is called directly by the WebView thread
-// This needs to be called each time we call CachedRoot::setCursor() with
-// non-null CachedNode/CachedFrame, since otherwise the WebViewCore's data
-// about the cursor is incorrect. When we call setCursor(0,0), we need
-// to set hasCursorBounds to false.
-void WebViewCore::updateCursorBounds(const CachedRoot* root,
- const CachedFrame* cachedFrame, const CachedNode* cachedNode)
-{
- LOG_ASSERT(root, "updateCursorBounds: root cannot be null");
- LOG_ASSERT(cachedNode, "updateCursorBounds: cachedNode cannot be null");
- LOG_ASSERT(cachedFrame, "updateCursorBounds: cachedFrame cannot be null");
- gCursorBoundsMutex.lock();
- m_hasCursorBounds = !cachedNode->isHidden();
- // If m_hasCursorBounds is false, we never look at the other
- // values, so do not bother setting them.
- if (m_hasCursorBounds) {
- WebCore::IntRect bounds = cachedNode->bounds(cachedFrame);
- if (m_cursorBounds != bounds)
- DBG_NAV_LOGD("new cursor bounds=(%d,%d,w=%d,h=%d)",
- bounds.x(), bounds.y(), bounds.width(), bounds.height());
- m_cursorBounds = bounds;
- m_cursorHitBounds = cachedNode->hitBounds(cachedFrame);
- m_cursorFrame = cachedFrame->framePointer();
- root->getSimulatedMousePosition(&m_cursorLocation);
- m_cursorNode = cachedNode->nodePointer();
- }
- gCursorBoundsMutex.unlock();
+ m_content.updatePicturesIfNeeded(this);
}
void WebViewCore::clearContent()
{
- DBG_SET_LOG("");
- m_content.clear();
- m_addInval.setEmpty();
- m_rebuildInval.setEmpty();
+ m_content.reset();
+ updateLocale();
}
bool WebViewCore::focusBoundsChanged()
@@ -820,75 +735,82 @@ bool WebViewCore::focusBoundsChanged()
return result;
}
-SkPicture* WebViewCore::rebuildPicture(const SkIRect& inval)
+void WebViewCore::paintContents(WebCore::GraphicsContext* gc, WebCore::IntRect& dirty)
{
WebCore::FrameView* view = m_mainFrame->view();
- int width = view->contentsWidth();
- int height = view->contentsHeight();
- SkPicture* picture = new SkPicture();
- SkAutoPictureRecord arp(picture, width, height, PICT_RECORD_FLAGS);
- SkAutoMemoryUsageProbe mup(__FUNCTION__);
- SkCanvas* recordingCanvas = arp.getRecordingCanvas();
+ if (!view) {
+ gc->setFillColor(WebCore::Color::white, WebCore::ColorSpaceDeviceRGB);
+ gc->fillColor();
+ return;
+ }
- WebCore::PlatformGraphicsContext pgc(recordingCanvas);
- WebCore::GraphicsContext gc(&pgc);
IntPoint origin = view->minimumScrollPosition();
- WebCore::IntRect drawArea(inval.fLeft + origin.x(), inval.fTop + origin.y(),
- inval.width(), inval.height());
- recordingCanvas->translate(-drawArea.x(), -drawArea.y());
- recordingCanvas->save();
- view->platformWidget()->draw(&gc, drawArea);
- m_rebuildInval.op(inval, SkRegion::kUnion_Op);
- DBG_SET_LOGD("m_rebuildInval={%d,%d,r=%d,b=%d}",
- m_rebuildInval.getBounds().fLeft, m_rebuildInval.getBounds().fTop,
- m_rebuildInval.getBounds().fRight, m_rebuildInval.getBounds().fBottom);
-
- return picture;
+ IntRect drawArea = dirty;
+ gc->translate(-origin.x(), -origin.y());
+ drawArea.move(origin.x(), origin.y());
+ view->platformWidget()->draw(gc, drawArea);
}
-void WebViewCore::rebuildPictureSet(PictureSet* pictureSet)
+void WebViewCore::setPrerenderingEnabled(bool enable)
{
- WebCore::FrameView* view = m_mainFrame->view();
-
-#ifdef FAST_PICTURESET
- WTF::Vector<Bucket*>* buckets = pictureSet->bucketsToUpdate();
-
- for (unsigned int i = 0; i < buckets->size(); i++) {
- Bucket* bucket = (*buckets)[i];
- for (unsigned int j = 0; j < bucket->size(); j++) {
- BucketPicture& bucketPicture = (*bucket)[j];
- const SkIRect& inval = bucketPicture.mRealArea;
- SkPicture* picture = rebuildPicture(inval);
- SkSafeUnref(bucketPicture.mPicture);
- bucketPicture.mPicture = picture;
- }
- }
- buckets->clear();
-#else
- size_t size = pictureSet->size();
- for (size_t index = 0; index < size; index++) {
- if (pictureSet->upToDate(index))
- continue;
- const SkIRect& inval = pictureSet->bounds(index);
- DBG_SET_LOGD("pictSet=%p [%d] {%d,%d,w=%d,h=%d}", pictureSet, index,
- inval.fLeft, inval.fTop, inval.width(), inval.height());
- pictureSet->setPicture(index, rebuildPicture(inval));
- }
+ MutexLocker locker(m_prerenderLock);
+ m_prerenderEnabled = enable;
+}
- pictureSet->validate(__FUNCTION__);
-#endif
+bool WebViewCore::prerenderingEnabled()
+{
+ MutexLocker locker(m_prerenderLock);
+ return m_prerenderEnabled;
}
-bool WebViewCore::updateLayers(LayerAndroid* layers)
+SkCanvas* WebViewCore::createPrerenderCanvas(PrerenderedInval* prerendered)
{
- // We update the layers
- ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(m_mainFrame->page()->chrome()->client());
- GraphicsLayerAndroid* root = static_cast<GraphicsLayerAndroid*>(chromeC->layersSync());
- if (root) {
- LayerAndroid* updatedLayer = root->contentLayer();
- return layers->updateWithTree(updatedLayer);
- }
- return true;
+ // Has WebView disabled prerenders (not attached, etc...)?
+ if (!prerenderingEnabled())
+ return 0;
+ // Does this WebView have focus?
+ if (!m_mainFrame->page()->focusController()->isActive())
+ return 0;
+ // Are we scrolling?
+ if (currentTimeMS() - m_scrollSetTime < PRERENDER_AFTER_SCROLL_DELAY)
+ return 0;
+ // Do we have anything to render?
+ if (prerendered->area.isEmpty())
+ return 0;
+ FloatRect scaleTemp(m_scrollOffsetX, m_scrollOffsetY, m_screenWidth, m_screenHeight);
+ scaleTemp.scale(m_scale);
+ IntRect visibleTileClip = enclosingIntRect(scaleTemp);
+ FloatRect scaledArea = prerendered->area;
+ scaledArea.scale(m_scale);
+ IntRect enclosingScaledArea = enclosingIntRect(scaledArea);
+ if (enclosingScaledArea.isEmpty())
+ return 0;
+ // "round out" the screen to tile boundaries so that we can clip yet still
+ // cover any visible tiles with the prerender
+ int tw = TilesManager::tileWidth();
+ int th = TilesManager::tileHeight();
+ float left = tw * (int) (visibleTileClip.x() / tw);
+ float top = th * (int) (visibleTileClip.y() / th);
+ float right = tw * (int) ceilf(visibleTileClip.maxX() / (float) tw);
+ float bottom = th * (int) ceilf(visibleTileClip.maxY() / (float) th);
+ visibleTileClip = IntRect(left, top, right - left, bottom - top);
+ enclosingScaledArea.intersect(visibleTileClip);
+ if (enclosingScaledArea.isEmpty())
+ return 0;
+ prerendered->screenArea = enclosingScaledArea;
+ FloatRect enclosingDocArea(enclosingScaledArea);
+ enclosingDocArea.scale(1 / m_scale);
+ prerendered->area = enclosingIntRect(enclosingDocArea);
+ if (prerendered->area.isEmpty())
+ return 0;
+ prerendered->bitmap.setConfig(SkBitmap::kARGB_8888_Config,
+ enclosingScaledArea.width(),
+ enclosingScaledArea.height());
+ prerendered->bitmap.allocPixels();
+ SkCanvas* bitmapCanvas = new SkCanvas(prerendered->bitmap);
+ bitmapCanvas->scale(m_scale, m_scale);
+ bitmapCanvas->translate(-enclosingDocArea.x(), -enclosingDocArea.y());
+ return bitmapCanvas;
}
void WebViewCore::notifyAnimationStarted()
@@ -902,93 +824,113 @@ void WebViewCore::notifyAnimationStarted()
}
-BaseLayerAndroid* WebViewCore::createBaseLayer(SkRegion* region)
+BaseLayerAndroid* WebViewCore::createBaseLayer(GraphicsLayerAndroid* root)
{
- BaseLayerAndroid* base = new BaseLayerAndroid();
- base->setContent(m_content);
+ // We set the background color
+ Color background = Color::white;
- m_skipContentDraw = true;
- bool layoutSucceeded = layoutIfNeededRecursive(m_mainFrame);
- m_skipContentDraw = false;
- // Layout only fails if called during a layout.
- LOG_ASSERT(layoutSucceeded, "Can never be called recursively");
+ bool bodyHasFixedBackgroundImage = false;
+ bool bodyHasCSSBackground = false;
-#if USE(ACCELERATED_COMPOSITING)
- // We set the background color
if (m_mainFrame && m_mainFrame->document()
&& m_mainFrame->document()->body()) {
+
Document* document = m_mainFrame->document();
RefPtr<RenderStyle> style = document->styleForElementIgnoringPendingStylesheets(document->body());
if (style->hasBackground()) {
- Color color = style->visitedDependentColor(CSSPropertyBackgroundColor);
- if (color.isValid() && color.alpha() > 0)
- base->setBackgroundColor(color);
+ background = style->visitedDependentColor(CSSPropertyBackgroundColor);
+ bodyHasCSSBackground = true;
+ }
+ WebCore::FrameView* view = m_mainFrame->view();
+ if (view) {
+ Color viewBackground = view->baseBackgroundColor();
+ background = bodyHasCSSBackground ? viewBackground.blend(background) : viewBackground;
}
+ if (style->hasFixedBackgroundImage()) {
+ Image* backgroundImage = FixedBackgroundImageLayerAndroid::GetCachedImage(style);
+ if (backgroundImage && backgroundImage->width() > 1 && backgroundImage->height() > 1)
+ bodyHasFixedBackgroundImage = true;
+ }
+ }
+
+ PicturePileLayerContent* content = new PicturePileLayerContent(m_content);
+ m_content.clearPrerenders();
+
+ BaseLayerAndroid* realBase = 0;
+ LayerAndroid* base = 0;
+
+ //If we have a fixed background image on the body element, the fixed image
+ // will be contained in the PictureSet (the content object), and the foreground
+ //of the body element will be moved to a layer.
+ //In that case, let's change the hierarchy to obtain:
+ //
+ //BaseLayerAndroid
+ // \- FixedBackgroundBaseLayerAndroid (fixed positioning)
+ // \- ForegroundBaseLayerAndroid
+ // \- root layer (webkit composited tree)
+
+ if (bodyHasFixedBackgroundImage) {
+ base = new ForegroundBaseLayerAndroid(0);
+ base->setSize(content->width(), content->height());
+
+ Document* document = m_mainFrame->document();
+ RefPtr<RenderStyle> style = document->styleForElementIgnoringPendingStylesheets(document->body());
+
+ FixedBackgroundImageLayerAndroid* baseBackground =
+ new FixedBackgroundImageLayerAndroid(style, content->width(), content->height());
+
+ realBase = new BaseLayerAndroid(0);
+ realBase->setSize(content->width(), content->height());
+ realBase->addChild(baseBackground);
+ realBase->addChild(base);
+ baseBackground->unref();
+ base->unref();
+ } else {
+ realBase = new BaseLayerAndroid(content);
+ base = realBase;
}
+ realBase->setBackgroundColor(background);
+
+ SkSafeUnref(content);
+
// We update the layers
- ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(m_mainFrame->page()->chrome()->client());
- GraphicsLayerAndroid* root = static_cast<GraphicsLayerAndroid*>(chromeC->layersSync());
if (root) {
LayerAndroid* copyLayer = new LayerAndroid(*root->contentLayer());
base->addChild(copyLayer);
copyLayer->unref();
root->contentLayer()->clearDirtyRegion();
}
-#endif
- return base;
+ return realBase;
}
-BaseLayerAndroid* WebViewCore::recordContent(SkRegion* region, SkIPoint* point)
+BaseLayerAndroid* WebViewCore::recordContent(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.");
- return 0;
- }
- float progress = (float) m_mainFrame->page()->progress()->estimatedProgress();
- m_progressDone = progress <= 0.0f || progress >= 1.0f;
- recordPictureSet(&m_content);
- if (!m_progressDone && m_content.isEmpty()) {
- DBG_SET_LOGD("empty (progress=%g)", progress);
- return 0;
- }
- region->set(m_addInval);
- m_addInval.setEmpty();
+ m_skipContentDraw = true;
+ layout();
+ ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(m_mainFrame->page()->chrome()->client());
+ GraphicsLayerAndroid* root = static_cast<GraphicsLayerAndroid*>(chromeC->layersSync());
+ m_skipContentDraw = false;
+ recordPicturePile();
+
+ BaseLayerAndroid* baseLayer = createBaseLayer(root);
+
+ baseLayer->markAsDirty(m_content.dirtyRegion());
+ m_content.dirtyRegion().setEmpty();
#if USE(ACCELERATED_COMPOSITING)
#else
- region->op(m_rebuildInval, SkRegion::kUnion_Op);
+ baseLayer->markAsDirty(m_rebuildInval);
#endif
- m_rebuildInval.setEmpty();
- point->fX = m_content.width();
- point->fY = m_content.height();
- DBG_SET_LOGD("region={%d,%d,r=%d,b=%d}", region->getBounds().fLeft,
- region->getBounds().fTop, region->getBounds().fRight,
- region->getBounds().fBottom);
- DBG_SET_LOG("end");
+ point->fX = m_content.size().width();
+ point->fY = m_content.size().height();
- return createBaseLayer(region);
-}
-
-void WebViewCore::splitContent(PictureSet* content)
-{
-#ifdef FAST_PICTURESET
-#else
- bool layoutSucceeded = layoutIfNeededRecursive(m_mainFrame);
- LOG_ASSERT(layoutSucceeded, "Can never be called recursively");
- content->split(&m_content);
- rebuildPictureSet(&m_content);
- content->set(m_content);
-#endif // FAST_PICTURESET
+ return baseLayer;
}
void WebViewCore::scrollTo(int x, int y, bool animate)
{
- LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
-
-// LOGD("WebViewCore::scrollTo(%d %d)\n", x, y);
+ ALOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
JNIEnv* env = JSC::Bindings::getJNIEnv();
AutoJObject javaObject = m_javaGlue->object(env);
@@ -1001,7 +943,7 @@ void WebViewCore::scrollTo(int x, int y, bool animate)
void WebViewCore::sendNotifyProgressFinished()
{
- LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
+ ALOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
JNIEnv* env = JSC::Bindings::getJNIEnv();
AutoJObject javaObject = m_javaGlue->object(env);
if (!javaObject.get())
@@ -1012,7 +954,7 @@ void WebViewCore::sendNotifyProgressFinished()
void WebViewCore::viewInvalidate(const WebCore::IntRect& rect)
{
- LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
+ ALOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
JNIEnv* env = JSC::Bindings::getJNIEnv();
AutoJObject javaObject = m_javaGlue->object(env);
if (!javaObject.get())
@@ -1033,26 +975,12 @@ void WebViewCore::contentDraw()
checkException(env);
}
-void WebViewCore::layersDraw()
-{
- JNIEnv* env = JSC::Bindings::getJNIEnv();
- AutoJObject javaObject = m_javaGlue->object(env);
- if (!javaObject.get())
- return;
- env->CallVoidMethod(javaObject.get(), m_javaGlue->m_layersDraw);
- checkException(env);
-}
-
void WebViewCore::contentInvalidate(const WebCore::IntRect &r)
{
- DBG_SET_LOGD("rect={%d,%d,w=%d,h=%d}", r.x(), r.y(), r.width(), r.height());
- SkIRect rect(r);
- if (!rect.intersect(0, 0, INT_MAX, INT_MAX))
- return;
- m_addInval.op(rect, SkRegion::kUnion_Op);
- DBG_SET_LOGD("m_addInval={%d,%d,r=%d,b=%d}",
- m_addInval.getBounds().fLeft, m_addInval.getBounds().fTop,
- m_addInval.getBounds().fRight, m_addInval.getBounds().fBottom);
+ IntPoint origin = m_mainFrame->view()->minimumScrollPosition();
+ IntRect dirty = r;
+ dirty.move(-origin.x(), -origin.y());
+ m_content.invalidate(dirty);
if (!m_skipContentDraw)
contentDraw();
}
@@ -1072,19 +1000,9 @@ void WebViewCore::offInvalidate(const WebCore::IntRect &r)
contentInvalidate(r);
}
-static int pin_pos(int x, int width, int targetWidth)
-{
- if (x + width > targetWidth)
- x = targetWidth - width;
- if (x < 0)
- x = 0;
- return x;
-}
-
void WebViewCore::didFirstLayout()
{
- DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
- LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
+ ALOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
JNIEnv* env = JSC::Bindings::getJNIEnv();
AutoJObject javaObject = m_javaGlue->object(env);
@@ -1094,7 +1012,7 @@ void WebViewCore::didFirstLayout()
const WebCore::KURL& url = m_mainFrame->document()->url();
if (url.isEmpty())
return;
- LOGV("::WebCore:: didFirstLayout %s", url.string().ascii().data());
+ ALOGV("::WebCore:: didFirstLayout %s", url.string().ascii().data());
WebCore::FrameLoadType loadType = m_mainFrame->loader()->loadType();
@@ -1108,17 +1026,11 @@ void WebViewCore::didFirstLayout()
// a newly-loaded page.
|| loadType == WebCore::FrameLoadTypeSame);
checkException(env);
-
- DBG_NAV_LOG("call updateFrameCache");
- m_check_domtree_version = false;
- updateFrameCache();
- m_history.setDidFirstLayout(true);
}
void WebViewCore::updateViewport()
{
- DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
- LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
+ ALOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
JNIEnv* env = JSC::Bindings::getJNIEnv();
AutoJObject javaObject = m_javaGlue->object(env);
@@ -1130,8 +1042,7 @@ void WebViewCore::updateViewport()
void WebViewCore::restoreScale(float scale, float textWrapScale)
{
- DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
- LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
+ ALOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
JNIEnv* env = JSC::Bindings::getJNIEnv();
AutoJObject javaObject = m_javaGlue->object(env);
@@ -1143,8 +1054,7 @@ void WebViewCore::restoreScale(float scale, float textWrapScale)
void WebViewCore::needTouchEvents(bool need)
{
- DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
- LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
+ ALOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
#if ENABLE(TOUCH_EVENTS)
JNIEnv* env = JSC::Bindings::getJNIEnv();
@@ -1162,26 +1072,9 @@ void WebViewCore::needTouchEvents(bool need)
#endif
}
-void WebViewCore::requestKeyboardWithSelection(const WebCore::Node* node,
- int selStart, int selEnd)
-{
- DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
- LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
-
- JNIEnv* env = JSC::Bindings::getJNIEnv();
- AutoJObject javaObject = m_javaGlue->object(env);
- if (!javaObject.get())
- return;
- env->CallVoidMethod(javaObject.get(),
- m_javaGlue->m_requestKeyboardWithSelection,
- reinterpret_cast<int>(node), selStart, selEnd, m_textGeneration);
- checkException(env);
-}
-
void WebViewCore::requestKeyboard(bool showKeyboard)
{
- DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
- LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
+ ALOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
JNIEnv* env = JSC::Bindings::getJNIEnv();
AutoJObject javaObject = m_javaGlue->object(env);
@@ -1193,42 +1086,15 @@ void WebViewCore::requestKeyboard(bool showKeyboard)
void WebViewCore::notifyProgressFinished()
{
- m_check_domtree_version = true;
sendNotifyProgressFinished();
}
-void WebViewCore::doMaxScroll(CacheBuilder::Direction dir)
-{
- int dx = 0, dy = 0;
-
- switch (dir) {
- case CacheBuilder::LEFT:
- dx = -m_maxXScroll;
- break;
- case CacheBuilder::UP:
- dy = -m_maxYScroll;
- break;
- case CacheBuilder::RIGHT:
- dx = m_maxXScroll;
- break;
- case CacheBuilder::DOWN:
- dy = m_maxYScroll;
- break;
- case CacheBuilder::UNINITIALIZED:
- default:
- LOG_ASSERT(0, "unexpected focus selector");
- }
- WebCore::FrameView* view = m_mainFrame->view();
- this->scrollTo(view->scrollX() + dx, view->scrollY() + dy, true);
-}
-
-void WebViewCore::setScrollOffset(int moveGeneration, bool sendScrollEvent, int dx, int dy)
+void WebViewCore::setScrollOffset(bool sendScrollEvent, int dx, int dy)
{
- DBG_NAV_LOGD("{%d,%d} m_scrollOffset=(%d,%d), sendScrollEvent=%d", dx, dy,
- m_scrollOffsetX, m_scrollOffsetY, sendScrollEvent);
if (m_scrollOffsetX != dx || m_scrollOffsetY != dy) {
m_scrollOffsetX = dx;
m_scrollOffsetY = dy;
+ m_scrollSetTime = currentTimeMS();
// The visible rect is located within our coordinate space so it
// contains the actual scroll position. Setting the location makes hit
// testing work correctly.
@@ -1259,19 +1125,10 @@ void WebViewCore::setScrollOffset(int moveGeneration, bool sendScrollEvent, int
// update the currently visible screen
sendPluginVisibleScreen();
}
- gCursorBoundsMutex.lock();
- bool hasCursorBounds = m_hasCursorBounds;
- Frame* frame = (Frame*) m_cursorFrame;
- IntPoint location = m_cursorLocation;
- gCursorBoundsMutex.unlock();
- if (!hasCursorBounds)
- return;
- moveMouseIfLatest(moveGeneration, frame, location.x(), location.y());
}
void WebViewCore::setGlobalBounds(int x, int y, int h, int v)
{
- DBG_NAV_LOGD("{%d,%d}", x, y);
m_mainFrame->view()->platformWidget()->setWindowBounds(x, y, h, v);
}
@@ -1290,9 +1147,6 @@ void WebViewCore::setSizeScreenWidthAndScale(int width, int height,
int osw = m_screenWidth;
int osh = m_screenHeight;
int otw = m_textWrapWidth;
- float oldScale = m_scale;
- DBG_NAV_LOGD("old:(w=%d,h=%d,sw=%d,scale=%g) new:(w=%d,h=%d,sw=%d,scale=%g)",
- ow, oh, osw, m_scale, width, height, screenWidth, scale);
m_screenWidth = screenWidth;
m_screenHeight = screenHeight;
m_textWrapWidth = textWrapWidth;
@@ -1311,11 +1165,8 @@ void WebViewCore::setSizeScreenWidthAndScale(int width, int height,
if (ow != width || (!ignoreHeight && oh != height) || reflow) {
WebCore::RenderObject *r = m_mainFrame->contentRenderer();
- DBG_NAV_LOGD("renderer=%p view=(w=%d,h=%d)", r,
- screenWidth, screenHeight);
if (r) {
WebCore::IntPoint anchorPoint = WebCore::IntPoint(anchorX, anchorY);
- DBG_NAV_LOGD("anchorX=%d anchorY=%d", anchorX, anchorY);
RefPtr<WebCore::Node> node;
WebCore::IntRect bounds;
WebCore::IntPoint offset;
@@ -1327,11 +1178,19 @@ void WebViewCore::setSizeScreenWidthAndScale(int width, int height,
m_mainFrame->eventHandler()->hitTestResultAtPoint(
anchorPoint, false);
node = hitTestResult.innerNode();
+ if (node && !node->isTextNode()) {
+ // If the hitTestResultAtPoint didn't find a suitable node
+ // for anchoring, try again with some slop.
+ static const int HIT_SLOP = 30;
+ anchorPoint.move(HIT_SLOP, HIT_SLOP);
+ hitTestResult =
+ m_mainFrame->eventHandler()->hitTestResultAtPoint(
+ anchorPoint, false);
+ node = hitTestResult.innerNode();
+ }
}
if (node) {
bounds = node->getRect();
- DBG_NAV_LOGD("ob:(x=%d,y=%d,w=%d,h=%d)",
- bounds.x(), bounds.y(), bounds.width(), bounds.height());
// sites like nytimes.com insert a non-standard tag <nyt_text>
// in the html. If it is the HitTestResult, it may have zero
// width and height. In this case, use its parent node.
@@ -1339,8 +1198,6 @@ void WebViewCore::setSizeScreenWidthAndScale(int width, int height,
node = node->parentOrHostNode();
if (node) {
bounds = node->getRect();
- DBG_NAV_LOGD("found a zero width node and use its parent, whose ob:(x=%d,y=%d,w=%d,h=%d)",
- bounds.x(), bounds.y(), bounds.width(), bounds.height());
}
}
}
@@ -1361,9 +1218,6 @@ void WebViewCore::setSizeScreenWidthAndScale(int width, int height,
// scroll to restore current screen center
if (node && node->inDocument()) {
const WebCore::IntRect& newBounds = node->getRect();
- DBG_NAV_LOGD("nb:(x=%d,y=%d,w=%d,"
- "h=%d)", newBounds.x(), newBounds.y(),
- newBounds.width(), newBounds.height());
if ((osw && osh && bounds.width() && bounds.height())
&& (bounds != newBounds)) {
WebCore::FrameView* view = m_mainFrame->view();
@@ -1440,13 +1294,6 @@ void WebViewCore::dumpRenderTree(bool useFile)
#endif
}
-void WebViewCore::dumpNavTree()
-{
-#if DUMP_NAV_CACHE
- cacheBuilder().mDebug.print();
-#endif
-}
-
HTMLElement* WebViewCore::retrieveElement(int x, int y,
const QualifiedName& tagName)
{
@@ -1455,12 +1302,12 @@ HTMLElement* WebViewCore::retrieveElement(int x, int y,
DontHitTestScrollbars, HitTestRequest::Active | HitTestRequest::ReadOnly,
IntSize(1, 1));
if (!hitTestResult.innerNode() || !hitTestResult.innerNode()->inDocument()) {
- LOGE("Should not happen: no in document Node found");
+ ALOGE("Should not happen: no in document Node found");
return 0;
}
const ListHashSet<RefPtr<Node> >& list = hitTestResult.rectBasedTestResult();
if (list.isEmpty()) {
- LOGE("Should not happen: no rect-based-test nodes found");
+ ALOGE("Should not happen: no rect-based-test nodes found");
return 0;
}
Node* node = hitTestResult.innerNode();
@@ -1469,9 +1316,6 @@ HTMLElement* WebViewCore::retrieveElement(int x, int y,
|| !element->hasTagName(tagName))) {
element = element->parentNode();
}
- DBG_NAV_LOGD("node=%p element=%p x=%d y=%d nodeName=%s tagName=%s", node,
- element, x, y, node->nodeName().utf8().data(),
- element ? ((Element*) element)->tagName().utf8().data() : "<none>");
return static_cast<WebCore::HTMLElement*>(element);
}
@@ -1489,8 +1333,10 @@ HTMLImageElement* WebViewCore::retrieveImageElement(int x, int y)
WTF::String WebViewCore::retrieveHref(int x, int y)
{
- WebCore::HTMLAnchorElement* anchor = retrieveAnchorElement(x, y);
- return anchor ? anchor->href() : WTF::String();
+ // TODO: This is expensive, cache
+ HitTestResult result = m_mainFrame->eventHandler()->hitTestResultAtPoint(IntPoint(x, y),
+ false, false, DontHitTestScrollbars, HitTestRequest::Active | HitTestRequest::ReadOnly, IntSize(1, 1));
+ return result.absoluteLinkURL();
}
WTF::String WebViewCore::retrieveAnchorText(int x, int y)
@@ -1501,14 +1347,16 @@ WTF::String WebViewCore::retrieveAnchorText(int x, int y)
WTF::String WebViewCore::retrieveImageSource(int x, int y)
{
- HTMLImageElement* image = retrieveImageElement(x, y);
- return image ? image->src().string() : WTF::String();
+ // TODO: This is expensive, cache
+ HitTestResult result = m_mainFrame->eventHandler()->hitTestResultAtPoint(IntPoint(x, y),
+ false, false, DontHitTestScrollbars, HitTestRequest::Active | HitTestRequest::ReadOnly, IntSize(1, 1));
+ return result.absoluteImageURL();
}
WTF::String WebViewCore::requestLabel(WebCore::Frame* frame,
WebCore::Node* node)
{
- if (node && CacheBuilder::validNode(m_mainFrame, frame, node)) {
+ if (node && validNode(m_mainFrame, frame, node)) {
RefPtr<WebCore::NodeList> list = node->document()->getElementsByTagName("label");
unsigned length = list->length();
for (unsigned i = 0; i < length; i++) {
@@ -1532,17 +1380,18 @@ WTF::String WebViewCore::requestLabel(WebCore::Frame* frame,
static bool isContentEditable(const WebCore::Node* node)
{
- if (!node) return false;
- return node->document()->frame()->selection()->isContentEditable();
+ if (!node)
+ return false;
+ return node->isContentEditable();
}
// Returns true if the node is a textfield, textarea, or contentEditable
static bool isTextInput(const WebCore::Node* node)
{
- if (isContentEditable(node))
- return true;
if (!node)
return false;
+ if (isContentEditable(node))
+ return true;
WebCore::RenderObject* renderer = node->renderer();
return renderer && (renderer->isTextField() || renderer->isTextArea());
}
@@ -1560,107 +1409,9 @@ void WebViewCore::revealSelection()
focusedFrame->selection()->revealSelection(ScrollAlignment::alignToEdgeIfNeeded);
}
-void WebViewCore::updateCacheOnNodeChange()
-{
- gCursorBoundsMutex.lock();
- bool hasCursorBounds = m_hasCursorBounds;
- Frame* frame = (Frame*) m_cursorFrame;
- Node* node = (Node*) m_cursorNode;
- IntRect bounds = m_cursorHitBounds;
- gCursorBoundsMutex.unlock();
- if (!hasCursorBounds || !node)
- return;
- if (CacheBuilder::validNode(m_mainFrame, frame, node)) {
- RenderObject* renderer = node->renderer();
- if (renderer && renderer->style()->visibility() != HIDDEN) {
- IntRect absBox = renderer->absoluteBoundingBoxRect();
- int globalX, globalY;
- CacheBuilder::GetGlobalOffset(frame, &globalX, &globalY);
- absBox.move(globalX, globalY);
- if (absBox == bounds)
- return;
- DBG_NAV_LOGD("absBox=(%d,%d,%d,%d) bounds=(%d,%d,%d,%d)",
- absBox.x(), absBox.y(), absBox.width(), absBox.height(),
- bounds.x(), bounds.y(), bounds.width(), bounds.height());
- }
- }
- DBG_NAV_LOGD("updateFrameCache node=%p", node);
- updateFrameCache();
-}
-
-void WebViewCore::updateFrameCache()
-{
- if (!m_frameCacheOutOfDate) {
- DBG_NAV_LOG("!m_frameCacheOutOfDate");
- return;
- }
-
- // If there is a pending style recalculation, do not update the frame cache.
- // Until the recalculation is complete, there may be internal objects that
- // are in an inconsistent state (such as font pointers).
- // In any event, there's not much point to updating the cache while a style
- // recalculation is pending, since it will simply have to be updated again
- // once the recalculation is complete.
- // TODO: Do we need to reschedule an update for after the style is recalculated?
- if (m_mainFrame && m_mainFrame->document() && m_mainFrame->document()->isPendingStyleRecalc()) {
- LOGW("updateFrameCache: pending style recalc, ignoring.");
- return;
- }
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::WebViewCoreBuildNavTimeCounter);
-#endif
- m_frameCacheOutOfDate = false;
- m_temp = new CachedRoot();
- m_temp->init(m_mainFrame, &m_history);
-#if USE(ACCELERATED_COMPOSITING)
- GraphicsLayerAndroid* graphicsLayer = graphicsRootLayer();
- if (graphicsLayer)
- m_temp->setRootLayer(graphicsLayer->contentLayer());
-#endif
- CacheBuilder& builder = cacheBuilder();
- WebCore::Settings* settings = m_mainFrame->page()->settings();
- builder.allowAllTextDetection();
-#ifdef ANDROID_META_SUPPORT
- if (settings) {
- if (!settings->formatDetectionAddress())
- builder.disallowAddressDetection();
- if (!settings->formatDetectionEmail())
- builder.disallowEmailDetection();
- if (!settings->formatDetectionTelephone())
- builder.disallowPhoneDetection();
- }
-#endif
- builder.buildCache(m_temp);
- m_tempPict = new SkPicture();
- recordPicture(m_tempPict);
- m_temp->setPicture(m_tempPict);
- m_temp->setTextGeneration(m_textGeneration);
- WebCoreViewBridge* window = m_mainFrame->view()->platformWidget();
- m_temp->setVisibleRect(WebCore::IntRect(m_scrollOffsetX,
- m_scrollOffsetY, window->width(), window->height()));
- gFrameCacheMutex.lock();
- delete m_frameCacheKit;
- delete m_navPictureKit;
- m_frameCacheKit = m_temp;
- m_navPictureKit = m_tempPict;
- m_updatedFrameCache = true;
-#if DEBUG_NAV_UI
- const CachedNode* cachedFocusNode = m_frameCacheKit->currentFocus();
- DBG_NAV_LOGD("cachedFocusNode=%d (nodePointer=%p)",
- cachedFocusNode ? cachedFocusNode->index() : 0,
- cachedFocusNode ? cachedFocusNode->nodePointer() : 0);
-#endif
- gFrameCacheMutex.unlock();
-}
-
-void WebViewCore::updateFrameCacheIfLoading()
-{
- if (!m_check_domtree_version)
- updateFrameCache();
-}
-
struct TouchNodeData {
- Node* mNode;
+ Node* mUrlNode;
+ Node* mInnerNode;
IntRect mBounds;
};
@@ -1668,6 +1419,8 @@ struct TouchNodeData {
static IntRect getAbsoluteBoundingBox(Node* node) {
IntRect rect;
RenderObject* render = node->renderer();
+ if (!render)
+ return rect;
if (render->isRenderInline())
rect = toRenderInline(render)->linesVisualOverflowBoundingBox();
else if (render->isBox())
@@ -1675,30 +1428,395 @@ static IntRect getAbsoluteBoundingBox(Node* node) {
else if (render->isText())
rect = toRenderText(render)->linesBoundingBox();
else
- LOGE("getAbsoluteBoundingBox failed for node %p, name %s", node, render->renderName());
- FloatPoint absPos = render->localToAbsolute();
+ ALOGE("getAbsoluteBoundingBox failed for node %p, name %s", node, render->renderName());
+ FloatPoint absPos = render->localToAbsolute(FloatPoint(), false, true);
rect.move(absPos.x(), absPos.y());
return rect;
}
+WebCore::Frame* WebViewCore::focusedFrame() const
+{
+ return m_mainFrame->page()->focusController()->focusedOrMainFrame();
+}
+
+VisiblePosition WebViewCore::visiblePositionForContentPoint(int x, int y)
+{
+ return visiblePositionForContentPoint(IntPoint(x, y));
+}
+
+VisiblePosition WebViewCore::visiblePositionForContentPoint(const IntPoint& point)
+{
+ // Hit test of this kind required for this to work inside input fields
+ HitTestRequest request(HitTestRequest::Active
+ | HitTestRequest::MouseMove
+ | HitTestRequest::ReadOnly
+ | HitTestRequest::IgnoreClipping);
+ HitTestResult result(point);
+ focusedFrame()->document()->renderView()->layer()->hitTest(request, result);
+
+ // Matching the logic in MouseEventWithHitTestResults::targetNode()
+ Node* node = result.innerNode();
+ if (!node)
+ return VisiblePosition();
+ Element* element = node->parentElement();
+ if (!node->inDocument() && element && element->inDocument())
+ node = element;
+
+ return node->renderer()->positionForPoint(result.localPoint());
+}
+
+bool WebViewCore::selectWordAt(int x, int y)
+{
+ HitTestResult hoverResult;
+ moveMouse(x, y, &hoverResult);
+ if (hoverResult.innerNode()) {
+ Node* node = hoverResult.innerNode();
+ Frame* frame = node->document()->frame();
+ Page* page = m_mainFrame->document()->page();
+ page->focusController()->setFocusedFrame(frame);
+ }
+
+ IntPoint point = convertGlobalContentToFrameContent(IntPoint(x, y));
+
+ // Hit test of this kind required for this to work inside input fields
+ HitTestRequest request(HitTestRequest::Active);
+ HitTestResult result(point);
+
+ focusedFrame()->document()->renderView()->layer()->hitTest(request, result);
+
+ // Matching the logic in MouseEventWithHitTestResults::targetNode()
+ Node* node = result.innerNode();
+ if (!node)
+ return false;
+ Element* element = node->parentElement();
+ if (!node->inDocument() && element && element->inDocument())
+ node = element;
+
+ SelectionController* sc = focusedFrame()->selection();
+ bool wordSelected = false;
+ if (!sc->contains(point) && (node->isContentEditable() || node->isTextNode()) && !result.isLiveLink()
+ && node->dispatchEvent(Event::create(eventNames().selectstartEvent, true, true))) {
+ VisiblePosition pos(node->renderer()->positionForPoint(result.localPoint()));
+ wordSelected = selectWordAroundPosition(node->document()->frame(), pos);
+ }
+ return wordSelected;
+}
+
+bool WebViewCore::selectWordAroundPosition(Frame* frame, VisiblePosition pos)
+{
+ VisibleSelection selection(pos);
+ selection.expandUsingGranularity(WordGranularity);
+ SelectionController* selectionController = frame->selection();
+
+ bool wordSelected = false;
+ if (selectionController->shouldChangeSelection(selection)) {
+ bool allWhitespaces = true;
+ RefPtr<Range> firstRange = selection.firstRange();
+ String text = firstRange.get() ? firstRange->text() : "";
+ for (size_t i = 0; i < text.length(); ++i) {
+ if (!isSpaceOrNewline(text[i])) {
+ allWhitespaces = false;
+ break;
+ }
+ }
+ if (allWhitespaces) {
+ VisibleSelection emptySelection(pos);
+ selectionController->setSelection(emptySelection);
+ } else {
+ selectionController->setSelection(selection);
+ wordSelected = true;
+ }
+ }
+ return wordSelected;
+}
+
+int WebViewCore::platformLayerIdFromNode(Node* node, LayerAndroid** outLayer)
+{
+ if (!node || !node->renderer())
+ return -1;
+ RenderLayer* renderLayer = node->renderer()->enclosingLayer();
+ while (renderLayer && !renderLayer->isComposited())
+ renderLayer = renderLayer->parent();
+ if (!renderLayer || !renderLayer->isComposited())
+ return -1;
+ GraphicsLayer* graphicsLayer = renderLayer->backing()->graphicsLayer();
+ if (!graphicsLayer)
+ return -1;
+ GraphicsLayerAndroid* agl = static_cast<GraphicsLayerAndroid*>(graphicsLayer);
+ LayerAndroid* layer = agl->foregroundLayer();
+ if (!layer)
+ layer = agl->contentLayer();
+ if (!layer)
+ return -1;
+ if (outLayer)
+ *outLayer = layer;
+ return layer->uniqueId();
+}
+
+void WebViewCore::layerToAbsoluteOffset(const LayerAndroid* layer, IntPoint& offset)
+{
+ while (layer) {
+ const SkPoint& pos = layer->getPosition();
+ offset.move(pos.fX, pos.fY);
+ const IntPoint& scroll = layer->getScrollOffset();
+ offset.move(-scroll.x(), -scroll.y());
+ layer = static_cast<LayerAndroid*>(layer->getParent());
+ }
+}
+
+void WebViewCore::setSelectionCaretInfo(SelectText* selectTextContainer,
+ const WebCore::Position& pos, const IntPoint& frameOffset,
+ SelectText::HandleId handleId, int caretRectOffset, EAffinity affinity)
+{
+ Node* node = pos.anchorNode();
+ LayerAndroid* layer = 0;
+ int layerId = platformLayerIdFromNode(node, &layer);
+ selectTextContainer->setCaretLayerId(handleId, layerId);
+ IntPoint offset = frameOffset;
+ layerToAbsoluteOffset(layer, offset);
+ RenderObject* r = node->renderer();
+ RenderText* renderText = toRenderText(r);
+ int caretOffset;
+ InlineBox* inlineBox;
+ pos.getInlineBoxAndOffset(affinity, inlineBox, caretOffset);
+ IntRect caretRect = renderText->localCaretRect(inlineBox, caretOffset);
+ FloatPoint absoluteOffset = renderText->localToAbsolute(caretRect.location());
+ caretRect.setX(absoluteOffset.x() - offset.x() + caretRectOffset);
+ caretRect.setY(absoluteOffset.y() - offset.y());
+ selectTextContainer->setCaretRect(handleId, caretRect);
+ selectTextContainer->setTextRect(handleId,
+ positionToTextRect(pos, affinity, offset));
+}
+
+bool WebViewCore::isLtr(const Position& position)
+{
+ InlineBox* inlineBox = 0;
+ int caretOffset = 0;
+ position.getInlineBoxAndOffset(DOWNSTREAM, inlineBox, caretOffset);
+ bool isLtr;
+ if (inlineBox)
+ isLtr = inlineBox->isLeftToRightDirection();
+ else
+ isLtr = position.primaryDirection() == LTR;
+ return isLtr;
+}
+
+SelectText* WebViewCore::createSelectText(const VisibleSelection& selection)
+{
+ bool isCaret = selection.isCaret();
+ if (selection.isNone() || (!selection.isContentEditable() && isCaret)
+ || !selection.start().anchorNode()
+ || !selection.start().anchorNode()->renderer()
+ || !selection.end().anchorNode()
+ || !selection.end().anchorNode()->renderer())
+ return 0;
+
+ RefPtr<Range> range = selection.firstRange();
+ Node* startContainer = range->startContainer();
+ Node* endContainer = range->endContainer();
+
+ if (!startContainer || !endContainer)
+ return 0;
+ if (!isCaret && startContainer == endContainer
+ && range->startOffset() == range->endOffset())
+ return 0;
+
+ IntPoint frameOffset = convertGlobalContentToFrameContent(IntPoint());
+ SelectText* selectTextContainer = new SelectText();
+ if (isCaret) {
+ setSelectionCaretInfo(selectTextContainer, selection.start(), frameOffset,
+ SelectText::LeftHandle, 0, selection.affinity());
+ setSelectionCaretInfo(selectTextContainer, selection.start(), frameOffset,
+ SelectText::RightHandle, 0, selection.affinity());
+ } else {
+ bool ltr = isLtr(selection.start());
+ Position left = ltr ? selection.start() : selection.end();
+ Position right = ltr ? selection.end() : selection.start();
+ int leftOffset = isLtr(left) ? 0 : -1;
+ int rightOffset = isLtr(right) ? 0 : -1;
+ setSelectionCaretInfo(selectTextContainer, left, frameOffset,
+ SelectText::LeftHandle, leftOffset, selection.affinity());
+ setSelectionCaretInfo(selectTextContainer, right, frameOffset,
+ SelectText::RightHandle, rightOffset, selection.affinity());
+
+ Node* stopNode = range->pastLastNode();
+ for (Node* node = range->firstNode(); node != stopNode; node = node->traverseNextNode()) {
+ RenderObject* r = node->renderer();
+ if (!r || !r->isText() || r->style()->visibility() != VISIBLE)
+ continue;
+ RenderText* renderText = toRenderText(r);
+ int startOffset = node == startContainer ? range->startOffset() : 0;
+ int endOffset = node == endContainer ? range->endOffset() : numeric_limits<int>::max();
+ LayerAndroid* layer = 0;
+ int layerId = platformLayerIdFromNode(node, &layer);
+ Vector<IntRect> rects;
+ renderText->absoluteRectsForRange(rects, startOffset, endOffset, true);
+ selectTextContainer->addHighlightRegion(layer, rects, frameOffset);
+ }
+ }
+ selectTextContainer->setText(range->text());
+ return selectTextContainer;
+}
+
+IntRect WebViewCore::positionToTextRect(const Position& position,
+ EAffinity affinity, const WebCore::IntPoint& offset)
+{
+ IntRect textRect;
+ InlineBox* inlineBox;
+ int offsetIndex;
+ position.getInlineBoxAndOffset(affinity, inlineBox, offsetIndex);
+ if (inlineBox && inlineBox->isInlineTextBox()) {
+ InlineTextBox* box = static_cast<InlineTextBox*>(inlineBox);
+ RootInlineBox* root = box->root();
+ RenderText* renderText = box->textRenderer();
+ int left = root->logicalLeft();
+ int width = root->logicalWidth();
+ int top = root->selectionTop();
+ int height = root->selectionHeight();
+
+ if (!renderText->style()->isHorizontalWritingMode()) {
+ swap(left, top);
+ swap(width, height);
+ }
+ FloatPoint origin(left, top);
+ FloatPoint absoluteOrigin = renderText->localToAbsolute(origin);
+
+ textRect.setX(absoluteOrigin.x() - offset.x());
+ textRect.setWidth(width);
+ textRect.setY(absoluteOrigin.y() - offset.y());
+ textRect.setHeight(height);
+ }
+ return textRect;
+}
+
+IntPoint WebViewCore::convertGlobalContentToFrameContent(const IntPoint& point, WebCore::Frame* frame)
+{
+ if (!frame) frame = focusedFrame();
+ IntPoint frameOffset(-m_scrollOffsetX, -m_scrollOffsetY);
+ frameOffset = frame->view()->windowToContents(frameOffset);
+ return IntPoint(point.x() + frameOffset.x(), point.y() + frameOffset.y());
+}
+
+Position WebViewCore::trimSelectionPosition(const Position &start, const Position& stop)
+{
+ int direction = comparePositions(start, stop);
+ if (direction == 0)
+ return start;
+ bool forward = direction < 0;
+ EAffinity affinity = forward ? DOWNSTREAM : UPSTREAM;
+ bool move;
+ Position pos = start;
+ bool movedTooFar = false;
+ do {
+ move = true;
+ Node* node = pos.anchorNode();
+ if (node && node->isTextNode() && node->renderer()) {
+ RenderText *textRenderer = toRenderText(node->renderer());
+ move = !textRenderer->textLength();
+ }
+ if (move) {
+ Position nextPos = forward ? pos.next() : pos.previous();
+ movedTooFar = nextPos.isNull() || pos == nextPos
+ || ((comparePositions(nextPos, stop) < 0) != forward);
+ pos = nextPos;
+ }
+ } while (move && !movedTooFar);
+ if (movedTooFar)
+ pos = stop;
+ return pos;
+}
+
+void WebViewCore::selectText(int startX, int startY, int endX, int endY)
+{
+ SelectionController* sc = focusedFrame()->selection();
+ IntPoint startPoint = convertGlobalContentToFrameContent(IntPoint(startX, startY));
+ VisiblePosition startPosition(visiblePositionForContentPoint(startPoint));
+ IntPoint endPoint = convertGlobalContentToFrameContent(IntPoint(endX, endY));
+ VisiblePosition endPosition(visiblePositionForContentPoint(endPoint));
+
+ if (startPosition.isNull() || endPosition.isNull())
+ return;
+
+ // Ensure startPosition is before endPosition
+ if (comparePositions(startPosition, endPosition) > 0)
+ swap(startPosition, endPosition);
+
+ if (sc->isContentEditable()) {
+ startPosition = sc->selection().visibleStart().honorEditableBoundaryAtOrAfter(startPosition);
+ endPosition = sc->selection().visibleEnd().honorEditableBoundaryAtOrBefore(endPosition);
+ if (startPosition.isNull() || endPosition.isNull()) {
+ return;
+ }
+ }
+
+ // Ensure startPosition is not at end of block
+ if (startPosition != endPosition && isEndOfBlock(startPosition)) {
+ VisiblePosition nextStartPosition(startPosition.next());
+ if (!nextStartPosition.isNull())
+ startPosition = nextStartPosition;
+ }
+ // Ensure endPosition is not at start of block
+ if (startPosition != endPosition && isStartOfBlock(endPosition)) {
+ VisiblePosition prevEndPosition(endPosition.previous());
+ if (!prevEndPosition.isNull())
+ endPosition = prevEndPosition;
+ }
+
+ Position start = startPosition.deepEquivalent();
+ Position end = endPosition.deepEquivalent();
+ start = trimSelectionPosition(start, end);
+ end = trimSelectionPosition(end, start);
+ VisibleSelection selection(start, end);
+ // Only allow changes between caret positions or to text selection.
+ bool selectChangeAllowed = (!selection.isCaret() || sc->isCaret());
+ if (selectChangeAllowed && sc->shouldChangeSelection(selection))
+ sc->setSelection(selection);
+}
+
+bool WebViewCore::nodeIsClickableOrFocusable(Node* node)
+{
+ if (!node)
+ return false;
+ if (node->disabled())
+ return false;
+ if (!node->inDocument())
+ return false;
+ if (!node->renderer() || node->renderer()->style()->visibility() != VISIBLE)
+ return false;
+ return node->supportsFocus()
+ || node->hasEventListeners(eventNames().clickEvent)
+ || node->hasEventListeners(eventNames().mousedownEvent)
+ || node->hasEventListeners(eventNames().mouseupEvent)
+ || node->hasEventListeners(eventNames().mouseoverEvent);
+}
+
// get the highlight rectangles for the touch point (x, y) with the slop
-Vector<IntRect> WebViewCore::getTouchHighlightRects(int x, int y, int slop)
+AndroidHitTestResult WebViewCore::hitTestAtPoint(int x, int y, int slop, bool doMoveMouse)
{
- Vector<IntRect> rects;
- m_mousePos = IntPoint(x - m_scrollOffsetX, y - m_scrollOffsetY);
+ if (doMoveMouse)
+ moveMouse(x, y, 0, true);
HitTestResult hitTestResult = m_mainFrame->eventHandler()->hitTestResultAtPoint(IntPoint(x, y),
false, false, DontHitTestScrollbars, HitTestRequest::Active | HitTestRequest::ReadOnly, IntSize(slop, slop));
+ AndroidHitTestResult androidHitResult(this, hitTestResult);
if (!hitTestResult.innerNode() || !hitTestResult.innerNode()->inDocument()) {
- LOGE("Should not happen: no in document Node found");
- return rects;
+ ALOGE("Should not happen: no in document Node found");
+ return androidHitResult;
}
const ListHashSet<RefPtr<Node> >& list = hitTestResult.rectBasedTestResult();
if (list.isEmpty()) {
- LOGE("Should not happen: no rect-based-test nodes found");
- return rects;
+ ALOGE("Should not happen: no rect-based-test nodes found");
+ return androidHitResult;
}
Frame* frame = hitTestResult.innerNode()->document()->frame();
Vector<TouchNodeData> nodeDataList;
+ 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?
@@ -1708,14 +1826,12 @@ Vector<IntRect> WebViewCore::getTouchHighlightRects(int x, int y, int slop)
// 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)) {
+ if (nodeIsClickableOrFocusable(eventNode)) {
found = true;
break;
}
@@ -1747,7 +1863,7 @@ Vector<IntRect> WebViewCore::getTouchHighlightRects(int x, int y, int slop)
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) {
+ if (eventNode == n->mUrlNode) {
found = false;
break;
}
@@ -1788,16 +1904,19 @@ Vector<IntRect> WebViewCore::getTouchHighlightRects(int x, int y, int slop)
}
if (!found) {
TouchNodeData newNode;
- newNode.mNode = eventNode;
+ newNode.mUrlNode = eventNode;
newNode.mBounds = rect;
+ newNode.mInnerNode = innerNode;
nodeDataList.append(newNode);
}
}
- if (!nodeDataList.size())
- return rects;
+ if (!nodeDataList.size()) {
+ androidHitResult.searchContentDetectors();
+ 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;
@@ -1806,101 +1925,47 @@ Vector<IntRect> WebViewCore::getTouchHighlightRects(int x, int y, int slop)
IntRect rect = n->mBounds;
rect.intersect(testRect);
int a = rect.width() * rect.height();
- if (a > area) {
+ if (a > area || !final.mUrlNode) {
final = *n;
area = a;
}
}
// now get the node's highlight rectangles in the page coordinate system
- if (final.mNode) {
- IntPoint frameAdjust;
- if (frame != m_mainFrame) {
- frameAdjust = frame->view()->contentsToWindow(IntPoint());
- frameAdjust.move(m_scrollOffsetX, m_scrollOffsetY);
+ if (final.mUrlNode) {
+ // Update innerNode and innerNonSharedNode
+ androidHitResult.hitTestResult().setInnerNode(final.mInnerNode);
+ androidHitResult.hitTestResult().setInnerNonSharedNode(final.mInnerNode);
+ if (final.mUrlNode->isElementNode()) {
+ // We found a URL element. Update the hitTestResult
+ androidHitResult.setURLElement(static_cast<Element*>(final.mUrlNode));
+ } else {
+ androidHitResult.setURLElement(0);
}
- if (final.mNode->isLink()) {
- // 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();
- IntPoint offset = roundedIntPoint(render->localToAbsolute());
- render->absoluteRects(rects, offset.x() + frameAdjust.x(), offset.y() + frameAdjust.y());
- bool inside = false;
- int distance = INT_MAX;
- int newx = x, newy = y;
- int i = rects.size();
- while (i--) {
- if (rects[i].isEmpty()) {
- rects.remove(i);
- continue;
- }
- // check whether the point (x, y) is inside one of the rectangles.
- if (inside)
- continue;
- if (rects[i].contains(x, y)) {
- inside = true;
- continue;
- }
- if (x >= rects[i].x() && x < rects[i].maxX()) {
- if (y < rects[i].y()) {
- if (rects[i].y() - y < distance) {
- newx = x;
- newy = rects[i].y();
- distance = rects[i].y() - y;
- }
- } else if (y >= rects[i].maxY()) {
- if (y - rects[i].maxY() + 1 < distance) {
- newx = x;
- newy = rects[i].maxY() - 1;
- distance = y - rects[i].maxY() + 1;
- }
- }
- } else if (y >= rects[i].y() && y < rects[i].maxY()) {
- if (x < rects[i].x()) {
- if (rects[i].x() - x < distance) {
- newx = rects[i].x();
- newy = y;
- distance = rects[i].x() - x;
- }
- } else if (x >= rects[i].maxX()) {
- if (x - rects[i].maxX() + 1 < distance) {
- newx = rects[i].maxX() - 1;
- newy = y;
- distance = x - rects[i].maxX() + 1;
- }
- }
+ Vector<IntRect>& highlightRects = androidHitResult.highlightRects();
+ if (doMoveMouse && highlightRects.size() > 0) {
+ // adjust m_mousePos if it is not inside the returned highlight
+ // rectangles
+ IntRect foundIntersection;
+ IntRect inputRect = IntRect(x - slop, y - slop,
+ slop * 2 + 1, slop * 2 + 1);
+ for (size_t i = 0; i < highlightRects.size(); i++) {
+ IntRect& hr = highlightRects[i];
+ IntRect test = inputRect;
+ test.intersect(hr);
+ if (!test.isEmpty()) {
+ foundIntersection = test;
+ break;
}
}
- if (!rects.isEmpty()) {
- if (!inside) {
- // 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);
- 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;
+ if (!foundIntersection.isEmpty() && !foundIntersection.contains(x, y)) {
+ IntPoint pt = foundIntersection.center();
+ moveMouse(pt.x(), pt.y(), 0, true);
}
}
- 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);
- }
+ } else {
+ androidHitResult.searchContentDetectors();
}
- return rects;
+ return androidHitResult;
}
///////////////////////////////////////////////////////////////////////////////
@@ -2071,70 +2136,46 @@ static PluginView* nodeIsPlugin(Node* node) {
return 0;
}
-Node* WebViewCore::cursorNodeIsPlugin() {
- gCursorBoundsMutex.lock();
- bool hasCursorBounds = m_hasCursorBounds;
- Frame* frame = (Frame*) m_cursorFrame;
- Node* node = (Node*) m_cursorNode;
- gCursorBoundsMutex.unlock();
- if (hasCursorBounds && CacheBuilder::validNode(m_mainFrame, frame, node)
- && nodeIsPlugin(node)) {
- return node;
- }
- return 0;
-}
-
///////////////////////////////////////////////////////////////////////////////
-void WebViewCore::moveMouseIfLatest(int moveGeneration,
- WebCore::Frame* frame, int x, int y)
-{
- DBG_NAV_LOGD("m_moveGeneration=%d moveGeneration=%d"
- " frame=%p x=%d y=%d",
- m_moveGeneration, moveGeneration, frame, x, y);
- if (m_moveGeneration > moveGeneration) {
- DBG_NAV_LOGD("m_moveGeneration=%d > moveGeneration=%d",
- m_moveGeneration, moveGeneration);
- return; // short-circuit if a newer move has already been generated
- }
- m_lastGeneration = moveGeneration;
- moveMouse(frame, x, y);
-}
-
-void WebViewCore::moveFocus(WebCore::Frame* frame, WebCore::Node* node)
-{
- DBG_NAV_LOGD("frame=%p node=%p", frame, node);
- if (!node || !CacheBuilder::validNode(m_mainFrame, frame, node)
- || !node->isElementNode())
- return;
- // Code borrowed from FocusController::advanceFocus
- WebCore::FocusController* focusController
- = m_mainFrame->page()->focusController();
- WebCore::Document* oldDoc
- = focusController->focusedOrMainFrame()->document();
- if (oldDoc->focusedNode() == node)
- return;
- if (node->document() != oldDoc)
- oldDoc->setFocusedNode(0);
- focusController->setFocusedFrame(frame);
- static_cast<WebCore::Element*>(node)->focus(false);
-}
// Update mouse position
-void WebViewCore::moveMouse(WebCore::Frame* frame, int x, int y)
+void WebViewCore::moveMouse(int x, int y, HitTestResult* hoveredNode, bool isClickCandidate)
{
- DBG_NAV_LOGD("frame=%p x=%d y=%d scrollOffset=(%d,%d)", frame,
- x, y, m_scrollOffsetX, m_scrollOffsetY);
- if (!frame || !CacheBuilder::validNode(m_mainFrame, frame, 0))
- frame = m_mainFrame;
// mouse event expects the position in the window coordinate
m_mousePos = WebCore::IntPoint(x - m_scrollOffsetX, y - m_scrollOffsetY);
+ if (isClickCandidate)
+ m_mouseClickPos = m_mousePos;
// validNode will still return true if the node is null, as long as we have
// a valid frame. Do not want to make a call on frame unless it is valid.
WebCore::PlatformMouseEvent mouseEvent(m_mousePos, m_mousePos,
WebCore::NoButton, WebCore::MouseEventMoved, 1, false, false, false,
false, WTF::currentTime());
- frame->eventHandler()->handleMouseMoveEvent(mouseEvent);
- updateCacheOnNodeChange();
+ m_mainFrame->eventHandler()->handleMouseMoveEvent(mouseEvent, hoveredNode);
+}
+
+Position WebViewCore::getPositionForOffset(Node* node, int offset)
+{
+ Position start = firstPositionInNode(node);
+ Position end = lastPositionInNode(node);
+ Document* document = node->document();
+ PassRefPtr<Range> range = Range::create(document, start, end);
+ WebCore::CharacterIterator iterator(range.get());
+ iterator.advance(offset);
+ return iterator.range()->startPosition();
+}
+
+void WebViewCore::setSelection(Node* node, int start, int end)
+{
+ RenderTextControl* control = toRenderTextControl(node);
+ if (control)
+ setSelectionRange(node, start, end);
+ else {
+ Position startPosition = getPositionForOffset(node, start);
+ Position endPosition = getPositionForOffset(node, end);
+ VisibleSelection selection(startPosition, endPosition);
+ SelectionController* selector = node->document()->frame()->selection();
+ selector->setSelection(selection);
+ }
}
void WebViewCore::setSelection(int start, int end)
@@ -2142,28 +2183,22 @@ void WebViewCore::setSelection(int start, int end)
WebCore::Node* focus = currentFocus();
if (!focus)
return;
- WebCore::RenderObject* renderer = focus->renderer();
- if (!renderer || (!renderer->isTextField() && !renderer->isTextArea()))
- return;
- if (start > end) {
- int temp = start;
- start = end;
- end = temp;
- }
+ if (start > end)
+ swap(start, end);
+
// Tell our EditorClient that this change was generated from the UI, so it
// does not need to echo it to the UI.
EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
m_mainFrame->editor()->client());
client->setUiGeneratedSelectionChange(true);
- setSelectionRange(focus, start, end);
- if (start != end) {
+ setSelection(focus, start, end);
+ RenderTextControl* control = toRenderTextControl(focus);
+ if (start != end && control) {
// Fire a select event. No event is sent when the selection reduces to
// an insertion point
- RenderTextControl* control = toRenderTextControl(renderer);
control->selectionChanged(true);
}
client->setUiGeneratedSelectionChange(false);
- WebCore::Frame* focusedFrame = focus->document()->frame();
bool isPasswordField = false;
if (focus->isElementNode()) {
WebCore::Element* element = static_cast<WebCore::Element*>(focus);
@@ -2172,7 +2207,7 @@ void WebViewCore::setSelection(int start, int end)
}
// For password fields, this is done in the UI side via
// bringPointIntoView, since the UI does the drawing.
- if (renderer->isTextArea() || !isPasswordField)
+ if ((control && control->isTextArea()) || !isPasswordField)
revealSelection();
}
@@ -2197,7 +2232,7 @@ String WebViewCore::modifySelection(const int direction, const int axis)
case AXIS_DOCUMENT:
return modifySelectionDomNavigationAxis(selection, direction, axis);
default:
- LOGE("Invalid navigation axis: %d", axis);
+ ALOGE("Invalid navigation axis: %d", axis);
return String();
}
}
@@ -2238,9 +2273,9 @@ String WebViewCore::modifySelectionTextNavigationAxis(DOMSelection* selection, i
// initialize the selection if necessary
if (selection->rangeCount() == 0) {
if (m_currentNodeDomNavigationAxis
- && CacheBuilder::validNode(m_mainFrame,
+ && validNode(m_mainFrame,
m_mainFrame, m_currentNodeDomNavigationAxis)) {
- PassRefPtr<Range> rangeRef =
+ RefPtr<Range> rangeRef =
selection->frame()->document()->createRange();
rangeRef->selectNode(m_currentNodeDomNavigationAxis, ec);
m_currentNodeDomNavigationAxis = 0;
@@ -2249,15 +2284,6 @@ String WebViewCore::modifySelectionTextNavigationAxis(DOMSelection* selection, i
selection->addRange(rangeRef.get());
} else if (currentFocus()) {
selection->setPosition(currentFocus(), 0, ec);
- } else if (m_cursorNode
- && CacheBuilder::validNode(m_mainFrame,
- m_mainFrame, m_cursorNode)) {
- PassRefPtr<Range> rangeRef =
- selection->frame()->document()->createRange();
- rangeRef->selectNode(reinterpret_cast<Node*>(m_cursorNode), ec);
- if (ec)
- return String();
- selection->addRange(rangeRef.get());
} else {
selection->setPosition(body, 0, ec);
}
@@ -2456,13 +2482,13 @@ String WebViewCore::modifySelectionTextNavigationAxis(DOMSelection* selection, i
scrollNodeIntoView(m_mainFrame, selection->anchorNode());
// format markup for the visible content
- PassRefPtr<Range> range = selection->getRangeAt(0, ec);
+ RefPtr<Range> range = selection->getRangeAt(0, ec);
if (ec)
return String();
IntRect bounds = range->boundingBox();
selectAt(bounds.center().x(), bounds.center().y());
markup = formatMarkup(selection);
- LOGV("Selection markup: %s", markup.utf8().data());
+ ALOGV("Selection markup: %s", markup.utf8().data());
return markup;
}
@@ -2670,7 +2696,7 @@ String WebViewCore::modifySelectionDomNavigationAxis(DOMSelection* selection, in
if (!m_currentNodeDomNavigationAxis)
m_currentNodeDomNavigationAxis = currentFocus();
if (!m_currentNodeDomNavigationAxis
- || !CacheBuilder::validNode(m_mainFrame, m_mainFrame,
+ || !validNode(m_mainFrame, m_mainFrame,
m_currentNodeDomNavigationAxis))
m_currentNodeDomNavigationAxis = body;
Node* currentNode = m_currentNodeDomNavigationAxis;
@@ -2714,14 +2740,14 @@ String WebViewCore::modifySelectionDomNavigationAxis(DOMSelection* selection, in
if (direction == DIRECTION_FORWARD)
currentNode = currentNode->lastDescendant();
} else {
- LOGE("Invalid axis: %d", axis);
+ ALOGE("Invalid axis: %d", axis);
return String();
}
if (currentNode) {
m_currentNodeDomNavigationAxis = currentNode;
scrollNodeIntoView(m_mainFrame, currentNode);
String selectionString = createMarkup(currentNode);
- LOGV("Selection markup: %s", selectionString.utf8().data());
+ ALOGV("Selection markup: %s", selectionString.utf8().data());
return selectionString;
}
return String();
@@ -2771,7 +2797,7 @@ bool WebViewCore::isVisible(Node* node)
while (currentNode && currentNode != body) {
RenderStyle* style = currentNode->computedStyle();
if (style &&
- (style->display() == NONE || style->visibility() == HIDDEN)) {
+ (style->display() == WebCore::NONE || style->visibility() == WebCore::HIDDEN)) {
return false;
}
currentNode = currentNode->parentNode();
@@ -2783,7 +2809,7 @@ String WebViewCore::formatMarkup(DOMSelection* selection)
{
ExceptionCode ec = 0;
String markup = String();
- PassRefPtr<Range> wholeRange = selection->getRangeAt(0, ec);
+ RefPtr<Range> wholeRange = selection->getRangeAt(0, ec);
if (ec)
return String();
if (!wholeRange->startContainer() || !wholeRange->startContainer())
@@ -2793,7 +2819,7 @@ String WebViewCore::formatMarkup(DOMSelection* selection)
Node* firstNode = wholeRange->firstNode();
Node* pastLastNode = wholeRange->pastLastNode();
Node* currentNode = firstNode;
- PassRefPtr<Range> currentRange;
+ RefPtr<Range> currentRange;
while (currentNode != pastLastNode) {
Node* nextNode = currentNode->traverseNextNode();
@@ -2870,7 +2896,6 @@ void WebViewCore::deleteSelection(int start, int end, int textGeneration)
key(up);
client->setUiGeneratedSelectionChange(false);
m_textGeneration = textGeneration;
- m_shouldPaintCaret = true;
}
void WebViewCore::replaceTextfieldText(int oldStart,
@@ -2886,13 +2911,15 @@ void WebViewCore::replaceTextfieldText(int oldStart,
EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
m_mainFrame->editor()->client());
client->setUiGeneratedSelectionChange(true);
- WebCore::TypingCommand::insertText(focus->document(), replace,
- false);
+ if (replace.length())
+ WebCore::TypingCommand::insertText(focus->document(), replace,
+ false);
+ else
+ WebCore::TypingCommand::deleteSelection(focus->document());
client->setUiGeneratedSelectionChange(false);
// setSelection calls revealSelection, so there is no need to do it here.
setSelection(start, end);
m_textGeneration = textGeneration;
- m_shouldPaintCaret = true;
}
void WebViewCore::passToJs(int generation, const WTF::String& current,
@@ -2900,13 +2927,6 @@ void WebViewCore::passToJs(int generation, const WTF::String& current,
{
WebCore::Node* focus = currentFocus();
if (!focus) {
- DBG_NAV_LOG("!focus");
- clearTextEntry();
- return;
- }
- WebCore::RenderObject* renderer = focus->renderer();
- if (!renderer || (!renderer->isTextField() && !renderer->isTextArea())) {
- DBG_NAV_LOGD("renderer==%p || not text", renderer);
clearTextEntry();
return;
}
@@ -2921,42 +2941,36 @@ void WebViewCore::passToJs(int generation, const WTF::String& current,
client->setUiGeneratedSelectionChange(false);
m_blockTextfieldUpdates = false;
m_textGeneration = generation;
- WebCore::RenderTextControl* renderText =
- static_cast<WebCore::RenderTextControl*>(renderer);
- WTF::String test = renderText->text();
+ WTF::String test = getInputText(focus);
if (test != current) {
// If the text changed during the key event, update the UI text field.
updateTextfield(focus, false, test);
- } else {
- DBG_NAV_LOG("test == current");
}
// Now that the selection has settled down, send it.
updateTextSelection();
- m_shouldPaintCaret = true;
}
-void WebViewCore::scrollFocusedTextInput(float xPercent, int y)
+WebCore::IntRect WebViewCore::scrollFocusedTextInput(float xPercent, int y)
{
WebCore::Node* focus = currentFocus();
if (!focus) {
- DBG_NAV_LOG("!focus");
clearTextEntry();
- return;
+ return WebCore::IntRect();
}
- WebCore::RenderObject* renderer = focus->renderer();
- if (!renderer || (!renderer->isTextField() && !renderer->isTextArea())) {
- DBG_NAV_LOGD("renderer==%p || not text", renderer);
+ WebCore::RenderTextControl* renderText = toRenderTextControl(focus);
+ if (!renderText) {
clearTextEntry();
- return;
+ return WebCore::IntRect();
}
- WebCore::RenderTextControl* renderText =
- static_cast<WebCore::RenderTextControl*>(renderer);
+
int x = (int) (xPercent * (renderText->scrollWidth() -
renderText->clientWidth()));
- DBG_NAV_LOGD("x=%d y=%d xPercent=%g scrollW=%d clientW=%d", x, y,
- xPercent, renderText->scrollWidth(), renderText->clientWidth());
renderText->setScrollLeft(x);
renderText->setScrollTop(y);
+ focus->document()->frame()->selection()->recomputeCaretRect();
+ LayerAndroid* layer = 0;
+ platformLayerIdFromNode(focus, &layer);
+ return absoluteContentRect(focus, layer);
}
void WebViewCore::setFocusControllerActive(bool active)
@@ -2966,7 +2980,7 @@ void WebViewCore::setFocusControllerActive(bool active)
void WebViewCore::saveDocumentState(WebCore::Frame* frame)
{
- if (!CacheBuilder::validNode(m_mainFrame, frame, 0))
+ if (!validNode(m_mainFrame, frame, 0))
frame = m_mainFrame;
WebCore::HistoryItem *item = frame->loader()->history()->currentItem();
@@ -2982,9 +2996,9 @@ void WebViewCore::saveDocumentState(WebCore::Frame* frame)
static jobjectArray makeLabelArray(JNIEnv* env, const uint16_t** labels, size_t count)
{
jclass stringClass = env->FindClass("java/lang/String");
- LOG_ASSERT(stringClass, "Could not find java/lang/String");
+ ALOG_ASSERT(stringClass, "Could not find java/lang/String");
jobjectArray array = env->NewObjectArray(count, stringClass, 0);
- LOG_ASSERT(array, "Could not create new string array");
+ ALOG_ASSERT(array, "Could not create new string array");
for (size_t i = 0; i < count; i++) {
jobject newString = env->NewString(&labels[i][1], labels[i][0]);
@@ -3007,11 +3021,19 @@ void WebViewCore::openFileChooser(PassRefPtr<WebCore::FileChooser> chooser)
return;
WTF::String acceptType = chooser->acceptTypes();
+ WTF::String capture;
+
+#if ENABLE(MEDIA_CAPTURE)
+ capture = chooser->capture();
+#endif
+
jstring jAcceptType = wtfStringToJstring(env, acceptType, true);
+ jstring jCapture = wtfStringToJstring(env, capture, true);
jstring jName = (jstring) env->CallObjectMethod(
- javaObject.get(), m_javaGlue->m_openFileChooser, jAcceptType);
+ javaObject.get(), m_javaGlue->m_openFileChooser, jAcceptType, jCapture);
checkException(env);
env->DeleteLocalRef(jAcceptType);
+ env->DeleteLocalRef(jCapture);
WTF::String wtfString = jstringToWtfString(env, jName);
env->DeleteLocalRef(jName);
@@ -3023,7 +3045,7 @@ void WebViewCore::openFileChooser(PassRefPtr<WebCore::FileChooser> chooser)
void WebViewCore::listBoxRequest(WebCoreReply* reply, const uint16_t** labels, size_t count, const int enabled[], size_t enabledCount,
bool multiple, const int selected[], size_t selectedCountOrSelection)
{
- LOG_ASSERT(m_javaGlue->m_obj, "No java widget associated with this view!");
+ ALOG_ASSERT(m_javaGlue->m_obj, "No java widget associated with this view!");
JNIEnv* env = JSC::Bindings::getJNIEnv();
AutoJObject javaObject = m_javaGlue->object(env);
@@ -3082,14 +3104,15 @@ bool WebViewCore::key(const PlatformKeyboardEvent& event)
{
WebCore::EventHandler* eventHandler;
WebCore::Node* focusNode = currentFocus();
- DBG_NAV_LOGD("keyCode=%s unichar=%d focusNode=%p",
- event.keyIdentifier().utf8().data(), event.unichar(), focusNode);
if (focusNode) {
WebCore::Frame* frame = focusNode->document()->frame();
- WebFrame* webFrame = WebFrame::getWebFrame(frame);
eventHandler = frame->eventHandler();
VisibleSelection old = frame->selection()->selection();
+ EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
+ m_mainFrame->editor()->client());
+ client->setUiGeneratedSelectionChange(true);
bool handled = eventHandler->keyEvent(event);
+ client->setUiGeneratedSelectionChange(false);
if (isContentEditable(focusNode)) {
// keyEvent will return true even if the contentEditable did not
// change its selection. In the case that it does not, we want to
@@ -3099,33 +3122,53 @@ bool WebViewCore::key(const PlatformKeyboardEvent& event)
}
return handled;
} else {
- eventHandler = m_mainFrame->eventHandler();
+ eventHandler = focusedFrame()->eventHandler();
}
return eventHandler->keyEvent(event);
}
-// For when the user clicks the trackball, presses dpad center, or types into an
-// unfocused textfield. In the latter case, 'fake' will be true
-void WebViewCore::click(WebCore::Frame* frame, WebCore::Node* node, bool fake) {
- if (!node) {
- WebCore::IntPoint pt = m_mousePos;
- pt.move(m_scrollOffsetX, m_scrollOffsetY);
- WebCore::HitTestResult hitTestResult = m_mainFrame->eventHandler()->
- hitTestResultAtPoint(pt, false);
- node = hitTestResult.innerNode();
- frame = node->document()->frame();
- DBG_NAV_LOGD("m_mousePos=(%d,%d) m_scrollOffset=(%d,%d) pt=(%d,%d)"
- " node=%p", m_mousePos.x(), m_mousePos.y(),
- m_scrollOffsetX, m_scrollOffsetY, pt.x(), pt.y(), node);
- }
- if (node) {
- EditorClientAndroid* client
- = static_cast<EditorClientAndroid*>(
- m_mainFrame->editor()->client());
- client->setShouldChangeSelectedRange(false);
- handleMouseClick(frame, node, fake);
- client->setShouldChangeSelectedRange(true);
+bool WebViewCore::chromeCanTakeFocus(FocusDirection direction)
+{
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ AutoJObject javaObject = m_javaGlue->object(env);
+ if (!javaObject.get())
+ return false;
+ return env->CallBooleanMethod(javaObject.get(), m_javaGlue->m_chromeCanTakeFocus, direction);
+}
+
+void WebViewCore::chromeTakeFocus(FocusDirection direction)
+{
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ AutoJObject javaObject = m_javaGlue->object(env);
+ if (!javaObject.get())
+ return;
+ env->CallVoidMethod(javaObject.get(), m_javaGlue->m_chromeTakeFocus, direction);
+}
+
+void WebViewCore::setInitialFocus(const WebCore::PlatformKeyboardEvent& platformEvent)
+{
+ Frame* frame = focusedFrame();
+ Document* document = frame->document();
+ if (document)
+ document->setFocusedNode(0);
+ FocusDirection direction;
+ switch (platformEvent.nativeVirtualKeyCode()) {
+ case AKEYCODE_DPAD_LEFT:
+ direction = FocusDirectionLeft;
+ break;
+ case AKEYCODE_DPAD_RIGHT:
+ direction = FocusDirectionRight;
+ break;
+ case AKEYCODE_DPAD_UP:
+ direction = FocusDirectionUp;
+ break;
+ default:
+ direction = FocusDirectionDown;
+ break;
}
+ RefPtr<KeyboardEvent> webkitEvent = KeyboardEvent::create(platformEvent, 0);
+ m_mainFrame->page()->focusController()->setInitialFocus(direction,
+ webkitEvent.get());
}
#if USE(ACCELERATED_COMPOSITING)
@@ -3139,9 +3182,9 @@ GraphicsLayerAndroid* WebViewCore::graphicsRootLayer() const
}
#endif
-bool WebViewCore::handleTouchEvent(int action, Vector<int>& ids, Vector<IntPoint>& points, int actionIndex, int metaState)
+int WebViewCore::handleTouchEvent(int action, Vector<int>& ids, Vector<IntPoint>& points, int actionIndex, int metaState)
{
- bool preventDefault = false;
+ int flags = 0;
#if USE(ACCELERATED_COMPOSITING)
GraphicsLayerAndroid* rootLayer = graphicsRootLayer();
@@ -3182,18 +3225,10 @@ bool WebViewCore::handleTouchEvent(int action, Vector<int>& ids, Vector<IntPoint
type = WebCore::TouchEnd;
defaultTouchState = WebCore::PlatformTouchPoint::TouchStationary;
break;
- case 0x100: // WebViewCore.ACTION_LONGPRESS
- type = WebCore::TouchLongPress;
- defaultTouchState = WebCore::PlatformTouchPoint::TouchPressed;
- break;
- case 0x200: // WebViewCore.ACTION_DOUBLETAP
- type = WebCore::TouchDoubleTap;
- defaultTouchState = WebCore::PlatformTouchPoint::TouchPressed;
- break;
default:
// We do not support other kinds of touch event inside WebCore
// at the moment.
- LOGW("Java passed a touch event type that we do not support in WebCore: %d", action);
+ ALOGW("Java passed a touch event type that we do not support in WebCore: %d", action);
return 0;
}
@@ -3213,52 +3248,41 @@ bool WebViewCore::handleTouchEvent(int action, Vector<int>& ids, Vector<IntPoint
}
WebCore::PlatformTouchEvent te(ids, points, type, touchStates, metaState);
- preventDefault = m_mainFrame->eventHandler()->handleTouchEvent(te);
+ if (m_mainFrame->eventHandler()->handleTouchEvent(te))
+ flags |= TOUCH_FLAG_PREVENT_DEFAULT;
+ if (te.hitTouchHandler())
+ flags |= TOUCH_FLAG_HIT_HANDLER;
#endif
#if USE(ACCELERATED_COMPOSITING)
if (rootLayer)
rootLayer->pauseDisplay(false);
#endif
- return preventDefault;
+ return flags;
}
-void WebViewCore::touchUp(int touchGeneration,
- WebCore::Frame* frame, WebCore::Node* node, int x, int y)
+bool WebViewCore::performMouseClick()
{
- if (touchGeneration == 0) {
- // m_mousePos should be set in getTouchHighlightRects()
- WebCore::HitTestResult hitTestResult = m_mainFrame->eventHandler()->hitTestResultAtPoint(m_mousePos, false);
- node = hitTestResult.innerNode();
- if (node)
- frame = node->document()->frame();
- else
- frame = 0;
- DBG_NAV_LOGD("touch up on (%d, %d), scrollOffset is (%d, %d), node:%p, frame:%p", m_mousePos.x() + m_scrollOffsetX, m_mousePos.y() + m_scrollOffsetY, m_scrollOffsetX, m_scrollOffsetY, node, frame);
- } else {
- if (m_touchGeneration > touchGeneration) {
- DBG_NAV_LOGD("m_touchGeneration=%d > touchGeneration=%d"
- " x=%d y=%d", m_touchGeneration, touchGeneration, x, y);
- return; // short circuit if a newer touch has been generated
- }
- // This moves m_mousePos to the correct place, and handleMouseClick uses
- // m_mousePos to determine where the click happens.
- moveMouse(frame, x, y);
- m_lastGeneration = touchGeneration;
- }
- if (frame && CacheBuilder::validNode(m_mainFrame, frame, 0)) {
- frame->loader()->resetMultipleFormSubmissionProtection();
- }
- DBG_NAV_LOGD("touchGeneration=%d handleMouseClick frame=%p node=%p"
- " x=%d y=%d", touchGeneration, frame, node, x, y);
- handleMouseClick(frame, node, false);
+ WebCore::PlatformMouseEvent mouseDown(m_mouseClickPos, m_mouseClickPos, WebCore::LeftButton,
+ WebCore::MouseEventPressed, 1, false, false, false, false,
+ WTF::currentTime());
+ // ignore the return from as it will return true if the hit point can trigger selection change
+ m_mainFrame->eventHandler()->handleMousePressEvent(mouseDown);
+ WebCore::PlatformMouseEvent mouseUp(m_mouseClickPos, m_mouseClickPos, WebCore::LeftButton,
+ WebCore::MouseEventReleased, 1, false, false, false, false,
+ WTF::currentTime());
+ bool handled = m_mainFrame->eventHandler()->handleMouseReleaseEvent(mouseUp);
+
+ WebCore::Node* focusNode = currentFocus();
+ initializeTextInput(focusNode, false);
+ return handled;
}
// Check for the "x-webkit-soft-keyboard" attribute. If it is there and
// set to hidden, do not show the soft keyboard. Node passed as a parameter
// must not be null.
static bool shouldSuppressKeyboard(const WebCore::Node* node) {
- LOG_ASSERT(node, "node passed to shouldSuppressKeyboard cannot be null");
+ ALOG_ASSERT(node, "node passed to shouldSuppressKeyboard cannot be null");
const NamedNodeMap* attributes = node->attributes();
if (!attributes) return false;
size_t length = attributes->length();
@@ -3270,84 +3294,160 @@ static bool shouldSuppressKeyboard(const WebCore::Node* node) {
return false;
}
-// Common code for both clicking with the trackball and touchUp
-// Also used when typing into a non-focused textfield to give the textfield focus,
-// in which case, 'fake' is set to true
-bool WebViewCore::handleMouseClick(WebCore::Frame* framePtr, WebCore::Node* nodePtr, bool fake)
-{
- bool valid = !framePtr || CacheBuilder::validNode(m_mainFrame, framePtr, nodePtr);
- WebFrame* webFrame = WebFrame::getWebFrame(m_mainFrame);
- if (valid && nodePtr) {
- // Need to special case area tags because an image map could have an area element in the middle
- // so when attempting to get the default, the point chosen would be follow the wrong link.
- if (nodePtr->hasTagName(WebCore::HTMLNames::areaTag)) {
- webFrame->setUserInitiatedAction(true);
- nodePtr->dispatchSimulatedClick(0, true, true);
- webFrame->setUserInitiatedAction(false);
- DBG_NAV_LOG("area");
- return true;
- }
+WebViewCore::InputType WebViewCore::getInputType(Node* node)
+{
+ WebCore::RenderObject* renderer = node->renderer();
+ if (!renderer)
+ return WebViewCore::NONE;
+ if (renderer->isTextArea())
+ return WebViewCore::TEXT_AREA;
+
+ if (node->hasTagName(WebCore::HTMLNames::inputTag)) {
+ HTMLInputElement* htmlInput = static_cast<HTMLInputElement*>(node);
+ if (htmlInput->isPasswordField())
+ return WebViewCore::PASSWORD;
+ if (htmlInput->isSearchField())
+ return WebViewCore::SEARCH;
+ if (htmlInput->isEmailField())
+ return WebViewCore::EMAIL;
+ if (htmlInput->isNumberField())
+ return WebViewCore::NUMBER;
+ if (htmlInput->isTelephoneField())
+ return WebViewCore::TELEPHONE;
+ if (htmlInput->isTextField())
+ return WebViewCore::NORMAL_TEXT_FIELD;
}
- if (!valid || !framePtr)
- framePtr = m_mainFrame;
- webFrame->setUserInitiatedAction(true);
- WebCore::PlatformMouseEvent mouseDown(m_mousePos, m_mousePos, WebCore::LeftButton,
- WebCore::MouseEventPressed, 1, false, false, false, false,
- WTF::currentTime());
- // ignore the return from as it will return true if the hit point can trigger selection change
- framePtr->eventHandler()->handleMousePressEvent(mouseDown);
- WebCore::PlatformMouseEvent mouseUp(m_mousePos, m_mousePos, WebCore::LeftButton,
- WebCore::MouseEventReleased, 1, false, false, false, false,
- WTF::currentTime());
- bool handled = framePtr->eventHandler()->handleMouseReleaseEvent(mouseUp);
- webFrame->setUserInitiatedAction(false);
- // If the user clicked on a textfield, make the focusController active
- // so we show the blinking cursor.
- WebCore::Node* focusNode = currentFocus();
- DBG_NAV_LOGD("m_mousePos={%d,%d} focusNode=%p handled=%s", m_mousePos.x(),
- m_mousePos.y(), focusNode, handled ? "true" : "false");
- if (focusNode) {
- WebCore::RenderObject* renderer = focusNode->renderer();
- if (renderer && (renderer->isTextField() || renderer->isTextArea())) {
- bool ime = !shouldSuppressKeyboard(focusNode)
- && !(static_cast<WebCore::HTMLInputElement*>(focusNode))->readOnly();
- if (ime) {
-#if ENABLE(WEB_AUTOFILL)
- if (renderer->isTextField()) {
- EditorClientAndroid* editorC = static_cast<EditorClientAndroid*>(framePtr->page()->editorClient());
- WebAutofill* autoFill = editorC->getAutofill();
- autoFill->formFieldFocused(static_cast<HTMLFormControlElement*>(focusNode));
- }
-#endif
- if (!fake) {
- RenderTextControl* rtc
- = static_cast<RenderTextControl*> (renderer);
- // Force an update of the navcache as this will fire off a
- // message to WebView that *must* have an updated focus.
- m_frameCacheOutOfDate = true;
- updateFrameCache();
- requestKeyboardWithSelection(focusNode, rtc->selectionStart(),
- rtc->selectionEnd());
- }
- } else if (!fake) {
- requestKeyboard(false);
- }
- } else if (!fake){
- // If the selection is contentEditable, show the keyboard so the
- // user can type. Otherwise hide the keyboard because no text
- // input is needed.
- if (isContentEditable(focusNode)) {
- requestKeyboard(true);
- } else if (!nodeIsPlugin(focusNode)) {
- clearTextEntry();
- }
+ if (node->isContentEditable())
+ return WebViewCore::TEXT_AREA;
+
+ return WebViewCore::NONE;
+}
+
+int WebViewCore::getMaxLength(Node* node)
+{
+ int maxLength = -1;
+ if (node->hasTagName(WebCore::HTMLNames::inputTag)) {
+ HTMLInputElement* htmlInput = static_cast<HTMLInputElement*>(node);
+ maxLength = htmlInput->maxLength();
+ }
+ return maxLength;
+}
+
+String WebViewCore::getFieldName(Node* node)
+{
+ String name;
+ if (node->hasTagName(WebCore::HTMLNames::inputTag)) {
+ HTMLInputElement* htmlInput = static_cast<HTMLInputElement*>(node);
+ name = htmlInput->name();
+ }
+ return name;
+}
+
+bool WebViewCore::isSpellCheckEnabled(Node* node)
+{
+ bool isEnabled = true;
+ if (node->isElementNode()) {
+ WebCore::Element* element = static_cast<WebCore::Element*>(node);
+ isEnabled = element->isSpellCheckingEnabled();
+ }
+ return isEnabled;
+}
+
+bool WebViewCore::isAutoCompleteEnabled(Node* node)
+{
+ bool isEnabled = false;
+ if (node->hasTagName(WebCore::HTMLNames::inputTag)) {
+ HTMLInputElement* htmlInput = static_cast<HTMLInputElement*>(node);
+ isEnabled = htmlInput->autoComplete();
+ }
+ return isEnabled;
+}
+
+WebCore::IntRect WebViewCore::absoluteContentRect(WebCore::Node* node,
+ LayerAndroid* layer)
+{
+ IntRect contentRect;
+ if (node) {
+ RenderObject* render = node->renderer();
+ if (render && render->isBox() && !render->isBody()) {
+ IntPoint offset = convertGlobalContentToFrameContent(IntPoint(),
+ node->document()->frame());
+ WebViewCore::layerToAbsoluteOffset(layer, offset);
+
+ RenderBox* renderBox = toRenderBox(render);
+ contentRect = renderBox->absoluteContentBox();
+ contentRect.move(-offset.x(), -offset.y());
}
- } else if (!fake) {
- // There is no focusNode, so the keyboard is not needed.
- clearTextEntry();
}
- return handled;
+ return contentRect;
+}
+
+jobject WebViewCore::createTextFieldInitData(Node* node)
+{
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ TextFieldInitDataGlue* classDef = m_textFieldInitDataGlue;
+ ScopedLocalRef<jclass> clazz(env,
+ env->FindClass("android/webkit/WebViewCore$TextFieldInitData"));
+ jobject initData = env->NewObject(clazz.get(), classDef->m_constructor);
+ env->SetIntField(initData, classDef->m_fieldPointer,
+ reinterpret_cast<int>(node));
+ ScopedLocalRef<jstring> inputText(env,
+ wtfStringToJstring(env, getInputText(node), true));
+ env->SetObjectField(initData, classDef->m_text, inputText.get());
+ env->SetIntField(initData, classDef->m_type, getInputType(node));
+ env->SetBooleanField(initData, classDef->m_isSpellCheckEnabled,
+ isSpellCheckEnabled(node));
+ Document* document = node->document();
+ PlatformKeyboardEvent tab(AKEYCODE_TAB, 0, 0, false, false, false, false);
+ PassRefPtr<KeyboardEvent> tabEvent =
+ KeyboardEvent::create(tab, document->defaultView());
+ env->SetBooleanField(initData, classDef->m_isTextFieldNext,
+ isTextInput(document->nextFocusableNode(node, tabEvent.get())));
+ env->SetBooleanField(initData, classDef->m_isTextFieldPrev,
+ isTextInput(document->previousFocusableNode(node, tabEvent.get())));
+ env->SetBooleanField(initData, classDef->m_isAutoCompleteEnabled,
+ isAutoCompleteEnabled(node));
+ ScopedLocalRef<jstring> fieldName(env,
+ wtfStringToJstring(env, getFieldName(node), false));
+ env->SetObjectField(initData, classDef->m_name, fieldName.get());
+ ScopedLocalRef<jstring> label(env,
+ wtfStringToJstring(env, requestLabel(document->frame(), node), false));
+ env->SetObjectField(initData, classDef->m_label, label.get());
+ env->SetIntField(initData, classDef->m_maxLength, getMaxLength(node));
+ LayerAndroid* layer = 0;
+ int layerId = platformLayerIdFromNode(node, &layer);
+ IntRect bounds = absoluteContentRect(node, layer);
+ ScopedLocalRef<jobject> jbounds(env, intRectToRect(env, bounds));
+ env->SetObjectField(initData, classDef->m_contentBounds, jbounds.get());
+ env->SetIntField(initData, classDef->m_nodeLayerId, layerId);
+ IntRect contentRect;
+ RenderTextControl* rtc = toRenderTextControl(node);
+ if (rtc) {
+ contentRect.setWidth(rtc->scrollWidth());
+ contentRect.setHeight(rtc->scrollHeight());
+ contentRect.move(-rtc->scrollLeft(), -rtc->scrollTop());
+ }
+ ScopedLocalRef<jobject> jcontentRect(env, intRectToRect(env, contentRect));
+ env->SetObjectField(initData, classDef->m_contentRect, jcontentRect.get());
+ return initData;
+}
+
+void WebViewCore::initEditField(Node* node)
+{
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ AutoJObject javaObject = m_javaGlue->object(env);
+ if (!javaObject.get())
+ return;
+ m_textGeneration = 0;
+ int start = 0;
+ int end = 0;
+ getSelectionOffsets(node, start, end);
+ SelectText* selectText = createSelectText(focusedFrame()->selection()->selection());
+ ScopedLocalRef<jobject> initData(env, createTextFieldInitData(node));
+ env->CallVoidMethod(javaObject.get(), m_javaGlue->m_initEditField,
+ start, end, reinterpret_cast<int>(selectText), initData.get());
+ checkException(env);
}
void WebViewCore::popupReply(int index)
@@ -3368,28 +3468,99 @@ void WebViewCore::popupReply(const int* array, int count)
}
}
-void WebViewCore::formDidBlur(const WebCore::Node* node)
+// This is a slightly modified Node::nextNodeConsideringAtomicNodes() with the
+// extra constraint of limiting the search to inside a containing parent
+WebCore::Node* nextNodeWithinParent(WebCore::Node* parent, WebCore::Node* start)
{
- // If the blur is on a text input, keep track of the node so we can
- // hide the soft keyboard when the new focus is set, if it is not a
- // text input.
- if (isTextInput(node))
- m_blurringNodePointer = reinterpret_cast<int>(node);
+ if (!isAtomicNode(start) && start->firstChild())
+ return start->firstChild();
+ if (start->nextSibling())
+ return start->nextSibling();
+ const Node *n = start;
+ while (n && !n->nextSibling()) {
+ n = n->parentNode();
+ if (n == parent)
+ return 0;
+ }
+ if (n)
+ return n->nextSibling();
+ return 0;
}
-void WebViewCore::focusNodeChanged(const WebCore::Node* newFocus)
+void WebViewCore::initializeTextInput(WebCore::Node* node, bool fake)
{
+ if (node) {
+ if (isTextInput(node)) {
+ bool showKeyboard = true;
+ initEditField(node);
+ WebCore::RenderTextControl* rtc = toRenderTextControl(node);
+ if (rtc && node->hasTagName(HTMLNames::inputTag)) {
+ HTMLInputElement* inputElement = static_cast<HTMLInputElement*>(node);
+ bool ime = !shouldSuppressKeyboard(node) && !inputElement->readOnly();
+ if (ime) {
+#if ENABLE(WEB_AUTOFILL)
+ if (rtc->isTextField()) {
+ Page* page = node->document()->page();
+ EditorClient* editorClient = page->editorClient();
+ EditorClientAndroid* androidEditor =
+ static_cast<EditorClientAndroid*>(editorClient);
+ WebAutofill* autoFill = androidEditor->getAutofill();
+ autoFill->formFieldFocused(inputElement);
+ }
+#endif
+ } else
+ showKeyboard = false;
+ }
+ if (!fake)
+ requestKeyboard(showKeyboard);
+ } else if (!fake && !nodeIsPlugin(node)) {
+ // not a text entry field, put away the keyboard.
+ clearTextEntry();
+ }
+ } else if (!fake) {
+ // There is no focusNode, so the keyboard is not needed.
+ clearTextEntry();
+ }
+}
+
+void WebViewCore::focusNodeChanged(WebCore::Node* newFocus)
+{
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ AutoJObject javaObject = m_javaGlue->object(env);
+ if (!javaObject.get())
+ return;
if (isTextInput(newFocus))
- m_shouldPaintCaret = true;
- else if (m_blurringNodePointer) {
- JNIEnv* env = JSC::Bindings::getJNIEnv();
- AutoJObject javaObject = m_javaGlue->object(env);
- if (!javaObject.get())
- return;
- env->CallVoidMethod(javaObject.get(), m_javaGlue->m_formDidBlur, m_blurringNodePointer);
- checkException(env);
- m_blurringNodePointer = 0;
+ initializeTextInput(newFocus, true);
+ HitTestResult focusHitResult;
+ focusHitResult.setInnerNode(newFocus);
+ focusHitResult.setInnerNonSharedNode(newFocus);
+ if (newFocus && newFocus->isLink() && newFocus->isElementNode()) {
+ focusHitResult.setURLElement(static_cast<Element*>(newFocus));
+ if (newFocus->hasChildNodes() && !newFocus->hasTagName(HTMLNames::imgTag)) {
+ // Check to see if any of the children are images, and if so
+ // set them as the innerNode and innerNonSharedNode
+ // This will stop when it hits the first image. I'm not sure what
+ // should be done in the case of multiple images inside one anchor...
+ Node* nextNode = newFocus->firstChild();
+ bool found = false;
+ while (nextNode) {
+ if (nextNode->hasTagName(HTMLNames::imgTag)) {
+ found = true;
+ break;
+ }
+ nextNode = nextNodeWithinParent(newFocus, nextNode);
+ }
+ if (found) {
+ focusHitResult.setInnerNode(nextNode);
+ focusHitResult.setInnerNonSharedNode(nextNode);
+ }
+ }
}
+ AndroidHitTestResult androidHitTest(this, focusHitResult);
+ jobject jHitTestObj = androidHitTest.createJavaObject(env);
+ env->CallVoidMethod(javaObject.get(), m_javaGlue->m_focusNodeChanged,
+ reinterpret_cast<int>(newFocus), jHitTestObj);
+ env->DeleteLocalRef(jHitTestObj);
}
void WebViewCore::addMessageToConsole(const WTF::String& message, unsigned int lineNumber, const WTF::String& sourceID, int msgLevel) {
@@ -3588,7 +3759,57 @@ WebViewCore::getWebViewJavaObject()
AutoJObject javaObject = m_javaGlue->object(env);
if (!javaObject.get())
return 0;
- return env->GetObjectField(javaObject.get(), gWebViewCoreFields.m_webView);
+ return env->CallObjectMethod(javaObject.get(), m_javaGlue->m_getWebView);
+}
+
+RenderTextControl* WebViewCore::toRenderTextControl(Node* node)
+{
+ RenderTextControl* rtc = 0;
+ RenderObject* renderer = node->renderer();
+ if (renderer && renderer->isTextControl()) {
+ rtc = WebCore::toRenderTextControl(renderer);
+ }
+ return rtc;
+}
+
+void WebViewCore::getSelectionOffsets(Node* node, int& start, int& end)
+{
+ RenderTextControl* rtc = toRenderTextControl(node);
+ if (rtc) {
+ start = rtc->selectionStart();
+ end = rtc->selectionEnd();
+ } else {
+ // It must be content editable field.
+ Document* document = node->document();
+ Frame* frame = document->frame();
+ SelectionController* selector = frame->selection();
+ Position selectionStart = selector->start();
+ Position selectionEnd = selector->end();
+ Position startOfNode = firstPositionInNode(node);
+ RefPtr<Range> startRange = Range::create(document, startOfNode,
+ selectionStart);
+ start = TextIterator::rangeLength(startRange.get(), true);
+ RefPtr<Range> endRange = Range::create(document, startOfNode,
+ selectionEnd);
+ end = TextIterator::rangeLength(endRange.get(), true);
+ }
+}
+
+String WebViewCore::getInputText(Node* node)
+{
+ String text;
+ WebCore::RenderTextControl* renderText = toRenderTextControl(node);
+ if (renderText)
+ text = renderText->text();
+ else {
+ // It must be content editable field.
+ Position start = firstPositionInNode(node);
+ Position end = lastPositionInNode(node);
+ VisibleSelection allEditableText(start, end);
+ if (allEditableText.isRange())
+ text = allEditableText.firstRange()->text();
+ }
+ return text;
}
void WebViewCore::updateTextSelection()
@@ -3597,16 +3818,33 @@ void WebViewCore::updateTextSelection()
AutoJObject javaObject = m_javaGlue->object(env);
if (!javaObject.get())
return;
- WebCore::Node* focusNode = currentFocus();
- if (!focusNode)
+ VisibleSelection selection = focusedFrame()->selection()->selection();
+ int start = 0;
+ int end = 0;
+ if (selection.isCaretOrRange())
+ getSelectionOffsets(selection.start().anchorNode(), start, end);
+ SelectText* selectText = createSelectText(selection);
+ env->CallVoidMethod(javaObject.get(),
+ m_javaGlue->m_updateTextSelection, reinterpret_cast<int>(currentFocus()),
+ start, end, m_textGeneration, reinterpret_cast<int>(selectText));
+ checkException(env);
+}
+
+void WebViewCore::updateTextSizeAndScroll(WebCore::Node* node)
+{
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ AutoJObject javaObject = m_javaGlue->object(env);
+ if (!javaObject.get())
return;
- RenderObject* renderer = focusNode->renderer();
- if (!renderer || (!renderer->isTextArea() && !renderer->isTextField()))
+ RenderTextControl* rtc = toRenderTextControl(node);
+ if (!rtc)
return;
- RenderTextControl* rtc = static_cast<RenderTextControl*>(renderer);
- env->CallVoidMethod(javaObject.get(),
- m_javaGlue->m_updateTextSelection, reinterpret_cast<int>(focusNode),
- rtc->selectionStart(), rtc->selectionEnd(), m_textGeneration);
+ int width = rtc->scrollWidth();
+ int height = rtc->contentHeight();
+ int scrollX = rtc->scrollLeft();
+ int scrollY = rtc->scrollTop();
+ env->CallVoidMethod(javaObject.get(), m_javaGlue->m_updateTextSizeAndScroll,
+ reinterpret_cast<int>(node), width, height, scrollX, scrollY);
checkException(env);
}
@@ -3650,11 +3888,18 @@ void WebViewCore::setBackgroundColor(SkColor c)
// need (int) cast to find the right constructor
WebCore::Color bcolor((int)SkColorGetR(c), (int)SkColorGetG(c),
(int)SkColorGetB(c), (int)SkColorGetA(c));
+
+ if (view->baseBackgroundColor() == bcolor)
+ return;
+
view->setBaseBackgroundColor(bcolor);
// Background color of 0 indicates we want a transparent background
if (c == 0)
view->setTransparent(true);
+
+ //invalidate so the new color is shown
+ contentInvalidateAll();
}
jclass WebViewCore::getPluginClass(const WTF::String& libName, const char* className)
@@ -3780,21 +4025,6 @@ void WebViewCore::keepScreenOn(bool screenOn) {
m_screenOnCounter--;
}
-bool WebViewCore::validNodeAndBounds(Frame* frame, Node* node,
- const IntRect& originalAbsoluteBounds)
-{
- bool valid = CacheBuilder::validNode(m_mainFrame, frame, node);
- if (!valid)
- return false;
- RenderObject* renderer = node->renderer();
- if (!renderer)
- return false;
- IntRect absBounds = node->hasTagName(HTMLNames::areaTag)
- ? CacheBuilder::getAreaRect(static_cast<HTMLAreaElement*>(node))
- : renderer->absoluteBoundingBoxRect();
- return absBounds == originalAbsoluteBounds;
-}
-
void WebViewCore::showRect(int left, int top, int width, int height,
int contentWidth, int contentHeight, float xPercentInDoc,
float xPercentInView, float yPercentInDoc, float yPercentInView)
@@ -3848,6 +4078,20 @@ void WebViewCore::enterFullscreenForVideoLayer(int layerId, const WTF::String& u
return;
jstring jUrlStr = wtfStringToJstring(env, url);
env->CallVoidMethod(javaObject.get(), m_javaGlue->m_enterFullscreenForVideoLayer, layerId, jUrlStr);
+ m_fullscreenVideoMode = true;
+ checkException(env);
+}
+
+void WebViewCore::exitFullscreenVideo()
+{
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ AutoJObject javaObject = m_javaGlue->object(env);
+ if (!javaObject.get())
+ return;
+ if (m_fullscreenVideoMode) {
+ env->CallVoidMethod(javaObject.get(), m_javaGlue->m_exitFullscreenVideo);
+ m_fullscreenVideoMode = false;
+ }
checkException(env);
}
#endif
@@ -3873,7 +4117,6 @@ bool WebViewCore::drawIsPaused() const
return false;
}
-#if USE(CHROME_NETWORK_STACK)
void WebViewCore::setWebRequestContextUserAgent()
{
// We cannot create a WebRequestContext, because we might not know it this is a private tab or not yet
@@ -3901,7 +4144,6 @@ WebRequestContext* WebViewCore::webRequestContext()
}
return m_webRequestContext.get();
}
-#endif
void WebViewCore::scrollRenderLayer(int layer, const SkRect& rect)
{
@@ -3922,189 +4164,370 @@ void WebViewCore::scrollRenderLayer(int layer, const SkRect& rect)
if (!owner)
return;
- if (owner->stackingContext())
+ if (owner->isRootLayer()) {
+ FrameView* view = owner->renderer()->frame()->view();
+ IntPoint pt(rect.fLeft, rect.fTop);
+ view->setScrollPosition(pt);
+ } else
owner->scrollToOffset(rect.fLeft, rect.fTop);
#endif
}
+Vector<VisibleSelection> WebViewCore::getTextRanges(
+ int startX, int startY, int endX, int endY)
+{
+ // These are the positions of the selection handles,
+ // which reside below the line that they are selecting.
+ // Use the vertical position higher, which will include
+ // the selected text.
+ startY--;
+ endY--;
+ VisiblePosition startSelect = visiblePositionForContentPoint(startX, startY);
+ VisiblePosition endSelect = visiblePositionForContentPoint(endX, endY);
+ Position start = startSelect.deepEquivalent();
+ Position end = endSelect.deepEquivalent();
+ Vector<VisibleSelection> ranges;
+ if (!start.isNull() && !end.isNull()) {
+ if (comparePositions(start, end) > 0) {
+ swap(start, end); // RTL start/end positions may be swapped
+ }
+ Position nextRangeStart = start;
+ Position previousRangeEnd;
+ do {
+ VisibleSelection selection(nextRangeStart, end);
+ ranges.append(selection);
+ previousRangeEnd = selection.end();
+ nextRangeStart = nextCandidate(previousRangeEnd);
+ } while (comparePositions(previousRangeEnd, end) < 0);
+ }
+ return ranges;
+}
+
+void WebViewCore::deleteText(int startX, int startY, int endX, int endY)
+{
+ Vector<VisibleSelection> ranges =
+ getTextRanges(startX, startY, endX, endY);
+
+ EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
+ m_mainFrame->editor()->client());
+ client->setUiGeneratedSelectionChange(true);
+
+ SelectionController* selector = m_mainFrame->selection();
+ for (size_t i = 0; i < ranges.size(); i++) {
+ const VisibleSelection& selection = ranges[i];
+ if (selection.isContentEditable()) {
+ selector->setSelection(selection, CharacterGranularity);
+ Document* document = selection.start().anchorNode()->document();
+ WebCore::TypingCommand::deleteSelection(document, 0);
+ }
+ }
+ client->setUiGeneratedSelectionChange(false);
+}
+
+void WebViewCore::insertText(const WTF::String &text)
+{
+ WebCore::Node* focus = currentFocus();
+ if (!focus || !isTextInput(focus))
+ return;
+
+ Document* document = focus->document();
+
+ EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
+ m_mainFrame->editor()->client());
+ if (!client)
+ return;
+ client->setUiGeneratedSelectionChange(true);
+ WebCore::TypingCommand::insertText(document, text,
+ TypingCommand::PreventSpellChecking);
+ client->setUiGeneratedSelectionChange(false);
+}
+
+void WebViewCore::resetFindOnPage()
+{
+ m_searchText.truncate(0);
+ m_matchCount = 0;
+ m_activeMatchIndex = 0;
+ m_activeMatch = 0;
+}
+
+int WebViewCore::findTextOnPage(const WTF::String &text)
+{
+ resetFindOnPage(); // reset even if parameters are bad
+
+ WebCore::Frame* frame = m_mainFrame;
+ if (!frame)
+ return 0;
+
+ m_searchText = text;
+ FindOptions findOptions = WebCore::CaseInsensitive;
+
+ do {
+ frame->document()->markers()->removeMarkers(DocumentMarker::TextMatch);
+ m_matchCount += frame->editor()->countMatchesForText(text, findOptions,
+ 0, true);
+ frame->editor()->setMarkedTextMatchesAreHighlighted(true);
+ frame = frame->tree()->traverseNextWithWrap(false);
+ } while (frame);
+ m_activeMatchIndex = m_matchCount - 1; // prime first findNext
+ return m_matchCount;
+}
+
+int WebViewCore::findNextOnPage(bool forward)
+{
+ if (!m_mainFrame)
+ return -1;
+ if (!m_matchCount)
+ return -1;
+
+ EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
+ m_mainFrame->editor()->client());
+ client->setUiGeneratedSelectionChange(true);
+
+ // Clear previous active match.
+ if (m_activeMatch) {
+ m_mainFrame->document()->markers()->setMarkersActive(
+ m_activeMatch.get(), false);
+ }
+
+ FindOptions findOptions = WebCore::CaseInsensitive
+ | WebCore::StartInSelection | WebCore::WrapAround;
+ if (!forward)
+ findOptions |= WebCore::Backwards;
+
+ // Start from the previous active match.
+ if (m_activeMatch) {
+ m_mainFrame->selection()->setSelection(m_activeMatch.get());
+ }
+
+ bool found = m_mainFrame->editor()->findString(m_searchText, findOptions);
+ if (found) {
+ VisibleSelection selection(m_mainFrame->selection()->selection());
+ if (selection.isNone() || selection.start() == selection.end()) {
+ // Temporary workaround for findString() refusing to select text
+ // marked "-webkit-user-select: none".
+ m_activeMatchIndex = 0;
+ m_activeMatch = 0;
+ } else {
+ // Mark current match "active".
+ if (forward) {
+ ++m_activeMatchIndex;
+ if (m_activeMatchIndex == m_matchCount)
+ m_activeMatchIndex = 0;
+ } else {
+ if (m_activeMatchIndex == 0)
+ m_activeMatchIndex = m_matchCount;
+ --m_activeMatchIndex;
+ }
+ m_activeMatch = selection.firstRange();
+ m_mainFrame->document()->markers()->setMarkersActive(
+ m_activeMatch.get(), true);
+ m_mainFrame->selection()->revealSelection(
+ ScrollAlignment::alignCenterIfNeeded, true);
+ }
+ }
+
+ // Clear selection so it doesn't display.
+ m_mainFrame->selection()->clear();
+ client->setUiGeneratedSelectionChange(false);
+ return m_activeMatchIndex;
+}
+
+String WebViewCore::getText(int startX, int startY, int endX, int endY)
+{
+ String text;
+
+ Vector<VisibleSelection> ranges =
+ getTextRanges(startX, startY, endX, endY);
+
+ for (size_t i = 0; i < ranges.size(); i++) {
+ const VisibleSelection& selection = ranges[i];
+ if (selection.isRange()) {
+ PassRefPtr<Range> range = selection.firstRange();
+ String textInRange = range->text();
+ if (textInRange.length() > 0) {
+ if (text.length() > 0)
+ text.append('\n');
+ text.append(textInRange);
+ }
+ }
+ }
+
+ return text;
+}
+
+/**
+ * Read the persistent locale.
+ */
+void WebViewCore::getLocale(String& language, String& region)
+{
+ char propLang[PROPERTY_VALUE_MAX], propRegn[PROPERTY_VALUE_MAX];
+
+ property_get("persist.sys.language", propLang, "");
+ property_get("persist.sys.country", propRegn, "");
+ if (*propLang == 0 && *propRegn == 0) {
+ /* Set to ro properties, default is en_US */
+ property_get("ro.product.locale.language", propLang, "en");
+ property_get("ro.product.locale.region", propRegn, "US");
+ }
+ language = String(propLang, 2);
+ region = String(propRegn, 2);
+}
+
+void WebViewCore::updateLocale()
+{
+ static String prevLang;
+ static String prevRegn;
+ String language;
+ String region;
+
+ getLocale(language, region);
+
+ if ((language != prevLang) || (region != prevRegn)) {
+ prevLang = language;
+ prevRegn = region;
+ GlyphPageTreeNode::resetRoots();
+ fontCache()->invalidate();
+ }
+}
+
//----------------------------------------------------------------------
// Native JNI methods
//----------------------------------------------------------------------
-static void RevealSelection(JNIEnv *env, jobject obj)
+static void RevealSelection(JNIEnv* env, jobject obj, jint nativeClass)
{
- GET_NATIVE_VIEW(env, obj)->revealSelection();
+ reinterpret_cast<WebViewCore*>(nativeClass)->revealSelection();
}
-static jstring RequestLabel(JNIEnv *env, jobject obj, int framePointer,
- int nodePointer)
+static jstring RequestLabel(JNIEnv* env, jobject obj, jint nativeClass,
+ int framePointer, int nodePointer)
{
- return wtfStringToJstring(env, GET_NATIVE_VIEW(env, obj)->requestLabel(
+ WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
+ return wtfStringToJstring(env, viewImpl->requestLabel(
(WebCore::Frame*) framePointer, (WebCore::Node*) nodePointer));
}
-static void ClearContent(JNIEnv *env, jobject obj)
+static void ClearContent(JNIEnv* env, jobject obj, jint nativeClass)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
-#endif
- WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
+ WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
viewImpl->clearContent();
}
-static void UpdateFrameCacheIfLoading(JNIEnv *env, jobject obj)
-{
- GET_NATIVE_VIEW(env, obj)->updateFrameCacheIfLoading();
-}
-
-static void SetSize(JNIEnv *env, jobject obj, jint width, jint height,
- jint textWrapWidth, jfloat scale, jint screenWidth, jint screenHeight,
- jint anchorX, jint anchorY, jboolean ignoreHeight)
+static void SetSize(JNIEnv* env, jobject obj, jint nativeClass, jint width,
+ jint height, jint textWrapWidth, jfloat scale, jint screenWidth,
+ jint screenHeight, jint anchorX, jint anchorY, jboolean ignoreHeight)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
-#endif
- WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
- LOGV("webviewcore::nativeSetSize(%u %u)\n viewImpl: %p", (unsigned)width, (unsigned)height, viewImpl);
- LOG_ASSERT(viewImpl, "viewImpl not set in nativeSetSize");
+ WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
+ ALOGV("webviewcore::nativeSetSize(%u %u)\n viewImpl: %p", (unsigned)width, (unsigned)height, viewImpl);
+ ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSetSize");
viewImpl->setSizeScreenWidthAndScale(width, height, textWrapWidth, scale,
screenWidth, screenHeight, anchorX, anchorY, ignoreHeight);
}
-static void SetScrollOffset(JNIEnv *env, jobject obj, jint gen, jboolean sendScrollEvent, jint x, jint y)
+static void SetScrollOffset(JNIEnv* env, jobject obj, jint nativeClass,
+ jboolean sendScrollEvent, jint x, jint y)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
-#endif
- WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(viewImpl, "need viewImpl");
+ WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
+ ALOG_ASSERT(viewImpl, "need viewImpl");
- viewImpl->setScrollOffset(gen, sendScrollEvent, x, y);
+ viewImpl->setScrollOffset(sendScrollEvent, x, y);
}
-static void SetGlobalBounds(JNIEnv *env, jobject obj, jint x, jint y, jint h,
- jint v)
+static void SetGlobalBounds(JNIEnv* env, jobject obj, jint nativeClass,
+ jint x, jint y, jint h, jint v)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
-#endif
- WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(viewImpl, "need viewImpl");
+ WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
+ ALOG_ASSERT(viewImpl, "need viewImpl");
viewImpl->setGlobalBounds(x, y, h, v);
}
-static jboolean Key(JNIEnv *env, jobject obj, jint keyCode, jint unichar,
- jint repeatCount, jboolean isShift, jboolean isAlt, jboolean isSym,
- jboolean isDown)
+static jboolean Key(JNIEnv* env, jobject obj, jint nativeClass, jint keyCode,
+ jint unichar, jint repeatCount, jboolean isShift, jboolean isAlt,
+ jboolean isSym, jboolean isDown)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
-#endif
- return GET_NATIVE_VIEW(env, obj)->key(PlatformKeyboardEvent(keyCode,
+ WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
+ return viewImpl->key(PlatformKeyboardEvent(keyCode,
unichar, repeatCount, isDown, isShift, isAlt, isSym));
}
-static void Click(JNIEnv *env, jobject obj, int framePtr, int nodePtr, jboolean fake)
+static void SetInitialFocus(JNIEnv* env, jobject obj, jint nativeClass,
+ jint keyDirection)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
-#endif
- WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(viewImpl, "viewImpl not set in Click");
-
- viewImpl->click(reinterpret_cast<WebCore::Frame*>(framePtr),
- reinterpret_cast<WebCore::Node*>(nodePtr), fake);
+ WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
+ viewImpl->setInitialFocus(PlatformKeyboardEvent(keyDirection,
+ 0, 0, false, false, false, false));
}
-static void ContentInvalidateAll(JNIEnv *env, jobject obj)
+static void ContentInvalidateAll(JNIEnv* env, jobject obj, jint nativeClass)
{
- GET_NATIVE_VIEW(env, obj)->contentInvalidateAll();
+ reinterpret_cast<WebViewCore*>(nativeClass)->contentInvalidateAll();
}
-static void DeleteSelection(JNIEnv *env, jobject obj, jint start, jint end,
- jint textGeneration)
+static void DeleteSelection(JNIEnv* env, jobject obj, jint nativeClass,
+ jint start, jint end, jint textGeneration)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
-#endif
- WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
+ WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
viewImpl->deleteSelection(start, end, textGeneration);
}
-static void SetSelection(JNIEnv *env, jobject obj, jint start, jint end)
+static void SetSelection(JNIEnv* env, jobject obj, jint nativeClass,
+ jint start, jint end)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
-#endif
- WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
+ WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
viewImpl->setSelection(start, end);
}
-static jstring ModifySelection(JNIEnv *env, jobject obj, jint direction, jint granularity)
+static jstring ModifySelection(JNIEnv* env, jobject obj, jint nativeClass,
+ jint direction, jint granularity)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
-#endif
- WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
+ WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
String selectionString = viewImpl->modifySelection(direction, granularity);
return wtfStringToJstring(env, selectionString);
}
-static void ReplaceTextfieldText(JNIEnv *env, jobject obj,
+static void ReplaceTextfieldText(JNIEnv* env, jobject obj, jint nativeClass,
jint oldStart, jint oldEnd, jstring replace, jint start, jint end,
jint textGeneration)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
-#endif
- WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
+ WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
WTF::String webcoreString = jstringToWtfString(env, replace);
viewImpl->replaceTextfieldText(oldStart,
oldEnd, webcoreString, start, end, textGeneration);
}
-static void PassToJs(JNIEnv *env, jobject obj,
+static void PassToJs(JNIEnv* env, jobject obj, jint nativeClass,
jint generation, jstring currentText, jint keyCode,
jint keyValue, jboolean down, jboolean cap, jboolean fn, jboolean sym)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
-#endif
WTF::String current = jstringToWtfString(env, currentText);
- GET_NATIVE_VIEW(env, obj)->passToJs(generation, current,
+ reinterpret_cast<WebViewCore*>(nativeClass)->passToJs(generation, current,
PlatformKeyboardEvent(keyCode, keyValue, 0, down, cap, fn, sym));
}
-static void ScrollFocusedTextInput(JNIEnv *env, jobject obj, jfloat xPercent,
- jint y)
+static void ScrollFocusedTextInput(JNIEnv* env, jobject obj, jint nativeClass,
+ jfloat xPercent, jint y, jobject contentBounds)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
-#endif
- WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
- viewImpl->scrollFocusedTextInput(xPercent, y);
+ WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
+ IntRect bounds = viewImpl->scrollFocusedTextInput(xPercent, y);
+ if (contentBounds)
+ GraphicsJNI::irect_to_jrect(bounds, env, contentBounds);
}
-static void SetFocusControllerActive(JNIEnv *env, jobject obj, jboolean active)
+static void SetFocusControllerActive(JNIEnv* env, jobject obj, jint nativeClass,
+ jboolean active)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
-#endif
- LOGV("webviewcore::nativeSetFocusControllerActive()\n");
- WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(viewImpl, "viewImpl not set in nativeSetFocusControllerActive");
+ ALOGV("webviewcore::nativeSetFocusControllerActive()\n");
+ WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
+ ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSetFocusControllerActive");
viewImpl->setFocusControllerActive(active);
}
-static void SaveDocumentState(JNIEnv *env, jobject obj, jint frame)
+static void SaveDocumentState(JNIEnv* env, jobject obj, jint nativeClass)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
-#endif
- LOGV("webviewcore::nativeSaveDocumentState()\n");
- WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(viewImpl, "viewImpl not set in nativeSaveDocumentState");
- viewImpl->saveDocumentState((WebCore::Frame*) frame);
+ ALOGV("webviewcore::nativeSaveDocumentState()\n");
+ WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
+ ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSaveDocumentState");
+ viewImpl->saveDocumentState(viewImpl->focusedFrame());
}
void WebViewCore::addVisitedLink(const UChar* string, int length)
@@ -4113,53 +4536,26 @@ void WebViewCore::addVisitedLink(const UChar* string, int length)
m_groupForVisitedLinks->addVisitedLink(string, length);
}
-static bool UpdateLayers(JNIEnv *env, jobject obj, jint nativeClass, jint jbaseLayer)
-{
- WebViewCore* viewImpl = (WebViewCore*) nativeClass;
- BaseLayerAndroid* baseLayer = (BaseLayerAndroid*) jbaseLayer;
- if (baseLayer) {
- LayerAndroid* root = static_cast<LayerAndroid*>(baseLayer->getChild(0));
- if (root)
- return viewImpl->updateLayers(root);
- }
- return true;
-}
-
-static void NotifyAnimationStarted(JNIEnv *env, jobject obj, jint nativeClass)
+static void NotifyAnimationStarted(JNIEnv* env, jobject obj, jint nativeClass)
{
WebViewCore* viewImpl = (WebViewCore*) nativeClass;
viewImpl->notifyAnimationStarted();
}
-static jint RecordContent(JNIEnv *env, jobject obj, jobject region, jobject pt)
+static jint RecordContent(JNIEnv* env, jobject obj, jint nativeClass, jobject pt)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
-#endif
- WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
- SkRegion* nativeRegion = GraphicsJNI::getNativeRegion(env, region);
+ WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
SkIPoint nativePt;
- BaseLayerAndroid* result = viewImpl->recordContent(nativeRegion, &nativePt);
+ BaseLayerAndroid* result = viewImpl->recordContent(&nativePt);
GraphicsJNI::ipoint_to_jpoint(nativePt, env, pt);
return reinterpret_cast<jint>(result);
}
-static void SplitContent(JNIEnv *env, jobject obj, jint content)
-{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
-#endif
- WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
- viewImpl->splitContent(reinterpret_cast<PictureSet*>(content));
-}
-
-static void SendListBoxChoice(JNIEnv* env, jobject obj, jint choice)
+static void SendListBoxChoice(JNIEnv* env, jobject obj, jint nativeClass,
+ jint choice)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
-#endif
- WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoice");
+ WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
+ ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoice");
viewImpl->popupReply(choice);
}
@@ -4169,14 +4565,11 @@ static void SendListBoxChoice(JNIEnv* env, jobject obj, jint choice)
// number of items in the average multiple-select listbox.
#define PREPARED_LISTBOX_STORAGE 10
-static void SendListBoxChoices(JNIEnv* env, jobject obj, jbooleanArray jArray,
- jint size)
+static void SendListBoxChoices(JNIEnv* env, jobject obj, jint nativeClass,
+ jbooleanArray jArray, jint size)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
-#endif
- WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoices");
+ WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
+ ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoices");
jboolean* ptrArray = env->GetBooleanArrayElements(jArray, 0);
SkAutoSTMalloc<PREPARED_LISTBOX_STORAGE, int> storage(size);
int* array = storage.get();
@@ -4190,21 +4583,19 @@ static void SendListBoxChoices(JNIEnv* env, jobject obj, jbooleanArray jArray,
viewImpl->popupReply(array, count);
}
-static jstring FindAddress(JNIEnv *env, jobject obj, jstring addr,
- jboolean caseInsensitive)
+// TODO: Move this to WebView.cpp since it is only needed there
+static jstring FindAddress(JNIEnv* env, jobject obj, jstring addr,
+ jboolean caseInsensitive)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
-#endif
if (!addr)
return 0;
int length = env->GetStringLength(addr);
if (!length)
return 0;
const jchar* addrChars = env->GetStringChars(addr, 0);
- int start, end;
- bool success = CacheBuilder::FindAddress(addrChars, length,
- &start, &end, caseInsensitive) == CacheBuilder::FOUND_COMPLETE;
+ size_t start, end;
+ AddressDetector detector;
+ bool success = detector.FindContent(addrChars, addrChars + length, &start, &end);
jstring ret = 0;
if (success)
ret = env->NewString(addrChars + start, end - start);
@@ -4212,15 +4603,12 @@ static jstring FindAddress(JNIEnv *env, jobject obj, jstring addr,
return ret;
}
-static jboolean HandleTouchEvent(JNIEnv *env, jobject obj, jint action, jintArray idArray,
- jintArray xArray, jintArray yArray,
- jint count, jint actionIndex, jint metaState)
+static jint HandleTouchEvent(JNIEnv* env, jobject obj, jint nativeClass,
+ jint action, jintArray idArray, jintArray xArray, jintArray yArray,
+ jint count, jint actionIndex, jint metaState)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
-#endif
- WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
+ WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
+ ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
jint* ptrIdArray = env->GetIntArrayElements(idArray, 0);
jint* ptrXArray = env->GetIntArrayElements(xArray, 0);
jint* ptrYArray = env->GetIntArrayElements(yArray, 0);
@@ -4238,105 +4626,53 @@ static jboolean HandleTouchEvent(JNIEnv *env, jobject obj, jint action, jintArra
return viewImpl->handleTouchEvent(action, ids, points, actionIndex, metaState);
}
-static void TouchUp(JNIEnv *env, jobject obj, jint touchGeneration,
- jint frame, jint node, jint x, jint y)
+static bool MouseClick(JNIEnv* env, jobject obj, jint nativeClass)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
-#endif
- WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
- viewImpl->touchUp(touchGeneration,
- (WebCore::Frame*) frame, (WebCore::Node*) node, x, y);
+ WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
+ return viewImpl->performMouseClick();
}
-static jstring RetrieveHref(JNIEnv *env, jobject obj, jint x, jint y)
+static jstring RetrieveHref(JNIEnv* env, jobject obj, jint nativeClass,
+ jint x, jint y)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
-#endif
- WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
+ WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
+ ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
WTF::String result = viewImpl->retrieveHref(x, y);
if (!result.isEmpty())
return wtfStringToJstring(env, result);
return 0;
}
-static jstring RetrieveAnchorText(JNIEnv *env, jobject obj, jint x, jint y)
+static jstring RetrieveAnchorText(JNIEnv* env, jobject obj, jint nativeClass,
+ jint x, jint y)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
-#endif
- WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
+ WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
+ ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
WTF::String result = viewImpl->retrieveAnchorText(x, y);
if (!result.isEmpty())
return wtfStringToJstring(env, result);
return 0;
}
-static jstring RetrieveImageSource(JNIEnv *env, jobject obj, jint x, jint y)
-{
- WTF::String result = GET_NATIVE_VIEW(env, obj)->retrieveImageSource(x, y);
- return !result.isEmpty() ? wtfStringToJstring(env, result) : 0;
-}
-
-static void StopPaintingCaret(JNIEnv *env, jobject obj)
-{
- GET_NATIVE_VIEW(env, obj)->setShouldPaintCaret(false);
-}
-
-static void MoveFocus(JNIEnv *env, jobject obj, jint framePtr, jint nodePtr)
-{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
-#endif
- WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
- viewImpl->moveFocus((WebCore::Frame*) framePtr, (WebCore::Node*) nodePtr);
-}
-
-static void MoveMouse(JNIEnv *env, jobject obj, jint frame,
+static jstring RetrieveImageSource(JNIEnv* env, jobject obj, jint nativeClass,
jint x, jint y)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
-#endif
- WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
- viewImpl->moveMouse((WebCore::Frame*) frame, x, y);
-}
-
-static void MoveMouseIfLatest(JNIEnv *env, jobject obj, jint moveGeneration,
- jint frame, jint x, jint y)
-{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
-#endif
- WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
- viewImpl->moveMouseIfLatest(moveGeneration,
- (WebCore::Frame*) frame, x, y);
+ WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
+ WTF::String result = viewImpl->retrieveImageSource(x, y);
+ return !result.isEmpty() ? wtfStringToJstring(env, result) : 0;
}
-static void UpdateFrameCache(JNIEnv *env, jobject obj)
+static void MoveMouse(JNIEnv* env, jobject obj, jint nativeClass, jint x, jint y)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
-#endif
- WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
- viewImpl->updateFrameCache();
+ WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
+ ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
+ viewImpl->moveMouse(x, y);
}
-static jint GetContentMinPrefWidth(JNIEnv *env, jobject obj)
+static jint GetContentMinPrefWidth(JNIEnv* env, jobject obj, jint nativeClass)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
-#endif
- WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
+ WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
+ ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
WebCore::Frame* frame = viewImpl->mainFrame();
if (frame) {
@@ -4351,13 +4687,11 @@ static jint GetContentMinPrefWidth(JNIEnv *env, jobject obj)
return 0;
}
-static void SetViewportSettingsFromNative(JNIEnv *env, jobject obj)
+static void SetViewportSettingsFromNative(JNIEnv* env, jobject obj,
+ jint nativeClass)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
-#endif
- WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
+ WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
+ ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
WebCore::Settings* s = viewImpl->mainFrame()->page()->settings();
if (!s)
@@ -4374,66 +4708,49 @@ static void SetViewportSettingsFromNative(JNIEnv *env, jobject obj)
#endif
}
-static void SetBackgroundColor(JNIEnv *env, jobject obj, jint color)
+static void SetBackgroundColor(JNIEnv* env, jobject obj, jint nativeClass,
+ jint color)
{
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
-#endif
- WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
+ WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
+ ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
viewImpl->setBackgroundColor((SkColor) color);
}
-static void DumpDomTree(JNIEnv *env, jobject obj, jboolean useFile)
+static void DumpDomTree(JNIEnv* env, jobject obj, jint nativeClass,
+ jboolean useFile)
{
- WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
+ WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
+ ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
viewImpl->dumpDomTree(useFile);
}
-static void DumpRenderTree(JNIEnv *env, jobject obj, jboolean useFile)
+static void DumpRenderTree(JNIEnv* env, jobject obj, jint nativeClass,
+ jboolean useFile)
{
- WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
+ WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
+ ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
viewImpl->dumpRenderTree(useFile);
}
-static void DumpNavTree(JNIEnv *env, jobject obj)
-{
- WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
-
- viewImpl->dumpNavTree();
-}
-
-static void DumpV8Counters(JNIEnv*, jobject)
+static void SetJsFlags(JNIEnv* env, jobject obj, jint nativeClass, jstring flags)
{
-#if USE(V8)
-#ifdef ANDROID_INSTRUMENT
- V8Counters::dumpCounters();
-#endif
-#endif
-}
-
-static void SetJsFlags(JNIEnv *env, jobject obj, jstring flags)
-{
-#if USE(V8)
WTF::String flagsString = jstringToWtfString(env, flags);
WTF::CString utf8String = flagsString.utf8();
WebCore::ScriptController::setFlags(utf8String.data(), utf8String.length());
-#endif
}
// Called from the Java side to set a new quota for the origin or new appcache
// max size in response to a notification that the original quota was exceeded or
// that the appcache has reached its maximum size.
-static void SetNewStorageLimit(JNIEnv* env, jobject obj, jlong quota) {
+static void SetNewStorageLimit(JNIEnv* env, jobject obj, jint nativeClass,
+ jlong quota)
+{
#if ENABLE(DATABASE) || ENABLE(OFFLINE_WEB_APPLICATIONS)
- WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
+ WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
Frame* frame = viewImpl->mainFrame();
// The main thread is blocked awaiting this response, so now we can wake it
@@ -4444,93 +4761,102 @@ static void SetNewStorageLimit(JNIEnv* env, jobject obj, jlong quota) {
}
// Called from Java to provide a Geolocation permission state for the specified origin.
-static void GeolocationPermissionsProvide(JNIEnv* env, jobject obj, jstring origin, jboolean allow, jboolean remember) {
- WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
+static void GeolocationPermissionsProvide(JNIEnv* env, jobject obj,
+ jint nativeClass, jstring origin, jboolean allow, jboolean remember)
+{
+ WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
Frame* frame = viewImpl->mainFrame();
ChromeClientAndroid* chromeClient = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client());
chromeClient->provideGeolocationPermissions(jstringToWtfString(env, origin), allow, remember);
}
-static void RegisterURLSchemeAsLocal(JNIEnv* env, jobject obj, jstring scheme) {
-#ifdef ANDROID_INSTRUMENT
- TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
-#endif
+static void RegisterURLSchemeAsLocal(JNIEnv* env, jobject obj, jint nativeClass,
+ jstring scheme)
+{
WebCore::SchemeRegistry::registerURLSchemeAsLocal(jstringToWtfString(env, scheme));
}
-static bool FocusBoundsChanged(JNIEnv* env, jobject obj)
+static bool FocusBoundsChanged(JNIEnv* env, jobject obj, jint nativeClass)
{
- return GET_NATIVE_VIEW(env, obj)->focusBoundsChanged();
+ return reinterpret_cast<WebViewCore*>(nativeClass)->focusBoundsChanged();
}
-static void SetIsPaused(JNIEnv* env, jobject obj, jboolean isPaused)
+static void SetIsPaused(JNIEnv* env, jobject obj, jint nativeClass,
+ jboolean isPaused)
{
// tell the webcore thread to stop thinking while we do other work
// (selection and scrolling). This has nothing to do with the lifecycle
// pause and resume.
- GET_NATIVE_VIEW(env, obj)->setIsPaused(isPaused);
+ reinterpret_cast<WebViewCore*>(nativeClass)->setIsPaused(isPaused);
}
-static void Pause(JNIEnv* env, jobject obj)
+static void Pause(JNIEnv* env, jobject obj, jint nativeClass)
{
// This is called for the foreground tab when the browser is put to the
// background (and also for any tab when it is put to the background of the
// browser). The browser can only be killed by the system when it is in the
// background, so saving the Geolocation permission state now ensures that
// is maintained when the browser is killed.
- ChromeClient* chromeClient = GET_NATIVE_VIEW(env, obj)->mainFrame()->page()->chrome()->client();
+ WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
+ ChromeClient* chromeClient = viewImpl->mainFrame()->page()->chrome()->client();
ChromeClientAndroid* chromeClientAndroid = static_cast<ChromeClientAndroid*>(chromeClient);
chromeClientAndroid->storeGeolocationPermissions();
- Frame* mainFrame = GET_NATIVE_VIEW(env, obj)->mainFrame();
+ Frame* mainFrame = viewImpl->mainFrame();
for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) {
Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation();
if (geolocation)
geolocation->suspend();
}
+ if (mainFrame)
+ mainFrame->settings()->setMinDOMTimerInterval(BACKGROUND_TIMER_INTERVAL);
- GET_NATIVE_VIEW(env, obj)->deviceMotionAndOrientationManager()->maybeSuspendClients();
+ viewImpl->deviceMotionAndOrientationManager()->maybeSuspendClients();
ANPEvent event;
SkANP::InitEvent(&event, kLifecycle_ANPEventType);
event.data.lifecycle.action = kPause_ANPLifecycleAction;
- GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event);
+ viewImpl->sendPluginEvent(event);
- GET_NATIVE_VIEW(env, obj)->setIsPaused(true);
+ viewImpl->setIsPaused(true);
}
-static void Resume(JNIEnv* env, jobject obj)
+static void Resume(JNIEnv* env, jobject obj, jint nativeClass)
{
- Frame* mainFrame = GET_NATIVE_VIEW(env, obj)->mainFrame();
+ WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
+ Frame* mainFrame = viewImpl->mainFrame();
for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) {
Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation();
if (geolocation)
geolocation->resume();
}
+ if (mainFrame)
+ mainFrame->settings()->setMinDOMTimerInterval(FOREGROUND_TIMER_INTERVAL);
- GET_NATIVE_VIEW(env, obj)->deviceMotionAndOrientationManager()->maybeResumeClients();
+ viewImpl->deviceMotionAndOrientationManager()->maybeResumeClients();
ANPEvent event;
SkANP::InitEvent(&event, kLifecycle_ANPEventType);
event.data.lifecycle.action = kResume_ANPLifecycleAction;
- GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event);
+ viewImpl->sendPluginEvent(event);
- GET_NATIVE_VIEW(env, obj)->setIsPaused(false);
+ viewImpl->setIsPaused(false);
}
-static void FreeMemory(JNIEnv* env, jobject obj)
+static void FreeMemory(JNIEnv* env, jobject obj, jint nativeClass)
{
ANPEvent event;
SkANP::InitEvent(&event, kLifecycle_ANPEventType);
event.data.lifecycle.action = kFreeMemory_ANPLifecycleAction;
- GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event);
+ reinterpret_cast<WebViewCore*>(nativeClass)->sendPluginEvent(event);
}
-static void ProvideVisitedHistory(JNIEnv *env, jobject obj, jobject hist)
+static void ProvideVisitedHistory(JNIEnv* env, jobject obj, jint nativeClass,
+ jobject hist)
{
- WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
+ WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
+ ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
jobjectArray array = static_cast<jobjectArray>(hist);
@@ -4545,78 +4871,38 @@ static void ProvideVisitedHistory(JNIEnv *env, jobject obj, jobject hist)
}
}
-static void PluginSurfaceReady(JNIEnv* env, jobject obj)
+static void PluginSurfaceReady(JNIEnv* env, jobject obj, jint nativeClass)
{
- WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
+ WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
if (viewImpl)
viewImpl->sendPluginSurfaceReady();
}
// Notification from the UI thread that the plugin's full-screen surface has been discarded
-static void FullScreenPluginHidden(JNIEnv* env, jobject obj, jint npp)
+static void FullScreenPluginHidden(JNIEnv* env, jobject obj, jint nativeClass,
+ jint npp)
{
- WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
+ WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
PluginWidgetAndroid* plugin = viewImpl->getPluginWidget((NPP)npp);
if (plugin)
plugin->exitFullScreen(false);
}
-static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj)
-{
- int L, T, R, B;
- GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B);
- return WebCore::IntRect(L, T, R - L, B - T);
-}
-
-static bool ValidNodeAndBounds(JNIEnv *env, jobject obj, int frame, int node,
- jobject rect)
-{
- IntRect nativeRect = jrect_to_webrect(env, rect);
- return GET_NATIVE_VIEW(env, obj)->validNodeAndBounds(
- reinterpret_cast<Frame*>(frame),
- reinterpret_cast<Node*>(node), nativeRect);
-}
-
-static jobject GetTouchHighlightRects(JNIEnv* env, jobject obj, 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 = GET_NATIVE_VIEW(env, obj);
+ WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
if (!viewImpl)
return 0;
- Vector<IntRect> rects = viewImpl->getTouchHighlightRects(x, y, slop);
- if (rects.isEmpty())
- return 0;
-
- jclass arrayClass = env->FindClass("java/util/ArrayList");
- LOG_ASSERT(arrayClass, "Could not find java/util/ArrayList");
- jmethodID init = env->GetMethodID(arrayClass, "<init>", "(I)V");
- LOG_ASSERT(init, "Could not find constructor for ArrayList");
- jobject array = env->NewObject(arrayClass, init, rects.size());
- LOG_ASSERT(array, "Could not create a new ArrayList");
- jmethodID add = env->GetMethodID(arrayClass, "add", "(Ljava/lang/Object;)Z");
- LOG_ASSERT(add, "Could not find add method on ArrayList");
- jclass rectClass = env->FindClass("android/graphics/Rect");
- LOG_ASSERT(rectClass, "Could not find android/graphics/Rect");
- jmethodID rectinit = env->GetMethodID(rectClass, "<init>", "(IIII)V");
- LOG_ASSERT(rectinit, "Could not find init method on Rect");
-
- 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->CallBooleanMethod(array, add, rect);
- env->DeleteLocalRef(rect);
- }
- }
-
- env->DeleteLocalRef(rectClass);
- env->DeleteLocalRef(arrayClass);
- return array;
+ AndroidHitTestResult result = viewImpl->hitTestAtPoint(x, y, slop, doMoveMouse);
+ return result.createJavaObject(env);
}
-static void AutoFillForm(JNIEnv* env, jobject obj, jint queryId)
+static void AutoFillForm(JNIEnv* env, jobject obj, jint nativeClass,
+ jint queryId)
{
#if ENABLE(WEB_AUTOFILL)
- WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
+ WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
if (!viewImpl)
return;
@@ -4629,19 +4915,87 @@ static void AutoFillForm(JNIEnv* env, jobject obj, jint queryId)
#endif
}
-static void CloseIdleConnections(JNIEnv* env, jobject obj)
+static void CloseIdleConnections(JNIEnv* env, jobject obj, jint nativeClass)
{
-#if USE(CHROME_NETWORK_STACK)
WebCache::get(true)->closeIdleConnections();
WebCache::get(false)->closeIdleConnections();
-#endif
}
-static void ScrollRenderLayer(JNIEnv* env, jobject obj, jint layer, jobject jRect)
+static void nativeCertTrustChanged(JNIEnv *env, jobject obj)
+{
+ WebCache::get(true)->certTrustChanged();
+ WebCache::get(false)->certTrustChanged();
+}
+
+static void ScrollRenderLayer(JNIEnv* env, jobject obj, jint nativeClass,
+ jint layer, jobject jRect)
{
SkRect rect;
GraphicsJNI::jrect_to_rect(env, jRect, &rect);
- GET_NATIVE_VIEW(env, obj)->scrollRenderLayer(layer, rect);
+ reinterpret_cast<WebViewCore*>(nativeClass)->scrollRenderLayer(layer, rect);
+}
+
+static void DeleteText(JNIEnv* env, jobject obj, jint nativeClass,
+ jint startX, jint startY, jint endX, jint endY)
+{
+ WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
+ viewImpl->deleteText(startX, startY, endX, endY);
+}
+
+static void InsertText(JNIEnv* env, jobject obj, jint nativeClass,
+ jstring text)
+{
+ WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
+ WTF::String wtfText = jstringToWtfString(env, text);
+ viewImpl->insertText(wtfText);
+}
+
+static jobject GetText(JNIEnv* env, jobject obj, jint nativeClass,
+ jint startX, jint startY, jint endX, jint endY)
+{
+ WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
+ WTF::String text = viewImpl->getText(startX, startY, endX, endY);
+ return text.isEmpty() ? 0 : wtfStringToJstring(env, text);
+}
+
+static void SelectText(JNIEnv* env, jobject obj, jint nativeClass,
+ jint startX, jint startY, jint endX, jint endY)
+{
+ WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
+ viewImpl->selectText(startX, startY, endX, endY);
+}
+
+static void ClearSelection(JNIEnv* env, jobject obj, jint nativeClass)
+{
+ WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
+ viewImpl->focusedFrame()->selection()->clear();
+}
+
+static bool SelectWordAt(JNIEnv* env, jobject obj, jint nativeClass, jint x, jint y)
+{
+ WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
+ return viewImpl->selectWordAt(x, y);
+}
+
+static void SelectAll(JNIEnv* env, jobject obj, jint nativeClass)
+{
+ WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
+ viewImpl->focusedFrame()->selection()->selectAll();
+}
+
+static int FindAll(JNIEnv* env, jobject obj, jint nativeClass,
+ jstring text)
+{
+ WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
+ WTF::String wtfText = jstringToWtfString(env, text);
+ return viewImpl->findTextOnPage(wtfText);
+}
+
+static int FindNext(JNIEnv* env, jobject obj, jint nativeClass,
+ jboolean forward)
+{
+ WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
+ return viewImpl->findNextOnPage(forward);
}
// ----------------------------------------------------------------------------
@@ -4650,164 +5004,159 @@ static void ScrollRenderLayer(JNIEnv* env, jobject obj, jint layer, jobject jRec
* JNI registration.
*/
static JNINativeMethod gJavaWebViewCoreMethods[] = {
- { "nativeClearContent", "()V",
+ { "nativeClearContent", "(I)V",
(void*) ClearContent },
- { "nativeFocusBoundsChanged", "()Z",
+ { "nativeFocusBoundsChanged", "(I)Z",
(void*) FocusBoundsChanged } ,
- { "nativeKey", "(IIIZZZZ)Z",
+ { "nativeKey", "(IIIIZZZZ)Z",
(void*) Key },
- { "nativeClick", "(IIZ)V",
- (void*) Click },
- { "nativeContentInvalidateAll", "()V",
+ { "nativeContentInvalidateAll", "(I)V",
(void*) ContentInvalidateAll },
- { "nativeSendListBoxChoices", "([ZI)V",
+ { "nativeSendListBoxChoices", "(I[ZI)V",
(void*) SendListBoxChoices },
- { "nativeSendListBoxChoice", "(I)V",
+ { "nativeSendListBoxChoice", "(II)V",
(void*) SendListBoxChoice },
- { "nativeSetSize", "(IIIFIIIIZ)V",
+ { "nativeSetSize", "(IIIIFIIIIZ)V",
(void*) SetSize },
{ "nativeSetScrollOffset", "(IZII)V",
(void*) SetScrollOffset },
- { "nativeSetGlobalBounds", "(IIII)V",
+ { "nativeSetGlobalBounds", "(IIIII)V",
(void*) SetGlobalBounds },
- { "nativeSetSelection", "(II)V",
+ { "nativeSetSelection", "(III)V",
(void*) SetSelection } ,
- { "nativeModifySelection", "(II)Ljava/lang/String;",
+ { "nativeModifySelection", "(III)Ljava/lang/String;",
(void*) ModifySelection },
- { "nativeDeleteSelection", "(III)V",
+ { "nativeDeleteSelection", "(IIII)V",
(void*) DeleteSelection } ,
- { "nativeReplaceTextfieldText", "(IILjava/lang/String;III)V",
+ { "nativeReplaceTextfieldText", "(IIILjava/lang/String;III)V",
(void*) ReplaceTextfieldText } ,
- { "nativeMoveFocus", "(II)V",
- (void*) MoveFocus },
{ "nativeMoveMouse", "(III)V",
(void*) MoveMouse },
- { "nativeMoveMouseIfLatest", "(IIII)V",
- (void*) MoveMouseIfLatest },
- { "passToJs", "(ILjava/lang/String;IIZZZZ)V",
+ { "passToJs", "(IILjava/lang/String;IIZZZZ)V",
(void*) PassToJs },
- { "nativeScrollFocusedTextInput", "(FI)V",
+ { "nativeScrollFocusedTextInput", "(IFILandroid/graphics/Rect;)V",
(void*) ScrollFocusedTextInput },
- { "nativeSetFocusControllerActive", "(Z)V",
+ { "nativeSetFocusControllerActive", "(IZ)V",
(void*) SetFocusControllerActive },
{ "nativeSaveDocumentState", "(I)V",
(void*) SaveDocumentState },
{ "nativeFindAddress", "(Ljava/lang/String;Z)Ljava/lang/String;",
(void*) FindAddress },
- { "nativeHandleTouchEvent", "(I[I[I[IIII)Z",
- (void*) HandleTouchEvent },
- { "nativeTouchUp", "(IIIII)V",
- (void*) TouchUp },
- { "nativeRetrieveHref", "(II)Ljava/lang/String;",
+ { "nativeHandleTouchEvent", "(II[I[I[IIII)I",
+ (void*) HandleTouchEvent },
+ { "nativeMouseClick", "(I)Z",
+ (void*) MouseClick },
+ { "nativeRetrieveHref", "(III)Ljava/lang/String;",
(void*) RetrieveHref },
- { "nativeRetrieveAnchorText", "(II)Ljava/lang/String;",
+ { "nativeRetrieveAnchorText", "(III)Ljava/lang/String;",
(void*) RetrieveAnchorText },
- { "nativeRetrieveImageSource", "(II)Ljava/lang/String;",
+ { "nativeRetrieveImageSource", "(III)Ljava/lang/String;",
(void*) RetrieveImageSource },
- { "nativeStopPaintingCaret", "()V",
- (void*) StopPaintingCaret },
- { "nativeUpdateFrameCache", "()V",
- (void*) UpdateFrameCache },
- { "nativeGetContentMinPrefWidth", "()I",
+ { "nativeGetContentMinPrefWidth", "(I)I",
(void*) GetContentMinPrefWidth },
- { "nativeUpdateLayers", "(II)Z",
- (void*) UpdateLayers },
{ "nativeNotifyAnimationStarted", "(I)V",
(void*) NotifyAnimationStarted },
- { "nativeRecordContent", "(Landroid/graphics/Region;Landroid/graphics/Point;)I",
+ { "nativeRecordContent", "(ILandroid/graphics/Point;)I",
(void*) RecordContent },
- { "setViewportSettingsFromNative", "()V",
+ { "setViewportSettingsFromNative", "(I)V",
(void*) SetViewportSettingsFromNative },
- { "nativeSplitContent", "(I)V",
- (void*) SplitContent },
- { "nativeSetBackgroundColor", "(I)V",
+ { "nativeSetBackgroundColor", "(II)V",
(void*) SetBackgroundColor },
- { "nativeRegisterURLSchemeAsLocal", "(Ljava/lang/String;)V",
+ { "nativeRegisterURLSchemeAsLocal", "(ILjava/lang/String;)V",
(void*) RegisterURLSchemeAsLocal },
- { "nativeDumpDomTree", "(Z)V",
+ { "nativeDumpDomTree", "(IZ)V",
(void*) DumpDomTree },
- { "nativeDumpRenderTree", "(Z)V",
+ { "nativeDumpRenderTree", "(IZ)V",
(void*) DumpRenderTree },
- { "nativeDumpNavTree", "()V",
- (void*) DumpNavTree },
- { "nativeDumpV8Counters", "()V",
- (void*) DumpV8Counters },
- { "nativeSetNewStorageLimit", "(J)V",
+ { "nativeSetNewStorageLimit", "(IJ)V",
(void*) SetNewStorageLimit },
- { "nativeGeolocationPermissionsProvide", "(Ljava/lang/String;ZZ)V",
+ { "nativeGeolocationPermissionsProvide", "(ILjava/lang/String;ZZ)V",
(void*) GeolocationPermissionsProvide },
- { "nativeSetIsPaused", "(Z)V", (void*) SetIsPaused },
- { "nativePause", "()V", (void*) Pause },
- { "nativeResume", "()V", (void*) Resume },
- { "nativeFreeMemory", "()V", (void*) FreeMemory },
- { "nativeSetJsFlags", "(Ljava/lang/String;)V", (void*) SetJsFlags },
- { "nativeRequestLabel", "(II)Ljava/lang/String;",
+ { "nativeSetIsPaused", "(IZ)V", (void*) SetIsPaused },
+ { "nativePause", "(I)V", (void*) Pause },
+ { "nativeResume", "(I)V", (void*) Resume },
+ { "nativeFreeMemory", "(I)V", (void*) FreeMemory },
+ { "nativeSetJsFlags", "(ILjava/lang/String;)V", (void*) SetJsFlags },
+ { "nativeRequestLabel", "(III)Ljava/lang/String;",
(void*) RequestLabel },
- { "nativeRevealSelection", "()V", (void*) RevealSelection },
- { "nativeUpdateFrameCacheIfLoading", "()V",
- (void*) UpdateFrameCacheIfLoading },
- { "nativeProvideVisitedHistory", "([Ljava/lang/String;)V",
+ { "nativeRevealSelection", "(I)V", (void*) RevealSelection },
+ { "nativeProvideVisitedHistory", "(I[Ljava/lang/String;)V",
(void*) ProvideVisitedHistory },
- { "nativeFullScreenPluginHidden", "(I)V",
+ { "nativeFullScreenPluginHidden", "(II)V",
(void*) FullScreenPluginHidden },
- { "nativePluginSurfaceReady", "()V",
+ { "nativePluginSurfaceReady", "(I)V",
(void*) PluginSurfaceReady },
- { "nativeValidNodeAndBounds", "(IILandroid/graphics/Rect;)Z",
- (void*) ValidNodeAndBounds },
- { "nativeGetTouchHighlightRects", "(III)Ljava/util/ArrayList;",
- (void*) GetTouchHighlightRects },
- { "nativeAutoFillForm", "(I)V",
+ { "nativeHitTest", "(IIIIZ)Landroid/webkit/WebViewCore$WebKitHitTest;",
+ (void*) HitTest },
+ { "nativeAutoFillForm", "(II)V",
(void*) AutoFillForm },
- { "nativeScrollLayer", "(ILandroid/graphics/Rect;)V",
+ { "nativeScrollLayer", "(IILandroid/graphics/Rect;)V",
(void*) ScrollRenderLayer },
- { "nativeCloseIdleConnections", "()V",
+ { "nativeCloseIdleConnections", "(I)V",
(void*) CloseIdleConnections },
+ { "nativeDeleteText", "(IIIII)V",
+ (void*) DeleteText },
+ { "nativeInsertText", "(ILjava/lang/String;)V",
+ (void*) InsertText },
+ { "nativeGetText", "(IIIII)Ljava/lang/String;",
+ (void*) GetText },
+ { "nativeSelectText", "(IIIII)V",
+ (void*) SelectText },
+ { "nativeClearTextSelection", "(I)V",
+ (void*) ClearSelection },
+ { "nativeSelectWordAt", "(III)Z",
+ (void*) SelectWordAt },
+ { "nativeSelectAll", "(I)V",
+ (void*) SelectAll },
+ { "nativeCertTrustChanged","()V",
+ (void*) nativeCertTrustChanged },
+ { "nativeFindAll", "(ILjava/lang/String;)I",
+ (void*) FindAll },
+ { "nativeFindNext", "(IZ)I",
+ (void*) FindNext },
+ { "nativeSetInitialFocus", "(II)V", (void*) SetInitialFocus },
};
int registerWebViewCore(JNIEnv* env)
{
jclass widget = env->FindClass("android/webkit/WebViewCore");
- LOG_ASSERT(widget,
+ ALOG_ASSERT(widget,
"Unable to find class android/webkit/WebViewCore");
gWebViewCoreFields.m_nativeClass = env->GetFieldID(widget, "mNativeClass",
"I");
- LOG_ASSERT(gWebViewCoreFields.m_nativeClass,
+ ALOG_ASSERT(gWebViewCoreFields.m_nativeClass,
"Unable to find android/webkit/WebViewCore.mNativeClass");
gWebViewCoreFields.m_viewportWidth = env->GetFieldID(widget,
"mViewportWidth", "I");
- LOG_ASSERT(gWebViewCoreFields.m_viewportWidth,
+ ALOG_ASSERT(gWebViewCoreFields.m_viewportWidth,
"Unable to find android/webkit/WebViewCore.mViewportWidth");
gWebViewCoreFields.m_viewportHeight = env->GetFieldID(widget,
"mViewportHeight", "I");
- LOG_ASSERT(gWebViewCoreFields.m_viewportHeight,
+ ALOG_ASSERT(gWebViewCoreFields.m_viewportHeight,
"Unable to find android/webkit/WebViewCore.mViewportHeight");
gWebViewCoreFields.m_viewportInitialScale = env->GetFieldID(widget,
"mViewportInitialScale", "I");
- LOG_ASSERT(gWebViewCoreFields.m_viewportInitialScale,
+ ALOG_ASSERT(gWebViewCoreFields.m_viewportInitialScale,
"Unable to find android/webkit/WebViewCore.mViewportInitialScale");
gWebViewCoreFields.m_viewportMinimumScale = env->GetFieldID(widget,
"mViewportMinimumScale", "I");
- LOG_ASSERT(gWebViewCoreFields.m_viewportMinimumScale,
+ ALOG_ASSERT(gWebViewCoreFields.m_viewportMinimumScale,
"Unable to find android/webkit/WebViewCore.mViewportMinimumScale");
gWebViewCoreFields.m_viewportMaximumScale = env->GetFieldID(widget,
"mViewportMaximumScale", "I");
- LOG_ASSERT(gWebViewCoreFields.m_viewportMaximumScale,
+ ALOG_ASSERT(gWebViewCoreFields.m_viewportMaximumScale,
"Unable to find android/webkit/WebViewCore.mViewportMaximumScale");
gWebViewCoreFields.m_viewportUserScalable = env->GetFieldID(widget,
"mViewportUserScalable", "Z");
- LOG_ASSERT(gWebViewCoreFields.m_viewportUserScalable,
+ ALOG_ASSERT(gWebViewCoreFields.m_viewportUserScalable,
"Unable to find android/webkit/WebViewCore.mViewportUserScalable");
gWebViewCoreFields.m_viewportDensityDpi = env->GetFieldID(widget,
"mViewportDensityDpi", "I");
- LOG_ASSERT(gWebViewCoreFields.m_viewportDensityDpi,
+ ALOG_ASSERT(gWebViewCoreFields.m_viewportDensityDpi,
"Unable to find android/webkit/WebViewCore.mViewportDensityDpi");
- gWebViewCoreFields.m_webView = env->GetFieldID(widget,
- "mWebView", "Landroid/webkit/WebView;");
- LOG_ASSERT(gWebViewCoreFields.m_webView,
- "Unable to find android/webkit/WebViewCore.mWebView");
gWebViewCoreFields.m_drawIsPaused = env->GetFieldID(widget,
"mDrawIsPaused", "Z");
- LOG_ASSERT(gWebViewCoreFields.m_drawIsPaused,
+ ALOG_ASSERT(gWebViewCoreFields.m_drawIsPaused,
"Unable to find android/webkit/WebViewCore.mDrawIsPaused");
gWebViewCoreFields.m_lowMemoryUsageMb = env->GetFieldID(widget, "mLowMemoryUsageThresholdMb", "I");
gWebViewCoreFields.m_highMemoryUsageMb = env->GetFieldID(widget, "mHighMemoryUsageThresholdMb", "I");
diff --git a/Source/WebKit/android/jni/WebViewCore.h b/Source/WebKit/android/jni/WebViewCore.h
index a19a5b2..5264f7f 100644
--- a/Source/WebKit/android/jni/WebViewCore.h
+++ b/Source/WebKit/android/jni/WebViewCore.h
@@ -26,29 +26,36 @@
#ifndef WebViewCore_h
#define WebViewCore_h
-#include "CacheBuilder.h"
-#include "CachedHistory.h"
#include "DeviceMotionAndOrientationManager.h"
#include "DOMSelection.h"
#include "FileChooser.h"
-#include "PictureSet.h"
+#include "FocusDirection.h"
+#include "HitTestResult.h"
+#include "PicturePile.h"
#include "PlatformGraphicsContext.h"
+#include "Position.h"
+#include "ScrollTypes.h"
#include "SkColor.h"
#include "SkTDArray.h"
#include "SkRegion.h"
+#include "Text.h"
#include "Timer.h"
#include "WebCoreRefObject.h"
#include "WebCoreJni.h"
#include "WebRequestContext.h"
#include "android_npapi.h"
+#include "VisiblePosition.h"
+#include "SelectText.h"
#include <jni.h>
-#include <ui/KeycodeLabels.h>
+#include <androidfw/KeycodeLabels.h>
#include <ui/PixelFormat.h>
#include <utils/threads.h>
+#include <wtf/Threading.h>
namespace WebCore {
class Color;
+ class GraphicsOperationCollection;
class FrameView;
class HTMLAnchorElement;
class HTMLElement;
@@ -68,6 +75,7 @@ namespace WebCore {
#if USE(ACCELERATED_COMPOSITING)
namespace WebCore {
class GraphicsLayerAndroid;
+ class LayerAndroid;
}
#endif
@@ -96,10 +104,8 @@ namespace android {
AXIS_DOCUMENT = 6
};
- class CachedFrame;
- class CachedNode;
- class CachedRoot;
class ListBoxReply;
+ class AndroidHitTestResult;
class WebCoreReply : public WebCoreRefObject {
public:
@@ -116,7 +122,7 @@ namespace android {
};
// one instance of WebViewCore per page for calling into Java's WebViewCore
- class WebViewCore : public WebCoreRefObject {
+ class WebViewCore : public WebCoreRefObject, public WebCore::PicturePainter {
public:
/**
* Initialize the native WebViewCore with a JNI environment, a Java
@@ -131,13 +137,7 @@ namespace android {
// Followings are called from native WebCore to Java
- /**
- * Notification that a form was blurred. Pass a message to hide the
- * keyboard if it was showing for that Node.
- * @param Node The Node that blurred.
- */
- void formDidBlur(const WebCore::Node*);
- void focusNodeChanged(const WebCore::Node*);
+ void focusNodeChanged(WebCore::Node*);
/**
* Scroll to an absolute position.
@@ -161,13 +161,8 @@ namespace android {
*/
void contentDraw();
- /**
- * copy the layers to the UI side
- */
- void layersDraw();
-
#if USE(ACCELERATED_COMPOSITING)
- GraphicsLayerAndroid* graphicsRootLayer() const;
+ WebCore::GraphicsLayerAndroid* graphicsRootLayer() const;
#endif
/** Invalidate the view/screen, NOT the content/DOM, but expressed in
@@ -207,7 +202,7 @@ namespace android {
* Tell the java side to update the focused textfield
* @param pointer Pointer to the node for the input field.
* @param changeToPassword If true, we are changing the textfield to
- * a password field, and ignore the String
+ * a password field, and ignore the WTF::String
* @param text If changeToPassword is false, this is the new text that
* should go into the textfield.
*/
@@ -222,6 +217,12 @@ namespace android {
*/
void updateTextSelection();
+ /**
+ * Updates the java side with the node's content size and scroll
+ * position.
+ */
+ void updateTextSizeAndScroll(WebCore::Node* node);
+
void clearTextEntry();
// JavaScript support
void jsAlert(const WTF::String& url, const WTF::String& text);
@@ -277,12 +278,13 @@ namespace android {
jobject getDeviceMotionService();
jobject getDeviceOrientationService();
- void addMessageToConsole(const String& message, unsigned int lineNumber, const String& sourceID, int msgLevel);
+ void addMessageToConsole(const WTF::String& message, unsigned int lineNumber, const WTF::String& sourceID, int msgLevel);
/**
* Tell the Java side of the scrollbar mode
*/
- void setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode verticalMode);
+ void setScrollbarModes(WebCore::ScrollbarMode horizontalMode,
+ WebCore::ScrollbarMode verticalMode);
//
// Followings support calls from Java to native WebCore
@@ -296,16 +298,12 @@ namespace android {
// If the focus is a textfield (<input>), textarea, or contentEditable,
// scroll the selection on screen (if necessary).
void revealSelection();
- // Create a single picture to represent the drawn DOM (used by navcache)
- void recordPicture(SkPicture* picture);
- void moveFocus(WebCore::Frame* frame, WebCore::Node* node);
- void moveMouse(WebCore::Frame* frame, int x, int y);
- void moveMouseIfLatest(int moveGeneration,
- WebCore::Frame* frame, int x, int y);
+ void moveMouse(int x, int y, WebCore::HitTestResult* hoveredNode = 0,
+ bool isClickCandidate = false);
// set the scroll amount that webview.java is currently showing
- void setScrollOffset(int moveGeneration, bool sendScrollEvent, int dx, int dy);
+ void setScrollOffset(bool sendScrollEvent, int dx, int dy);
void setGlobalBounds(int x, int y, int h, int v);
@@ -318,31 +316,24 @@ namespace android {
* @return Whether keyCode was handled by this class.
*/
bool key(const WebCore::PlatformKeyboardEvent& event);
-
- /**
- * Handle (trackball) click event / dpad center press from Java.
- * Also used when typing into an unfocused textfield, in which case 'fake'
- * will be true.
- */
- void click(WebCore::Frame* frame, WebCore::Node* node, bool fake);
+ bool chromeCanTakeFocus(WebCore::FocusDirection direction);
+ void chromeTakeFocus(WebCore::FocusDirection direction);
+ void setInitialFocus(const WebCore::PlatformKeyboardEvent& event);
/**
* Handle touch event
+ * Returns an int with the following flags:
+ * bit 0: hit an event handler
+ * bit 1: preventDefault was called
*/
- bool handleTouchEvent(int action, Vector<int>& ids, Vector<IntPoint>& points, int actionIndex, int metaState);
+ int handleTouchEvent(int action, WTF::Vector<int>& ids,
+ WTF::Vector<WebCore::IntPoint>& points,
+ int actionIndex, int metaState);
/**
- * Handle motionUp event from the UI thread (called touchUp in the
- * WebCore thread).
- * @param touchGeneration Generation number for touches so we can ignore
- * touches when a newer one has been generated.
- * @param frame Pointer to Frame containing the node that was touched.
- * @param node Pointer to Node that was touched.
- * @param x x-position of the touch.
- * @param y y-position of the touch.
+ * Clicks the mouse at its current location
*/
- void touchUp(int touchGeneration, WebCore::Frame* frame,
- WebCore::Node* node, int x, int y);
+ bool performMouseClick();
/**
* Sets the index of the label from a popup
@@ -372,11 +363,11 @@ namespace android {
* direction - The direction in which to alter the selection.
* granularity - The granularity of the selection modification.
*
- * returns - The selected HTML as a string. This is not a well formed
+ * returns - The selected HTML as a WTF::String. This is not a well formed
* HTML, rather the selection annotated with the tags of all
* intermediary elements it crosses.
*/
- String modifySelection(const int direction, const int granularity);
+ WTF::String modifySelection(const int direction, const int granularity);
/**
* Moves the selection to the given node in a given frame i.e. selects that node.
@@ -386,11 +377,11 @@ namespace android {
* frame - The frame in which to select is the node to be selected.
* node - The node to be selected.
*
- * returns - The selected HTML as a string. This is not a well formed
+ * returns - The selected HTML as a WTF::String. This is not a well formed
* HTML, rather the selection annotated with the tags of all
* intermediary elements it crosses.
*/
- String moveSelection(WebCore::Frame* frame, WebCore::Node* node);
+ WTF::String moveSelection(WebCore::Frame* frame, WebCore::Node* node);
/**
* In the currently focused textfield, replace the characters from oldStart to oldEnd
@@ -405,7 +396,7 @@ namespace android {
/**
* Scroll the focused textfield to (x, y) in document space
*/
- void scrollFocusedTextInput(float x, int y);
+ WebCore::IntRect scrollFocusedTextInput(float x, int y);
/**
* Set the FocusController's active and focused states, so that
* the caret will draw (true) or not.
@@ -425,11 +416,9 @@ namespace android {
jobject getWebViewJavaObject();
void setBackgroundColor(SkColor c);
- void updateFrameCache();
- void updateCacheOnNodeChange();
+
void dumpDomTree(bool);
void dumpRenderTree(bool);
- void dumpNavTree();
/* We maintain a list of active plugins. The list is edited by the
pluginview itself. The list is used to service invals to the plugin
@@ -449,7 +438,7 @@ namespace android {
void sendPluginSurfaceReady();
// send onLoad event to plugins who are descendents of the given frame
- void notifyPluginsOnFrameLoad(const Frame*);
+ void notifyPluginsOnFrameLoad(const WebCore::Frame*);
// gets a rect representing the current on-screen portion of the document
void getVisibleScreen(ANPRectI&);
@@ -460,9 +449,6 @@ namespace android {
// lookup the plugin widget struct given an NPP
PluginWidgetAndroid* getPluginWidget(NPP npp);
- // return the cursorNode if it is a plugin
- Node* cursorNodeIsPlugin();
-
// Notify the Java side whether it needs to pass down the touch events
void needTouchEvents(bool);
@@ -497,8 +483,6 @@ namespace android {
// Manages requests to keep the screen on while the WebView is visible
void keepScreenOn(bool screenOn);
- bool validNodeAndBounds(Frame* , Node* , const IntRect& );
-
// Make the rect (left, top, width, height) visible. If it can be fully
// fit, center it on the screen. Otherwise make sure the point specified
// by (left + xPercentInDoc * width, top + yPercentInDoc * height)
@@ -512,7 +496,11 @@ namespace android {
void centerFitRect(int x, int y, int width, int height);
// return a list of rects matching the touch point (x, y) with the slop
- Vector<IntRect> getTouchHighlightRects(int x, int y, int slop);
+ WTF::Vector<WebCore::IntRect> getTouchHighlightRects(int x, int y, int slop,
+ WebCore::Node** node, WebCore::HitTestResult* hitTestResult);
+ // This does a sloppy hit test
+ AndroidHitTestResult hitTestAtPoint(int x, int y, int slop, bool doMoveMouse = false);
+ static bool nodeIsClickableOrFocusable(WebCore::Node* node);
// Open a file chooser for selecting a file to upload
void openFileChooser(PassRefPtr<WebCore::FileChooser> );
@@ -522,31 +510,37 @@ namespace android {
bool focusBoundsChanged();
- // record the inval area, and the picture size
- BaseLayerAndroid* recordContent(SkRegion* , SkIPoint* );
+ // record content in a new BaseLayerAndroid, copying the layer tree as well
+ WebCore::BaseLayerAndroid* recordContent(SkIPoint* );
// This creates a new BaseLayerAndroid by copying the current m_content
// and doing a copy of the layers. The layers' content may be updated
// as we are calling layersSync().
- BaseLayerAndroid* createBaseLayer(SkRegion*);
- bool updateLayers(LayerAndroid*);
+ WebCore::BaseLayerAndroid* createBaseLayer(GraphicsLayerAndroid* root);
+ bool updateLayers(WebCore::LayerAndroid*);
void notifyAnimationStarted();
int textWrapWidth() const { return m_textWrapWidth; }
float scale() const { return m_scale; }
float textWrapScale() const { return m_screenWidth * m_scale / m_textWrapWidth; }
WebCore::Frame* mainFrame() const { return m_mainFrame; }
- void updateCursorBounds(const CachedRoot* root,
- const CachedFrame* cachedFrame, const CachedNode* cachedNode);
- void updateFrameCacheIfLoading();
-
- // utility to split slow parts of the picture set
- void splitContent(PictureSet*);
+ WebCore::Frame* focusedFrame() const;
void notifyWebAppCanBeInstalled();
+ void deleteText(int startX, int startY, int endX, int endY);
+ WTF::String getText(int startX, int startY, int endX, int endY);
+ void insertText(const WTF::String &text);
+
+ // find on page
+ void resetFindOnPage();
+ int findTextOnPage(const WTF::String &text);
+ int findNextOnPage(bool forward);
+ void updateMatchCount() const;
+
#if ENABLE(VIDEO)
void enterFullscreenForVideoLayer(int layerId, const WTF::String& url);
+ void exitFullscreenVideo();
#endif
void setWebTextViewAutoFillable(int queryId, const string16& previewSummary);
@@ -556,19 +550,15 @@ namespace android {
void listBoxRequest(WebCoreReply* reply, const uint16_t** labels,
size_t count, const int enabled[], size_t enabledCount,
bool multiple, const int selected[], size_t selectedCountOrSelection);
- bool shouldPaintCaret() { return m_shouldPaintCaret; }
- void setShouldPaintCaret(bool should) { m_shouldPaintCaret = should; }
bool isPaused() const { return m_isPaused; }
void setIsPaused(bool isPaused) { m_isPaused = isPaused; }
bool drawIsPaused() const;
// The actual content (without title bar) size in doc coordinate
int screenWidth() const { return m_screenWidth; }
int screenHeight() const { return m_screenHeight; }
-#if USE(CHROME_NETWORK_STACK)
void setWebRequestContextUserAgent();
void setWebRequestContextCacheMode(int mode);
WebRequestContext* webRequestContext();
-#endif
// Attempts to scroll the layer to the x,y coordinates of rect. The
// layer is the id of the LayerAndroid.
void scrollRenderLayer(int layer, const SkRect& rect);
@@ -581,35 +571,62 @@ namespace android {
// Check whether a media mimeType is supported in Android media framework.
static bool isSupportedMediaMimeType(const WTF::String& mimeType);
+ /**
+ * Returns all text ranges consumed by the cursor points referred
+ * to by startX, startY, endX, and endY. The vector will be empty
+ * if no text is in the given area or if the positions are invalid.
+ */
+ Vector<WebCore::VisibleSelection> getTextRanges(
+ int startX, int startY, int endX, int endY);
+ static int platformLayerIdFromNode(WebCore::Node* node,
+ WebCore::LayerAndroid** outLayer = 0);
+ void selectText(int startX, int startY, int endX, int endY);
+ bool selectWordAt(int x, int y);
+
+ // Converts from the global content coordinates that WebView sends
+ // to frame-local content coordinates using the focused frame
+ WebCore::IntPoint convertGlobalContentToFrameContent(const WebCore::IntPoint& point, WebCore::Frame* frame = 0);
+ static void layerToAbsoluteOffset(const WebCore::LayerAndroid* layer,
+ WebCore::IntPoint& offset);
+
+ // Retrieves the current locale from system properties
+ void getLocale(String& language, WTF::String& region);
+
+ // Handles changes in system locale
+ void updateLocale();
+
// these members are shared with webview.cpp
- static Mutex gFrameCacheMutex;
- CachedRoot* m_frameCacheKit; // nav data being built by webcore
- SkPicture* m_navPictureKit;
- int m_moveGeneration; // copy of state in WebViewNative triggered by move
int m_touchGeneration; // copy of state in WebViewNative triggered by touch
int m_lastGeneration; // last action using up to date cache
- bool m_updatedFrameCache;
- bool m_findIsUp;
- bool m_hasCursorBounds;
- WebCore::IntRect m_cursorBounds;
- WebCore::IntRect m_cursorHitBounds;
- void* m_cursorFrame;
- IntPoint m_cursorLocation;
- void* m_cursorNode;
- static Mutex gCursorBoundsMutex;
// end of shared members
+ void setPrerenderingEnabled(bool enable);
+
// internal functions
private:
- CacheBuilder& cacheBuilder();
+ enum InputType {
+ NONE = -1,
+ NORMAL_TEXT_FIELD = 0,
+ TEXT_AREA = 1,
+ PASSWORD = 2,
+ SEARCH = 3,
+ EMAIL = 4,
+ NUMBER = 5,
+ TELEPHONE = 6,
+ URL = 7,
+ };
+
WebCore::Node* currentFocus();
+ void layout();
// Create a set of pictures to represent the drawn DOM, driven by
// the invalidated region and the time required to draw (used to draw)
- void recordPictureSet(PictureSet* master);
+ void recordPicturePile();
- void doMaxScroll(CacheBuilder::Direction dir);
- SkPicture* rebuildPicture(const SkIRect& inval);
- void rebuildPictureSet(PictureSet* );
+ virtual void paintContents(WebCore::GraphicsContext* gc, WebCore::IntRect& dirty);
+ virtual SkCanvas* createPrerenderCanvas(WebCore::PrerenderedInval* prerendered);
+#ifdef CONTEXT_RECORDING
+ WebCore::GraphicsOperationCollection* rebuildGraphicsOperationCollection(const SkIRect& inval);
+#endif
void sendNotifyProgressFinished();
/*
* Handle a mouse click, either from a touch or trackball press.
@@ -618,47 +635,127 @@ namespace android {
* @param fake This is a fake mouse click, used to put a textfield into focus. Do not
* open the IME.
*/
- bool handleMouseClick(WebCore::Frame*, WebCore::Node*, bool fake);
WebCore::HTMLAnchorElement* retrieveAnchorElement(int x, int y);
WebCore::HTMLElement* retrieveElement(int x, int y,
const WebCore::QualifiedName& );
WebCore::HTMLImageElement* retrieveImageElement(int x, int y);
// below are members responsible for accessibility support
- String modifySelectionTextNavigationAxis(DOMSelection* selection, int direction, int granularity);
- String modifySelectionDomNavigationAxis(DOMSelection* selection, int direction, int granularity);
- Text* traverseNextContentTextNode(Node* fromNode, Node* toNode ,int direction);
- bool isVisible(Node* node);
- bool isHeading(Node* node);
- String formatMarkup(DOMSelection* selection);
+ WTF::String modifySelectionTextNavigationAxis(WebCore::DOMSelection* selection,
+ int direction, int granularity);
+ WTF::String modifySelectionDomNavigationAxis(WebCore::DOMSelection* selection,
+ int direction, int granularity);
+ WebCore::Text* traverseNextContentTextNode(WebCore::Node* fromNode,
+ WebCore::Node* toNode,
+ int direction);
+ bool isVisible(WebCore::Node* node);
+ bool isHeading(WebCore::Node* node);
+ WTF::String formatMarkup(WebCore::DOMSelection* selection);
void selectAt(int x, int y);
- void scrollNodeIntoView(Frame* frame, Node* node);
- bool isContentTextNode(Node* node);
- Node* getIntermediaryInputElement(Node* fromNode, Node* toNode, int direction);
- bool isContentInputElement(Node* node);
- bool isDescendantOf(Node* parent, Node* node);
- void advanceAnchorNode(DOMSelection* selection, int direction, String& markup, bool ignoreFirstNode, ExceptionCode& ec);
- Node* getNextAnchorNode(Node* anchorNode, bool skipFirstHack, int direction);
- Node* getImplicitBoundaryNode(Node* node, unsigned offset, int direction);
+ void scrollNodeIntoView(WebCore::Frame* frame, WebCore::Node* node);
+ bool isContentTextNode(WebCore::Node* node);
+ WebCore::Node* getIntermediaryInputElement(WebCore::Node* fromNode,
+ WebCore::Node* toNode,
+ int direction);
+ bool isContentInputElement(WebCore::Node* node);
+ bool isDescendantOf(WebCore::Node* parent, WebCore::Node* node);
+ void advanceAnchorNode(WebCore::DOMSelection* selection, int direction,
+ WTF::String& markup, bool ignoreFirstNode,
+ WebCore::ExceptionCode& ec);
+ WebCore::Node* getNextAnchorNode(WebCore::Node* anchorNode,
+ bool skipFirstHack, int direction);
+ WebCore::Node* getImplicitBoundaryNode(WebCore::Node* node,
+ unsigned offset, int direction);
+ jobject createTextFieldInitData(WebCore::Node* node);
+ /**
+ * Calls into java to reset the text edit field with the
+ * current contents and selection.
+ */
+ void initEditField(WebCore::Node* node);
+
+ /**
+ * If node is not a text input field or if it explicitly requests
+ * not to have keyboard input, then the soft keyboard is closed. If
+ * it is a text input field then initEditField is called and
+ * auto-fill information is requested for HTML form input fields.
+ */
+ void initializeTextInput(WebCore::Node* node, bool fake);
+
+ /**
+ * Gets the input type a Node. NONE is returned if it isn't an
+ * input field.
+ */
+ InputType getInputType(WebCore::Node* node);
+
+ /**
+ * If node is an input field, the spellcheck value for the
+ * field is returned. Otherwise true is returned.
+ */
+ static bool isSpellCheckEnabled(WebCore::Node* node);
+
+ /**
+ * Returns the offsets of the selection area for both normal text
+ * fields and content editable fields. start and end are modified
+ * by this method.
+ */
+ static void getSelectionOffsets(WebCore::Node* node, int& start, int& end);
+ /**
+ * Gets the plain text of the specified editable text field. node
+ * may be content-editable or a plain text fields.
+ */
+ static WTF::String getInputText(WebCore::Node* node);
+ /**
+ * Gets the RenderTextControl for the given node if it has one.
+ * If its renderer isn't a RenderTextControl, then NULL is returned.
+ */
+ static WebCore::RenderTextControl* toRenderTextControl(WebCore::Node *node);
+ /**
+ * Sets the selection for node's editable field to the offsets
+ * between start (inclusive) and end (exclusive).
+ */
+ static void setSelection(WebCore::Node* node, int start, int end);
+ /**
+ * Returns the Position for the given offset for an editable
+ * field. The offset is relative to the node start.
+ */
+ static WebCore::Position getPositionForOffset(WebCore::Node* node, int offset);
+
+ WebCore::VisiblePosition visiblePositionForContentPoint(int x, int y);
+ WebCore::VisiblePosition visiblePositionForContentPoint(const WebCore::IntPoint& point);
+ bool selectWordAroundPosition(WebCore::Frame* frame,
+ WebCore::VisiblePosition pos);
+ SelectText* createSelectText(const WebCore::VisibleSelection&);
+ void setSelectionCaretInfo(SelectText* selectTextContainer,
+ const WebCore::Position& position,
+ const WebCore::IntPoint& frameOffset,
+ SelectText::HandleId handleId, int offset,
+ EAffinity affinity);
+ static int getMaxLength(WebCore::Node* node);
+ static WTF::String getFieldName(WebCore::Node* node);
+ static bool isAutoCompleteEnabled(WebCore::Node* node);
+ WebCore::IntRect absoluteContentRect(WebCore::Node* node,
+ WebCore::LayerAndroid* layer);
+ static WebCore::IntRect positionToTextRect(const WebCore::Position& position,
+ WebCore::EAffinity affinity, const WebCore::IntPoint& offset);
+ static bool isLtr(const WebCore::Position& position);
+ static WebCore::Position trimSelectionPosition(
+ const WebCore::Position& start, const WebCore::Position& stop);
// called from constructor, to add this to a global list
static void addInstance(WebViewCore*);
// called from destructor, to remove this from a global list
static void removeInstance(WebViewCore*);
+ bool prerenderingEnabled();
+
friend class ListBoxReply;
struct JavaGlue;
struct JavaGlue* m_javaGlue;
+ struct TextFieldInitDataGlue;
+ struct TextFieldInitDataGlue* m_textFieldInitDataGlue;
WebCore::Frame* m_mainFrame;
WebCoreReply* m_popupReply;
- WebCore::Node* m_lastFocused;
- WebCore::IntRect m_lastFocusedBounds;
- int m_blurringNodePointer;
- int m_lastFocusedSelStart;
- int m_lastFocusedSelEnd;
- PictureSet m_content; // the set of pictures to draw
- SkRegion m_addInval; // the accumulated inval region (not yet drawn)
- SkRegion m_rebuildInval; // the accumulated region for rebuilt pictures
+ WebCore::PicturePile m_content; // the set of pictures to draw
// Used in passToJS to avoid updating the UI text field until after the
// key event has been processed.
bool m_blockTextfieldUpdates;
@@ -667,26 +764,33 @@ namespace android {
// Passed in with key events to know when they were generated. Store it
// with the cache so that we can ignore stale text changes.
int m_textGeneration;
- CachedRoot* m_temp;
- SkPicture* m_tempPict;
int m_maxXScroll;
int m_maxYScroll;
int m_scrollOffsetX; // webview.java's current scroll in X
int m_scrollOffsetY; // webview.java's current scroll in Y
+ double m_scrollSetTime; // when the scroll was last set
WebCore::IntPoint m_mousePos;
- bool m_frameCacheOutOfDate;
- bool m_progressDone;
- CachedHistory m_history;
+ // This is the location at which we will click. This is tracked
+ // separately from m_mousePos, because m_mousePos may be updated
+ // in the interval between ACTION_UP and when the click fires since
+ // that occurs after a delay. This also works around potential hardware
+ // issues if we get onHoverEvents when using the touch screen, as that
+ // will nullify the slop checking we do in hitTest (aka, ACTION_DOWN)
+ WebCore::IntPoint m_mouseClickPos;
int m_screenWidth; // width of the visible rect in document coordinates
int m_screenHeight;// height of the visible rect in document coordinates
int m_textWrapWidth;
float m_scale;
- unsigned m_domtree_version;
- bool m_check_domtree_version;
- PageGroup* m_groupForVisitedLinks;
+ WebCore::PageGroup* m_groupForVisitedLinks;
bool m_isPaused;
int m_cacheMode;
- bool m_shouldPaintCaret;
+ bool m_fullscreenVideoMode;
+
+ // find on page data
+ WTF::String m_searchText;
+ int m_matchCount;
+ int m_activeMatchIndex;
+ RefPtr<WebCore::Range> m_activeMatch;
SkTDArray<PluginWidgetAndroid*> m_plugins;
WebCore::Timer<WebViewCore> m_pluginInvalTimer;
@@ -695,17 +799,17 @@ namespace android {
}
int m_screenOnCounter;
- Node* m_currentNodeDomNavigationAxis;
+ WebCore::Node* m_currentNodeDomNavigationAxis;
DeviceMotionAndOrientationManager m_deviceMotionAndOrientationManager;
#if ENABLE(TOUCH_EVENTS)
bool m_forwardingTouchEvents;
#endif
-#if USE(CHROME_NETWORK_STACK)
scoped_refptr<WebRequestContext> m_webRequestContext;
-#endif
+ WTF::Mutex m_prerenderLock;
+ bool m_prerenderEnabled;
};
} // namespace android
diff --git a/Source/WebKit/android/nav/CacheBuilder.cpp b/Source/WebKit/android/nav/CacheBuilder.cpp
deleted file mode 100644
index 940991f..0000000
--- a/Source/WebKit/android/nav/CacheBuilder.cpp
+++ /dev/null
@@ -1,3194 +0,0 @@
-/*
- * Copyright 2006, 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.
- */
-
-#include "CachedPrefix.h"
-#include "CachedNode.h"
-#include "CachedRoot.h"
-#include "ColumnInfo.h"
-#include "Document.h"
-#include "EventListener.h"
-#include "EventNames.h"
-#include "Frame.h"
-#include "FrameLoader.h"
-#include "FrameLoaderClientAndroid.h"
-#include "FrameTree.h"
-#include "FrameView.h"
-//#include "GraphicsContext.h"
-#include "HTMLAreaElement.h"
-#include "HTMLImageElement.h"
-#include "HTMLInputElement.h"
-#include "HTMLMapElement.h"
-#include "HTMLNames.h"
-#include "HTMLOptionElement.h"
-#include "HTMLSelectElement.h"
-#include "HTMLTextAreaElement.h"
-#include "InlineTextBox.h"
-#include "KURL.h"
-#include "LayerAndroid.h"
-#include "PluginView.h"
-#include "RegisteredEventListener.h"
-#include "RenderImage.h"
-#include "RenderInline.h"
-#include "RenderLayerBacking.h"
-#include "RenderListBox.h"
-#include "RenderSkinCombo.h"
-#include "RenderTextControl.h"
-#include "RenderView.h"
-#include "RenderWidget.h"
-#include "SkCanvas.h"
-#include "SkPoint.h"
-#include "Text.h"
-#include "WebCoreFrameBridge.h"
-#include "WebCoreViewBridge.h"
-#include "Widget.h"
-#include <wtf/unicode/Unicode.h>
-
-#ifdef DUMP_NAV_CACHE_USING_PRINTF
- FILE* gNavCacheLogFile = NULL;
- android::Mutex gWriteLogMutex;
-#endif
-
-#include "CacheBuilder.h"
-
-#define MINIMUM_FOCUSABLE_WIDTH 3
-#define MINIMUM_FOCUSABLE_HEIGHT 3
-#define MAXIMUM_FOCUS_RING_COUNT 32
-
-namespace android {
-
-CacheBuilder* CacheBuilder::Builder(Frame* frame) {
- return &((FrameLoaderClientAndroid*) frame->loader()->client())->getCacheBuilder();
-}
-
-Frame* CacheBuilder::FrameAnd(CacheBuilder* cacheBuilder) {
- FrameLoaderClientAndroid* loader = (FrameLoaderClientAndroid*)
- ((char*) cacheBuilder - OFFSETOF(FrameLoaderClientAndroid, m_cacheBuilder));
- return loader->getFrame();
-}
-
-Frame* CacheBuilder::FrameAnd(const CacheBuilder* cacheBuilder) {
- FrameLoaderClientAndroid* loader = (FrameLoaderClientAndroid*)
- ((char*) cacheBuilder - OFFSETOF(FrameLoaderClientAndroid, m_cacheBuilder));
- return loader->getFrame();
-}
-
-CacheBuilder::LayerTracker::~LayerTracker() {
- // Check for a stacking context to prevent a crash in layers without a
- // parent.
- if (mRenderLayer && mRenderLayer->stackingContext())
- // Restore the scroll position of the layer. Does not affect layers
- // without overflow scroll as the layer will not be scrolled.
- mRenderLayer->scrollToOffset(mScroll.x(), mScroll.y());
-}
-
-#if DUMP_NAV_CACHE
-
-static bool hasEventListener(Node* node, const AtomicString& eventType) {
- if (!node->isElementNode())
- return false;
- Element* element = static_cast<Element*>(node);
- EventListener* listener = element->getAttributeEventListener(eventType);
- return 0 != listener;
-}
-
-#define DEBUG_BUFFER_SIZE 256
-#define DEBUG_WRAP_SIZE 150
-#define DEBUG_WRAP_MAX 170
-
-Frame* CacheBuilder::Debug::frameAnd() const {
- CacheBuilder* nav = (CacheBuilder*) ((char*) this - OFFSETOF(CacheBuilder, mDebug));
- return CacheBuilder::FrameAnd(nav);
-}
-
-void CacheBuilder::Debug::attr(const AtomicString& name, const AtomicString& value) {
- if (name.isNull() || name.isEmpty() || value.isNull() || value.isEmpty())
- return;
- uChar(name.characters(), name.length(), false);
- print("=");
- wideString(value.characters(), value.length(), false);
- print(" ");
-}
-
-void CacheBuilder::Debug::comma(const char* str) {
- print(str);
- print(", ");
-}
-
-void CacheBuilder::Debug::flush() {
- int len;
- do {
- int limit = mIndex;
- if (limit < DEBUG_WRAP_SIZE)
- return;
- if (limit < DEBUG_WRAP_MAX)
- len = limit;
- else {
- limit = DEBUG_WRAP_MAX;
- len = DEBUG_WRAP_SIZE;
- while (len < limit) {
- char test = mBuffer[len];
- if (test < '/' || (test > '9' && test < 'A') || (test > 'Z' && test < 'a') || test > 'z')
- break;
- len++;
- }
- while (len > 0 && mBuffer[len - 1] == '\\')
- len--;
- while (mBuffer[len] == '"')
- len++;
- }
- const char* prefix = mPrefix;
- if (prefix[0] == '\"') {
- // see if we're inside a quote
- int quoteCount = 0;
- for (int index = 0; index < len; index++) {
- if (mBuffer[index] == '\\') {
- index++;
- continue;
- }
- if (mBuffer[index] == '\n') {
- quoteCount = 0;
- continue;
- }
- if (mBuffer[index] == '"')
- quoteCount++;
- }
- if ((quoteCount & 1) == 0)
- prefix = "\n";
- }
- DUMP_NAV_LOGD("%.*s", len, mBuffer);
- int copy = mIndex - len;
- strcpy(mBuffer, prefix);
- memcpy(&mBuffer[strlen(prefix)], &mBuffer[len], copy);
- mIndex = strlen(prefix) + copy;
- } while (true);
-}
-
-void CacheBuilder::Debug::frameName(char*& namePtr, const char* max) const {
- if (namePtr >= max)
- return;
- Frame* frame = frameAnd();
- Frame* parent = frame->tree()->parent();
- if (parent)
- Builder(parent)->mDebug.frameName(namePtr, max);
- const AtomicString& name = frame->tree()->name();
- if (name.length() == 0)
- return;
- unsigned index = 0;
- if (name.startsWith(AtomicString("opener")))
- index = 6;
- for (; index < name.length(); index++) {
- char ch = name[index];
- if (ch <= ' ')
- ch = '_';
- if (WTF::isASCIIAlphanumeric(ch) || ch == '_')
- *namePtr++ = ch;
- }
-}
-
-void CacheBuilder::Debug::frames() {
- Frame* frame = frameAnd();
- Document* doc = frame->document();
- if (doc == NULL)
- return;
- bool top = frame->tree()->parent() == NULL;
- if (top) {
-#ifdef DUMP_NAV_CACHE_USING_PRINTF
- gWriteLogMutex.lock();
- ASSERT(gNavCacheLogFile == NULL);
- gNavCacheLogFile = fopen(NAV_CACHE_LOG_FILE, "a");
-#endif
- groups();
- }
- Frame* child = frame->tree()->firstChild();
- bool hasChild = child != NULL;
- if (top && hasChild)
- DUMP_NAV_LOGD("\nnamespace TEST_SPACE {\n\n");
- while (child) {
- Builder(child)->mDebug.frames();
- child = child->tree()->nextSibling();
- }
- if (hasChild) {
- child = frame->tree()->firstChild();
- while (child) {
- char childName[256];
- char* childNamePtr = childName;
- Builder(child)->mDebug.frameName(childNamePtr, childNamePtr + sizeof(childName) - 1);
- *childNamePtr = '\0';
- if (child == frame->tree()->firstChild())
- DUMP_NAV_LOGD("DebugTestFrameGroup TEST%s_GROUP[] = {\n", childName);
- Frame* next = child->tree()->nextSibling();
- Document* doc = child->document();
- if (doc != NULL) {
- RenderObject* renderer = doc->renderer();
- if (renderer != NULL) {
- RenderLayer* layer = renderer->enclosingLayer();
- if (layer != NULL) {
- DUMP_NAV_LOGD("{ ");
- DUMP_NAV_LOGD("TEST%s_RECTS, ", childName);
- DUMP_NAV_LOGD("TEST%s_RECT_COUNT, ", childName);
- DUMP_NAV_LOGD("TEST%s_RECTPARTS, ", childName);
- DUMP_NAV_LOGD("TEST%s_BOUNDS,\n", childName);
- DUMP_NAV_LOGD("TEST%s_WIDTH, ", childName);
- DUMP_NAV_LOGD("TEST%s_HEIGHT,\n", childName);
- DUMP_NAV_LOGD("0, 0, 0, 0,\n");
- DUMP_NAV_LOGD("TEST%s_FOCUS, ", childName);
- Frame* grandChild = child->tree()->firstChild();
- if (grandChild) {
- char grandChildName[256];
- char* grandChildNamePtr = grandChildName;
- Builder(grandChild)->mDebug.frameName(grandChildNamePtr,
- grandChildNamePtr + sizeof(grandChildName) - 1);
- *grandChildNamePtr = '\0';
- DUMP_NAV_LOGD("TEST%s_GROUP, ", grandChildName);
- DUMP_NAV_LOGD("sizeof(TEST%s_GROUP) / sizeof(DebugTestFrameGroup), ", grandChildName);
- } else
- DUMP_NAV_LOGD("NULL, 0, ");
- DUMP_NAV_LOGD("\"%s\"\n", childName);
- DUMP_NAV_LOGD("}%c\n", next ? ',' : ' ');
- }
- }
- }
- child = next;
- }
- DUMP_NAV_LOGD("};\n");
- }
- if (top) {
- if (hasChild)
- DUMP_NAV_LOGD("\n} // end of namespace\n\n");
- char name[256];
- char* frameNamePtr = name;
- frameName(frameNamePtr, frameNamePtr + sizeof(name) - 1);
- *frameNamePtr = '\0';
- DUMP_NAV_LOGD("DebugTestFrameGroup TEST%s_GROUP = {\n", name);
- DUMP_NAV_LOGD("TEST%s_RECTS, ", name);
- DUMP_NAV_LOGD("TEST%s_RECT_COUNT, ", name);
- DUMP_NAV_LOGD("TEST%s_RECTPARTS, ", name);
- DUMP_NAV_LOGD("TEST%s_BOUNDS,\n", name);
- DUMP_NAV_LOGD("TEST%s_WIDTH, ", name);
- DUMP_NAV_LOGD("TEST%s_HEIGHT,\n", name);
- DUMP_NAV_LOGD("TEST%s_MAX_H, ", name);
- DUMP_NAV_LOGD("TEST%s_MIN_H, ", name);
- DUMP_NAV_LOGD("TEST%s_MAX_V, ", name);
- DUMP_NAV_LOGD("TEST%s_MIN_V,\n", name);
- DUMP_NAV_LOGD("TEST%s_FOCUS, ", name);
- if (hasChild) {
- child = frame->tree()->firstChild();
- char childName[256];
- char* childNamePtr = childName;
- Builder(child)->mDebug.frameName(childNamePtr, childNamePtr + sizeof(childName) - 1);
- *childNamePtr = '\0';
- DUMP_NAV_LOGD("TEST_SPACE::TEST%s_GROUP, ", childName);
- DUMP_NAV_LOGD("sizeof(TEST_SPACE::TEST%s_GROUP) / sizeof(DebugTestFrameGroup), \n" ,childName);
- } else
- DUMP_NAV_LOGD("NULL, 0, ");
- DUMP_NAV_LOGD("\"%s\"\n", name);
- DUMP_NAV_LOGD("};\n");
-#ifdef DUMP_NAV_CACHE_USING_PRINTF
- if (gNavCacheLogFile)
- fclose(gNavCacheLogFile);
- gNavCacheLogFile = NULL;
- gWriteLogMutex.unlock();
-#endif
- }
-}
-
-void CacheBuilder::Debug::init(char* buffer, size_t size) {
- mBuffer = buffer;
- mBufferSize = size;
- mIndex = 0;
- mPrefix = "";
-}
-
-void CacheBuilder::Debug::groups() {
- Frame* frame = frameAnd();
- Frame* child = frame->tree()->firstChild();
- bool hasChild = child != NULL;
- if (frame->tree()->parent() == NULL && hasChild)
- DUMP_NAV_LOGD("namespace TEST_SPACE {\n\n");
- while (child) {
- Builder(child)->mDebug.groups();
- child = child->tree()->nextSibling();
- }
- if (frame->tree()->parent() == NULL && hasChild)
- DUMP_NAV_LOGD("\n} // end of namespace\n\n");
- Document* doc = frame->document();
- char name[256];
- char* frameNamePtr = name;
- frameName(frameNamePtr, frameNamePtr + sizeof(name) - 1);
- *frameNamePtr = '\0';
- if (doc == NULL) {
- DUMP_NAV_LOGD("// %s has no document\n", name);
- return;
- }
- RenderObject* renderer = doc->renderer();
- if (renderer == NULL) {
- DUMP_NAV_LOGD("// %s has no renderer\n", name);
- return;
- }
- RenderLayer* layer = renderer->enclosingLayer();
- if (layer == NULL) {
- DUMP_NAV_LOGD("// %s has no enclosingLayer\n", name);
- return;
- }
- Node* node = doc;
- Node* focus = doc->focusedNode();
- bool atLeastOne = false;
- do {
- if ((atLeastOne |= isFocusable(node)) != false)
- break;
- } while ((node = node->traverseNextNode()) != NULL);
- int focusIndex = -1;
- if (atLeastOne == false) {
- DUMP_NAV_LOGD("static DebugTestNode TEST%s_RECTS[] = {\n"
- "{{0, 0, 0, 0}, \"\", 0, -1, \"\", {0, 0, 0, 0}, false, 0}\n"
- "};\n\n", name);
- DUMP_NAV_LOGD("static int TEST%s_RECT_COUNT = 1;"
- " // no focusable nodes\n", name);
- DUMP_NAV_LOGD("#define TEST%s_RECTPARTS NULL\n", name);
- } else {
- node = doc;
- int count = 1;
- DUMP_NAV_LOGD("static DebugTestNode TEST%s_RECTS[] = {\n", name);
- do {
- String properties;
- if (hasEventListener(node, eventNames().clickEvent))
- properties.append("ONCLICK | ");
- if (hasEventListener(node, eventNames().mousedownEvent))
- properties.append("MOUSEDOWN | ");
- if (hasEventListener(node, eventNames().mouseupEvent))
- properties.append("MOUSEUP | ");
- if (hasEventListener(node, eventNames().mouseoverEvent))
- properties.append("MOUSEOVER | ");
- if (hasEventListener(node, eventNames().mouseoutEvent))
- properties.append("MOUSEOUT | ");
- if (hasEventListener(node, eventNames().keydownEvent))
- properties.append("KEYDOWN | ");
- if (hasEventListener(node, eventNames().keyupEvent))
- properties.append("KEYUP | ");
- if (CacheBuilder::HasFrame(node))
- properties.append("FRAME | ");
- if (focus == node) {
- properties.append("FOCUS | ");
- focusIndex = count;
- }
- if (node->isKeyboardFocusable(NULL))
- properties.append("KEYBOARD_FOCUSABLE | ");
- if (node->isMouseFocusable())
- properties.append("MOUSE_FOCUSABLE | ");
- if (node->isFocusable())
- properties.append("SIMPLE_FOCUSABLE | ");
- if (properties.isEmpty())
- properties.append("0");
- else
- properties.truncate(properties.length() - 3);
- IntRect rect = node->getRect();
- if (node->hasTagName(HTMLNames::areaTag))
- rect = getAreaRect(static_cast<HTMLAreaElement*>(node));
- char buffer[DEBUG_BUFFER_SIZE];
- memset(buffer, 0, sizeof(buffer));
- mBuffer = buffer;
- mBufferSize = sizeof(buffer);
- mPrefix = "\"\n\"";
- mIndex = snprintf(buffer, sizeof(buffer), "{{%d, %d, %d, %d}, ", rect.x(), rect.y(),
- rect.width(), rect.height());
- localName(node);
- uChar(properties.characters(), properties.length(), false);
- print(", ");
- int parentIndex = ParentIndex(node, count, node->parentNode());
- char scratch[256];
- snprintf(scratch, sizeof(scratch), "%d", parentIndex);
- comma(scratch);
- Element* element = static_cast<Element*>(node);
- if (node->isElementNode() && element->hasID())
- wideString(element->getIdAttribute());
- else if (node->isTextNode()) {
- #if 01 // set to one to abbreviate text that can be omitted from the address detection code
- if (rect.isEmpty() && node->textContent().length() > 100) {
- wideString(node->textContent().characters(), 100, false);
- snprintf(scratch, sizeof(scratch), "/* + %d bytes */",
- node->textContent().length() - 100);
- print(scratch);
- } else
- #endif
- wideString(node->textContent().characters(), node->textContent().length(), true);
- } else if (node->hasTagName(HTMLNames::aTag) ||
- node->hasTagName(HTMLNames::areaTag))
- {
- HTMLAnchorElement* anchor = static_cast<HTMLAnchorElement*>(node);
- wideString(anchor->href());
- } else if (node->hasTagName(HTMLNames::imgTag)) {
- HTMLImageElement* image = static_cast<HTMLImageElement*>(node);
- wideString(image->src());
- } else
- print("\"\"");
- RenderObject* renderer = node->renderer();
- int tabindex = node->isElementNode() ? node->tabIndex() : 0;
- RenderLayer* layer = 0;
- if (renderer) {
- const IntRect& absB = renderer->absoluteBoundingBoxRect();
- bool hasLayer = renderer->hasLayer();
- layer = hasLayer ? toRenderBoxModelObject(renderer)->layer() : 0;
- snprintf(scratch, sizeof(scratch), ", {%d, %d, %d, %d}, %s"
- ", %d, %s, %s},",
- absB.x(), absB.y(), absB.width(), absB.height(),
- renderer->hasOverflowClip() ? "true" : "false", tabindex,
- hasLayer ? "true" : "false",
- hasLayer && layer->isComposited() ? "true" : "false");
- // TODO: add renderer->style()->visibility()
- print(scratch);
- } else
- print(", {0, 0, 0, 0}, false, 0},");
-
- flush();
- snprintf(scratch, sizeof(scratch), "// %d: ", count);
- mPrefix = "\n// ";
- print(scratch);
- //print(renderer ? renderer->information().ascii() : "NO_RENDER_INFO");
- if (node->isElementNode()) {
- Element* element = static_cast<Element*>(node);
- NamedNodeMap* attrs = element->attributes();
- unsigned length = attrs->length();
- if (length > 0) {
- newLine();
- print("// attr: ");
- for (unsigned i = 0; i < length; i++) {
- Attribute* a = attrs->attributeItem(i);
- attr(a->localName(), a->value());
- }
- }
- }
- if (renderer) {
- RenderStyle* style = renderer->style();
- snprintf(scratch, sizeof(scratch), "// renderStyle:"
- " visibility=%s hasBackGround=%d"
- " tapHighlightColor().alpha()=0x%02x"
- " isTransparent()=%s",
- style->visibility() == HIDDEN ? "HIDDEN" : "VISIBLE",
- renderer->hasBackground(), style->tapHighlightColor().alpha(),
- renderer->isTransparent() ? "true" : "false");
- newLine();
- print(scratch);
- RenderBlock* renderBlock = static_cast<RenderBlock*>(renderer);
- if (renderer->isRenderBlock() && renderBlock->hasColumns()) {
- const RenderBox* box = static_cast<RenderBox*>(renderer);
- const IntRect& oRect = box->visibleOverflowRect();
- snprintf(scratch, sizeof(scratch), "// renderBlock:"
- " columnCount=%d columnGap=%d direction=%d"
- " hasOverflowClip=%d overflow=(%d,%d,w=%d,h=%d)",
- renderBlock->columnInfo()->columnCount(), renderBlock->columnGap(),
- renderBlock->style()->direction(), renderer->hasOverflowClip(),
- oRect.x(), oRect.y(), oRect.width(), oRect.height());
- newLine();
- print(scratch);
- }
- }
- #if USE(ACCELERATED_COMPOSITING)
- if (renderer && renderer->hasLayer()) {
- RenderLayer* layer = toRenderBoxModelObject(renderer)->layer();
- RenderLayerBacking* back = layer->backing();
- GraphicsLayer* grLayer = back ? back->graphicsLayer() : 0;
- LayerAndroid* aLayer = grLayer ? grLayer->platformLayer() : 0;
- const SkPicture* pict = aLayer ? aLayer->picture() : 0;
- const IntRect& r = renderer->absoluteBoundingBoxRect();
- snprintf(scratch, sizeof(scratch), "// layer:%p back:%p"
- " gLayer:%p aLayer:%p pict:%p r:(%d,%d,w=%d,h=%d)",
- layer, back, grLayer, aLayer, pict, r.x(), r.y(),
- r.width(), r.height());
- newLine();
- print(scratch);
- }
- #endif
- count++;
- newLine();
- } while ((node = node->traverseNextNode()) != NULL);
- DUMP_NAV_LOGD("}; // focusables = %d\n", count - 1);
- DUMP_NAV_LOGD("\n");
- DUMP_NAV_LOGD("static int TEST%s_RECT_COUNT = %d;\n\n", name, count - 1);
- // look for rects with multiple parts
- node = doc;
- count = 1;
- bool hasRectParts = false;
- int globalOffsetX, globalOffsetY;
- GetGlobalOffset(frame, &globalOffsetX, &globalOffsetY);
- do {
- IntRect rect;
- bool _isFocusable = isFocusable(node) || (node->isTextNode()
- && node->getRect().isEmpty() == false
- );
- int nodeIndex = count++;
- if (_isFocusable == false)
- continue;
- RenderObject* renderer = node->renderer();
- if (renderer == NULL)
- continue;
- WTF::Vector<IntRect> rects;
- IntRect clipBounds = IntRect(0, 0, INT_MAX, INT_MAX);
- IntRect focusBounds = IntRect(0, 0, INT_MAX, INT_MAX);
- IntRect* rectPtr = &focusBounds;
- int imageCount = 0;
- if (node->isTextNode()) {
- Text* textNode = (Text*) node;
- if (CacheBuilder::ConstructTextRects(textNode, 0, textNode,
- INT_MAX, globalOffsetX, globalOffsetY, rectPtr,
- clipBounds, &rects) == false)
- continue;
- } else {
- IntRect nodeBounds = node->getRect();
- if (CacheBuilder::ConstructPartRects(node, nodeBounds, rectPtr,
- globalOffsetX, globalOffsetY, &rects, &imageCount) == false)
- continue;
- }
- unsigned arraySize = rects.size();
- if (arraySize > 1 || (arraySize == 1 && (rectPtr->width() != rect.width())) ||
- rectPtr->height() != rect.height()) {
- if (hasRectParts == false) {
- DUMP_NAV_LOGD("static DebugTestRectPart TEST%s_RECTPARTS[] = {\n", name);
- hasRectParts = true;
- }
- if (node->isTextNode() == false) {
- unsigned rectIndex = 0;
- for (; rectIndex < arraySize; rectIndex++) {
- rectPtr = &rects.at(rectIndex);
- DUMP_NAV_LOGD("{ %d, %d, %d, %d, %d }, // %d\n", nodeIndex,
- rectPtr->x(), rectPtr->y(), rectPtr->width(),
- rectPtr->height(), rectIndex + 1);
- }
- } else {
- RenderText* renderText = (RenderText*) node->renderer();
- InlineTextBox* textBox = renderText->firstTextBox();
- unsigned rectIndex = 0;
- while (textBox) {
- FloatPoint pt = renderText->localToAbsolute();
- IntRect rect = textBox->selectionRect((int) pt.x(), (int) pt.y(), 0, INT_MAX);
- mIndex = 0;
- mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex, "{ %d, %d, %d, %d, %d",
- nodeIndex, rect.x(), rect.y(), rect.width(), rect.height());
- mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex, ", %d, %d, %d",
- textBox->len(), 0 /*textBox->selectionHeight()*/,
- 0 /*textBox->selectionTop()*/);
- mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex, ", %d, %d, %d",
- 0 /*textBox->spaceAdd()*/, textBox->start(), 0 /*textBox->textPos()*/);
- mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex, ", %d, %d, %d, %d",
- textBox->x(), textBox->y(), textBox->logicalWidth(), textBox->logicalHeight());
- int baseline = textBox->renderer()->style(textBox->isFirstLineStyle())->font().ascent();
- mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex, ", %d, %d }, // %d ",
- baseline, imageCount, ++rectIndex);
- wideString(node->textContent().characters() + textBox->start(), textBox->len(), true);
- DUMP_NAV_LOGD("%.*s\n", mIndex, mBuffer);
- textBox = textBox->nextTextBox();
- }
- }
- }
- } while ((node = node->traverseNextNode()) != NULL);
- if (hasRectParts)
- DUMP_NAV_LOGD("{0}\n};\n\n");
- else
- DUMP_NAV_LOGD("static DebugTestRectPart* TEST%s_RECTPARTS = NULL;\n", name);
- }
- int contentsWidth = layer->width();
- int contentsHeight = layer->height();
- DUMP_NAV_LOGD("static int TEST%s_FOCUS = %d;\n", name, focusIndex);
- DUMP_NAV_LOGD("static int TEST%s_WIDTH = %d;\n", name, contentsWidth);
- DUMP_NAV_LOGD("static int TEST%s_HEIGHT = %d;\n\n", name, contentsHeight);
-}
-
-bool CacheBuilder::Debug::isFocusable(Node* node) {
- if (node->hasTagName(HTMLNames::areaTag))
- return true;
- if (node->renderer() == false)
- return false;
- if (node->isKeyboardFocusable(NULL))
- return true;
- if (node->isMouseFocusable())
- return true;
- if (node->isFocusable())
- return true;
- if (CacheBuilder::AnyIsClick(node))
- return false;
- if (CacheBuilder::HasTriggerEvent(node))
- return true;
- return false;
-}
-
-void CacheBuilder::Debug::localName(Node* node) {
- const AtomicString& local = node->localName();
- if (node->isTextNode())
- print("\"#text\"");
- else
- wideString(local.characters(), local.length(), false);
- print(", ");
-}
-
-void CacheBuilder::Debug::newLine(int indent) {
- if (mPrefix[0] != '\n')
- print(&mPrefix[0], 1);
- flush();
- int lastnewline = mIndex - 1;
- while (lastnewline >= 0 && mBuffer[lastnewline] != '\n')
- lastnewline--;
- lastnewline++;
- char* buffer = mBuffer;
- if (lastnewline > 0) {
- DUMP_NAV_LOGD("%.*s", lastnewline, buffer);
- mIndex -= lastnewline;
- buffer += lastnewline;
- }
- size_t prefixLen = strlen(mPrefix);
- int minPrefix = prefixLen - 1;
- while (minPrefix >= 0 && mPrefix[minPrefix] != '\n')
- minPrefix--;
- minPrefix = prefixLen - minPrefix - 1;
- if (mIndex > minPrefix)
- DUMP_NAV_LOGD("%.*s\n", mIndex, buffer);
- mIndex = 0;
- setIndent(indent);
-}
-
-int CacheBuilder::Debug::ParentIndex(Node* node, int count, Node* parent)
-{
- if (parent == NULL)
- return -1;
- ASSERT(node != parent);
- int result = count;
- Node* previous = node;
- do {
- result--;
- previous = previous->traversePreviousNode();
- } while (previous && previous != parent);
- if (previous != NULL)
- return result;
- result = count;
- do {
- result++;
- } while ((node = node->traverseNextNode()) != NULL && node != parent);
- if (node != NULL)
- return result;
- ASSERT(0);
- return -1;
-}
-
-void CacheBuilder::Debug::print(const char* name) {
- print(name, strlen(name));
-}
-
-void CacheBuilder::Debug::print(const char* name, unsigned len) {
- do {
- if (mIndex + len >= DEBUG_BUFFER_SIZE)
- flush();
- int copyLen = mIndex + len < DEBUG_BUFFER_SIZE ?
- len : DEBUG_BUFFER_SIZE - mIndex;
- memcpy(&mBuffer[mIndex], name, copyLen);
- mIndex += copyLen;
- name += copyLen;
- len -= copyLen;
- } while (len > 0);
- mBuffer[mIndex] = '\0';
-}
-
-void CacheBuilder::Debug::setIndent(int indent)
-{
- char scratch[64];
- snprintf(scratch, sizeof(scratch), "%.*s", indent,
- " ");
- print(scratch);
-}
-
-void CacheBuilder::Debug::uChar(const UChar* name, unsigned len, bool hex) {
- const UChar* end = name + len;
- bool wroteHex = false;
- while (name < end) {
- unsigned ch = *name++;
- if (ch == '\t' || ch == '\n' || ch == '\r' || ch == 0xa0)
- ch = ' ';
- if (ch < ' ' || ch == 0x7f) {
- if (hex) {
- mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex, "\\x%02x", ch);
- wroteHex = true;
- } else
- mBuffer[mIndex++] = '?';
- } else if (ch >= 0x80) {
- if (hex) {
- if (ch < 0x800)
- mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex,
- "\\x%02x\\x%02x", ch >> 6 | 0xc0, (ch & 0x3f) | 0x80);
- else
- mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex,
- "\\x%02x\\x%02x\\x%02x", ch >> 12 | 0xe0,
- (ch >> 6 & 0x3f) | 0x80, (ch & 0x3f) | 0x80);
- wroteHex = true;
- } else
- mBuffer[mIndex++] = '?';
- } else {
- if (wroteHex && WTF::isASCIIHexDigit((UChar) ch))
- mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex,
- "\" \"");
- else if (ch == '"' || ch == '\\')
- mBuffer[mIndex++] = '\\';
- mBuffer[mIndex++] = ch;
- wroteHex = false;
- }
- if (mIndex + 1 >= DEBUG_BUFFER_SIZE)
- flush();
- }
- flush();
-}
-
-void CacheBuilder::Debug::validateFrame() {
- Frame* frame = frameAnd();
- Page* page = frame->page();
- ASSERT(page);
- ASSERT((int) page > 0x10000);
- Frame* child = frame->tree()->firstChild();
- while (child) {
- Builder(child)->mDebug.validateFrame();
- child = child->tree()->nextSibling();
- }
-}
-
-void CacheBuilder::Debug::wideString(const UChar* chars, int length, bool hex) {
- if (length == 0)
- print("\"\"");
- else {
- print("\"");
- uChar(chars, length, hex);
- print("\"");
- }
-}
-
-void CacheBuilder::Debug::wideString(const String& str) {
- wideString(str.characters(), str.length(), false);
-}
-
-#endif // DUMP_NAV_CACHE
-
-CacheBuilder::CacheBuilder()
-{
- mAllowableTypes = ALL_CACHEDNODE_BITS;
-#ifdef DUMP_NAV_CACHE_USING_PRINTF
- gNavCacheLogFile = NULL;
-#endif
-}
-
-void CacheBuilder::adjustForColumns(const ClipColumnTracker& track,
- CachedNode* node, IntRect* bounds, RenderBlock* renderer)
-{
- if (!renderer->hasColumns())
- return;
- int x = 0;
- int y = 0;
- int tx = track.mBounds.x();
- int ty = track.mBounds.y();
- int columnGap = track.mColumnGap;
- size_t limit = track.mColumnInfo->columnCount();
- for (size_t index = 0; index < limit; index++) {
- IntRect column = renderer->columnRectAt(track.mColumnInfo, index);
- column.move(tx, ty);
- IntRect test = *bounds;
- test.move(x, y);
- if (column.contains(test)) {
- if ((x | y) == 0)
- return;
- *bounds = test;
- node->move(x, y);
- return;
- }
- int xOffset = column.width() + columnGap;
- x += track.mDirection == LTR ? xOffset : -xOffset;
- y -= column.height();
- }
-}
-
-// Checks if a node has one of event listener types.
-bool CacheBuilder::NodeHasEventListeners(Node* node, AtomicString* eventTypes, int length) {
- for (int i = 0; i < length; ++i) {
- if (!node->getEventListeners(eventTypes[i]).isEmpty())
- return true;
- }
- return false;
-}
-
-bool CacheBuilder::AnyChildIsClick(Node* node)
-{
- AtomicString eventTypes[5] = {
- eventNames().clickEvent,
- eventNames().mousedownEvent,
- eventNames().mouseupEvent,
- eventNames().keydownEvent,
- eventNames().keyupEvent
- };
-
- Node* child = node->firstChild();
- while (child != NULL) {
- if (child->isFocusable() ||
- NodeHasEventListeners(child, eventTypes, 5))
- return true;
- if (AnyChildIsClick(child))
- return true;
- child = child->nextSibling();
- }
- return false;
-}
-
-bool CacheBuilder::AnyIsClick(Node* node)
-{
- if (node->hasTagName(HTMLNames::bodyTag))
- return AnyChildIsClick(node);
-
- AtomicString eventTypeSetOne[4] = {
- eventNames().mouseoverEvent,
- eventNames().mouseoutEvent,
- eventNames().keydownEvent,
- eventNames().keyupEvent
- };
-
- if (!NodeHasEventListeners(node, eventTypeSetOne, 4))
- return false;
-
- AtomicString eventTypeSetTwo[3] = {
- eventNames().clickEvent,
- eventNames().mousedownEvent,
- eventNames().mouseupEvent
- };
-
- if (NodeHasEventListeners(node, eventTypeSetTwo, 3))
- return false;
-
- return AnyChildIsClick(node);
-}
-
-void CacheBuilder::buildCache(CachedRoot* root)
-{
- Frame* frame = FrameAnd(this);
- mPictureSetDisabled = false;
- BuildFrame(frame, frame, root, (CachedFrame*) root);
- root->finishInit(); // set up frame parent pointers, child pointers
- setData((CachedFrame*) root);
-}
-
-static Node* ParentWithChildren(Node* node)
-{
- Node* parent = node;
- while ((parent = parent->parentNode())) {
- if (parent->childNodeCount() > 1)
- return parent;
- }
- return 0;
-}
-
-// FIXME
-// Probably this should check for null instead of the caller. If the
-// Tracker object is the last thing in the dom, checking for null in the
-// caller in some cases fails to set up Tracker state which may be useful
-// to the nodes parsed immediately after the tracked noe.
-static Node* OneAfter(Node* node)
-{
- Node* parent = node;
- Node* sibling = NULL;
- while ((parent = parent->parentNode()) != NULL) {
- sibling = parent->nextSibling();
- if (sibling != NULL)
- break;
- }
- return sibling;
-}
-
-// return true if this renderer is really a pluinview, and it wants
-// key-events (i.e. focus)
-static bool checkForPluginViewThatWantsFocus(RenderObject* renderer) {
- if (renderer->isWidget()) {
- Widget* widget = static_cast<RenderWidget*>(renderer)->widget();
- if (widget && (widget->isPluginView() || widget->isPluginViewBase())) {
- // check if this plugin really wants key events (TODO)
- return true;
- }
- }
- return false;
-}
-
-#if USE(ACCELERATED_COMPOSITING)
-static void AddLayer(CachedFrame* frame, size_t index, const IntPoint& location, int id)
-{
- DBG_NAV_LOGD("frame=%p index=%d loc=(%d,%d) id=%d", frame, index,
- location.x(), location.y(), id);
- CachedLayer cachedLayer;
- cachedLayer.setCachedNodeIndex(index);
- cachedLayer.setOffset(location);
- cachedLayer.setUniqueId(id);
- frame->add(cachedLayer);
-}
-#endif
-
-static int FindColorIndex(WTF::Vector<CachedColor>& colorTracker,
- const CachedColor& cachedColor)
-{
- CachedColor* work = colorTracker.begin() - 1;
- CachedColor* end = colorTracker.end();
- while (++work < end) {
- if (*work == cachedColor)
- return work - colorTracker.begin();
- }
- int result = colorTracker.size();
- colorTracker.grow(result + 1);
- CachedColor& newColor = colorTracker.last();
- newColor = cachedColor;
- return result;
-}
-
-static void InitColor(CachedColor* color)
-{
- color->setFillColor(RenderStyle::initialRingFillColor());
- color->setInnerWidth(RenderStyle::initialRingInnerWidth());
- color->setOuterWidth(RenderStyle::initialRingOuterWidth());
- color->setOutset(RenderStyle::initialRingOutset());
- color->setPressedInnerColor(RenderStyle::initialRingPressedInnerColor());
- color->setPressedOuterColor(RenderStyle::initialRingPressedOuterColor());
- color->setRadius(RenderStyle::initialRingRadius());
- color->setSelectedInnerColor(RenderStyle::initialRingSelectedInnerColor());
- color->setSelectedOuterColor(RenderStyle::initialRingSelectedOuterColor());
-}
-
-// when new focus is found, push it's parent on a stack
- // as long as more focii are found with the same (grand) parent, note it
- // (which only requires retrieving the last parent on the stack)
-// when the parent's last child is found, pop the stack
-// different from Tracker in that Tracker only pushes focii with children
-
-// making this work with focus - child focus - grandchild focus is tricky
-// if I keep the generation number, I may be able to more quickly determine that
-// a node is a grandchild of the focus's parent
-// this additionally requires being able to find the grandchild's parent
-
-// keep nodes that are focusable
-void CacheBuilder::BuildFrame(Frame* root, Frame* frame,
- CachedRoot* cachedRoot, CachedFrame* cachedFrame)
-{
- WTF::Vector<FocusTracker> tracker(1); // sentinel
- {
- FocusTracker* baseTracker = tracker.data();
- bzero(baseTracker, sizeof(FocusTracker));
- baseTracker->mCachedNodeIndex = -1;
- }
- WTF::Vector<LayerTracker> layerTracker(1); // sentinel
- bzero(layerTracker.data(), sizeof(LayerTracker));
- WTF::Vector<ClipColumnTracker> clipTracker(1); // sentinel
- bzero(clipTracker.data(), sizeof(ClipColumnTracker));
- WTF::Vector<TabIndexTracker> tabIndexTracker(1); // sentinel
- bzero(tabIndexTracker.data(), sizeof(TabIndexTracker));
- WTF::Vector<CachedColor> colorTracker(1);
- InitColor(colorTracker.data());
-#if DUMP_NAV_CACHE
- char* frameNamePtr = cachedFrame->mDebug.mFrameName;
- Builder(frame)->mDebug.frameName(frameNamePtr, frameNamePtr +
- sizeof(cachedFrame->mDebug.mFrameName) - 1);
- *frameNamePtr = '\0';
- int nodeIndex = 1;
-#endif
- NodeWalk walk;
- Document* doc = frame->document();
- Node* parent = doc;
- CachedNode cachedParentNode;
- cachedParentNode.init(parent);
-#if DUMP_NAV_CACHE
- cachedParentNode.mDebug.mNodeIndex = nodeIndex;
-#endif
- cachedFrame->add(colorTracker[0]);
- cachedFrame->add(cachedParentNode);
- Node* node = parent;
- int cacheIndex = 1;
- int colorIndex = 0; // assume no special css ring colors
- const void* lastStyleDataPtr = 0;
- int textInputIndex = 0;
- Node* focused = doc->focusedNode();
- if (focused)
- cachedRoot->setFocusBounds(focused->getRect());
- int globalOffsetX, globalOffsetY;
- GetGlobalOffset(frame, &globalOffsetX, &globalOffsetY);
-#if USE(ACCELERATED_COMPOSITING)
- // The frame itself might be composited so we need to track the layer. Do
- // not track the base frame's layer as the main content is draw as part of
- // BaseLayerAndroid's picture.
- if (frame != root && frame->contentRenderer()
- && frame->contentRenderer()->usesCompositing() && node->lastChild())
- TrackLayer(layerTracker, frame->contentRenderer(), node->lastChild(),
- globalOffsetX, globalOffsetY);
-#endif
- while (walk.mMore || (node = node->traverseNextNode()) != NULL) {
-#if DUMP_NAV_CACHE
- nodeIndex++;
-#endif
- FocusTracker* last = &tracker.last();
- int lastChildIndex = cachedFrame->size() - 1;
- while (node == last->mLastChild) {
- if (CleanUpContainedNodes(cachedRoot, cachedFrame, last, lastChildIndex))
- cacheIndex--;
- tracker.removeLast();
- lastChildIndex = last->mCachedNodeIndex;
- last = &tracker.last();
- }
- do {
- const ClipColumnTracker* lastClip = &clipTracker.last();
- if (node != lastClip->mLastChild)
- break;
- clipTracker.removeLast();
- } while (true);
- do {
- const LayerTracker* lastLayer = &layerTracker.last();
- if (node != lastLayer->mLastChild)
- break;
- layerTracker.removeLast();
- } while (true);
- do {
- const TabIndexTracker* lastTabIndex = &tabIndexTracker.last();
- if (node != lastTabIndex->mLastChild)
- break;
- tabIndexTracker.removeLast();
- } while (true);
- Frame* child = HasFrame(node);
- CachedNode cachedNode;
- if (child != NULL) {
- if (child->document() == NULL)
- continue;
- RenderObject* nodeRenderer = node->renderer();
- if (nodeRenderer != NULL && nodeRenderer->style()->visibility() == HIDDEN)
- continue;
- CachedFrame cachedChild;
- cachedChild.init(cachedRoot, cacheIndex, child);
- int childFrameIndex = cachedFrame->childCount();
- cachedFrame->addFrame(cachedChild);
- cachedNode.init(node);
- cachedNode.setIndex(cacheIndex++);
- cachedNode.setDataIndex(childFrameIndex);
- cachedNode.setType(FRAME_CACHEDNODETYPE);
-#if DUMP_NAV_CACHE
- cachedNode.mDebug.mNodeIndex = nodeIndex;
- cachedNode.mDebug.mParentGroupIndex = Debug::ParentIndex(
- node, nodeIndex, NULL);
-#endif
- cachedFrame->add(cachedNode);
- CachedFrame* childPtr = cachedFrame->lastChild();
- BuildFrame(root, child, cachedRoot, childPtr);
- continue;
- }
- int tabIndex = node->tabIndex();
- Node* lastChild = node->lastChild();
- if (tabIndex <= 0)
- tabIndex = tabIndexTracker.last().mTabIndex;
- else if (tabIndex > 0 && lastChild) {
- DBG_NAV_LOGD("tabIndex=%d node=%p", tabIndex, node);
- tabIndexTracker.grow(tabIndexTracker.size() + 1);
- TabIndexTracker& indexTracker = tabIndexTracker.last();
- indexTracker.mTabIndex = tabIndex;
- indexTracker.mLastChild = OneAfter(lastChild);
- }
- RenderObject* nodeRenderer = node->renderer();
- bool isTransparent = false;
- bool hasCursorRing = true;
- if (nodeRenderer != NULL) {
- RenderStyle* style = nodeRenderer->style();
- if (style->visibility() == HIDDEN)
- continue;
- isTransparent = nodeRenderer->hasBackground() == false;
-#ifdef ANDROID_CSS_TAP_HIGHLIGHT_COLOR
- hasCursorRing = style->tapHighlightColor().alpha() > 0;
-#endif
-#if USE(ACCELERATED_COMPOSITING)
- // If this renderer has its own layer and the layer is composited,
- // start tracking it.
- if (lastChild && nodeRenderer->hasLayer() && toRenderBoxModelObject(nodeRenderer)->layer()->backing())
- TrackLayer(layerTracker, nodeRenderer, lastChild, globalOffsetX, globalOffsetY);
-#endif
- }
- bool more = walk.mMore;
- walk.reset();
- // GetGlobalBounds(node, &bounds, false);
- bool computeCursorRings = false;
- bool hasClip = false;
- bool hasMouseOver = false;
- bool isUnclipped = false;
- bool isFocus = node == focused;
- bool takesFocus = false;
- int columnGap = 0;
- int imageCount = 0;
- TextDirection direction = LTR;
- String exported;
- CachedNodeType type = NORMAL_CACHEDNODETYPE;
- CachedColor cachedColor;
- CachedInput cachedInput;
- IntRect bounds;
- IntRect absBounds;
- IntRect originalAbsBounds;
- ColumnInfo* columnInfo = NULL;
- if (node->hasTagName(HTMLNames::areaTag)) {
- type = AREA_CACHEDNODETYPE;
- HTMLAreaElement* area = static_cast<HTMLAreaElement*>(node);
- bounds = getAreaRect(area);
- originalAbsBounds = bounds;
- bounds.move(globalOffsetX, globalOffsetY);
- absBounds = bounds;
- isUnclipped = true; // FIXME: areamaps require more effort to detect
- // assume areamaps are always visible for now
- takesFocus = true;
- goto keepNode;
- }
- if (nodeRenderer == NULL)
- continue;
-
- // some common setup
- absBounds = nodeRenderer->absoluteBoundingBoxRect();
- originalAbsBounds = absBounds;
- absBounds.move(globalOffsetX, globalOffsetY);
- hasClip = nodeRenderer->hasOverflowClip();
-
- if (checkForPluginViewThatWantsFocus(nodeRenderer)) {
- bounds = absBounds;
- isUnclipped = true;
- takesFocus = true;
- type = PLUGIN_CACHEDNODETYPE;
- goto keepNode;
- }
- // Only use the root contentEditable element
- if (node->rendererIsEditable() && !node->parentOrHostNode()->rendererIsEditable()) {
- bounds = absBounds;
- takesFocus = true;
- type = CONTENT_EDITABLE_CACHEDNODETYPE;
- goto keepNode;
- }
- if (nodeRenderer->isRenderBlock()) {
- RenderBlock* renderBlock = (RenderBlock*) nodeRenderer;
- if (renderBlock->hasColumns()) {
- columnInfo = renderBlock->columnInfo();
- columnGap = renderBlock->columnGap();
- direction = renderBlock->style()->direction();
- }
- }
- if ((hasClip != false || columnInfo != NULL) && lastChild) {
- clipTracker.grow(clipTracker.size() + 1);
- ClipColumnTracker& clip = clipTracker.last();
- clip.mBounds = absBounds;
- clip.mLastChild = OneAfter(lastChild);
- clip.mNode = node;
- clip.mColumnInfo = columnInfo;
- clip.mColumnGap = columnGap;
- clip.mHasClip = hasClip;
- clip.mDirection = direction;
- if (columnInfo != NULL) {
- const IntRect& oRect = ((RenderBox*)nodeRenderer)->visualOverflowRect();
- clip.mBounds.move(oRect.x(), oRect.y());
- }
- }
- if (node->isTextNode() && mAllowableTypes != NORMAL_CACHEDNODE_BITS) {
- if (last->mSomeParentTakesFocus) // don't look at text inside focusable node
- continue;
- CachedNodeType checkType;
- if (isFocusableText(&walk, more, node, &checkType,
- &exported) == false)
- continue;
- #if DUMP_NAV_CACHE
- {
- char buffer[DEBUG_BUFFER_SIZE];
- mDebug.init(buffer, sizeof(buffer));
- mDebug.print("text link found: ");
- mDebug.wideString(exported);
- DUMP_NAV_LOGD("%s\n", buffer);
- }
- #endif
- type = checkType;
- // !!! test ! is the following line correctly needed for frames to work?
- cachedNode.init(node);
- const ClipColumnTracker& clipTrack = clipTracker.last();
- const IntRect& clip = clipTrack.mHasClip ? clipTrack.mBounds :
- IntRect(0, 0, INT_MAX, INT_MAX);
- if (ConstructTextRects((WebCore::Text*) node, walk.mStart,
- (WebCore::Text*) walk.mFinalNode, walk.mEnd, globalOffsetX,
- globalOffsetY, &bounds, clip, &cachedNode.mCursorRing) == false)
- continue;
- absBounds = bounds;
- cachedNode.setBounds(bounds);
- if (bounds.width() < MINIMUM_FOCUSABLE_WIDTH)
- continue;
- if (bounds.height() < MINIMUM_FOCUSABLE_HEIGHT)
- continue;
- computeCursorRings = true;
- isUnclipped = true; // FIXME: to hide or partially occlude synthesized links, each
- // focus ring will also need the offset and length of characters
- // used to produce it
- goto keepTextNode;
- }
- if (node->hasTagName(WebCore::HTMLNames::inputTag)) {
- HTMLInputElement* input = static_cast<HTMLInputElement*>(node);
- if (input->isTextField()) {
- if (input->readOnly())
- continue;
- type = TEXT_INPUT_CACHEDNODETYPE;
- cachedInput.init();
- cachedInput.setAutoComplete(input->autoComplete());
- cachedInput.setSpellcheck(input->spellcheck());
- cachedInput.setFormPointer(input->form());
- cachedInput.setIsTextField(true);
- exported = input->value().threadsafeCopy();
- cachedInput.setMaxLength(input->maxLength());
- cachedInput.setTypeFromElement(input);
- // If this does not need to be threadsafe, we can use crossThreadString().
- // See http://trac.webkit.org/changeset/49160.
- cachedInput.setName(input->name().string().threadsafeCopy());
- // can't detect if this is drawn on top (example: deviant.com login parts)
- isUnclipped = isTransparent;
- } else if (input->isInputTypeHidden())
- continue;
- else if (input->isRadioButton() || input->isCheckbox())
- isTransparent = false;
- } else if (node->hasTagName(HTMLNames::textareaTag)) {
- HTMLTextAreaElement* area = static_cast<HTMLTextAreaElement*>(node);
- if (area->readOnly())
- continue;
- cachedInput.init();
- type = TEXT_INPUT_CACHEDNODETYPE;
- cachedInput.setFormPointer(area->form());
- cachedInput.setIsTextArea(true);
- cachedInput.setSpellcheck(area->spellcheck());
- exported = area->value().threadsafeCopy();
- } else if (node->hasTagName(HTMLNames::aTag)) {
- const HTMLAnchorElement* anchorNode =
- (const HTMLAnchorElement*) node;
- if (!anchorNode->isFocusable() && !HasTriggerEvent(node))
- continue;
- if (node->disabled())
- continue;
- hasMouseOver = NodeHasEventListeners(node, &eventNames().mouseoverEvent, 1);
- type = ANCHOR_CACHEDNODETYPE;
- KURL href = anchorNode->href();
- if (!href.isEmpty() && !WebCore::protocolIsJavaScript(href.string()))
- // Set the exported string for all non-javascript anchors.
- exported = href.string().threadsafeCopy();
- } else if (node->hasTagName(HTMLNames::selectTag)) {
- type = SELECT_CACHEDNODETYPE;
- }
- if (type == TEXT_INPUT_CACHEDNODETYPE) {
- RenderTextControl* renderText =
- static_cast<RenderTextControl*>(nodeRenderer);
- if (isFocus)
- cachedRoot->setSelection(renderText->selectionStart(), renderText->selectionEnd());
- // FIXME: Are we sure there will always be a style and font, and it's correct?
- RenderStyle* style = nodeRenderer->style();
- if (style) {
- isUnclipped |= !style->hasAppearance();
- int lineHeight = -1;
- Length lineHeightLength = style->lineHeight();
- // If the lineHeight is negative, WebTextView will calculate it
- // based on the text size, using the Paint.
- // See RenderStyle.computedLineHeight.
- if (lineHeightLength.isPositive())
- lineHeight = style->computedLineHeight();
- cachedInput.setLineHeight(lineHeight);
- cachedInput.setTextSize(style->font().size());
- cachedInput.setIsRtlText(style->direction() == RTL
- || style->textAlign() == WebCore::RIGHT
- || style->textAlign() == WebCore::WEBKIT_RIGHT);
- }
- cachedInput.setPaddingLeft(renderText->paddingLeft() + renderText->borderLeft());
- cachedInput.setPaddingTop(renderText->paddingTop() + renderText->borderTop());
- cachedInput.setPaddingRight(renderText->paddingRight() + renderText->borderRight());
- cachedInput.setPaddingBottom(renderText->paddingBottom() + renderText->borderBottom());
- }
- takesFocus = true;
- bounds = absBounds;
- if (type != ANCHOR_CACHEDNODETYPE) {
- bool isFocusable = node->isKeyboardFocusable(NULL) ||
- node->isMouseFocusable() || node->isFocusable();
- if (isFocusable == false) {
- if (node->disabled())
- continue;
- bool overOrOut = HasOverOrOut(node);
- bool hasTrigger = HasTriggerEvent(node);
- if (overOrOut == false && hasTrigger == false)
- continue;
- takesFocus = hasTrigger;
- }
- }
- computeCursorRings = true;
- keepNode:
- cachedNode.init(node);
- if (computeCursorRings == false) {
- cachedNode.setBounds(bounds);
- cachedNode.mCursorRing.append(bounds);
- } else if (ConstructPartRects(node, bounds, &cachedNode.mBounds,
- globalOffsetX, globalOffsetY, &cachedNode.mCursorRing,
- &imageCount) == false)
- continue;
- keepTextNode:
- if (nodeRenderer) { // area tags' node->renderer() == 0
- RenderStyle* style = nodeRenderer->style();
- const void* styleDataPtr = style->ringData();
- // to save time, see if we're pointing to the same style data as before
- if (lastStyleDataPtr != styleDataPtr) {
- lastStyleDataPtr = styleDataPtr;
- cachedColor.setFillColor(style->ringFillColor());
- cachedColor.setInnerWidth(style->ringInnerWidth());
- cachedColor.setOuterWidth(style->ringOuterWidth());
- cachedColor.setOutset(style->ringOutset());
- cachedColor.setPressedInnerColor(style->ringPressedInnerColor());
- cachedColor.setPressedOuterColor(style->ringPressedOuterColor());
- cachedColor.setRadius(style->ringRadius());
- cachedColor.setSelectedInnerColor(style->ringSelectedInnerColor());
- cachedColor.setSelectedOuterColor(style->ringSelectedOuterColor());
- int oldSize = colorTracker.size();
- colorIndex = FindColorIndex(colorTracker, cachedColor);
- if (colorIndex == oldSize)
- cachedFrame->add(cachedColor);
- }
- } else
- colorIndex = 0;
- IntRect clip = hasClip ? bounds : absBounds;
- size_t clipIndex = clipTracker.size();
- if (clipTracker.last().mNode == node)
- clipIndex -= 1;
- while (--clipIndex > 0) {
- const ClipColumnTracker& clipTrack = clipTracker.at(clipIndex);
- if (clipTrack.mHasClip == false) {
- adjustForColumns(clipTrack, &cachedNode, &absBounds, static_cast<RenderBlock*>(nodeRenderer));
- continue;
- }
- const IntRect& parentClip = clipTrack.mBounds;
- if (hasClip == false && type == ANCHOR_CACHEDNODETYPE)
- clip = parentClip;
- else
- clip.intersect(parentClip);
- hasClip = true;
- }
- bool isInLayer = false;
-#if USE(ACCELERATED_COMPOSITING)
- // If this renderer has a composited parent layer (including itself),
- // add the node to the cached layer.
- // FIXME: does not work for area rects
- RenderLayer* enclosingLayer = nodeRenderer->enclosingLayer();
- if (enclosingLayer && enclosingLayer->enclosingCompositingLayer()) {
- LayerAndroid* layer = layerTracker.last().mLayer;
- if (layer) {
- const IntRect& layerClip = layerTracker.last().mBounds;
- if (!layerClip.isEmpty() && !cachedNode.clip(layerClip)) {
- DBG_NAV_LOGD("skipped on layer clip %d", cacheIndex);
- continue; // skip this node if outside of the clip
- }
- isInLayer = true;
- isUnclipped = true; // assume that layers do not have occluded nodes
- hasClip = false;
- AddLayer(cachedFrame, cachedFrame->size(), layerClip.location(),
- layer->uniqueId());
- }
- }
-#endif
- if (hasClip) {
- if (clip.isEmpty())
- continue; // skip this node if clip prevents all drawing
- else if (cachedNode.clip(clip) == false)
- continue; // skip this node if outside of the clip
- }
- cachedNode.setColorIndex(colorIndex);
- cachedNode.setExport(exported);
- cachedNode.setHasCursorRing(hasCursorRing);
- cachedNode.setHasMouseOver(hasMouseOver);
- cachedNode.setHitBounds(absBounds);
- cachedNode.setIndex(cacheIndex);
- cachedNode.setIsFocus(isFocus);
- cachedNode.setIsInLayer(isInLayer);
- cachedNode.setIsTransparent(isTransparent);
- cachedNode.setIsUnclipped(isUnclipped);
- cachedNode.setOriginalAbsoluteBounds(originalAbsBounds);
- cachedNode.setParentIndex(last->mCachedNodeIndex);
- cachedNode.setParentGroup(ParentWithChildren(node));
- cachedNode.setSingleImage(imageCount == 1);
- cachedNode.setTabIndex(tabIndex);
- cachedNode.setType(type);
- if (type == TEXT_INPUT_CACHEDNODETYPE) {
- cachedFrame->add(cachedInput);
- cachedNode.setDataIndex(textInputIndex);
- textInputIndex++;
- } else
- cachedNode.setDataIndex(-1);
-#if DUMP_NAV_CACHE
- cachedNode.mDebug.mNodeIndex = nodeIndex;
- cachedNode.mDebug.mParentGroupIndex = Debug::ParentIndex(
- node, nodeIndex, (Node*) cachedNode.parentGroup());
-#endif
- cachedFrame->add(cachedNode);
- {
- int lastIndex = cachedFrame->size() - 1;
- if (node == focused) {
- CachedNode* cachedNodePtr = cachedFrame->getIndex(lastIndex);
- cachedRoot->setCachedFocus(cachedFrame, cachedNodePtr);
- }
- if (lastChild != NULL) {
- tracker.grow(tracker.size() + 1);
- FocusTracker& working = tracker.last();
- working.mCachedNodeIndex = lastIndex;
- working.mLastChild = OneAfter(lastChild);
- last = &tracker.at(tracker.size() - 2);
- working.mSomeParentTakesFocus = last->mSomeParentTakesFocus | takesFocus;
- }
- }
- cacheIndex++;
- }
- while (tracker.size() > 1) {
- FocusTracker* last = &tracker.last();
- int lastChildIndex = cachedFrame->size() - 1;
- if (CleanUpContainedNodes(cachedRoot, cachedFrame, last, lastChildIndex))
- cacheIndex--;
- tracker.removeLast();
- }
-}
-
-bool CacheBuilder::CleanUpContainedNodes(CachedRoot* cachedRoot,
- CachedFrame* cachedFrame, const FocusTracker* last, int lastChildIndex)
-{
- // if outer is body, disable outer
- // or if there's more than one inner, disable outer
- // or if inner is keyboard focusable, disable outer
- // else disable inner by removing it
- int childCount = lastChildIndex - last->mCachedNodeIndex;
- if (childCount == 0)
- return false;
- CachedNode* lastCached = cachedFrame->getIndex(last->mCachedNodeIndex);
- Node* lastNode = (Node*) lastCached->nodePointer();
- if ((childCount > 1 && lastNode->hasTagName(HTMLNames::selectTag) == false) ||
- lastNode->hasTagName(HTMLNames::bodyTag) ||
- lastNode->hasTagName(HTMLNames::formTag)) {
- lastCached->setBounds(IntRect(0, 0, 0, 0));
- lastCached->mCursorRing.clear();
- return false;
- }
- CachedNode* onlyChildCached = cachedFrame->lastNode();
- Node* onlyChild = (Node*) onlyChildCached->nodePointer();
- bool outerIsMouseMoveOnly =
- lastNode->isKeyboardFocusable(NULL) == false &&
- lastNode->isMouseFocusable() == false &&
- lastNode->isFocusable() == false &&
- HasOverOrOut(lastNode) == true &&
- HasTriggerEvent(lastNode) == false;
- if (onlyChildCached->parent() == lastCached)
- onlyChildCached->setParentIndex(lastCached->parentIndex());
- bool hasFocus = lastCached->isFocus() || onlyChildCached->isFocus();
- if (outerIsMouseMoveOnly || onlyChild->isKeyboardFocusable(NULL)
- || onlyChildCached->isPlugin()) {
- int index = lastCached->index();
- *lastCached = *onlyChildCached;
- lastCached->setIndex(index);
- CachedFrame* frame = cachedFrame->hasFrame(lastCached);
- if (frame)
- frame->setIndexInParent(index);
- }
- cachedFrame->removeLast();
- if (hasFocus)
- cachedRoot->setCachedFocus(cachedFrame, cachedFrame->lastNode());
- return true;
-}
-
-Node* CacheBuilder::currentFocus() const
-{
- Frame* frame = FrameAnd(this);
- Document* doc = frame->document();
- if (doc != NULL) {
- Node* focus = doc->focusedNode();
- if (focus != NULL)
- return focus;
- }
- Frame* child = frame->tree()->firstChild();
- while (child) {
- CacheBuilder* cacheBuilder = Builder(child);
- Node* focus = cacheBuilder->currentFocus();
- if (focus)
- return focus;
- child = child->tree()->nextSibling();
- }
- return NULL;
-}
-
-static bool strCharCmp(const char* matches, const UChar* test, int wordLength,
- int wordCount)
-{
- for (int index = 0; index < wordCount; index++) {
- for (int inner = 0; inner < wordLength; inner++) {
- if (matches[inner] != test[inner]) {
- matches += wordLength;
- goto next;
- }
- }
- return true;
-next:
- ;
- }
- return false;
-}
-
-static const int stateTwoLetter[] = {
- 0x02060c00, // A followed by: [KLRSZ]
- 0x00000000, // B
- 0x00084001, // C followed by: [AOT]
- 0x00000014, // D followed by: [CE]
- 0x00000000, // E
- 0x00001800, // F followed by: [LM]
- 0x00100001, // G followed by: [AU]
- 0x00000100, // H followed by: [I]
- 0x00002809, // I followed by: [ADLN]
- 0x00000000, // J
- 0x01040000, // K followed by: [SY]
- 0x00000001, // L followed by: [A]
- 0x000ce199, // M followed by: [ADEHINOPST]
- 0x0120129c, // N followed by: [CDEHJMVY]
- 0x00020480, // O followed by: [HKR]
- 0x00420001, // P followed by: [ARW]
- 0x00000000, // Q
- 0x00000100, // R followed by: [I]
- 0x0000000c, // S followed by: [CD]
- 0x00802000, // T followed by: [NX]
- 0x00080000, // U followed by: [T]
- 0x00080101, // V followed by: [AIT]
- 0x01200101 // W followed by: [AIVY]
-};
-
-static const char firstIndex[] = {
- 0, 5, 5, 8, 10, 10, 12, 14,
- 15, 19, 19, 21, 22, 32, 40, 43,
- 46, 46, 47, 49, 51, 52, 55, 59
-};
-
-// from http://infolab.stanford.edu/~manku/bitcount/bitcount.html
-#define TWO(c) (0x1u << (c))
-#define MASK(c) (((unsigned int)(-1)) / (TWO(TWO(c)) + 1u))
-#define COUNT(x,c) ((x) & MASK(c)) + (((x) >> (TWO(c))) & MASK(c))
-
-int bitcount (unsigned int n)
-{
- n = COUNT(n, 0);
- n = COUNT(n, 1);
- n = COUNT(n, 2);
- n = COUNT(n, 3);
- return COUNT(n, 4);
-}
-
-#undef TWO
-#undef MASK
-#undef COUNT
-
-static bool isUnicodeSpace(UChar ch)
-{
- return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' || ch == 0xa0;
-}
-
-static bool validZip(int stateIndex, const UChar* zipPtr)
-{
- static const struct {
- char mLow;
- char mHigh;
- char mException1;
- char mException2;
- } zipRange[] = {
- { 99, 99, -1, -1 }, // AK Alaska
- { 35, 36, -1, -1 }, // AL Alabama
- { 71, 72, -1, -1 }, // AR Arkansas
- { 96, 96, -1, -1 }, // AS American Samoa
- { 85, 86, -1, -1 }, // AZ Arizona
- { 90, 96, -1, -1 }, // CA California
- { 80, 81, -1, -1 }, // CO Colorado
- { 6, 6, -1, -1 }, // CT Connecticut
- { 20, 20, -1, -1 }, // DC District of Columbia
- { 19, 19, -1, -1 }, // DE Delaware
- { 32, 34, -1, -1 }, // FL Florida
- { 96, 96, -1, -1 }, // FM Federated States of Micronesia
- { 30, 31, -1, -1 }, // GA Georgia
- { 96, 96, -1, -1 }, // GU Guam
- { 96, 96, -1, -1 }, // HI Hawaii
- { 50, 52, -1, -1 }, // IA Iowa
- { 83, 83, -1, -1 }, // ID Idaho
- { 60, 62, -1, -1 }, // IL Illinois
- { 46, 47, -1, -1 }, // IN Indiana
- { 66, 67, 73, -1 }, // KS Kansas
- { 40, 42, -1, -1 }, // KY Kentucky
- { 70, 71, -1, -1 }, // LA Louisiana
- { 1, 2, -1, -1 }, // MA Massachusetts
- { 20, 21, -1, -1 }, // MD Maryland
- { 3, 4, -1, -1 }, // ME Maine
- { 96, 96, -1, -1 }, // MH Marshall Islands
- { 48, 49, -1, -1 }, // MI Michigan
- { 55, 56, -1, -1 }, // MN Minnesota
- { 63, 65, -1, -1 }, // MO Missouri
- { 96, 96, -1, -1 }, // MP Northern Mariana Islands
- { 38, 39, -1, -1 }, // MS Mississippi
- { 55, 56, -1, -1 }, // MT Montana
- { 27, 28, -1, -1 }, // NC North Carolina
- { 58, 58, -1, -1 }, // ND North Dakota
- { 68, 69, -1, -1 }, // NE Nebraska
- { 3, 4, -1, -1 }, // NH New Hampshire
- { 7, 8, -1, -1 }, // NJ New Jersey
- { 87, 88, 86, -1 }, // NM New Mexico
- { 88, 89, 96, -1 }, // NV Nevada
- { 10, 14, 0, 6 }, // NY New York
- { 43, 45, -1, -1 }, // OH Ohio
- { 73, 74, -1, -1 }, // OK Oklahoma
- { 97, 97, -1, -1 }, // OR Oregon
- { 15, 19, -1, -1 }, // PA Pennsylvania
- { 6, 6, 0, 9 }, // PR Puerto Rico
- { 96, 96, -1, -1 }, // PW Palau
- { 2, 2, -1, -1 }, // RI Rhode Island
- { 29, 29, -1, -1 }, // SC South Carolina
- { 57, 57, -1, -1 }, // SD South Dakota
- { 37, 38, -1, -1 }, // TN Tennessee
- { 75, 79, 87, 88 }, // TX Texas
- { 84, 84, -1, -1 }, // UT Utah
- { 22, 24, 20, -1 }, // VA Virginia
- { 6, 9, -1, -1 }, // VI Virgin Islands
- { 5, 5, -1, -1 }, // VT Vermont
- { 98, 99, -1, -1 }, // WA Washington
- { 53, 54, -1, -1 }, // WI Wisconsin
- { 24, 26, -1, -1 }, // WV West Virginia
- { 82, 83, -1, -1 } // WY Wyoming
- };
-
- int zip = zipPtr[0] - '0';
- zip *= 10;
- zip += zipPtr[1] - '0';
- int low = zipRange[stateIndex].mLow;
- int high = zipRange[stateIndex].mHigh;
- if (zip >= low && zip <= high)
- return true;
- if (zip == zipRange[stateIndex].mException1)
- return true;
- if (zip == zipRange[stateIndex].mException2)
- return true;
- return false;
-}
-
-#define MAX_PLACE_NAME_LENGTH 25 // the longest allowable one word place name
-
-CacheBuilder::FoundState CacheBuilder::FindAddress(const UChar* chars,
- unsigned length, int* start, int* end, bool caseInsensitive)
-{
- FindState addressState;
- FindReset(&addressState);
- addressState.mWords[0] = addressState.mStarts[0] = chars;
- addressState.mCaseInsensitive = caseInsensitive;
- FoundState state = FindPartialAddress(chars, chars, length, &addressState);
- if (state == FOUND_PARTIAL && addressState.mProgress == ZIP_CODE &&
- addressState.mNumberCount == 0) {
- addressState.mProgress = FIND_STREET;
- state = FindPartialAddress(NULL, NULL, 0, &addressState);
- }
- *start = addressState.mStartResult;
- *end = addressState.mEndResult;
- return state;
-}
-
-CacheBuilder::FoundState CacheBuilder::FindPartialAddress(const UChar* baseChars,
- const UChar* chars, unsigned length, FindState* s)
-{
- // lower case letters are optional; trailing asterisk is optional 's'
- static char const* const longStreetNames[] = {
- "\x04" "LleY" "\x04" "NneX" "\x05" "RCade" "\x05" "VEnue" "\x06" "LAMEDA", // A
- "\x04" "aYoU" "\x04" "eaCH" "\x03" "eND" "\x05" "LuFf*" "\x05" "oTtoM"
- "\x08" "ouLeVarD" "\x05" "Ranch" "\x05" "RidGe" "\x05" "RooK*"
- "\x04" "urG*" "\x05" "YPass" "\x07" "roadWAY", // B
- "\x05" "AMINO"
- "\x03" "amP" "\x05" "anYoN" "\x03" "aPE" "\x07" "auSeWaY" "\x06" "enTeR*"
- "\x06" "IRcle*" "\x05" "LiFf*" "\x03" "LuB" "\x05" "oMmoN" "\x06" "ORner*"
- "\x05" "ouRSE" "\x05" "ourT*" "\x04" "oVe*" "\x04" "ReeK" "\x07" "REScent"
- "\x04" "ReST" "\x07" "ROSSING" "\x08" "ROSSROAD" "\x04" "URVe"
- "\x05" "AMINO" "\x06" "IRCULO" "\x07" "REScent", // C
- "\x03" "aLe" "\x02" "aM" "\x05" "iVide" "\x05" "Rive*", // D
- "\x06" "STate*" "\x09" "XPresswaY" "\x09" "XTension*", // E
- "\x04" "ALL*" "\x04" "eRrY" "\x05" "ieLD*" "\x04" "LaT*" "\x04" "oRD*"
- "\x05" "oReST" "\x05" "oRGe*" "\x04" "oRK*" "\x03" "orT" "\x06" "reeWaY", // F
- "\x06" "arDeN*" "\x06" "aTeWaY" "\x04" "LeN*" "\x05" "ReeN*" "\x05" "RoVe*", // G
- "\x06" "arBoR*" "\x04" "aVeN" "\x06" "eighTS" "\x06" "ighWaY" "\x04" "iLl*"
- "\x05" "OLloW", // H
- "\x04" "NLeT" "\x06" "Sland*" "\x03" "SLE", // I
- "\x08" "unCTion*", // J
- "\x03" "eY*" "\x05" "NoLl*", // K
- "\x04" "aKe*" "\x03" "AND" "\x06" "aNDinG" "\x03" "aNe" "\x05" "iGhT*"
- "\x03" "oaF" "\x04" "oCK*" "\x04" "oDGe" "\x03" "OOP", // L
- "\x03" "ALL" "\x05" "aNoR*" "\x06" "eaDoW*" "\x03" "EWS" "\x04" "iLl*"
- "\x06" "iSsioN" "\x07" "oTorWaY" "\x04" "ounT" "\x08" "ounTaiN*", // M
- "\x03" "eCK", // N
- "\x06" "RCHard" "\x03" "VAL" "\x07" "verPASs", // O
- "\x04" "ARK*" "\x07" "arKWaY*" "\x03" "ASS" "\x06" "aSsaGE" "\x03" "ATH"
- "\x03" "IKE" "\x04" "iNE*" "\x04" "Lace" "\x05" "LaiN*" "\x04" "LaZa"
- "\x05" "oinT*" "\x04" "oRT*" "\x06" "Rairie" "\x06" "RIVADA", // P
- NULL,
- "\x05" "ADiaL" "\x03" "AMP" "\x04" "aNCH" "\x05" "aPiD*"
- "\x03" "eST"
- "\x05" "iDGe*" "\x04" "IVer" "\x04" "oaD*" "\x04" "ouTE" "\x02" "OW"
- "\x02" "UE" "\x02" "UN", // R
- "\x05" "HoaL*" "\x05" "HoRe*" "\x05" "KyWaY" "\x06" "PrinG*" "\x04" "PUR*"
- "\x06" "Quare*" "\x06" "TAtion" "\x08" "TRAvenue" "\x05" "TReaM"
- "\x06" "Treet*" "\x05" "uMmiT" "\x07" "PeeDWaY", // S
- "\x06" "ERrace" "\x09" "hRoughWaY" "\x04" "RaCE" "\x04" "RAcK" "\x09" "RaFficwaY"
- "\x04" "RaiL" "\x05" "UNneL" "\x07" "urnPiKE", // T
- "\x08" "nderPASs" "\x05" "Nion*", // U
- "\x06" "aLleY*" "\x06" "IAduct" "\x04" "ieW*" "\x07" "iLlaGe*" "\x04" "iLle"
- "\x04" "ISta", // V
- "\x04" "ALK*" "\x03" "ALL" "\x03" "AY*" "\x04" "eLl*", // W
- "\x03" "ING" "\x02" "RD", // X
- };
-
- static char const* const longStateNames[] = {
- "\x8e" "la" "\x85" "bama" "\x02" "\x84" "ska" "\x01" "\x8f" "merican Samoa" "\x04"
- "\x91" "r" "\x86" "izona" "\x05" "\x87" "kansas" "\x03",
- NULL,
- "\x8b" "alifornia" "\x06" "\x95" "o" "\x87" "lorado" "\x07" "\x8a" "nnecticut" "\x08",
- "\x89" "elaware" "\x0a" "\x95" "istrict of Columbia" "\x09",
- NULL,
- "\x9f" "ederated States of Micronesia" "\x0c" "\x88" "lorida" "\x0b",
- "\x85" "uam" "\x0e" "\x88" "eorgia" "\x0d",
- "\x87" "awaii" "\x0f",
- "\x86" "daho" "\x11" "\x89" "llinois" "\x12" "\x88" "ndiana" "\x13" "\x85"
- "owa" "\x10",
- NULL,
- "\x87" "ansas" "\x14" "\x89" "entucky" "\x15",
- "\x8a" "ouisiana" "\x16",
- "\x86" "aine" "\x19" "\x99" "ar" "\x8e" "shall Islands" "\x1a" "\x86" "yland" "\x18"
- "\x8e" "assachusetts" "\x17" "\x93" "i" "\x87" "chigan" "\x1b"
- "\x88" "nnesota" "\x1c" "\x93" "iss" "\x88" "issippi" "\x1f" "\x85"
- "ouri" "\x1d" "\x88" "ontana" "\x20",
- "\x90" "e" "\x87" "braska" "\x23" "\x85" "vada" "\x27" "\xa5" "ew " "\x8a"
- "Hampshire" "\x24" "\x87" "Jersey" "\x25" "\x87" "Mexico" "\x26"
- "\x85" "York" "\x28" "\x98" "orth " "\x89" "Carolina" "\x21" "\x87"
- "Dakota" "\x22" "\x99" "orthern Mariana Islands" "\x1e",
- "\x85" "hio" "\x29" "\x89" "klahoma" "\x2a" "\x87" "regon" "\x2b",
- "\x86" "alau" "\x2e" "\x8d" "ennsylvania" "\x2c" "\x8c" "uerto Rico" "\x2d",
- NULL,
- "\x8d" "hode Island" "\x2f",
- "\x98" "outh " "\x89" "Carolina" "\x30" "\x87" "Dakota" "\x31",
- "\x90" "e" "\x88" "nnessee" "\x32" "\x84" "xas" "\x33",
- "\x85" "tah" "\x34",
- "\x88" "ermont" "\x37" "\x94" "irgin" "\x89" " Islands" "\x36" "\x83" "ia" "\x35",
- "\x8b" "ashington" "\x38" "\x8e" "est Virginia" "\x3a" "\x8a" "isconsin" "\x39"
- "\x88" "yoming" "\x3b"
- };
-
-#if 0 // DEBUG_NAV_UI
- static char const* const progressNames[] = {
- "NO_ADDRESS",
- "SKIP_TO_SPACE",
- "HOUSE_NUMBER",
- "NUMBER_TRAILING_SPACE",
- "ADDRESS_LINE",
- "STATE_NAME",
- "SECOND_HALF",
- "ZIP_CODE",
- "PLUS_4",
- "FIND_STREET"
- };
-#endif
- // strategy: US only support at first
- // look for a 1 - 5 digit number for a street number (no support for 'One Microsoft Way')
- // ignore if preceded by '#', Suite, Ste, Rm
- // look for two or more words (up to 5? North Frank Lloyd Wright Blvd)
- // note: "The Circle at North Hills St." has six words, and a lower 'at' -- allow at, by, of, in, the, and, ... ?
- // if a word starts with a lowercase letter, no match
- // allow: , . - # / (for 1/2) ' "
- // don't look for street name type yet
- // look for one or two delimiters to represent possible 2nd addr line and city name
- // look for either full state name, or state two letters, and/or zip code (5 or 9 digits)
- // now look for street suffix, either in full or abbreviated form, with optional 's' if there's an asterisk
-
- s->mCurrentStart = chars;
- s->mEnd = chars + length;
- int candIndex = 0;
- bool retryState;
- bool mustBeAllUpper = false;
- bool secondHalf = false;
- chars -= 1;
- UChar ch = s->mCurrent;
- while (++chars <= s->mEnd) {
- UChar prior = ch;
- ch = chars < s->mEnd ? *chars : ' ';
- switch (s->mProgress) {
- case NO_ADDRESS:
- if (WTF::isASCIIDigit(ch) == false) {
- if (ch != 'O') // letter 'O', not zero
- continue;
- if (s->mEnd - chars < 3)
- continue;
- prior = *++chars;
- ch = *++chars;
- if ((prior != 'n' || ch != 'e') && (prior != 'N' || ch != 'E'))
- continue;
- if (isUnicodeSpace(*++chars) == false)
- continue;
- s->mProgress = ADDRESS_LINE;
- s->mStartResult = chars - 3 - s->mCurrentStart;
- continue;
- }
- if (isUnicodeSpace(prior) == false) {
- s->mProgress = SKIP_TO_SPACE;
- continue;
- }
- s->mNumberCount = 1;
- s->mProgress = HOUSE_NUMBER;
- s->mStartResult = chars - s->mCurrentStart;
- continue;
- case SKIP_TO_SPACE:
- if (isUnicodeSpace(ch) == false)
- continue;
- break;
- case HOUSE_NUMBER:
- if (WTF::isASCIIDigit(ch)) {
- if (++s->mNumberCount >= 6)
- s->mProgress = SKIP_TO_SPACE;
- continue;
- }
- if (WTF::isASCIIUpper(ch)) { // allow one letter after house number, e.g. 12A SKOLFIELD PL, HARPSWELL, ME 04079
- if (WTF::isASCIIDigit(prior) == false)
- s->mProgress = SKIP_TO_SPACE;
- continue;
- }
- if (ch == '-') {
- if (s->mNumberCount > 0) { // permit 21-23 ELM ST
- ++s->mNumberCount;
- continue;
- }
- }
- s->mNumberCount = 0;
- s->mProgress = NUMBER_TRAILING_SPACE;
- case NUMBER_TRAILING_SPACE:
- if (isUnicodeSpace(ch))
- continue;
- if (0 && WTF::isASCIIDigit(ch)) {
- s->mNumberCount = 1;
- s->mProgress = HOUSE_NUMBER;
- s->mStartResult = chars - s->mCurrentStart;
- continue;
- }
- if (WTF::isASCIIDigit(ch) == false && WTF::isASCIIUpper(ch) == false)
- break;
- s->mProgress = ADDRESS_LINE;
- case ADDRESS_LINE:
- if (WTF::isASCIIAlpha(ch) || ch == '\'' || ch == '-' || ch == '&' || ch == '(' || ch == ')') {
- if (++s->mLetterCount > 1) {
- s->mNumberWords &= ~(1 << s->mWordCount);
- continue;
- }
- if (s->mNumberCount >= 5)
- break;
-// FIXME: the test below was added to give up on a non-address, but it
-// incorrectly discards addresses where the house number is in one node
-// and the street name is in the next; I don't recall what the failing case
-// is that suggested this fix.
-// if (s->mWordCount == 0 && s->mContinuationNode)
-// return FOUND_NONE;
- s->newWord(baseChars, chars);
- if (WTF::isASCIILower(ch) && s->mNumberCount == 0)
- s->mFirstLower = chars;
- s->mNumberCount = 0;
- if (WTF::isASCIILower(ch) || (WTF::isASCIIAlpha(ch) == false && ch != '-'))
- s->mNumberWords &= ~(1 << s->mWordCount);
- s->mUnparsed = true;
- continue;
- } else if (s->mLetterCount >= MAX_PLACE_NAME_LENGTH) {
- break;
- } else if (s->mFirstLower != NULL) {
- if (s->mCaseInsensitive)
- goto resetWord;
- size_t length = chars - s->mFirstLower;
- if (length > 3)
- break;
- if (length == 3 && strCharCmp("and" "the", s->mFirstLower, 3, 2) == false)
- break;
- if (length == 2 && strCharCmp("at" "by" "el" "in" "of", s->mFirstLower, 2, 5) == false)
- break;
- goto resetWord;
- }
- if (ch == ',' || ch == '*') { // delimits lines
- // asterisk as delimiter: http://www.sa.sc.edu/wellness/members.html
- if (++s->mLineCount > 5)
- break;
- goto lookForState;
- }
- if (isUnicodeSpace(ch) || prior == '-') {
- lookForState:
- if (s->mUnparsed == false)
- continue;
- const UChar* candidate = s->mWords[s->mWordCount];
- UChar firstLetter = candidate[0];
- if (WTF::isASCIIUpper(firstLetter) == false && WTF::isASCIIDigit(firstLetter) == false)
- goto resetWord;
- s->mWordCount++;
- if ((s->mWordCount == 2 && s->mNumberWords == 3 && WTF::isASCIIDigit(s->mWords[1][1])) || // choose second of 8888 333 Main
- (s->mWordCount >= sizeof(s->mWords) / sizeof(s->mWords[0]) - 1)) { // subtract 1 since state names may have two parts
- // search for simple number already stored since first potential house # didn't pan out
- if (s->mNumberWords == 0)
- break;
- int shift = 0;
- while ((s->mNumberWords & (1 << shift)) == 0)
- shift++;
- s->mNumberWords >>= ++shift;
- if (s->mBases[0] != s->mBases[shift]) // if we're past the original node, bail
- break;
- s->shiftWords(shift);
- s->mStartResult = s->mWords[0] - s->mStarts[0];
- s->mWordCount -= shift;
- // FIXME: need to adjust lineCount to account for discarded delimiters
- }
- if (s->mWordCount < 4)
- goto resetWord;
- firstLetter -= 'A';
- if (firstLetter > 'W' - 'A')
- goto resetWord;
- UChar secondLetter = candidate[1];
- if (prior == '-')
- s->mLetterCount--; // trim trailing dashes, to accept CA-94043
- if (s->mLetterCount == 2) {
- secondLetter -= 'A';
- if (secondLetter > 'Z' - 'A')
- goto resetWord;
- if ((stateTwoLetter[firstLetter] & 1 << secondLetter) != 0) {
- // special case to ignore 'et al'
- if (strCharCmp("ET", s->mWords[s->mWordCount - 2], 2, 1) == false) {
- s->mStateWord = s->mWordCount - 1;
- s->mZipHint = firstIndex[firstLetter] +
- bitcount(stateTwoLetter[firstLetter] & ((1 << secondLetter) - 1));
- goto foundStateName;
- }
- }
- goto resetWord;
- }
- s->mStates = longStateNames[firstLetter];
- if (s->mStates == NULL)
- goto resetWord;
- mustBeAllUpper = false;
- s->mProgress = STATE_NAME;
- unsigned char section = s->mStates[0];
- ASSERT(section > 0x80);
- s->mSectionLength = section & 0x7f;
- candIndex = 1;
- secondHalf = false;
- s->mStateWord = s->mWordCount - 1;
- goto stateName;
- }
- if (WTF::isASCIIDigit(ch)) {
- if (s->mLetterCount == 0) {
- if (++s->mNumberCount > 1)
- continue;
- if (s->mWordCount == 0 && s->mContinuationNode)
- return FOUND_NONE;
- s->newWord(baseChars, chars);
- s->mNumberWords |= 1 << s->mWordCount;
- s->mUnparsed = true;
- }
- continue;
- }
- if (ch == '.') { // optionally can follow letters
- if (s->mLetterCount == 0)
- break;
- if (s->mNumberCount > 0)
- break;
- continue;
- }
- if (ch == '/') // between numbers (1/2) between words (12 Main / Ste 4d)
- goto resetWord;
- if (ch == '#') // can precede numbers, allow it to appear randomly
- goto resetWord;
- if (ch == '"') // sometimes parts of addresses are quoted (FIXME: cite an example here)
- continue;
- break;
- case SECOND_HALF:
- if (WTF::isASCIIAlpha(ch)) {
- if (s->mLetterCount == 0) {
- s->newWord(baseChars, chars);
- s->mWordCount++;
- }
- s->mLetterCount++;
- continue;
- }
- if (WTF::isASCIIDigit(ch) == false) {
- if (s->mLetterCount > 0) {
- s->mProgress = STATE_NAME;
- candIndex = 0;
- secondHalf = true;
- goto stateName;
- }
- continue;
- }
- s->mProgress = ADDRESS_LINE;
- goto resetState;
- case STATE_NAME:
- stateName:
- // pick up length of first section
- do {
- int stateIndex = 1;
- int skip = 0;
- int prefix = 0;
- bool subStr = false;
- do {
- unsigned char match = s->mStates[stateIndex];
- if (match >= 0x80) {
- if (stateIndex == s->mSectionLength)
- break;
- subStr = true;
- // if (skip > 0)
- // goto foundStateName;
- prefix = candIndex;
- skip = match & 0x7f;
- match = s->mStates[++stateIndex];
- }
- UChar candChar = s->mWords[s->mWordCount - 1][candIndex];
- if (mustBeAllUpper && WTF::isASCIILower(candChar))
- goto skipToNext;
- if (match != candChar) {
- if (match != WTF::toASCIILower(candChar)) {
- skipToNext:
- if (subStr == false)
- break;
- if (stateIndex == s->mSectionLength) {
- if (secondHalf) {
- s->mProgress = ADDRESS_LINE;
- goto resetState;
- }
- break;
- }
- stateIndex += skip;
- skip = 0;
- candIndex = prefix;
- continue; // try next substring
- }
- mustBeAllUpper = true;
- }
- int nextindex = stateIndex + 1;
- if (++candIndex >= s->mLetterCount && s->mStates[nextindex] == ' ') {
- s->mProgress = SECOND_HALF;
- s->mStates += nextindex;
- s->mSectionLength -= nextindex;
- goto resetWord;
- }
- if (nextindex + 1 == s->mSectionLength || skip == 2) {
- s->mZipHint = s->mStates[nextindex] - 1;
- goto foundStateName;
- }
- stateIndex += 1;
- skip -= 1;
- } while (true);
- s->mStates += s->mSectionLength;
- ASSERT(s->mStates[0] == 0 || (unsigned) s->mStates[0] > 0x80);
- s->mSectionLength = s->mStates[0] & 0x7f;
- candIndex = 1;
- subStr = false;
- } while (s->mSectionLength != 0);
- s->mProgress = ADDRESS_LINE;
- goto resetState;
- foundStateName:
- s->mEndResult = chars - s->mCurrentStart;
- s->mEndWord = s->mWordCount - 1;
- s->mProgress = ZIP_CODE;
- // a couple of delimiters is an indication that the state name is good
- // or, a non-space / non-alpha-digit is also good
- s->mZipDelimiter = s->mLineCount > 2
- || isUnicodeSpace(ch) == false
- || chars == s->mEnd;
- if (WTF::isASCIIDigit(ch))
- s->mZipStart = chars;
- goto resetState;
- case ZIP_CODE:
- if (WTF::isASCIIDigit(ch)) {
- int count = ++s->mNumberCount;
- if (count == 1) {
- if (WTF::isASCIIDigit(prior))
- ++s->mNumberCount;
- else
- s->mZipStart = chars;
- }
- if (count <= 9)
- continue;
- } else if (isUnicodeSpace(ch)) {
- if (s->mNumberCount == 0) {
- s->mZipDelimiter = true; // two spaces delimit state name
- continue;
- }
- } else if (ch == '-') {
- if (s->mNumberCount == 5 && validZip(s->mZipHint, s->mZipStart)) {
- s->mNumberCount = 0;
- s->mProgress = PLUS_4;
- continue;
- }
- if (s->mNumberCount == 0)
- s->mZipDelimiter = true;
- } else if (WTF::isASCIIAlpha(ch) == false)
- s->mZipDelimiter = true;
- else {
- if (s->mLetterCount == 0) {
- s->newWord(baseChars, chars);
- s->mUnparsed = true;
- }
- ++s->mLetterCount;
- }
- if (s->mNumberCount == 5 || s->mNumberCount == 9) {
- if (validZip(s->mZipHint, s->mZipStart) == false)
- goto noZipMatch;
- s->mEndResult = chars - s->mCurrentStart;
- s->mEndWord = s->mWordCount - 1;
- } else if (s->mZipDelimiter == false) {
- noZipMatch:
- --chars;
- s->mProgress = ADDRESS_LINE;
- continue;
- }
- s->mProgress = FIND_STREET;
- goto findStreet;
- case PLUS_4:
- if (WTF::isASCIIDigit(ch)) {
- if (++s->mNumberCount <= 4)
- continue;
- }
- if (isUnicodeSpace(ch)) {
- if (s->mNumberCount == 0)
- continue;
- }
- if (s->mNumberCount == 4) {
- if (WTF::isASCIIAlpha(ch) == false) {
- s->mEndResult = chars - s->mCurrentStart;
- s->mEndWord = s->mWordCount - 1;
- }
- } else if (s->mNumberCount != 0)
- break;
- s->mProgress = FIND_STREET;
- case FIND_STREET:
- findStreet:
- retryState = false;
- for (int wordsIndex = s->mStateWord - 1; wordsIndex >= 0; --wordsIndex) {
- const UChar* test = s->mWords[wordsIndex];
- UChar letter = test[0];
- letter -= 'A';
- if (letter > 'X' - 'A')
- continue;
- const char* names = longStreetNames[letter];
- if (names == NULL)
- continue;
- int offset;
- while ((offset = *names++) != 0) {
- int testIndex = 1;
- bool abbr = false;
- for (int idx = 0; idx < offset; idx++) {
- char nameLetter = names[idx];
- char testUpper = WTF::toASCIIUpper(test[testIndex]);
- if (nameLetter == '*') {
- if (testUpper == 'S')
- testIndex++;
- break;
- }
- bool fullOnly = WTF::isASCIILower(nameLetter);
- nameLetter = WTF::toASCIIUpper(nameLetter);
- if (testUpper == nameLetter) {
- if (abbr && fullOnly)
- goto nextTest;
- testIndex++;
- continue;
- }
- if (fullOnly == false)
- goto nextTest;
- abbr = true;
- }
- letter = &test[testIndex] < s->mEnds[wordsIndex] ?
- test[testIndex] : ' ';
- if (WTF::isASCIIAlpha(letter) == false && WTF::isASCIIDigit(letter) == false) {
- if (s->mNumberWords != 0) {
- int shift = 0;
- int wordReduction = -1;
- do {
- while ((s->mNumberWords & (1 << shift)) == 0)
- shift++;
- if (shift > wordsIndex)
- break;
- wordReduction = shift;
- } while (s->mNumberWords >> ++shift != 0);
- if (wordReduction >= 0) {
- if (s->mContinuationNode) {
- if (retryState)
- break;
- return FOUND_NONE;
- }
- s->mStartResult = s->mWords[wordReduction] - s->mStarts[wordReduction];
- }
- }
- if (wordsIndex != s->mStateWord - 1)
- return FOUND_COMPLETE;
- retryState = true;
- }
- nextTest:
- names += offset;
- }
- }
- if (retryState) {
- s->mProgress = ADDRESS_LINE;
- s->mStates = NULL;
- continue;
- }
- if (s->mNumberWords != 0) {
- unsigned shift = 0;
- while ((s->mNumberWords & (1 << shift)) == 0)
- shift++;
- s->mNumberWords >>= ++shift;
- if (s->mBases[0] != s->mBases[shift])
- return FOUND_NONE;
- s->shiftWords(shift);
- s->mStartResult = s->mWords[0] - s->mStarts[0];
- s->mWordCount -= shift;
- s->mProgress = ADDRESS_LINE;
- --chars;
- continue;
- }
- break;
- }
- if (s->mContinuationNode)
- return FOUND_NONE;
- s->mProgress = NO_ADDRESS;
- s->mWordCount = s->mLineCount = 0;
- s->mNumberWords = 0;
- resetState:
- s->mStates = NULL;
- resetWord:
- s->mNumberCount = s->mLetterCount = 0;
- s->mFirstLower = NULL;
- s->mUnparsed = false;
- }
- s->mCurrent = ch;
- return s->mProgress == NO_ADDRESS ? FOUND_NONE : FOUND_PARTIAL;
-}
-
-// Recogize common email patterns only. Currently has lots of state, walks text forwards and backwards -- will be
-// a real challenge to adapt to walk text across multiple nodes, I imagine
-// FIXME: it's too hard for the caller to call these incrementally -- it's probably best for this to
-// either walk the node tree directly or make a callout to get the next or previous node, if there is one
-// walking directly will avoid adding logic in caller to track the multiple partial or full nodes that compose this
-// text pattern.
-CacheBuilder::FoundState CacheBuilder::FindPartialEMail(const UChar* chars, unsigned length,
- FindState* s)
-{
- // the following tables were generated by tests/browser/focusNavigation/BrowserDebug.cpp
- // hand-edit at your own risk
- static const int domainTwoLetter[] = {
- 0x02df797c, // a followed by: [cdefgilmnoqrstuwxz]
- 0x036e73fb, // b followed by: [abdefghijmnorstvwyz]
- 0x03b67ded, // c followed by: [acdfghiklmnorsuvxyz]
- 0x02005610, // d followed by: [ejkmoz]
- 0x001e00d4, // e followed by: [ceghrstu]
- 0x00025700, // f followed by: [ijkmor]
- 0x015fb9fb, // g followed by: [abdefghilmnpqrstuwy]
- 0x001a3400, // h followed by: [kmnrtu]
- 0x000f7818, // i followed by: [delmnoqrst]
- 0x0000d010, // j followed by: [emop]
- 0x0342b1d0, // k followed by: [eghimnprwyz]
- 0x013e0507, // l followed by: [abcikrstuvy]
- 0x03fffccd, // m followed by: [acdghklmnopqrstuvwxyz]
- 0x0212c975, // n followed by: [acefgilopruz]
- 0x00001000, // o followed by: [m]
- 0x014e3cf1, // p followed by: [aefghklmnrstwy]
- 0x00000001, // q followed by: [a]
- 0x00504010, // r followed by: [eouw]
- 0x032a7fdf, // s followed by: [abcdeghijklmnortvyz]
- 0x026afeec, // t followed by: [cdfghjklmnoprtvwz]
- 0x03041441, // u followed by: [agkmsyz]
- 0x00102155, // v followed by: [aceginu]
- 0x00040020, // w followed by: [fs]
- 0x00000000, // x
- 0x00180010, // y followed by: [etu]
- 0x00401001, // z followed by: [amw]
- };
-
- static char const* const longDomainNames[] = {
- "\x03" "ero" "\x03" "rpa", // aero, arpa
- "\x02" "iz", // biz
- "\x02" "at" "\x02" "om" "\x03" "oop", // cat, com, coop
- NULL, // d
- "\x02" "du", // edu
- NULL, // f
- "\x02" "ov", // gov
- NULL, // h
- "\x03" "nfo" "\x02" "nt", // info, int
- "\x03" "obs", // jobs
- NULL, // k
- NULL, // l
- "\x02" "il" "\x03" "obi" "\x05" "useum", // mil, mobi, museum
- "\x03" "ame" "\x02" "et", // name, net
- "\x02" "rg", // , org
- "\x02" "ro", // pro
- NULL, // q
- NULL, // r
- NULL, // s
- "\x05" "ravel", // travel
- NULL, // u
- NULL, // v
- NULL, // w
- NULL, // x
- NULL, // y
- NULL, // z
- };
-
- const UChar* start = chars;
- const UChar* end = chars + length;
- while (chars < end) {
- UChar ch = *chars++;
- if (ch != '@')
- continue;
- const UChar* atLocation = chars - 1;
- // search for domain
- ch = *chars++ | 0x20; // convert uppercase to lower
- if (ch < 'a' || ch > 'z')
- continue;
- while (chars < end) {
- ch = *chars++;
- if (IsDomainChar(ch) == false)
- goto nextAt;
- if (ch != '.')
- continue;
- UChar firstLetter = *chars++ | 0x20; // first letter of the domain
- if (chars >= end)
- return FOUND_NONE; // only one letter; must be at least two
- firstLetter -= 'a';
- if (firstLetter > 'z' - 'a')
- continue; // non-letter followed '.'
- int secondLetterMask = domainTwoLetter[firstLetter];
- ch = *chars | 0x20; // second letter of the domain
- ch -= 'a';
- if (ch >= 'z' - 'a')
- continue;
- bool secondMatch = (secondLetterMask & 1 << ch) != 0;
- const char* wordMatch = longDomainNames[firstLetter];
- int wordIndex = 0;
- while (wordMatch != NULL) {
- int len = *wordMatch++;
- char match;
- do {
- match = wordMatch[wordIndex];
- if (match < 0x20)
- goto foundDomainStart;
- if (chars[wordIndex] != match)
- break;
- wordIndex++;
- } while (true);
- wordMatch += len;
- if (*wordMatch == '\0')
- break;
- wordIndex = 0;
- }
- if (secondMatch) {
- wordIndex = 1;
- foundDomainStart:
- chars += wordIndex;
- if (chars < end) {
- ch = *chars;
- if (ch != '.') {
- if (IsDomainChar(ch))
- goto nextDot;
- } else if (chars + 1 < end && IsDomainChar(chars[1]))
- goto nextDot;
- }
- // found domain. Search backwards from '@' for beginning of email address
- s->mEndResult = chars - start;
- chars = atLocation;
- if (chars <= start)
- goto nextAt;
- ch = *--chars;
- if (ch == '.')
- goto nextAt; // mailbox can't end in period
- do {
- if (IsMailboxChar(ch) == false) {
- chars++;
- break;
- }
- if (chars == start)
- break;
- ch = *--chars;
- } while (true);
- UChar firstChar = *chars;
- if (firstChar == '.' || firstChar == '@') // mailbox can't start with period or be empty
- goto nextAt;
- s->mStartResult = chars - start;
- return FOUND_COMPLETE;
- }
- nextDot:
- ;
- }
-nextAt:
- chars = atLocation + 1;
- }
- return FOUND_NONE;
-}
-
-#define PHONE_PATTERN "(200) /-.\\ 100 -. 0000" // poor man's regex: parens optional, any one of punct, digit smallest allowed
-
-CacheBuilder::FoundState CacheBuilder::FindPartialNumber(const UChar* chars, unsigned length,
- FindState* s)
-{
- char* pattern = s->mPattern;
- UChar* store = s->mStorePtr;
- const UChar* start = chars;
- const UChar* end = chars + length;
- const UChar* lastDigit = NULL;
- do {
- bool initialized = s->mInitialized;
- while (chars < end) {
- if (initialized == false) {
- s->mBackTwo = s->mBackOne;
- s->mBackOne = s->mCurrent;
- }
- UChar ch = s->mCurrent = *chars;
- do {
- char patternChar = *pattern;
- switch (patternChar) {
- case '2':
- if (initialized == false) {
- s->mStartResult = chars - start;
- initialized = true;
- }
- case '0':
- case '1':
- if (ch < patternChar || ch > '9')
- goto resetPattern;
- *store++ = ch;
- pattern++;
- lastDigit = chars;
- goto nextChar;
- case '\0':
- if (WTF::isASCIIDigit(ch) == false) {
- *store = '\0';
- goto checkMatch;
- }
- goto resetPattern;
- case ' ':
- if (ch == patternChar)
- goto nextChar;
- break;
- case '(':
- if (ch == patternChar) {
- s->mStartResult = chars - start;
- initialized = true;
- s->mOpenParen = true;
- }
- goto commonPunctuation;
- case ')':
- if ((ch == patternChar) ^ s->mOpenParen)
- goto resetPattern;
- default:
- commonPunctuation:
- if (ch == patternChar) {
- pattern++;
- goto nextChar;
- }
- }
- } while (++pattern); // never false
- nextChar:
- chars++;
- }
- break;
-resetPattern:
- if (s->mContinuationNode)
- return FOUND_NONE;
- FindResetNumber(s);
- pattern = s->mPattern;
- store = s->mStorePtr;
- } while (++chars < end);
-checkMatch:
- if (WTF::isASCIIDigit(s->mBackOne != '1' ? s->mBackOne : s->mBackTwo))
- return FOUND_NONE;
- *store = '\0';
- s->mStorePtr = store;
- s->mPattern = pattern;
- s->mEndResult = lastDigit - start + 1;
- char pState = pattern[0];
- return pState == '\0' ? FOUND_COMPLETE : pState == '(' || (WTF::isASCIIDigit(pState) && WTF::isASCIIDigit(pattern[-1])) ?
- FOUND_NONE : FOUND_PARTIAL;
-}
-
-CacheBuilder::FoundState CacheBuilder::FindPhoneNumber(const UChar* chars, unsigned length,
- int* start, int* end)
-{
- FindState state;
- FindReset(&state);
- FoundState result = FindPartialNumber(chars, length, &state);
- *start = state.mStartResult;
- *end = state.mEndResult;
- return result;
-}
-
-void CacheBuilder::FindReset(FindState* state)
-{
- memset(state, 0, sizeof(FindState));
- state->mCurrent = ' ';
- FindResetNumber(state);
-}
-
-void CacheBuilder::FindResetNumber(FindState* state)
-{
- state->mOpenParen = false;
- state->mPattern = (char*) PHONE_PATTERN;
- state->mStorePtr = state->mStore;
-}
-
-IntRect CacheBuilder::getAreaRect(const HTMLAreaElement* area)
-{
- Node* node = area->document();
- while ((node = node->traverseNextNode()) != NULL) {
- RenderObject* renderer = node->renderer();
- if (renderer && renderer->isRenderImage()) {
- RenderImage* image = static_cast<RenderImage*>(renderer);
- HTMLMapElement* map = image->imageMap();
- if (map) {
- Node* n;
- for (n = map->firstChild(); n;
- n = n->traverseNextNode(map)) {
- if (n == area) {
- if (area->isDefault())
- return image->absoluteBoundingBoxRect();
- return area->computeRect(image);
- }
- }
- }
- }
- }
- return IntRect();
-}
-
-void CacheBuilder::GetGlobalOffset(Node* node, int* x, int * y)
-{
- GetGlobalOffset(node->document()->frame(), x, y);
-}
-
-void CacheBuilder::GetGlobalOffset(Frame* frame, int* x, int* y)
-{
-// TIMER_PROBE(__FUNCTION__);
- ASSERT(x);
- ASSERT(y);
- *x = 0;
- *y = 0;
- if (!frame->view())
- return;
- Frame* parent;
- while ((parent = frame->tree()->parent()) != NULL) {
- const WebCore::IntRect& rect = frame->view()->platformWidget()->getBounds();
- *x += rect.x();
- *y += rect.y();
- frame = parent;
- }
- // TIMER_PROBE_END();
-}
-
-Frame* CacheBuilder::HasFrame(Node* node)
-{
- RenderObject* renderer = node->renderer();
- if (renderer == NULL)
- return NULL;
- if (renderer->isWidget() == false)
- return NULL;
- Widget* widget = static_cast<RenderWidget*>(renderer)->widget();
- if (widget == NULL)
- return NULL;
- if (widget->isFrameView() == false)
- return NULL;
- return static_cast<FrameView*>(widget)->frame();
-}
-
-bool CacheBuilder::HasOverOrOut(Node* node)
-{
- // eventNames are thread-local data, I avoid using 'static' variable here.
- AtomicString eventTypes[2] = {
- eventNames().mouseoverEvent,
- eventNames().mouseoutEvent
- };
-
- return NodeHasEventListeners(node, eventTypes, 2);
-}
-
-bool CacheBuilder::HasTriggerEvent(Node* node)
-{
- AtomicString eventTypes[5] = {
- eventNames().clickEvent,
- eventNames().mousedownEvent,
- eventNames().mouseupEvent,
- eventNames().keydownEvent,
- eventNames().keyupEvent
- };
-
- return NodeHasEventListeners(node, eventTypes, 5);
-}
-
-// #define EMAIL_PATTERN "x@y.d" // where 'x' is letters, numbers, and '-', '.', '_' ; 'y' is 'x' without the underscore, and 'd' is a valid domain
-// - 0x2D . 0x2E 0-9 0x30-39 A-Z 0x41-5A _ 0x5F a-z 0x61-7A
-
-bool CacheBuilder::IsDomainChar(UChar ch)
-{
- static const unsigned body[] = {0x03ff6000, 0x07fffffe, 0x07fffffe}; // 0-9 . - A-Z a-z
- ch -= 0x20;
- if (ch > 'z' - 0x20)
- return false;
- return (body[ch >> 5] & 1 << (ch & 0x1f)) != 0;
-}
-
-bool CacheBuilder::isFocusableText(NodeWalk* walk, bool more, Node* node,
- CachedNodeType* type, String* exported) const
-{
- Text* textNode = static_cast<Text*>(node);
- StringImpl* string = textNode->dataImpl();
- const UChar* baseChars = string->characters();
-// const UChar* originalBase = baseChars;
- int length = string->length();
- int index = 0;
- while (index < length && isUnicodeSpace(baseChars[index]))
- index++;
- if (index >= length)
- return false;
- if (more == false) {
- walk->mStart = 0;
- walk->mEnd = 0;
- walk->mFinalNode = node;
- walk->mLastInline = NULL;
- }
- // starting with this node, search forward for email, phone number, and address
- // if any of the three is found, track it so that the remaining can be looked for later
- FoundState state = FOUND_NONE;
- RenderText* renderer = (RenderText*) node->renderer();
- bool foundBetter = false;
- InlineTextBox* baseInline = walk->mLastInline != NULL ? walk->mLastInline :
- renderer->firstTextBox();
- if (baseInline == NULL)
- return false;
- int start = walk->mEnd;
- InlineTextBox* saveInline;
- int baseStart, firstStart = start;
- saveInline = baseInline;
- baseStart = start;
- for (CachedNodeType checkType = ADDRESS_CACHEDNODETYPE;
- checkType <= PHONE_CACHEDNODETYPE;
- checkType = static_cast<CachedNodeType>(checkType + 1))
- {
- if ((1 << (checkType - 1) & mAllowableTypes) == 0)
- continue;
- InlineTextBox* inlineTextBox = baseInline;
- FindState findState;
- FindReset(&findState);
- start = baseStart;
- if (checkType == ADDRESS_CACHEDNODETYPE) {
- findState.mBases[0] = baseChars;
- findState.mWords[0] = baseChars + start;
- findState.mStarts[0] = baseChars + start;
- }
- Node* lastPartialNode = NULL;
- int lastPartialEnd = -1;
- bool lastPartialMore = false;
- bool firstPartial = true;
- InlineTextBox* lastPartialInline = NULL;
- do {
- do {
- const UChar* chars = baseChars + start;
- length = inlineTextBox == NULL ? 0 :
- inlineTextBox->end() - start + 1;
- bool wasInitialized = findState.mInitialized;
- switch (checkType) {
- case ADDRESS_CACHEDNODETYPE:
- state = FindPartialAddress(baseChars, chars, length, &findState);
- break;
- case EMAIL_CACHEDNODETYPE:
- state = FindPartialEMail(chars, length, &findState);
- break;
- case PHONE_CACHEDNODETYPE:
- state = FindPartialNumber(chars, length, &findState);
- break;
- default:
- ASSERT(0);
- }
- findState.mInitialized = state != FOUND_NONE;
- if (wasInitialized != findState.mInitialized)
- firstStart = start;
- if (state == FOUND_PARTIAL) {
- lastPartialNode = node;
- lastPartialEnd = findState.mEndResult + start;
- lastPartialMore = firstPartial &&
- lastPartialEnd < (int) string->length();
- firstPartial = false;
- lastPartialInline = inlineTextBox;
- findState.mContinuationNode = true;
- } else if (state == FOUND_COMPLETE) {
- if (foundBetter == false || walk->mStart > findState.mStartResult) {
- walk->mStart = findState.mStartResult + firstStart;
- if (findState.mEndResult > 0) {
- walk->mFinalNode = node;
- walk->mEnd = findState.mEndResult + start;
- walk->mMore = node == textNode &&
- walk->mEnd < (int) string->length();
- walk->mLastInline = inlineTextBox;
- } else {
- walk->mFinalNode = lastPartialNode;
- walk->mEnd = lastPartialEnd;
- walk->mMore = lastPartialMore;
- walk->mLastInline = lastPartialInline;
- }
- *type = checkType;
- if (checkType == PHONE_CACHEDNODETYPE) {
- const UChar* store = findState.mStore;
- *exported = String(store);
- } else {
- Node* temp = textNode;
- length = 1;
- start = walk->mStart;
- exported->truncate(0);
- do {
- Text* tempText = static_cast<Text*>(temp);
- StringImpl* string = tempText->dataImpl();
- int end = tempText == walk->mFinalNode ?
- walk->mEnd : string->length();
- exported->append(String(string->substring(
- start, end - start)));
- ASSERT(end > start);
- length += end - start + 1;
- if (temp == walk->mFinalNode)
- break;
- start = 0;
- do {
- temp = temp->traverseNextNode();
- ASSERT(temp);
- } while (temp->isTextNode() == false);
- // add a space in between text nodes to avoid
- // words collapsing together
- exported->append(" ");
- } while (true);
- }
- foundBetter = true;
- }
- goto tryNextCheckType;
- } else if (findState.mContinuationNode)
- break;
- if (inlineTextBox == NULL)
- break;
- inlineTextBox = inlineTextBox->nextTextBox();
- if (inlineTextBox == NULL)
- break;
- start = inlineTextBox->start();
- if (state == FOUND_PARTIAL && node == textNode)
- findState.mContinuationNode = false;
- } while (true);
- if (state == FOUND_NONE)
- break;
- // search for next text node, if any
- Text* nextNode;
- do {
- do {
- do {
- if (node)
- node = node->traverseNextNode();
- if (node == NULL || node->hasTagName(HTMLNames::aTag)
- || node->hasTagName(HTMLNames::inputTag)
- || node->hasTagName(HTMLNames::textareaTag)) {
- if (state == FOUND_PARTIAL &&
- checkType == ADDRESS_CACHEDNODETYPE &&
- findState.mProgress == ZIP_CODE &&
- findState.mNumberCount == 0) {
- baseChars = NULL;
- inlineTextBox = NULL;
- start = 0;
- findState.mProgress = FIND_STREET;
- goto finalNode;
- }
- goto tryNextCheckType;
- }
- } while (node->isTextNode() == false);
- nextNode = static_cast<Text*>(node);
- renderer = (RenderText*) nextNode->renderer();
- } while (renderer == NULL);
- baseInline = renderer->firstTextBox();
- } while (baseInline == NULL);
- string = nextNode->dataImpl();
- baseChars = string->characters();
- inlineTextBox = baseInline;
- start = inlineTextBox->start();
- finalNode:
- findState.mEndResult = 0;
- } while (true);
-tryNextCheckType:
- node = textNode;
- baseInline = saveInline;
- string = textNode->dataImpl();
- baseChars = string->characters();
- }
- if (foundBetter) {
- CachedNodeType temp = *type;
- switch (temp) {
- case ADDRESS_CACHEDNODETYPE: {
- static const char geoString[] = "geo:0,0?q=";
- exported->insert(String(geoString), 0);
- int index = sizeof(geoString) - 1;
- String escapedComma("%2C");
- while ((index = exported->find(',', index)) >= 0)
- exported->replace(index, 1, escapedComma);
- } break;
- case EMAIL_CACHEDNODETYPE: {
- String encoded = WebCore::encodeWithURLEscapeSequences(*exported);
- exported->swap(encoded);
- exported->insert(WTF::String("mailto:"), 0);
- } break;
- case PHONE_CACHEDNODETYPE:
- exported->insert(WTF::String("tel:"), 0);
- break;
- default:
- break;
- }
- return true;
- }
-noTextMatch:
- walk->reset();
- return false;
-}
-
-bool CacheBuilder::IsMailboxChar(UChar ch)
-{
- // According to http://en.wikipedia.org/wiki/Email_address
- // ! # $ % & ' * + - . / 0-9 = ?
- // A-Z ^ _
- // ` a-z { | } ~
- static const unsigned body[] = {0xa3ffecfa, 0xc7fffffe, 0x7fffffff};
- ch -= 0x20;
- if (ch > '~' - 0x20)
- return false;
- return (body[ch >> 5] & 1 << (ch & 0x1f)) != 0;
-}
-
-bool CacheBuilder::setData(CachedFrame* cachedFrame)
-{
- Frame* frame = FrameAnd(this);
- Document* doc = frame->document();
- if (doc == NULL)
- return false;
- RenderObject* renderer = doc->renderer();
- if (renderer == NULL)
- return false;
- RenderLayer* layer = renderer->enclosingLayer();
- if (layer == NULL)
- return false;
- if (!frame->view())
- return false;
- int x, y;
- GetGlobalOffset(frame, &x, &y);
- WebCore::IntRect viewBounds = frame->view()->platformWidget()->getBounds();
- if ((x | y) != 0)
- viewBounds.setLocation(WebCore::IntPoint(x, y));
- cachedFrame->setLocalViewBounds(viewBounds);
- cachedFrame->setContentsSize(layer->scrollWidth(), layer->scrollHeight());
- if (cachedFrame->childCount() == 0)
- return true;
- CachedFrame* lastCachedFrame = cachedFrame->lastChild();
- cachedFrame = cachedFrame->firstChild();
- do {
- CacheBuilder* cacheBuilder = Builder((Frame* )cachedFrame->framePointer());
- cacheBuilder->setData(cachedFrame);
- } while (cachedFrame++ != lastCachedFrame);
- return true;
-}
-
-#if USE(ACCELERATED_COMPOSITING)
-void CacheBuilder::TrackLayer(WTF::Vector<LayerTracker>& layerTracker,
- RenderObject* nodeRenderer, Node* lastChild, int offsetX, int offsetY)
-{
- RenderLayer* layer = nodeRenderer->enclosingLayer();
- RenderLayerBacking* back = layer->backing();
- if (!back)
- return;
- GraphicsLayer* grLayer = back->graphicsLayer();
- if (back->hasContentsLayer())
- grLayer = back->foregroundLayer();
- if (!grLayer)
- return;
- LayerAndroid* aLayer = grLayer->platformLayer();
- if (!aLayer)
- return;
- IntPoint scroll(layer->scrollXOffset(), layer->scrollYOffset());
-#if ENABLE(ANDROID_OVERFLOW_SCROLL)
- // If this is an overflow element, track the content layer.
- if (layer->hasOverflowScroll() && aLayer->getChild(0))
- aLayer = aLayer->getChild(0)->getChild(0);
- if (!aLayer)
- return;
- // Prevent a crash when scrolling a layer that does not have a parent.
- if (layer->stackingContext())
- layer->scrollToOffset(0, 0);
-#endif
- layerTracker.grow(layerTracker.size() + 1);
- LayerTracker& indexTracker = layerTracker.last();
- indexTracker.mLayer = aLayer;
- indexTracker.mRenderLayer = layer;
- indexTracker.mBounds = enclosingIntRect(aLayer->bounds());
- // Use the absolute location of the layer as the bounds location. This
- // provides the original offset of nodes in the layer so that we can
- // translate nodes between their original location and the layer's new
- // location.
- indexTracker.mBounds.setLocation(layer->absoluteBoundingBox().location());
- indexTracker.mBounds.move(offsetX, offsetY);
- indexTracker.mScroll = scroll;
- indexTracker.mLastChild = OneAfter(lastChild);
- DBG_NAV_LOGD("layer=%p [%d] bounds=(%d,%d,w=%d,h=%d)", aLayer,
- aLayer->uniqueId(), indexTracker.mBounds.x(), indexTracker.mBounds.y(),
- indexTracker.mBounds.width(), indexTracker.mBounds.height());
-}
-#endif
-
-bool CacheBuilder::validNode(Frame* startFrame, void* matchFrame,
- void* matchNode)
-{
- if (matchFrame == startFrame) {
- if (matchNode == NULL)
- return true;
- Node* node = startFrame->document();
- while (node != NULL) {
- if (node == matchNode) {
- const IntRect& rect = node->hasTagName(HTMLNames::areaTag) ?
- getAreaRect(static_cast<HTMLAreaElement*>(node)) : node->getRect();
- // Consider nodes with empty rects that are not at the origin
- // to be valid, since news.google.com has valid nodes like this
- if (rect.x() == 0 && rect.y() == 0 && rect.isEmpty())
- return false;
- return true;
- }
- node = node->traverseNextNode();
- }
- DBG_NAV_LOGD("frame=%p valid node=%p invalid\n", matchFrame, matchNode);
- return false;
- }
- Frame* child = startFrame->tree()->firstChild();
- while (child) {
- bool result = validNode(child, matchFrame, matchNode);
- if (result)
- return result;
- child = child->tree()->nextSibling();
- }
-#if DEBUG_NAV_UI
- if (startFrame->tree()->parent() == NULL)
- DBG_NAV_LOGD("frame=%p node=%p false\n", matchFrame, matchNode);
-#endif
- return false;
-}
-
-static int Area(const IntRect& rect)
-{
- return rect.width() * rect.height();
-}
-
-bool CacheBuilder::AddPartRect(IntRect& bounds, int x, int y,
- WTF::Vector<IntRect>* result, IntRect* focusBounds)
-{
- if (bounds.isEmpty())
- return true;
- bounds.move(x, y);
- if (bounds.maxX() <= 0 || bounds.maxY() <= 0)
- return true;
- IntRect* work = result->begin() - 1;
- IntRect* end = result->end();
- while (++work < end) {
- if (work->contains(bounds))
- return true;
- if (bounds.contains(*work)) {
- *work = bounds;
- focusBounds->unite(bounds);
- return true;
- }
- if ((bounds.x() != work->x() || bounds.width() != work->width()) &&
- (bounds.y() != work->y() || bounds.height() != work->height()))
- continue;
- IntRect test = *work;
- test.unite(bounds);
- if (Area(test) > Area(*work) + Area(bounds))
- continue;
- *work = test;
- focusBounds->unite(bounds);
- return true;
- }
- if (result->size() >= MAXIMUM_FOCUS_RING_COUNT)
- return false;
- result->append(bounds);
- if (focusBounds->isEmpty())
- *focusBounds = bounds;
- else
- focusBounds->unite(bounds);
- return true;
-}
-
-bool CacheBuilder::ConstructPartRects(Node* node, const IntRect& bounds,
- IntRect* focusBounds, int x, int y, WTF::Vector<IntRect>* result,
- int* imageCountPtr)
-{
- WTF::Vector<ClipColumnTracker> clipTracker(1);
- ClipColumnTracker* baseTracker = clipTracker.data(); // sentinel
- bzero(baseTracker, sizeof(ClipColumnTracker));
- if (node->hasChildNodes() && node->hasTagName(HTMLNames::buttonTag) == false
- && node->hasTagName(HTMLNames::selectTag) == false) {
- // collect all text rects from first to last child
- Node* test = node->firstChild();
- Node* last = NULL;
- Node* prior = node;
- while ((prior = prior->lastChild()) != NULL)
- last = prior;
- ASSERT(last != NULL);
- bool nodeIsAnchor = node->hasTagName(HTMLNames::aTag);
- do {
- do {
- const ClipColumnTracker* lastClip = &clipTracker.last();
- if (test != lastClip->mLastChild)
- break;
- clipTracker.removeLast();
- } while (true);
- RenderObject* renderer = test->renderer();
- if (renderer == NULL)
- continue;
- EVisibility vis = renderer->style()->visibility();
- if (vis == HIDDEN)
- continue;
- bool hasClip = renderer->hasOverflowClip();
- size_t clipIndex = clipTracker.size();
- IntRect clipBounds = IntRect(0, 0, INT_MAX, INT_MAX);
- if (hasClip || --clipIndex > 0) {
- clipBounds = hasClip ? renderer->absoluteBoundingBoxRect() :
- clipTracker.at(clipIndex).mBounds; // x, y fixup done by ConstructTextRect
- }
- if (test->isTextNode()) {
- RenderText* renderText = (RenderText*) renderer;
- InlineTextBox *textBox = renderText->firstTextBox();
- if (textBox == NULL)
- continue;
- if (ConstructTextRect((Text*) test, textBox, 0, INT_MAX,
- x, y, focusBounds, clipBounds, result) == false) {
- return false;
- }
- continue;
- }
- if (test->hasTagName(HTMLNames::imgTag)) {
- IntRect bounds = test->getRect();
- bounds.intersect(clipBounds);
- if (AddPartRect(bounds, x, y, result, focusBounds) == false)
- return false;
- *imageCountPtr += 1;
- continue;
- }
- if (hasClip == false) {
- if (nodeIsAnchor && test->hasTagName(HTMLNames::divTag)) {
- IntRect bounds = renderer->absoluteBoundingBoxRect(); // x, y fixup done by AddPartRect
- RenderBox* renderBox = static_cast<RenderBox*>(renderer);
- int left = bounds.x() + renderBox->paddingLeft() + renderBox->borderLeft();
- int top = bounds.y() + renderBox->paddingTop() + renderBox->borderTop();
- int right = bounds.maxX() - renderBox->paddingRight() - renderBox->borderRight();
- int bottom = bounds.maxY() - renderBox->paddingBottom() - renderBox->borderBottom();
- if (left >= right || top >= bottom)
- continue;
- bounds = IntRect(left, top, right - left, bottom - top);
- if (AddPartRect(bounds, x, y, result, focusBounds) == false)
- return false;
- }
- continue;
- }
- Node* lastChild = test->lastChild();
- if (lastChild == NULL)
- continue;
- clipTracker.grow(clipTracker.size() + 1);
- ClipColumnTracker& clip = clipTracker.last();
- clip.mBounds = renderer->absoluteBoundingBoxRect(); // x, y fixup done by ConstructTextRect
- clip.mLastChild = OneAfter(lastChild);
- clip.mNode = test;
- } while (test != last && (test = test->traverseNextNode()) != NULL);
- }
- if (result->size() == 0 || focusBounds->width() < MINIMUM_FOCUSABLE_WIDTH
- || focusBounds->height() < MINIMUM_FOCUSABLE_HEIGHT) {
- if (bounds.width() < MINIMUM_FOCUSABLE_WIDTH)
- return false;
- if (bounds.height() < MINIMUM_FOCUSABLE_HEIGHT)
- return false;
- result->append(bounds);
- *focusBounds = bounds;
- }
- return true;
-}
-
-static inline bool isNotSpace(UChar c)
-{
- return c <= 0xA0 ? isUnicodeSpace(c) == false :
- WTF::Unicode::direction(c) != WTF::Unicode::WhiteSpaceNeutral;
-}
-
-bool CacheBuilder::ConstructTextRect(Text* textNode,
- InlineTextBox* textBox, int start, int relEnd, int x, int y,
- IntRect* focusBounds, const IntRect& clipBounds, WTF::Vector<IntRect>* result)
-{
- RenderText* renderText = (RenderText*) textNode->renderer();
- EVisibility vis = renderText->style()->visibility();
- StringImpl* string = textNode->dataImpl();
- const UChar* chars = string->characters();
- FloatPoint pt = renderText->localToAbsolute();
- do {
- int textBoxStart = textBox->start();
- int textBoxEnd = textBoxStart + textBox->len();
- if (textBoxEnd <= start)
- continue;
- if (textBoxEnd > relEnd)
- textBoxEnd = relEnd;
- IntRect bounds = textBox->selectionRect((int) pt.x(), (int) pt.y(),
- start, textBoxEnd);
- bounds.intersect(clipBounds);
- if (bounds.isEmpty())
- continue;
- bool drawable = false;
- for (int index = start; index < textBoxEnd; index++)
- if ((drawable |= isNotSpace(chars[index])) != false)
- break;
- if (drawable && vis != HIDDEN) {
- if (AddPartRect(bounds, x, y, result, focusBounds) == false)
- return false;
- }
- if (textBoxEnd == relEnd)
- break;
- } while ((textBox = textBox->nextTextBox()) != NULL);
- return true;
-}
-
-bool CacheBuilder::ConstructTextRects(Text* node, int start,
- Text* last, int end, int x, int y, IntRect* focusBounds,
- const IntRect& clipBounds, WTF::Vector<IntRect>* result)
-{
- result->clear();
- *focusBounds = IntRect(0, 0, 0, 0);
- do {
- RenderText* renderText = (RenderText*) node->renderer();
- int relEnd = node == last ? end : renderText->textLength();
- InlineTextBox *textBox = renderText->firstTextBox();
- if (textBox != NULL) {
- do {
- if ((int) textBox->end() >= start)
- break;
- } while ((textBox = textBox->nextTextBox()) != NULL);
- if (textBox && ConstructTextRect(node, textBox, start, relEnd,
- x, y, focusBounds, clipBounds, result) == false)
- return false;
- }
- start = 0;
- do {
- if (node == last)
- return true;
- node = (Text*) node->traverseNextNode();
- ASSERT(node != NULL);
- } while (node->isTextNode() == false || node->renderer() == NULL);
- } while (true);
-}
-
-}
diff --git a/Source/WebKit/android/nav/CacheBuilder.h b/Source/WebKit/android/nav/CacheBuilder.h
deleted file mode 100644
index 8f1cc72..0000000
--- a/Source/WebKit/android/nav/CacheBuilder.h
+++ /dev/null
@@ -1,297 +0,0 @@
-/*
- * Copyright 2006, 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 CacheBuilder_h
-#define CacheBuilder_h
-
-#include "CachedDebug.h"
-#include "CachedNodeType.h"
-#include "IntRect.h"
-#include "PlatformString.h"
-#include "TextDirection.h"
-#include <wtf/Forward.h>
-#include <wtf/Vector.h>
-
-#define NAVIGATION_MAX_PHONE_LENGTH 14
-
-using namespace WebCore;
-
-namespace WebCore {
-
-class ColumnInfo;
-class Document;
-class Frame;
-class HTMLAreaElement;
-class InlineTextBox;
-class LayerAndroid;
-class Node;
-class PlatformGraphicsContext;
-class RenderBlock;
-class RenderFlow;
-class RenderLayer;
-class RenderObject;
-class Text;
-
-}
-
-namespace android {
-
-class CachedFrame;
-class CachedNode;
-class CachedRoot;
-
-class CacheBuilder {
-public:
- enum Direction {
- UNINITIALIZED = -1,
- LEFT,
- RIGHT,
- UP,
- DOWN,
- DIRECTION_COUNT,
- UP_DOWN = UP & DOWN, // mask and result
- RIGHT_DOWN = RIGHT & DOWN, // mask and result
- };
- enum FoundState {
- FOUND_NONE,
- FOUND_PARTIAL,
- FOUND_COMPLETE
- };
- CacheBuilder();
- void allowAllTextDetection() { mAllowableTypes = ALL_CACHEDNODE_BITS; }
- void buildCache(CachedRoot* root);
- static bool ConstructPartRects(Node* node, const IntRect& bounds,
- IntRect* focusBounds, int x, int y, WTF::Vector<IntRect>* result,
- int* imageCountPtr);
- Node* currentFocus() const;
- void disallowAddressDetection() { mAllowableTypes = (CachedNodeBits) (
- mAllowableTypes & ~ADDRESS_CACHEDNODE_BIT); }
- void disallowEmailDetection() { mAllowableTypes = (CachedNodeBits) (
- mAllowableTypes & ~EMAIL_CACHEDNODE_BIT); }
- void disallowPhoneDetection() { mAllowableTypes = (CachedNodeBits) (
- mAllowableTypes & ~PHONE_CACHEDNODE_BIT); }
- static FoundState FindAddress(const UChar* , unsigned length, int* start,
- int* end, bool caseInsensitive);
- static IntRect getAreaRect(const HTMLAreaElement* area);
- static void GetGlobalOffset(Frame* , int* x, int * y);
- static void GetGlobalOffset(Node* , int* x, int * y);
- bool pictureSetDisabled() { return mPictureSetDisabled; }
- static bool validNode(Frame* startFrame, void* framePtr, void* nodePtr);
-private:
- enum AddressProgress {
- NO_ADDRESS,
- SKIP_TO_SPACE,
- HOUSE_NUMBER,
- NUMBER_TRAILING_SPACE,
- ADDRESS_LINE,
- STATE_NAME,
- SECOND_HALF,
- ZIP_CODE,
- PLUS_4,
- FIND_STREET
- };
- struct NodeWalk {
- NodeWalk() { reset(); }
- int mStart;
- int mEnd;
- Node* mFinalNode;
- InlineTextBox* mLastInline;
- bool mMore;
- void reset() { mMore = false; }
- };
- struct BoundsPart {
- IntRect mRect;
- int mStart;
- int mEnd;
- };
- struct Bounds {
- typedef bool (*FindText)(BoundsPart* result, InlineTextBox* , const String& match);
- IntRect mNodeBounds;
- BoundsPart mPart;
- WTF::Vector<BoundsPart> mParts;
- char mStore[NAVIGATION_MAX_PHONE_LENGTH + 1];
- int mPartIndex;
- Node* mNode;
- Node* mFinalNode;
- void reset() { mNode = NULL; }
- };
- struct FindState {
- int mStartResult;
- int mEndResult;
- const UChar* mCurrentStart;
- const UChar* mEnd;
- AddressProgress mProgress;
- int mNumberCount;
- int mLetterCount;
- unsigned mWordCount;
- int mLineCount;
- const UChar* mFirstLower;
- const UChar* mZipStart;
- const UChar* mBases[16]; // FIXME: random guess, maybe too small, maybe too big
- const UChar* mWords[16];
- const UChar* mEnds[16];
- const UChar* mStarts[16]; // text is not necessarily contiguous
- const char* mStates;
- int mEndWord;
- int mStateWord;
- int mZipHint;
- int mSectionLength;
- unsigned mNumberWords; // must contain as many bits as mWords contains elements
- char* mPattern;
- UChar mStore[NAVIGATION_MAX_PHONE_LENGTH + 1];
- UChar* mStorePtr;
- UChar mBackOne;
- UChar mBackTwo;
- UChar mCurrent;
- bool mUnparsed;
- bool mZipDelimiter;
- bool mOpenParen;
- bool mInitialized;
- bool mContinuationNode;
- bool mCaseInsensitive;
- void shiftWords(int shift) {
- memmove(mBases, &mBases[shift], (sizeof(mBases) /
- sizeof(mBases[0]) - shift) * sizeof(mBases[0]));
- memmove(mWords, &mWords[shift], (sizeof(mWords) /
- sizeof(mWords[0]) - shift) * sizeof(mWords[0]));
- memmove(mEnds, &mEnds[shift], (sizeof(mEnds) /
- sizeof(mEnds[0]) - shift) * sizeof(mEnds[0]));
- memmove(mStarts, &mStarts[shift], (sizeof(mStarts) /
- sizeof(mStarts[0]) - shift) * sizeof(mStarts[0]));
- }
- void newWord(const UChar* baseChars, const UChar* chars) {
- mBases[mWordCount] = baseChars;
- mWords[mWordCount] = chars;
- mEnds[mWordCount] = mEnd;
- mStarts[mWordCount] = mCurrentStart;
- }
- };
- struct Tracker {
- Node* mLastChild;
- };
- struct ClipColumnTracker : Tracker {
- Node* mNode;
- IntRect mBounds;
- ColumnInfo* mColumnInfo;
- int mColumnGap;
- TextDirection mDirection;
- bool mHasClip;
- };
- struct LayerTracker : Tracker {
- LayerAndroid* mLayer;
- RenderLayer* mRenderLayer;
- IntRect mBounds;
- IntPoint mScroll;
- ~LayerTracker();
- };
- struct TabIndexTracker : Tracker {
- int mTabIndex;
- };
- struct FocusTracker : TabIndexTracker {
- int mCachedNodeIndex;
- bool mSomeParentTakesFocus;
- };
- void adjustForColumns(const ClipColumnTracker& track,
- CachedNode* node, IntRect* bounds, RenderBlock*);
- static bool AddPartRect(IntRect& bounds, int x, int y,
- WTF::Vector<IntRect>* result, IntRect* focusBounds);
- static bool AnyIsClick(Node* node);
- static bool AnyChildIsClick(Node* node);
- static bool NodeHasEventListeners(Node* node, AtomicString* eventTypes, int length);
- void BuildFrame(Frame* root, Frame* frame,
- CachedRoot* cachedRoot, CachedFrame* cachedFrame);
- bool CleanUpContainedNodes(CachedRoot* cachedRoot, CachedFrame* cachedFrame,
- const FocusTracker* last, int lastChildIndex);
- static bool ConstructTextRect(Text* textNode,
- InlineTextBox* textBox, int start, int relEnd, int x, int y,
- IntRect* focusBounds, const IntRect& clip, WTF::Vector<IntRect>* result);
- static bool ConstructTextRects(Text* node, int start,
- Text* last, int end, int x, int y, IntRect* focusBounds,
- const IntRect& clip, WTF::Vector<IntRect>* result);
- static FoundState FindPartialAddress(const UChar* , const UChar* , unsigned length, FindState* );
- static FoundState FindPartialEMail(const UChar* , unsigned length, FindState* );
- static FoundState FindPartialNumber(const UChar* , unsigned length, FindState* );
- static FoundState FindPhoneNumber(const UChar* chars, unsigned length, int* start, int* end);
- static void FindReset(FindState* );
- static void FindResetNumber(FindState* );
- static Frame* FrameAnd(CacheBuilder* focusNav);
- static Frame* FrameAnd(const CacheBuilder* focusNav);
- static CacheBuilder* Builder(Frame* );
- static Frame* HasFrame(Node* );
- static bool HasOverOrOut(Node* );
- static bool HasTriggerEvent(Node* );
- static bool IsDomainChar(UChar ch);
- bool isFocusableText(NodeWalk* , bool oldMore, Node* , CachedNodeType* type,
- String* exported) const; //returns true if it is focusable
- static bool IsMailboxChar(UChar ch);
- static bool IsRealNode(Frame* , Node* );
- int overlap(int left, int right); // returns distance scale factor as 16.16 scalar
- bool setData(CachedFrame* );
-#if USE(ACCELERATED_COMPOSITING)
- void TrackLayer(WTF::Vector<LayerTracker>& layerTracker,
- RenderObject* nodeRenderer, Node* lastChild, int offsetX, int offsetY);
-#endif
- Node* tryFocus(Direction direction);
- Node* trySegment(Direction direction, int mainStart, int mainEnd);
- CachedNodeBits mAllowableTypes;
- bool mPictureSetDisabled;
-#if DUMP_NAV_CACHE
-public:
- class Debug {
-public:
- void frameName(char*& namePtr, const char* max) const;
- void init(char* buffer, size_t size);
- static int ParentIndex(Node* node, int count, Node* parent);
- void print() { frames(); }
- void print(const char* name);
- void wideString(const String& str);
-private:
- void attr(const AtomicString& name, const AtomicString& value);
- void comma(const char* str);
- void flush();
- Frame* frameAnd() const;
- void frames();
- void groups();
- bool isFocusable(Node* node);
- void localName(Node* node);
- void newLine(int indent = 0);
- void print(const char* name, unsigned len);
- void setIndent(int );
- void uChar(const UChar* name, unsigned len, bool hex);
- void validateFrame();
- void validateStringData();
- void wideString(const UChar* chars, int length, bool hex);
- char* mBuffer;
- size_t mBufferSize;
- int mIndex;
- const char* mPrefix;
- int mMinPrefix;
- } mDebug;
-#endif
-};
-
-}
-
-#endif
diff --git a/Source/WebKit/android/nav/CachedColor.cpp b/Source/WebKit/android/nav/CachedColor.cpp
deleted file mode 100644
index c610022..0000000
--- a/Source/WebKit/android/nav/CachedColor.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2010, 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.
- */
-
-#include "CachedPrefix.h"
-#include "CachedColor.h"
-
-namespace android {
-
-#if DUMP_NAV_CACHE
-
-#define DEBUG_PRINT_COLOR(field) \
- DUMP_NAV_LOGD("// SkColor " #field "=0x%08x;\n", b->field)
-
-CachedColor* CachedColor::Debug::base() const {
- CachedColor* nav = (CachedColor*) ((char*) this - OFFSETOF(CachedColor, mDebug));
- return nav;
-}
-
-void CachedColor::Debug::print() const
-{
- CachedColor* b = base();
- DEBUG_PRINT_COLOR(mFillColor);
- DUMP_NAV_LOGD("// int mInnerWidth=%d;\n", b->mInnerWidth);
- DUMP_NAV_LOGD("// int mOuterWidth=%d;\n", b->mOuterWidth);
- DUMP_NAV_LOGD("// int mOutset=%d;\n", b->mOutset);
- DEBUG_PRINT_COLOR(mPressedInnerColor);
- DEBUG_PRINT_COLOR(mPressedOuterColor);
- DUMP_NAV_LOGD("// int mRadius=%d;\n", b->mRadius);
- DEBUG_PRINT_COLOR(mSelectedInnerColor);
- DEBUG_PRINT_COLOR(mSelectedOuterColor);
-}
-
-#endif
-
-}
-
diff --git a/Source/WebKit/android/nav/CachedColor.h b/Source/WebKit/android/nav/CachedColor.h
deleted file mode 100644
index 2ba9b18..0000000
--- a/Source/WebKit/android/nav/CachedColor.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright 2010, 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 CachedColor_h
-#define CachedColor_h
-
-#include "CachedDebug.h"
-#include "Color.h"
-#include "Length.h"
-#include "SkColor.h"
-
-using namespace WebCore;
-
-namespace android {
-
-class CachedColor {
-public:
- CachedColor() {
- // Initiaized to 0 in its array, so nothing to do in the
- // constructor
- }
- bool operator==(const CachedColor& o) const {
- return memcmp(&o, this, sizeof(this)) == 0; }
- SkColor fillColor() const { return mFillColor; }
- void init();
- int innerWidth() const { return mInnerWidth; }
- int outerWidth() const { return mOuterWidth; }
- int outset() const { return mOutset; }
- SkColor pressedInnerColor() const { return mPressedInnerColor; }
- SkColor pressedOuterColor() const { return mPressedOuterColor; }
- int radius() const { return mRadius; }
- SkColor selectedInnerColor() const { return mSelectedInnerColor; }
- SkColor selectedOuterColor() const { return mSelectedOuterColor; }
- void setFillColor(const Color& c) { mFillColor = c.rgb(); }
- void setInnerWidth(Length l) { mInnerWidth = l.value(); }
- void setOuterWidth(Length l) { mOuterWidth = l.value(); }
- void setOutset(Length l) { mOutset = l.value(); }
- void setPressedInnerColor(const Color& c) { mPressedInnerColor = c.rgb(); }
- void setPressedOuterColor(const Color& c) { mPressedOuterColor = c.rgb(); }
- void setRadius(Length l) { mRadius = l.value(); }
- void setSelectedInnerColor(const Color& c) { mSelectedInnerColor = c.rgb(); }
- void setSelectedOuterColor(const Color& c) { mSelectedOuterColor = c.rgb(); }
-private:
- SkColor mFillColor;
- int mInnerWidth;
- int mOuterWidth;
- int mOutset;
- SkColor mPressedInnerColor;
- SkColor mPressedOuterColor;
- int mRadius;
- SkColor mSelectedInnerColor;
- SkColor mSelectedOuterColor;
-#if DUMP_NAV_CACHE
-public:
- class Debug {
-public:
- CachedColor* base() const;
- void print() const;
- } mDebug;
-#endif
-};
-
-}
-
-#endif
diff --git a/Source/WebKit/android/nav/CachedDebug.h b/Source/WebKit/android/nav/CachedDebug.h
deleted file mode 100644
index f77c07a..0000000
--- a/Source/WebKit/android/nav/CachedDebug.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright 2007, 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 CachedDebug_h
-#define CachedDebug_h
-
-#define DUMP_NAV_CACHE 0
-#define DEBUG_NAV_UI 0
-#define DEBUG_NAV_UI_VERBOSE 0
-
-#if DEBUG_NAV_UI
-#define DBG_NAV_LOG(message) LOGD("%s %s", __FUNCTION__, message)
-#define DBG_NAV_LOGD(format, ...) LOGD("%s " format, __FUNCTION__, __VA_ARGS__)
-#define DEBUG_NAV_UI_LOGD(...) LOGD(__VA_ARGS__)
-#else
-#define DBG_NAV_LOG(message) ((void)0)
-#define DBG_NAV_LOGD(format, ...) ((void)0)
-#define DEBUG_NAV_UI_LOGD(...) ((void)0)
-#endif
-
-#if DEBUG_NAV_UI_VERBOSE
-#define DBG_NAV_LOGV(format, ...) LOGD("%s " format, __FUNCTION__, __VA_ARGS__)
-#else
-#define DBG_NAV_LOGV(format, ...) ((void)0)
-#endif
-
-#if DUMP_NAV_CACHE != 0 && !defined DUMP_NAV_CACHE_USING_PRINTF && defined NDEBUG
-#define DUMP_NAV_CACHE_USING_PRINTF
-#endif
-
-#if DUMP_NAV_CACHE
-#ifdef DUMP_NAV_CACHE_USING_PRINTF
-#include <stdio.h>
-extern FILE* gNavCacheLogFile;
-#define NAV_CACHE_LOG_FILE "/data/data/com.android.browser/navlog"
-#define DUMP_NAV_LOGD(...) do { if (gNavCacheLogFile) \
- fprintf(gNavCacheLogFile, __VA_ARGS__); else LOGD(__VA_ARGS__); } while (false)
-#define DUMP_NAV_LOGX(format, ...) do { if (gNavCacheLogFile) \
- fprintf(gNavCacheLogFile, format, __VA_ARGS__); \
- else LOGD("%s " format, __FUNCTION__, __VA_ARGS__); } while (false)
-#else
-#define DUMP_NAV_LOGD(...) LOGD(__VA_ARGS__)
-#define DUMP_NAV_LOGX(format, ...) LOGD("%s " format, __FUNCTION__, __VA_ARGS__)
-#endif
-#else
-#define DUMP_NAV_LOGD(...) ((void)0)
-#define DUMP_NAV_LOGX(...) ((void)0)
-#endif
-
-#endif
diff --git a/Source/WebKit/android/nav/CachedFrame.cpp b/Source/WebKit/android/nav/CachedFrame.cpp
deleted file mode 100644
index c51944e..0000000
--- a/Source/WebKit/android/nav/CachedFrame.cpp
+++ /dev/null
@@ -1,1511 +0,0 @@
-/*
- * Copyright 2007, 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.
- */
-
-#include "CachedPrefix.h"
-#include "CachedHistory.h"
-#include "CachedNode.h"
-#include "CachedRoot.h"
-#include "LayerAndroid.h"
-
-#include "CachedFrame.h"
-
-#define OFFSETOF(type, field) ((char*)&(((type*)1)->field) - (char*)1) // avoids gnu warning
-
-#define MIN_OVERLAP 3 // if rects overlap by 2 pixels or fewer, treat them as non-intersecting
-
-namespace android {
-
-WebCore::IntRect CachedFrame::adjustBounds(const CachedNode* node,
- const WebCore::IntRect& rect) const
-{
- DBG_NAV_LOGV("node=%p [%d] rect=(%d,%d,w=%d,h=%d) view=(%d,%d,w=%d,h=%d)"
- " local=(%d,%d,w=%d,h=%d) root=(%d,%d,w=%d,h=%d)",
- node, node->index(), rect.x(), rect.y(), rect.width(), rect.height(),
- mViewBounds.x(), mViewBounds.y(),
- mViewBounds.width(), mViewBounds.height(),
- mLocalViewBounds.x(), mLocalViewBounds.y(),
- mLocalViewBounds.width(), mLocalViewBounds.height(),
- mRoot->mViewBounds.x(), mRoot->mViewBounds.y(),
- mRoot->mViewBounds.width(), mRoot->mViewBounds.height());
-#if USE(ACCELERATED_COMPOSITING)
- if (!mRoot)
- return rect;
-
- const CachedLayer* cachedLayer = layer(node);
- if (!cachedLayer)
- return rect;
-
- const WebCore::LayerAndroid* rootLayer = mRoot->rootLayer();
- const LayerAndroid* aLayer = cachedLayer->layer(rootLayer);
- if (aLayer)
- return cachedLayer->adjustBounds(rootLayer, rect);
-#endif
- return rect;
-}
-
-bool CachedFrame::CheckBetween(Direction direction, const WebCore::IntRect& bestRect,
- const WebCore::IntRect& prior, WebCore::IntRect* result)
-{
- int left, top, width, height;
- if (direction & UP_DOWN) {
- top = direction == UP ? bestRect.maxY() : prior.maxY();
- int bottom = direction == UP ? prior.y() : bestRect.y();
- height = bottom - top;
- if (height < 0)
- return false;
- left = prior.x();
- int testLeft = bestRect.x();
- if (left > testLeft)
- left = testLeft;
- int right = prior.maxX();
- int testRight = bestRect.maxX();
- if (right < testRight)
- right = testRight;
- width = right - left;
- } else {
- left = direction == LEFT ? bestRect.maxX() : prior.maxX();
- int right = direction == LEFT ? prior.x() : bestRect.x();
- width = right - left;
- if (width < 0)
- return false;
- top = prior.y();
- int testTop = bestRect.y();
- if (top > testTop)
- top = testTop;
- int bottom = prior.maxY();
- int testBottom = bestRect.maxY();
- if (bottom < testBottom)
- bottom = testBottom;
- height = bottom - top;
- }
- *result = WebCore::IntRect(left, top, width, height);
- return true;
-}
-
-bool CachedFrame::checkBetween(BestData* best, Direction direction)
-{
- const WebCore::IntRect& bestRect = best->bounds();
- BestData test;
- test.mDistance = INT_MAX;
- test.mNode = NULL;
- int index = direction;
- int limit = index + DIRECTION_COUNT;
- do {
- WebCore::IntRect edges;
- Direction check = (Direction) (index & DIRECTION_MASK);
- if (CheckBetween(check, bestRect,
- history()->priorBounds(), &edges) == false)
- continue;
- WebCore::IntRect clip = mRoot->scrolledBounds();
- clip.intersect(edges);
- if (clip.isEmpty())
- continue;
- findClosest(&test, direction, check, &clip);
- if (test.mNode == NULL)
- continue;
- if (direction == check)
- break;
- } while (++index < limit);
- if (test.mNode == NULL)
- return false;
- *best = test;
- return true;
-}
-
-bool CachedFrame::checkRings(const CachedNode* node,
- const WebCore::IntRect& testBounds) const
-{
- return mRoot->checkRings(picture(node), node, testBounds);
-}
-
-bool CachedFrame::checkVisited(const CachedNode* node, Direction direction) const
-{
- return history()->checkVisited(node, direction);
-}
-
-void CachedFrame::clearCursor()
-{
- DBG_NAV_LOGD("mCursorIndex=%d", mCursorIndex);
- if (mCursorIndex < CURSOR_SET)
- return;
- CachedNode& cursor = mCachedNodes[mCursorIndex];
- cursor.clearCursor(this);
- mCursorIndex = CURSOR_CLEARED; // initialized and explicitly cleared
-}
-
-// returns 0 if test is preferable to best, 1 if not preferable, or -1 if unknown
-int CachedFrame::compare(BestData& testData, const BestData& bestData) const
-{
- if (testData.mNode->tabIndex() != bestData.mNode->tabIndex()) {
- if (testData.mNode->tabIndex() < bestData.mNode->tabIndex()
- || (mRoot->mCursor && mRoot->mCursor->tabIndex() < bestData.mNode->tabIndex())) {
- testData.mNode->setCondition(CachedNode::HIGHER_TAB_INDEX);
- return REJECT_TEST;
- }
- return TEST_IS_BEST;
- }
- // if the test minor axis line intersects the line segment between cursor
- // center and best center, choose it
- // give more weight to exact major axis alignment (rows, columns)
- if (testData.mInNav != bestData.mInNav) {
- if (bestData.mInNav) {
- testData.mNode->setCondition(CachedNode::IN_CURSOR);
- return REJECT_TEST;
- }
- return TEST_IS_BEST;
- }
- if (testData.mInNav) {
- if (bestData.mMajorDelta < testData.mMajorDelta) {
- testData.mNode->setCondition(CachedNode::CLOSER_IN_CURSOR);
- return REJECT_TEST;
- }
- if (testData.mMajorDelta < bestData.mMajorDelta)
- return TEST_IS_BEST;
- }
- if (testData.mMajorDelta < 0 && bestData.mMajorDelta >= 0) {
- testData.mNode->setCondition(CachedNode::FURTHER);
- return REJECT_TEST;
- }
- if ((testData.mMajorDelta ^ bestData.mMajorDelta) < 0) // one above, one below (or one left, one right)
- return TEST_IS_BEST;
- bool bestInWorking = bestData.inOrSubsumesWorking();
- bool testInWorking = testData.inOrSubsumesWorking();
- if (bestInWorking && testData.mWorkingOutside && testData.mNavOutside) {
- testData.mNode->setCondition(CachedNode::IN_WORKING);
- return REJECT_TEST;
- }
- if (testInWorking && bestData.mWorkingOutside && bestData.mNavOutside)
- return TEST_IS_BEST;
- bool bestInNav = directionChange() && bestData.inOrSubsumesNav();
- bool testInNav = directionChange() && testData.inOrSubsumesNav();
- if (bestInWorking == false && testInWorking == false) {
- if (bestInNav && testData.mNavOutside) {
- testData.mNode->setCondition(CachedNode::IN_UMBRA);
- return REJECT_TEST;
- }
- if (testInNav && bestData.mNavOutside)
- return TEST_IS_BEST;
- }
-#if 01 // hopefully butt test will remove need for this
- if (testData.mCursorChild != bestData.mCursorChild) {
- if (bestData.mCursorChild) {
- testData.mNode->setCondition(CachedNode::IN_CURSOR_CHILDREN);
- return REJECT_TEST;
- }
- return TEST_IS_BEST;
- }
-#endif
- bool bestTestIn = (bestInWorking || bestInNav) && (testInWorking || testInNav);
- bool testOverlap = bestTestIn || (testData.mWorkingOverlap != 0 && bestData.mWorkingOverlap == 0);
- bool bestOverlap = bestTestIn || (testData.mWorkingOverlap == 0 && bestData.mWorkingOverlap != 0);
-#if 01 // this isn't working?
- if (testOverlap == bestOverlap) {
- if (bestData.mMajorButt < 10 && testData.mMajorButt >= 40) {
- testData.mNode->setCondition(CachedNode::BUTTED_UP);
- return REJECT_TEST;
- }
- if (testData.mMajorButt < 10 && bestData.mMajorButt >= 40)
- return TEST_IS_BEST;
- }
-#endif
- if (bestOverlap && bestData.mMajorDelta < testData.mMajorDelta) { // choose closest major axis center
- testData.mNode->setCondition(CachedNode::CLOSER);
- return REJECT_TEST;
- }
- if (testOverlap && testData.mMajorDelta < bestData.mMajorDelta)
- return TEST_IS_BEST;
- if (bestOverlap && bestData.mMajorDelta2 < testData.mMajorDelta2) {
- testData.mNode->setCondition(CachedNode::CLOSER_TOP);
- return REJECT_TEST;
- }
- if (testOverlap && testData.mMajorDelta2 < bestData.mMajorDelta2)
- return TEST_IS_BEST;
-#if 01
- if (bestOverlap && ((bestData.mSideDistance <= 0 && testData.mSideDistance > 0) ||
- abs(bestData.mSideDistance) < abs(testData.mSideDistance))) {
- testData.mNode->setCondition(CachedNode::LEFTMOST);
- return REJECT_TEST;
- }
- if (testOverlap && ((testData.mSideDistance <= 0 && bestData.mSideDistance > 0) ||
- abs(testData.mSideDistance) < abs(bestData.mSideDistance)))
- return TEST_IS_BEST;
-// fix me : the following ASSERT fires -- not sure if this case should be handled or not
-// ASSERT(bestOverlap == false && testOverlap == false);
-#endif
- SkFixed testMultiplier = testData.mWorkingOverlap > testData.mNavOverlap ?
- testData.mWorkingOverlap : testData.mNavOverlap;
- SkFixed bestMultiplier = bestData.mWorkingOverlap > bestData.mNavOverlap ?
- bestData.mWorkingOverlap : bestData.mNavOverlap;
- int testDistance = testData.mDistance;
- int bestDistance = bestData.mDistance;
-// start here;
- // this fails if they're off by 1
- // try once again to implement sliding scale so that off by 1 is nearly like zero,
- // and off by a lot causes sideDistance to have little or no effect
- // try elliptical distance -- lengthen side contribution
- // these ASSERTs should not fire, but do fire on mail.google.com
- // can't debug yet, won't reproduce
- ASSERT(testDistance >= 0);
- ASSERT(bestDistance >= 0);
- testDistance += testDistance; // multiply by 2
- testDistance *= testDistance;
- bestDistance += bestDistance; // multiply by 2
- bestDistance *= bestDistance;
- int side = testData.mSideDistance;
- int negative = side < 0 && bestData.mSideDistance > 0;
- side *= side;
- if (negative)
- side = -side;
- testDistance += side;
- side = bestData.mSideDistance;
- negative = side < 0 && testData.mSideDistance > 0;
- side *= side;
- if (negative)
- side = -side;
- bestDistance += side;
- if (testMultiplier > (SK_Fixed1 >> 1) || bestMultiplier > (SK_Fixed1 >> 1)) { // considerable working overlap?
- testDistance = SkFixedMul(testDistance, bestMultiplier);
- bestDistance = SkFixedMul(bestDistance, testMultiplier);
- }
- if (bestDistance < testDistance) {
- testData.mNode->setCondition(CachedNode::CLOSER_OVERLAP);
- return REJECT_TEST;
- }
- if (testDistance < bestDistance)
- return TEST_IS_BEST;
-#if 0
- int distance = testData.mDistance + testData.mSideDistance;
- int best = bestData.mDistance + bestData.mSideDistance;
- if (distance > best) {
- testData.mNode->setCondition(CachedNode::CLOSER_RAW_DISTANCE);
- return REJECT_TEST;
- }
- else if (distance < best)
- return TEST_IS_BEST;
- best = bestData.mSideDistance;
- if (testData.mSideDistance > best) {
- testData.mNode->setCondition(CachedNode::SIDE_DISTANCE);
- return REJECT_TEST;
- }
- if (testData.mSideDistance < best)
- return TEST_IS_BEST;
-#endif
- if (testData.mPreferred < bestData.mPreferred) {
- testData.mNode->setCondition(CachedNode::PREFERRED);
- return REJECT_TEST;
- }
- if (testData.mPreferred > bestData.mPreferred)
- return TEST_IS_BEST;
- return UNDECIDED;
-}
-
-const CachedNode* CachedFrame::currentCursor(const CachedFrame** framePtr) const
-{
- if (framePtr)
- *framePtr = this;
- if (mCursorIndex < CURSOR_SET)
- return NULL;
- const CachedNode* result = &mCachedNodes[mCursorIndex];
- const CachedFrame* frame = hasFrame(result);
- if (frame != NULL)
- return frame->currentCursor(framePtr);
- (const_cast<CachedNode*>(result))->fixUpCursorRects(this);
- return result;
-}
-
-const CachedNode* CachedFrame::currentFocus(const CachedFrame** framePtr) const
-{
- if (framePtr)
- *framePtr = this;
- if (mFocusIndex < 0)
- return NULL;
- const CachedNode* result = &mCachedNodes[mFocusIndex];
- const CachedFrame* frame = hasFrame(result);
- if (frame != NULL)
- return frame->currentFocus(framePtr);
- return result;
-}
-
-bool CachedFrame::directionChange() const
-{
- return history()->directionChange();
-}
-
-#ifdef BROWSER_DEBUG
-CachedNode* CachedFrame::find(WebCore::Node* node) // !!! probably debugging only
-{
- for (CachedNode* test = mCachedNodes.begin(); test != mCachedNodes.end(); test++)
- if (node == test->webCoreNode())
- return test;
- for (CachedFrame* frame = mCachedFrames.begin(); frame != mCachedFrames.end();
- frame++) {
- CachedNode* result = frame->find(node);
- if (result != NULL)
- return result;
- }
- return NULL;
-}
-#endif
-
-const CachedNode* CachedFrame::findBestAt(const WebCore::IntRect& rect,
- int* best, bool* inside, const CachedNode** directHit,
- const CachedFrame** directHitFramePtr,
- const CachedFrame** framePtr, int* x, int* y,
- bool checkForHiddenStart) const
-{
- const CachedNode* result = NULL;
- int rectWidth = rect.width();
- WebCore::IntPoint center = WebCore::IntPoint(rect.x() + (rectWidth >> 1),
- rect.y() + (rect.height() >> 1));
- mRoot->setupScrolledBounds();
- for (const CachedNode* test = mCachedNodes.begin(); test != mCachedNodes.end(); test++) {
- if (test->disabled())
- continue;
- size_t parts = test->navableRects();
- BestData testData;
- testData.mNode = test;
- testData.mFrame = this;
- WebCore::IntRect bounds = test->bounds(this);
- testData.setMouseBounds(bounds);
- testData.setNodeBounds(bounds);
- bool checkForHidden = checkForHiddenStart;
- for (size_t part = 0; part < parts; part++) {
- WebCore::IntRect testRect = test->ring(this, part);
- if (testRect.intersects(rect)) {
-#if DEBUG_NAV_UI
- if (test->isInLayer()) {
- DBG_NAV_LOGD("[%d] intersects=%s testRect=(%d,%d,w=%d,h=%d)"
- " rect=(%d,%d,w=%d,h=%d)", test->index(),
- testRect.intersects(rect) ? "true" : "false",
- testRect.x(), testRect.y(),
- testRect.width(), testRect.height(),
- rect.x(), rect.y(), rect.width(), rect.height());
- }
-#endif
- if (checkForHidden && mRoot->maskIfHidden(&testData) == true) {
- DBG_NAV_LOGD("hidden [%d]", test->index());
- break;
- }
- checkForHidden = false;
- testRect.intersect(testData.mouseBounds());
- if (testRect.contains(center)) {
- // We have a direct hit.
- if (*directHit == NULL) {
- DBG_NAV_LOGD("direct hit 1 [%d]", test->index());
- *directHit = test;
- *directHitFramePtr = this;
- IntRect r(center, IntSize(0, 0));
- *x = r.x();
- *y = r.y();
- } else {
- DBG_NAV_LOGD("direct hit 2 [%d]", test->index());
- // We have hit another one before
- const CachedNode* d = *directHit;
- if (d->bounds(this).contains(testRect)) {
- // This rectangle is inside the other one, so it is
- // the best one.
- *directHit = test;
- *directHitFramePtr = this;
- }
- }
- }
- if (NULL != *directHit) {
- // If we have a direct hit already, there is no need to
- // calculate the distances, or check the other parts
- break;
- }
- DBG_NAV_LOGD("indirect hit [%d]", test->index());
- WebCore::IntRect both = rect;
- int smaller = testRect.width() < testRect.height() ?
- testRect.width() : testRect.height();
- smaller -= rectWidth;
- int inset = smaller < rectWidth ? smaller : rectWidth;
- inset >>= 1; // inflate doubles the width decrease
- if (inset > 1)
- both.inflate(1 - inset);
- both.intersect(testRect);
- if (both.isEmpty())
- continue;
- bool testInside = testRect.contains(center);
- if (*inside && !testInside)
- continue;
- WebCore::IntPoint testCenter = WebCore::IntPoint(testRect.x() +
- (testRect.width() >> 1), testRect.y() + (testRect.height() >> 1));
- int dx = testCenter.x() - center.x();
- int dy = testCenter.y() - center.y();
- int distance = dx * dx + dy * dy;
- if ((!*inside && testInside) || *best >= distance) {
- *best = distance;
- *inside = testInside;
- result = test;
- *framePtr = this;
- *x = both.x() + (both.width() >> 1);
- *y = both.y() + (both.height() >> 1);
- }
- }
- }
- }
- for (const CachedFrame* frame = mCachedFrames.begin();
- frame != mCachedFrames.end(); frame++) {
- const CachedNode* frameResult = frame->findBestAt(rect, best, inside,
- directHit, directHitFramePtr, framePtr, x, y, checkForHiddenStart);
- if (NULL != frameResult)
- result = frameResult;
- }
- if (NULL != *directHit) {
- result = *directHit;
- *framePtr = *directHitFramePtr;
- }
- return result;
-}
-
-const CachedFrame* CachedFrame::findBestFrameAt(int x, int y) const
-{
- if (mLocalViewBounds.contains(x, y) == false)
- return NULL;
- const CachedFrame* result = this;
- for (const CachedFrame* frame = mCachedFrames.begin();
- frame != mCachedFrames.end(); frame++) {
- const CachedFrame* frameResult = frame->findBestFrameAt(x, y);
- if (NULL != frameResult)
- result = frameResult;
- }
- return result;
-}
-
-const CachedNode* CachedFrame::findBestHitAt(const WebCore::IntRect& rect,
- const CachedFrame** framePtr, int* x, int* y) const
-{
- mRoot->setupScrolledBounds();
- for (const CachedFrame* frame = mCachedFrames.end() - 1;
- frame != mCachedFrames.begin() - 1; frame--) {
- const CachedNode* frameResult = frame->findBestHitAt(rect,
- framePtr, x, y);
- if (NULL != frameResult)
- return frameResult;
- }
- for (const CachedNode* test = mCachedNodes.end() - 1;
- test != mCachedNodes.begin() - 1; test--) {
- if (test->disabled())
- continue;
- WebCore::IntRect testRect = test->hitBounds(this);
- if (testRect.intersects(rect) == false)
- continue;
- BestData testData;
- testData.mNode = test;
- testData.mFrame = this;
- testData.setMouseBounds(testRect);
- testData.setNodeBounds(testRect);
- if (mRoot->maskIfHidden(&testData) == true)
- continue;
- DBG_NAV_LOGD("candidate %d rect=(%d,%d,r=%d,b=%d)"
- " testRect=(%d,%d,r=%d,b=%d)",
- test->index(), rect.x(), rect.y(), rect.maxX(), rect.maxY(),
- testRect.x(), testRect.y(), testRect.maxX(), testRect.maxY());
- for (int i = 0; i < test->navableRects(); i++) {
- WebCore::IntRect cursorRect = test->ring(this, i);
- DBG_NAV_LOGD("candidate %d cursorRect=(%d,%d,r=%d,b=%d)",
- i, cursorRect.x(), cursorRect.y(), cursorRect.maxX(),
- cursorRect.maxY());
- if (cursorRect.intersects(rect)) {
- WebCore::IntRect intersection(cursorRect);
- intersection.intersect(rect);
- *x = intersection.x() + (intersection.width() >> 1);
- *y = intersection.y() + (intersection.height() >> 1);
- *framePtr = this;
- return test;
- }
- }
- testRect.intersect(rect);
- *x = testRect.x() + (testRect.width() >> 1);
- *y = testRect.y() + (testRect.height() >> 1);
- *framePtr = this;
- return test;
- }
- return NULL;
-}
-
-void CachedFrame::findClosest(BestData* bestData, Direction originalDirection,
- Direction direction, WebCore::IntRect* clip) const
-{
- const CachedNode* test = mCachedNodes.begin();
- while ((test = test->traverseNextNode()) != NULL) {
- const CachedFrame* child = hasFrame(test);
- if (child != NULL) {
- const CachedNode* childDoc = child->validDocument();
- if (childDoc == NULL)
- continue;
- child->findClosest(bestData, originalDirection, direction, clip);
- }
- if (test->noSecondChance())
- continue;
- if (test->isNavable(this, *clip) == false)
- continue;
- if (checkVisited(test, originalDirection) == false)
- continue;
- size_t partMax = test->navableRects();
- for (size_t part = 0; part < partMax; part++) {
- WebCore::IntRect testBounds = test->ring(this, part);
- if (clip->intersects(testBounds) == false)
- continue;
- if (clip->contains(testBounds) == false) {
- if (direction & UP_DOWN) {
-// if (testBounds.x() > clip->x() || testBounds.right() < clip->right())
-// continue;
- testBounds.setX(clip->x());
- testBounds.setWidth(clip->width());
- } else {
-// if (testBounds.y() > clip->y() || testBounds.bottom() < clip->bottom())
-// continue;
- testBounds.setY(clip->y());
- testBounds.setHeight(clip->height());
- }
- if (clip->contains(testBounds) == false)
- continue;
- }
- int distance;
- // seems like distance for UP for instance needs to be 'test top closest to
- // clip bottom' -- keep the old code but try this instead
- switch (direction) {
-#if 0
- case LEFT:
- distance = testBounds.x() - clip->x();
- break;
- case RIGHT:
- distance = clip->right() - testBounds.right();
- break;
- case UP:
- distance = testBounds.y() - clip->y();
- break;
- case DOWN:
- distance = clip->bottom() - testBounds.bottom();
- break;
-#else
- case LEFT:
- distance = clip->maxX() - testBounds.x();
- break;
- case RIGHT:
- distance = testBounds.maxX() - clip->x();
- break;
- case UP:
- distance = clip->maxY() - testBounds.y();
- break;
- case DOWN:
- distance = testBounds.maxY() - clip->y();
- break;
-#endif
- default:
- distance = 0;
- ASSERT(false);
- }
- if (distance < bestData->mDistance) {
- bestData->mNode = test;
- bestData->mFrame = this;
- bestData->mDistance = distance;
- WebCore::IntRect rect = test->ring(this, part);
- bestData->setMouseBounds(rect);
- bestData->setNodeBounds(rect);
- CachedHistory* cachedHistory = history();
- switch (direction) {
- case LEFT:
- bestData->setLeftDirection(cachedHistory);
- break;
- case RIGHT:
- bestData->setRightDirection(cachedHistory);
- break;
- case UP:
- bestData->setUpDirection(cachedHistory);
- break;
- case DOWN:
- bestData->setDownDirection(cachedHistory);
- break;
- default:
- ASSERT(0);
- }
- }
- }
- }
-}
-
-void CachedFrame::finishInit()
-{
- CachedNode* lastCached = lastNode();
- lastCached->setLast();
- CachedFrame* child = mCachedFrames.begin();
- while (child != mCachedFrames.end()) {
- child->mParent = this;
- child->finishInit();
- child++;
- }
- CachedFrame* frameParent;
- if (mFocusIndex >= 0 && (frameParent = parent()))
- frameParent->setFocusIndex(indexInParent());
-}
-
-const CachedNode* CachedFrame::frameDown(const CachedNode* test,
- const CachedNode* limit, BestData* bestData) const
-{
- BestData originalData = *bestData;
- do {
- if (moveInFrame(&CachedFrame::frameDown, test, bestData))
- continue;
- BestData testData;
- if (frameNodeCommon(testData, test, bestData, &originalData) == REJECT_TEST)
- continue;
- if (checkVisited(test, DOWN) == false)
- continue;
- size_t parts = test->navableRects();
- for (size_t part = 0; part < parts; part++) {
- testData.setNodeBounds(test->ring(this, part));
- if (testData.setDownDirection(history()))
- continue;
- int result = framePartCommon(testData, test, bestData);
- if (result == REJECT_TEST)
- continue;
- if (result == 0 && limit == NULL) { // retry all data up to this point, since smaller may have replaced node preferable to larger
- BestData innerData = testData;
- frameDown(document(), test, &innerData);
- if (checkVisited(innerData.mNode, DOWN)) {
- *bestData = innerData;
- continue;
- }
- }
- if (checkVisited(test, DOWN))
- *bestData = testData;
- }
- } while ((test = test->traverseNextNode()) != limit);
- ASSERT(mRoot->mCursor == NULL || bestData->mNode != mRoot->mCursor);
- // does the best contain something (or, is it contained by an area which is not the cursor?)
- // if so, is the conainer/containee should have been chosen, but wasn't -- so there's a better choice
- // in the doc list prior to this choice
- //
- return bestData->mNode;
-}
-
-const CachedNode* CachedFrame::frameLeft(const CachedNode* test,
- const CachedNode* limit, BestData* bestData) const
-{
- BestData originalData = *bestData;
- do {
- if (moveInFrame(&CachedFrame::frameLeft, test, bestData))
- continue;
- BestData testData;
- if (frameNodeCommon(testData, test, bestData, &originalData) == REJECT_TEST)
- continue;
- if (checkVisited(test, LEFT) == false)
- continue;
- size_t parts = test->navableRects();
- for (size_t part = 0; part < parts; part++) {
- testData.setNodeBounds(test->ring(this, part));
- if (testData.setLeftDirection(history()))
- continue;
- int result = framePartCommon(testData, test, bestData);
- if (result == REJECT_TEST)
- continue;
- if (result == 0 && limit == NULL) { // retry all data up to this point, since smaller may have replaced node preferable to larger
- BestData innerData = testData;
- frameLeft(document(), test, &innerData);
- if (checkVisited(innerData.mNode, LEFT)) {
- *bestData = innerData;
- continue;
- }
- }
- if (checkVisited(test, LEFT))
- *bestData = testData;
- }
- } while ((test = test->traverseNextNode()) != limit); // FIXME ??? left and up should use traversePreviousNode to choose reverse document order
- ASSERT(mRoot->mCursor == NULL || bestData->mNode != mRoot->mCursor);
- return bestData->mNode;
-}
-
-int CachedFrame::frameNodeCommon(BestData& testData, const CachedNode* test,
- BestData* bestData, BestData* originalData) const
-{
- testData.mFrame = this;
- testData.mNode = test;
- test->clearCondition();
- if (test->disabled()) {
- testData.mNode->setCondition(CachedNode::DISABLED);
- return REJECT_TEST;
- }
- WebCore::IntRect bounds = test->bounds(this);
- if (bounds.isEmpty()) {
- testData.mNode->setCondition(CachedNode::NAVABLE);
- return REJECT_TEST;
- }
- if (mRoot->scrolledBounds().intersects(bounds) == false) {
- testData.mNode->setCondition(CachedNode::NAVABLE);
- return REJECT_TEST;
- }
- if (mRoot->rootLayer() && !test->isInLayer()
- && !mRoot->baseUncovered().intersects(bounds)) {
- testData.mNode->setCondition(CachedNode::UNDER_LAYER);
- return REJECT_TEST;
- }
-// if (isNavable(test, &testData.mNodeBounds, walk) == false) {
-// testData.mNode->setCondition(CachedNode::NAVABLE);
-// return REJECT_TEST;
-// }
-//
- if (test == mRoot->mCursor) {
- testData.mNode->setCondition(CachedNode::NOT_CURSOR_NODE);
- return REJECT_TEST;
- }
-// if (test->bounds().contains(mRoot->mCursorBounds)) {
-// testData.mNode->setCondition(CachedNode::NOT_ENCLOSING_CURSOR);
-// return REJECT_TEST;
-// }
- void* par = mRoot->mCursor ? mRoot->mCursor->parentGroup() : NULL;
- testData.mCursorChild = par ? test->parentGroup() == par : false;
- if (bestData->mNode == NULL)
- return TEST_IS_BEST;
- if (mRoot->mCursor && testData.mNode->parentIndex() != bestData->mNode->parentIndex()) {
- int cursorParentIndex = mRoot->mCursor->parentIndex();
- if (cursorParentIndex >= 0) {
- if (bestData->mNode->parentIndex() == cursorParentIndex)
- return REJECT_TEST;
- if (testData.mNode->parentIndex() == cursorParentIndex)
- return TEST_IS_BEST;
- }
- }
- if (testData.mNode->parent() == bestData->mNode) {
- testData.mNode->setCondition(CachedNode::CHILD);
- return REJECT_TEST;
- }
- if (testData.mNode == bestData->mNode->parent())
- return TEST_IS_BEST;
- int testInBest = testData.isContainer(bestData); /* -1 pick best over test, 0 no containership, 1 pick test over best */
- if (testInBest == 1) {
- if (test->isArea() || bestData->mNode->isArea())
- return UNDECIDED;
- bestData->mNode = NULL; // force part tests to be ignored, yet still set up remaining test data for later comparisons
- return TEST_IS_BEST;
- }
- if (testInBest == -1) {
- testData.mNode->setCondition(CachedNode::OUTSIDE_OF_BEST);
- return REJECT_TEST;
- }
- if (originalData->mNode != NULL) { // test is best case
- testInBest = testData.isContainer(originalData);
- if (testInBest == -1) { /* test is inside best */
- testData.mNode->setCondition(CachedNode::OUTSIDE_OF_ORIGINAL);
- return REJECT_TEST;
- }
- }
- return UNDECIDED;
-}
-
-int CachedFrame::framePartCommon(BestData& testData,
- const CachedNode* test, BestData* bestData) const
-{
- if (mRoot->mCursor
- && testData.bounds().contains(mRoot->mCursorBounds)
- && !test->wantsKeyEvents()) {
- testData.mNode->setCondition(CachedNode::NOT_ENCLOSING_CURSOR);
- return REJECT_TEST;
- }
- testData.setDistances();
- if (bestData->mNode != NULL) {
- int compared = compare(testData, *bestData);
- if (compared == 0 && test->isArea() == false && bestData->mNode->isArea() == false)
- goto pickTest;
- if (compared >= 0)
- return compared;
- }
-pickTest:
- return -1; // pick test
-}
-
-const CachedNode* CachedFrame::frameRight(const CachedNode* test,
- const CachedNode* limit, BestData* bestData) const
-{
- BestData originalData = *bestData;
- do {
- if (moveInFrame(&CachedFrame::frameRight, test, bestData))
- continue;
- BestData testData;
- if (frameNodeCommon(testData, test, bestData, &originalData) == REJECT_TEST)
- continue;
- if (checkVisited(test, RIGHT) == false)
- continue;
- size_t parts = test->navableRects();
- for (size_t part = 0; part < parts; part++) {
- testData.setNodeBounds(test->ring(this, part));
- if (testData.setRightDirection(history()))
- continue;
- int result = framePartCommon(testData, test, bestData);
- if (result == REJECT_TEST)
- continue;
- if (result == 0 && limit == NULL) { // retry all data up to this point, since smaller may have replaced node preferable to larger
- BestData innerData = testData;
- frameRight(document(), test, &innerData);
- if (checkVisited(innerData.mNode, RIGHT)) {
- *bestData = innerData;
- continue;
- }
- }
- if (checkVisited(test, RIGHT))
- *bestData = testData;
- }
- } while ((test = test->traverseNextNode()) != limit);
- ASSERT(mRoot->mCursor == NULL || bestData->mNode != mRoot->mCursor);
- return bestData->mNode;
-}
-
-const CachedNode* CachedFrame::frameUp(const CachedNode* test,
- const CachedNode* limit, BestData* bestData) const
-{
- BestData originalData = *bestData;
- do {
- if (moveInFrame(&CachedFrame::frameUp, test, bestData))
- continue;
- BestData testData;
- if (frameNodeCommon(testData, test, bestData, &originalData) == REJECT_TEST)
- continue;
- if (checkVisited(test, UP) == false)
- continue;
- size_t parts = test->navableRects();
- for (size_t part = 0; part < parts; part++) {
- testData.setNodeBounds(test->ring(this, part));
- if (testData.setUpDirection(history()))
- continue;
- int result = framePartCommon(testData, test, bestData);
- if (result == REJECT_TEST)
- continue;
- if (result == 0 && limit == NULL) { // retry all data up to this point, since smaller may have replaced node preferable to larger
- BestData innerData = testData;
- frameUp(document(), test, &innerData);
- if (checkVisited(innerData.mNode, UP)) {
- *bestData = innerData;
- continue;
- }
- }
- if (checkVisited(test, UP))
- *bestData = testData;
- }
- } while ((test = test->traverseNextNode()) != limit); // FIXME ??? left and up should use traversePreviousNode to choose reverse document order
- ASSERT(mRoot->mCursor == NULL || bestData->mNode != mRoot->mCursor);
- return bestData->mNode;
-}
-
-CachedFrame* CachedFrame::hasFrame(const CachedNode* node)
-{
- return node->isFrame() ? &mCachedFrames[node->childFrameIndex()] : NULL;
-}
-
-void CachedFrame::hideCursor()
-{
- DBG_NAV_LOGD("mCursorIndex=%d", mCursorIndex);
- if (mCursorIndex < CURSOR_SET)
- return;
- CachedNode& cursor = mCachedNodes[mCursorIndex];
- cursor.hideCursor(this);
-}
-
-CachedHistory* CachedFrame::history() const
-{
- return mRoot->rootHistory();
-}
-
-void CachedFrame::init(const CachedRoot* root, int childFrameIndex,
- WebCore::Frame* frame)
-{
- mContents = WebCore::IntRect(0, 0, 0, 0); // fixed up for real in setData()
- mLocalViewBounds = WebCore::IntRect(0, 0, 0, 0);
- mViewBounds = WebCore::IntRect(0, 0, 0, 0);
- mRoot = root;
- mCursorIndex = CURSOR_UNINITIALIZED; // not explicitly cleared
- mFocusIndex = -1;
- mFrame = frame;
- mParent = NULL; // set up parents after stretchy arrays are set up
- mIndexInParent = childFrameIndex;
-}
-
-#if USE(ACCELERATED_COMPOSITING)
-const CachedLayer* CachedFrame::layer(const CachedNode* node) const
-{
- if (!node->isInLayer())
- return 0;
- CachedLayer test;
- test.setCachedNodeIndex(node->index());
- return std::lower_bound(mCachedLayers.begin(), mCachedLayers.end(), test);
-}
-#endif
-
-WebCore::IntRect CachedFrame::localBounds(const CachedNode* node,
- const WebCore::IntRect& rect) const
-{
- DBG_NAV_LOGD("node=%p [%d] rect=(%d,%d,w=%d,h=%d)",
- node, node->index(), rect.x(), rect.y(), rect.width(), rect.height());
-#if USE(ACCELERATED_COMPOSITING)
- return layer(node)->localBounds(mRoot->rootLayer(), rect);
-#else
- return rect;
-#endif
-}
-
-int CachedFrame::minWorkingHorizontal() const
-{
- return history()->minWorkingHorizontal();
-}
-
-int CachedFrame::minWorkingVertical() const
-{
- return history()->minWorkingVertical();
-}
-
-int CachedFrame::maxWorkingHorizontal() const
-{
- return history()->maxWorkingHorizontal();
-}
-
-int CachedFrame::maxWorkingVertical() const
-{
- return history()->maxWorkingVertical();
-}
-
-const CachedNode* CachedFrame::nextTextField(const CachedNode* start,
- const CachedFrame** framePtr, bool* startFound) const
-{
- const CachedNode* test = mCachedNodes.begin();
- while ((test = test->traverseNextNode())) {
- const CachedFrame* frame = hasFrame(test);
- if (frame) {
- if (!frame->validDocument())
- continue;
- const CachedNode* node
- = frame->nextTextField(start, framePtr, startFound);
- if (node)
- return node;
- } else if (test->isTextInput()) {
- if (test == start)
- *startFound = true;
- else if (*startFound) {
- if (framePtr)
- *framePtr = this;
- return test;
- }
- }
- }
- return 0;
-}
-
-bool CachedFrame::moveInFrame(MoveInDirection moveInDirection,
- const CachedNode* test, BestData* bestData) const
-{
- const CachedFrame* frame = hasFrame(test);
- if (frame == NULL)
- return false; // if it's not a frame, let the caller have another swing at it
- const CachedNode* childDoc = frame->validDocument();
- if (childDoc == NULL)
- return true;
- (frame->*moveInDirection)(childDoc, NULL, bestData);
- return true;
-}
-
-const WebCore::IntRect& CachedFrame::_navBounds() const
-{
- return history()->navBounds();
-}
-
-SkPicture* CachedFrame::picture(const CachedNode* node) const
-{
-#if USE(ACCELERATED_COMPOSITING)
- if (node->isInLayer())
- return layer(node)->picture(mRoot->rootLayer());
-#endif
- return mRoot->mPicture;
-}
-
-SkPicture* CachedFrame::picture(const CachedNode* node, int* xPtr, int* yPtr) const
-{
-#if USE(ACCELERATED_COMPOSITING)
- if (node->isInLayer()) {
- const CachedLayer* cachedLayer = layer(node);
- const LayerAndroid* rootLayer = mRoot->rootLayer();
- cachedLayer->toLocal(rootLayer, xPtr, yPtr);
- return cachedLayer->picture(rootLayer);
- }
-#endif
- return mRoot->mPicture;
-}
-
-void CachedFrame::resetClippedOut()
-{
- for (CachedNode* test = mCachedNodes.begin(); test != mCachedNodes.end(); test++)
- {
- if (test->clippedOut()) {
- test->setDisabled(false);
- test->setClippedOut(false);
- }
- }
- for (CachedFrame* frame = mCachedFrames.begin(); frame != mCachedFrames.end();
- frame++) {
- frame->resetClippedOut();
- }
-}
-
-void CachedFrame::resetLayers()
-{
-#if USE(ACCELERATED_COMPOSITING)
- for (CachedFrame* frame = mCachedFrames.begin(); frame != mCachedFrames.end();
- frame++) {
- frame->resetLayers();
- }
-#endif
-}
-
-bool CachedFrame::sameFrame(const CachedFrame* test) const
-{
- ASSERT(test);
- if (mIndexInParent != test->mIndexInParent)
- return false;
- if (mIndexInParent == -1) // index within parent's array of children, or -1 if root
- return true;
- return mParent->sameFrame(test->mParent);
-}
-
-void CachedFrame::setData()
-{
- if (this != mRoot) {
- mViewBounds = mLocalViewBounds;
- mViewBounds.intersect(mRoot->mViewBounds);
- }
- int x, y;
- if (parent() == NULL)
- x = y = 0;
- else {
- x = mLocalViewBounds.x();
- y = mLocalViewBounds.y();
- }
- mContents.setX(x);
- mContents.setY(y);
- CachedFrame* child = mCachedFrames.begin();
- while (child != mCachedFrames.end()) {
- child->setData();
- child++;
- }
-}
-
-bool CachedFrame::setCursor(WebCore::Frame* frame, WebCore::Node* node,
- int x, int y)
-{
- if (NULL == node) {
- const_cast<CachedRoot*>(mRoot)->setCursor(NULL, NULL);
- return true;
- }
- if (mFrame != frame) {
- for (CachedFrame* testF = mCachedFrames.begin(); testF != mCachedFrames.end();
- testF++) {
- if (testF->setCursor(frame, node, x, y))
- return true;
- }
- DBG_NAV_LOGD("no frame frame=%p node=%p", frame, node);
- return false;
- }
- bool first = true;
- CachedNode const * const end = mCachedNodes.end();
- do {
- for (CachedNode* test = mCachedNodes.begin(); test != end; test++) {
- if (test->nodePointer() != node && first)
- continue;
- size_t partMax = test->navableRects();
- for (size_t part = 0; part < partMax; part++) {
- WebCore::IntRect testBounds = test->ring(this, part);
- if (testBounds.contains(x, y) == false)
- continue;
- if (test->isCursor()) {
- DBG_NAV_LOGD("already set? test=%d frame=%p node=%p x=%d y=%d",
- test->index(), frame, node, x, y);
- return false;
- }
- const_cast<CachedRoot*>(mRoot)->setCursor(this, test);
- return true;
- }
- }
- DBG_NAV_LOGD("moved? frame=%p node=%p x=%d y=%d", frame, node, x, y);
- } while ((first ^= true) == false);
-failed:
- DBG_NAV_LOGD("no match frame=%p node=%p", frame, node);
- return false;
-}
-
-const CachedNode* CachedFrame::validDocument() const
-{
- const CachedNode* doc = document();
- return doc != NULL && mViewBounds.isEmpty() == false ? doc : NULL;
-}
-
-bool CachedFrame::BestData::canBeReachedByAnotherDirection()
-{
- if (mMajorButt > -MIN_OVERLAP)
- return false;
- mMajorButt = -mMajorButt;
- return mNavOutside;
-}
-
-int CachedFrame::BestData::isContainer(CachedFrame::BestData* other)
-{
- int _x = x();
- int otherRight = other->right();
- if (_x >= otherRight)
- return 0; // does not intersect
- int _y = y();
- int otherBottom = other->bottom();
- if (_y >= otherBottom)
- return 0; // does not intersect
- int _right = right();
- int otherX = other->x();
- if (otherX >= _right)
- return 0; // does not intersect
- int _bottom = bottom();
- int otherY = other->y();
- if (otherY >= _bottom)
- return 0; // does not intersect
- int intoX = otherX - _x;
- int intoY = otherY - _y;
- int intoRight = otherRight - _right;
- int intoBottom = otherBottom - _bottom;
- bool contains = intoX >= 0 && intoY >= 0 && intoRight <= 0 && intoBottom <= 0;
- if (contains && mNode->partRectsContains(other->mNode)) {
-// if (mIsArea == false && hasMouseOver())
-// other->mMouseOver = mNode;
- return mNode->isArea() ? 1 : -1;
- }
- bool containedBy = intoX <= 0 && intoY <= 0 && intoRight >= 0 && intoBottom >= 0;
- if (containedBy && other->mNode->partRectsContains(mNode)) {
-// if (other->mIsArea == false && other->hasMouseOver())
-// mMouseOver = other->mNode;
- return other->mNode->isArea() ? -1 : 1;
- }
- return 0;
-}
-
-// distance scale factor factor as a 16.16 scalar
-SkFixed CachedFrame::BestData::Overlap(int span, int left, int right)
-{
- unsigned result;
- if (left > 0 && left < span && right > span)
- result = (unsigned) left;
- else if (right > 0 && right < span && left > span)
- result = (unsigned) right;
- else if (left > 0 && right > 0)
- return SK_Fixed1;
- else
- return 0;
- result = (result << 16) / (unsigned) span; // linear proportion, always less than fixed 1
- return (SkFixed) result;
-// !!! experiment with weight -- enable if overlaps are preferred too much
-// or reverse weighting if overlaps are preferred to little
-// return (SkFixed) (result * result >> 16); // but fall off with square
-}
-
-void CachedFrame::BestData::setDistances()
-{
- mDistance = abs(mMajorDelta);
- int sideDistance = mWorkingDelta;
- if (mWorkingOverlap < SK_Fixed1) {
- if (mPreferred > 0)
- sideDistance = mWorkingDelta2;
- } else if (sideDistance >= 0 && mWorkingDelta2 >=- 0)
- sideDistance = 0;
- else {
- ASSERT(sideDistance <= 0 && mWorkingDelta2 <= 0);
- if (sideDistance < mWorkingDelta2)
- sideDistance = mWorkingDelta2;
- }
- // if overlap, smaller abs mWorkingDelta is better, smaller abs majorDelta is better
- // if not overlap, positive mWorkingDelta is better
- mSideDistance = sideDistance;
-}
-
-bool CachedFrame::BestData::setDownDirection(const CachedHistory* history)
-{
- const WebCore::IntRect& navBounds = history->navBounds();
- mMajorButt = mNodeBounds.y() - navBounds.maxY();
- int testX = mNodeBounds.x();
- int testRight = mNodeBounds.maxX();
- setNavOverlap(navBounds.width(), navBounds.maxX() - testX,
- testRight - navBounds.x());
- if (canBeReachedByAnotherDirection()) {
- mNode->setCondition(CachedNode::BEST_DIRECTION);
- return REJECT_TEST;
- }
- int inNavTop = mNodeBounds.y() - navBounds.y();
- mMajorDelta2 = inNavTop;
- mMajorDelta = mMajorDelta2 + ((mNodeBounds.height() -
- navBounds.height()) >> 1);
- if (mMajorDelta2 <= 1 && mMajorDelta <= 1) {
- mNode->setCondition(CachedNode::CENTER_FURTHER); // never move up or sideways
- return REJECT_TEST;
- }
- int inNavBottom = navBounds.maxY() - mNodeBounds.maxY();
- setNavInclusion(testRight - navBounds.maxX(), navBounds.x() - testX);
- bool subsumes = navBounds.height() > 0 && inOrSubsumesNav();
- if (inNavTop <= 0 && inNavBottom <= 0 && subsumes && !mNode->wantsKeyEvents()) {
- mNode->setCondition(CachedNode::NOT_ENCLOSING_CURSOR);
- return REJECT_TEST;
- }
- int maxV = history->maxWorkingVertical();
- int minV = history->minWorkingVertical();
- setWorkingOverlap(testRight - testX, maxV - testX, testRight - minV);
- setWorkingInclusion(testRight - maxV, minV - testX);
- if (mWorkingOverlap == 0 && mNavOverlap == 0 && inNavBottom >= 0) {
- mNode->setCondition(CachedNode::OVERLAP_OR_EDGE_FURTHER);
- return REJECT_TEST;
- }
- mInNav = history->directionChange() && inNavTop >= 0 &&
- inNavBottom > 0 && subsumes;
- return false;
-}
-
-bool CachedFrame::BestData::setLeftDirection(const CachedHistory* history)
-{
- const WebCore::IntRect& navBounds = history->navBounds();
- mMajorButt = navBounds.x() - mNodeBounds.maxX();
- int testY = mNodeBounds.y();
- int testBottom = mNodeBounds.maxY();
- setNavOverlap(navBounds.height(), navBounds.maxY() - testY,
- testBottom - navBounds.y());
- if (canBeReachedByAnotherDirection()) {
- mNode->setCondition(CachedNode::BEST_DIRECTION);
- return REJECT_TEST;
- }
- int inNavRight = navBounds.maxX() - mNodeBounds.maxX();
- mMajorDelta2 = inNavRight;
- mMajorDelta = mMajorDelta2 - ((navBounds.width() -
- mNodeBounds.width()) >> 1);
- if (mMajorDelta2 <= 1 && mMajorDelta <= 1) {
- mNode->setCondition(CachedNode::CENTER_FURTHER); // never move right or sideways
- return REJECT_TEST;
- }
- int inNavLeft = mNodeBounds.x() - navBounds.x();
- setNavInclusion(navBounds.y() - testY, testBottom - navBounds.maxY());
- bool subsumes = navBounds.width() > 0 && inOrSubsumesNav();
- if (inNavLeft <= 0 && inNavRight <= 0 && subsumes && !mNode->wantsKeyEvents()) {
- mNode->setCondition(CachedNode::NOT_ENCLOSING_CURSOR);
- return REJECT_TEST;
- }
- int maxH = history->maxWorkingHorizontal();
- int minH = history->minWorkingHorizontal();
- setWorkingOverlap(testBottom - testY, maxH - testY, testBottom - minH);
- setWorkingInclusion(minH - testY, testBottom - maxH);
- if (mWorkingOverlap == 0 && mNavOverlap == 0 && inNavLeft >= 0) {
- mNode->setCondition(CachedNode::OVERLAP_OR_EDGE_FURTHER);
- return REJECT_TEST;
- }
- mInNav = history->directionChange() && inNavLeft >= 0 &&
- inNavRight > 0 && subsumes; /* both L/R in or out */
- return false;
-}
-
-bool CachedFrame::BestData::setRightDirection(const CachedHistory* history)
-{
- const WebCore::IntRect& navBounds = history->navBounds();
- mMajorButt = mNodeBounds.x() - navBounds.maxX();
- int testY = mNodeBounds.y();
- int testBottom = mNodeBounds.maxY();
- setNavOverlap(navBounds.height(), navBounds.maxY() - testY,
- testBottom - navBounds.y());
- if (canBeReachedByAnotherDirection()) {
- mNode->setCondition(CachedNode::BEST_DIRECTION);
- return REJECT_TEST;
- }
- int inNavLeft = mNodeBounds.x() - navBounds.x();
- mMajorDelta2 = inNavLeft;
- mMajorDelta = mMajorDelta2 + ((mNodeBounds.width() -
- navBounds.width()) >> 1);
- if (mMajorDelta2 <= 1 && mMajorDelta <= 1) {
- mNode->setCondition(CachedNode::CENTER_FURTHER); // never move left or sideways
- return REJECT_TEST;
- }
- int inNavRight = navBounds.maxX() - mNodeBounds.maxX();
- setNavInclusion(testBottom - navBounds.maxY(), navBounds.y() - testY);
- bool subsumes = navBounds.width() > 0 && inOrSubsumesNav();
- if (inNavLeft <= 0 && inNavRight <= 0 && subsumes && !mNode->wantsKeyEvents()) {
- mNode->setCondition(CachedNode::NOT_ENCLOSING_CURSOR);
- return REJECT_TEST;
- }
- int maxH = history->maxWorkingHorizontal();
- int minH = history->minWorkingHorizontal();
- setWorkingOverlap(testBottom - testY, testBottom - minH, maxH - testY);
- setWorkingInclusion(testBottom - maxH, minH - testY);
- if (mWorkingOverlap == 0 && mNavOverlap == 0 && inNavRight >= 0) {
- mNode->setCondition(CachedNode::OVERLAP_OR_EDGE_FURTHER);
- return REJECT_TEST;
- }
- mInNav = history->directionChange() && inNavLeft >= 0 &&
- inNavRight > 0 && subsumes; /* both L/R in or out */
- return false;
-}
-
-bool CachedFrame::BestData::setUpDirection(const CachedHistory* history)
-{
- const WebCore::IntRect& navBounds = history->navBounds();
- mMajorButt = navBounds.y() - mNodeBounds.maxY();
- int testX = mNodeBounds.x();
- int testRight = mNodeBounds.maxX();
- setNavOverlap(navBounds.width(), navBounds.maxX() - testX,
- testRight - navBounds.x());
- if (canBeReachedByAnotherDirection()) {
- mNode->setCondition(CachedNode::BEST_DIRECTION);
- return REJECT_TEST;
- }
- int inNavBottom = navBounds.maxY() - mNodeBounds.maxY();
- mMajorDelta2 = inNavBottom;
- mMajorDelta = mMajorDelta2 - ((navBounds.height() -
- mNodeBounds.height()) >> 1);
- if (mMajorDelta2 <= 1 && mMajorDelta <= 1) {
- mNode->setCondition(CachedNode::CENTER_FURTHER); // never move down or sideways
- return REJECT_TEST;
- }
- int inNavTop = mNodeBounds.y() - navBounds.y();
- setNavInclusion(navBounds.x() - testX, testRight - navBounds.maxX());
- bool subsumes = navBounds.height() > 0 && inOrSubsumesNav();
- if (inNavTop <= 0 && inNavBottom <= 0 && subsumes && !mNode->wantsKeyEvents()) {
- mNode->setCondition(CachedNode::NOT_ENCLOSING_CURSOR);
- return REJECT_TEST;
- }
- int maxV = history->maxWorkingVertical();
- int minV = history->minWorkingVertical();
- setWorkingOverlap(testRight - testX, testRight - minV, maxV - testX);
- setWorkingInclusion(minV - testX, testRight - maxV);
- if (mWorkingOverlap == 0 && mNavOverlap == 0 && inNavTop >= 0) {
- mNode->setCondition(CachedNode::OVERLAP_OR_EDGE_FURTHER);
- return REJECT_TEST;
- }
- mInNav = history->directionChange() && inNavTop >= 0 &&
- inNavBottom > 0 && subsumes; /* both L/R in or out */
- return false;
-}
-
-void CachedFrame::BestData::setNavInclusion(int left, int right)
-{
- // if left and right <= 0, test node is completely in umbra of cursor
- // prefer leftmost center
- // if left and right > 0, test node subsumes cursor
- mNavDelta = left;
- mNavDelta2 = right;
-}
-
-void CachedFrame::BestData::setNavOverlap(int span, int left, int right)
-{
- // if left or right < 0, test node is not in umbra of cursor
- mNavOutside = left < MIN_OVERLAP || right < MIN_OVERLAP;
- mNavOverlap = Overlap(span, left, right); // prefer smallest negative left
-}
-
-void CachedFrame::BestData::setWorkingInclusion(int left, int right)
-{
- mWorkingDelta = left;
- mWorkingDelta2 = right;
-}
-
-// distance scale factor factor as a 16.16 scalar
-void CachedFrame::BestData::setWorkingOverlap(int span, int left, int right)
-{
- // if left or right < 0, test node is not in umbra of cursor
- mWorkingOutside = left < MIN_OVERLAP || right < MIN_OVERLAP;
- mWorkingOverlap = Overlap(span, left, right);
- mPreferred = left <= 0 ? 0 : left;
-}
-
-#if DUMP_NAV_CACHE
-
-#define DEBUG_PRINT_RECT(prefix, debugName, field) \
- { const WebCore::IntRect& r = b->field; \
- DUMP_NAV_LOGD("%s DebugTestRect TEST%s_" #debugName "={%d, %d, %d, %d}; //" #field "\n", \
- prefix, mFrameName, r.x(), r.y(), r.width(), r.height()); }
-
-CachedFrame* CachedFrame::Debug::base() const {
- CachedFrame* nav = (CachedFrame*) ((char*) this - OFFSETOF(CachedFrame, mDebug));
- return nav;
-}
-
-void CachedFrame::Debug::print() const
-{
- CachedFrame* b = base();
- DEBUG_PRINT_RECT("//", CONTENTS, mContents);
- DEBUG_PRINT_RECT("", BOUNDS, mLocalViewBounds);
- DEBUG_PRINT_RECT("//", VIEW, mViewBounds);
-
- DUMP_NAV_LOGD("// CachedNode mCachedNodes={ // count=%d\n", b->mCachedNodes.size());
- for (CachedNode* node = b->mCachedNodes.begin();
- node != b->mCachedNodes.end(); node++) {
- node->mDebug.print();
- const CachedInput* input = b->textInput(node);
- if (input)
- input->mDebug.print();
- DUMP_NAV_LOGD("\n");
- }
- DUMP_NAV_LOGD("// }; // end of nodes\n");
-#if USE(ACCELERATED_COMPOSITING)
- DUMP_NAV_LOGD("// CachedLayer mCachedLayers={ // count=%d\n", b->mCachedLayers.size());
- for (CachedLayer* layer = b->mCachedLayers.begin();
- layer != b->mCachedLayers.end(); layer++) {
- layer->mDebug.print();
- }
- DUMP_NAV_LOGD("// }; // end of layers\n");
-#endif // USE(ACCELERATED_COMPOSITING)
- DUMP_NAV_LOGD("// CachedColor mCachedColors={ // count=%d\n", b->mCachedColors.size());
- for (CachedColor* color = b->mCachedColors.begin();
- color != b->mCachedColors.end(); color++) {
- color->mDebug.print();
- }
- DUMP_NAV_LOGD("// }; // end of colors\n");
- DUMP_NAV_LOGD("// CachedFrame mCachedFrames={ // count=%d\n", b->mCachedFrames.size());
- for (CachedFrame* child = b->mCachedFrames.begin();
- child != b->mCachedFrames.end(); child++)
- {
- child->mDebug.print();
- }
- DUMP_NAV_LOGD("// }; // end of child frames\n");
- DUMP_NAV_LOGD("// void* mFrame=(void*) %p;\n", b->mFrame);
- DUMP_NAV_LOGD("// CachedFrame* mParent=%p;\n", b->mParent);
- DUMP_NAV_LOGD("// int mIndexInParent=%d;\n", b->mIndexInParent);
- DUMP_NAV_LOGD("// const CachedRoot* mRoot=%p;\n", b->mRoot);
- DUMP_NAV_LOGD("// int mCursorIndex=%d;\n", b->mCursorIndex);
- DUMP_NAV_LOGD("// int mFocusIndex=%d;\n", b->mFocusIndex);
-}
-
-bool CachedFrame::Debug::validate(const CachedNode* node) const
-{
- const CachedFrame* b = base();
- if (b->mCachedNodes.size() == 0)
- return false;
- if (node >= b->mCachedNodes.begin() && node < b->mCachedNodes.end())
- return true;
- for (const CachedFrame* child = b->mCachedFrames.begin();
- child != b->mCachedFrames.end(); child++)
- if (child->mDebug.validate(node))
- return true;
- return false;
-}
-
-#undef DEBUG_PRINT_RECT
-
-#endif
-
-}
diff --git a/Source/WebKit/android/nav/CachedFrame.h b/Source/WebKit/android/nav/CachedFrame.h
deleted file mode 100644
index da86521..0000000
--- a/Source/WebKit/android/nav/CachedFrame.h
+++ /dev/null
@@ -1,287 +0,0 @@
-/*
- * Copyright 2007, 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.
- */
-
-// FIXME: A file of this name already exists in WebCore/history.
-// This file should be renamed.
-#ifndef AndroidCachedFrame_h
-#define AndroidCachedFrame_h
-
-#include "CachedColor.h"
-#include "CachedInput.h"
-#include "CachedLayer.h"
-#include "CachedNode.h"
-#include "IntRect.h"
-#include "SkFixed.h"
-#include "wtf/Vector.h"
-
-class SkPicture;
-
-namespace WebCore {
- class Frame;
- class Node;
-}
-
-namespace android {
-
-class CachedHistory;
-class CachedRoot;
-
- // first node referenced by cache is always document
-class CachedFrame {
-public:
- enum Direction {
- UNINITIALIZED = -1,
- LEFT,
- RIGHT,
- UP,
- DOWN,
- DIRECTION_COUNT,
- DIRECTION_MASK = DIRECTION_COUNT - 1,
- UP_DOWN = UP & DOWN, // mask and result
- RIGHT_DOWN = RIGHT & DOWN, // mask and result
- };
- enum Compare {
- UNDECIDED = -1,
- TEST_IS_BEST,
- REJECT_TEST
- };
- enum CursorInit {
- CURSOR_UNINITIALIZED = -2,
- CURSOR_CLEARED = -1,
- CURSOR_SET = 0
- };
- CachedFrame() {}
- void add(CachedColor& color) { mCachedColors.append(color); }
- void add(CachedInput& input) { mCachedTextInputs.append(input); }
-#if USE(ACCELERATED_COMPOSITING)
- void add(CachedLayer& layer) { mCachedLayers.append(layer); }
-#endif
- void add(CachedNode& node) { mCachedNodes.append(node); }
- void addFrame(CachedFrame& child) { mCachedFrames.append(child); }
- WebCore::IntRect adjustBounds(const CachedNode* ,
- const WebCore::IntRect& ) const;
- bool checkRings(const CachedNode* node,
- const WebCore::IntRect& testBounds) const;
- bool checkVisited(const CachedNode* , CachedFrame::Direction ) const;
- size_t childCount() { return mCachedFrames.size(); }
- void clearCursor();
- const CachedColor& color(const CachedNode* node) const {
- return mCachedColors[node->colorIndex()];
- }
- const CachedNode* currentCursor() const { return currentCursor(NULL); }
- const CachedNode* currentCursor(const CachedFrame** ) const;
- const CachedNode* currentFocus() const { return currentFocus(NULL); }
- const CachedNode* currentFocus(const CachedFrame** ) const;
- bool directionChange() const;
- const CachedNode* document() const { return mCachedNodes.begin(); }
- bool empty() const { return mCachedNodes.size() < 2; } // must have 1 past doc
- const CachedNode* findBestAt(const WebCore::IntRect& , int* best,
- bool* inside, const CachedNode** , const CachedFrame** directFrame,
- const CachedFrame** resultFrame, int* x,
- int* y, bool checkForHidden) const;
- const CachedFrame* findBestFrameAt(int x, int y) const;
- const CachedNode* findBestHitAt(const WebCore::IntRect& ,
- const CachedFrame** , int* x, int* y) const;
- void finishInit();
- CachedFrame* firstChild() { return mCachedFrames.begin(); }
- const CachedFrame* firstChild() const { return mCachedFrames.begin(); }
- void* framePointer() const { return mFrame; }
- CachedNode* getIndex(int index) { return index >= 0 ?
- &mCachedNodes[index] : NULL; }
- const CachedFrame* hasFrame(const CachedNode* node) const {
- return const_cast<CachedFrame*>(this)->hasFrame(node);
- }
- CachedFrame* hasFrame(const CachedNode* node);
- void hideCursor();
- int indexInParent() const { return mIndexInParent; }
- void init(const CachedRoot* root, int index, WebCore::Frame* frame);
- const CachedFrame* lastChild() const { return &mCachedFrames.last(); }
-#if USE(ACCELERATED_COMPOSITING)
- const CachedLayer* lastLayer() const { return &mCachedLayers.last(); }
-#endif
- CachedNode* lastNode() { return &mCachedNodes.last(); }
- CachedFrame* lastChild() { return &mCachedFrames.last(); }
-#if USE(ACCELERATED_COMPOSITING)
- const CachedLayer* layer(const CachedNode* ) const;
- size_t layerCount() const { return mCachedLayers.size(); }
-#endif
- WebCore::IntRect localBounds(const CachedNode* ,
- const WebCore::IntRect& ) const;
- const CachedFrame* parent() const { return mParent; }
- CachedFrame* parent() { return mParent; }
- SkPicture* picture(const CachedNode* ) const;
- SkPicture* picture(const CachedNode* , int* xPtr, int* yPtr) const;
- void resetLayers();
- bool sameFrame(const CachedFrame* ) const;
- void removeLast() { mCachedNodes.removeLast(); }
- void resetClippedOut();
- void setContentsSize(int width, int height) { mContents.setWidth(width);
- mContents.setHeight(height); }
- bool setCursor(WebCore::Frame* , WebCore::Node* , int x, int y);
- void setCursorIndex(int index) { mCursorIndex = index; }
- void setData();
- bool setFocus(WebCore::Frame* , WebCore::Node* , int x, int y);
- void setFocusIndex(int index) { mFocusIndex = index; }
- void setIndexInParent(int index) { mIndexInParent = index; }
- void setLocalViewBounds(const WebCore::IntRect& bounds) { mLocalViewBounds = bounds; }
- int size() { return mCachedNodes.size(); }
- const CachedInput* textInput(const CachedNode* node) const {
- return node->isTextInput() ? &mCachedTextInputs[node->textInputIndex()]
- : 0;
- }
- const CachedNode* validDocument() const;
-protected:
- const CachedNode* nextTextField(const CachedNode* start,
- const CachedFrame** framePtr, bool* found) const;
- struct BestData {
- int mDistance;
- int mSideDistance;
- int mMajorDelta; // difference of center of object
- // used only when leading and trailing edges contain another set of edges
- int mMajorDelta2; // difference of leading edge (only used when center is same)
- int mMajorButt; // checks for next cell butting up against or close to previous one
- int mWorkingDelta;
- int mWorkingDelta2;
- int mNavDelta;
- int mNavDelta2;
- const CachedFrame* mFrame;
- const CachedNode* mNode;
- SkFixed mWorkingOverlap; // this and below are fuzzy answers instead of bools
- SkFixed mNavOverlap;
- SkFixed mPreferred;
- bool mCursorChild;
- bool mInNav;
- bool mNavOutside;
- bool mWorkingOutside;
- int bottom() const { return bounds().maxY(); }
- const WebCore::IntRect& bounds() const { return mNodeBounds; }
- bool canBeReachedByAnotherDirection();
- int height() const { return bounds().height(); }
- bool inOrSubsumesNav() const { return (mNavDelta ^ mNavDelta2) >= 0; }
- bool inOrSubsumesWorking() const { return (mWorkingDelta ^ mWorkingDelta2) >= 0; }
- int isContainer(BestData* );
- const WebCore::IntRect& mouseBounds() const { return mMouseBounds; }
- static SkFixed Overlap(int span, int left, int right);
- void reset() { mNode = NULL; }
- int right() const { return bounds().maxX(); }
- void setMouseBounds(const WebCore::IntRect& b) { mMouseBounds = b; }
- void setNodeBounds(const WebCore::IntRect& b) { mNodeBounds = b; }
- void setDistances();
- bool setDownDirection(const CachedHistory* );
- bool setLeftDirection(const CachedHistory* );
- bool setRightDirection(const CachedHistory* );
- bool setUpDirection(const CachedHistory* );
- void setNavInclusion(int left, int right);
- void setNavOverlap(int span, int left, int right);
- void setWorkingInclusion(int left, int right);
- void setWorkingOverlap(int span, int left, int right);
- int width() const { return bounds().width(); }
- int x() const { return bounds().x(); }
- int y() const { return bounds().y(); }
-private: // since computing these is complicated, protect them so that the
- // are only written by appropriate helpers
- WebCore::IntRect mMouseBounds;
- WebCore::IntRect mNodeBounds;
- };
- typedef const CachedNode* (CachedFrame::*MoveInDirection)(
- const CachedNode* test, const CachedNode* limit, BestData* ) const;
- void adjustToTextColumn(int* delta) const;
- static bool CheckBetween(Direction , const WebCore::IntRect& bestRect,
- const WebCore::IntRect& prior, WebCore::IntRect* result);
- bool checkBetween(BestData* , Direction );
- int compare(BestData& testData, const BestData& bestData) const;
- void findClosest(BestData* , Direction original, Direction test,
- WebCore::IntRect* clip) const;
- int frameNodeCommon(BestData& testData, const CachedNode* test,
- BestData* bestData, BestData* originalData) const;
- int framePartCommon(BestData& testData, const CachedNode* test,
- BestData* ) const;
- const CachedNode* frameDown(const CachedNode* test, const CachedNode* limit,
- BestData* ) const;
- const CachedNode* frameLeft(const CachedNode* test, const CachedNode* limit,
- BestData* ) const;
- const CachedNode* frameRight(const CachedNode* test, const CachedNode* limit,
- BestData* ) const;
- const CachedNode* frameUp(const CachedNode* test, const CachedNode* limit,
- BestData* ) const;
- int minWorkingHorizontal() const;
- int minWorkingVertical() const;
- int maxWorkingHorizontal() const;
- int maxWorkingVertical() const;
- bool moveInFrame(MoveInDirection , const CachedNode* test, BestData* ) const;
- const WebCore::IntRect& _navBounds() const;
- WebCore::IntRect mContents;
- WebCore::IntRect mLocalViewBounds;
- WebCore::IntRect mViewBounds;
- WTF::Vector<CachedColor> mCachedColors;
- WTF::Vector<CachedNode> mCachedNodes;
- WTF::Vector<CachedFrame> mCachedFrames;
- WTF::Vector<CachedInput> mCachedTextInputs;
-#if USE(ACCELERATED_COMPOSITING)
- WTF::Vector<CachedLayer> mCachedLayers;
-#endif
- void* mFrame; // WebCore::Frame*, used only to compare pointers
- CachedFrame* mParent;
- int mCursorIndex;
- int mFocusIndex;
- int mIndexInParent; // index within parent's array of children, or -1 if root
- const CachedRoot* mRoot;
-private:
- CachedHistory* history() const;
-#ifdef BROWSER_DEBUG
-public:
- CachedNode* find(WebCore::Node* ); // !!! probably debugging only
- int mDebugIndex;
- int mDebugLoopbackOffset;
-#endif
-#if !defined NDEBUG || DUMP_NAV_CACHE
-public:
- class Debug {
-public:
- Debug() {
-#if DUMP_NAV_CACHE
- mFrameName[0] = '\0';
-#endif
-#if !defined NDEBUG
- mInUse = true;
-#endif
- }
-#if !defined NDEBUG
- ~Debug() { mInUse = false; }
- bool mInUse;
-#endif
-#if DUMP_NAV_CACHE
- CachedFrame* base() const;
- void print() const;
- bool validate(const CachedNode* ) const;
- char mFrameName[256];
-#endif
- } mDebug;
-#endif
-};
-
-}
-
-#endif // AndroidCachedFrame_h
diff --git a/Source/WebKit/android/nav/CachedHistory.cpp b/Source/WebKit/android/nav/CachedHistory.cpp
deleted file mode 100644
index d132cc3..0000000
--- a/Source/WebKit/android/nav/CachedHistory.cpp
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Copyright 2007, 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.
- */
-
-#include "CachedPrefix.h"
-#include "CachedFrame.h"
-#include "CachedNode.h"
-#if DUMP_NAV_CACHE
-#include "CachedRoot.h"
-#endif
-
-#include "CachedHistory.h"
-
-namespace android {
-
-CachedHistory::CachedHistory() {
- memset(this, 0, sizeof(CachedHistory)); // this assume the class has no virtuals
- mLastMove = CachedFrame::UNINITIALIZED;
- mPriorMove = CachedFrame::UNINITIALIZED;
-}
-
-
-void CachedHistory::addToVisited(const CachedNode* node, CachedFrame::Direction direction)
-{
- memmove(&mVisited[1], &mVisited[0], sizeof(mVisited) - sizeof(mVisited[0]));
- mVisited[0].mNode = node;
- mVisited[0].mDirection = direction;
-}
-
-bool CachedHistory::checkVisited(const CachedNode* node, CachedFrame::Direction direction) const
-{
- // if the direction is unchanged and we've already visited this node, don't visit it again
- int index = 0;
- while (index < NAVIGATION_VISIT_DEPTH - 1) {
- if (direction != mVisited[index].mDirection)
- break;
- index++; // compare with last direction, previous to last node (where the arrow took us from)
- if (node == mVisited[index].mNode)
- return false;
- }
- return true;
-}
-
-void CachedHistory::pinMaxMin(const WebCore::IntRect& viewBounds)
-{
- if (mMinWorkingHorizontal < viewBounds.y() || mMinWorkingHorizontal >= viewBounds.maxY())
- mMinWorkingHorizontal = viewBounds.y();
- if (mMaxWorkingHorizontal > viewBounds.maxY() || mMaxWorkingHorizontal <= viewBounds.y())
- mMaxWorkingHorizontal = viewBounds.maxY();
- if (mMinWorkingVertical < viewBounds.x() || mMinWorkingVertical >= viewBounds.maxX())
- mMinWorkingVertical = viewBounds.x();
- if (mMaxWorkingVertical > viewBounds.maxX() || mMaxWorkingVertical <= viewBounds.x())
- mMaxWorkingVertical = viewBounds.maxX();
-}
-
-void CachedHistory::reset()
-{
- memset(mVisited, 0, sizeof(mVisited));
-// mLastScroll = 0;
- mPriorBounds = WebCore::IntRect(0, 0, 0, 0);
- mDirectionChange = false;
- mDidFirstLayout = false;
- mPriorMove = mLastMove = CachedFrame::UNINITIALIZED;
- mMinWorkingHorizontal = mMinWorkingVertical = INT_MIN;
- mMaxWorkingHorizontal = mMaxWorkingVertical = INT_MAX;
-}
-
-void CachedHistory::setWorking(CachedFrame::Direction newMove,
- const CachedFrame* cursorFrame, const CachedNode* cursor,
- const WebCore::IntRect& viewBounds)
-{
- CachedFrame::Direction lastAxis = (CachedFrame::Direction) (mLastMove & ~CachedFrame::RIGHT_DOWN); // up, left or uninitialized
- CachedFrame::Direction newAxis = (CachedFrame::Direction) (newMove & ~CachedFrame::RIGHT_DOWN);
- bool change = newAxis != lastAxis;
- mDirectionChange = change && mLastMove != CachedFrame::UNINITIALIZED;
- if (cursor != NULL || mLastMove != CachedFrame::UNINITIALIZED) {
- mPriorMove = mLastMove;
- mLastMove = newMove;
- }
- const WebCore::IntRect* navBounds = &mNavBounds;
- if (cursor != NULL) {
- WebCore::IntRect cursorBounds = cursor->bounds(cursorFrame);
- if (cursorBounds.isEmpty() == false)
- mNavBounds = cursorBounds;
- }
- if (change) { // uninitialized or change in direction
- if (lastAxis != CachedFrame::LEFT && navBounds->height() > 0) {
- mMinWorkingHorizontal = navBounds->y();
- mMaxWorkingHorizontal = navBounds->maxY();
- }
- if (lastAxis != CachedFrame::UP && navBounds->width() > 0) {
- mMinWorkingVertical = navBounds->x();
- mMaxWorkingVertical = navBounds->maxX();
- }
- }
- pinMaxMin(viewBounds);
-}
-
-#if DUMP_NAV_CACHE
-
-#define DEBUG_PRINT_BOOL(field) \
- DUMP_NAV_LOGD("// bool " #field "=%s;\n", b->field ? "true" : "false")
-
-#define DEBUG_PRINT_RECT(field) \
- { const WebCore::IntRect& r = b->field; \
- DUMP_NAV_LOGD("// IntRect " #field "={%d, %d, %d, %d};\n", \
- r.x(), r.y(), r.width(), r.height()); }
-
-CachedHistory* CachedHistory::Debug::base() const {
- CachedHistory* nav = (CachedHistory*) ((char*) this - OFFSETOF(CachedHistory, mDebug));
- return nav;
-}
-
-const char* CachedHistory::Debug::direction(CachedFrame::Direction d) const
-{
- switch (d) {
- case CachedFrame::LEFT: return "LEFT"; break;
- case CachedFrame::RIGHT: return "RIGHT"; break;
- case CachedFrame::UP: return "UP"; break;
- case CachedFrame::DOWN: return "DOWN"; break;
- default: return "UNINITIALIZED";
- }
-}
-
-void CachedHistory::Debug::print(CachedRoot* root) const
-{
- CachedHistory* b = base();
- DUMP_NAV_LOGD("// Visited mVisited[]={\n");
- for (size_t i = 0; i < NAVIGATION_VISIT_DEPTH; i++) {
- const Visited& visit = b->mVisited[i];
- const CachedNode* node = visit.mNode;
- int index = root != NULL && root->CachedFrame::mDebug.validate(node) ?
- node->index() : -1;
- DUMP_NAV_LOGD(" // { 0x%p (%d), %s },\n", node, index, direction(visit.mDirection));
- }
- DUMP_NAV_LOGD("// };\n");
-// DUMP_NAV_LOGD("// int mLastScroll=%d;\n", b->mLastScroll);
- DEBUG_PRINT_RECT(mMouseBounds);
- DEBUG_PRINT_RECT(mNavBounds);
- DEBUG_PRINT_RECT(mPriorBounds);
- DEBUG_PRINT_BOOL(mDirectionChange);
- DEBUG_PRINT_BOOL(mDidFirstLayout);
- DUMP_NAV_LOGD("// CachedFrame::Direction mLastMove=%s, mPriorMove=%s;\n",
- direction(b->mLastMove), direction(b->mPriorMove));
- int max = b->mMaxWorkingHorizontal;
- DUMP_NAV_LOGD("static int TEST_MAX_H = %d;\n", max);
- int min = b->mMinWorkingHorizontal;
- if (min == INT_MIN)
- min++;
- DUMP_NAV_LOGD("static int TEST_MIN_H = %d;\n", min);
- max = b->mMaxWorkingVertical;
- DUMP_NAV_LOGD("static int TEST_MAX_V = %d;\n", max);
- min = b->mMinWorkingVertical;
- if (min == INT_MIN)
- min++;
- DUMP_NAV_LOGD("static int TEST_MIN_V = %d;\n", min);
- DUMP_NAV_LOGD("\n");
-}
-
-#endif
-
-}
diff --git a/Source/WebKit/android/nav/CachedHistory.h b/Source/WebKit/android/nav/CachedHistory.h
deleted file mode 100644
index 96975ca..0000000
--- a/Source/WebKit/android/nav/CachedHistory.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright 2007, 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 CachedHistory_h
-#define CachedHistory_h
-
-#include "CachedFrame.h"
-
-#define NAVIGATION_VISIT_DEPTH 8 // the number of nodes last visited -- used to detect ping-ponging (number should be tuned)
-
-namespace android {
-
-class CachedRoot;
-
-// CachedHistory is maintained even if DOM is rebuilt by running script.
-// It uses blind pointers for comparison in the previously visited nodes.
-class CachedHistory {
-public:
- CachedHistory();
- void addToVisited(const CachedNode* , CachedFrame::Direction );
- bool checkVisited(const CachedNode* , CachedFrame::Direction ) const;
- bool didFirstLayout() const { return mDidFirstLayout; }
- bool directionChange() const { return mDirectionChange; }
- int minWorkingHorizontal() const { return mMinWorkingHorizontal; }
- int minWorkingVertical() const { return mMinWorkingVertical; }
- int maxWorkingHorizontal() const { return mMaxWorkingHorizontal; }
- int maxWorkingVertical() const { return mMaxWorkingVertical; }
- const WebCore::IntRect& navBounds() const { return mNavBounds; }
- const WebCore::IntRect& priorBounds() const { return mPriorBounds; }
- void setDidFirstLayout(bool did) { mDidFirstLayout = did; }
- void setMouseBounds(const WebCore::IntRect& loc) { mMouseBounds = loc; }
- void setNavBounds(const WebCore::IntRect& loc) { mNavBounds = loc; }
- void setWorking(CachedFrame::Direction , const CachedFrame* ,
- const CachedNode* , const WebCore::IntRect& viewBounds);
- void reset();
-private:
- void pinMaxMin(const WebCore::IntRect& viewBounds);
- struct Visited {
- const CachedNode* mNode;
- CachedFrame::Direction mDirection;
- } mVisited[NAVIGATION_VISIT_DEPTH];
- WebCore::IntRect mMouseBounds; // constricted bounds, if cursor ring is partially visible
- WebCore::IntRect mNavBounds; // cursor ring bounds plus optional keystroke movement
- WebCore::IntRect mPriorBounds; // prior chosen cursor ring (for reversing narrowing)
- bool mDirectionChange;
- bool mDidFirstLayout; // set true when page is newly laid out
- CachedFrame::Direction mLastMove;
- CachedFrame::Direction mPriorMove;
- int mMinWorkingHorizontal;
- int mMaxWorkingHorizontal;
- int mMinWorkingVertical;
- int mMaxWorkingVertical;
- friend class CachedRoot;
-#if DUMP_NAV_CACHE
-public:
- class Debug {
-public:
- CachedHistory* base() const;
- const char* direction(CachedFrame::Direction d) const;
- void print(CachedRoot* ) const;
- } mDebug;
-#endif
-};
-
-}
-
-#endif
diff --git a/Source/WebKit/android/nav/CachedInput.cpp b/Source/WebKit/android/nav/CachedInput.cpp
deleted file mode 100644
index a6a57ef..0000000
--- a/Source/WebKit/android/nav/CachedInput.cpp
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright 2009, 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.
- */
-
-#include "CachedPrefix.h"
-#include "CachedInput.h"
-
-namespace android {
-
-void CachedInput::init() {
- bzero(this, sizeof(CachedInput));
- mName = WTF::String();
-}
-
-void CachedInput::setTypeFromElement(WebCore::HTMLInputElement* element)
-{
- ASSERT(element);
-
- if (element->isPasswordField())
- mType = PASSWORD;
- else if (element->isSearchField())
- mType = SEARCH;
- else if (element->isEmailField())
- mType = EMAIL;
- else if (element->isNumberField())
- mType = NUMBER;
- else if (element->isTelephoneField())
- mType = TELEPHONE;
- else if (element->isURLField())
- mType = URL;
- else
- mType = NORMAL_TEXT_FIELD;
-}
-
-#if DUMP_NAV_CACHE
-
-#define DEBUG_PRINT_BOOL(field) \
- DUMP_NAV_LOGD("// bool " #field "=%s;\n", b->field ? "true" : "false")
-
-CachedInput* CachedInput::Debug::base() const {
- CachedInput* nav = (CachedInput*) ((char*) this - OFFSETOF(CachedInput, mDebug));
- return nav;
-}
-
-static void printWebCoreString(const char* label,
- const WTF::String& string) {
- char scratch[256];
- size_t index = snprintf(scratch, sizeof(scratch), label);
- const UChar* ch = string.characters();
- while (ch && *ch && index < sizeof(scratch)) {
- UChar c = *ch++;
- if (c < ' ' || c >= 0x7f) c = ' ';
- scratch[index++] = c;
- }
- DUMP_NAV_LOGD("%.*s\"\n", index, scratch);
-}
-
-void CachedInput::Debug::print() const
-{
- CachedInput* b = base();
- DEBUG_PRINT_BOOL(mAutoComplete);
- DUMP_NAV_LOGD("// void* mForm=%p;\n", b->mForm);
- printWebCoreString("// char* mName=\"", b->mName);
- DUMP_NAV_LOGD("// int mMaxLength=%d;\n", b->mMaxLength);
- DUMP_NAV_LOGD("// int mPaddingLeft=%d;\n", b->mPaddingLeft);
- DUMP_NAV_LOGD("// int mPaddingTop=%d;\n", b->mPaddingTop);
- DUMP_NAV_LOGD("// int mPaddingRight=%d;\n", b->mPaddingRight);
- DUMP_NAV_LOGD("// int mPaddingBottom=%d;\n", b->mPaddingBottom);
- DUMP_NAV_LOGD("// float mTextSize=%f;\n", b->mTextSize);
- DUMP_NAV_LOGD("// int mLineHeight=%d;\n", b->mLineHeight);
- DUMP_NAV_LOGD("// Type mType=%d;\n", b->mType);
- DEBUG_PRINT_BOOL(mIsRtlText);
- DEBUG_PRINT_BOOL(mIsTextField);
- DEBUG_PRINT_BOOL(mIsTextArea);
-}
-
-#endif
-
-}
diff --git a/Source/WebKit/android/nav/CachedInput.h b/Source/WebKit/android/nav/CachedInput.h
deleted file mode 100644
index 77ae57b..0000000
--- a/Source/WebKit/android/nav/CachedInput.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright 2009, 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 CachedInput_h
-#define CachedInput_h
-
-#include "CachedDebug.h"
-#include "HTMLInputElement.h"
-#include "PlatformString.h"
-
-namespace android {
-
-class CachedInput {
-public:
- CachedInput() {
- // Initiaized to 0 in its array, so nothing to do in the
- // constructor
- }
-
- enum Type {
- NONE = -1,
- NORMAL_TEXT_FIELD = 0,
- TEXT_AREA = 1,
- PASSWORD = 2,
- SEARCH = 3,
- EMAIL = 4,
- NUMBER = 5,
- TELEPHONE = 6,
- URL = 7
- };
-
- bool autoComplete() const { return mAutoComplete; }
- void* formPointer() const { return mForm; }
- void init();
- void setTypeFromElement(WebCore::HTMLInputElement*);
- Type getType() const { return mType; }
- bool isRtlText() const { return mIsRtlText; }
- bool isTextField() const { return mIsTextField; }
- bool isTextArea() const { return mIsTextArea; }
- int lineHeight() const { return mLineHeight; }
- int maxLength() const { return mMaxLength; };
- const WTF::String& name() const { return mName; }
- int paddingBottom() const { return mPaddingBottom; }
- int paddingLeft() const { return mPaddingLeft; }
- int paddingRight() const { return mPaddingRight; }
- int paddingTop() const { return mPaddingTop; }
- void setAutoComplete(bool autoComplete) { mAutoComplete = autoComplete; }
- void setFormPointer(void* form) { mForm = form; }
- void setIsRtlText(bool isRtlText) { mIsRtlText = isRtlText; }
- void setIsTextField(bool isTextField) { mIsTextField = isTextField; }
- void setIsTextArea(bool isTextArea) { mIsTextArea = isTextArea; }
- void setLineHeight(int height) { mLineHeight = height; }
- void setMaxLength(int maxLength) { mMaxLength = maxLength; }
- void setName(const WTF::String& name) { mName = name; }
- void setPaddingBottom(int bottom) { mPaddingBottom = bottom; }
- void setPaddingLeft(int left) { mPaddingLeft = left; }
- void setPaddingRight(int right) { mPaddingRight = right; }
- void setPaddingTop(int top) { mPaddingTop = top; }
- void setSpellcheck(bool spellcheck) { mSpellcheck = spellcheck; }
- void setTextSize(float textSize) { mTextSize = textSize; }
- bool spellcheck() const { return mSpellcheck; }
- float textSize() const { return mTextSize; }
-
-private:
-
- void* mForm;
- int mLineHeight;
- int mMaxLength;
- WTF::String mName;
- int mPaddingBottom;
- int mPaddingLeft;
- int mPaddingRight;
- int mPaddingTop;
- float mTextSize;
- Type mType;
- bool mAutoComplete : 1;
- bool mSpellcheck : 1;
- bool mIsRtlText : 1;
- bool mIsTextField : 1;
- bool mIsTextArea : 1;
-#if DUMP_NAV_CACHE
-public:
- class Debug {
-public:
- CachedInput* base() const;
- void print() const;
- } mDebug;
-#endif
-};
-
-}
-
-#endif
diff --git a/Source/WebKit/android/nav/CachedLayer.cpp b/Source/WebKit/android/nav/CachedLayer.cpp
deleted file mode 100644
index f6dfb88..0000000
--- a/Source/WebKit/android/nav/CachedLayer.cpp
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- * Copyright 2010, 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.
- */
-
-#include "CachedPrefix.h"
-
-#include "CachedLayer.h"
-#include "FloatRect.h"
-#include "LayerAndroid.h"
-
-namespace android {
-
-#if USE(ACCELERATED_COMPOSITING)
-
-IntRect CachedLayer::adjustBounds(const LayerAndroid* root,
- const IntRect& bounds) const
-{
- const LayerAndroid* aLayer = layer(root);
- if (!aLayer) {
- DBG_NAV_LOGD("no layer in root=%p uniqueId=%d", root, mUniqueId);
-#if DUMP_NAV_CACHE
- if (root)
- mDebug.printRootLayerAndroid(root);
-#endif
- return bounds;
- }
- FloatRect temp = bounds;
- // First, remove the original offset from the bounds.
- temp.move(-mOffset.x(), -mOffset.y());
-
- // Next, add in the new position of the layer (could be different due to a
- // fixed position layer).
- FloatPoint position = getGlobalPosition(aLayer);
- temp.move(position.x(), position.y());
-
- // Add in any layer translation.
- // FIXME: Should use bounds() and apply the entire transformation matrix.
- const FloatPoint& translation = aLayer->translation();
- temp.move(translation.x(), translation.y());
-
- SkRect clip;
- aLayer->bounds(&clip);
-
- // Do not try to traverse the parent chain if this is the root as the parent
- // will not be a LayerAndroid.
- if (aLayer != root) {
- LayerAndroid* parent = static_cast<LayerAndroid*>(aLayer->getParent());
- while (parent) {
- SkRect pClip;
- parent->bounds(&pClip);
-
- // Move our position into our parent's coordinate space.
- clip.offset(pClip.fLeft, pClip.fTop);
- // Clip our visible rectangle to the parent.
- clip.intersect(pClip);
-
- // Stop at the root.
- if (parent == root)
- break;
- parent = static_cast<LayerAndroid*>(parent->getParent());
- }
- }
-
- // Intersect the result with the visible clip.
- temp.intersect(clip);
-
- IntRect result = enclosingIntRect(temp);
-
- DBG_NAV_LOGV("root=%p aLayer=%p [%d]"
- " bounds=(%d,%d,w=%d,h=%d) trans=(%g,%g) pos=(%f,%f)"
- " offset=(%d,%d)"
- " result=(%d,%d,w=%d,h=%d)",
- root, aLayer, aLayer->uniqueId(),
- bounds.x(), bounds.y(), bounds.width(), bounds.height(),
- translation.x(), translation.y(), position.x(), position.y(),
- mOffset.x(), mOffset.y(),
- result.x(), result.y(), result.width(), result.height());
- return result;
-}
-
-FloatPoint CachedLayer::getGlobalPosition(const LayerAndroid* aLayer) const
-{
- SkPoint result = aLayer->getPosition();
- const Layer* parent = aLayer->getParent();
- while (parent) {
- result += parent->getPosition();
- DBG_NAV_LOGV("result=(%g,%g) parent=%p [%d]", result.fX, result.fY,
- parent, ((LayerAndroid*) parent)->uniqueId());
- parent = parent->getParent();
- }
- return result;
-}
-
-const LayerAndroid* CachedLayer::layer(const LayerAndroid* root) const
-{
- if (!root)
- return 0;
- return root->findById(mUniqueId);
-}
-
-// return bounds relative to the layer as recorded when walking the dom
-IntRect CachedLayer::localBounds(const LayerAndroid* root,
- const IntRect& bounds) const
-{
- IntRect temp = bounds;
- // Remove the original offset from the bounds.
- temp.move(-mOffset.x(), -mOffset.y());
-
-#if DEBUG_NAV_UI
- const LayerAndroid* aLayer = layer(root);
- DBG_NAV_LOGD("aLayer=%p [%d] bounds=(%d,%d,w=%d,h=%d) offset=(%d,%d)"
- " result=(%d,%d,w=%d,h=%d)",
- aLayer, aLayer ? aLayer->uniqueId() : 0,
- bounds.x(), bounds.y(), bounds.width(), bounds.height(),
- mOffset.x(), mOffset.y(),
- temp.x(), temp.y(), temp.width(), temp.height());
-#endif
-
- return temp;
-}
-
-SkPicture* CachedLayer::picture(const LayerAndroid* root) const
-{
- const LayerAndroid* aLayer = layer(root);
- if (!aLayer)
- return 0;
- DBG_NAV_LOGD("root=%p aLayer=%p [%d] picture=%p",
- root, aLayer, aLayer->uniqueId(), aLayer->picture());
- return aLayer->picture();
-}
-
-void CachedLayer::toLocal(const LayerAndroid* root, int* xPtr, int* yPtr) const
-{
- const LayerAndroid* aLayer = layer(root);
- if (!aLayer)
- return;
- DBG_NAV_LOGD("root=%p aLayer=%p [%d]", root, aLayer, aLayer->uniqueId());
- SkRect localBounds;
- aLayer->bounds(&localBounds);
- *xPtr -= localBounds.fLeft;
- *yPtr -= localBounds.fTop;
-}
-
-#if DUMP_NAV_CACHE
-
-CachedLayer* CachedLayer::Debug::base() const {
- return (CachedLayer*) ((char*) this - OFFSETOF(CachedLayer, mDebug));
-}
-
-void CachedLayer::Debug::print() const
-{
- CachedLayer* b = base();
- DUMP_NAV_LOGD(" // int mCachedNodeIndex=%d;\n", b->mCachedNodeIndex);
- DUMP_NAV_LOGD(" // int mOffset=(%d, %d);\n",
- b->mOffset.x(), b->mOffset.y());
- DUMP_NAV_LOGD(" // int mUniqueId=%p;\n", b->mUniqueId);
- DUMP_NAV_LOGD("%s\n", "");
-}
-
-#endif
-
-#if DUMP_NAV_CACHE
-
-int CachedLayer::Debug::spaces;
-
-void CachedLayer::Debug::printLayerAndroid(const LayerAndroid* layer)
-{
- ++spaces;
- SkRect bounds;
- layer->bounds(&bounds);
- DBG_NAV_LOGD("%.*s layer=%p [%d] (%g,%g,%g,%g)"
- " position=(%g,%g) translation=(%g,%g) anchor=(%g,%g)"
- " matrix=(%g,%g) childMatrix=(%g,%g) picture=%p clipped=%s"
- " scrollable=%s\n",
- spaces, " ", layer, layer->uniqueId(),
- bounds.fLeft, bounds.fTop, bounds.width(), bounds.height(),
- layer->getPosition().fX, layer->getPosition().fY,
- layer->translation().x(), layer->translation().y(),
- layer->getAnchorPoint().fX, layer->getAnchorPoint().fY,
- layer->getMatrix().getTranslateX(), layer->getMatrix().getTranslateY(),
- layer->getChildrenMatrix().getTranslateX(),
- layer->getChildrenMatrix().getTranslateY(),
- layer->picture(), layer->m_haveClip ? "true" : "false",
- layer->contentIsScrollable() ? "true" : "false");
- for (int i = 0; i < layer->countChildren(); i++)
- printLayerAndroid(layer->getChild(i));
- --spaces;
-}
-
-void CachedLayer::Debug::printRootLayerAndroid(const LayerAndroid* layer)
-{
- spaces = 0;
- printLayerAndroid(layer);
-}
-#endif
-
-#endif // USE(ACCELERATED_COMPOSITING)
-
-}
-
diff --git a/Source/WebKit/android/nav/CachedLayer.h b/Source/WebKit/android/nav/CachedLayer.h
deleted file mode 100644
index fa427d2..0000000
--- a/Source/WebKit/android/nav/CachedLayer.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright 2010, 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 CachedLayer_h
-#define CachedLayer_h
-
-#include "CachedDebug.h"
-#include "IntRect.h"
-
-class SkPicture;
-
-namespace WebCore {
- class FloatPoint;
- class LayerAndroid;
-}
-
-using namespace WebCore;
-
-namespace android {
-
-class CachedLayer {
-public:
-#if USE(ACCELERATED_COMPOSITING)
- bool operator<(const CachedLayer& l) const {
- return mCachedNodeIndex < l.mCachedNodeIndex;
- }
- // FIXME: adjustBounds should be renamed globalBounds or toGlobal
- IntRect adjustBounds(const LayerAndroid* root, const IntRect& bounds) const;
- int cachedNodeIndex() const { return mCachedNodeIndex; }
- FloatPoint getGlobalPosition(const LayerAndroid* ) const;
- const LayerAndroid* layer(const LayerAndroid* root) const;
- IntRect localBounds(const LayerAndroid* root, const IntRect& bounds) const;
- SkPicture* picture(const LayerAndroid* root) const;
- void toLocal(const LayerAndroid* root, int* xPtr, int* yPtr) const;
- void setCachedNodeIndex(int index) { mCachedNodeIndex = index; }
- // Set the global position of the layer. This is recorded by the nav cache
- // and corresponds to RenderLayer::absoluteBoundingBox() which is in
- // document coordinates. This can be different from the global position of
- // the layer if the layer is fixed positioned or scrollable.
- void setOffset(const IntPoint& offset) { mOffset = offset; }
- void setUniqueId(int uniqueId) { mUniqueId = uniqueId; }
- int uniqueId() const { return mUniqueId; }
-private:
- int mCachedNodeIndex;
- IntPoint mOffset;
- int mUniqueId;
-
-#if DUMP_NAV_CACHE
-public:
- class Debug {
-public:
- CachedLayer* base() const;
- void print() const;
- static void printLayerAndroid(const LayerAndroid* );
- static void printRootLayerAndroid(const LayerAndroid* );
- static int spaces;
- } mDebug;
-#endif
-#endif // USE(ACCELERATED_COMPOSITING)
-};
-
-}
-
-#endif
diff --git a/Source/WebKit/android/nav/CachedNode.cpp b/Source/WebKit/android/nav/CachedNode.cpp
deleted file mode 100644
index e500875..0000000
--- a/Source/WebKit/android/nav/CachedNode.cpp
+++ /dev/null
@@ -1,431 +0,0 @@
-/*
- * Copyright 2007, 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.
- */
-
-#include "CachedPrefix.h"
-#include "android_graphics.h"
-#include "CachedFrame.h"
-#include "CachedHistory.h"
-#include "Node.h"
-#include "PlatformString.h"
-
-#include "CachedNode.h"
-
-namespace android {
-
-WebCore::IntRect CachedNode::bounds(const CachedFrame* frame) const
-{
- return mIsInLayer ? frame->adjustBounds(this, mBounds) : mBounds;
-}
-
-void CachedNode::clearCursor(CachedFrame* parent)
-{
- if (isFrame()) {
- CachedFrame* child = const_cast<CachedFrame*>(parent->hasFrame(this));
- child->clearCursor();
- }
- mIsCursor = false;
-}
-
-bool CachedNode::Clip(const WebCore::IntRect& outer, WebCore::IntRect* inner,
- WTF::Vector<WebCore::IntRect>* rings)
-{
- if (outer.contains(*inner))
- return true;
-// DBG_NAV_LOGD("outer:{%d,%d,%d,%d} does not contain inner:{%d,%d,%d,%d}",
-// outer.x(), outer.y(), outer.width(), outer.height(),
-// inner->x(), inner->y(), inner->width(), inner->height());
- bool intersects = outer.intersects(*inner);
- size_t size = intersects ? rings->size() : 0;
- *inner = WebCore::IntRect(0, 0, 0, 0);
- if (intersects) {
- WebCore::IntRect * const start = rings->begin();
- WebCore::IntRect* ring = start + size - 1;
- do {
- ring->intersect(outer);
- if (ring->isEmpty()) {
- if ((size_t) (ring - start) != --size)
- *ring = start[size];
- } else
- inner->unite(*ring);
- } while (ring-- != start);
- }
- rings->shrink(size);
-// DBG_NAV_LOGD("size:%d", size);
- return size != 0;
-}
-
-bool CachedNode::clip(const WebCore::IntRect& bounds)
-{
- return Clip(bounds, &mBounds, &mCursorRing);
-}
-
-
-void CachedNode::cursorRings(const CachedFrame* frame,
- WTF::Vector<WebCore::IntRect>* rings) const
-{
- rings->clear();
- for (unsigned index = 0; index < mCursorRing.size(); index++)
- rings->append(ring(frame, index));
-}
-
-WebCore::IntRect CachedNode::cursorRingBounds(const CachedFrame* frame) const
-{
- int partMax = navableRects();
- WebCore::IntRect bounds;
- for (int partIndex = 0; partIndex < partMax; partIndex++)
- bounds.unite(mCursorRing[partIndex]);
- bounds.inflate(CURSOR_RING_HIT_TEST_RADIUS);
- return mIsInLayer ? frame->adjustBounds(this, bounds) : bounds;
-}
-
-#define OVERLAP 3
-
-void CachedNode::fixUpCursorRects(const CachedFrame* frame)
-{
- if (mFixedUpCursorRects)
- return;
- mFixedUpCursorRects = true;
- // if the hit-test rect doesn't intersect any other rect, use it
- if (mHitBounds != mBounds && mHitBounds.contains(mBounds) &&
- frame->checkRings(this, mHitBounds)) {
- DBG_NAV_LOGD("use mHitBounds (%d,%d,%d,%d)", mHitBounds.x(),
- mHitBounds.y(), mHitBounds.width(), mHitBounds.height());
- mUseHitBounds = true;
- return;
- }
- if (navableRects() <= 1)
- return;
- // if there is more than 1 rect, and the bounds doesn't intersect
- // any other cursor ring bounds, use it
- IntRect sloppyBounds = mBounds;
- sloppyBounds.inflate(2); // give it a couple of extra pixels
- if (frame->checkRings(this, sloppyBounds)) {
- DBG_NAV_LOGD("use mBounds (%d,%d,%d,%d)", mBounds.x(),
- mBounds.y(), mBounds.width(), mBounds.height());
- mUseBounds = true;
- return;
- }
-#if DEBUG_NAV_UI
- {
- WebCore::IntRect* boundsPtr = mCursorRing.begin() - 1;
- const WebCore::IntRect* const boundsEnd = mCursorRing.begin() + mCursorRing.size();
- while (++boundsPtr < boundsEnd)
- LOGD("%s %d:(%d, %d, %d, %d)\n", __FUNCTION__, boundsPtr - mCursorRing.begin(),
- boundsPtr->x(), boundsPtr->y(), boundsPtr->width(), boundsPtr->height());
- }
-#endif
- // q: need to know when rects are for drawing and hit-testing, but not mouse down calcs?
- bool again;
- do {
- again = false;
- size_t size = mCursorRing.size();
- WebCore::IntRect* unitBoundsPtr = mCursorRing.begin() - 1;
- const WebCore::IntRect* const unitBoundsEnd = mCursorRing.begin() + size;
- while (++unitBoundsPtr < unitBoundsEnd) {
- // any other unitBounds to the left or right of this one?
- int unitTop = unitBoundsPtr->y();
- int unitBottom = unitBoundsPtr->maxY();
- int unitLeft = unitBoundsPtr->x();
- int unitRight = unitBoundsPtr->maxX();
- WebCore::IntRect* testBoundsPtr = mCursorRing.begin() - 1;
- while (++testBoundsPtr < unitBoundsEnd) {
- if (unitBoundsPtr == testBoundsPtr)
- continue;
- int testTop = testBoundsPtr->y();
- int testBottom = testBoundsPtr->maxY();
- int testLeft = testBoundsPtr->x();
- int testRight = testBoundsPtr->maxX();
- int candidateTop = unitTop > testTop ? unitTop : testTop;
- int candidateBottom = unitBottom < testBottom ? unitBottom : testBottom;
- int candidateLeft = unitRight < testLeft ? unitRight : testRight;
- int candidateRight = unitRight > testLeft ? unitLeft : testLeft;
- bool leftRight = true;
- if (candidateTop + OVERLAP >= candidateBottom ||
- candidateLeft + OVERLAP >= candidateRight) {
- candidateTop = unitBottom < testTop ? unitBottom : testBottom;
- candidateBottom = unitBottom > testTop ? unitTop : testTop;
- candidateLeft = unitLeft > testLeft ? unitLeft : testLeft;
- candidateRight = unitRight < testRight ? unitRight : testRight;
- if (candidateTop + OVERLAP >= candidateBottom ||
- candidateLeft + OVERLAP >= candidateRight)
- continue;
- leftRight = false;
- }
- // construct candidate to add
- WebCore::IntRect candidate = WebCore::IntRect(candidateLeft, candidateTop,
- candidateRight - candidateLeft, candidateBottom - candidateTop);
- // does a different unit bounds intersect the candidate? if so, don't add
- WebCore::IntRect* checkBoundsPtr = mCursorRing.begin() - 1;
- while (++checkBoundsPtr < unitBoundsEnd) {
- if (checkBoundsPtr->intersects(candidate) == false)
- continue;
- if (leftRight) {
- if (candidateTop >= checkBoundsPtr->y() &&
- candidateBottom > checkBoundsPtr->maxY())
- candidateTop = checkBoundsPtr->maxY();
- else if (candidateTop < checkBoundsPtr->y() &&
- candidateBottom <= checkBoundsPtr->maxY())
- candidateBottom = checkBoundsPtr->y();
- else
- goto nextCheck;
- } else {
- if (candidateLeft >= checkBoundsPtr->x() &&
- candidateRight > checkBoundsPtr->maxX())
- candidateLeft = checkBoundsPtr->maxX();
- else if (candidateLeft < checkBoundsPtr->x() &&
- candidateRight <= checkBoundsPtr->maxX())
- candidateRight = checkBoundsPtr->x();
- else
- goto nextCheck;
- }
- }
- candidate = WebCore::IntRect(candidateLeft, candidateTop,
- candidateRight - candidateLeft, candidateBottom - candidateTop);
- ASSERT(candidate.isEmpty() == false);
-#if DEBUG_NAV_UI
- LOGD("%s %d:(%d, %d, %d, %d)\n", __FUNCTION__, mCursorRing.size(),
- candidate.x(), candidate.y(), candidate.width(), candidate.height());
-#endif
- mCursorRing.append(candidate);
- again = true;
- goto tryAgain;
- nextCheck:
- continue;
- }
- }
-tryAgain:
- ;
- } while (again);
-}
-
-
-void CachedNode::hideCursor(CachedFrame* parent)
-{
- if (isFrame()) {
- CachedFrame* child = const_cast<CachedFrame*>(parent->hasFrame(this));
- child->hideCursor();
- }
- mIsHidden = true;
-}
-
-WebCore::IntRect CachedNode::hitBounds(const CachedFrame* frame) const
-{
- return mIsInLayer ? frame->adjustBounds(this, mHitBounds) : mHitBounds;
-}
-
-void CachedNode::init(WebCore::Node* node)
-{
- bzero(this, sizeof(CachedNode));
- mExport = WTF::String();
- mNode = node;
- mParentIndex = mDataIndex = -1;
- mType = android::NORMAL_CACHEDNODETYPE;
-}
-
-bool CachedNode::isTextField(const CachedFrame* frame) const
-{
- const CachedInput* input = frame->textInput(this);
- return input ? input->isTextField() : false;
-}
-
-void CachedNode::localCursorRings(const CachedFrame* frame,
- WTF::Vector<WebCore::IntRect>* rings) const
-{
- rings->clear();
- for (unsigned index = 0; index < mCursorRing.size(); index++)
- rings->append(localRing(frame, index));
-}
-
-WebCore::IntRect CachedNode::localBounds(const CachedFrame* frame) const
-{
- return mIsInLayer ? frame->localBounds(this, mBounds) : mBounds;
-}
-
-WebCore::IntRect CachedNode::localHitBounds(const CachedFrame* frame) const
-{
- return mIsInLayer ? frame->localBounds(this, mHitBounds) : mHitBounds;
-}
-
-WebCore::IntRect CachedNode::localRing(const CachedFrame* frame,
- size_t part) const
-{
- const WebCore::IntRect& rect = mCursorRing.at(part);
- return mIsInLayer ? frame->localBounds(this, rect) : rect;
-}
-
-void CachedNode::move(int x, int y)
-{
- mBounds.move(x, y);
- // mHitTestBounds will be moved by caller
- WebCore::IntRect* first = mCursorRing.begin();
- WebCore::IntRect* last = first + mCursorRing.size();
- --first;
- while (++first != last)
- first->move(x, y);
-}
-
-bool CachedNode::partRectsContains(const CachedNode* other) const
-{
- int outerIndex = 0;
- int outerMax = navableRects();
- int innerMax = other->navableRects();
- do {
- const WebCore::IntRect& outerBounds = mCursorRing[outerIndex];
- int innerIndex = 0;
- do {
- const WebCore::IntRect& innerBounds = other->mCursorRing[innerIndex];
- if (innerBounds.contains(outerBounds))
- return true;
- } while (++innerIndex < innerMax);
- } while (++outerIndex < outerMax);
- return false;
-}
-
-WebCore::IntRect CachedNode::ring(const CachedFrame* frame, size_t part) const
-{
- const WebCore::IntRect& rect = mCursorRing.at(part);
- return mIsInLayer ? frame->adjustBounds(this, rect) : rect;
-}
-
-#if DUMP_NAV_CACHE
-
-#define DEBUG_PRINT_BOOL(field) \
- DUMP_NAV_LOGD("// bool " #field "=%s;\n", b->field ? "true" : "false")
-
-#define DEBUG_PRINT_RECT(field) \
- { const WebCore::IntRect& r = b->field; \
- DUMP_NAV_LOGD("// IntRect " #field "={%d, %d, %d, %d};\n", \
- r.x(), r.y(), r.width(), r.height()); }
-
-CachedNode* CachedNode::Debug::base() const {
- CachedNode* nav = (CachedNode*) ((char*) this - OFFSETOF(CachedNode, mDebug));
- return nav;
-}
-
-const char* CachedNode::Debug::condition(Condition t) const
-{
- switch (t) {
- case NOT_REJECTED: return "NOT_REJECTED"; break;
- case BUTTED_UP: return "BUTTED_UP"; break;
- case CENTER_FURTHER: return "CENTER_FURTHER"; break;
- case CLOSER: return "CLOSER"; break;
- case CLOSER_IN_CURSOR: return "CLOSER_IN_CURSOR"; break;
- case CLOSER_OVERLAP: return "CLOSER_OVERLAP"; break;
- case CLOSER_TOP: return "CLOSER_TOP"; break;
- case NAVABLE: return "NAVABLE"; break;
- case FURTHER: return "FURTHER"; break;
- case IN_UMBRA: return "IN_UMBRA"; break;
- case IN_WORKING: return "IN_WORKING"; break;
- case LEFTMOST: return "LEFTMOST"; break;
- case OVERLAP_OR_EDGE_FURTHER: return "OVERLAP_OR_EDGE_FURTHER"; break;
- case PREFERRED: return "PREFERRED"; break;
- case ANCHOR_IN_ANCHOR: return "ANCHOR_IN_ANCHOR"; break;
- case BEST_DIRECTION: return "BEST_DIRECTION"; break;
- case CHILD: return "CHILD"; break;
- case DISABLED: return "DISABLED"; break;
- case HIGHER_TAB_INDEX: return "HIGHER_TAB_INDEX"; break;
- case IN_CURSOR: return "IN_CURSOR"; break;
- case IN_CURSOR_CHILDREN: return "IN_CURSOR_CHILDREN"; break;
- case NOT_ENCLOSING_CURSOR: return "NOT_ENCLOSING_CURSOR"; break;
- case NOT_CURSOR_NODE: return "NOT_CURSOR_NODE"; break;
- case OUTSIDE_OF_BEST: return "OUTSIDE_OF_BEST"; break;
- case OUTSIDE_OF_ORIGINAL: return "OUTSIDE_OF_ORIGINAL"; break;
- default: return "???";
- }
-}
-
-const char* CachedNode::Debug::type(android::CachedNodeType t) const
-{
- switch (t) {
- case NORMAL_CACHEDNODETYPE: return "NORMAL"; break;
- case ADDRESS_CACHEDNODETYPE: return "ADDRESS"; break;
- case EMAIL_CACHEDNODETYPE: return "EMAIL"; break;
- case PHONE_CACHEDNODETYPE: return "PHONE"; break;
- case ANCHOR_CACHEDNODETYPE: return "ANCHOR"; break;
- case AREA_CACHEDNODETYPE: return "AREA"; break;
- case FRAME_CACHEDNODETYPE: return "FRAME"; break;
- case PLUGIN_CACHEDNODETYPE: return "PLUGIN"; break;
- case TEXT_INPUT_CACHEDNODETYPE: return "INPUT"; break;
- case SELECT_CACHEDNODETYPE: return "SELECT"; break;
- case CONTENT_EDITABLE_CACHEDNODETYPE: return "CONTENT_EDITABLE"; break;
- default: return "???";
- }
-}
-
-void CachedNode::Debug::print() const
-{
- CachedNode* b = base();
- char scratch[256];
- size_t index = snprintf(scratch, sizeof(scratch), "// char* mExport=\"");
- const UChar* ch = b->mExport.characters();
- while (ch && *ch && index < sizeof(scratch)) {
- UChar c = *ch++;
- if (c < ' ' || c >= 0x7f) c = ' ';
- scratch[index++] = c;
- }
- DUMP_NAV_LOGD("%.*s\"\n", index, scratch);
- DEBUG_PRINT_RECT(mBounds);
- DEBUG_PRINT_RECT(mHitBounds);
- DEBUG_PRINT_RECT(mOriginalAbsoluteBounds);
- const WTF::Vector<WebCore::IntRect>* rects = &b->mCursorRing;
- size_t size = rects->size();
- DUMP_NAV_LOGD("// IntRect cursorRings={ // size=%d\n", size);
- for (size_t i = 0; i < size; i++) {
- const WebCore::IntRect& rect = (*rects)[i];
- DUMP_NAV_LOGD(" // {%d, %d, %d, %d}, // %d\n", rect.x(), rect.y(),
- rect.width(), rect.height(), i);
- }
- DUMP_NAV_LOGD("// };\n");
- DUMP_NAV_LOGD("// void* mNode=%p; // (%d) \n", b->mNode, mNodeIndex);
- DUMP_NAV_LOGD("// void* mParentGroup=%p; // (%d) \n", b->mParentGroup, mParentGroupIndex);
- DUMP_NAV_LOGD("// int mDataIndex=%d;\n", b->mDataIndex);
- DUMP_NAV_LOGD("// int mIndex=%d;\n", b->mIndex);
- DUMP_NAV_LOGD("// int navableRects()=%d;\n", b->navableRects());
- DUMP_NAV_LOGD("// int mParentIndex=%d;\n", b->mParentIndex);
- DUMP_NAV_LOGD("// int mTabIndex=%d;\n", b->mTabIndex);
- DUMP_NAV_LOGD("// int mColorIndex=%d;\n", b->mColorIndex);
- DUMP_NAV_LOGD("// Condition mCondition=%s;\n", condition(b->mCondition));
- DUMP_NAV_LOGD("// Type mType=%s;\n", type(b->mType));
- DEBUG_PRINT_BOOL(mClippedOut);
- DEBUG_PRINT_BOOL(mDisabled);
- DEBUG_PRINT_BOOL(mFixedUpCursorRects);
- DEBUG_PRINT_BOOL(mHasCursorRing);
- DEBUG_PRINT_BOOL(mHasMouseOver);
- DEBUG_PRINT_BOOL(mIsCursor);
- DEBUG_PRINT_BOOL(mIsFocus);
- DEBUG_PRINT_BOOL(mIsHidden);
- DEBUG_PRINT_BOOL(mIsInLayer);
- DEBUG_PRINT_BOOL(mIsParentAnchor);
- DEBUG_PRINT_BOOL(mIsTransparent);
- DEBUG_PRINT_BOOL(mIsUnclipped);
- DEBUG_PRINT_BOOL(mLast);
- DEBUG_PRINT_BOOL(mUseBounds);
- DEBUG_PRINT_BOOL(mUseHitBounds);
- DEBUG_PRINT_BOOL(mSingleImage);
-}
-
-#endif
-
-}
diff --git a/Source/WebKit/android/nav/CachedNode.h b/Source/WebKit/android/nav/CachedNode.h
deleted file mode 100644
index 321b7fd..0000000
--- a/Source/WebKit/android/nav/CachedNode.h
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * Copyright 2007, 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 CachedNode_h
-#define CachedNode_h
-
-#include "CachedDebug.h"
-#include "CachedNodeType.h"
-#include "IntRect.h"
-#include "PlatformString.h"
-
-#include <wtf/Vector.h>
-#include <wtf/text/AtomicString.h>
-
-class SkPicture;
-
-namespace WebCore {
- class Node;
-}
-
-namespace android {
-
-class CachedFrame;
-class CachedRoot;
-
-class CachedNode {
-public:
-// Nodes are rejected because either they are spacially not the best (first set)
-// or because they have the wrong DOM attribute (in focus, a focused child, etc)
-// findClosest() gives only spacially rejected nodes a second chance
- enum Condition { // if bigger than 32, increase bitfield size below
- // rejections that get a second chance
- NOT_REJECTED = 0,
- SECOND_CHANCE_START = NOT_REJECTED, // must be first in list
- BUTTED_UP,
- CENTER_FURTHER,
- CLOSER,
- CLOSER_IN_CURSOR,
- CLOSER_OVERLAP,
- CLOSER_TOP,
- NAVABLE,
- FURTHER,
- IN_UMBRA,
- IN_WORKING,
- LEFTMOST,
- NOT_ENCLOSING_CURSOR,
- OVERLAP_OR_EDGE_FURTHER,
- PREFERRED, // better overlap measure
- SECOND_CHANCE_END = PREFERRED, // must be last in list
- // rejections that don't get a second chance
- ANCHOR_IN_ANCHOR,
- BEST_DIRECTION, // can be reached by another direction
- CHILD,
- DISABLED,
- HIGHER_TAB_INDEX,
- IN_CURSOR,
- IN_CURSOR_CHILDREN,
- NOT_CURSOR_NODE,
- OUTSIDE_OF_BEST, // containership
- OUTSIDE_OF_ORIGINAL, // containership
- UNDER_LAYER,
- CONDITION_SIZE // FIXME: test that CONDITION_SIZE fits in mCondition
- };
- CachedNode() {
- // The node is initiaized to 0 in its array, so nothing to do in the
- // constructor
- }
-
- WebCore::IntRect bounds(const CachedFrame* ) const;
- int childFrameIndex() const { return isFrame() ? mDataIndex : -1; }
- void clearCondition() const { mCondition = NOT_REJECTED; }
- void clearCursor(CachedFrame* );
- static bool Clip(const WebCore::IntRect& outer, WebCore::IntRect* inner,
- WTF::Vector<WebCore::IntRect>* rings);
- bool clip(const WebCore::IntRect& );
- bool clippedOut() { return mClippedOut; }
- int colorIndex() const { return mColorIndex; }
- WebCore::IntRect cursorRingBounds(const CachedFrame* ) const;
- void cursorRings(const CachedFrame* , WTF::Vector<WebCore::IntRect>* ) const;
- bool disabled() const { return mDisabled; }
- const CachedNode* document() const { return &this[-mIndex]; }
- void fixUpCursorRects(const CachedFrame* frame);
- const WTF::String& getExport() const { return mExport; }
- bool hasCursorRing() const { return mHasCursorRing; }
- bool hasMouseOver() const { return mHasMouseOver; }
- void hideCursor(CachedFrame* );
- WebCore::IntRect hitBounds(const CachedFrame* ) const;
- int index() const { return mIndex; }
- void init(WebCore::Node* node);
- bool isAnchor() const { return mType == ANCHOR_CACHEDNODETYPE; }
- bool isContentEditable() const { return mType == CONTENT_EDITABLE_CACHEDNODETYPE; }
- bool isCursor() const { return mIsCursor; }
- bool isArea() const { return mType == AREA_CACHEDNODETYPE; }
- bool isFocus() const { return mIsFocus; }
- bool isFrame() const { return mType == FRAME_CACHEDNODETYPE; }
- bool isHidden() const { return mIsHidden; }
- bool isInLayer() const { return mIsInLayer; }
- bool isNavable(const CachedFrame* frame, const WebCore::IntRect& clip) const {
- return clip.intersects(bounds(frame));
- }
- bool isPlugin() const { return mType == PLUGIN_CACHEDNODETYPE; }
- bool isSelect() const { return mType == SELECT_CACHEDNODETYPE; }
- bool isSyntheticLink() const {
- return mType >= ADDRESS_CACHEDNODETYPE && mType <= PHONE_CACHEDNODETYPE;
- }
- bool isTextField(const CachedFrame*) const;
- bool isTextInput() const { return mType == TEXT_INPUT_CACHEDNODETYPE; }
- bool isTransparent() const { return mIsTransparent; }
- bool isUnclipped() const { return mIsUnclipped; }
- // localXXX functions are used only for drawing cursor rings
- WebCore::IntRect localBounds(const CachedFrame* ) const;
- void localCursorRings(const CachedFrame* ,
- WTF::Vector<WebCore::IntRect>* ) const;
- WebCore::IntRect localHitBounds(const CachedFrame* ) const;
- WebCore::IntRect localRing(const CachedFrame* , size_t part) const;
- void move(int x, int y);
- int navableRects() const { return mCursorRing.size(); }
- void* nodePointer() const { return mNode; }
- bool noSecondChance() const { return mCondition > SECOND_CHANCE_END; }
- const WebCore::IntRect& originalAbsoluteBounds() const {
- return mOriginalAbsoluteBounds; }
- const CachedNode* parent() const { return document() + mParentIndex; }
- void* parentGroup() const { return mParentGroup; }
- int parentIndex() const { return mParentIndex; }
- bool partRectsContains(const CachedNode* other) const;
- const WebCore::IntRect& rawBounds() const { return mBounds; }
- void reset();
- WebCore::IntRect ring(const CachedFrame* , size_t part) const;
- const WTF::Vector<WebCore::IntRect>& rings() const { return mCursorRing; }
- void setBounds(const WebCore::IntRect& bounds) { mBounds = bounds; }
- void setClippedOut(bool clipped) { mClippedOut = clipped; }
- void setColorIndex(int index) { mColorIndex = index; }
- void setCondition(Condition condition) const { mCondition = condition; }
- void setDataIndex(int index) { mDataIndex = index; }
- void setDisabled(bool disabled) { mDisabled = disabled; }
- void setExport(const WTF::String& exported) { mExport = exported; }
- void setHasCursorRing(bool hasRing) { mHasCursorRing = hasRing; }
- void setHasMouseOver(bool hasMouseOver) { mHasMouseOver = hasMouseOver; }
- void setHitBounds(const WebCore::IntRect& bounds) { mHitBounds = bounds; }
- void setOriginalAbsoluteBounds(const WebCore::IntRect& bounds) {
- mOriginalAbsoluteBounds = bounds; }
- void setIndex(int index) { mIndex = index; }
- void setIsCursor(bool isCursor) { mIsCursor = isCursor; }
- void setIsFocus(bool isFocus) { mIsFocus = isFocus; }
- void setIsInLayer(bool isInLayer) { mIsInLayer = isInLayer; }
- void setIsParentAnchor(bool isAnchor) { mIsParentAnchor = isAnchor; }
- void setIsTransparent(bool isTransparent) { mIsTransparent = isTransparent; }
- void setIsUnclipped(bool unclipped) { mIsUnclipped = unclipped; }
- void setLast() { mLast = true; }
- void setParentGroup(void* group) { mParentGroup = group; }
- void setParentIndex(int parent) { mParentIndex = parent; }
- void setSingleImage(bool single) { mSingleImage = single; }
- void setTabIndex(int index) { mTabIndex = index; }
- void setType(CachedNodeType type) { mType = type; }
- void show() { mIsHidden = false; }
- bool singleImage() const { return mSingleImage; }
- int tabIndex() const { return mTabIndex; }
- int textInputIndex() const { return isTextInput() ? mDataIndex : -1; }
- const CachedNode* traverseNextNode() const { return mLast ? NULL : &this[1]; }
- bool useBounds() const { return mUseBounds; }
- bool useHitBounds() const { return mUseHitBounds; }
- bool wantsKeyEvents() const { return isTextInput() || isPlugin()
- || isContentEditable() || isFrame(); }
-private:
- friend class CacheBuilder;
- WTF::String mExport;
- WebCore::IntRect mBounds;
- WebCore::IntRect mHitBounds;
- WebCore::IntRect mOriginalAbsoluteBounds;
- WTF::Vector<WebCore::IntRect> mCursorRing;
- void* mNode; // WebCore::Node*, only used to match pointers
- void* mParentGroup; // WebCore::Node*, only used to match pointers
- int mDataIndex; // child frame if a frame; input data index; or -1
- int mIndex; // index of itself, to find first in array (document)
- int mParentIndex;
- int mTabIndex;
- int mColorIndex; // index to ring color and other stylable properties
- mutable Condition mCondition : 5; // why the node was not chosen on the first pass
- CachedNodeType mType : 4;
- bool mClippedOut : 1;
- bool mDisabled : 1;
- bool mFixedUpCursorRects : 1;
- bool mHasCursorRing : 1;
- bool mHasMouseOver : 1;
- bool mIsCursor : 1;
- bool mIsFocus : 1;
- bool mIsHidden : 1;
- bool mIsInLayer : 1;
- bool mIsParentAnchor : 1;
- bool mIsTransparent : 1;
- bool mIsUnclipped : 1;
- bool mLast : 1; // true if this is the last node in a group
- bool mSingleImage : 1;
- bool mUseBounds : 1;
- bool mUseHitBounds : 1;
-#ifdef BROWSER_DEBUG
-public:
- WebCore::Node* webCoreNode() const { return (WebCore::Node*) mNode; }
- bool mDisplayMeasure;
- mutable bool mInCompare;
- int mSideDistance;
- int mSecondSide;
-#endif
-#if DEBUG_NAV_UI || DUMP_NAV_CACHE
-public:
- class Debug {
-public:
- CachedNode* base() const;
- const char* condition(Condition t) const;
- void print() const;
- const char* type(CachedNodeType t) const;
-#if DUMP_NAV_CACHE
- int mNodeIndex;
- int mParentGroupIndex;
-#endif
- } mDebug;
- friend class CachedNode::Debug;
-#endif
-};
-
-}
-
-#endif
diff --git a/Source/WebKit/android/nav/CachedNodeType.h b/Source/WebKit/android/nav/CachedNodeType.h
deleted file mode 100644
index f922946..0000000
--- a/Source/WebKit/android/nav/CachedNodeType.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright 2007, 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 CachedNodeType_h
-#define CachedNodeType_h
-
-namespace android {
-
-enum CachedNodeType {
- NORMAL_CACHEDNODETYPE,
- ADDRESS_CACHEDNODETYPE,
- EMAIL_CACHEDNODETYPE,
- PHONE_CACHEDNODETYPE,
- ANCHOR_CACHEDNODETYPE,
- AREA_CACHEDNODETYPE,
- FRAME_CACHEDNODETYPE,
- PLUGIN_CACHEDNODETYPE,
- TEXT_INPUT_CACHEDNODETYPE,
- SELECT_CACHEDNODETYPE,
- CONTENT_EDITABLE_CACHEDNODETYPE
-};
-
-enum CachedNodeBits {
- NORMAL_CACHEDNODE_BITS = 0,
- ADDRESS_CACHEDNODE_BIT = 1 << (ADDRESS_CACHEDNODETYPE - 1),
- EMAIL_CACHEDNODE_BIT = 1 << (EMAIL_CACHEDNODETYPE - 1),
- PHONE_CACHEDNODE_BIT = 1 << (PHONE_CACHEDNODETYPE - 1),
- ALL_CACHEDNODE_BITS = ADDRESS_CACHEDNODE_BIT | EMAIL_CACHEDNODE_BIT
- | PHONE_CACHEDNODE_BIT
-};
-
-}
-
-#endif
diff --git a/Source/WebKit/android/nav/CachedPrefix.h b/Source/WebKit/android/nav/CachedPrefix.h
deleted file mode 100644
index 576aa4a..0000000
--- a/Source/WebKit/android/nav/CachedPrefix.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 2007, 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 CachedPrefix_h
-#define CachedPrefix_h
-
-#ifndef LOG_TAG
-#define LOG_TAG "navcache"
-#endif
-
-#include "config.h"
-#include "CachedDebug.h"
-
-#ifndef _LIBS_CUTILS_LOG_H
- #ifdef LOG
- #undef LOG
- #endif
-
- #include <utils/Log.h>
-#endif
-
-#define OFFSETOF(type, field) ((char*)&(((type*)1)->field) - (char*)1) // avoids gnu warning
-
-#ifndef BZERO_DEFINED
-#define BZERO_DEFINED
-// http://www.opengroup.org/onlinepubs/000095399/functions/bzero.html
-// For maximum portability, it is recommended to replace the function call to bzero() as follows:
-#define bzero(b,len) (memset((b), '\0', (len)), (void) 0)
-#endif
-
-#endif
diff --git a/Source/WebKit/android/nav/CachedRoot.cpp b/Source/WebKit/android/nav/CachedRoot.cpp
deleted file mode 100644
index 2371c4f..0000000
--- a/Source/WebKit/android/nav/CachedRoot.cpp
+++ /dev/null
@@ -1,1815 +0,0 @@
-/*
- * Copyright 2007, 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.
- */
-
-#include "CachedPrefix.h"
-#include "android_graphics.h"
-#include "CachedHistory.h"
-#include "CachedInput.h"
-#include "CachedLayer.h"
-#include "CachedNode.h"
-#include "FindCanvas.h"
-#include "FloatRect.h"
-#include "LayerAndroid.h"
-#include "ParseCanvas.h"
-#include "SkBitmap.h"
-#include "SkBounder.h"
-#include "SkPixelRef.h"
-#include "SkRegion.h"
-
-#include "CachedRoot.h"
-
-#if DEBUG_NAV_UI
-#include "wtf/text/CString.h"
-#endif
-
-#define DONT_CENTER_IF_ALREADY_VISIBLE
-
-using std::min;
-using std::max;
-
-#ifdef DUMP_NAV_CACHE_USING_PRINTF
- extern android::Mutex gWriteLogMutex;
-#endif
-
-namespace android {
-
-class CommonCheck : public SkBounder {
-public:
- enum Type {
- kNo_Type,
- kDrawBitmap_Type,
- kDrawGlyph_Type,
- kDrawPaint_Type,
- kDrawPath_Type,
- kDrawPicture_Type,
- kDrawPoints_Type,
- kDrawPosText_Type,
- kDrawPosTextH_Type,
- kDrawRect_Type,
- kDrawSprite_Type,
- kDrawText_Type,
- kDrawTextOnPath_Type,
- kPopLayer_Type,
- kPushLayer_Type,
- kPushSave_Type
- };
-
- static bool isTextType(Type t) {
- return t == kDrawPosTextH_Type || t == kDrawText_Type;
- }
-
- CommonCheck() : mType(kNo_Type), mAllOpaque(true), mIsOpaque(true) {
- setEmpty();
- }
-
- bool doRect(Type type) {
- mType = type;
- return doIRect(mUnion);
- }
-
- bool isEmpty() { return mUnion.isEmpty(); }
-
- bool joinGlyphs(const SkIRect& rect) {
- bool isGlyph = mType == kDrawGlyph_Type;
- if (isGlyph)
- mUnion.join(rect);
- return isGlyph;
- }
-
- void setAllOpaque(bool opaque) { mAllOpaque = opaque; }
- void setEmpty() { mUnion.setEmpty(); }
- void setIsOpaque(bool opaque) { mIsOpaque = opaque; }
- void setType(Type type) { mType = type; }
-
- Type mType;
- SkIRect mUnion;
- bool mAllOpaque;
- bool mIsOpaque;
-};
-
-#if DEBUG_NAV_UI
- static const char* TypeNames[] = {
- "kNo_Type",
- "kDrawBitmap_Type",
- "kDrawGlyph_Type",
- "kDrawPaint_Type",
- "kDrawPath_Type",
- "kDrawPicture_Type",
- "kDrawPoints_Type",
- "kDrawPosText_Type",
- "kDrawPosTextH_Type",
- "kDrawRect_Type",
- "kDrawSprite_Type",
- "kDrawText_Type",
- "kDrawTextOnPath_Type",
- "kPopLayer_Type",
- "kPushLayer_Type",
- "kPushSave_Type"
- };
-#endif
-
-#define kMargin 16
-#define kSlop 2
-
-class BoundsCanvas : public ParseCanvas {
-public:
-
- BoundsCanvas(CommonCheck* bounder) : mBounder(*bounder) {
- mTransparentLayer = 0;
- setBounder(bounder);
- }
-
- virtual void drawPaint(const SkPaint& paint) {
- mBounder.setType(CommonCheck::kDrawPaint_Type);
- INHERITED::drawPaint(paint);
- }
-
- virtual void drawPoints(PointMode mode, size_t count, const SkPoint pts[],
- const SkPaint& paint) {
- mBounder.setType(CommonCheck::kDrawPoints_Type);
- INHERITED::drawPoints(mode, count, pts, paint);
- }
-
- virtual void drawRect(const SkRect& rect, const SkPaint& paint) {
- mBounder.setType(CommonCheck::kDrawRect_Type);
- INHERITED::drawRect(rect, paint);
- }
-
- virtual void drawPath(const SkPath& path, const SkPaint& paint) {
- mBounder.setType(CommonCheck::kDrawPath_Type);
- INHERITED::drawPath(path, paint);
- }
-
- virtual void commonDrawBitmap(const SkBitmap& bitmap, const SkIRect* rect,
- const SkMatrix& matrix, const SkPaint& paint) {
- mBounder.setType(CommonCheck::kDrawBitmap_Type);
- mBounder.setIsOpaque(bitmap.isOpaque());
- INHERITED::commonDrawBitmap(bitmap, rect, matrix, paint);
- }
-
- virtual void drawSprite(const SkBitmap& bitmap, int left, int top,
- const SkPaint* paint) {
- mBounder.setType(CommonCheck::kDrawSprite_Type);
- mBounder.setIsOpaque(bitmap.isOpaque() &&
- (!paint || paint->getAlpha() == 255));
- INHERITED::drawSprite(bitmap, left, top, paint);
- }
-
- virtual void drawText(const void* text, size_t byteLength, SkScalar x,
- SkScalar y, const SkPaint& paint) {
- mBounder.setEmpty();
- mBounder.setType(CommonCheck::kDrawGlyph_Type);
- INHERITED::drawText(text, byteLength, x, y, paint);
- mBounder.doRect(CommonCheck::kDrawText_Type);
- }
-
- virtual void drawPosText(const void* text, size_t byteLength,
- const SkPoint pos[], const SkPaint& paint) {
- mBounder.setEmpty();
- mBounder.setType(CommonCheck::kDrawGlyph_Type);
- INHERITED::drawPosText(text, byteLength, pos, paint);
- if (!mBounder.isEmpty())
- mBounder.doRect(CommonCheck::kDrawPosText_Type);
- }
-
- virtual void drawPosTextH(const void* text, size_t byteLength,
- const SkScalar xpos[], SkScalar constY,
- const SkPaint& paint) {
- mBounder.setEmpty();
- mBounder.setType(CommonCheck::kDrawGlyph_Type);
- INHERITED::drawPosTextH(text, byteLength, xpos, constY, paint);
- if (mBounder.mUnion.isEmpty()) {
- DBG_NAV_LOGD("empty constY=%g", SkScalarToFloat(constY));
- return;
- }
- SkPaint::FontMetrics metrics;
- paint.getFontMetrics(&metrics);
- SkPoint upDown[2] = { {xpos[0], constY + metrics.fAscent},
- {xpos[0], constY + metrics.fDescent} };
- const SkMatrix& matrix = getTotalMatrix();
- matrix.mapPoints(upDown, 2);
- if (upDown[0].fX == upDown[1].fX) {
- mBounder.mUnion.fTop = SkScalarFloor(upDown[0].fY);
- mBounder.mUnion.fBottom = SkScalarFloor(upDown[1].fY);
- }
- mBounder.doRect(CommonCheck::kDrawPosTextH_Type);
- }
-
- virtual void drawTextOnPath(const void* text, size_t byteLength,
- const SkPath& path, const SkMatrix* matrix,
- const SkPaint& paint) {
- mBounder.setEmpty();
- mBounder.setType(CommonCheck::kDrawGlyph_Type);
- INHERITED::drawTextOnPath(text, byteLength, path, matrix, paint);
- mBounder.doRect(CommonCheck::kDrawTextOnPath_Type);
- }
-
- virtual void drawPicture(SkPicture& picture) {
- mBounder.setType(CommonCheck::kDrawPicture_Type);
- INHERITED::drawPicture(picture);
- }
-
- virtual int saveLayer(const SkRect* bounds, const SkPaint* paint,
- SaveFlags flags) {
- int depth = INHERITED::saveLayer(bounds, paint, flags);
- if (mTransparentLayer == 0 && paint && paint->getAlpha() < 255) {
- mTransparentLayer = depth;
- mBounder.setAllOpaque(false);
- }
- return depth;
- }
-
- virtual void restore() {
- mBounder.setType(CommonCheck::kDrawSprite_Type); // for layer draws
- int depth = getSaveCount();
- if (depth == mTransparentLayer) {
- mTransparentLayer = 0;
- mBounder.setAllOpaque(true);
- }
- INHERITED::restore();
- }
-
- int mTransparentLayer;
- CommonCheck& mBounder;
-private:
- typedef ParseCanvas INHERITED;
-};
-
-/*
-LeftCheck examines the text in a picture, within a viewable rectangle,
-and returns via left() the position of the left edge of the paragraph.
-It first looks at the left edge of the test point, then looks above and below
-it for more lines of text to determine the div's left edge.
-*/
-class LeftCheck : public CommonCheck {
-public:
- LeftCheck(int x, int y) : mX(x), mY(y), mHitLeft(INT_MAX),
- mMostLeft(INT_MAX) {
- mHit.set(x - (HIT_SLOP << 1), y - HIT_SLOP, x, y + HIT_SLOP);
- mPartial.setEmpty();
- mBounds.setEmpty();
- mPartialType = kNo_Type;
- }
-
- int left() {
- if (isTextType(mType))
- doRect(); // process the final line of text
- return mMostLeft != INT_MAX ? mMostLeft : mX >> 1;
- }
-
- // FIXME: this is identical to CenterCheck::onIRect()
- // refactor so that LeftCheck and CenterCheck inherit common functions
- virtual bool onIRect(const SkIRect& rect) {
- bool opaqueBitmap = mType == kDrawBitmap_Type && mIsOpaque;
- if (opaqueBitmap && rect.contains(mX, mY)) {
- mMostLeft = rect.fLeft;
- return false;
- }
- if (joinGlyphs(rect)) // assembles glyphs into a text string
- return false;
- if (!isTextType(mType) && !opaqueBitmap)
- return false;
- /* Text on one line may be broken into several parts. Reassemble
- the text into a rectangle before considering it. */
- if (rect.fTop < mPartial.fBottom
- && rect.fBottom > mPartial.fTop
- && mPartial.fRight + JOIN_SLOP_X >= rect.fLeft
- && (mPartialType != kDrawBitmap_Type
- || mPartial.height() <= rect.height() + JOIN_SLOP_Y)) {
- DBG_NAV_LOGD("LeftCheck join mPartial=(%d, %d, %d, %d)"
- " rect=(%d, %d, %d, %d)",
- mPartial.fLeft, mPartial.fTop, mPartial.fRight, mPartial.fBottom,
- rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
- mPartial.join(rect);
- return false;
- }
- if (mPartial.isEmpty() == false) {
- doRect(); // process the previous line of text
-#if DEBUG_NAV_UI
- if (mHitLeft == INT_MAX)
- DBG_NAV_LOGD("LeftCheck disabled rect=(%d, %d, %d, %d)",
- rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
-#endif
- }
- mPartial = rect;
- mPartialType = mType;
- return false;
- }
-
- void doRect()
- {
- /* Record the outer bounds of the lines of text that intersect the
- touch coordinates, given some slop */
- if (SkIRect::Intersects(mPartial, mHit)) {
- if (mHitLeft > mPartial.fLeft)
- mHitLeft = mPartial.fLeft;
- DBG_NAV_LOGD("LeftCheck mHitLeft=%d", mHitLeft);
- } else if (mHitLeft == INT_MAX)
- return; // wait for intersect success
- /* If text is too far away vertically, don't consider it */
- if (!mBounds.isEmpty() && (mPartial.fTop > mBounds.fBottom + HIT_SLOP
- || mPartial.fBottom < mBounds.fTop - HIT_SLOP)) {
- DBG_NAV_LOGD("LeftCheck stop mPartial=(%d, %d, %d, %d)"
- " mBounds=(%d, %d, %d, %d)",
- mPartial.fLeft, mPartial.fTop, mPartial.fRight, mPartial.fBottom,
- mBounds.fLeft, mBounds.fTop, mBounds.fRight, mBounds.fBottom);
- mHitLeft = INT_MAX; // and disable future comparisons
- return;
- }
- /* If the considered text is completely to the left or right of the
- touch coordinates, skip it, turn off further detection */
- if (mPartial.fLeft > mX || mPartial.fRight < mX) {
- DBG_NAV_LOGD("LeftCheck stop mX=%d mPartial=(%d, %d, %d, %d)", mX,
- mPartial.fLeft, mPartial.fTop, mPartial.fRight, mPartial.fBottom);
- mHitLeft = INT_MAX;
- return;
- }
- /* record the smallest margins on the left and right */
- if (mMostLeft > mPartial.fLeft) {
- DBG_NAV_LOGD("LeftCheck new mMostLeft=%d (old=%d)", mPartial.fLeft,
- mMostLeft);
- mMostLeft = mPartial.fLeft;
- }
- if (mBounds.isEmpty())
- mBounds = mPartial;
- else if (mPartial.fBottom > mBounds.fBottom) {
- DBG_NAV_LOGD("LeftCheck new bottom=%d (old=%d)", mPartial.fBottom,
- mBounds.fBottom);
- mBounds.fBottom = mPartial.fBottom;
- }
- }
-
- static const int JOIN_SLOP_X = 30; // horizontal space between text parts
- static const int JOIN_SLOP_Y = 5; // vertical space between text lines
- static const int HIT_SLOP = 30; // diameter allowing for tap size
- /* const */ SkIRect mHit; // sloppy hit rectangle
- SkIRect mBounds; // reference bounds
- SkIRect mPartial; // accumulated text bounds, per line
- const int mX; // touch location
- const int mY;
- int mHitLeft; // touched text extremes
- int mMostLeft; // paragraph extremes
- Type mPartialType;
-};
-
-/*
-CenterCheck examines the text in a picture, within a viewable rectangle,
-and returns via center() the optimal amount to scroll in x to display the
-paragraph of text.
-
-The caller of CenterCheck has configured (but not allocated) a bitmap
-the height and three times the width of the view. The picture is drawn centered
-in the bitmap, so text that would be revealed, if the view was scrolled up to
-a view-width to the left or right, is considered.
-*/
-class CenterCheck : public CommonCheck {
-public:
- CenterCheck(int x, int y, int width) : mX(x), mY(y),
- mHitLeft(x), mHitRight(x), mMostLeft(INT_MAX), mMostRight(-INT_MAX),
- mViewLeft(width), mViewRight(width << 1) {
- mHit.set(x - CENTER_SLOP, y - CENTER_SLOP,
- x + CENTER_SLOP, y + CENTER_SLOP);
- mPartial.setEmpty();
- }
-
- int center() {
- doRect(); // process the final line of text
- /* If the touch coordinates aren't near any text, return 0 */
- if (mHitLeft == mHitRight) {
- DBG_NAV_LOGD("abort: mHitLeft=%d ==mHitRight", mHitLeft);
- return 0;
- }
- int leftOver = mHitLeft - mViewLeft;
- int rightOver = mHitRight - mViewRight;
- int center;
- /* If the touched text is too large to entirely fit on the screen,
- center it. */
- if (leftOver < 0 && rightOver > 0) {
- center = (leftOver + rightOver) >> 1;
- DBG_NAV_LOGD("overlap: leftOver=%d rightOver=%d center=%d",
- leftOver, rightOver, center);
- return center;
- }
- center = (mMostLeft + mMostRight) >> 1; // the paragraph center
- if (leftOver > 0 && rightOver >= 0) { // off to the right
- if (center > mMostLeft) // move to center loses left-most text?
- center = mMostLeft;
- } else if (rightOver < 0 && leftOver <= 0) { // off to the left
- if (center < mMostRight) // move to center loses right-most text?
- center = mMostRight;
- } else {
-#ifdef DONT_CENTER_IF_ALREADY_VISIBLE
- center = 0; // paragraph is already fully visible
-#endif
- }
- DBG_NAV_LOGD("scroll: leftOver=%d rightOver=%d center=%d",
- leftOver, rightOver, center);
- return center;
- }
-
-protected:
- virtual bool onIRect(const SkIRect& rect) {
- if (joinGlyphs(rect)) // assembles glyphs into a text string
- return false;
- if (!isTextType(mType))
- return false;
- /* Text on one line may be broken into several parts. Reassemble
- the text into a rectangle before considering it. */
- if (rect.fTop < mPartial.fBottom && rect.fBottom >
- mPartial.fTop && mPartial.fRight + CENTER_SLOP >= rect.fLeft) {
- DBG_NAV_LOGD("join mPartial=(%d, %d, %d, %d) rect=(%d, %d, %d, %d)",
- mPartial.fLeft, mPartial.fTop, mPartial.fRight, mPartial.fBottom,
- rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
- mPartial.join(rect);
- return false;
- }
- if (mPartial.isEmpty() == false)
- doRect(); // process the previous line of text
- mPartial = rect;
- return false;
- }
-
- void doRect()
- {
- /* Record the outer bounds of the lines of text that was 'hit' by the
- touch coordinates, given some slop */
- if (SkIRect::Intersects(mPartial, mHit)) {
- if (mHitLeft > mPartial.fLeft)
- mHitLeft = mPartial.fLeft;
- if (mHitRight < mPartial.fRight)
- mHitRight = mPartial.fRight;
- DBG_NAV_LOGD("mHitLeft=%d mHitRight=%d", mHitLeft, mHitRight);
- }
- /* If the considered text is completely to the left or right of the
- touch coordinates, skip it */
- if (mPartial.fLeft > mX || mPartial.fRight < mX)
- return;
- int leftOver = mPartial.fLeft - mViewLeft;
- int rightOver = mPartial.fRight - mViewRight;
- /* If leftOver <= 0, the text starts off the screen.
- If rightOver >= 0, the text ends off the screen.
- */
- if (leftOver <= 0 && rightOver >= 0) // discard wider than screen
- return;
-#ifdef DONT_CENTER_IF_ALREADY_VISIBLE
- if (leftOver > 0 && rightOver < 0) // discard already visible
- return;
-#endif
- /* record the smallest margins on the left and right */
- if (mMostLeft > leftOver)
- mMostLeft = leftOver;
- if (mMostRight < rightOver)
- mMostRight = rightOver;
- DBG_NAV_LOGD("leftOver=%d rightOver=%d mMostLeft=%d mMostRight=%d",
- leftOver, rightOver, mMostLeft, mMostRight);
- }
-
- static const int CENTER_SLOP = 10; // space between text parts and lines
- /* const */ SkIRect mHit; // sloppy hit rectangle
- SkIRect mPartial; // accumulated text bounds, per line
- const int mX; // touch location
- const int mY;
- int mHitLeft; // touched text extremes
- int mHitRight;
- int mMostLeft; // paragraph extremes
- int mMostRight;
- const int mViewLeft; // middle third of 3x-wide view
- const int mViewRight;
-};
-
-class ImageCanvas : public ParseCanvas {
-public:
- ImageCanvas(SkBounder* bounder) : mURI(NULL) {
- setBounder(bounder);
- }
-
- const char* getURI() { return mURI; }
-
-protected:
-// Currently webkit's bitmap draws always seem to be cull'd before this entry
-// point is called, so we assume that any bitmap that gets here is inside our
-// tiny clip (may not be true in the future)
- virtual void commonDrawBitmap(const SkBitmap& bitmap, const SkIRect* rect,
- const SkMatrix& , const SkPaint& ) {
- SkPixelRef* pixelRef = bitmap.pixelRef();
- if (pixelRef != NULL) {
- mURI = pixelRef->getURI();
- }
- }
-
-private:
- const char* mURI;
-};
-
-class ImageCheck : public SkBounder {
-public:
- virtual bool onIRect(const SkIRect& rect) {
- return false;
- }
-};
-
-class JiggleCheck : public CommonCheck {
-public:
- JiggleCheck(int delta, int width) : mDelta(delta), mMaxX(width) {
- mMaxJiggle = 0;
- mMinX = mMinJiggle = abs(delta);
- mMaxWidth = width + mMinX;
- }
-
- int jiggle() {
- if (mMinJiggle > mMaxJiggle)
- return mDelta;
- int avg = (mMinJiggle + mMaxJiggle + 1) >> 1;
- return mDelta < 0 ? -avg : avg;
- }
-
- virtual bool onIRect(const SkIRect& rect) {
- if (joinGlyphs(rect))
- return false;
- if (mType != kDrawBitmap_Type && !isTextType(mType))
- return false;
- int min, max;
- if (mDelta < 0) {
- min = mMinX - rect.fLeft;
- max = mMaxWidth - rect.fRight;
- } else {
- min = rect.fRight - mMaxX;
- max = rect.fLeft;
- }
- if (min <= 0)
- return false;
- if (max >= mMinX)
- return false;
- if (mMinJiggle > min)
- mMinJiggle = min;
- if (mMaxJiggle < max)
- mMaxJiggle = max;
- return false;
- }
-
- int mDelta;
- int mMaxJiggle;
- int mMaxX;
- int mMinJiggle;
- int mMinX;
- int mMaxWidth;
-};
-
-class RingCheck : public CommonCheck {
-public:
- RingCheck(const WTF::Vector<WebCore::IntRect>& rings,
- const WebCore::IntRect& bitBounds, const WebCore::IntRect& testBounds,
- bool singleImage)
- : mTestBounds(testBounds)
- , mBitBounds(bitBounds)
- , mPushPop(false)
- , mSingleImage(singleImage)
- {
- const WebCore::IntRect* r;
- for (r = rings.begin(); r != rings.end(); r++) {
- SkIRect fatter = {r->x(), r->y(), r->maxX(), r->maxY()};
- fatter.inset(-CURSOR_RING_HIT_TEST_RADIUS, -CURSOR_RING_HIT_TEST_RADIUS);
- DBG_NAV_LOGD("RingCheck fat=(%d,%d,r=%d,b=%d)", fatter.fLeft, fatter.fTop,
- fatter.fRight, fatter.fBottom);
- mTextSlop.op(fatter, SkRegion::kUnion_Op);
- mTextTest.op(*r, SkRegion::kUnion_Op);
- }
- int dx = -bitBounds.x();
- int dy = -bitBounds.y();
- DBG_NAV_LOGD("RingCheck translate=(%d,%d)", dx, dy);
- mTextSlop.translate(dx, dy);
- mTextTest.translate(dx, dy);
- mTestBounds.translate(dx, dy);
- mEmpty.setEmpty();
- }
-
- bool hiddenRings(SkRegion* clipped)
- {
- findBestLayer();
- if (!mBestLayer) {
- DBG_NAV_LOG("RingCheck empty");
- clipped->setEmpty();
- return true;
- }
- const SkRegion* layersEnd = mLayers.end();
- const Type* layerTypes = &mLayerTypes[mBestLayer - mLayers.begin()];
- bool collectGlyphs = true;
- bool collectOvers = false;
- SkRegion over;
- for (const SkRegion* layers = mBestLayer; layers != layersEnd; layers++) {
- Type layerType = *layerTypes++;
- DBG_NAV_LOGD("RingCheck #%d %s (%d,%d,r=%d,b=%d)",
- layers - mLayers.begin(), TypeNames[layerType],
- layers->getBounds().fLeft, layers->getBounds().fTop,
- layers->getBounds().fRight, layers->getBounds().fBottom);
- if (collectGlyphs && (layerType == kDrawGlyph_Type
- || ((layerType == kDrawRect_Type && mTextTest.contains(*layers))
- || (layerType == kDrawBitmap_Type && mTextSlop.contains(*layers))))) {
- DBG_NAV_LOGD("RingCheck #%d collectOvers", layers - mLayers.begin());
- collectOvers = true;
- clipped->op(*layers, SkRegion::kUnion_Op);
- continue;
- }
- collectGlyphs &= layerType != kPushLayer_Type;
- if (collectOvers && (layerType == kDrawRect_Type
- || layerType == kDrawBitmap_Type
- || (!collectGlyphs && layerType == kDrawSprite_Type))) {
- DBG_NAV_LOGD("RingCheck #%d over.op", layers - mLayers.begin());
- over.op(*layers, SkRegion::kUnion_Op);
- }
- }
- bool result = !collectOvers || clipped->intersects(over);
- const SkIRect t = clipped->getBounds();
- const SkIRect o = over.getBounds();
- clipped->op(over, SkRegion::kDifference_Op);
- clipped->translate(mBitBounds.x(), mBitBounds.y());
- const SkIRect c = clipped->getBounds();
- DBG_NAV_LOGD("RingCheck intersects=%s text=(%d,%d,r=%d,b=%d)"
- " over=(%d,%d,r=%d,b=%d) clipped=(%d,%d,r=%d,b=%d)",
- result ? "true" : "false",
- t.fLeft, t.fTop, t.fRight, t.fBottom,
- o.fLeft, o.fTop, o.fRight, o.fBottom,
- c.fLeft, c.fTop, c.fRight, c.fBottom);
- return result;
- }
-
- void push(Type type, const SkIRect& bounds)
- {
-#if DEBUG_NAV_UI
- // this caches the push string and subquently ignores if pushSave
- // is immediately followed by popLayer. Push/pop pairs happen
- // frequently and just add noise to the log.
- static String lastLog;
- String currentLog = String("RingCheck append #")
- + String::number(mLayers.size())
- + " type=" + TypeNames[type] + " bounds=("
- + String::number(bounds.fLeft)
- + "," + String::number(bounds.fTop) + ","
- + String::number(bounds.fRight) + ","
- + String::number(bounds.fBottom) + ")";
- if (lastLog.length() == 0 || type != kPopLayer_Type) {
- if (lastLog.length() != 0)
- DBG_NAV_LOGD("%s", lastLog.latin1().data());
- if (type == kPushSave_Type)
- lastLog = currentLog;
- else
- DBG_NAV_LOGD("%s", currentLog.latin1().data());
- } else
- lastLog = "";
-#endif
- popEmpty();
- mPushPop |= type >= kPopLayer_Type;
- if (type == kPopLayer_Type) {
- Type last = mLayerTypes.last();
- // remove empty brackets
- if (last == kPushLayer_Type || last == kPushSave_Type) {
- mLayers.removeLast();
- mLayerTypes.removeLast();
- return;
- }
- // remove push/pop from push/bitmap/pop
- size_t pushIndex = mLayerTypes.size() - 2;
- if (last == kDrawBitmap_Type
- && mLayerTypes.at(pushIndex) == kPushLayer_Type) {
- mLayers.at(pushIndex) = mLayers.last();
- mLayerTypes.at(pushIndex) = kDrawBitmap_Type;
- mLayers.removeLast();
- mLayerTypes.removeLast();
- return;
- }
- // remove non-layer brackets
- int stack = 0;
- Type* types = mLayerTypes.end();
- while (types != mLayerTypes.begin()) {
- Type type = *--types;
- if (type == kPopLayer_Type) {
- stack++;
- continue;
- }
- if (type != kPushLayer_Type && type != kPushSave_Type)
- continue;
- if (--stack >= 0)
- continue;
- if (type == kPushLayer_Type)
- break;
- int remove = types - mLayerTypes.begin();
- DBG_NAV_LOGD("RingCheck remove=%d mLayers.size=%d"
- " mLayerTypes.size=%d", remove, mLayers.size(),
- mLayerTypes.size());
- mLayers.remove(remove);
- mLayerTypes.remove(remove);
- mAppendLikeTypes = false;
- return;
- }
- }
- mLayers.append(bounds);
- mLayerTypes.append(type);
- }
-
- void startText(const SkPaint& paint)
- {
- mPaint = &paint;
- if (!mLayerTypes.isEmpty() && mLayerTypes.last() == kDrawGlyph_Type
- && !mLayers.last().isEmpty()) {
- push(kDrawGlyph_Type, mEmpty);
- }
- }
-
- bool textOutsideRings()
- {
- findBestLayer();
- if (!mBestLayer) {
- DBG_NAV_LOG("RingCheck empty");
- return false;
- }
- const SkRegion* layers = mBestLayer;
- const Type* layerTypes = &mLayerTypes[layers - mLayers.begin()];
- // back up to include text drawn before the best layer
- SkRegion active = SkRegion(mBitBounds);
- active.translate(-mBitBounds.x(), -mBitBounds.y());
- while (layers != mLayers.begin()) {
- --layers;
- Type layerType = *--layerTypes;
- DBG_NAV_LOGD("RingCheck #%d %s"
- " mTestBounds=(%d,%d,r=%d,b=%d) layers=(%d,%d,r=%d,b=%d)"
- " active=(%d,%d,r=%d,b=%d)",
- layers - mLayers.begin(), TypeNames[layerType],
- mTestBounds.getBounds().fLeft, mTestBounds.getBounds().fTop,
- mTestBounds.getBounds().fRight, mTestBounds.getBounds().fBottom,
- layers->getBounds().fLeft, layers->getBounds().fTop,
- layers->getBounds().fRight, layers->getBounds().fBottom,
- active.getBounds().fLeft, active.getBounds().fTop,
- active.getBounds().fRight, active.getBounds().fBottom);
- if (layerType == kDrawRect_Type || layerType == kDrawBitmap_Type) {
- SkRegion temp = *layers;
- temp.op(mTestBounds, SkRegion::kIntersect_Op);
- active.op(temp, SkRegion::kDifference_Op);
- if (active.isEmpty()) {
- DBG_NAV_LOGD("RingCheck #%d empty", layers - mLayers.begin());
- break;
- }
- } else if (layerType == kDrawGlyph_Type) {
- SkRegion temp = *layers;
- temp.op(active, SkRegion::kIntersect_Op);
- if (!mTestBounds.intersects(temp))
- continue;
- if (!mTestBounds.contains(temp))
- return false;
- } else
- break;
- }
- layers = mBestLayer;
- layerTypes = &mLayerTypes[layers - mLayers.begin()];
- bool foundGlyph = false;
- bool collectGlyphs = true;
- do {
- Type layerType = *layerTypes++;
- DBG_NAV_LOGD("RingCheck #%d %s mTestBounds=(%d,%d,r=%d,b=%d)"
- " layers=(%d,%d,r=%d,b=%d) collects=%s intersects=%s contains=%s",
- layers - mLayers.begin(), TypeNames[layerType],
- mTestBounds.getBounds().fLeft, mTestBounds.getBounds().fTop,
- mTestBounds.getBounds().fRight, mTestBounds.getBounds().fBottom,
- layers->getBounds().fLeft, layers->getBounds().fTop,
- layers->getBounds().fRight, layers->getBounds().fBottom,
- collectGlyphs ? "true" : "false",
- mTestBounds.intersects(*layers) ? "true" : "false",
- mTextSlop.contains(*layers) ? "true" : "false");
- if (collectGlyphs && layerType == kDrawGlyph_Type) {
- if (!mTestBounds.intersects(*layers))
- continue;
- if (!mTextSlop.contains(*layers))
- return false;
- foundGlyph = true;
- }
- collectGlyphs &= layerType != kPushLayer_Type;
- } while (++layers != mLayers.end());
- DBG_NAV_LOGD("RingCheck foundGlyph=%s", foundGlyph ? "true" : "false");
- return foundGlyph;
- }
-
-protected:
- virtual bool onIRect(const SkIRect& rect)
- {
- joinGlyphs(rect);
- if (mType != kDrawGlyph_Type && mType != kDrawRect_Type
- && mType != kDrawSprite_Type && mType != kDrawBitmap_Type)
- return false;
- if (mLayerTypes.isEmpty() || mLayerTypes.last() != mType
- || !mAppendLikeTypes || mPushPop || mSingleImage
- // if the last and current were not glyphs,
- // and the two bounds have a gap between, don't join them -- push
- // an empty between them
- || (mType != kDrawGlyph_Type && !joinable(rect))) {
- push(mType, mEmpty);
- }
- DBG_NAV_LOGD("RingCheck join %s (%d,%d,r=%d,b=%d) '%c'",
- TypeNames[mType], rect.fLeft, rect.fTop, rect.fRight, rect.fBottom,
- mCh);
- mLayers.last().op(rect, SkRegion::kUnion_Op);
- mAppendLikeTypes = true;
- mPushPop = false;
- return false;
- }
-
- virtual bool onIRectGlyph(const SkIRect& rect,
- const SkBounder::GlyphRec& rec)
- {
- mCh = ' ';
- if (mPaint) {
- SkUnichar unichar;
- SkPaint utfPaint = *mPaint;
- utfPaint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
- utfPaint.glyphsToUnichars(&rec.fGlyphID, 1, &unichar);
- mCh = unichar < 0x7f ? unichar : '?';
- }
- return onIRect(rect);
- }
-
-private:
- int calcOverlap(SkRegion& testRegion)
- {
- if (testRegion.isEmpty())
- return INT_MAX;
- testRegion.op(mTextTest, SkRegion::kXOR_Op);
- SkRegion::Iterator iter(testRegion);
- int area = 0;
- while (!iter.done()) {
- const SkIRect& cr = iter.rect();
- area += cr.width() * cr.height();
- iter.next();
- }
- DBG_NAV_LOGD("RingCheck area=%d", area);
- return area;
- }
-
- void findBestLayer()
- {
- popEmpty();
- mBestLayer = 0;
- const SkRegion* layers = mLayers.begin();
- const SkRegion* layersEnd = mLayers.end();
- if (layers == layersEnd) {
- DBG_NAV_LOG("RingCheck empty");
- return;
- }
- // find text most like focus rings by xoring found with original
- int bestArea = INT_MAX;
- const SkRegion* testLayer = 0;
- SkRegion testRegion;
- const Type* layerTypes = &mLayerTypes[layers - mLayers.begin()];
- for (; layers != mLayers.end(); layers++) {
- Type layerType = *layerTypes++;
-#if DEBUG_NAV_UI
- const SkIRect& gb = layers->getBounds();
- const SkIRect& tb = mTextSlop.getBounds();
- DBG_NAV_LOGD("RingCheck #%d %s mTextSlop=(%d,%d,%d,%d)"
- " contains=%s bounds=(%d,%d,%d,%d)",
- layers - mLayers.begin(), TypeNames[layerType],
- tb.fLeft, tb.fTop, tb.fRight, tb.fBottom,
- mTextSlop.contains(*layers) ? "true" : "false",
- gb.fLeft, gb.fTop, gb.fRight, gb.fBottom);
-#endif
- if (((layerType == kDrawGlyph_Type || layerType == kDrawBitmap_Type)
- && mTextSlop.contains(*layers))
- || (layerType == kDrawRect_Type
- && mTextTest.contains(*layers))) {
- if (!testLayer)
- testLayer = layers;
- testRegion.op(*layers, SkRegion::kUnion_Op);
- continue;
- }
- if (testLayer) {
- int area = calcOverlap(testRegion);
- if (bestArea > area) {
- bestArea = area;
- mBestLayer = testLayer;
- }
- DBG_NAV_LOGD("RingCheck #%d push test=%d best=%d",
- layers - mLayers.begin(), testLayer - mLayers.begin(),
- mBestLayer ? mBestLayer - mLayers.begin() : -1);
- testRegion.setEmpty();
- testLayer = 0;
- }
- }
- if (testLayer && bestArea > calcOverlap(testRegion)) {
- DBG_NAV_LOGD("RingCheck last best=%d", testLayer - mLayers.begin());
- mBestLayer = testLayer;
- }
- }
-
- bool joinable(const SkIRect& rect)
- {
- SkRegion region = mLayers.last();
- if (!region.isRect())
- return false;
- const SkIRect& bounds1 = region.getBounds();
- int area1 = bounds1.width() * bounds1.height();
- area1 += rect.width() * rect.height();
- region.op(rect, SkRegion::kUnion_Op);
- const SkIRect& bounds2 = region.getBounds();
- int area2 = bounds2.width() * bounds2.height();
- return area2 <= area1;
- }
-
- void popEmpty()
- {
- if (mLayerTypes.size() == 0)
- return;
- Type last = mLayerTypes.last();
- if (last >= kPopLayer_Type)
- return;
- const SkRegion& area = mLayers.last();
- if (!area.isEmpty())
- return;
- DBG_NAV_LOGD("RingCheck #%d %s", mLayers.size() - 1, TypeNames[last]);
- mLayers.removeLast();
- mLayerTypes.removeLast();
- }
-
- SkRegion mTestBounds;
- IntRect mBitBounds;
- SkIRect mEmpty;
- const SkRegion* mBestLayer;
- SkRegion mTextSlop; // outset rects for inclusion test
- SkRegion mTextTest; // exact rects for xor area test
- Type mLastType;
- Vector<SkRegion> mLayers;
- Vector<Type> mLayerTypes;
- const SkPaint* mPaint;
- char mCh;
- bool mAppendLikeTypes;
- bool mPushPop;
- bool mSingleImage;
-};
-
-class RingCanvas : public BoundsCanvas {
-public:
- RingCanvas(RingCheck* bounder)
- : INHERITED(bounder)
- {
- }
-
-protected:
- virtual void drawText(const void* text, size_t byteLength, SkScalar x,
- SkScalar y, const SkPaint& paint) {
- static_cast<RingCheck&>(mBounder).startText(paint);
- INHERITED::drawText(text, byteLength, x, y, paint);
- }
-
- virtual void drawPosText(const void* text, size_t byteLength,
- const SkPoint pos[], const SkPaint& paint) {
- static_cast<RingCheck&>(mBounder).startText(paint);
- INHERITED::drawPosText(text, byteLength, pos, paint);
- }
-
- virtual void drawTextOnPath(const void* text, size_t byteLength,
- const SkPath& path, const SkMatrix* matrix,
- const SkPaint& paint) {
- static_cast<RingCheck&>(mBounder).startText(paint);
- INHERITED::drawTextOnPath(text, byteLength, path, matrix, paint);
- }
-
- virtual void drawPosTextH(const void* text, size_t byteLength,
- const SkScalar xpos[], SkScalar constY,
- const SkPaint& paint) {
- static_cast<RingCheck&>(mBounder).startText(paint);
- INHERITED::drawPosTextH(text, byteLength, xpos, constY, paint);
- }
-
- virtual int save(SaveFlags flags)
- {
- RingCheck& bounder = static_cast<RingCheck&>(mBounder);
- bounder.push(CommonCheck::kPushSave_Type, getTotalClip().getBounds());
- return INHERITED::save(flags);
- }
-
- virtual int saveLayer(const SkRect* bounds, const SkPaint* paint,
- SaveFlags flags)
- {
- RingCheck& bounder = static_cast<RingCheck&>(mBounder);
- bounder.push(CommonCheck::kPushLayer_Type, getTotalClip().getBounds());
- return INHERITED::save(flags);
- }
-
- virtual void restore()
- {
- RingCheck& bounder = static_cast<RingCheck&>(mBounder);
- bounder.push(CommonCheck::kPopLayer_Type, getTotalClip().getBounds());
- INHERITED::restore();
- }
-
-private:
- typedef BoundsCanvas INHERITED;
-};
-
-bool CachedRoot::adjustForScroll(BestData* best, CachedFrame::Direction direction,
- WebCore::IntPoint* scrollPtr, bool findClosest)
-{
- WebCore::IntRect newOutset;
- const CachedNode* newNode = best->mNode;
- // see if there's a middle node
- // if the middle node is in the visited list,
- // or if none was computed and the newNode is in the visited list,
- // treat result as NULL
- if (newNode != NULL && findClosest) {
- if (best->bounds().intersects(mHistory->mPriorBounds) == false &&
- checkBetween(best, direction))
- newNode = best->mNode;
- if (findClosest && maskIfHidden(best)) {
- innerMove(document(), best, direction, scrollPtr, false);
- return true;
- }
- newOutset = newNode->cursorRingBounds(best->mFrame);
- }
- int delta;
- bool newNodeInView = scrollDelta(newOutset, direction, &delta);
- if (delta && scrollPtr && (newNode == NULL || newNodeInView == false ||
- (best->mNavOutside && best->mWorkingOutside)))
- *scrollPtr = WebCore::IntPoint(direction & UP_DOWN ? 0 : delta,
- direction & UP_DOWN ? delta : 0);
- return false;
-}
-
-void CachedRoot::calcBitBounds(const IntRect& nodeBounds, IntRect* bitBounds) const
-{
- IntRect contentBounds = IntRect(0, 0, mPicture->width(), mPicture->height());
- IntRect overBounds = nodeBounds;
- overBounds.inflate(kMargin);
- IntRect viewableBounds = mScrolledBounds;
- viewableBounds.unite(mViewBounds);
- *bitBounds = contentBounds;
- bitBounds->intersect(overBounds);
- if (!bitBounds->intersects(viewableBounds))
- *bitBounds = IntRect(0, 0, 0, 0);
- DBG_NAV_LOGD("contentBounds=(%d,%d,r=%d,b=%d) overBounds=(%d,%d,r=%d,b=%d)"
- " mScrolledBounds=(%d,%d,r=%d,b=%d) mViewBounds=(%d,%d,r=%d,b=%d)"
- " bitBounds=(%d,%d,r=%d,b=%d)",
- contentBounds.x(), contentBounds.y(), contentBounds.maxX(),
- contentBounds.maxY(),
- overBounds.x(), overBounds.y(), overBounds.maxX(), overBounds.maxY(),
- mScrolledBounds.x(), mScrolledBounds.y(), mScrolledBounds.maxX(),
- mScrolledBounds.maxY(),
- mViewBounds.x(), mViewBounds.y(), mViewBounds.maxX(),
- mViewBounds.maxY(),
- bitBounds->x(), bitBounds->y(), bitBounds->maxX(),
- bitBounds->maxY());
-}
-
-
-int CachedRoot::checkForCenter(int x, int y) const
-{
- int width = mViewBounds.width();
- SkPicture* picture = pictureAt(&x, &y);
- CenterCheck centerCheck(x + width - mViewBounds.x(), y - mViewBounds.y(),
- width);
- BoundsCanvas checker(&centerCheck);
- SkBitmap bitmap;
- bitmap.setConfig(SkBitmap::kARGB_8888_Config, width * 3,
- mViewBounds.height());
- checker.setBitmapDevice(bitmap);
- checker.translate(SkIntToScalar(width - mViewBounds.x()),
- SkIntToScalar(-mViewBounds.y()));
- checker.drawPicture(*picture);
- return centerCheck.center();
-}
-
-void CachedRoot::checkForJiggle(int* xDeltaPtr) const
-{
- int xDelta = *xDeltaPtr;
- JiggleCheck jiggleCheck(xDelta, mViewBounds.width());
- BoundsCanvas checker(&jiggleCheck);
- SkBitmap bitmap;
- int absDelta = abs(xDelta);
- bitmap.setConfig(SkBitmap::kARGB_8888_Config, mViewBounds.width() +
- absDelta, mViewBounds.height());
- checker.setBitmapDevice(bitmap);
- int x = -mViewBounds.x() - (xDelta < 0 ? xDelta : 0);
- int y = -mViewBounds.y();
- SkPicture* picture = pictureAt(&x, &y);
- checker.translate(SkIntToScalar(x), SkIntToScalar(y));
- checker.drawPicture(*picture);
- *xDeltaPtr = jiggleCheck.jiggle();
-}
-
-bool CachedRoot::checkRings(SkPicture* picture, const CachedNode* node,
- const WebCore::IntRect& testBounds) const
-{
- if (!picture)
- return false;
- const WTF::Vector<WebCore::IntRect>& rings = node->rings();
- const WebCore::IntRect& nodeBounds = node->rawBounds();
- IntRect bitBounds;
- calcBitBounds(nodeBounds, &bitBounds);
- RingCheck ringCheck(rings, bitBounds, testBounds, node->singleImage());
- RingCanvas checker(&ringCheck);
- SkBitmap bitmap;
- bitmap.setConfig(SkBitmap::kARGB_8888_Config, bitBounds.width(),
- bitBounds.height());
- checker.setBitmapDevice(bitmap);
- checker.translate(SkIntToScalar(-bitBounds.x()),
- SkIntToScalar(-bitBounds.y()));
- checker.drawPicture(*picture);
- bool result = ringCheck.textOutsideRings();
- DBG_NAV_LOGD("bitBounds=(%d,%d,r=%d,b=%d) nodeBounds=(%d,%d,r=%d,b=%d)"
- " testBounds=(%d,%d,r=%d,b=%d) success=%s",
- bitBounds.x(), bitBounds.y(), bitBounds.maxX(), bitBounds.maxY(),
- nodeBounds.x(), nodeBounds.y(), nodeBounds.maxX(), nodeBounds.maxY(),
- testBounds.x(), testBounds.y(), testBounds.maxX(), testBounds.maxY(),
- result ? "true" : "false");
- return result;
-}
-
-void CachedRoot::draw(FindCanvas& canvas) const
-{
- canvas.setLayerId(-1); // overlays change the ID as their pictures draw
- canvas.drawPicture(*mPicture);
-#if USE(ACCELERATED_COMPOSITING)
- if (!mRootLayer)
- return;
- canvas.drawLayers(mRootLayer);
-#endif
-}
-
-const CachedNode* CachedRoot::findAt(const WebCore::IntRect& rect,
- const CachedFrame** framePtr, int* x, int* y, bool checkForHidden) const
-{
-#if DEBUG_NAV_UI
- DBG_NAV_LOGD("rect=(%d,%d,w=%d,h=%d) xy=(%d,%d)", rect.x(), rect.y(),
- rect.width(), rect.height(), *x, *y);
-#if DUMP_NAV_CACHE
- if (mRootLayer) CachedLayer::Debug::printRootLayerAndroid(mRootLayer);
-#endif
-#endif
- int best = INT_MAX;
- bool inside = false;
- (const_cast<CachedRoot*>(this))->resetClippedOut();
- const CachedFrame* directHitFramePtr;
- const CachedNode* directHit = NULL;
- const CachedNode* node = findBestAt(rect, &best, &inside, &directHit,
- &directHitFramePtr, framePtr, x, y, checkForHidden);
- DBG_NAV_LOGD("node=%d (%p) xy=(%d,%d)", node == NULL ? 0 : node->index(),
- node == NULL ? NULL : node->nodePointer(), *x, *y);
- if (node == NULL) {
- node = findBestHitAt(rect, framePtr, x, y);
- DBG_NAV_LOGD("node=%d (%p)", node == NULL ? 0 : node->index(),
- node == NULL ? NULL : node->nodePointer());
- }
- if (node == NULL) {
- *framePtr = findBestFrameAt(rect.x() + (rect.width() >> 1),
- rect.y() + (rect.height() >> 1));
- }
- return node;
-}
-
-WebCore::IntPoint CachedRoot::cursorLocation() const
-{
- const WebCore::IntRect& bounds = mHistory->mNavBounds;
- return WebCore::IntPoint(bounds.x() + (bounds.width() >> 1),
- bounds.y() + (bounds.height() >> 1));
-}
-
-WebCore::IntPoint CachedRoot::focusLocation() const
-{
- return WebCore::IntPoint(mFocusBounds.x() + (mFocusBounds.width() >> 1),
- mFocusBounds.y() + (mFocusBounds.height() >> 1));
-}
-
-// These reset the values because we only want to get the selection the first time.
-// After that, the selection is no longer accurate.
-int CachedRoot::getAndResetSelectionEnd()
-{
- int end = mSelectionEnd;
- mSelectionEnd = -1;
- return end;
-}
-
-int CachedRoot::getAndResetSelectionStart()
-{
- int start = mSelectionStart;
- mSelectionStart = -1;
- return start;
-}
-
-int CachedRoot::getBlockLeftEdge(int x, int y, float scale) const
-{
- DBG_NAV_LOGD("x=%d y=%d scale=%g mViewBounds=(%d,%d,%d,%d)", x, y, scale,
- mViewBounds.x(), mViewBounds.y(), mViewBounds.width(),
- mViewBounds.height());
- // if (x, y) is in a textArea or textField, return that
- const int slop = 1;
- WebCore::IntRect rect = WebCore::IntRect(x - slop, y - slop,
- slop * 2, slop * 2);
- const CachedFrame* frame;
- int fx, fy;
- const CachedNode* node = findAt(rect, &frame, &fx, &fy, true);
- if (node && node->wantsKeyEvents()) {
- DBG_NAV_LOGD("x=%d (%s)", node->bounds(frame).x(),
- node->isTextInput() ? "text" : "plugin");
- return node->bounds(frame).x();
- }
- SkPicture* picture = node ? frame->picture(node, &x, &y) : pictureAt(&x, &y);
- if (!picture)
- return x;
- int halfW = (int) (mViewBounds.width() * scale * 0.5f);
- int fullW = halfW << 1;
- int halfH = (int) (mViewBounds.height() * scale * 0.5f);
- int fullH = halfH << 1;
- LeftCheck leftCheck(fullW, halfH);
- BoundsCanvas checker(&leftCheck);
- SkBitmap bitmap;
- bitmap.setConfig(SkBitmap::kARGB_8888_Config, fullW, fullH);
- checker.setBitmapDevice(bitmap);
- checker.translate(SkIntToScalar(fullW - x), SkIntToScalar(halfH - y));
- checker.drawPicture(*picture);
- int result = x + leftCheck.left() - fullW;
- DBG_NAV_LOGD("halfW=%d halfH=%d mMostLeft=%d x=%d",
- halfW, halfH, leftCheck.mMostLeft, result);
- return result;
-}
-
-void CachedRoot::getSimulatedMousePosition(WebCore::IntPoint* point) const
-{
-#ifndef NDEBUG
- ASSERT(CachedFrame::mDebug.mInUse);
-#endif
- const WebCore::IntRect& mouseBounds = mHistory->mMouseBounds;
- int x = mouseBounds.x();
- int y = mouseBounds.y();
- int width = mouseBounds.width();
- int height = mouseBounds.height();
- point->setX(x + (width >> 1)); // default to box center
- point->setY(y + (height >> 1));
-#if DEBUG_NAV_UI
- const WebCore::IntRect& navBounds = mHistory->mNavBounds;
- DBG_NAV_LOGD("mHistory->mNavBounds={%d,%d,%d,%d} "
- "mHistory->mMouseBounds={%d,%d,%d,%d} point={%d,%d}",
- navBounds.x(), navBounds.y(), navBounds.width(), navBounds.height(),
- mouseBounds.x(), mouseBounds.y(), mouseBounds.width(),
- mouseBounds.height(), point->x(), point->y());
-#endif
-}
-
-void CachedRoot::init(WebCore::Frame* frame, CachedHistory* history)
-{
- CachedFrame::init(this, -1, frame);
- reset();
- mHistory = history;
- mPicture = NULL;
-}
-
-bool CachedRoot::innerDown(const CachedNode* test, BestData* bestData) const
-{
- ASSERT(minWorkingVertical() >= mViewBounds.x());
- ASSERT(maxWorkingVertical() <= mViewBounds.maxX());
- setupScrolledBounds();
- // (line up)
- mScrolledBounds.setHeight(mScrolledBounds.height() + mMaxYScroll);
- int testTop = mScrolledBounds.y();
- int viewBottom = mViewBounds.maxY();
- const WebCore::IntRect& navBounds = mHistory->mNavBounds;
- if (navBounds.isEmpty() == false &&
- navBounds.maxY() > viewBottom && viewBottom < mContents.height())
- return false;
- if (navBounds.isEmpty() == false) {
- int navTop = navBounds.y();
- int scrollBottom;
- if (testTop < navTop && navTop < (scrollBottom = mScrolledBounds.maxY())) {
- mScrolledBounds.setHeight(scrollBottom - navTop);
- mScrolledBounds.setY(navTop);
- }
- }
- setCursorCache(0, mMaxYScroll);
- frameDown(test, NULL, bestData);
- return true;
-}
-
-bool CachedRoot::innerLeft(const CachedNode* test, BestData* bestData) const
-{
- ASSERT(minWorkingHorizontal() >= mViewBounds.y());
- ASSERT(maxWorkingHorizontal() <= mViewBounds.maxY());
- setupScrolledBounds();
- mScrolledBounds.setX(mScrolledBounds.x() - mMaxXScroll);
- mScrolledBounds.setWidth(mScrolledBounds.width() + mMaxXScroll);
- int testRight = mScrolledBounds.maxX();
- int viewLeft = mViewBounds.x();
- const WebCore::IntRect& navBounds = mHistory->mNavBounds;
- if (navBounds.isEmpty() == false &&
- navBounds.x() < viewLeft && viewLeft > mContents.x())
- return false;
- if (navBounds.isEmpty() == false) {
- int navRight = navBounds.maxX();
- int scrollLeft;
- if (testRight > navRight && navRight > (scrollLeft = mScrolledBounds.x()))
- mScrolledBounds.setWidth(navRight - scrollLeft);
- }
- setCursorCache(-mMaxXScroll, 0);
- frameLeft(test, NULL, bestData);
- return true;
-}
-
-
-void CachedRoot::innerMove(const CachedNode* node, BestData* bestData,
- Direction direction, WebCore::IntPoint* scroll, bool firstCall)
-{
- bestData->reset();
- bool outOfCursor = mCursorIndex == CURSOR_CLEARED;
- DBG_NAV_LOGD("mHistory->didFirstLayout()=%s && mCursorIndex=%d",
- mHistory->didFirstLayout() ? "true" : "false", mCursorIndex);
- if (mHistory->didFirstLayout() && mCursorIndex < CURSOR_SET) {
- mHistory->reset();
- outOfCursor = true;
- }
- const CachedFrame* cursorFrame;
- const CachedNode* cursor = currentCursor(&cursorFrame);
- mHistory->setWorking(direction, cursorFrame, cursor, mViewBounds);
- bool findClosest = false;
- if (mScrollOnly == false) {
- switch (direction) {
- case LEFT:
- if (outOfCursor)
- mHistory->mNavBounds = WebCore::IntRect(mViewBounds.maxX(),
- mViewBounds.y(), 1, mViewBounds.height());
- findClosest = innerLeft(node, bestData);
- break;
- case RIGHT:
- if (outOfCursor)
- mHistory->mNavBounds = WebCore::IntRect(mViewBounds.x() - 1,
- mViewBounds.y(), 1, mViewBounds.height());
- findClosest = innerRight(node, bestData);
- break;
- case UP:
- if (outOfCursor)
- mHistory->mNavBounds = WebCore::IntRect(mViewBounds.x(),
- mViewBounds.maxY(), mViewBounds.width(), 1);
- findClosest = innerUp(node, bestData);
- break;
- case DOWN:
- if (outOfCursor)
- mHistory->mNavBounds = WebCore::IntRect(mViewBounds.x(),
- mViewBounds.y() - 1, mViewBounds.width(), 1);
- findClosest = innerDown(node, bestData);
- break;
- case UNINITIALIZED:
- default:
- ASSERT(0);
- }
- }
- if (firstCall)
- mHistory->mPriorBounds = mHistory->mNavBounds; // bounds always advances, even if new node is ultimately NULL
- bestData->setMouseBounds(bestData->bounds());
- if (adjustForScroll(bestData, direction, scroll, findClosest))
- return;
- if (bestData->mNode != NULL) {
- mHistory->addToVisited(bestData->mNode, direction);
- mHistory->mNavBounds = bestData->bounds();
- mHistory->mMouseBounds = bestData->mouseBounds();
- } else if (scroll->x() != 0 || scroll->y() != 0) {
- WebCore::IntRect newBounds = mHistory->mNavBounds;
- int offsetX = scroll->x();
- int offsetY = scroll->y();
- newBounds.move(offsetX, offsetY);
- if (mViewBounds.x() > newBounds.x())
- offsetX = mViewBounds.x() - mHistory->mNavBounds.x();
- else if (mViewBounds.maxX() < newBounds.maxX())
- offsetX = mViewBounds.maxX() - mHistory->mNavBounds.maxX();
- if (mViewBounds.y() > newBounds.y())
- offsetY = mViewBounds.y() - mHistory->mNavBounds.y();
- else if (mViewBounds.maxY() < newBounds.maxY())
- offsetY = mViewBounds.maxY() - mHistory->mNavBounds.maxY();
- mHistory->mNavBounds.move(offsetX, offsetY);
- }
- mHistory->setDidFirstLayout(false);
-}
-
-bool CachedRoot::innerRight(const CachedNode* test, BestData* bestData) const
-{
- ASSERT(minWorkingHorizontal() >= mViewBounds.y());
- ASSERT(maxWorkingHorizontal() <= mViewBounds.maxY());
- setupScrolledBounds();
- // (align)
- mScrolledBounds.setWidth(mScrolledBounds.width() + mMaxXScroll);
- int testLeft = mScrolledBounds.x();
- int viewRight = mViewBounds.maxX();
- const WebCore::IntRect& navBounds = mHistory->mNavBounds;
- if (navBounds.isEmpty() == false &&
- navBounds.maxX() > viewRight && viewRight < mContents.width())
- return false;
- if (navBounds.isEmpty() == false) {
- int navLeft = navBounds.x();
- int scrollRight;
- if (testLeft < navLeft && navLeft < (scrollRight = mScrolledBounds.maxX())) {
- mScrolledBounds.setWidth(scrollRight - navLeft);
- mScrolledBounds.setX(navLeft);
- }
- }
- setCursorCache(mMaxXScroll, 0);
- frameRight(test, NULL, bestData);
- return true;
-}
-
-bool CachedRoot::innerUp(const CachedNode* test, BestData* bestData) const
-{
- ASSERT(minWorkingVertical() >= mViewBounds.x());
- ASSERT(maxWorkingVertical() <= mViewBounds.maxX());
- setupScrolledBounds();
- mScrolledBounds.setY(mScrolledBounds.y() - mMaxYScroll);
- mScrolledBounds.setHeight(mScrolledBounds.height() + mMaxYScroll);
- int testBottom = mScrolledBounds.maxY();
- int viewTop = mViewBounds.y();
- const WebCore::IntRect& navBounds = mHistory->mNavBounds;
- if (navBounds.isEmpty() == false &&
- navBounds.y() < viewTop && viewTop > mContents.y())
- return false;
- if (navBounds.isEmpty() == false) {
- int navBottom = navBounds.maxY();
- int scrollTop;
- if (testBottom > navBottom && navBottom > (scrollTop = mScrolledBounds.y()))
- mScrolledBounds.setHeight(navBottom - scrollTop);
- }
- setCursorCache(0, -mMaxYScroll);
- frameUp(test, NULL, bestData);
- return true;
-}
-
-WTF::String CachedRoot::imageURI(int x, int y) const
-{
- DBG_NAV_LOGD("x/y=(%d,%d)", x, y);
- ImageCheck imageCheck;
- ImageCanvas checker(&imageCheck);
- SkBitmap bitmap;
- bitmap.setConfig(SkBitmap::kARGB_8888_Config, 1, 1);
- checker.setBitmapDevice(bitmap);
- SkPicture* picture = pictureAt(&x, &y);
- checker.translate(SkIntToScalar(-x), SkIntToScalar(-y));
- checker.drawPicture(*picture);
- DBG_NAV_LOGD("uri=%s", checker.getURI());
- return WTF::String(checker.getURI());
-}
-
-bool CachedRoot::maskIfHidden(BestData* best) const
-{
- const CachedNode* bestNode = best->mNode;
- if (bestNode->isUnclipped())
- return false;
- const CachedFrame* frame = best->mFrame;
- SkPicture* picture = frame->picture(bestNode);
- if (picture == NULL) {
- DBG_NAV_LOG("missing picture");
- return false;
- }
- Vector<IntRect> rings;
- bestNode->cursorRings(frame, &rings);
- const WebCore::IntRect& bounds = bestNode->bounds(frame);
- IntRect bitBounds;
- calcBitBounds(bounds, &bitBounds);
- RingCheck ringCheck(rings, bitBounds, bounds, bestNode->singleImage());
- RingCanvas checker(&ringCheck);
- SkBitmap bitmap;
- bitmap.setConfig(SkBitmap::kARGB_8888_Config, bitBounds.width(),
- bitBounds.height());
- checker.setBitmapDevice(bitmap);
- checker.translate(SkIntToScalar(-bitBounds.x()),
- SkIntToScalar(-bitBounds.y()));
- checker.drawPicture(*picture);
- SkRegion clipRgn;
- bool clipped = ringCheck.hiddenRings(&clipRgn);
- CachedNode* node = const_cast<CachedNode*>(best->mNode);
- DBG_NAV_LOGD("clipped=%s clipRgn.isEmpty=%s", clipped ? "true" : "false",
- clipRgn.isEmpty() ? "true" : "false");
- if (clipped && clipRgn.isEmpty()) {
- node->setDisabled(true);
- IntRect clippedBounds = bounds;
- clippedBounds.intersect(bitBounds);
- node->setClippedOut(clippedBounds != bounds);
- return true;
- }
- // was it partially occluded by later drawing?
- // if partially occluded, modify the bounds so that the mouse click has a better x,y
- if (clipped) {
- DBG_NAV_LOGD("clipped clipRgn={%d,%d,r=%d,b=%d}",
- clipRgn.getBounds().fLeft, clipRgn.getBounds().fTop,
- clipRgn.getBounds().fRight, clipRgn.getBounds().fBottom);
- best->setMouseBounds(clipRgn.getBounds());
- if (!node->clip(best->mouseBounds())) {
- node->setDisabled(true);
- node->setClippedOut(true);
- return true;
- }
- } else
- node->fixUpCursorRects(frame);
- return false;
-}
-
-const CachedNode* CachedRoot::moveCursor(Direction direction, const CachedFrame** framePtr,
- WebCore::IntPoint* scroll)
-{
-#ifndef NDEBUG
- ASSERT(CachedFrame::mDebug.mInUse);
-#endif
- CachedRoot* frame = this;
- const CachedNode* node = frame->document();
- if (node == NULL)
- return NULL;
- if (mViewBounds.isEmpty())
- return NULL;
- resetClippedOut();
- setData();
- BestData bestData;
- innerMove(node, &bestData, direction, scroll, true);
- // if node is partially or fully concealed by layer, scroll it into view
- if (mRootLayer && bestData.mNode && !bestData.mNode->isInLayer()) {
-#if USE(ACCELERATED_COMPOSITING)
-#if DUMP_NAV_CACHE
- CachedLayer::Debug::printRootLayerAndroid(mRootLayer);
-#endif
- SkIRect original = bestData.mNode->cursorRingBounds(bestData.mFrame);
- DBG_NAV_LOGD("original=(%d,%d,w=%d,h=%d) scroll=(%d,%d)",
- original.fLeft, original.fTop, original.width(), original.height(),
- scroll->x(), scroll->y());
- original.offset(-scroll->x(), -scroll->y());
- SkRegion rings(original);
- SkTDArray<SkRect> region;
- mRootLayer->clipArea(&region);
- SkRegion layers;
- for (int index = 0; index < region.count(); index++) {
- SkIRect enclosing;
- region[index].round(&enclosing);
- rings.op(enclosing, SkRegion::kDifference_Op);
- layers.op(enclosing, SkRegion::kUnion_Op);
- }
- SkIRect layerBounds(layers.getBounds());
- SkIRect ringBounds(rings.getBounds());
- int scrollX = scroll->x();
- int scrollY = scroll->y();
- if (rings.getBounds() != original) {
- int topOverlap = layerBounds.fBottom - original.fTop;
- int bottomOverlap = original.fBottom - layerBounds.fTop;
- int leftOverlap = layerBounds.fRight - original.fLeft;
- int rightOverlap = original.fRight - layerBounds.fLeft;
- if (direction & UP_DOWN) {
- if (layerBounds.fLeft < original.fLeft && leftOverlap < 0)
- scroll->setX(leftOverlap);
- if (original.fRight < layerBounds.fRight && rightOverlap > 0
- && -leftOverlap > rightOverlap)
- scroll->setX(rightOverlap);
- bool topSet = scrollY > topOverlap && (direction == UP
- || !scrollY);
- if (topSet)
- scroll->setY(topOverlap);
- if (scrollY < bottomOverlap && (direction == DOWN || (!scrollY
- && (!topSet || -topOverlap > bottomOverlap))))
- scroll->setY(bottomOverlap);
- } else {
- if (layerBounds.fTop < original.fTop && topOverlap < 0)
- scroll->setY(topOverlap);
- if (original.fBottom < layerBounds.fBottom && bottomOverlap > 0
- && -topOverlap > bottomOverlap)
- scroll->setY(bottomOverlap);
- bool leftSet = scrollX > leftOverlap && (direction == LEFT
- || !scrollX);
- if (leftSet)
- scroll->setX(leftOverlap);
- if (scrollX < rightOverlap && (direction == RIGHT || (!scrollX
- && (!leftSet || -leftOverlap > rightOverlap))))
- scroll->setX(rightOverlap);
- }
- DBG_NAV_LOGD("rings=(%d,%d,w=%d,h=%d) layers=(%d,%d,w=%d,h=%d)"
- " scroll=(%d,%d)",
- ringBounds.fLeft, ringBounds.fTop, ringBounds.width(), ringBounds.height(),
- layerBounds.fLeft, layerBounds.fTop, layerBounds.width(), layerBounds.height(),
- scroll->x(), scroll->y());
- }
-#endif
- }
- *framePtr = bestData.mFrame;
- return const_cast<CachedNode*>(bestData.mNode);
-}
-
-const CachedNode* CachedRoot::nextTextField(const CachedNode* start,
- const CachedFrame** framePtr) const
-{
- bool startFound = false;
- return CachedFrame::nextTextField(start, framePtr, &startFound);
-}
-
-SkPicture* CachedRoot::pictureAt(int* xPtr, int* yPtr, int* id) const
-{
-#if USE(ACCELERATED_COMPOSITING)
- if (mRootLayer) {
- const LayerAndroid* layer = mRootLayer->find(xPtr, yPtr, mPicture);
- if (layer) {
- SkPicture* picture = layer->picture();
- DBG_NAV_LOGD("layer %d picture=%p (%d,%d)", layer->uniqueId(),
- picture, picture ? picture->width() : 0,
- picture ? picture->height() : 0);
- if (picture) {
- if (id)
- *id = layer->uniqueId();
- return picture;
- }
- }
- }
-#endif
- DBG_NAV_LOGD("root mPicture=%p (%d,%d)", mPicture, mPicture ?
- mPicture->width() : 0, mPicture ? mPicture->height() : 0);
- if (id)
- *id = -1;
- return mPicture;
-}
-
-void CachedRoot::reset()
-{
-#ifndef NDEBUG
- ASSERT(CachedFrame::mDebug.mInUse);
-#endif
- mContents = mViewBounds = WebCore::IntRect(0, 0, 0, 0);
- mMaxXScroll = mMaxYScroll = 0;
- mRootLayer = 0;
- mSelectionStart = mSelectionEnd = -1;
- mScrollOnly = false;
-}
-
-bool CachedRoot::scrollDelta(WebCore::IntRect& newOutset, Direction direction, int* delta)
-{
- switch (direction) {
- case LEFT:
- *delta = -mMaxXScroll;
- return newOutset.x() >= mViewBounds.x();
- case RIGHT:
- *delta = mMaxXScroll;
- return newOutset.maxX() <= mViewBounds.maxX();
- case UP:
- *delta = -mMaxYScroll;
- return newOutset.y() >= mViewBounds.y();
- case DOWN:
- *delta = mMaxYScroll;
- return newOutset.maxY() <= mViewBounds.maxY();
- default:
- *delta = 0;
- ASSERT(0);
- }
- return false;
-}
-
-void CachedRoot::setCachedFocus(CachedFrame* frame, CachedNode* node)
-{
- mFocusBounds = WebCore::IntRect(0, 0, 0, 0);
- if (node == NULL)
- return;
- node->setIsFocus(true);
- mFocusBounds = node->bounds(frame);
- frame->setFocusIndex(node - frame->document());
- CachedFrame* parent;
- while ((parent = frame->parent()) != NULL) {
- parent->setFocusIndex(frame->indexInParent());
- frame = parent;
- }
-#if DEBUG_NAV_UI
- const CachedFrame* focusFrame;
- const CachedNode* focus = currentFocus(&focusFrame);
- WebCore::IntRect bounds = WebCore::IntRect(0, 0, 0, 0);
- if (focus)
- bounds = focus->bounds(focusFrame);
- DBG_NAV_LOGD("new focus %d (nodePointer=%p) bounds={%d,%d,%d,%d}",
- focus ? focus->index() : 0,
- focus ? focus->nodePointer() : NULL, bounds.x(), bounds.y(),
- bounds.width(), bounds.height());
-#endif
-}
-
-void CachedRoot::setCursor(CachedFrame* frame, CachedNode* node)
-{
-#if DEBUG_NAV_UI
- const CachedFrame* cursorFrame;
- const CachedNode* cursor = currentCursor(&cursorFrame);
- WebCore::IntRect bounds;
- if (cursor)
- bounds = cursor->bounds(cursorFrame);
- DBG_NAV_LOGD("old cursor %d (nodePointer=%p) bounds={%d,%d,%d,%d}",
- cursor ? cursor->index() : 0,
- cursor ? cursor->nodePointer() : NULL, bounds.x(), bounds.y(),
- bounds.width(), bounds.height());
-#endif
- clearCursor();
- if (node == NULL)
- return;
- node->setIsCursor(true);
- node->show();
- frame->setCursorIndex(node - frame->document());
- CachedFrame* parent;
- while ((parent = frame->parent()) != NULL) {
- parent->setCursorIndex(frame->indexInParent());
- frame = parent;
- }
-#if DEBUG_NAV_UI
- cursor = currentCursor(&cursorFrame);
- bounds = WebCore::IntRect(0, 0, 0, 0);
- if (cursor)
- bounds = cursor->bounds(cursorFrame);
- DBG_NAV_LOGD("new cursor %d (nodePointer=%p) bounds={%d,%d,%d,%d}",
- cursor ? cursor->index() : 0,
- cursor ? cursor->nodePointer() : NULL, bounds.x(), bounds.y(),
- bounds.width(), bounds.height());
-#endif
-}
-
-void CachedRoot::setCursorCache(int scrollX, int scrollY) const
-{
- mCursor = currentCursor();
- if (mCursor)
- mCursorBounds = mCursor->bounds(this);
- if (!mRootLayer)
- return;
- SkRegion baseScrolled(mScrolledBounds);
- mBaseUncovered = SkRegion(mScrolledBounds);
-#if USE(ACCELERATED_COMPOSITING)
-#if DUMP_NAV_CACHE
- CachedLayer::Debug::printRootLayerAndroid(mRootLayer);
-#endif
- SkTDArray<SkRect> region;
- mRootLayer->clipArea(&region);
- WebCore::IntSize offset(
- copysign(min(max(0, mContents.width() - mScrolledBounds.width()),
- abs(scrollX)), scrollX),
- copysign(min(max(0, mContents.height() - mScrolledBounds.height()),
- abs(scrollY)), scrollY));
- bool hasOffset = offset.width() || offset.height();
- // restrict scrollBounds to that which is not under layer
- for (int index = 0; index < region.count(); index++) {
- SkIRect less;
- region[index].round(&less);
- DBG_NAV_LOGD("less=(%d,%d,w=%d,h=%d)", less.fLeft, less.fTop,
- less.width(), less.height());
- mBaseUncovered.op(less, SkRegion::kDifference_Op);
- if (!hasOffset)
- continue;
- less.offset(offset.width(), offset.height());
- baseScrolled.op(less, SkRegion::kDifference_Op);
- }
- if (hasOffset)
- mBaseUncovered.op(baseScrolled, SkRegion::kUnion_Op);
-#endif
-}
-
-#if DUMP_NAV_CACHE
-
-#define DEBUG_PRINT_BOOL(field) \
- DUMP_NAV_LOGD("// bool " #field "=%s;\n", b->field ? "true" : "false")
-
-#define DEBUG_PRINT_RECT(field) \
- { const WebCore::IntRect& r = b->field; \
- DUMP_NAV_LOGD("// IntRect " #field "={%d, %d, %d, %d};\n", \
- r.x(), r.y(), r.width(), r.height()); }
-
-CachedRoot* CachedRoot::Debug::base() const {
- CachedRoot* nav = (CachedRoot*) ((char*) this - OFFSETOF(CachedRoot, mDebug));
- return nav;
-}
-
-void CachedRoot::Debug::print() const
-{
-#ifdef DUMP_NAV_CACHE_USING_PRINTF
- gWriteLogMutex.lock();
- ASSERT(gNavCacheLogFile == NULL);
- gNavCacheLogFile = fopen(NAV_CACHE_LOG_FILE, "a");
-#endif
- CachedRoot* b = base();
- b->CachedFrame::mDebug.print();
- b->mHistory->mDebug.print(b);
- DUMP_NAV_LOGD("// int mMaxXScroll=%d, mMaxYScroll=%d;\n",
- b->mMaxXScroll, b->mMaxYScroll);
- if (b->mRootLayer)
- CachedLayer::Debug::printRootLayerAndroid(b->mRootLayer);
-#ifdef DUMP_NAV_CACHE_USING_PRINTF
- if (gNavCacheLogFile)
- fclose(gNavCacheLogFile);
- gNavCacheLogFile = NULL;
- gWriteLogMutex.unlock();
-#endif
-}
-
-#endif
-
-}
diff --git a/Source/WebKit/android/nav/CachedRoot.h b/Source/WebKit/android/nav/CachedRoot.h
deleted file mode 100644
index 65c6062..0000000
--- a/Source/WebKit/android/nav/CachedRoot.h
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright 2007, 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 CachedRoot_h
-#define CachedRoot_h
-
-#include "CachedFrame.h"
-#include "IntRect.h"
-#include "SkPicture.h"
-#include "SkRegion.h"
-#include "wtf/Vector.h"
-
-class SkRect;
-
-namespace WebCore {
- class LayerAndroid;
-}
-
-namespace android {
-
-class CachedHistory;
-class CachedNode;
-class FindCanvas;
-
-class CachedRoot : public CachedFrame {
-public:
- bool adjustForScroll(BestData* , Direction , WebCore::IntPoint* scrollPtr,
- bool findClosest);
- const SkRegion& baseUncovered() const { return mBaseUncovered; }
- void calcBitBounds(const IntRect& , IntRect* ) const;
- int checkForCenter(int x, int y) const;
- void checkForJiggle(int* ) const;
- bool checkRings(SkPicture* , const CachedNode* ,
- const WebCore::IntRect& testBounds) const;
- WebCore::IntPoint cursorLocation() const;
- int documentHeight() { return mContents.height(); }
- int documentWidth() { return mContents.width(); }
- void draw(FindCanvas& ) const;
- const CachedNode* findAt(const WebCore::IntRect& , const CachedFrame** ,
- int* x, int* y, bool checkForHidden) const;
- const WebCore::IntRect& focusBounds() const { return mFocusBounds; }
- WebCore::IntPoint focusLocation() const;
- int getAndResetSelectionEnd();
- int getAndResetSelectionStart();
- int getBlockLeftEdge(int x, int y, float scale) const;
- void getSimulatedMousePosition(WebCore::IntPoint* ) const;
- void init(WebCore::Frame* , CachedHistory* );
- bool innerDown(const CachedNode* , BestData* ) const;
- bool innerLeft(const CachedNode* , BestData* ) const;
- void innerMove(const CachedNode* ,BestData* bestData, Direction ,
- WebCore::IntPoint* scroll, bool firstCall);
- bool innerRight(const CachedNode* , BestData* ) const;
- bool innerUp(const CachedNode* , BestData* ) const;
- WTF::String imageURI(int x, int y) const;
- bool maskIfHidden(BestData* ) const;
- const CachedNode* moveCursor(Direction , const CachedFrame** , WebCore::IntPoint* scroll);
- /**
- * Find the next textfield/textarea
- * @param start The textfield/textarea to search from.
- * @param framePtr If non-zero, returns CachedFrame* containing result.
- * @return CachedNode* Next textfield/textarea or null (0) if none.
- */
- const CachedNode* nextTextField(const CachedNode* start,
- const CachedFrame** framePtr) const;
- SkPicture* pictureAt(int* xPtr, int* yPtr, int* id) const;
- SkPicture* pictureAt(int* xPtr, int* yPtr) const {
- return pictureAt(xPtr, yPtr, 0); }
- void reset();
- CachedHistory* rootHistory() const { return mHistory; }
- WebCore::LayerAndroid* rootLayer() const { return mRootLayer; }
- bool scrollDelta(WebCore::IntRect& cursorRingBounds, Direction , int* delta);
- const WebCore::IntRect& scrolledBounds() const { return mScrolledBounds; }
- void setCursor(CachedFrame* , CachedNode* );
- void setCursorCache(int scrollX, int scrollY) const; // compute cached state used to find next cursor
- void setCachedFocus(CachedFrame* , CachedNode* );
- void setFocusBounds(const WebCore::IntRect& r) { mFocusBounds = r; }
- void setTextGeneration(int textGeneration) { mTextGeneration = textGeneration; }
- void setMaxScroll(int x, int y) { mMaxXScroll = x; mMaxYScroll = y; }
- void setPicture(SkPicture* picture) { mPicture = picture; }
- void setRootLayer(WebCore::LayerAndroid* layer) {
- mRootLayer = layer;
- resetLayers();
- }
- void setScrollOnly(bool state) { mScrollOnly = state; }
- void setSelection(int start, int end) { mSelectionStart = start; mSelectionEnd = end; }
- void setupScrolledBounds() const { mScrolledBounds = mViewBounds; }
- void setVisibleRect(const WebCore::IntRect& r) { mViewBounds = r; }
- int textGeneration() const { return mTextGeneration; }
- int width() const { return mPicture ? mPicture->width() : 0; }
-private:
- friend class CachedFrame;
- CachedHistory* mHistory;
- SkPicture* mPicture;
- WebCore::LayerAndroid* mRootLayer;
- WebCore::IntRect mFocusBounds; // dom text input focus node bounds
- mutable WebCore::IntRect mScrolledBounds; // view bounds + amount visible as result of scroll
- int mTextGeneration;
- int mMaxXScroll;
- int mMaxYScroll;
- // These two are ONLY used when the tree is rebuilt and the focus is a textfield/area
- int mSelectionStart;
- int mSelectionEnd;
- // these four set up as cache for use by frameDown/Up/Left/Right etc
- mutable WebCore::IntRect mCursorBounds;
- mutable const CachedNode* mCursor;
- mutable SkRegion mBaseUncovered;
- bool mScrollOnly;
-#if DUMP_NAV_CACHE
-public:
- class Debug {
-public:
- CachedRoot* base() const;
- void print() const;
- } mDebug;
-#endif
-};
-
-}
-
-#endif
diff --git a/Source/WebKit/android/nav/DrawExtra.cpp b/Source/WebKit/android/nav/DrawExtra.cpp
new file mode 100644
index 0000000..2f57dc1
--- /dev/null
+++ b/Source/WebKit/android/nav/DrawExtra.cpp
@@ -0,0 +1,96 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+
+#include "DrawExtra.h"
+#include "GLExtras.h"
+#include "LayerAndroid.h"
+#include "SkCanvas.h"
+#include "SkRegion.h"
+#include "WebViewCore.h"
+
+RegionLayerDrawExtra::RegionLayerDrawExtra()
+ : m_highlightColor(COLOR_HOLO_LIGHT)
+{}
+
+RegionLayerDrawExtra::~RegionLayerDrawExtra()
+{
+ HighlightRegionMap::iterator end = m_highlightRegions.end();
+ for (HighlightRegionMap::iterator it = m_highlightRegions.begin(); it != end; ++it) {
+ delete it->second;
+ it->second = 0;
+ }
+}
+
+SkRegion* RegionLayerDrawExtra::getHighlightRegionsForLayer(const LayerAndroid* layer)
+{
+ int layerId = layer ? layer->uniqueId() : 0;
+ return m_highlightRegions.get(layerId);
+}
+
+void RegionLayerDrawExtra::addHighlightRegion(const LayerAndroid* layer, const Vector<IntRect>& rects,
+ const IntPoint& additionalOffset)
+{
+ if (rects.isEmpty())
+ return;
+ int layerId = layer ? layer->uniqueId() : 0;
+ SkRegion* region = m_highlightRegions.get(layerId);
+ if (!region) {
+ region = new SkRegion();
+ m_highlightRegions.set(layerId, region);
+ }
+ IntPoint offset = additionalOffset;
+ WebViewCore::layerToAbsoluteOffset(layer, offset);
+ for (size_t i = 0; i < rects.size(); i++) {
+ IntRect r = rects.at(i);
+ r.move(-offset.x(), -offset.y());
+ region->op(r.x(), r.y(), r.maxX(), r.maxY(), SkRegion::kUnion_Op);
+ }
+}
+
+void RegionLayerDrawExtra::draw(SkCanvas* canvas, LayerAndroid* layer)
+{
+ SkRegion* region = getHighlightRegionsForLayer(layer);
+ if (!region || region->isEmpty())
+ return;
+ SkRegion::Iterator rgnIter(*region);
+ SkPaint paint;
+ paint.setColor(m_highlightColor.rgb());
+ while (!rgnIter.done()) {
+ const SkIRect& rect = rgnIter.rect();
+ canvas->drawIRect(rect, paint);
+ rgnIter.next();
+ }
+}
+
+void RegionLayerDrawExtra::drawGL(GLExtras* glExtras, const LayerAndroid* layer)
+{
+ SkRegion* region = getHighlightRegionsForLayer(layer);
+ if (!region || region->isEmpty())
+ return;
+ const TransformationMatrix* transform = layer ? layer->drawTransform() : 0;
+ glExtras->drawRegion(*region, true, false, transform, m_highlightColor);
+}
diff --git a/Source/WebKit/android/nav/DrawExtra.h b/Source/WebKit/android/nav/DrawExtra.h
index 6716a65..cc94476 100644
--- a/Source/WebKit/android/nav/DrawExtra.h
+++ b/Source/WebKit/android/nav/DrawExtra.h
@@ -26,11 +26,25 @@
#ifndef DrawExtra_h
#define DrawExtra_h
+#include "config.h"
+
+#include "Color.h"
+#include "IntPoint.h"
+#include "IntRect.h"
+#include "wtf/HashMap.h"
+#include "wtf/Vector.h"
+
+// Color of the ring copied from framework's holo_light
+#define COLOR_HOLO_LIGHT 0x6633B5E5
+// Color of the ring copied from framework's holo_dark
+#define COLOR_HOLO_DARK 0x660099CC
+
class SkCanvas;
+class SkRegion;
namespace WebCore {
- class IntRect;
class LayerAndroid;
+ class GLExtras;
}
using namespace WebCore;
@@ -40,7 +54,27 @@ namespace android {
class DrawExtra {
public:
virtual ~DrawExtra() {}
- virtual void draw(SkCanvas* , LayerAndroid* , IntRect* ) = 0;
+ virtual void draw(SkCanvas*, LayerAndroid*) {}
+ virtual void drawGL(GLExtras*, const LayerAndroid*) {}
+};
+
+// A helper extra that has a SkRegion per LayerAndroid
+class RegionLayerDrawExtra : public DrawExtra {
+public:
+ RegionLayerDrawExtra();
+ virtual ~RegionLayerDrawExtra();
+
+ void addHighlightRegion(const LayerAndroid* layer, const Vector<IntRect>& rects,
+ const IntPoint& additionalOffset = IntPoint());
+ virtual void draw(SkCanvas*, LayerAndroid*);
+ virtual void drawGL(GLExtras*, const LayerAndroid*);
+
+private:
+ SkRegion* getHighlightRegionsForLayer(const LayerAndroid* layer);
+
+ typedef HashMap<int, SkRegion* > HighlightRegionMap;
+ HighlightRegionMap m_highlightRegions;
+ Color m_highlightColor;
};
}
diff --git a/Source/WebKit/android/nav/FindCanvas.cpp b/Source/WebKit/android/nav/FindCanvas.cpp
deleted file mode 100644
index ca3cfba..0000000
--- a/Source/WebKit/android/nav/FindCanvas.cpp
+++ /dev/null
@@ -1,700 +0,0 @@
-/*
- * Copyright 2008, 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 "webviewglue"
-
-#include "config.h"
-#include "FindCanvas.h"
-#include "LayerAndroid.h"
-#include "IntRect.h"
-#include "SelectText.h"
-#include "SkBlurMaskFilter.h"
-#include "SkCornerPathEffect.h"
-#include "SkRect.h"
-#include "SkUtils.h"
-
-#include <utils/Log.h>
-
-#define INTEGER_OUTSET 2
-
-namespace android {
-
-// MatchInfo methods
-////////////////////////////////////////////////////////////////////////////////
-
-MatchInfo::MatchInfo() {
- m_picture = 0;
-}
-
-MatchInfo::~MatchInfo() {
- SkSafeUnref(m_picture);
-}
-
-MatchInfo::MatchInfo(const MatchInfo& src) {
- m_layerId = src.m_layerId;
- m_location = src.m_location;
- m_picture = src.m_picture;
- SkSafeRef(m_picture);
-}
-
-void MatchInfo::set(const SkRegion& region, SkPicture* pic, int layerId) {
- SkSafeUnref(m_picture);
- m_layerId = layerId;
- m_location = region;
- m_picture = pic;
- SkASSERT(pic);
- pic->ref();
-}
-
-// GlyphSet methods
-////////////////////////////////////////////////////////////////////////////////
-
-GlyphSet::GlyphSet(const SkPaint& paint, const UChar* lower, const UChar* upper,
- size_t byteLength) {
- SkPaint clonePaint(paint);
- clonePaint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
- mTypeface = paint.getTypeface();
- mCount = clonePaint.textToGlyphs(lower, byteLength, NULL);
- if (mCount > MAX_STORAGE_COUNT) {
- mLowerGlyphs = new uint16_t[2*mCount];
- } else {
- mLowerGlyphs = &mStorage[0];
- }
- // Use one array, and have mUpperGlyphs point to a portion of it,
- // so that we can reduce the number of new/deletes
- mUpperGlyphs = mLowerGlyphs + mCount;
- int count2 = clonePaint.textToGlyphs(lower, byteLength, mLowerGlyphs);
- SkASSERT(mCount == count2);
- count2 = clonePaint.textToGlyphs(upper, byteLength, mUpperGlyphs);
- SkASSERT(mCount == count2);
-}
-
-GlyphSet::~GlyphSet() {
- // Do not need to delete mTypeface, which is not owned by us.
- if (mCount > MAX_STORAGE_COUNT) {
- delete[] mLowerGlyphs;
- } // Otherwise, we just used local storage space, so no need to delete
- // Also do not need to delete mUpperGlyphs, which simply points to a
- // part of mLowerGlyphs
-}
-
-GlyphSet& GlyphSet::operator=(GlyphSet& src) {
- mTypeface = src.mTypeface;
- mCount = src.mCount;
- if (mCount > MAX_STORAGE_COUNT) {
- mLowerGlyphs = new uint16_t[2*mCount];
- } else {
- mLowerGlyphs = &mStorage[0];
- }
- memcpy(mLowerGlyphs, src.mLowerGlyphs, 2*mCount*sizeof(uint16_t));
- mUpperGlyphs = mLowerGlyphs + mCount;
- return *this;
-}
-
-bool GlyphSet::characterMatches(uint16_t c, int index) {
- SkASSERT(index < mCount && index >= 0);
- return c == mLowerGlyphs[index] || c == mUpperGlyphs[index];
-}
-
-// FindCanvas methods
-////////////////////////////////////////////////////////////////////////////////
-
-FindCanvas::FindCanvas(int width, int height, const UChar* lower,
- const UChar* upper, size_t byteLength)
- : mLowerText(lower)
- , mUpperText(upper)
- , mLength(byteLength)
- , mNumFound(0) {
- // the text has been provided in read order. Reverse as needed so the
- // result contains left-to-right characters.
- const uint16_t* start = mLowerText;
- size_t count = byteLength >> 1;
- const uint16_t* end = mLowerText + count;
- while (start < end) {
- SkUnichar ch = SkUTF16_NextUnichar(&start);
- WTF::Unicode::Direction charDirection = WTF::Unicode::direction(ch);
- if (WTF::Unicode::RightToLeftArabic == charDirection
- || WTF::Unicode::RightToLeft == charDirection) {
- mLowerReversed.clear();
- mLowerReversed.append(mLowerText, count);
- WebCore::ReverseBidi(mLowerReversed.begin(), count);
- mLowerText = mLowerReversed.begin();
- mUpperReversed.clear();
- mUpperReversed.append(mUpperText, count);
- WebCore::ReverseBidi(mUpperReversed.begin(), count);
- mUpperText = mUpperReversed.begin();
- break;
- }
- }
-
- setBounder(&mBounder);
- mOutset = -SkIntToScalar(INTEGER_OUTSET);
- mMatches = new WTF::Vector<MatchInfo>();
- mWorkingIndex = 0;
- mWorkingCanvas = 0;
- mWorkingPicture = 0;
-}
-
-FindCanvas::~FindCanvas() {
- setBounder(NULL);
- /* Just in case getAndClear was not called. */
- delete mMatches;
- SkSafeUnref(mWorkingPicture);
-}
-
-// Each version of addMatch returns a rectangle for a match.
-// Not all of the parameters are used by each version.
-SkRect FindCanvas::addMatchNormal(int index,
- const SkPaint& paint, int count, const uint16_t* glyphs,
- const SkScalar pos[], SkScalar y) {
- const uint16_t* lineStart = glyphs - index;
- /* Use the original paint, since "text" is in glyphs */
- SkScalar before = paint.measureText(lineStart, index * sizeof(uint16_t), 0);
- SkRect rect;
- rect.fLeft = pos[0] + before;
- int countInBytes = count * sizeof(uint16_t);
- rect.fRight = paint.measureText(glyphs, countInBytes, 0) + rect.fLeft;
- SkPaint::FontMetrics fontMetrics;
- paint.getFontMetrics(&fontMetrics);
- SkScalar baseline = y;
- rect.fTop = baseline + fontMetrics.fAscent;
- rect.fBottom = baseline + fontMetrics.fDescent;
- const SkMatrix& matrix = getTotalMatrix();
- matrix.mapRect(&rect);
- // Add the text to our picture.
- SkCanvas* canvas = getWorkingCanvas();
- int saveCount = canvas->save();
- canvas->concat(matrix);
- canvas->drawText(glyphs, countInBytes, pos[0] + before, y, paint);
- canvas->restoreToCount(saveCount);
- return rect;
-}
-
-SkRect FindCanvas::addMatchPos(int index,
- const SkPaint& paint, int count, const uint16_t* glyphs,
- const SkScalar xPos[], SkScalar /* y */) {
- SkRect r;
- r.setEmpty();
- const SkPoint* temp = reinterpret_cast<const SkPoint*> (xPos);
- const SkPoint* points = &temp[index];
- int countInBytes = count * sizeof(uint16_t);
- SkPaint::FontMetrics fontMetrics;
- paint.getFontMetrics(&fontMetrics);
- // Need to check each character individually, since the heights may be
- // different.
- for (int j = 0; j < count; j++) {
- SkRect bounds;
- bounds.fLeft = points[j].fX;
- bounds.fRight = bounds.fLeft +
- paint.measureText(&glyphs[j], sizeof(uint16_t), 0);
- SkScalar baseline = points[j].fY;
- bounds.fTop = baseline + fontMetrics.fAscent;
- bounds.fBottom = baseline + fontMetrics.fDescent;
- /* Accumulate and then add the resulting rect to mMatches */
- r.join(bounds);
- }
- SkMatrix matrix = getTotalMatrix();
- matrix.mapRect(&r);
- SkCanvas* canvas = getWorkingCanvas();
- int saveCount = canvas->save();
- canvas->concat(matrix);
- canvas->drawPosText(glyphs, countInBytes, points, paint);
- canvas->restoreToCount(saveCount);
- return r;
-}
-
-SkRect FindCanvas::addMatchPosH(int index,
- const SkPaint& paint, int count, const uint16_t* glyphs,
- const SkScalar position[], SkScalar constY) {
- SkRect r;
- // We only care about the positions starting at the index of our match
- const SkScalar* xPos = &position[index];
- // This assumes that the position array is monotonic increasing
- // The left bounds will be the position of the left most character
- r.fLeft = xPos[0];
- // The right bounds will be the position of the last character plus its
- // width
- int lastIndex = count - 1;
- r.fRight = paint.measureText(&glyphs[lastIndex], sizeof(uint16_t), 0)
- + xPos[lastIndex];
- // Grab font metrics to determine the top and bottom of the bounds
- SkPaint::FontMetrics fontMetrics;
- paint.getFontMetrics(&fontMetrics);
- r.fTop = constY + fontMetrics.fAscent;
- r.fBottom = constY + fontMetrics.fDescent;
- const SkMatrix& matrix = getTotalMatrix();
- matrix.mapRect(&r);
- SkCanvas* canvas = getWorkingCanvas();
- int saveCount = canvas->save();
- canvas->concat(matrix);
- canvas->drawPosTextH(glyphs, count * sizeof(uint16_t), xPos, constY, paint);
- canvas->restoreToCount(saveCount);
- return r;
-}
-
-void FindCanvas::drawLayers(LayerAndroid* layer) {
-#if USE(ACCELERATED_COMPOSITING)
- SkPicture* picture = layer->picture();
- if (picture) {
- setLayerId(layer->uniqueId());
- drawPicture(*picture);
- }
- for (int i = 0; i < layer->countChildren(); i++)
- drawLayers(layer->getChild(i));
-#endif
-}
-
-void FindCanvas::drawText(const void* text, size_t byteLength, SkScalar x,
- SkScalar y, const SkPaint& paint) {
- findHelper(text, byteLength, paint, &x, y, &FindCanvas::addMatchNormal);
-}
-
-void FindCanvas::drawPosText(const void* text, size_t byteLength,
- const SkPoint pos[], const SkPaint& paint) {
- // Pass in the first y coordinate for y so that we can check to see whether
- // it is lower than the last draw call (to check if we are continuing to
- // another line).
- findHelper(text, byteLength, paint, (const SkScalar*) pos, pos[0].fY,
- &FindCanvas::addMatchPos);
-}
-
-void FindCanvas::drawPosTextH(const void* text, size_t byteLength,
- const SkScalar xpos[], SkScalar constY,
- const SkPaint& paint) {
- findHelper(text, byteLength, paint, xpos, constY,
- &FindCanvas::addMatchPosH);
-}
-
-/* The current behavior is to skip substring matches. This means that in the
- * string
- * batbatbat
- * a search for
- * batbat
- * will return 1 match. If the desired behavior is to return 2 matches, define
- * INCLUDE_SUBSTRING_MATCHES to be 1.
- */
-#define INCLUDE_SUBSTRING_MATCHES 0
-
-// Need a quick way to know a maximum distance between drawText calls to know if
-// they are part of the same logical phrase when searching. By crude
-// inspection, half the point size seems a good guess at the width of a space
-// character.
-static inline SkScalar approximateSpaceWidth(const SkPaint& paint) {
- return SkScalarHalf(paint.getTextSize());
-}
-
-void FindCanvas::findHelper(const void* text, size_t byteLength,
- const SkPaint& paint, const SkScalar positions[],
- SkScalar y,
- SkRect (FindCanvas::*addMatch)(int index,
- const SkPaint& paint, int count,
- const uint16_t* glyphs,
- const SkScalar positions[], SkScalar y)) {
- SkASSERT(paint.getTextEncoding() == SkPaint::kGlyphID_TextEncoding);
- SkASSERT(mMatches);
- GlyphSet* glyphSet = getGlyphs(paint);
- const int count = glyphSet->getCount();
- int numCharacters = byteLength >> 1;
- const uint16_t* chars = (const uint16_t*) text;
- // This block will check to see if we are continuing from another line. If
- // so, the user needs to have added a space, which we do not draw.
- if (mWorkingIndex) {
- SkPoint newY;
- getTotalMatrix().mapXY(0, y, &newY);
- SkIRect workingBounds = mWorkingRegion.getBounds();
- int newYInt = SkScalarRound(newY.fY);
- if (workingBounds.fTop > newYInt) {
- // The new text is above the working region, so we know it's not
- // a continuation.
- resetWorkingCanvas();
- mWorkingIndex = 0;
- mWorkingRegion.setEmpty();
- } else if (workingBounds.fBottom < newYInt) {
- // Now we know that this line is lower than our partial match.
- SkPaint clonePaint(paint);
- clonePaint.setTextEncoding(SkPaint::kUTF8_TextEncoding);
- uint16_t space;
- clonePaint.textToGlyphs(" ", 1, &space);
- if (glyphSet->characterMatches(space, mWorkingIndex)) {
- mWorkingIndex++;
- if (mWorkingIndex == count) {
- // We already know that it is not clipped out because we
- // checked for that before saving the working region.
- insertMatchInfo(mWorkingRegion);
-
- resetWorkingCanvas();
- mWorkingIndex = 0;
- mWorkingRegion.setEmpty();
- // We have found a match, so continue on this line from
- // scratch.
- }
- } else {
- resetWorkingCanvas();
- mWorkingIndex = 0;
- mWorkingRegion.setEmpty();
- }
- }
- // If neither one is true, then we are likely continuing on the same
- // line, but are in a new draw call because the paint has changed. In
- // this case, we can continue without adding a space.
- }
- // j is the position in the search text
- // Start off with mWorkingIndex in case we are continuing from a prior call
- int j = mWorkingIndex;
- // index is the position in the drawn text
- int index = 0;
- for ( ; index != numCharacters; index++) {
- if (glyphSet->characterMatches(chars[index], j)) {
- // The jth character in the search text matches the indexth position
- // in the drawn text, so increase j.
- j++;
- if (j != count) {
- continue;
- }
- // The last count characters match, so we found the entire
- // search string.
- int remaining = count - mWorkingIndex;
- int matchIndex = index - remaining + 1;
- // Set up a pointer to the matching text in 'chars'.
- const uint16_t* glyphs = chars + matchIndex;
- SkRect rect = (this->*addMatch)(matchIndex, paint,
- remaining, glyphs, positions, y);
- // We need an SkIRect for SkRegion operations.
- SkIRect iRect;
- rect.roundOut(&iRect);
- // Want to outset the drawn rectangle by the same amount as
- // mOutset
- iRect.inset(-INTEGER_OUTSET, -INTEGER_OUTSET);
- SkRegion regionToAdd(iRect);
- if (!mWorkingRegion.isEmpty()) {
- // If this is on the same line as our working region, make
- // sure that they are close enough together that they are
- // supposed to be part of the same text string.
- // The width of two spaces has arbitrarily been chosen.
- const SkIRect& workingBounds = mWorkingRegion.getBounds();
- if (workingBounds.fTop <= iRect.fBottom &&
- workingBounds.fBottom >= iRect.fTop &&
- SkIntToScalar(iRect.fLeft - workingBounds.fRight) >
- approximateSpaceWidth(paint)) {
- index = -1; // Will increase to 0 on next run
- // In this case, we need to start from the beginning of
- // the text being searched and our search term.
- j = 0;
- mWorkingIndex = 0;
- mWorkingRegion.setEmpty();
- continue;
- }
- // Add the mWorkingRegion, which contains rectangles from
- // the previous line(s).
- regionToAdd.op(mWorkingRegion, SkRegion::kUnion_Op);
- }
- insertMatchInfo(regionToAdd);
-#if INCLUDE_SUBSTRING_MATCHES
- // Reset index to the location of the match and reset j to the
- // beginning, so that on the next iteration of the loop, index
- // will advance by 1 and we will compare the next character in
- // chars to the first character in the GlyphSet.
- index = matchIndex;
-#endif
- // Whether the clip contained it or not, we need to start over
- // with our recording canvas
- resetWorkingCanvas();
- } else {
- // Index needs to be set to index - j + 1.
- // This is a ridiculous case, but imagine the situation where the
- // user is looking for the string "jjog" in the drawText call for
- // "jjjog". The first two letters match. However, when the index
- // is 2, and we discover that 'o' and 'j' do not match, we should go
- // back to 1, where we do, in fact, have a match
- // FIXME: This does not work if (as in our example) "jj" is in one
- // draw call and "jog" is in the next. Doing so would require a
- // stack, keeping track of multiple possible working indeces and
- // regions. This is likely an uncommon case.
- index = index - j; // index will be increased by one on the next
- // iteration
- }
- // We reach here in one of two cases:
- // 1) We just completed a match, so any working rectangle/index is no
- // longer needed, and we will start over from the beginning
- // 2) The glyphs do not match, so we start over at the beginning of
- // the search string.
- j = 0;
- mWorkingIndex = 0;
- mWorkingRegion.setEmpty();
- }
- // At this point, we have searched all of the text in the current drawText
- // call.
- // Keep track of a partial match that may start on this line.
- if (j > 0) { // if j is greater than 0, we have a partial match
- int relativeCount = j - mWorkingIndex; // Number of characters in this
- // part of the match.
- int partialIndex = index - relativeCount; // Index that starts our
- // partial match.
- const uint16_t* partialGlyphs = chars + partialIndex;
- SkRect partial = (this->*addMatch)(partialIndex, paint, relativeCount,
- partialGlyphs, positions, y);
- partial.inset(mOutset, mOutset);
- SkIRect dest;
- partial.roundOut(&dest);
- mWorkingRegion.op(dest, SkRegion::kUnion_Op);
- mWorkingIndex = j;
- return;
- }
- // This string doesn't go into the next drawText, so reset our working
- // variables
- mWorkingRegion.setEmpty();
- mWorkingIndex = 0;
-}
-
-SkCanvas* FindCanvas::getWorkingCanvas() {
- if (!mWorkingPicture) {
- mWorkingPicture = new SkPicture;
- mWorkingCanvas = mWorkingPicture->beginRecording(0,0);
- }
- return mWorkingCanvas;
-}
-
-GlyphSet* FindCanvas::getGlyphs(const SkPaint& paint) {
- SkTypeface* typeface = paint.getTypeface();
- GlyphSet* end = mGlyphSets.end();
- for (GlyphSet* ptr = mGlyphSets.begin();ptr != end; ptr++) {
- if (ptr->getTypeface() == typeface) {
- return ptr;
- }
- }
-
- GlyphSet set(paint, mLowerText, mUpperText, mLength);
- *mGlyphSets.append() = set;
- return &(mGlyphSets.top());
-}
-
-void FindCanvas::insertMatchInfo(const SkRegion& region) {
- mNumFound++;
- mWorkingPicture->endRecording();
- MatchInfo matchInfo;
- mMatches->append(matchInfo);
- LOGD("%s region=%p pict=%p layer=%d", __FUNCTION__,
- &region, mWorkingPicture, mLayerId);
- mMatches->last().set(region, mWorkingPicture, mLayerId);
-}
-
-void FindCanvas::resetWorkingCanvas() {
- mWorkingPicture->unref();
- mWorkingPicture = 0;
- // Do not need to reset mWorkingCanvas itself because we only access it via
- // getWorkingCanvas.
-}
-
-// This function sets up the paints that are used to draw the matches.
-void FindOnPage::setUpFindPaint() {
- // Set up the foreground paint
- m_findPaint.setAntiAlias(true);
- const SkScalar roundiness = SkIntToScalar(2);
- SkCornerPathEffect* cornerEffect = new SkCornerPathEffect(roundiness);
- m_findPaint.setPathEffect(cornerEffect);
- m_findPaint.setARGB(255, 132, 190, 0);
-
- // Set up the background blur paint.
- m_findBlurPaint.setAntiAlias(true);
- m_findBlurPaint.setARGB(204, 0, 0, 0);
- m_findBlurPaint.setPathEffect(cornerEffect);
- cornerEffect->unref();
- SkMaskFilter* blurFilter = SkBlurMaskFilter::Create(SK_Scalar1,
- SkBlurMaskFilter::kNormal_BlurStyle);
- m_findBlurPaint.setMaskFilter(blurFilter)->unref();
- m_isFindPaintSetUp = true;
-}
-
-IntRect FindOnPage::currentMatchBounds() const {
- IntRect noBounds = IntRect(0, 0, 0, 0);
- if (!m_matches || !m_matches->size())
- return noBounds;
- MatchInfo& info = (*m_matches)[m_findIndex];
- return info.getLocation().getBounds();
-}
-
-bool FindOnPage::currentMatchIsInLayer() const {
- if (!m_matches || !m_matches->size())
- return false;
- MatchInfo& info = (*m_matches)[m_findIndex];
- return info.isInLayer();
-}
-
-int FindOnPage::currentMatchLayerId() const {
- return (*m_matches)[m_findIndex].layerId();
-}
-
-// This function is only used by findNext and setMatches. In it, we store
-// upper left corner of the match specified by m_findIndex in
-// m_currentMatchLocation.
-void FindOnPage::storeCurrentMatchLocation() {
- SkASSERT(m_findIndex < m_matches->size());
- const SkIRect& bounds = (*m_matches)[m_findIndex].getLocation().getBounds();
- m_currentMatchLocation.set(bounds.fLeft, bounds.fTop);
- m_hasCurrentLocation = true;
-}
-
-// Put a cap on the number of matches to draw. If the current page has more
-// matches than this, only draw the focused match.
-#define MAX_NUMBER_OF_MATCHES_TO_DRAW 101
-
-void FindOnPage::draw(SkCanvas* canvas, LayerAndroid* layer, IntRect* inval) {
- if (!m_lastBounds.isEmpty()) {
- inval->unite(m_lastBounds);
- m_lastBounds.setEmpty();
- }
- if (!m_hasCurrentLocation || !m_matches || !m_matches->size())
- return;
- int layerId = layer->uniqueId();
- if (m_findIndex >= m_matches->size())
- m_findIndex = 0;
- const MatchInfo& matchInfo = (*m_matches)[m_findIndex];
- const SkRegion& currentMatchRegion = matchInfo.getLocation();
-
- // Set up the paints used for drawing the matches
- if (!m_isFindPaintSetUp)
- setUpFindPaint();
-
- // Draw the current match
- if (matchInfo.layerId() == layerId) {
- drawMatch(currentMatchRegion, canvas, true);
- // Now draw the picture, so that it shows up on top of the rectangle
- int saveCount = canvas->save();
- SkPath matchPath;
- currentMatchRegion.getBoundaryPath(&matchPath);
- canvas->clipPath(matchPath);
- canvas->drawPicture(*matchInfo.getPicture());
- canvas->restoreToCount(saveCount);
- const SkMatrix& matrix = canvas->getTotalMatrix();
- const SkRect& localBounds = matchPath.getBounds();
- SkRect globalBounds;
- matrix.mapRect(&globalBounds, localBounds);
- globalBounds.round(&m_lastBounds);
- inval->unite(m_lastBounds);
- }
- // Draw the rest
- unsigned numberOfMatches = m_matches->size();
- if (numberOfMatches > 1
- && numberOfMatches < MAX_NUMBER_OF_MATCHES_TO_DRAW) {
- for (unsigned i = 0; i < numberOfMatches; i++) {
- // The current match has already been drawn
- if (i == m_findIndex)
- continue;
- if ((*m_matches)[i].layerId() != layerId)
- continue;
- const SkRegion& region = (*m_matches)[i].getLocation();
- // Do not draw matches which intersect the current one, or if it is
- // offscreen
- if (currentMatchRegion.intersects(region))
- continue;
- SkRect bounds;
- bounds.set(region.getBounds());
- if (canvas->quickReject(bounds, SkCanvas::kAA_EdgeType))
- continue;
- drawMatch(region, canvas, false);
- }
- }
-}
-
-// Draw the match specified by region to the canvas.
-void FindOnPage::drawMatch(const SkRegion& region, SkCanvas* canvas,
- bool focused)
-{
- // For the match which has focus, use a filled paint. For the others, use
- // a stroked paint.
- if (focused) {
- m_findPaint.setStyle(SkPaint::kFill_Style);
- m_findBlurPaint.setStyle(SkPaint::kFill_Style);
- } else {
- m_findPaint.setStyle(SkPaint::kStroke_Style);
- m_findPaint.setStrokeWidth(SK_Scalar1);
- m_findBlurPaint.setStyle(SkPaint::kStroke_Style);
- m_findBlurPaint.setStrokeWidth(SkIntToScalar(2));
- }
- // Find the path for the current match
- SkPath matchPath;
- region.getBoundaryPath(&matchPath);
- // Offset the path for a blurred shadow
- SkPath blurPath;
- matchPath.offset(SK_Scalar1, SkIntToScalar(2), &blurPath);
- int saveCount = 0;
- if (!focused) {
- saveCount = canvas->save();
- canvas->clipPath(matchPath, SkRegion::kDifference_Op);
- }
- // Draw the blurred background
- canvas->drawPath(blurPath, m_findBlurPaint);
- if (!focused)
- canvas->restoreToCount(saveCount);
- // Draw the foreground
- canvas->drawPath(matchPath, m_findPaint);
-}
-
-void FindOnPage::findNext(bool forward)
-{
- if (!m_matches || !m_matches->size() || !m_hasCurrentLocation)
- return;
- if (forward) {
- m_findIndex++;
- if (m_findIndex == m_matches->size())
- m_findIndex = 0;
- } else {
- if (m_findIndex == 0) {
- m_findIndex = m_matches->size() - 1;
- } else {
- m_findIndex--;
- }
- }
- storeCurrentMatchLocation();
-}
-
-// With this call, WebView takes ownership of matches, and is responsible for
-// deleting it.
-void FindOnPage::setMatches(WTF::Vector<MatchInfo>* matches)
-{
- if (m_matches)
- delete m_matches;
- m_matches = matches;
- if (m_matches->size()) {
- if (m_hasCurrentLocation) {
- for (unsigned i = 0; i < m_matches->size(); i++) {
- const SkIRect& rect = (*m_matches)[i].getLocation().getBounds();
- if (rect.fLeft == m_currentMatchLocation.fX
- && rect.fTop == m_currentMatchLocation.fY) {
- m_findIndex = i;
- return;
- }
- }
- }
- // If we did not have a stored location, or if we were unable to restore
- // it, store the new one.
- m_findIndex = 0;
- storeCurrentMatchLocation();
- } else {
- m_hasCurrentLocation = false;
- }
-}
-
-}
diff --git a/Source/WebKit/android/nav/FindCanvas.h b/Source/WebKit/android/nav/FindCanvas.h
deleted file mode 100644
index 0fa095c..0000000
--- a/Source/WebKit/android/nav/FindCanvas.h
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- * Copyright 2008, 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 Find_Canvas_h
-#define Find_Canvas_h
-
-#include "DrawExtra.h"
-#include "IntRect.h"
-#include "SkBounder.h"
-#include "SkCanvas.h"
-#include "SkPicture.h"
-#include "SkRect.h"
-#include "SkRegion.h"
-#include "SkTDArray.h"
-
-#include <unicode/umachine.h>
-#include <wtf/Vector.h>
-
-namespace android {
-
-// Stores both region information and an SkPicture of the match, so that the
-// region can be drawn, followed by drawing the matching text on top of it.
-// This class owns its SkPicture
-class MatchInfo {
-public:
- MatchInfo();
- ~MatchInfo();
- MatchInfo(const MatchInfo& src);
- const SkRegion& getLocation() const { return m_location; }
- // Return a pointer to our picture, representing the matching text. Does
- // not transfer ownership of the picture.
- SkPicture* getPicture() const { return m_picture; }
- // This will make a copy of the region, and increase the ref count on the
- // SkPicture. If this MatchInfo already had one, unref it.
- void set(const SkRegion& region, SkPicture* pic, int layerId);
- bool isInLayer() const { return m_layerId >= 0; }
- int layerId() const { return m_layerId; }
-private:
- MatchInfo& operator=(MatchInfo& src);
- SkRegion m_location;
- SkPicture* m_picture;
- int m_layerId;
-};
-
-// A class containing a typeface for reference, the length in glyphs, and
-// the upper and lower case representations of the search string.
-class GlyphSet {
-public:
- GlyphSet(const SkPaint& paint, const UChar* lower, const UChar* upper,
- size_t byteLength);
- ~GlyphSet();
- GlyphSet& operator=(GlyphSet& src);
-
- // Return true iff c matches one of our glyph arrays at index
- bool characterMatches(uint16_t c, int index);
-
- int getCount() const { return mCount; }
-
- const SkTypeface* getTypeface() const { return mTypeface; }
-
-private:
- // Disallow copy constructor
- GlyphSet(GlyphSet& src) { }
-
- // mTypeface is used for comparison only
- const SkTypeface* mTypeface;
- // mLowerGlyphs points to all of our storage space: the lower set followed
- // by the upper set. mUpperGlyphs is purely a convenience pointer to the
- // start of the upper case glyphs.
- uint16_t* mLowerGlyphs;
- uint16_t* mUpperGlyphs;
- // mCount is the number of glyphs of the search string. Must be the same
- // for both the lower case set and the upper case set.
- int mCount;
-
- // Arbitrarily chose the maximum storage to use in the GlyphSet. This is
- // based on the length of the word being searched. If users are always
- // searching for 3 letter words (for example), an ideal number would be 3.
- // Each time the user searches for a word longer than (in this case, 3) that
- // will result in calling new/delete.
- enum Storage {
- MAX_STORAGE_COUNT = 16
- };
- // In order to eliminate new/deletes, create storage that will be enough
- // most of the time
- uint16_t mStorage[2*MAX_STORAGE_COUNT];
-};
-
-class FindBounder : public SkBounder {
-public:
- FindBounder() {}
- ~FindBounder() {}
-protected:
- virtual bool onIRect(const SkIRect&) { return false; }
-};
-
-class FindCanvas : public SkCanvas {
-public:
- FindCanvas(int width, int height, const UChar* , const UChar*,
- size_t byteLength);
-
- virtual ~FindCanvas();
-
- virtual void drawText(const void* text, size_t byteLength, SkScalar x,
- SkScalar y, const SkPaint& paint);
-
- /* FIXME: This path has not been tested. */
- virtual void drawPosText(const void* text, size_t byteLength,
- const SkPoint pos[], const SkPaint& paint);
-
- /* Also untested */
- virtual void drawPosTextH(const void* text, size_t byteLength,
- const SkScalar xpos[], SkScalar constY,
- const SkPaint& paint);
-
- /* Not sure what to do here or for drawTextOnPathHV */
- virtual void drawTextOnPath(const void* text, size_t byteLength,
- const SkPath& path, const SkMatrix* matrix,
- const SkPaint& paint) {
- }
-
- void drawLayers(LayerAndroid*);
- int found() const { return mNumFound; }
- void setLayerId(int layerId) { mLayerId = layerId; }
-
- // This method detaches our array of matches and passes ownership to
- // the caller, who is then responsible for deleting them.
- WTF::Vector<MatchInfo>* detachMatches() {
- WTF::Vector<MatchInfo>* array = mMatches;
- mMatches = NULL;
- return array;
- }
-
-private:
- // These calls are made by findHelper to store information about each match
- // that is found. They return a rectangle which is used to highlight the
- // match. They also add to our SkPicture (which can be accessed with
- // getDrawnMatches) a draw of each match. This way it can be drawn after
- // the rectangle. The rect that is returned is in device coordinates.
- SkRect addMatchNormal(int index,
- const SkPaint& paint, int count, const uint16_t* glyphs,
- const SkScalar pos[], SkScalar y);
-
- SkRect addMatchPos(int index,
- const SkPaint& paint, int count, const uint16_t* glyphs,
- const SkScalar xPos[], SkScalar /* y */);
-
- SkRect addMatchPosH(int index,
- const SkPaint& paint, int count, const uint16_t* glyphs,
- const SkScalar position[], SkScalar constY);
-
- // Helper for each of our draw calls
- void findHelper(const void* text, size_t byteLength, const SkPaint& paint,
- const SkScalar xPos[], SkScalar y,
- SkRect (FindCanvas::*addMatch)(int index,
- const SkPaint& paint, int count, const uint16_t* glyphs,
- const SkScalar pos[], SkScalar y));
-
- // If we already have a working canvas, grab it. Otherwise, create a new
- // one.
- SkCanvas* getWorkingCanvas();
-
- // Return the set of glyphs and its count for the text being searched for
- // and the parameter paint. If one has already been created and cached
- // for this paint, use it. If not, create a new one and cache it.
- GlyphSet* getGlyphs(const SkPaint& paint);
-
- // Store all the accumulated info about a match in our vector.
- void insertMatchInfo(const SkRegion& region);
-
- // Throw away our cumulative information about our working SkCanvas. After
- // this call, next call to getWorkingCanvas will create a new one.
- void resetWorkingCanvas();
-
- // Since we may transfer ownership of this array (see detachRects()), we
- // hold a pointer to the array instead of just the array itself.
- WTF::Vector<MatchInfo>* mMatches;
- const UChar* mLowerText;
- const UChar* mUpperText;
- Vector<UChar> mLowerReversed;
- Vector<UChar> mUpperReversed;
- size_t mLength;
- FindBounder mBounder;
- int mNumFound;
- SkScalar mOutset;
- SkTDArray<GlyphSet> mGlyphSets;
-
- SkPicture* mWorkingPicture;
- SkCanvas* mWorkingCanvas;
- SkRegion mWorkingRegion;
- int mWorkingIndex;
- int mLayerId;
-};
-
-class FindOnPage : public DrawExtra {
-public:
- FindOnPage() {
- m_matches = 0;
- m_hasCurrentLocation = false;
- m_isFindPaintSetUp = false;
- m_lastBounds.setEmpty();
- }
- virtual ~FindOnPage() { if (m_matches) delete m_matches; }
- void clearCurrentLocation() { m_hasCurrentLocation = false; }
- IntRect currentMatchBounds() const;
- int currentMatchIndex() const { return m_findIndex; }
- bool currentMatchIsInLayer() const;
- // This requires the current match to be in a layer. See
- // currentMatchIsInLayer().
- int currentMatchLayerId() const;
- virtual void draw(SkCanvas* , LayerAndroid* , IntRect* );
- void findNext(bool forward);
- bool isCurrentLocationValid() { return m_hasCurrentLocation; }
- void setMatches(WTF::Vector<MatchInfo>* matches);
- WTF::Vector<MatchInfo>* matches() { return m_matches; }
-private:
- void drawMatch(const SkRegion& region, SkCanvas* canvas, bool focused);
- void setUpFindPaint();
- void storeCurrentMatchLocation();
- WTF::Vector<MatchInfo>* m_matches;
- // Stores the location of the current match.
- SkIPoint m_currentMatchLocation;
- // Tells whether the value in m_currentMatchLocation is valid.
- bool m_hasCurrentLocation;
- // Tells whether we have done the setup to draw the Find matches.
- bool m_isFindPaintSetUp;
- // Paint used to draw our Find matches.
- SkPaint m_findPaint;
- // Paint used for the background of our Find matches.
- SkPaint m_findBlurPaint;
- unsigned m_findIndex;
- SkIRect m_lastBounds;
-};
-
-}
-
-#endif // Find_Canvas_h
diff --git a/Source/WebKit/android/nav/SelectText.cpp b/Source/WebKit/android/nav/SelectText.cpp
index d20c44a..7ce32c3 100644
--- a/Source/WebKit/android/nav/SelectText.cpp
+++ b/Source/WebKit/android/nav/SelectText.cpp
@@ -25,23 +25,20 @@
#define LOG_TAG "webviewglue"
-#include "CachedPrefix.h"
+#include "config.h"
+
#include "BidiResolver.h"
#include "BidiRunList.h"
-#include "CachedRoot.h"
+#include "GLExtras.h"
#include "LayerAndroid.h"
-#include "ParseCanvas.h"
#include "SelectText.h"
#include "SkBitmap.h"
#include "SkBounder.h"
-#include "SkGradientShader.h"
-#include "SkMatrix.h"
+#include "SkCanvas.h"
#include "SkPicture.h"
-#include "SkPixelXorXfermode.h"
#include "SkPoint.h"
#include "SkRect.h"
#include "SkRegion.h"
-#include "SkUtils.h"
#include "TextRun.h"
#ifdef DEBUG_NAV_UI
@@ -52,7 +49,7 @@
// #define EXTRA_NOISY_LOGGING 1
#define DEBUG_TOUCH_HANDLES 0
#if DEBUG_TOUCH_HANDLES
-#define DBG_HANDLE_LOG(format, ...) LOGD("%s " format, __FUNCTION__, __VA_ARGS__)
+#define DBG_HANDLE_LOG(format, ...) ALOGD("%s " format, __FUNCTION__, __VA_ARGS__)
#else
#define DBG_HANDLE_LOG(...)
#endif
@@ -147,1921 +144,3 @@ void ReverseBidi(UChar* chars, int len) {
}
-namespace android {
-
-#define HYPHEN_MINUS 0x2D // ASCII hyphen
-#define SOLIDUS 0x2F // ASCII slash
-#define REVERSE_SOLIDUS 0x5C // ASCII backslash
-#define HYPHEN 0x2010 // unicode hyphen, first in range of dashes
-#define HORZ_BAR 0x2015 // unicode horizontal bar, last in range of dashes
-#define TOUCH_SLOP 10 // additional distance from character rect when hit
-
-class CommonCheck : public SkBounder {
-public:
- CommonCheck(const SkIRect& area)
- : mArea(area)
- , mLastUni(0)
- {
- mLastGlyph.fGlyphID = static_cast<uint16_t>(-1);
- mLastCandidate.fGlyphID = static_cast<uint16_t>(-1);
- mMatrix.reset();
- reset();
- }
-
- /* called only while the picture is parsed */
- int base() {
- if (mBase == INT_MAX) {
- SkPoint result;
- mMatrix.mapXY(0, mY, &result);
- mBase = SkScalarFloor(result.fY);
- }
- return mBase;
- }
-
- /* called only while the picture is parsed */
- int bottom() {
- if (mBottom == INT_MAX) {
- SkPoint result;
- SkPaint::FontMetrics metrics;
- mPaint.getFontMetrics(&metrics);
- mMatrix.mapXY(0, metrics.fDescent + mY, &result);
- mBottom = SkScalarCeil(result.fY);
- }
- return mBottom;
- }
-
-#if DEBUG_NAV_UI
- // make current (possibily uncomputed) value visible for debugging
- int bottomDebug() const
- {
- return mBottom;
- }
-#endif
-
- bool addNewLine(const SkBounder::GlyphRec& rec)
- {
- SkFixed lineSpacing = SkFixedAbs(mLastGlyph.fLSB.fY - rec.fLSB.fY);
- SkFixed lineHeight = SkIntToFixed(bottom() - top());
- return lineSpacing >= lineHeight + (lineHeight >> 1); // 1.5
- }
-
- bool addSpace(const SkBounder::GlyphRec& rec)
- {
- bool newBaseLine = mLastGlyph.fLSB.fY != rec.fLSB.fY;
- if (((mLastUni >= HYPHEN && mLastUni <= HORZ_BAR)
- || mLastUni == HYPHEN_MINUS || mLastUni == SOLIDUS
- || mLastUni == REVERSE_SOLIDUS) && newBaseLine)
- {
- return false;
- }
- return isSpace(rec);
- }
-
- void finishGlyph()
- {
- mLastGlyph = mLastCandidate;
- mLastUni = mLastUniCandidate;
- mLastPaint = mLastPaintCandidate;
- }
-
- const SkIRect& getArea() const {
- return mArea;
- }
-
- /* called only while the picture is parsed */
- SkUnichar getUniChar(const SkBounder::GlyphRec& rec)
- {
- SkUnichar unichar;
- SkPaint::TextEncoding save = mPaint.getTextEncoding();
- mPaint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
- mPaint.glyphsToUnichars(&rec.fGlyphID, 1, &unichar);
- mPaint.setTextEncoding(save);
- return unichar;
- }
-
- bool isSpace(const SkBounder::GlyphRec& rec)
- {
- if (mLastGlyph.fGlyphID == static_cast<uint16_t>(-1))
- return true;
- DBG_NAV_LOGD("mLastGlyph=((%g, %g),(%g, %g), %d)"
- " rec=((%g, %g),(%g, %g), %d) mLastUni=0x%04x '%c'",
- SkFixedToScalar(mLastGlyph.fLSB.fX),
- SkFixedToScalar(mLastGlyph.fLSB.fY),
- SkFixedToScalar(mLastGlyph.fRSB.fX),
- SkFixedToScalar(mLastGlyph.fRSB.fY), mLastGlyph.fGlyphID,
- SkFixedToScalar(rec.fLSB.fX), SkFixedToScalar(rec.fLSB.fY),
- SkFixedToScalar(rec.fRSB.fX), SkFixedToScalar(rec.fRSB.fY),
- rec.fGlyphID,
- mLastUni, mLastUni && mLastUni < 0x7f ? mLastUni : '?');
- bool newBaseLine = mLastGlyph.fLSB.fY != rec.fLSB.fY;
- if (newBaseLine)
- return true;
- SkFixed gapOne = mLastGlyph.fLSB.fX - rec.fRSB.fX;
- SkFixed gapTwo = rec.fLSB.fX - mLastGlyph.fRSB.fX;
- if (gapOne < 0 && gapTwo < 0)
- return false; // overlaps
- const SkBounder::GlyphRec& first = mLastGlyph.fLSB.fX < rec.fLSB.fX
- ? mLastGlyph : rec;
- const SkBounder::GlyphRec& second = mLastGlyph.fLSB.fX < rec.fLSB.fX
- ? rec : mLastGlyph;
- uint16_t firstGlyph = first.fGlyphID;
- SkScalar firstWidth = mLastPaint.measureText(&firstGlyph, sizeof(firstGlyph));
- SkFixed ceilWidth = SkIntToFixed(SkScalarCeil(firstWidth));
- SkFixed posNoSpace = first.fLSB.fX + ceilWidth;
- SkFixed ceilSpace = SkIntToFixed(SkFixedCeil(minSpaceWidth(mLastPaint)));
- SkFixed posWithSpace = posNoSpace + ceilSpace;
- SkFixed diffNoSpace = SkFixedAbs(second.fLSB.fX - posNoSpace);
- SkFixed diffWithSpace = SkFixedAbs(second.fLSB.fX - posWithSpace);
- DBG_NAV_LOGD("second=%g width=%g (%g) noSpace=%g (%g) withSpace=%g (%g)"
- " fontSize=%g",
- SkFixedToScalar(second.fLSB.fX),
- firstWidth, SkFixedToScalar(ceilWidth),
- SkFixedToScalar(posNoSpace), SkFixedToScalar(diffNoSpace),
- SkFixedToScalar(posWithSpace), SkFixedToScalar(diffWithSpace),
- mLastPaint.getTextSize());
- return diffWithSpace <= diffNoSpace;
- }
-
- SkFixed minSpaceWidth(SkPaint& paint)
- {
- if (mMinSpaceWidth == SK_FixedMax) {
- SkPaint::TextEncoding save = paint.getTextEncoding();
- paint.setTextEncoding(SkPaint::kUTF8_TextEncoding);
- SkScalar width = paint.measureText(" ", 1);
- mMinSpaceWidth = SkScalarToFixed(width * mMatrix.getScaleX());
- paint.setTextEncoding(save);
- DBG_NAV_LOGV("width=%g matrix sx/sy=(%g, %g) tx/ty=(%g, %g)"
- " mMinSpaceWidth=%g", width,
- mMatrix.getScaleX(), mMatrix.getScaleY(),
- mMatrix.getTranslateX(), mMatrix.getTranslateY(),
- SkFixedToScalar(mMinSpaceWidth));
- }
- return mMinSpaceWidth;
- }
-
- void recordGlyph(const SkBounder::GlyphRec& rec)
- {
- mLastCandidate = rec;
- mLastUniCandidate = getUniChar(rec);
- mLastPaintCandidate = mPaint;
- }
-
- void reset()
- {
- mMinSpaceWidth = SK_FixedMax; // mark as uninitialized
- mBase = mBottom = mTop = INT_MAX; // mark as uninitialized
- }
-
- void set(CommonCheck& check)
- {
- mLastGlyph = check.mLastGlyph;
- mLastUni = check.mLastUni;
- mMatrix = check.mMatrix;
- mLastPaint = check.mLastPaint;
- reset();
- }
-
- void setGlyph(CommonCheck& check)
- {
- mLastGlyph = check.mLastGlyph;
- mLastUni = check.mLastUni;
- mLastPaint = check.mLastPaint;
- }
-
- void setUp(const SkPaint& paint, const SkMatrix& matrix, SkScalar y,
- const void* text)
- {
- mMatrix = matrix;
- mPaint = paint;
- mText = static_cast<const uint16_t*>(text);
- mY = y;
- reset();
- }
-
- /* called only while the picture is parsed */
- int top() {
- if (mTop == INT_MAX) {
- SkPoint result;
- SkPaint::FontMetrics metrics;
- mPaint.getFontMetrics(&metrics);
- mMatrix.mapXY(0, metrics.fAscent + mY, &result);
- mTop = SkScalarFloor(result.fY);
- }
- return mTop;
- }
-
-#if DEBUG_NAV_UI
- // make current (possibily uncomputed) value visible for debugging
- int topDebug() const
- {
- return mTop;
- }
-#endif
-
-protected:
- SkIRect mArea;
- SkBounder::GlyphRec mLastCandidate;
- SkBounder::GlyphRec mLastGlyph;
- SkPaint mLastPaint; // available after picture has been parsed
- SkPaint mLastPaintCandidate; // associated with candidate glyph
- SkUnichar mLastUni;
- SkUnichar mLastUniCandidate;
- SkMatrix mMatrix;
- SkPaint mPaint; // only set up while the picture is parsed
- const uint16_t* mText;
- SkScalar mY;
-private:
- int mBase;
- int mBottom;
- SkFixed mMinSpaceWidth;
- int mTop;
- friend class EdgeCheck;
-};
-
-// generate the limit area for the new selection
-class LineCheck : public CommonCheck {
-public:
- LineCheck(int x, int y, const SkIRect& area)
- : INHERITED(area)
- , mX(x)
- , mY(y)
- , mInBetween(false)
- {
- mLast.setEmpty();
- }
-
- void finish(const SkRegion& selectedRgn)
- {
- if (!mParagraphs.count() && mLast.isEmpty())
- return;
- processLine();
- bool above = false;
- bool below = false;
- bool selected = false;
- SkRegion localRgn(selectedRgn);
- localRgn.translate(-mArea.fLeft, -mArea.fTop, &localRgn);
- DBG_NAV_LOGD("localRgn=(%d,%d,%d,%d)",
- localRgn.getBounds().fLeft, localRgn.getBounds().fTop,
- localRgn.getBounds().fRight, localRgn.getBounds().fBottom);
- for (int index = 0; index < mParagraphs.count(); index++) {
- const SkIRect& rect = mParagraphs[index];
- bool localSelected = localRgn.intersects(rect);
- DBG_NAV_LOGD("[%d] rect=(%d,%d,%d,%d)", index, rect.fLeft, rect.fTop,
- rect.fRight, rect.fBottom);
- if (localSelected) {
- DBG_NAV_LOGD("[%d] localSelected=true", index);
- *mSelected.append() = rect;
- }
- if (rect.fRight <= mX || rect.fLeft >= mX)
- continue;
- if (mY > rect.fBottom) {
- below = true;
- selected |= localSelected;
- DBG_NAV_LOGD("[%d] below=true localSelected=%s", index,
- localSelected ? "true" : "false");
- }
- if (mY < rect.fTop) {
- above = true;
- selected |= localSelected;
- DBG_NAV_LOGD("[%d] above=true localSelected=%s", index,
- localSelected ? "true" : "false");
- }
- }
- DBG_NAV_LOGD("mX=%d mY=%d above=%s below=%s selected=%s",
- mX, mY, above ? "true" : "false", below ? "true" : "false",
- selected ? "true" : "false");
- mInBetween = above && below && selected;
- }
-
- bool inBetween() const
- {
- return mInBetween;
- }
-
- bool inColumn(const SkIRect& test) const
- {
- for (int index = 0; index < mSelected.count(); index++) {
- const SkIRect& rect = mSelected[index];
- if (rect.fRight > test.fLeft && rect.fLeft < test.fRight)
- return true;
- }
- return false;
- }
-
- bool inColumn(int x, int y) const
- {
- for (int index = 0; index < mSelected.count(); index++) {
- const SkIRect& rect = mSelected[index];
- if (rect.contains(x, y))
- return true;
- }
- return false;
- }
-
- virtual bool onIRect(const SkIRect& rect)
- {
- SkIRect bounds;
- bounds.set(rect.fLeft, top(), rect.fRight, bottom());
- // assume that characters must be consecutive to describe spaces
- // (i.e., don't join rects drawn at different times)
- if (bounds.fTop != mLast.fTop || bounds.fBottom != mLast.fBottom
- || bounds.fLeft > mLast.fRight + minSpaceWidth(mPaint)
- || bounds.fLeft < mLast.fLeft) {
- processLine();
- mLast = bounds;
- } else
- mLast.join(bounds);
- return false;
- }
-
- void processLine()
- {
- // assume line spacing of 1.5
- int lineHeight = bottom() - top();
- mLast.inset(0, -lineHeight >> 1);
- // collect arrays of rectangles making up glyphs below or above this one
- for (int index = 0; index < mParagraphs.count(); index++) {
- SkIRect& rect = mParagraphs[index];
- if (SkIRect::Intersects(rect, mLast)) {
- rect.join(mLast);
- return;
- }
- }
- *mParagraphs.append() = mLast;
- }
-
-protected:
- int mX;
- int mY;
- SkIRect mLast;
- SkTDArray<SkIRect> mParagraphs;
- SkTDArray<SkIRect> mSelected;
- bool mInBetween;
-private:
- typedef CommonCheck INHERITED;
-};
-
-class SelectText::FirstCheck : public CommonCheck {
-public:
- FirstCheck(int x, int y, const SkIRect& area)
- : INHERITED(area)
- , mLineCheck(0)
- , mFocusX(x - area.fLeft)
- , mFocusY(y - area.fTop)
- , mBestInColumn(false)
- , mRecordGlyph(false)
- {
- reset();
- }
-
- const SkIRect& adjustedBounds(int* base)
- {
- *base = mBestBase + mArea.fTop;
- mBestBounds.offset(mArea.fLeft, mArea.fTop);
- DBG_NAV_LOGD("FirstCheck mBestBounds:(%d, %d, %d, %d) mTop=%d mBottom=%d",
- mBestBounds.fLeft, mBestBounds.fTop, mBestBounds.fRight,
- mBestBounds.fBottom, topDebug(), bottomDebug());
- return mBestBounds;
- }
-
- int focusX() const { return mFocusX; }
- int focusY() const { return mFocusY; }
-
- virtual bool onIRectGlyph(const SkIRect& rect,
- const SkBounder::GlyphRec& rec)
- {
- /* compute distance from rectangle center.
- * centerX = (rect.L + rect.R) / 2
- * multiply centerX and comparison x by 2 to retain better precision
- */
- SkIRect testBounds = {rect.fLeft, top(), rect.fRight, bottom()};
- // dx and dy are the distances from the tested edge
- // The edge distance is paramount if the test point is far away
- int dx = std::max(0, std::max(testBounds.fLeft - mFocusX,
- mFocusX - testBounds.fRight));
- int dy = std::max(0, std::max(testBounds.fTop - mFocusY,
- mFocusY - testBounds.fBottom));
- bool testInColumn = false;
- bool inBetween = false;
- bool inFocus = false;
- if (mLineCheck) {
- testInColumn = mLineCheck->inColumn(testBounds);
- inBetween = mLineCheck->inBetween();
- inFocus = mLineCheck->inColumn(mFocusX, mFocusY);
- }
-#ifdef EXTRA_NOISY_LOGGING
- if (dy < 10) {
- SkUnichar ch = getUniChar(rec);
- DBG_NAV_LOGD("FC dx/y=%d,%d mDx/y=%d,%d test=%d,%d,%d,%d"
- " best=%d,%d,%d,%d bestIn=%s tween=%s testIn=%s focus=%s ch=%c",
- dx, dy, mDx, mDy,
- testBounds.fLeft, testBounds.fTop, testBounds.fRight,
- testBounds.fBottom, mBestBounds.fLeft, mBestBounds.fTop,
- mBestBounds.fRight, mBestBounds.fBottom,
- mBestInColumn ? "true" : "false", inBetween ? "true" : "false",
- testInColumn ? "true" : "false", inFocus ? "true" : "false",
- ch < 0x7f ? ch : '?');
- }
-#endif
- if ((mBestInColumn || inBetween) && !testInColumn) {
-#ifdef EXTRA_NOISY_LOGGING
- if (dy < 10) DBG_NAV_LOG("FirstCheck reject column");
-#endif
- return false;
- }
- bool ignoreColumn = mBestInColumn == testInColumn || !inFocus;
- if (ignoreColumn && dy > 0 && (mDy < dy
- || (mDy == dy && dx > 0 && mDx <= dx))) {
-#ifdef EXTRA_NOISY_LOGGING
- if (dy < 10) DBG_NAV_LOG("FirstCheck reject edge");
-#endif
- return false;
- }
- // cx and cy are the distances from the tested center
- // The center distance is used when the test point is over the text
- int cx = std::abs(((testBounds.fLeft + testBounds.fRight) >> 1)
- - mFocusX);
- int cy = std::abs(((testBounds.fTop + testBounds.fBottom) >> 1)
- - mFocusY);
- if (ignoreColumn && dy == 0 && mDy == 0) {
- if (mCy < cy) {
-#ifdef EXTRA_NOISY_LOGGING
- DBG_NAV_LOGD("FirstCheck reject cy=%d mCy=%d", cy, mCy);
-#endif
- return false;
- }
- if (mCy == cy) {
- if (dx == 0 && mDx == 0) {
- if (mCx < cx) {
-#ifdef EXTRA_NOISY_LOGGING
- DBG_NAV_LOGD("FirstCheck reject cx=%d mCx=%d", cx, mCx);
-#endif
- return false;
- }
- } else if (dx > 0 && mDx <= dx) {
-#ifdef EXTRA_NOISY_LOGGING
- DBG_NAV_LOGD("FirstCheck reject dx=%d mDx=%d", dx, mDx);
-#endif
- return false;
- }
- }
- }
-#ifdef EXTRA_NOISY_LOGGING
- if (dy < 10) {
- DBG_NAV_LOGD("FirstCheck cx/y=(%d,%d)", cx, cy);
- }
-#endif
- mBestBase = base();
- mBestBounds = testBounds;
- mBestInColumn = testInColumn;
-#ifndef EXTRA_NOISY_LOGGING
- if (dy < 10 && dx < 10)
-#endif
- {
-#if DEBUG_NAV_UI
- SkUnichar ch = getUniChar(rec);
-#endif
- DBG_NAV_LOGD("FirstCheck dx/y=(%d,%d) mFocus=(%d,%d)"
- " mBestBounds={%d,%d,r=%d,b=%d} inColumn=%s ch=%c",
- dx, dy, mFocusX, mFocusY,
- mBestBounds.fLeft, mBestBounds.fTop,
- mBestBounds.fRight, mBestBounds.fBottom,
- mBestInColumn ? "true" : "false", ch < 0x7f ? ch : '?');
- }
- mCx = cx;
- mCy = cy;
- mDx = dx;
- mDy = dy;
- if (mRecordGlyph)
- recordGlyph(rec);
- return false;
- }
-
- void reset()
- {
- mBestBounds.setEmpty();
- mDx = mDy = mCx = mCy = INT_MAX;
- }
-
- void setLines(const LineCheck* lineCheck) { mLineCheck = lineCheck; }
- void setRecordGlyph() { mRecordGlyph = true; }
-
-protected:
- const LineCheck* mLineCheck;
- int mBestBase;
- SkIRect mBestBounds;
- int mCx;
- int mCy;
- int mDx;
- int mDy;
- int mFocusX;
- int mFocusY;
- bool mBestInColumn;
- bool mRecordGlyph;
-private:
- typedef CommonCheck INHERITED;
-};
-
-class SelectText::EdgeCheck : public SelectText::FirstCheck {
-public:
- EdgeCheck(int x, int y, const SkIRect& area, CommonCheck& last, bool left)
- : INHERITED(x, y, area)
- , mLast(area)
- , mLeft(left)
- {
- mLast.set(last); // CommonCheck::set()
- setGlyph(last);
- }
-
- bool adjacent()
- {
- return !mLast.isSpace(mLastGlyph);
- }
-
- const SkIRect& bestBounds(int* base)
- {
- *base = mBestBase;
- return mBestBounds;
- }
-
- virtual bool onIRectGlyph(const SkIRect& rect,
- const SkBounder::GlyphRec& rec)
- {
- int dx = mLeft ? mFocusX - rect.fRight : rect.fLeft - mFocusX;
- int dy = ((top() + bottom()) >> 1) - mFocusY;
- dx = abs(dx);
- dy = abs(dy);
- if (mLeft ? mFocusX <= rect.fLeft : mFocusX >= rect.fRight) {
- if (dx <= 10 && dy <= 10) {
- DBG_NAV_LOGD("EdgeCheck fLeft=%d fRight=%d mFocusX=%d dx=%d dy=%d",
- rect.fLeft, rect.fRight, mFocusX, dx, dy);
- }
- return false;
- }
- if (mDy > dy || (mDy == dy && mDx > dx)) {
- if (rec.fLSB == mLastGlyph.fLSB && rec.fRSB == mLastGlyph.fRSB) {
- DBG_NAV_LOGD("dup rec.fLSB.fX=%g rec.fRSB.fX=%g",
- SkFixedToScalar(rec.fLSB.fX), SkFixedToScalar(rec.fRSB.fX));
- return false;
- }
- recordGlyph(rec);
- mDx = dx;
- mDy = dy;
- mBestBase = base();
- mBestBounds.set(rect.fLeft, top(), rect.fRight, bottom());
- if (dx <= 10 && dy <= 10) {
- DBG_NAV_LOGD("EdgeCheck mBestBounds={%d,%d,r=%d,b=%d} dx/y=(%d, %d)",
- mBestBounds.fLeft, mBestBounds.fTop,
- mBestBounds.fRight, mBestBounds.fBottom, dx, dy);
- }
- }
- return false;
- }
-
- void shiftStart(SkIRect bounds)
- {
- DBG_NAV_LOGD("EdgeCheck mFocusX=%d mLeft=%s bounds.fLeft=%d bounds.fRight=%d",
- mFocusX, mLeft ? "true" : "false", bounds.fLeft, bounds.fRight);
- reset();
- mFocusX = mLeft ? bounds.fLeft : bounds.fRight;
- mLast.set(*this); // CommonCheck::set()
- }
-
-protected:
- CommonCheck mLast;
- bool mLeft;
-private:
- typedef SelectText::FirstCheck INHERITED;
-};
-
-class FindFirst : public CommonCheck {
-public:
- FindFirst(const SkIRect& area)
- : INHERITED(area)
- {
- mBestBounds.set(area.width(), area.height(), area.width(), area.height());
- }
-
- const SkIRect& bestBounds(int* base)
- {
- *base = mBestBase;
- return mBestBounds;
- }
-
- virtual bool onIRect(const SkIRect& rect)
- {
- if (mBestBounds.isEmpty()) {
- mBestBase = base();
- mBestBounds.set(rect.fLeft, top(), rect.fRight, bottom());
- }
- return false;
- }
-
-protected:
- int mBestBase;
- SkIRect mBestBounds;
-private:
- typedef CommonCheck INHERITED;
-};
-
-class FindLast : public FindFirst {
-public:
- FindLast(const SkIRect& area)
- : INHERITED(area)
- {
- mBestBounds.setEmpty();
- }
-
- virtual bool onIRect(const SkIRect& rect)
- {
- mBestBase = base();
- mBestBounds.set(rect.fLeft, top(), rect.fRight, bottom());
- return false;
- }
-
-private:
- typedef FindFirst INHERITED;
-};
-
-static bool baseLinesAgree(const SkIRect& rectA, int baseA,
- const SkIRect& rectB, int baseB)
-{
- return (rectA.fTop < baseB && rectA.fBottom >= baseB)
- || (rectB.fTop < baseA && rectB.fBottom >= baseA);
-}
-
-class BuilderCheck : public CommonCheck {
-protected:
- enum IntersectionType {
- NO_INTERSECTION, // debugging printf expects this to equal zero
- LAST_INTERSECTION, // debugging printf expects this to equal one
- WAIT_FOR_INTERSECTION
- };
-
- BuilderCheck(const SkIRect& start, int startBase, const SkIRect& end,
- int endBase, const SkIRect& area)
- : INHERITED(area)
- , mCapture(false)
- , mEnd(end)
- , mEndBase(endBase)
- , mStart(start)
- , mStartBase(startBase)
- {
- mEnd.offset(-area.fLeft, -area.fTop);
- mEndBase -= area.fTop;
- mEndExtra.setEmpty();
- mLast.setEmpty();
- mLastBase = INT_MAX;
- mSelectRect.setEmpty();
- mStart.offset(-area.fLeft, -area.fTop);
- mStartBase -= area.fTop;
- mStartExtra.setEmpty();
- DBG_NAV_LOGD(" mStart=(%d,%d,r=%d,b=%d) mStartBase=%d"
- " mEnd=(%d,%d,r=%d,b=%d) mEndBase=%d",
- mStart.fLeft, mStart.fTop, mStart.fRight, mStart.fBottom, mStartBase,
- mEnd.fLeft, mEnd.fTop, mEnd.fRight, mEnd.fBottom, mEndBase);
- }
-
- int checkFlipRect(const SkIRect& full, int fullBase) {
- mCollectFull = false;
- // is the text to collect between the selection top and bottom?
- if (fullBase < mStart.fTop || fullBase > mEnd.fBottom) {
- if (VERBOSE_LOGGING && !mLast.isEmpty()) DBG_NAV_LOGD("%s 1"
- " full=(%d,%d,r=%d,b=%d) fullBase=%d"
- " mLast=(%d,%d,r=%d,b=%d) mLastBase=%d",
- mLastIntersects ? "LAST_INTERSECTION" : "NO_INTERSECTION",
- full.fLeft, full.fTop, full.fRight, full.fBottom, fullBase,
- mLast.fLeft, mLast.fTop, mLast.fRight, mLast.fBottom, mLastBase);
- return mLastIntersects;
- }
- // is the text to the left of the selection start?
- if (baseLinesAgree(mStart, mStartBase, full, fullBase)
- && full.fLeft < mStart.fLeft) {
- if (VERBOSE_LOGGING) DBG_NAV_LOGD("%s 2"
- " full=(%d,%d,r=%d,b=%d) fullBase=%d"
- " mLast=(%d,%d,r=%d,b=%d) mLastBase=%d"
- " mStart=(%d,%d,r=%d,b=%d) mStartBase=%d",
- mLastIntersects ? "LAST_INTERSECTION" : "NO_INTERSECTION",
- full.fLeft, full.fTop, full.fRight, full.fBottom, fullBase,
- mLast.fLeft, mLast.fTop, mLast.fRight, mLast.fBottom, mLastBase,
- mStart.fLeft, mStart.fTop, mStart.fRight, mStart.fBottom, mStartBase);
- mStartExtra.join(full);
- return mLastIntersects;
- }
- // is the text to the right of the selection end?
- if (baseLinesAgree(mEnd, mEndBase, full, fullBase)
- && full.fRight > mEnd.fRight) {
- if (VERBOSE_LOGGING) DBG_NAV_LOGD("%s 3"
- " full=(%d,%d,r=%d,b=%d) fullBase=%d"
- " mLast=(%d,%d,r=%d,b=%d) mLastBase=%d"
- " mEnd=(%d,%d,r=%d,b=%d) mEndBase=%d",
- mLastIntersects ? "LAST_INTERSECTION" : "NO_INTERSECTION",
- full.fLeft, full.fTop, full.fRight, full.fBottom, fullBase,
- mLast.fLeft, mLast.fTop, mLast.fRight, mLast.fBottom, mLastBase,
- mEnd.fLeft, mEnd.fTop, mEnd.fRight, mEnd.fBottom, mEndBase);
- mEndExtra.join(full);
- return mLastIntersects;
- }
- int spaceGap = SkFixedRound(minSpaceWidth(mPaint) * 3);
- // should text to the left of the start be added to the selection bounds?
- if (!mStartExtra.isEmpty()) {
- if (VERBOSE_LOGGING) DBG_NAV_LOGD("mSelectRect=(%d,%d,r=%d,b=%d)"
- " mStartExtra=(%d,%d,r=%d,b=%d)",
- mSelectRect.fLeft, mSelectRect.fTop, mSelectRect.fRight, mSelectRect.fBottom,
- mStartExtra.fLeft, mStartExtra.fTop, mStartExtra.fRight, mStartExtra.fBottom);
- if (mStartExtra.fRight + spaceGap >= mStart.fLeft)
- mSelectRect.join(mStartExtra);
- mStartExtra.setEmpty();
- }
- // should text to the right of the end be added to the selection bounds?
- if (!mEndExtra.isEmpty()) {
- if (VERBOSE_LOGGING) DBG_NAV_LOGD("mSelectRect=(%d,%d,r=%d,b=%d)"
- " mEndExtra=(%d,%d,r=%d,b=%d)",
- mSelectRect.fLeft, mSelectRect.fTop, mSelectRect.fRight, mSelectRect.fBottom,
- mEndExtra.fLeft, mEndExtra.fTop, mEndExtra.fRight, mEndExtra.fBottom);
- if (mEndExtra.fLeft - spaceGap <= mEnd.fRight)
- mSelectRect.join(mEndExtra);
- mEndExtra.setEmpty();
- }
- bool sameBaseLine = baseLinesAgree(mLast, mLastBase, full, fullBase);
- bool adjacent = (full.fLeft - mLast.fRight) < spaceGap;
- // is this the first, or are there more characters on the same line?
- if (mLast.isEmpty() || (sameBaseLine && adjacent)) {
- if (VERBOSE_LOGGING) DBG_NAV_LOGD("WAIT_FOR_INTERSECTION"
- " full=(%d,%d,r=%d,b=%d) fullBase=%d"
- " mLast=(%d,%d,r=%d,b=%d) mLastBase=%d"
- " mSelectRect=(%d,%d,r=%d,b=%d)",
- full.fLeft, full.fTop, full.fRight, full.fBottom, fullBase,
- mLast.fLeft, mLast.fTop, mLast.fRight, mLast.fBottom, mLastBase,
- mSelectRect.fLeft, mSelectRect.fTop, mSelectRect.fRight, mSelectRect.fBottom);
- mLast.join(full);
- mLastIntersects = SkIRect::Intersects(mLast, mSelectRect);
- return WAIT_FOR_INTERSECTION;
- }
- if (VERBOSE_LOGGING) DBG_NAV_LOGD("%s 4"
- " mLast=(%d,%d,r=%d,b=%d) mLastBase=%d"
- " full=(%d,%d,r=%d,b=%d) fullBase=%d"
- " mSelectRect=(%d,%d,r=%d,b=%d)"
- " mStartExtra=(%d,%d,r=%d,b=%d)"
- " mEndExtra=(%d,%d,r=%d,b=%d)",
- mLastIntersects ? "LAST_INTERSECTION" : "NO_INTERSECTION",
- mLast.fLeft, mLast.fTop, mLast.fRight, mLast.fBottom, mLastBase,
- full.fLeft, full.fTop, full.fRight, full.fBottom, fullBase,
- mSelectRect.fLeft, mSelectRect.fTop, mSelectRect.fRight, mSelectRect.fBottom,
- mStartExtra.fLeft, mStartExtra.fTop, mStartExtra.fRight, mStartExtra.fBottom,
- mEndExtra.fLeft, mEndExtra.fTop, mEndExtra.fRight, mEndExtra.fBottom);
- // after the caller determines what to do with the last collection,
- // start the collection over with full and fullBase.
- mCollectFull = true;
- return mLastIntersects;
- }
-
- bool resetLast(const SkIRect& full, int fullBase)
- {
- if (mCollectFull) {
- mLast = full;
- mLastBase = fullBase;
- mLastIntersects = SkIRect::Intersects(mLast, mSelectRect);
- } else {
- mLast.setEmpty();
- mLastBase = INT_MAX;
- mLastIntersects = false;
- }
- return mCollectFull;
- }
-
- void setFlippedState()
- {
- mSelectRect = mStart;
- mSelectRect.join(mEnd);
- DBG_NAV_LOGD("mSelectRect=(%d,%d,r=%d,b=%d)",
- mSelectRect.fLeft, mSelectRect.fTop, mSelectRect.fRight, mSelectRect.fBottom);
- mLast.setEmpty();
- mLastBase = INT_MAX;
- mLastIntersects = NO_INTERSECTION;
- }
-
- bool mCapture;
- bool mCollectFull;
- SkIRect mEnd;
- int mEndBase;
- SkIRect mEndExtra;
- bool mFlipped;
- SkIRect mLast;
- int mLastBase;
- int mLastIntersects;
- SkIRect mSelectRect;
- SkIRect mStart;
- SkIRect mStartExtra;
- int mStartBase;
-private:
- typedef CommonCheck INHERITED;
-
-};
-
-class MultilineBuilder : public BuilderCheck {
-public:
- MultilineBuilder(const SkIRect& start, int startBase, const SkIRect& end,
- int endBase, const SkIRect& area, SkRegion* region)
- : INHERITED(start, startBase, end, endBase, area)
- , mSelectRegion(region)
- {
- mFlipped = false;
- }
-
- void addLastToRegion() {
- if (VERBOSE_LOGGING) DBG_NAV_LOGD(" mLast=(%d,%d,r=%d,b=%d)",
- mLast.fLeft, mLast.fTop, mLast.fRight, mLast.fBottom);
- mSelectRegion->op(mLast, SkRegion::kUnion_Op);
- }
-
- void finish() {
- if (!mFlipped || !mLastIntersects)
- return;
- addLastToRegion();
- }
-
- // return true if capture end was not found after capture begin
- bool flipped() {
- DBG_NAV_LOGD("flipped=%s", mCapture ? "true" : "false");
- if (!mCapture)
- return false;
- mFlipped = true;
- setFlippedState();
- mSelectRegion->setEmpty();
- return true;
- }
-
- virtual bool onIRect(const SkIRect& rect) {
- SkIRect full;
- full.set(rect.fLeft, top(), rect.fRight, bottom());
- int fullBase = base();
- if (mFlipped) {
- int intersectType = checkFlipRect(full, fullBase);
- if (intersectType == LAST_INTERSECTION)
- addLastToRegion();
- if (intersectType != WAIT_FOR_INTERSECTION)
- resetLast(full, fullBase);
- return false;
- }
- if (full == mStart) {
- if (VERBOSE_LOGGING) DBG_NAV_LOGD("full == mStart full=(%d,%d,r=%d,b=%d)",
- full.fLeft, full.fTop, full.fRight, full.fBottom);
- mCapture = true;
- }
- if (mCapture) {
- bool sameLines = baseLinesAgree(mLast, mLastBase, full, fullBase);
- if (sameLines)
- mLast.join(full);
- if (!sameLines || full == mEnd) {
- if (VERBOSE_LOGGING) DBG_NAV_LOGD("finish mLast=(%d,%d,r=%d,b=%d)",
- mLast.fLeft, mLast.fTop, mLast.fRight, mLast.fBottom);
- addLastToRegion();
- mLast = full;
- mLastBase = fullBase;
- }
- }
- if (full == mEnd) {
- if (VERBOSE_LOGGING) DBG_NAV_LOGD("full == mEnd full=(%d,%d,r=%d,b=%d)",
- full.fLeft, full.fTop, full.fRight, full.fBottom);
- mCapture = false;
- if (full == mStart)
- addLastToRegion();
- }
- return false;
- }
-
-protected:
- SkRegion* mSelectRegion;
-private:
- typedef BuilderCheck INHERITED;
-};
-
-static inline bool compareBounds(const SkIRect* first, const SkIRect* second)
-{
- return first->fTop < second->fTop;
-}
-
-class TextExtractor : public BuilderCheck {
-public:
- TextExtractor(const SkIRect& start, int startBase, const SkIRect& end,
- int endBase, const SkIRect& area, bool flipped)
- : INHERITED(start, startBase, end, endBase, area)
- , mSelectStartIndex(-1)
- , mSkipFirstSpace(true) // don't start with a space
- {
- mFlipped = flipped;
- if (flipped)
- setFlippedState();
- }
-
- void addCharacter(const SkBounder::GlyphRec& rec)
- {
- if (mSelectStartIndex < 0)
- mSelectStartIndex = mSelectText.count();
- if (!mSkipFirstSpace) {
- if (addNewLine(rec)) {
- DBG_NAV_LOG("write new line");
- *mSelectText.append() = '\n';
- *mSelectText.append() = '\n';
- } else if (addSpace(rec)) {
- DBG_NAV_LOG("write space");
- *mSelectText.append() = ' ';
- }
- } else
- mSkipFirstSpace = false;
- recordGlyph(rec);
- finishGlyph();
- if (VERBOSE_LOGGING) DBG_NAV_LOGD("glyphID=%d uni=%d '%c'", rec.fGlyphID,
- mLastUni, mLastUni && mLastUni < 0x7f ? mLastUni : '?');
- if (mLastUni) {
- uint16_t chars[2];
- size_t count = SkUTF16_FromUnichar(mLastUni, chars);
- *mSelectText.append() = chars[0];
- if (count == 2)
- *mSelectText.append() = chars[1];
- }
- }
-
- void addLast()
- {
- *mSelectBounds.append() = mLast;
- *mSelectStart.append() = mSelectStartIndex;
- *mSelectEnd.append() = mSelectText.count();
- }
-
- /* Text characters are collected before it's been determined that the
- characters are part of the selection. The bounds describe valid parts
- of the selection, but the bounds are out of order.
-
- This sorts the characters by sorting the bounds, then copying the
- characters that were captured.
- */
- void finish()
- {
- if (mLastIntersects)
- addLast();
- Vector<SkIRect*> sortedBounds;
- SkTDArray<uint16_t> temp;
- int index;
- DBG_NAV_LOGD("mSelectBounds.count=%d text=%d", mSelectBounds.count(),
- mSelectText.count());
- for (index = 0; index < mSelectBounds.count(); index++)
- sortedBounds.append(&mSelectBounds[index]);
- std::sort(sortedBounds.begin(), sortedBounds.end(), compareBounds);
- int lastEnd = -1;
- for (index = 0; index < mSelectBounds.count(); index++) {
- int order = sortedBounds[index] - &mSelectBounds[0];
- int start = mSelectStart[order];
- int end = mSelectEnd[order];
- DBG_NAV_LOGD("order=%d start=%d end=%d top=%d", order, start, end,
- mSelectBounds[order].fTop);
- int count = temp.count();
- if (count > 0 && temp[count - 1] != '\n' && start != lastEnd) {
- // always separate paragraphs when original text is out of order
- DBG_NAV_LOG("write new line");
- *temp.append() = '\n';
- *temp.append() = '\n';
- }
- temp.append(end - start, &mSelectText[start]);
- lastEnd = end;
- }
- mSelectText.swap(temp);
- }
-
- virtual bool onIRectGlyph(const SkIRect& rect,
- const SkBounder::GlyphRec& rec)
- {
- SkIRect full;
- full.set(rect.fLeft, top(), rect.fRight, bottom());
- int fullBase = base();
- if (mFlipped) {
- int intersectType = checkFlipRect(full, fullBase);
- if (WAIT_FOR_INTERSECTION == intersectType)
- addCharacter(rec); // may not be copied
- else {
- if (LAST_INTERSECTION == intersectType)
- addLast();
- else
- mSkipFirstSpace = true;
- mSelectStartIndex = -1;
- if (resetLast(full, fullBase))
- addCharacter(rec); // may not be copied
- }
- return false;
- }
- if (full == mStart)
- mCapture = true;
- if (mCapture)
- addCharacter(rec);
- else
- mSkipFirstSpace = true;
- if (full == mEnd)
- mCapture = false;
- return false;
- }
-
- WTF::String text() {
- if (mFlipped)
- finish();
- // the text has been copied in visual order. Reverse as needed if
- // result contains right-to-left characters.
- const uint16_t* start = mSelectText.begin();
- const uint16_t* end = mSelectText.end();
- while (start < end) {
- SkUnichar ch = SkUTF16_NextUnichar(&start);
- WTF::Unicode::Direction charDirection = WTF::Unicode::direction(ch);
- if (WTF::Unicode::RightToLeftArabic == charDirection
- || WTF::Unicode::RightToLeft == charDirection) {
- WebCore::ReverseBidi(mSelectText.begin(), mSelectText.count());
- break;
- }
- }
- return WTF::String(mSelectText.begin(), mSelectText.count());
- }
-
-protected:
- SkIRect mEmpty;
- SkTDArray<SkIRect> mSelectBounds;
- SkTDArray<int> mSelectEnd;
- SkTDArray<int> mSelectStart;
- int mSelectStartIndex;
- SkTDArray<uint16_t> mSelectText;
- bool mSkipFirstSpace;
-private:
- typedef BuilderCheck INHERITED;
-};
-
-class TextCanvas : public ParseCanvas {
-public:
-
- TextCanvas(CommonCheck* bounder)
- : mBounder(*bounder) {
- setBounder(bounder);
- SkBitmap bitmap;
- const SkIRect& area = bounder->getArea();
- bitmap.setConfig(SkBitmap::kARGB_8888_Config, area.width(),
- area.height());
- setBitmapDevice(bitmap);
- translate(SkIntToScalar(-area.fLeft), SkIntToScalar(-area.fTop));
-#ifdef DEBUG_NAV_UI
- const SkIRect& clip = getTotalClip().getBounds();
- const SkMatrix& matrix = getTotalMatrix();
- DBG_NAV_LOGD("bitmap=(%d,%d) clip=(%d,%d,%d,%d) matrix=(%g,%g)",
- bitmap.width(), bitmap.height(), clip.fLeft, clip.fTop,
- clip.fRight, clip.fBottom, matrix.getTranslateX(), matrix.getTranslateY());
-#endif
- }
-
- virtual void drawPaint(const SkPaint& paint) {
- }
-
- virtual void drawPoints(PointMode mode, size_t count, const SkPoint pts[],
- const SkPaint& paint) {
- }
-
- virtual void drawRect(const SkRect& rect, const SkPaint& paint) {
- }
-
- virtual void drawPath(const SkPath& path, const SkPaint& paint) {
- }
-
- virtual void commonDrawBitmap(const SkBitmap& bitmap, const SkIRect* rect,
- const SkMatrix& matrix, const SkPaint& paint) {
- }
-
- virtual void drawSprite(const SkBitmap& bitmap, int left, int top,
- const SkPaint* paint = NULL) {
- }
-
- virtual void drawText(const void* text, size_t byteLength, SkScalar x,
- SkScalar y, const SkPaint& paint) {
- mBounder.setUp(paint, getTotalMatrix(), y, text);
- INHERITED::drawText(text, byteLength, x, y, paint);
- }
-
- virtual void drawPosTextH(const void* text, size_t byteLength,
- const SkScalar xpos[], SkScalar constY,
- const SkPaint& paint) {
- mBounder.setUp(paint, getTotalMatrix(), constY, text);
- INHERITED::drawPosTextH(text, byteLength, xpos, constY, paint);
- }
-
- virtual void drawVertices(VertexMode vmode, int vertexCount,
- const SkPoint vertices[], const SkPoint texs[],
- const SkColor colors[], SkXfermode* xmode,
- const uint16_t indices[], int indexCount,
- const SkPaint& paint) {
- }
-
- CommonCheck& mBounder;
-private:
- typedef ParseCanvas INHERITED;
-};
-
-static bool buildSelection(const SkPicture& picture, const SkIRect& area,
- const SkIRect& selStart, int startBase,
- const SkIRect& selEnd, int endBase, SkRegion* region)
-{
- DBG_NAV_LOGD("area=(%d, %d, %d, %d) selStart=(%d, %d, %d, %d)"
- " selEnd=(%d, %d, %d, %d)",
- area.fLeft, area.fTop, area.fRight, area.fBottom,
- selStart.fLeft, selStart.fTop, selStart.fRight, selStart.fBottom,
- selEnd.fLeft, selEnd.fTop, selEnd.fRight, selEnd.fBottom);
- MultilineBuilder builder(selStart, startBase, selEnd, endBase, area, region);
- TextCanvas checker(&builder);
- checker.drawPicture(const_cast<SkPicture&>(picture));
- bool flipped = builder.flipped();
- if (flipped) {
- TextCanvas checker(&builder);
- checker.drawPicture(const_cast<SkPicture&>(picture));
- }
- builder.finish();
- region->translate(area.fLeft, area.fTop);
- return flipped;
-}
-
-static SkIRect findFirst(const SkPicture& picture, int* base)
-{
- SkIRect area;
- area.set(0, 0, picture.width(), picture.height());
- FindFirst finder(area);
- TextCanvas checker(&finder);
- checker.drawPicture(const_cast<SkPicture&>(picture));
- return finder.bestBounds(base);
-}
-
-static SkIRect findLast(const SkPicture& picture, int* base)
-{
- SkIRect area;
- area.set(0, 0, picture.width(), picture.height());
- FindLast finder(area);
- TextCanvas checker(&finder);
- checker.drawPicture(const_cast<SkPicture&>(picture));
- return finder.bestBounds(base);
-}
-
-static WTF::String text(const SkPicture& picture, const SkIRect& area,
- const SkIRect& start, int startBase, const SkIRect& end,
- int endBase, bool flipped)
-{
- TextExtractor extractor(start, startBase, end, endBase, area, flipped);
- TextCanvas checker(&extractor);
- checker.drawPicture(const_cast<SkPicture&>(picture));
- return extractor.text();
-}
-
-#define CONTROL_NOTCH 16
-// TODO: Now that java is the one actually drawing these, get the real values
-// from the drawable itself
-#define CONTROL_HEIGHT 47
-#define CONTROL_WIDTH 26
-#define CONTROL_SLOP 5
-#define STROKE_WIDTH 1.0f
-#define STROKE_OUTSET 3.5f
-#define STROKE_I_OUTSET 4 // (int) ceil(STROKE_OUTSET)
-#define STROKE_COLOR 0x66000000
-#define OUTER_COLOR 0x33000000
-#define INNER_COLOR 0xe6aae300
-
-SelectText::SelectText()
- : m_controlWidth(CONTROL_WIDTH)
- , m_controlHeight(CONTROL_HEIGHT)
- , m_controlSlop(CONTROL_SLOP)
-{
- m_picture = 0;
- reset();
- SkPaint paint;
- SkRect oval;
-
- SkPath startOuterPath;
- oval.set(-CONTROL_WIDTH - STROKE_OUTSET, CONTROL_NOTCH - STROKE_OUTSET,
- -CONTROL_WIDTH + STROKE_OUTSET, CONTROL_NOTCH + STROKE_OUTSET);
- startOuterPath.arcTo(oval, 180, 45, true);
- oval.set(-STROKE_OUTSET, -STROKE_OUTSET, STROKE_OUTSET, STROKE_OUTSET);
- startOuterPath.arcTo(oval, 180 + 45, 135, false);
- oval.set(-STROKE_OUTSET, CONTROL_HEIGHT - STROKE_OUTSET,
- STROKE_OUTSET, CONTROL_HEIGHT + STROKE_OUTSET);
- startOuterPath.arcTo(oval, 0, 90, false);
- oval.set(-CONTROL_WIDTH - STROKE_OUTSET, CONTROL_HEIGHT - STROKE_OUTSET,
- -CONTROL_WIDTH + STROKE_OUTSET, CONTROL_HEIGHT + STROKE_OUTSET);
- startOuterPath.arcTo(oval, 90, 90, false);
- startOuterPath.close();
- SkPath startInnerPath;
- startInnerPath.moveTo(-CONTROL_WIDTH, CONTROL_NOTCH);
- startInnerPath.lineTo(-CONTROL_WIDTH, CONTROL_HEIGHT);
- startInnerPath.lineTo(0, CONTROL_HEIGHT);
- startInnerPath.lineTo(0, 0);
- startInnerPath.close();
- startOuterPath.addPath(startInnerPath, 0, 0);
-
- SkCanvas* canvas = m_startControl.beginRecording(
- CONTROL_WIDTH + STROKE_OUTSET * 2,
- CONTROL_HEIGHT + STROKE_OUTSET * 2);
- paint.setAntiAlias(true);
- paint.setColor(INNER_COLOR);
- paint.setStyle(SkPaint::kFill_Style);
- canvas->drawPath(startInnerPath, paint);
- paint.setColor(OUTER_COLOR);
- canvas->drawPath(startOuterPath, paint);
- paint.setStyle(SkPaint::kStroke_Style);
- paint.setColor(STROKE_COLOR);
- paint.setStrokeWidth(STROKE_WIDTH);
- canvas->drawPath(startInnerPath, paint);
- m_startControl.endRecording();
-
- SkPath endOuterPath;
- oval.set(-STROKE_OUTSET, -STROKE_OUTSET, STROKE_OUTSET, STROKE_OUTSET);
- endOuterPath.arcTo(oval, 180, 135, true);
- oval.set(CONTROL_WIDTH - STROKE_OUTSET, CONTROL_NOTCH - STROKE_OUTSET,
- CONTROL_WIDTH + STROKE_OUTSET, CONTROL_NOTCH + STROKE_OUTSET);
- endOuterPath.arcTo(oval, 360 - 45, 45, false);
- oval.set(CONTROL_WIDTH - STROKE_OUTSET, CONTROL_HEIGHT - STROKE_OUTSET,
- CONTROL_WIDTH + STROKE_OUTSET, CONTROL_HEIGHT + STROKE_OUTSET);
- endOuterPath.arcTo(oval, 0, 90, false);
- oval.set(-STROKE_OUTSET, CONTROL_HEIGHT - STROKE_OUTSET,
- STROKE_OUTSET, CONTROL_HEIGHT + STROKE_OUTSET);
- endOuterPath.arcTo(oval, 90, 90, false);
- startOuterPath.close();
- SkPath endInnerPath;
- endInnerPath.moveTo(0, 0);
- endInnerPath.lineTo(0, CONTROL_HEIGHT);
- endInnerPath.lineTo(CONTROL_WIDTH, CONTROL_HEIGHT);
- endInnerPath.lineTo(CONTROL_WIDTH, CONTROL_NOTCH);
- endInnerPath.close();
- endOuterPath.addPath(endInnerPath, 0, 0);
-
- canvas = m_endControl.beginRecording(CONTROL_WIDTH + STROKE_OUTSET * 2,
- CONTROL_HEIGHT + STROKE_OUTSET * 2);
- paint.setColor(INNER_COLOR);
- paint.setStyle(SkPaint::kFill_Style);
- canvas->drawPath(endInnerPath, paint);
- paint.setColor(OUTER_COLOR);
- canvas->drawPath(endOuterPath, paint);
- paint.setStyle(SkPaint::kStroke_Style);
- paint.setColor(STROKE_COLOR);
- paint.setStrokeWidth(STROKE_WIDTH);
- canvas->drawPath(endInnerPath, paint);
- m_endControl.endRecording();
-}
-
-SelectText::~SelectText()
-{
- SkSafeUnref(m_picture);
-}
-
-void SelectText::draw(SkCanvas* canvas, LayerAndroid* layer, IntRect* inval)
-{
- if (m_layerId != layer->uniqueId())
- return;
- // reset m_picture to match m_layerId
- SkSafeUnref(m_picture);
- m_picture = layer->picture();
- SkSafeRef(m_picture);
- DBG_NAV_LOGD("m_extendSelection=%d m_drawPointer=%d layer [%d]",
- m_extendSelection, m_drawPointer, layer->uniqueId());
- if (m_extendSelection)
- drawSelectionRegion(canvas, inval);
- if (m_drawPointer)
- drawSelectionPointer(canvas, inval);
-}
-
-static void addInval(IntRect* inval, const SkCanvas* canvas,
- const SkRect& bounds) {
- const SkMatrix& matrix = canvas->getTotalMatrix();
- SkRect transformed;
- matrix.mapRect(&transformed, bounds);
- SkIRect iTrans;
- transformed.round(&iTrans);
- inval->unite(iTrans);
-}
-
-void SelectText::drawSelectionPointer(SkCanvas* canvas, IntRect* inval)
-{
- SkPath path;
- if (m_extendSelection)
- getSelectionCaret(&path);
- else
- getSelectionArrow(&path);
- SkPixelXorXfermode xorMode(SK_ColorWHITE);
- SkPaint paint;
- paint.setAntiAlias(true);
- paint.setStyle(SkPaint::kStroke_Style);
- paint.setColor(SK_ColorBLACK);
- if (m_extendSelection)
- paint.setXfermode(&xorMode);
- else
- paint.setStrokeWidth(SK_Scalar1 * 2);
- int sc = canvas->save();
- canvas->scale(m_inverseScale, m_inverseScale);
- canvas->translate(m_selectX, m_selectY);
- canvas->drawPath(path, paint);
- if (!m_extendSelection) {
- paint.setStyle(SkPaint::kFill_Style);
- paint.setColor(SK_ColorWHITE);
- canvas->drawPath(path, paint);
- }
- SkRect bounds = path.getBounds();
- bounds.inset(-SK_Scalar1 * 2, -SK_Scalar1 * 2); // stroke width
- addInval(inval, canvas, bounds);
- canvas->restoreToCount(sc);
-}
-
-static void addStart(SkRegion* diff, const SkIRect& rect)
-{
- SkIRect bounds;
- bounds.set(rect.fLeft - CONTROL_WIDTH - STROKE_I_OUTSET,
- rect.fBottom - STROKE_I_OUTSET, rect.fLeft + STROKE_I_OUTSET,
- rect.fBottom + CONTROL_HEIGHT + STROKE_I_OUTSET);
- diff->op(bounds, SkRegion::kUnion_Op);
-}
-
-static void addEnd(SkRegion* diff, const SkIRect& rect)
-{
- SkIRect bounds;
- bounds.set(rect.fRight - STROKE_I_OUTSET, rect.fBottom - STROKE_I_OUTSET,
- rect.fRight + CONTROL_WIDTH + STROKE_I_OUTSET,
- rect.fBottom + CONTROL_HEIGHT + STROKE_I_OUTSET);
- diff->op(bounds, SkRegion::kUnion_Op);
-}
-
-void SelectText::getSelectionRegion(const IntRect& vis, SkRegion *region,
- LayerAndroid* root)
-{
- SkIRect ivisBounds = vis;
- ivisBounds.join(m_selStart);
- ivisBounds.join(m_selEnd);
- region->setEmpty();
- buildSelection(*m_picture, ivisBounds, m_selStart, m_startBase,
- m_selEnd, m_endBase, region);
- if (root && m_layerId) {
- Layer* layer = root->findById(m_layerId);
- while (layer) {
- const SkPoint& pos = layer->getPosition();
- region->translate(pos.fX, pos.fY);
- layer = layer->getParent();
- }
- }
-}
-
-void SelectText::drawSelectionRegion(SkCanvas* canvas, IntRect* inval)
-{
- if (!m_picture)
- return;
- SkIRect ivisBounds = m_visibleRect;
- ivisBounds.join(m_selStart);
- ivisBounds.join(m_selEnd);
- DBG_NAV_LOGD("m_selStart=(%d,%d,r=%d,b=%d) m_selEnd=(%d,%d,r=%d,b=%d)"
- " ivisBounds=(%d,%d,r=%d,b=%d)",
- m_selStart.fLeft, m_selStart.fTop, m_selStart.fRight, m_selStart.fBottom,
- m_selEnd.fLeft, m_selEnd.fTop, m_selEnd.fRight, m_selEnd.fBottom,
- ivisBounds.fLeft, ivisBounds.fTop, ivisBounds.fRight, ivisBounds.fBottom);
- if (m_lastSelRegion != m_selRegion)
- m_lastSelRegion.set(m_selRegion);
- SkRegion diff(m_lastSelRegion);
- m_selRegion.setEmpty();
- m_flipped = buildSelection(*m_picture, ivisBounds, m_selStart, m_startBase,
- m_selEnd, m_endBase, &m_selRegion);
- SkPath path;
- m_selRegion.getBoundaryPath(&path);
- path.setFillType(SkPath::kEvenOdd_FillType);
-
- SkPaint paint;
- paint.setAntiAlias(true);
- paint.setColor(SkColorSetARGB(0x80, 0x83, 0xCC, 0x39));
- canvas->drawPath(path, paint);
- // experiment to draw touchable controls that resize the selection
- float scale = m_controlHeight / (float)CONTROL_HEIGHT;
- canvas->save();
- canvas->translate(m_selStart.fLeft, m_selStart.fBottom);
- canvas->scale(scale, scale);
- canvas->drawPicture(m_startControl);
- canvas->restore();
- canvas->save();
- canvas->translate(m_selEnd.fRight, m_selEnd.fBottom);
- canvas->scale(scale, scale);
- canvas->drawPicture(m_endControl);
- canvas->restore();
-
-#if DEBUG_TOUCH_HANDLES
- SkRect touchHandleRect;
- paint.setColor(SkColorSetARGB(0x60, 0xFF, 0x00, 0x00));
- touchHandleRect.set(0, m_selStart.fBottom, m_selStart.fLeft, 0);
- touchHandleRect.fBottom = touchHandleRect.fTop + m_controlHeight;
- touchHandleRect.fLeft = touchHandleRect.fRight - m_controlWidth;
- canvas->drawRect(touchHandleRect, paint);
- touchHandleRect.inset(-m_controlSlop, -m_controlSlop);
- canvas->drawRect(touchHandleRect, paint);
- touchHandleRect.set(m_selEnd.fRight, m_selEnd.fBottom, 0, 0);
- touchHandleRect.fBottom = touchHandleRect.fTop + m_controlHeight;
- touchHandleRect.fRight = touchHandleRect.fLeft + m_controlWidth;
- canvas->drawRect(touchHandleRect, paint);
- touchHandleRect.inset(-m_controlSlop, -m_controlSlop);
- canvas->drawRect(touchHandleRect, paint);
-#endif
-
- SkIRect a = diff.getBounds();
- SkIRect b = m_selRegion.getBounds();
- diff.op(m_selRegion, SkRegion::kXOR_Op);
- SkIRect c = diff.getBounds();
- DBG_NAV_LOGD("old=(%d,%d,r=%d,b=%d) new=(%d,%d,r=%d,b=%d) diff=(%d,%d,r=%d,b=%d)",
- a.fLeft, a.fTop, a.fRight, a.fBottom, b.fLeft, b.fTop, b.fRight, b.fBottom,
- c.fLeft, c.fTop, c.fRight, c.fBottom);
- DBG_NAV_LOGD("lastStart=(%d,%d,r=%d,b=%d) m_lastEnd=(%d,%d,r=%d,b=%d)",
- m_lastStart.fLeft, m_lastStart.fTop, m_lastStart.fRight, m_lastStart.fBottom,
- m_lastEnd.fLeft, m_lastEnd.fTop, m_lastEnd.fRight, m_lastEnd.fBottom);
- if (!m_lastDrawnStart.isEmpty())
- addStart(&diff, m_lastDrawnStart);
- if (m_lastStart != m_selStart) {
- m_lastDrawnStart = m_lastStart;
- m_lastStart = m_selStart;
- }
- addStart(&diff, m_selStart);
- if (!m_lastDrawnEnd.isEmpty())
- addEnd(&diff, m_lastDrawnEnd);
- if (m_lastEnd != m_selEnd) {
- m_lastDrawnEnd = m_lastEnd;
- m_lastEnd = m_selEnd;
- }
- addEnd(&diff, m_selEnd);
- SkIRect iBounds = diff.getBounds();
- DBG_NAV_LOGD("diff=(%d,%d,r=%d,b=%d)",
- iBounds.fLeft, iBounds.fTop, iBounds.fRight, iBounds.fBottom);
- SkRect bounds;
- bounds.set(iBounds);
- addInval(inval, canvas, bounds);
-}
-
-void SelectText::extendSelection(const IntRect& vis, int x, int y)
-{
- if (!m_picture)
- return;
- setVisibleRect(vis);
- SkIRect clipRect = m_visibleRect;
- int base;
- DBG_NAV_LOGD("extend x/y=%d,%d m_startOffset=%d,%d", x, y,
- m_startOffset.fX, m_startOffset.fY);
- x -= m_startOffset.fX;
- y -= m_startOffset.fY;
- if (m_startSelection) {
- if (!clipRect.contains(x, y)
- || !clipRect.contains(m_original.fX, m_original.fY)) {
- clipRect.set(m_original.fX, m_original.fY, x, y);
- clipRect.sort();
- clipRect.inset(-m_visibleRect.width(), -m_visibleRect.height());
- }
- FirstCheck center(m_original.fX, m_original.fY, clipRect);
- m_selStart = m_selEnd = findClosest(center, *m_picture, &base);
- if (m_selStart.isEmpty())
- return;
- DBG_NAV_LOGD("selStart clip=(%d,%d,%d,%d) m_original=%d,%d"
- " m_selStart=(%d,%d,%d,%d)", clipRect.fLeft, clipRect.fTop,
- clipRect.fRight, clipRect.fBottom, m_original.fX, m_original.fY,
- m_selStart.fLeft, m_selStart.fTop, m_selStart.fRight, m_selStart.fBottom);
- m_startBase = m_endBase = base;
- m_startSelection = false;
- m_extendSelection = true;
- m_original.fX = m_original.fY = 0;
- }
- DBG_NAV_LOGD("extend x/y=%d,%d m_original=%d,%d", x, y,
- m_original.fX, m_original.fY);
- x -= m_original.fX;
- y -= m_original.fY;
- if (!clipRect.contains(x, y) || !clipRect.contains(m_selStart)) {
- clipRect.set(m_selStart.fLeft, m_selStart.fTop, x, y);
- clipRect.sort();
- clipRect.inset(-m_visibleRect.width(), -m_visibleRect.height());
- }
- DBG_NAV_LOGD("extend clip=(%d,%d,%d,%d) x/y=%d,%d wordSel=%s outsideWord=%s",
- clipRect.fLeft, clipRect.fTop, clipRect.fRight, clipRect.fBottom, x, y,
- m_wordSelection ? "true" : "false", m_outsideWord ? "true" : "false");
- FirstCheck extension(x, y, clipRect);
- SkIRect found = findClosest(extension, *m_picture, &base);
- if (m_wordSelection) {
- SkIRect wordBounds = m_wordBounds;
- if (!m_outsideWord)
- wordBounds.inset(-TOUCH_SLOP, -TOUCH_SLOP);
- DBG_NAV_LOGD("x=%d y=%d wordBounds=(%d,%d,r=%d,b=%d)"
- " found=(%d,%d,r=%d,b=%d)", x, y, wordBounds.fLeft, wordBounds.fTop,
- wordBounds.fRight, wordBounds.fBottom, found.fLeft, found.fTop,
- found.fRight, found.fBottom);
- if (wordBounds.contains(x, y)) {
- DBG_NAV_LOG("wordBounds.contains=true");
- m_outsideWord = false;
- return;
- }
- m_outsideWord = true;
- if (found.fBottom <= wordBounds.fTop)
- m_hitTopLeft = true;
- else if (found.fTop >= wordBounds.fBottom)
- m_hitTopLeft = false;
- else
- m_hitTopLeft = (found.fLeft + found.fRight)
- < (wordBounds.fLeft + wordBounds.fRight);
- }
- DBG_NAV_LOGD("x=%d y=%d m_startSelection=%s %s=(%d, %d, %d, %d)"
- " m_extendSelection=%s",
- x, y, m_startSelection ? "true" : "false",
- m_hitTopLeft ? "m_selStart" : "m_selEnd",
- found.fLeft, found.fTop, found.fRight, found.fBottom,
- m_extendSelection ? "true" : "false");
- if (m_hitTopLeft) {
- m_startBase = base;
- m_selStart = found;
- } else {
- m_endBase = base;
- m_selEnd = found;
- }
- swapAsNeeded();
-}
-
-SkIRect SelectText::findClosest(FirstCheck& check, const SkPicture& picture,
- int* base)
-{
- LineCheck lineCheck(check.focusX(), check.focusY(), check.getArea());
- TextCanvas lineChecker(&lineCheck);
- lineChecker.drawPicture(const_cast<SkPicture&>(picture));
- lineCheck.finish(m_selRegion);
- check.setLines(&lineCheck);
- TextCanvas checker(&check);
- checker.drawPicture(const_cast<SkPicture&>(picture));
- check.finishGlyph();
- return check.adjustedBounds(base);
-}
-
-SkIRect SelectText::findEdge(const SkPicture& picture, const SkIRect& area,
- int x, int y, bool left, int* base)
-{
- SkIRect result;
- result.setEmpty();
- FirstCheck center(x, y, area);
- center.setRecordGlyph();
- int closestBase;
- SkIRect closest = findClosest(center, picture, &closestBase);
- SkIRect sloppy = closest;
- sloppy.inset(-TOUCH_SLOP, -TOUCH_SLOP);
- if (!sloppy.contains(x, y)) {
- DBG_NAV_LOGD("sloppy=(%d, %d, %d, %d) area=(%d, %d, %d, %d) x/y=%d,%d",
- sloppy.fLeft, sloppy.fTop, sloppy.fRight, sloppy.fBottom,
- area.fLeft, area.fTop, area.fRight, area.fBottom, x, y);
- return result;
- }
- EdgeCheck edge(x, y, area, center, left);
- do { // detect left or right until there's a gap
- DBG_NAV_LOGD("edge=%p picture=%p area=%d,%d,%d,%d",
- &edge, &picture, area.fLeft, area.fTop, area.fRight, area.fBottom);
- TextCanvas checker(&edge);
- checker.drawPicture(const_cast<SkPicture&>(picture));
- edge.finishGlyph();
- if (!edge.adjacent()) {
- if (result.isEmpty()) {
- *base = closestBase;
- DBG_NAV_LOGD("closest=%d,%d,%d,%d", closest.fLeft,
- closest.fTop, closest.fRight, closest.fBottom);
- return closest;
- }
- DBG_NAV_LOG("adjacent break");
- break;
- }
- int nextBase;
- const SkIRect& next = edge.bestBounds(&nextBase);
- if (next.isEmpty()) {
- DBG_NAV_LOG("empty");
- break;
- }
- if (result == next) {
- DBG_NAV_LOG("result == next");
- break;
- }
- *base = nextBase;
- result = next;
- edge.shiftStart(result);
- } while (true);
- if (!result.isEmpty()) {
- *base += area.fTop;
- result.offset(area.fLeft, area.fTop);
- }
- return result;
-}
-
-SkIRect SelectText::findLeft(const SkPicture& picture, const SkIRect& area,
- int x, int y, int* base)
-{
- return findEdge(picture, area, x, y, true, base);
-}
-
-SkIRect SelectText::findRight(const SkPicture& picture, const SkIRect& area,
- int x, int y, int* base)
-{
- return findEdge(picture, area, x, y, false, base);
-}
-
-const String SelectText::getSelection()
-{
- if (!m_picture)
- return String();
- SkIRect clipRect;
- clipRect.set(0, 0, m_picture->width(), m_picture->height());
- String result = text(*m_picture, clipRect, m_selStart, m_startBase,
- m_selEnd, m_endBase, m_flipped);
- DBG_NAV_LOGD("clip=(%d,%d,%d,%d)"
- " m_selStart=(%d, %d, %d, %d) m_selEnd=(%d, %d, %d, %d)",
- clipRect.fLeft, clipRect.fTop, clipRect.fRight, clipRect.fBottom,
- m_selStart.fLeft, m_selStart.fTop, m_selStart.fRight, m_selStart.fBottom,
- m_selEnd.fLeft, m_selEnd.fTop, m_selEnd.fRight, m_selEnd.fBottom);
- DBG_NAV_LOGD("text=%s", result.latin1().data()); // uses CString
- return result;
-}
-
-void SelectText::getSelectionArrow(SkPath* path)
-{
- const int arrow[] = {
- 0, 14, 3, 11, 5, 15, 9, 15, 7, 11, 11, 11
- };
- for (unsigned index = 0; index < sizeof(arrow)/sizeof(arrow[0]); index += 2)
- path->lineTo(arrow[index], arrow[index + 1]);
- path->close();
-}
-
-void SelectText::getSelectionCaret(SkPath* path)
-{
- SkScalar height = m_selStart.fBottom - m_selStart.fTop;
- SkScalar dist = height / 4;
- path->moveTo(0, -height / 2);
- path->rLineTo(0, height);
- path->rLineTo(-dist, dist);
- path->rMoveTo(0, -0.5f);
- path->rLineTo(dist * 2, 0);
- path->rMoveTo(0, 0.5f);
- path->rLineTo(-dist, -dist);
-}
-
-bool SelectText::hitCorner(int cx, int cy, int x, int y) const
-{
- SkIRect test;
- test.set(cx, cy, cx + m_controlWidth, cy + m_controlHeight);
- test.inset(-m_controlSlop, -m_controlSlop);
- DBG_HANDLE_LOG("checking if %dx%d,%d-%d contains %dx%d",
- cx, cy, m_controlWidth, m_controlHeight, x, y);
- return test.contains(x, y);
-}
-
-bool SelectText::hitStartHandle(int x, int y) const
-{
- int left = m_selStart.fLeft - m_controlWidth;
- return hitCorner(left, m_selStart.fBottom, x, y);
-}
-
-bool SelectText::hitEndHandle(int x, int y) const
-{
- int left = m_selEnd.fRight;
- return hitCorner(left, m_selEnd.fBottom, x, y);
-}
-
-bool SelectText::hitSelection(int x, int y) const
-{
- x -= m_startOffset.fX;
- y -= m_startOffset.fY;
- if (hitStartHandle(x, y))
- return true;
- if (hitEndHandle(x, y))
- return true;
- return m_selRegion.contains(x, y);
-}
-
-void SelectText::getSelectionHandles(int* handles, LayerAndroid* root)
-{
- handles[0] = m_selStart.fLeft;
- handles[1] = m_selStart.fBottom;
- handles[2] = m_selEnd.fRight;
- handles[3] = m_selEnd.fBottom;
- if (root && m_layerId) {
- Layer* layer = root->findById(m_layerId);
- while (layer) {
- const SkPoint& pos = layer->getPosition();
- handles[0] += pos.fX;
- handles[2] += pos.fX;
- handles[1] += pos.fY;
- handles[3] += pos.fY;
- layer = layer->getParent();
- }
- }
-}
-
-void SelectText::moveSelection(const IntRect& vis, int x, int y)
-{
- if (!m_picture)
- return;
- x -= m_startOffset.fX;
- y -= m_startOffset.fY;
- setVisibleRect(vis);
- SkIRect clipRect = m_visibleRect;
- clipRect.join(m_selStart);
- clipRect.join(m_selEnd);
- FirstCheck center(x, y, clipRect);
- int base;
- SkIRect found = findClosest(center, *m_picture, &base);
- if (m_hitTopLeft || !m_extendSelection) {
- m_startBase = base;
- m_selStart = found;
- }
- if (!m_hitTopLeft || !m_extendSelection) {
- m_endBase = base;
- m_selEnd = found;
- }
- swapAsNeeded();
- DBG_NAV_LOGD("x=%d y=%d extendSelection=%s m_selStart=(%d, %d, %d, %d)"
- " m_selEnd=(%d, %d, %d, %d)", x, y, m_extendSelection ? "true" : "false",
- m_selStart.fLeft, m_selStart.fTop, m_selStart.fRight, m_selStart.fBottom,
- m_selEnd.fLeft, m_selEnd.fTop, m_selEnd.fRight, m_selEnd.fBottom);
-}
-
-void SelectText::reset()
-{
- DBG_NAV_LOG("m_extendSelection=false");
- m_selStart.setEmpty();
- m_lastStart.setEmpty();
- m_lastDrawnStart.setEmpty();
- m_selEnd.setEmpty();
- m_lastEnd.setEmpty();
- m_lastDrawnEnd.setEmpty();
- m_extendSelection = false;
- m_startSelection = false;
- SkSafeUnref(m_picture);
- m_picture = 0;
- m_layerId = 0;
-}
-
-IntPoint SelectText::selectableText(const CachedRoot* root)
-{
- int x = 0;
- int y = 0;
- SkPicture* picture = root->pictureAt(&x, &y, &m_layerId);
- if (!picture) {
- DBG_NAV_LOG("picture==0");
- return IntPoint(0, 0);
- }
- int width = picture->width();
- int height = picture->height();
- IntRect vis(0, 0, width, height);
- FirstCheck center(width >> 1, height >> 1, vis);
- int base;
- const SkIRect& closest = findClosest(center, *picture, &base);
- return IntPoint((closest.fLeft + closest.fRight) >> 1,
- (closest.fTop + closest.fBottom) >> 1);
-}
-
-void SelectText::selectAll()
-{
- if (!m_picture)
- return;
- m_selStart = findFirst(*m_picture, &m_startBase);
- m_selEnd = findLast(*m_picture, &m_endBase);
- m_extendSelection = true;
-}
-
-int SelectText::selectionX() const
-{
- return (m_hitTopLeft ? m_selStart.fLeft : m_selEnd.fRight) + m_startOffset.fX;
-}
-
-int SelectText::selectionY() const
-{
- const SkIRect& rect = m_hitTopLeft ? m_selStart : m_selEnd;
- return ((rect.fTop + rect.fBottom) >> 1) + m_startOffset.fY;
-}
-
-void SelectText::setVisibleRect(const IntRect& vis)
-{
- DBG_NAV_LOGD("vis=(%d,%d,w=%d,h=%d) offset=(%d,%d)",
- vis.x(), vis.y(), vis.width(), vis.height(), m_startOffset.fX,
- m_startOffset.fY);
- m_visibleRect = vis;
- m_visibleRect.offset(-m_startOffset.fX, -m_startOffset.fY);
-}
-
-bool SelectText::startSelection(const CachedRoot* root, const IntRect& vis,
- int x, int y)
-{
- m_wordSelection = false;
- m_startOffset.set(x, y);
- DBG_NAV_LOGD("x/y=(%d,%d)", x, y);
- SkSafeUnref(m_picture);
- m_picture = root->pictureAt(&x, &y, &m_layerId);
- DBG_NAV_LOGD("m_picture=%p m_layerId=%d x/y=(%d,%d)", m_picture, m_layerId,
- x, y);
- if (!m_picture) {
- DBG_NAV_LOG("picture==0");
- return false;
- }
- m_picture->ref();
- m_startOffset.fX -= x;
- m_startOffset.fY -= y;
- m_original.fX = x;
- m_original.fY = y;
- setVisibleRect(vis);
- if (m_selStart.isEmpty()) {
- DBG_NAV_LOGD("empty start picture=(%d,%d) x=%d y=%d",
- m_picture->width(), m_picture->height(), x, y);
- m_startSelection = true;
- return true;
- }
- m_hitTopLeft = hitStartHandle(x, y);
- bool hitBottomRight = hitEndHandle(x, y);
- DBG_NAV_LOGD("picture=(%d,%d) left=%d top=%d right=%d bottom=%d x=%d y=%d",
- m_picture->width(), m_picture->height(),left, top, right, bottom, x, y);
- if (m_hitTopLeft) {
- DBG_NAV_LOG("hit top left");
- m_original.fX -= m_selStart.fLeft;
- m_original.fY -= (m_selStart.fTop + m_selStart.fBottom) >> 1;
- } else if (hitBottomRight) {
- DBG_NAV_LOG("hit bottom right");
- m_original.fX -= m_selEnd.fRight;
- m_original.fY -= (m_selEnd.fTop + m_selEnd.fBottom) >> 1;
- }
- return m_hitTopLeft || hitBottomRight;
-}
-
-void SelectText::updateHandleScale(float handleScale)
-{
- m_controlHeight = CONTROL_HEIGHT * handleScale;
- m_controlWidth = CONTROL_WIDTH * handleScale;
- m_controlSlop = CONTROL_SLOP * handleScale;
-}
-
-/* selects the word at (x, y)
-* a word is normally delimited by spaces
-* a string of digits (even with inside spaces) is a word (for phone numbers)
-* FIXME: digit find isn't implemented yet
-* returns true if a word was selected
-*/
-bool SelectText::wordSelection(const CachedRoot* root, const IntRect& vis,
- int x, int y)
-{
- IntRect tapArea = IntRect(x - TOUCH_SLOP, y - TOUCH_SLOP, TOUCH_SLOP * 2,
- TOUCH_SLOP * 2);
- if (!startSelection(root, tapArea, x, y))
- return false;
- extendSelection(tapArea, x, y);
- if (m_selStart.isEmpty())
- return false;
- setDrawPointer(false);
- setVisibleRect(vis);
- SkIRect ivisBounds = m_visibleRect;
- ivisBounds.join(m_selStart);
- ivisBounds.join(m_selEnd);
- DBG_NAV_LOGD("m_selStart=(%d,%d,r=%d,b=%d) m_selEnd=(%d,%d,r=%d,b=%d)"
- " ivisBounds=(%d,%d,r=%d,b=%d)",
- m_selStart.fLeft, m_selStart.fTop, m_selStart.fRight, m_selStart.fBottom,
- m_selEnd.fLeft, m_selEnd.fTop, m_selEnd.fRight, m_selEnd.fBottom,
- ivisBounds.fLeft, ivisBounds.fTop, ivisBounds.fRight, ivisBounds.fBottom);
- m_selRegion.setEmpty();
- buildSelection(*m_picture, ivisBounds, m_selStart, m_startBase,
- m_selEnd, m_endBase, &m_selRegion);
- x = m_selStart.fLeft;
- y = (m_selStart.fTop + m_selStart.fBottom) >> 1;
- SkIRect clipRect = m_visibleRect;
- clipRect.fLeft -= m_visibleRect.width() >> 1;
- clipRect.fLeft = std::max(clipRect.fLeft, 0);
- int base;
- SkIRect left = findLeft(*m_picture, clipRect, x, y, &base);
- if (!left.isEmpty()) {
- m_startBase = base;
- m_selStart = left;
- }
- x = m_selEnd.fRight;
- y = (m_selEnd.fTop + m_selEnd.fBottom) >> 1;
- clipRect = m_visibleRect;
- clipRect.fRight += m_visibleRect.width() >> 1;
- SkIRect right = findRight(*m_picture, clipRect, x, y, &base);
- if (!right.isEmpty()) {
- m_endBase = base;
- m_selEnd = right;
- }
- DBG_NAV_LOGD("m_selStart=(%d, %d, %d, %d) m_selEnd=(%d, %d, %d, %d)",
- m_selStart.fLeft, m_selStart.fTop, m_selStart.fRight, m_selStart.fBottom,
- m_selEnd.fLeft, m_selEnd.fTop, m_selEnd.fRight, m_selEnd.fBottom);
- if (!left.isEmpty() || !right.isEmpty()) {
- m_wordBounds = m_selStart;
- m_wordBounds.join(m_selEnd);
- m_extendSelection = m_wordSelection = true;
- m_outsideWord = false;
- return true;
- }
- return false;
-}
-
-void SelectText::swapAsNeeded()
-{
- if (m_selStart.fTop >= (m_selEnd.fTop + m_selEnd.fBottom) >> 1
- || (m_selEnd.fTop < (m_selStart.fTop + m_selStart.fBottom) >> 1
- && m_selStart.fRight > m_selEnd.fLeft))
- {
- SkTSwap(m_startBase, m_endBase);
- SkTSwap(m_selStart, m_selEnd);
- m_hitTopLeft ^= true;
- DBG_NAV_LOGD("m_hitTopLeft=%s", m_hitTopLeft ? "true" : "false");
- }
-}
-
-}
diff --git a/Source/WebKit/android/nav/SelectText.h b/Source/WebKit/android/nav/SelectText.h
index b454b8e..aaaf3bb 100644
--- a/Source/WebKit/android/nav/SelectText.h
+++ b/Source/WebKit/android/nav/SelectText.h
@@ -27,90 +27,33 @@
#define SelectText_h
#include "DrawExtra.h"
-#include "IntPoint.h"
#include "IntRect.h"
#include "PlatformString.h"
-#include "SkPath.h"
-#include "SkPicture.h"
-#include "SkRect.h"
-#include "SkRegion.h"
namespace android {
-class CachedRoot;
-
-class SelectText : public DrawExtra {
-public:
- SelectText();
- virtual ~SelectText();
- virtual void draw(SkCanvas* , LayerAndroid* , IntRect* );
- void extendSelection(const IntRect& vis, int x, int y);
- const String getSelection();
- bool hitSelection(int x, int y) const;
- void moveSelection(const IntRect& vis, int x, int y);
- void reset();
- IntPoint selectableText(const CachedRoot* );
- void selectAll();
- int selectionX() const;
- int selectionY() const;
- void setDrawPointer(bool drawPointer) { m_drawPointer = drawPointer; }
- void setExtendSelection(bool extend) { m_extendSelection = extend; }
- bool startSelection(const CachedRoot* , const IntRect& vis, int x, int y);
- bool wordSelection(const CachedRoot* , const IntRect& vis, int x, int y);
- void getSelectionRegion(const IntRect& vis, SkRegion *region, LayerAndroid* root);
- void updateHandleScale(float handleScale);
- void getSelectionHandles(int* handles, LayerAndroid* root);
+class SelectText : public RegionLayerDrawExtra {
public:
- float m_inverseScale; // inverse scale, x, y used for drawing select path
- int m_selectX;
- int m_selectY;
+ enum HandleId {
+ LeftHandle = 0,
+ RightHandle = 1,
+ };
+
+ IntRect& caretRect(HandleId id) { return m_caretRects[id]; }
+ void setCaretRect(HandleId id, const IntRect& rect) { m_caretRects[id] = rect; }
+ IntRect& textRect(HandleId id) { return m_textRects[id]; }
+ void setTextRect(HandleId id, const IntRect& rect) { m_textRects[id] = rect; }
+ int caretLayerId(HandleId id) { return m_caretLayerId[id]; }
+ void setCaretLayerId(HandleId id, int layerId) { m_caretLayerId[id] = layerId; }
+
+ void setText(const String& text) { m_text = text.threadsafeCopy(); }
+ String& getText() { return m_text; }
+
private:
- int m_controlWidth;
- int m_controlHeight;
- int m_controlSlop;
- class FirstCheck;
- class EdgeCheck;
- void drawSelectionPointer(SkCanvas* , IntRect* );
- void drawSelectionRegion(SkCanvas* , IntRect* );
- SkIRect findClosest(FirstCheck& , const SkPicture& , int* base);
- SkIRect findEdge(const SkPicture& , const SkIRect& area,
- int x, int y, bool left, int* base);
- SkIRect findLeft(const SkPicture& picture, const SkIRect& area,
- int x, int y, int* base);
- SkIRect findRight(const SkPicture& picture, const SkIRect& area,
- int x, int y, int* base);
- static void getSelectionArrow(SkPath* );
- void getSelectionCaret(SkPath* );
- bool hitCorner(int cx, int cy, int x, int y) const;
- bool hitStartHandle(int x, int y) const;
- bool hitEndHandle(int x, int y) const;
- void setVisibleRect(const IntRect& );
- void swapAsNeeded();
- SkIPoint m_original; // computed start of extend selection
- SkIPoint m_startOffset; // difference from global to layer
- SkIRect m_selStart;
- SkIRect m_selEnd;
- SkIRect m_lastStart;
- SkIRect m_lastEnd;
- SkIRect m_lastDrawnStart;
- SkIRect m_lastDrawnEnd;
- SkIRect m_wordBounds;
- int m_startBase;
- int m_endBase;
- int m_layerId;
- SkIRect m_visibleRect; // constrains picture computations to visible area
- SkRegion m_lastSelRegion;
- SkRegion m_selRegion; // computed from sel start, end
- SkPicture m_startControl;
- SkPicture m_endControl;
- const SkPicture* m_picture;
- bool m_drawPointer;
- bool m_extendSelection; // false when trackball is moving pointer
- bool m_flipped;
- bool m_hitTopLeft;
- bool m_startSelection;
- bool m_wordSelection;
- bool m_outsideWord;
+ IntRect m_caretRects[2];
+ IntRect m_textRects[2];
+ int m_caretLayerId[2];
+ String m_text;
};
}
diff --git a/Source/WebKit/android/nav/WebView.cpp b/Source/WebKit/android/nav/WebView.cpp
index 7cb41d9..a67b5fd 100644
--- a/Source/WebKit/android/nav/WebView.cpp
+++ b/Source/WebKit/android/nav/WebView.cpp
@@ -30,17 +30,16 @@
#include "AndroidAnimation.h"
#include "AndroidLog.h"
#include "BaseLayerAndroid.h"
-#include "CachedFrame.h"
-#include "CachedNode.h"
-#include "CachedRoot.h"
+#include "BaseRenderer.h"
#include "DrawExtra.h"
-#include "FindCanvas.h"
#include "Frame.h"
+#include "GLWebViewState.h"
#include "GraphicsJNI.h"
#include "HTMLInputElement.h"
#include "IntPoint.h"
#include "IntRect.h"
#include "LayerAndroid.h"
+#include "LayerContent.h"
#include "Node.h"
#include "utils/Functor.h"
#include "private/hwui/DrawGlInfo.h"
@@ -53,10 +52,8 @@
#include "SkPicture.h"
#include "SkRect.h"
#include "SkTime.h"
-#ifdef ANDROID_INSTRUMENT
-#include "TimeCounter.h"
-#endif
#include "TilesManager.h"
+#include "TransferQueue.h"
#include "WebCoreJni.h"
#include "WebRequestContext.h"
#include "WebViewCore.h"
@@ -71,7 +68,7 @@
#include <JNIUtility.h>
#include <JNIHelp.h>
#include <jni.h>
-#include <ui/KeycodeLabels.h>
+#include <androidfw/KeycodeLabels.h>
#include <wtf/text/AtomicString.h>
#include <wtf/text/CString.h>
@@ -95,7 +92,7 @@ static jfieldID gWebViewField;
static jmethodID GetJMethod(JNIEnv* env, jclass clazz, const char name[], const char signature[])
{
jmethodID m = env->GetMethodID(clazz, name, signature);
- LOG_ASSERT(m, "Could not find method %s", name);
+ ALOG_ASSERT(m, "Could not find method %s", name);
return m;
}
@@ -110,105 +107,81 @@ enum FrameCachePermission {
AllowNewer
};
+#define DRAW_EXTRAS_SIZE 2
enum DrawExtras { // keep this in sync with WebView.java
DrawExtrasNone = 0,
- DrawExtrasFind = 1,
- DrawExtrasSelection = 2,
- DrawExtrasCursorRing = 3
+ DrawExtrasSelection = 1,
+ DrawExtrasCursorRing = 2
};
struct JavaGlue {
jweak m_obj;
- jmethodID m_overrideLoading;
jmethodID m_scrollBy;
- jmethodID m_sendMoveFocus;
- jmethodID m_sendMoveMouse;
- jmethodID m_sendMoveMouseIfLatest;
- jmethodID m_sendMotionUp;
- jmethodID m_domChangedFocus;
jmethodID m_getScaledMaxXScroll;
jmethodID m_getScaledMaxYScroll;
- jmethodID m_getVisibleRect;
- jmethodID m_rebuildWebTextView;
+ jmethodID m_updateRectsForGL;
jmethodID m_viewInvalidate;
jmethodID m_viewInvalidateRect;
jmethodID m_postInvalidateDelayed;
jmethodID m_pageSwapCallback;
- jmethodID m_inFullScreenMode;
jfieldID m_rectLeft;
jfieldID m_rectTop;
jmethodID m_rectWidth;
jmethodID m_rectHeight;
- jfieldID m_rectFLeft;
- jfieldID m_rectFTop;
- jmethodID m_rectFWidth;
- jmethodID m_rectFHeight;
- jmethodID m_getTextHandleScale;
+ jfieldID m_quadFP1;
+ jfieldID m_quadFP2;
+ jfieldID m_quadFP3;
+ jfieldID m_quadFP4;
AutoJObject object(JNIEnv* env) {
return getRealObject(env, m_obj);
}
} m_javaGlue;
WebView(JNIEnv* env, jobject javaWebView, int viewImpl, WTF::String drawableDir,
- bool isHighEndGfx) :
- m_ring((WebViewCore*) viewImpl)
- , m_isHighEndGfx(isHighEndGfx)
+ bool isHighEndGfx)
+ : m_isHighEndGfx(isHighEndGfx)
{
- jclass clazz = env->FindClass("android/webkit/WebView");
- // m_javaGlue = new JavaGlue;
+ memset(m_extras, 0, DRAW_EXTRAS_SIZE * sizeof(DrawExtra*));
+ jclass clazz = env->FindClass("android/webkit/WebViewClassic");
m_javaGlue.m_obj = env->NewWeakGlobalRef(javaWebView);
m_javaGlue.m_scrollBy = GetJMethod(env, clazz, "setContentScrollBy", "(IIZ)Z");
- m_javaGlue.m_overrideLoading = GetJMethod(env, clazz, "overrideLoading", "(Ljava/lang/String;)V");
- m_javaGlue.m_sendMoveFocus = GetJMethod(env, clazz, "sendMoveFocus", "(II)V");
- m_javaGlue.m_sendMoveMouse = GetJMethod(env, clazz, "sendMoveMouse", "(IIII)V");
- m_javaGlue.m_sendMoveMouseIfLatest = GetJMethod(env, clazz, "sendMoveMouseIfLatest", "(ZZ)V");
- m_javaGlue.m_sendMotionUp = GetJMethod(env, clazz, "sendMotionUp", "(IIIII)V");
- m_javaGlue.m_domChangedFocus = GetJMethod(env, clazz, "domChangedFocus", "()V");
m_javaGlue.m_getScaledMaxXScroll = GetJMethod(env, clazz, "getScaledMaxXScroll", "()I");
m_javaGlue.m_getScaledMaxYScroll = GetJMethod(env, clazz, "getScaledMaxYScroll", "()I");
- m_javaGlue.m_getVisibleRect = GetJMethod(env, clazz, "sendOurVisibleRect", "()Landroid/graphics/Rect;");
- m_javaGlue.m_rebuildWebTextView = GetJMethod(env, clazz, "rebuildWebTextView", "()V");
+ m_javaGlue.m_updateRectsForGL = GetJMethod(env, clazz, "updateRectsForGL", "()V");
m_javaGlue.m_viewInvalidate = GetJMethod(env, clazz, "viewInvalidate", "()V");
m_javaGlue.m_viewInvalidateRect = GetJMethod(env, clazz, "viewInvalidate", "(IIII)V");
m_javaGlue.m_postInvalidateDelayed = GetJMethod(env, clazz,
"viewInvalidateDelayed", "(JIIII)V");
m_javaGlue.m_pageSwapCallback = GetJMethod(env, clazz, "pageSwapCallback", "(Z)V");
- m_javaGlue.m_inFullScreenMode = GetJMethod(env, clazz, "inFullScreenMode", "()Z");
- m_javaGlue.m_getTextHandleScale = GetJMethod(env, clazz, "getTextHandleScale", "()F");
env->DeleteLocalRef(clazz);
jclass rectClass = env->FindClass("android/graphics/Rect");
- LOG_ASSERT(rectClass, "Could not find Rect class");
+ ALOG_ASSERT(rectClass, "Could not find Rect class");
m_javaGlue.m_rectLeft = env->GetFieldID(rectClass, "left", "I");
m_javaGlue.m_rectTop = env->GetFieldID(rectClass, "top", "I");
m_javaGlue.m_rectWidth = GetJMethod(env, rectClass, "width", "()I");
m_javaGlue.m_rectHeight = GetJMethod(env, rectClass, "height", "()I");
env->DeleteLocalRef(rectClass);
- jclass rectClassF = env->FindClass("android/graphics/RectF");
- LOG_ASSERT(rectClassF, "Could not find RectF class");
- m_javaGlue.m_rectFLeft = env->GetFieldID(rectClassF, "left", "F");
- m_javaGlue.m_rectFTop = env->GetFieldID(rectClassF, "top", "F");
- m_javaGlue.m_rectFWidth = GetJMethod(env, rectClassF, "width", "()F");
- m_javaGlue.m_rectFHeight = GetJMethod(env, rectClassF, "height", "()F");
- env->DeleteLocalRef(rectClassF);
+ jclass quadFClass = env->FindClass("android/webkit/QuadF");
+ ALOG_ASSERT(quadFClass, "Could not find QuadF class");
+ m_javaGlue.m_quadFP1 = env->GetFieldID(quadFClass, "p1", "Landroid/graphics/PointF;");
+ m_javaGlue.m_quadFP2 = env->GetFieldID(quadFClass, "p2", "Landroid/graphics/PointF;");
+ m_javaGlue.m_quadFP3 = env->GetFieldID(quadFClass, "p3", "Landroid/graphics/PointF;");
+ m_javaGlue.m_quadFP4 = env->GetFieldID(quadFClass, "p4", "Landroid/graphics/PointF;");
+ env->DeleteLocalRef(quadFClass);
env->SetIntField(javaWebView, gWebViewField, (jint)this);
m_viewImpl = (WebViewCore*) viewImpl;
- m_frameCacheUI = 0;
- m_navPictureUI = 0;
m_generation = 0;
m_heightCanMeasure = false;
m_lastDx = 0;
m_lastDxTime = 0;
- m_ringAnimationEnd = 0;
m_baseLayer = 0;
m_glDrawFunctor = 0;
m_isDrawingPaused = false;
- m_buttonSkin = drawableDir.isEmpty() ? 0 : new RenderSkinButton(drawableDir);
#if USE(ACCELERATED_COMPOSITING)
m_glWebViewState = 0;
- m_pageSwapCallbackRegistered = false;
#endif
}
@@ -226,11 +199,17 @@ WebView(JNIEnv* env, jobject javaWebView, int viewImpl, WTF::String drawableDir,
// deallocated base layer.
stopGL();
#endif
- delete m_frameCacheUI;
- delete m_navPictureUI;
SkSafeUnref(m_baseLayer);
delete m_glDrawFunctor;
- delete m_buttonSkin;
+ for (int i = 0; i < DRAW_EXTRAS_SIZE; i++)
+ delete m_extras[i];
+}
+
+DrawExtra* getDrawExtra(DrawExtras extras)
+{
+ if (extras == DrawExtrasNone)
+ return 0;
+ return m_extras[extras - 1];
}
void stopGL()
@@ -245,126 +224,6 @@ WebViewCore* getWebViewCore() const {
return m_viewImpl;
}
-float getTextHandleScale()
-{
- LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
- JNIEnv* env = JSC::Bindings::getJNIEnv();
- AutoJObject javaObject = m_javaGlue.object(env);
- if (!javaObject.get())
- return 0;
- float result = env->CallFloatMethod(javaObject.get(), m_javaGlue.m_getTextHandleScale);
- checkException(env);
- return result;
-}
-
-void updateSelectionHandles()
-{
- if (!m_baseLayer)
- return;
- // Adjust for device density & scale
- m_selectText.updateHandleScale(getTextHandleScale());
-}
-
-// removes the cursor altogether (e.g., when going to a new page)
-void clearCursor()
-{
- CachedRoot* root = getFrameCache(AllowNewer);
- if (!root)
- return;
- DBG_NAV_LOG("");
- m_viewImpl->m_hasCursorBounds = false;
- root->clearCursor();
- viewInvalidate();
-}
-
-// leaves the cursor where it is, but suppresses drawing it
-void hideCursor()
-{
- CachedRoot* root = getFrameCache(AllowNewer);
- if (!root)
- return;
- DBG_NAV_LOG("");
- hideCursor(root);
- viewInvalidate();
-}
-
-void hideCursor(CachedRoot* root)
-{
- DBG_NAV_LOG("inner");
- m_viewImpl->m_hasCursorBounds = false;
- root->hideCursor();
-}
-
-#if DUMP_NAV_CACHE
-void debugDump()
-{
- CachedRoot* root = getFrameCache(DontAllowNewer);
- if (root)
- root->mDebug.print();
-}
-#endif
-
-void scrollToCurrentMatch()
-{
- if (!m_findOnPage.currentMatchIsInLayer()) {
- scrollRectOnScreen(m_findOnPage.currentMatchBounds());
- return;
- }
-
- SkRect matchBounds = m_findOnPage.currentMatchBounds();
- LayerAndroid* rootLayer = getFrameCache(DontAllowNewer)->rootLayer();
- Layer* layerContainingMatch = rootLayer->findById(m_findOnPage.currentMatchLayerId());
- ASSERT(layerContainingMatch);
-
- // If the match is in a fixed position layer, there's nothing to do.
- if (layerContainingMatch->shouldInheritFromRootTransform())
- return;
-
- // If the match is in a scrollable layer or a descendant of such a layer,
- // there may be a range of of scroll configurations that will make the
- // current match visible. Our approach is the simplest possible. Starting at
- // the layer in which the match is found, we move up the layer tree,
- // scrolling any scrollable layers as little as possible to make sure that
- // the current match is in view. This approach has the disadvantage that we
- // may end up scrolling a larger number of elements than is necessary, which
- // may be visually jarring. However, minimising the number of layers
- // scrolled would complicate the code significantly.
-
- bool didScrollLayer = false;
- for (Layer* layer = layerContainingMatch; layer; layer = layer->getParent()) {
- ASSERT(layer->getParent() || layer == rootLayer);
-
- if (layer->contentIsScrollable()) {
- // Convert the match location to layer's local space and scroll it.
- // Repeatedly calling Layer::localToAncestor() is inefficient as
- // each call repeats part of the calculation. It would be more
- // efficient to maintain the transform here and update it on each
- // iteration, but that would mean duplicating logic from
- // Layer::localToAncestor() and would complicate things.
- SkMatrix transform;
- layerContainingMatch->localToAncestor(layer, &transform);
- SkRect transformedMatchBounds;
- transform.mapRect(&transformedMatchBounds, matchBounds);
- SkIRect roundedTransformedMatchBounds;
- transformedMatchBounds.roundOut(&roundedTransformedMatchBounds);
- // Only ScrollableLayerAndroid returns true for contentIsScrollable().
- didScrollLayer |= static_cast<ScrollableLayerAndroid*>(layer)->scrollRectIntoView(roundedTransformedMatchBounds);
- }
- }
- // Invalidate, as the call below to scroll the main page may be a no-op.
- if (didScrollLayer)
- viewInvalidate();
-
- // Convert matchBounds to the global space so we can scroll the main page.
- SkMatrix transform;
- layerContainingMatch->localToGlobal(&transform);
- SkRect transformedMatchBounds;
- transform.mapRect(&transformedMatchBounds, matchBounds);
- SkIRect roundedTransformedMatchBounds;
- transformedMatchBounds.roundOut(&roundedTransformedMatchBounds);
- scrollRectOnScreen(roundedTransformedMatchBounds);
-}
-
void scrollRectOnScreen(const IntRect& rect)
{
if (rect.isEmpty())
@@ -372,147 +231,59 @@ void scrollRectOnScreen(const IntRect& rect)
int dx = 0;
int left = rect.x();
int right = rect.maxX();
- if (left < m_visibleRect.fLeft)
- dx = left - m_visibleRect.fLeft;
+ if (left < m_visibleContentRect.fLeft)
+ dx = left - m_visibleContentRect.fLeft;
// Only scroll right if the entire width can fit on screen.
- else if (right > m_visibleRect.fRight
- && right - left < m_visibleRect.width())
- dx = right - m_visibleRect.fRight;
+ else if (right > m_visibleContentRect.fRight
+ && right - left < m_visibleContentRect.width())
+ dx = right - m_visibleContentRect.fRight;
int dy = 0;
int top = rect.y();
int bottom = rect.maxY();
- if (top < m_visibleRect.fTop)
- dy = top - m_visibleRect.fTop;
+ if (top < m_visibleContentRect.fTop)
+ dy = top - m_visibleContentRect.fTop;
// Only scroll down if the entire height can fit on screen
- else if (bottom > m_visibleRect.fBottom
- && bottom - top < m_visibleRect.height())
- dy = bottom - m_visibleRect.fBottom;
+ else if (bottom > m_visibleContentRect.fBottom
+ && bottom - top < m_visibleContentRect.height())
+ dy = bottom - m_visibleContentRect.fBottom;
if ((dx|dy) == 0 || !scrollBy(dx, dy))
return;
viewInvalidate();
}
-void resetCursorRing()
+int drawGL(WebCore::IntRect& invScreenRect, WebCore::IntRect* invalRect,
+ WebCore::IntRect& screenRect, int titleBarHeight,
+ WebCore::IntRect& screenClip, float scale, int extras, bool shouldDraw)
{
- m_ringAnimationEnd = 0;
- m_viewImpl->m_hasCursorBounds = false;
-}
-
-bool drawCursorPreamble(CachedRoot* root)
-{
- if (!root) return false;
- const CachedFrame* frame;
- const CachedNode* node = root->currentCursor(&frame);
- if (!node) {
- DBG_NAV_LOGV("%s", "!node");
- resetCursorRing();
- return false;
- }
- m_ring.setIsButton(node);
- if (node->isHidden()) {
- DBG_NAV_LOG("node->isHidden()");
- m_viewImpl->m_hasCursorBounds = false;
- return false;
- }
#if USE(ACCELERATED_COMPOSITING)
- if (node->isInLayer() && root->rootLayer()) {
- LayerAndroid* layer = root->rootLayer();
- layer->updateFixedLayersPositions(m_visibleRect);
- layer->updatePositions();
- }
-#endif
- setVisibleRect(root);
- m_ring.m_root = root;
- m_ring.m_frame = frame;
- m_ring.m_node = node;
- SkMSec time = SkTime::GetMSecs();
- m_ring.m_isPressed = time < m_ringAnimationEnd
- && m_ringAnimationEnd != UINT_MAX;
- return true;
-}
-
-void drawCursorPostamble()
-{
- if (m_ringAnimationEnd == UINT_MAX)
- return;
- SkMSec time = SkTime::GetMSecs();
- if (time < m_ringAnimationEnd) {
- // views assume that inval bounds coordinates are non-negative
- WebCore::IntRect invalBounds(0, 0, INT_MAX, INT_MAX);
- invalBounds.intersect(m_ring.m_absBounds);
- postInvalidateDelayed(m_ringAnimationEnd - time, invalBounds);
- } else {
- hideCursor(const_cast<CachedRoot*>(m_ring.m_root));
- }
-}
+ if (!m_baseLayer)
+ return 0;
-bool drawGL(WebCore::IntRect& viewRect, WebCore::IntRect* invalRect,
- WebCore::IntRect& webViewRect, int titleBarHeight,
- WebCore::IntRect& clip, float scale, int extras)
-{
-#if USE(ACCELERATED_COMPOSITING)
- if (!m_baseLayer || inFullScreenMode())
- return false;
+ if (m_viewImpl)
+ m_viewImpl->setPrerenderingEnabled(!m_isDrawingPaused);
if (!m_glWebViewState) {
+ TilesManager::instance()->setHighEndGfx(m_isHighEndGfx);
m_glWebViewState = new GLWebViewState();
- m_glWebViewState->setHighEndGfx(m_isHighEndGfx);
- m_glWebViewState->glExtras()->setCursorRingExtra(&m_ring);
- m_glWebViewState->glExtras()->setFindOnPageExtra(&m_findOnPage);
- if (m_baseLayer->content()) {
- SkRegion region;
- SkIRect rect;
- rect.set(0, 0, m_baseLayer->content()->width(), m_baseLayer->content()->height());
- region.setRect(rect);
- m_glWebViewState->setBaseLayer(m_baseLayer, region, false, true);
- }
+ m_glWebViewState->setBaseLayer(m_baseLayer, false, true);
}
- CachedRoot* root = getFrameCache(AllowNewer);
- if (!root) {
- DBG_NAV_LOG("!root");
- if (extras == DrawExtrasCursorRing)
- resetCursorRing();
- }
- DrawExtra* extra = 0;
- switch (extras) {
- case DrawExtrasFind:
- extra = &m_findOnPage;
- break;
- case DrawExtrasSelection:
- // This will involve a JNI call, but under normal circumstances we will
- // not hit this anyway. Only if USE_JAVA_TEXT_SELECTION is disabled
- // in WebView.java will we hit this (so really debug only)
- updateSelectionHandles();
- extra = &m_selectText;
- break;
- case DrawExtrasCursorRing:
- if (drawCursorPreamble(root) && m_ring.setup()) {
- if (m_ring.m_isPressed || m_ringAnimationEnd == UINT_MAX)
- extra = &m_ring;
- drawCursorPostamble();
- }
- break;
- default:
- ;
- }
+ DrawExtra* extra = getDrawExtra((DrawExtras) extras);
- unsigned int pic = m_glWebViewState->currentPictureCounter();
m_glWebViewState->glExtras()->setDrawExtra(extra);
// Make sure we have valid coordinates. We might not have valid coords
// if the zoom manager is still initializing. We will be redrawn
// once the correct scale is set
- if (!m_visibleRect.isFinite())
- return false;
+ if (!m_visibleContentRect.isFinite())
+ return 0;
bool treesSwapped = false;
bool newTreeHasAnim = false;
- bool ret = m_glWebViewState->drawGL(viewRect, m_visibleRect, invalRect,
- webViewRect, titleBarHeight, clip, scale,
- &treesSwapped, &newTreeHasAnim);
- if (treesSwapped && (m_pageSwapCallbackRegistered || newTreeHasAnim)) {
- m_pageSwapCallbackRegistered = false;
- LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
+ int ret = m_glWebViewState->drawGL(invScreenRect, m_visibleContentRect, invalRect,
+ screenRect, titleBarHeight, screenClip, scale,
+ &treesSwapped, &newTreeHasAnim, shouldDraw);
+ if (treesSwapped) {
+ ALOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
JNIEnv* env = JSC::Bindings::getJNIEnv();
AutoJObject javaObject = m_javaGlue.object(env);
if (javaObject.get()) {
@@ -520,237 +291,45 @@ bool drawGL(WebCore::IntRect& viewRect, WebCore::IntRect* invalRect,
checkException(env);
}
}
- if (ret || m_glWebViewState->currentPictureCounter() != pic)
- return !m_isDrawingPaused;
+ return m_isDrawingPaused ? 0 : ret;
#endif
- return false;
+ return 0;
}
-PictureSet* draw(SkCanvas* canvas, SkColor bgColor, int extras, bool split)
+void draw(SkCanvas* canvas, SkColor bgColor, DrawExtras extras)
{
- PictureSet* ret = 0;
if (!m_baseLayer) {
canvas->drawColor(bgColor);
- return ret;
+ return;
}
// draw the content of the base layer first
- PictureSet* content = m_baseLayer->content();
+ LayerContent* content = m_baseLayer->content();
int sc = canvas->save(SkCanvas::kClip_SaveFlag);
- canvas->clipRect(SkRect::MakeLTRB(0, 0, content->width(),
- content->height()), SkRegion::kDifference_Op);
- canvas->drawColor(bgColor);
- canvas->restoreToCount(sc);
- if (content->draw(canvas))
- ret = split ? new PictureSet(*content) : 0;
-
- CachedRoot* root = getFrameCache(AllowNewer);
- if (!root) {
- DBG_NAV_LOG("!root");
- if (extras == DrawExtrasCursorRing)
- resetCursorRing();
- }
- LayerAndroid mainPicture(m_navPictureUI);
- DrawExtra* extra = 0;
- switch (extras) {
- case DrawExtrasFind:
- extra = &m_findOnPage;
- break;
- case DrawExtrasSelection:
- // This will involve a JNI call, but under normal circumstances we will
- // not hit this anyway. Only if USE_JAVA_TEXT_SELECTION is disabled
- // in WebView.java will we hit this (so really debug only)
- updateSelectionHandles();
- extra = &m_selectText;
- break;
- case DrawExtrasCursorRing:
- if (drawCursorPreamble(root) && m_ring.setup()) {
- extra = &m_ring;
- drawCursorPostamble();
- }
- break;
- default:
- ;
- }
-#if USE(ACCELERATED_COMPOSITING)
- LayerAndroid* compositeLayer = compositeRoot();
- if (compositeLayer) {
- // call this to be sure we've adjusted for any scrolling or animations
- // before we actually draw
- compositeLayer->updateFixedLayersPositions(m_visibleRect);
- compositeLayer->updatePositions();
- // We have to set the canvas' matrix on the base layer
- // (to have fixed layers work as intended)
- SkAutoCanvasRestore restore(canvas, true);
- m_baseLayer->setMatrix(canvas->getTotalMatrix());
- canvas->resetMatrix();
- m_baseLayer->draw(canvas);
- }
-#endif
- if (extra) {
- IntRect dummy; // inval area, unused for now
- extra->draw(canvas, &mainPicture, &dummy);
- }
- return ret;
-}
-
-
-bool cursorIsTextInput(FrameCachePermission allowNewer)
-{
- CachedRoot* root = getFrameCache(allowNewer);
- if (!root) {
- DBG_NAV_LOG("!root");
- return false;
- }
- const CachedNode* cursor = root->currentCursor();
- if (!cursor) {
- DBG_NAV_LOG("!cursor");
- return false;
+ if (content) {
+ canvas->clipRect(SkRect::MakeLTRB(0, 0, content->width(), content->height()),
+ SkRegion::kDifference_Op);
}
- DBG_NAV_LOGD("%s", cursor->isTextInput() ? "true" : "false");
- return cursor->isTextInput();
-}
-
-void cursorRingBounds(WebCore::IntRect* bounds)
-{
- DBG_NAV_LOGD("%s", "");
- CachedRoot* root = getFrameCache(DontAllowNewer);
- if (root) {
- const CachedFrame* cachedFrame;
- const CachedNode* cachedNode = root->currentCursor(&cachedFrame);
- if (cachedNode) {
- *bounds = cachedNode->cursorRingBounds(cachedFrame);
- DBG_NAV_LOGD("bounds={%d,%d,%d,%d}", bounds->x(), bounds->y(),
- bounds->width(), bounds->height());
- return;
- }
- }
- *bounds = WebCore::IntRect(0, 0, 0, 0);
-}
+ Color c = m_baseLayer->getBackgroundColor();
+ canvas->drawColor(SkColorSetARGBInline(c.alpha(), c.red(), c.green(), c.blue()));
+ canvas->restoreToCount(sc);
-void fixCursor()
-{
- m_viewImpl->gCursorBoundsMutex.lock();
- bool hasCursorBounds = m_viewImpl->m_hasCursorBounds;
- IntRect bounds = m_viewImpl->m_cursorBounds;
- m_viewImpl->gCursorBoundsMutex.unlock();
- if (!hasCursorBounds)
- return;
- int x, y;
- const CachedFrame* frame;
- const CachedNode* node = m_frameCacheUI->findAt(bounds, &frame, &x, &y, true);
- if (!node)
- return;
- // require that node have approximately the same bounds (+/- 4) and the same
- // center (+/- 2)
- IntPoint oldCenter = IntPoint(bounds.x() + (bounds.width() >> 1),
- bounds.y() + (bounds.height() >> 1));
- IntRect newBounds = node->bounds(frame);
- IntPoint newCenter = IntPoint(newBounds.x() + (newBounds.width() >> 1),
- newBounds.y() + (newBounds.height() >> 1));
- DBG_NAV_LOGD("oldCenter=(%d,%d) newCenter=(%d,%d)"
- " bounds=(%d,%d,w=%d,h=%d) newBounds=(%d,%d,w=%d,h=%d)",
- oldCenter.x(), oldCenter.y(), newCenter.x(), newCenter.y(),
- bounds.x(), bounds.y(), bounds.width(), bounds.height(),
- newBounds.x(), newBounds.y(), newBounds.width(), newBounds.height());
- if (abs(oldCenter.x() - newCenter.x()) > 2)
- return;
- if (abs(oldCenter.y() - newCenter.y()) > 2)
- return;
- if (abs(bounds.x() - newBounds.x()) > 4)
- return;
- if (abs(bounds.y() - newBounds.y()) > 4)
- return;
- if (abs(bounds.maxX() - newBounds.maxX()) > 4)
- return;
- if (abs(bounds.maxY() - newBounds.maxY()) > 4)
- return;
- DBG_NAV_LOGD("node=%p frame=%p x=%d y=%d bounds=(%d,%d,w=%d,h=%d)",
- node, frame, x, y, bounds.x(), bounds.y(), bounds.width(),
- bounds.height());
- m_frameCacheUI->setCursor(const_cast<CachedFrame*>(frame),
- const_cast<CachedNode*>(node));
-}
+ // call this to be sure we've adjusted for any scrolling or animations
+ // before we actually draw
+ m_baseLayer->updatePositionsRecursive(m_visibleContentRect);
+ m_baseLayer->updatePositions();
-CachedRoot* getFrameCache(FrameCachePermission allowNewer)
-{
- if (!m_viewImpl->m_updatedFrameCache) {
- DBG_NAV_LOGV("%s", "!m_viewImpl->m_updatedFrameCache");
- return m_frameCacheUI;
- }
- if (allowNewer == DontAllowNewer && m_viewImpl->m_lastGeneration < m_generation) {
- DBG_NAV_LOGD("allowNewer==DontAllowNewer m_viewImpl->m_lastGeneration=%d"
- " < m_generation=%d", m_viewImpl->m_lastGeneration, m_generation);
- return m_frameCacheUI;
- }
- DBG_NAV_LOGD("%s", "m_viewImpl->m_updatedFrameCache == true");
- const CachedFrame* oldCursorFrame;
- const CachedNode* oldCursorNode = m_frameCacheUI ?
- m_frameCacheUI->currentCursor(&oldCursorFrame) : 0;
-#if USE(ACCELERATED_COMPOSITING)
- int layerId = -1;
- if (oldCursorNode && oldCursorNode->isInLayer()) {
- const LayerAndroid* cursorLayer = oldCursorFrame->layer(oldCursorNode)
- ->layer(m_frameCacheUI->rootLayer());
- if (cursorLayer)
- layerId = cursorLayer->uniqueId();
- }
-#endif
- // get id from old layer and use to find new layer
- bool oldFocusIsTextInput = false;
- void* oldFocusNodePointer = 0;
- if (m_frameCacheUI) {
- const CachedNode* oldFocus = m_frameCacheUI->currentFocus();
- if (oldFocus) {
- oldFocusIsTextInput = oldFocus->isTextInput();
- oldFocusNodePointer = oldFocus->nodePointer();
- }
- }
- m_viewImpl->gFrameCacheMutex.lock();
- delete m_frameCacheUI;
- SkSafeUnref(m_navPictureUI);
- m_viewImpl->m_updatedFrameCache = false;
- m_frameCacheUI = m_viewImpl->m_frameCacheKit;
- m_navPictureUI = m_viewImpl->m_navPictureKit;
- m_viewImpl->m_frameCacheKit = 0;
- m_viewImpl->m_navPictureKit = 0;
- m_viewImpl->gFrameCacheMutex.unlock();
- if (m_frameCacheUI)
- m_frameCacheUI->setRootLayer(compositeRoot());
-#if USE(ACCELERATED_COMPOSITING)
- if (layerId >= 0) {
- LayerAndroid* layer = const_cast<LayerAndroid*>(
- m_frameCacheUI->rootLayer());
- if (layer) {
- layer->updateFixedLayersPositions(m_visibleRect);
- layer->updatePositions();
- }
- }
-#endif
- fixCursor();
- if (oldFocusIsTextInput) {
- const CachedNode* newFocus = m_frameCacheUI->currentFocus();
- if (newFocus && oldFocusNodePointer != newFocus->nodePointer()
- && newFocus->isTextInput()
- && newFocus != m_frameCacheUI->currentCursor()) {
- // The focus has changed. We may need to update things.
- LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
- JNIEnv* env = JSC::Bindings::getJNIEnv();
- AutoJObject javaObject = m_javaGlue.object(env);
- if (javaObject.get()) {
- env->CallVoidMethod(javaObject.get(), m_javaGlue.m_domChangedFocus);
- checkException(env);
- }
- }
- }
- if (oldCursorNode && (!m_frameCacheUI || !m_frameCacheUI->currentCursor()))
- viewInvalidate(); // redraw in case cursor ring is still visible
- return m_frameCacheUI;
+ // We have to set the canvas' matrix on the base layer
+ // (to have fixed layers work as intended)
+ SkAutoCanvasRestore restore(canvas, true);
+ m_baseLayer->setMatrix(canvas->getTotalMatrix());
+ canvas->resetMatrix();
+ m_baseLayer->draw(canvas, getDrawExtra(extras));
}
int getScaledMaxXScroll()
{
- LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
+ ALOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
JNIEnv* env = JSC::Bindings::getJNIEnv();
AutoJObject javaObject = m_javaGlue.object(env);
if (!javaObject.get())
@@ -762,7 +341,7 @@ int getScaledMaxXScroll()
int getScaledMaxYScroll()
{
- LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
+ ALOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
JNIEnv* env = JSC::Bindings::getJNIEnv();
AutoJObject javaObject = m_javaGlue.object(env);
if (!javaObject.get())
@@ -772,294 +351,37 @@ int getScaledMaxYScroll()
return result;
}
-IntRect getVisibleRect()
+// Call through JNI to ask Java side to update the rectangles for GL functor.
+// This is called at every draw when it is not in process mode, so we should
+// keep this route as efficient as possible. Currently, its average cost on Xoom
+// is about 0.1ms - 0.2ms.
+// Alternatively, this can be achieved by adding more listener on Java side, but
+// that will be more likely causing jank when triggering GC.
+void updateRectsForGL()
{
- IntRect rect;
- LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
JNIEnv* env = JSC::Bindings::getJNIEnv();
AutoJObject javaObject = m_javaGlue.object(env);
if (!javaObject.get())
- return rect;
- jobject jRect = env->CallObjectMethod(javaObject.get(), m_javaGlue.m_getVisibleRect);
- checkException(env);
- rect.setX(env->GetIntField(jRect, m_javaGlue.m_rectLeft));
- checkException(env);
- rect.setY(env->GetIntField(jRect, m_javaGlue.m_rectTop));
- checkException(env);
- rect.setWidth(env->CallIntMethod(jRect, m_javaGlue.m_rectWidth));
- checkException(env);
- rect.setHeight(env->CallIntMethod(jRect, m_javaGlue.m_rectHeight));
- checkException(env);
- env->DeleteLocalRef(jRect);
- checkException(env);
- return rect;
-}
-
-static CachedFrame::Direction KeyToDirection(int32_t keyCode)
-{
- switch (keyCode) {
- case AKEYCODE_DPAD_RIGHT:
- DBG_NAV_LOGD("keyCode=%s", "right");
- return CachedFrame::RIGHT;
- case AKEYCODE_DPAD_LEFT:
- DBG_NAV_LOGD("keyCode=%s", "left");
- return CachedFrame::LEFT;
- case AKEYCODE_DPAD_DOWN:
- DBG_NAV_LOGD("keyCode=%s", "down");
- return CachedFrame::DOWN;
- case AKEYCODE_DPAD_UP:
- DBG_NAV_LOGD("keyCode=%s", "up");
- return CachedFrame::UP;
- default:
- DBG_NAV_LOGD("bad key %d sent", keyCode);
- return CachedFrame::UNINITIALIZED;
- }
-}
-
-WTF::String imageURI(int x, int y)
-{
- const CachedRoot* root = getFrameCache(DontAllowNewer);
- return root ? root->imageURI(x, y) : WTF::String();
-}
-
-bool cursorWantsKeyEvents()
-{
- const CachedRoot* root = getFrameCache(DontAllowNewer);
- if (root) {
- const CachedNode* focus = root->currentCursor();
- if (focus)
- return focus->wantsKeyEvents();
- }
- return false;
-}
-
-
-/* returns true if the key had no effect (neither scrolled nor changed cursor) */
-bool moveCursor(int keyCode, int count, bool ignoreScroll)
-{
- CachedRoot* root = getFrameCache(AllowNewer);
- if (!root) {
- DBG_NAV_LOG("!root");
- return true;
- }
-
- m_viewImpl->m_moveGeneration++;
- CachedFrame::Direction direction = KeyToDirection(keyCode);
- const CachedFrame* cachedFrame, * oldFrame = 0;
- const CachedNode* cursor = root->currentCursor(&oldFrame);
- WebCore::IntPoint cursorLocation = root->cursorLocation();
- DBG_NAV_LOGD("old cursor %d (nativeNode=%p) cursorLocation={%d, %d}",
- cursor ? cursor->index() : 0,
- cursor ? cursor->nodePointer() : 0, cursorLocation.x(), cursorLocation.y());
- WebCore::IntRect visibleRect = setVisibleRect(root);
- int xMax = getScaledMaxXScroll();
- int yMax = getScaledMaxYScroll();
- root->setMaxScroll(xMax, yMax);
- const CachedNode* cachedNode = 0;
- int dx = 0;
- int dy = 0;
- int counter = count;
- while (--counter >= 0) {
- WebCore::IntPoint scroll = WebCore::IntPoint(0, 0);
- cachedNode = root->moveCursor(direction, &cachedFrame, &scroll);
- dx += scroll.x();
- dy += scroll.y();
- }
- DBG_NAV_LOGD("new cursor %d (nativeNode=%p) cursorLocation={%d, %d}"
- "bounds={%d,%d,w=%d,h=%d}", cachedNode ? cachedNode->index() : 0,
- cachedNode ? cachedNode->nodePointer() : 0,
- root->cursorLocation().x(), root->cursorLocation().y(),
- cachedNode ? cachedNode->bounds(cachedFrame).x() : 0,
- cachedNode ? cachedNode->bounds(cachedFrame).y() : 0,
- cachedNode ? cachedNode->bounds(cachedFrame).width() : 0,
- cachedNode ? cachedNode->bounds(cachedFrame).height() : 0);
- // If !m_heightCanMeasure (such as in the browser), we want to scroll no
- // matter what
- if (!ignoreScroll && (!m_heightCanMeasure ||
- !cachedNode ||
- (cursor && cursor->nodePointer() == cachedNode->nodePointer())))
- {
- if (count == 1 && dx != 0 && dy == 0 && -m_lastDx == dx &&
- SkTime::GetMSecs() - m_lastDxTime < 1000)
- root->checkForJiggle(&dx);
- DBG_NAV_LOGD("scrollBy %d,%d", dx, dy);
- if ((dx | dy))
- this->scrollBy(dx, dy);
- m_lastDx = dx;
- m_lastDxTime = SkTime::GetMSecs();
- }
- bool result = false;
- if (cachedNode) {
- showCursorUntimed();
- m_viewImpl->updateCursorBounds(root, cachedFrame, cachedNode);
- root->setCursor(const_cast<CachedFrame*>(cachedFrame),
- const_cast<CachedNode*>(cachedNode));
- const CachedNode* focus = root->currentFocus();
- bool clearTextEntry = cachedNode != focus && focus
- && cachedNode->nodePointer() != focus->nodePointer() && focus->isTextInput();
- // Stop painting the caret if the old focus was a text input and so is the new cursor.
- bool stopPaintingCaret = clearTextEntry && cachedNode->wantsKeyEvents();
- sendMoveMouseIfLatest(clearTextEntry, stopPaintingCaret);
- } else {
- int docHeight = root->documentHeight();
- int docWidth = root->documentWidth();
- if (visibleRect.maxY() + dy > docHeight)
- dy = docHeight - visibleRect.maxY();
- else if (visibleRect.y() + dy < 0)
- dy = -visibleRect.y();
- if (visibleRect.maxX() + dx > docWidth)
- dx = docWidth - visibleRect.maxX();
- else if (visibleRect.x() < 0)
- dx = -visibleRect.x();
- result = direction == CachedFrame::LEFT ? dx >= 0 :
- direction == CachedFrame::RIGHT ? dx <= 0 :
- direction == CachedFrame::UP ? dy >= 0 : dy <= 0;
- }
- return result;
-}
-
-void notifyProgressFinished()
-{
- DBG_NAV_LOGD("cursorIsTextInput=%d", cursorIsTextInput(DontAllowNewer));
- rebuildWebTextView();
-#if DEBUG_NAV_UI
- if (m_frameCacheUI) {
- const CachedNode* focus = m_frameCacheUI->currentFocus();
- DBG_NAV_LOGD("focus %d (nativeNode=%p)",
- focus ? focus->index() : 0,
- focus ? focus->nodePointer() : 0);
- }
-#endif
-}
-
-const CachedNode* findAt(CachedRoot* root, const WebCore::IntRect& rect,
- const CachedFrame** framePtr, int* rxPtr, int* ryPtr)
-{
- *rxPtr = 0;
- *ryPtr = 0;
- *framePtr = 0;
- if (!root)
- return 0;
- setVisibleRect(root);
- return root->findAt(rect, framePtr, rxPtr, ryPtr, true);
-}
-
-IntRect setVisibleRect(CachedRoot* root)
-{
- IntRect visibleRect = getVisibleRect();
- DBG_NAV_LOGD("getVisibleRect %d,%d,%d,%d",
- visibleRect.x(), visibleRect.y(), visibleRect.width(), visibleRect.height());
- root->setVisibleRect(visibleRect);
- return visibleRect;
-}
-
-void selectBestAt(const WebCore::IntRect& rect)
-{
- const CachedFrame* frame;
- int rx, ry;
- CachedRoot* root = getFrameCache(AllowNewer);
- if (!root)
return;
- const CachedNode* node = findAt(root, rect, &frame, &rx, &ry);
- if (!node) {
- DBG_NAV_LOGD("no nodes found root=%p", root);
- root->rootHistory()->setMouseBounds(rect);
- m_viewImpl->m_hasCursorBounds = false;
- root->setCursor(0, 0);
- viewInvalidate();
- } else {
- DBG_NAV_LOGD("CachedNode:%p (%d)", node, node->index());
- WebCore::IntRect bounds = node->bounds(frame);
- root->rootHistory()->setMouseBounds(bounds);
- m_viewImpl->updateCursorBounds(root, frame, node);
- showCursorTimed();
- root->setCursor(const_cast<CachedFrame*>(frame),
- const_cast<CachedNode*>(node));
- }
- sendMoveMouseIfLatest(false, false);
-}
-
-const CachedNode* m_cacheHitNode;
-const CachedFrame* m_cacheHitFrame;
-
-bool pointInNavCache(int x, int y, int slop)
-{
- CachedRoot* root = getFrameCache(AllowNewer);
- if (!root)
- return false;
- IntRect rect = IntRect(x - slop, y - slop, slop * 2, slop * 2);
- int rx, ry;
- return (m_cacheHitNode = findAt(root, rect, &m_cacheHitFrame, &rx, &ry));
-}
-
-bool motionUp(int x, int y, int slop)
-{
- bool pageScrolled = false;
- IntRect rect = IntRect(x - slop, y - slop, slop * 2, slop * 2);
- int rx, ry;
- CachedRoot* root = getFrameCache(AllowNewer);
- if (!root)
- return 0;
- const CachedFrame* frame = 0;
- const CachedNode* result = findAt(root, rect, &frame, &rx, &ry);
- CachedHistory* history = root->rootHistory();
- if (!result) {
- DBG_NAV_LOGD("no nodes found root=%p", root);
- history->setNavBounds(rect);
- m_viewImpl->m_hasCursorBounds = false;
- root->hideCursor();
- int dx = root->checkForCenter(x, y);
- if (dx) {
- scrollBy(dx, 0);
- pageScrolled = true;
- }
- sendMotionUp(frame ? (WebCore::Frame*) frame->framePointer() : 0,
- 0, x, y);
- viewInvalidate();
- return pageScrolled;
- }
- DBG_NAV_LOGD("CachedNode:%p (%d) x=%d y=%d rx=%d ry=%d", result,
- result->index(), x, y, rx, ry);
- WebCore::IntRect navBounds = WebCore::IntRect(rx, ry, 1, 1);
- history->setNavBounds(navBounds);
- history->setMouseBounds(navBounds);
- m_viewImpl->updateCursorBounds(root, frame, result);
- root->setCursor(const_cast<CachedFrame*>(frame),
- const_cast<CachedNode*>(result));
- if (result->isSyntheticLink())
- overrideUrlLoading(result->getExport());
- else {
- sendMotionUp(
- (WebCore::Frame*) frame->framePointer(),
- (WebCore::Node*) result->nodePointer(), rx, ry);
- }
- if (result->isTextInput() || result->isSelect()
- || result->isContentEditable()) {
- showCursorUntimed();
- } else
- showCursorTimed();
- return pageScrolled;
+ env->CallVoidMethod(javaObject.get(), m_javaGlue.m_updateRectsForGL);
+ checkException(env);
}
#if USE(ACCELERATED_COMPOSITING)
static const ScrollableLayerAndroid* findScrollableLayer(
const LayerAndroid* parent, int x, int y, SkIRect* foundBounds) {
- SkRect bounds;
- parent->bounds(&bounds);
+ IntRect bounds = enclosingIntRect(parent->fullContentAreaMapped());
+
// Check the parent bounds first; this will clip to within a masking layer's
// bounds.
if (parent->masksToBounds() && !bounds.contains(x, y))
return 0;
- // Move the hit test local to parent.
- x -= bounds.fLeft;
- y -= bounds.fTop;
+
int count = parent->countChildren();
while (count--) {
const LayerAndroid* child = parent->getChild(count);
- const ScrollableLayerAndroid* result = findScrollableLayer(child, x, y,
- foundBounds);
+ const ScrollableLayerAndroid* result = findScrollableLayer(child, x, y, foundBounds);
if (result) {
- foundBounds->offset(bounds.fLeft, bounds.fTop);
if (parent->masksToBounds()) {
if (bounds.width() < foundBounds->width())
foundBounds->fRight = foundBounds->fLeft + bounds.width();
@@ -1070,7 +392,7 @@ static const ScrollableLayerAndroid* findScrollableLayer(
}
}
if (parent->contentIsScrollable()) {
- foundBounds->set(0, 0, bounds.width(), bounds.height());
+ foundBounds->set(bounds.x(), bounds.y(), bounds.width(), bounds.height());
return static_cast<const ScrollableLayerAndroid*>(parent);
}
return 0;
@@ -1080,11 +402,9 @@ static const ScrollableLayerAndroid* findScrollableLayer(
int scrollableLayer(int x, int y, SkIRect* layerRect, SkIRect* bounds)
{
#if USE(ACCELERATED_COMPOSITING)
- const LayerAndroid* layerRoot = compositeRoot();
- if (!layerRoot)
+ if (!m_baseLayer)
return 0;
- const ScrollableLayerAndroid* result = findScrollableLayer(layerRoot, x, y,
- bounds);
+ const ScrollableLayerAndroid* result = findScrollableLayer(m_baseLayer, x, y, bounds);
if (result) {
result->getScrollRect(layerRect);
return result->uniqueId();
@@ -1099,52 +419,6 @@ void scrollLayer(int layerId, int x, int y)
m_glWebViewState->scrollLayer(layerId, x, y);
}
-int getBlockLeftEdge(int x, int y, float scale)
-{
- CachedRoot* root = getFrameCache(AllowNewer);
- if (root)
- return root->getBlockLeftEdge(x, y, scale);
- return -1;
-}
-
-void overrideUrlLoading(const WTF::String& url)
-{
- JNIEnv* env = JSC::Bindings::getJNIEnv();
- AutoJObject javaObject = m_javaGlue.object(env);
- if (!javaObject.get())
- return;
- jstring jName = wtfStringToJstring(env, url);
- env->CallVoidMethod(javaObject.get(), m_javaGlue.m_overrideLoading, jName);
- env->DeleteLocalRef(jName);
-}
-
-void setFindIsUp(bool up)
-{
- DBG_NAV_LOGD("up=%d", up);
- m_viewImpl->m_findIsUp = up;
-}
-
-void setFindIsEmpty()
-{
- DBG_NAV_LOG("");
- m_findOnPage.clearCurrentLocation();
-}
-
-void showCursorTimed()
-{
- DBG_NAV_LOG("");
- m_ringAnimationEnd = SkTime::GetMSecs() + PRESSED_STATE_DURATION;
- viewInvalidate();
-}
-
-void showCursorUntimed()
-{
- DBG_NAV_LOG("");
- m_ring.m_isPressed = false;
- m_ringAnimationEnd = UINT_MAX;
- viewInvalidate();
-}
-
void setHeightCanMeasure(bool measure)
{
m_heightCanMeasure = measure;
@@ -1152,170 +426,16 @@ void setHeightCanMeasure(bool measure)
String getSelection()
{
- return m_selectText.getSelection();
-}
-
-void moveSelection(int x, int y)
-{
- m_selectText.moveSelection(getVisibleRect(), x, y);
-}
-
-IntPoint selectableText()
-{
- const CachedRoot* root = getFrameCache(DontAllowNewer);
- if (!root)
- return IntPoint(0, 0);
- return m_selectText.selectableText(root);
-}
-
-void selectAll()
-{
- m_selectText.selectAll();
-}
-
-int selectionX()
-{
- return m_selectText.selectionX();
-}
-
-int selectionY()
-{
- return m_selectText.selectionY();
-}
-
-void resetSelection()
-{
- m_selectText.reset();
-}
-
-bool startSelection(int x, int y)
-{
- const CachedRoot* root = getFrameCache(DontAllowNewer);
- if (!root)
- return false;
- updateSelectionHandles();
- return m_selectText.startSelection(root, getVisibleRect(), x, y);
-}
-
-bool wordSelection(int x, int y)
-{
- const CachedRoot* root = getFrameCache(DontAllowNewer);
- if (!root)
- return false;
- updateSelectionHandles();
- return m_selectText.wordSelection(root, getVisibleRect(), x, y);
-}
-
-bool extendSelection(int x, int y)
-{
- m_selectText.extendSelection(getVisibleRect(), x, y);
- return true;
-}
-
-bool hitSelection(int x, int y)
-{
- updateSelectionHandles();
- return m_selectText.hitSelection(x, y);
-}
-
-void setExtendSelection()
-{
- m_selectText.setExtendSelection(true);
-}
-
-void setSelectionPointer(bool set, float scale, int x, int y)
-{
- m_selectText.setDrawPointer(set);
- if (!set)
- return;
- m_selectText.m_inverseScale = scale;
- m_selectText.m_selectX = x;
- m_selectText.m_selectY = y;
-}
-
-void sendMoveFocus(WebCore::Frame* framePtr, WebCore::Node* nodePtr)
-{
- DBG_NAV_LOGD("framePtr=%p nodePtr=%p", framePtr, nodePtr);
- JNIEnv* env = JSC::Bindings::getJNIEnv();
- AutoJObject javaObject = m_javaGlue.object(env);
- if (!javaObject.get())
- return;
- env->CallVoidMethod(javaObject.get(), m_javaGlue.m_sendMoveFocus, (jint) framePtr, (jint) nodePtr);
- checkException(env);
-}
-
-void sendMoveMouse(WebCore::Frame* framePtr, WebCore::Node* nodePtr, int x, int y)
-{
- DBG_NAV_LOGD("framePtr=%p nodePtr=%p x=%d y=%d", framePtr, nodePtr, x, y);
- JNIEnv* env = JSC::Bindings::getJNIEnv();
- AutoJObject javaObject = m_javaGlue.object(env);
- if (!javaObject.get())
- return;
- env->CallVoidMethod(javaObject.get(), m_javaGlue.m_sendMoveMouse, reinterpret_cast<jint>(framePtr), reinterpret_cast<jint>(nodePtr), x, y);
- checkException(env);
-}
-
-void sendMoveMouseIfLatest(bool clearTextEntry, bool stopPaintingCaret)
-{
- LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
- JNIEnv* env = JSC::Bindings::getJNIEnv();
- AutoJObject javaObject = m_javaGlue.object(env);
- if (!javaObject.get())
- return;
- env->CallVoidMethod(javaObject.get(), m_javaGlue.m_sendMoveMouseIfLatest, clearTextEntry, stopPaintingCaret);
- checkException(env);
-}
-
-void sendMotionUp(WebCore::Frame* framePtr, WebCore::Node* nodePtr, int x, int y)
-{
- DBG_NAV_LOGD("m_generation=%d framePtr=%p nodePtr=%p x=%d y=%d", m_generation, framePtr, nodePtr, x, y);
- LOG_ASSERT(m_javaGlue.m_obj, "A WebView was not associated with this WebViewNative!");
-
- JNIEnv* env = JSC::Bindings::getJNIEnv();
- AutoJObject javaObject = m_javaGlue.object(env);
- if (!javaObject.get())
- return;
- m_viewImpl->m_touchGeneration = ++m_generation;
- env->CallVoidMethod(javaObject.get(), m_javaGlue.m_sendMotionUp, m_generation, (jint) framePtr, (jint) nodePtr, x, y);
- checkException(env);
-}
-
-void findNext(bool forward)
-{
- m_findOnPage.findNext(forward);
- scrollToCurrentMatch();
- viewInvalidate();
-}
-
-// With this call, WebView takes ownership of matches, and is responsible for
-// deleting it.
-void setMatches(WTF::Vector<MatchInfo>* matches, jboolean sameAsLastSearch)
-{
- // If this search is the same as the last one, check against the old
- // location to determine whether to scroll. If the same word is found
- // in the same place, then do not scroll.
- IntRect oldLocation;
- bool checkAgainstOldLocation = false;
- if (sameAsLastSearch && m_findOnPage.isCurrentLocationValid()) {
- oldLocation = m_findOnPage.currentMatchBounds();
- checkAgainstOldLocation = true;
- }
-
- m_findOnPage.setMatches(matches);
-
- if (!checkAgainstOldLocation || oldLocation != m_findOnPage.currentMatchBounds())
- scrollToCurrentMatch();
- viewInvalidate();
-}
-
-int currentMatchIndex()
-{
- return m_findOnPage.currentMatchIndex();
+ SelectText* select = static_cast<SelectText*>(
+ getDrawExtra(WebView::DrawExtrasSelection));
+ if (select)
+ return select->getText();
+ return String();
}
bool scrollBy(int dx, int dy)
{
- LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
+ ALOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
JNIEnv* env = JSC::Bindings::getJNIEnv();
AutoJObject javaObject = m_javaGlue.object(env);
@@ -1334,44 +454,6 @@ void setIsScrolling(bool isScrolling)
#endif
}
-bool hasCursorNode()
-{
- CachedRoot* root = getFrameCache(DontAllowNewer);
- if (!root) {
- DBG_NAV_LOG("!root");
- return false;
- }
- const CachedNode* cursorNode = root->currentCursor();
- DBG_NAV_LOGD("cursorNode=%d (nodePointer=%p)",
- cursorNode ? cursorNode->index() : -1,
- cursorNode ? cursorNode->nodePointer() : 0);
- return cursorNode;
-}
-
-bool hasFocusNode()
-{
- CachedRoot* root = getFrameCache(DontAllowNewer);
- if (!root) {
- DBG_NAV_LOG("!root");
- return false;
- }
- const CachedNode* focusNode = root->currentFocus();
- DBG_NAV_LOGD("focusNode=%d (nodePointer=%p)",
- focusNode ? focusNode->index() : -1,
- focusNode ? focusNode->nodePointer() : 0);
- return focusNode;
-}
-
-void rebuildWebTextView()
-{
- JNIEnv* env = JSC::Bindings::getJNIEnv();
- AutoJObject javaObject = m_javaGlue.object(env);
- if (!javaObject.get())
- return;
- env->CallVoidMethod(javaObject.get(), m_javaGlue.m_rebuildWebTextView);
- checkException(env);
-}
-
void viewInvalidate()
{
JNIEnv* env = JSC::Bindings::getJNIEnv();
@@ -1403,112 +485,64 @@ void postInvalidateDelayed(int64_t delay, const WebCore::IntRect& bounds)
checkException(env);
}
-bool inFullScreenMode()
-{
- JNIEnv* env = JSC::Bindings::getJNIEnv();
- AutoJObject javaObject = m_javaGlue.object(env);
- if (!javaObject.get())
- return false;
- jboolean result = env->CallBooleanMethod(javaObject.get(), m_javaGlue.m_inFullScreenMode);
- checkException(env);
- return result;
-}
-
-int moveGeneration()
-{
- return m_viewImpl->m_moveGeneration;
-}
-
-LayerAndroid* compositeRoot() const
-{
- LOG_ASSERT(!m_baseLayer || m_baseLayer->countChildren() == 1,
- "base layer can't have more than one child %s", __FUNCTION__);
- if (m_baseLayer && m_baseLayer->countChildren() == 1)
- return static_cast<LayerAndroid*>(m_baseLayer->getChild(0));
- else
- return 0;
-}
-
#if ENABLE(ANDROID_OVERFLOW_SCROLL)
-static void copyScrollPositionRecursive(const LayerAndroid* from,
- LayerAndroid* root)
+static void copyScrollPosition(const LayerAndroid* fromRoot,
+ LayerAndroid* toRoot, int layerId)
{
- if (!from || !root)
+ if (!fromRoot || !toRoot)
return;
- for (int i = 0; i < from->countChildren(); i++) {
- const LayerAndroid* l = from->getChild(i);
- if (l->contentIsScrollable()) {
- const SkPoint& pos = l->getPosition();
- LayerAndroid* match = root->findById(l->uniqueId());
- if (match && match->contentIsScrollable())
- match->setPosition(pos.fX, pos.fY);
- }
- copyScrollPositionRecursive(l, root);
- }
+ const LayerAndroid* from = fromRoot->findById(layerId);
+ LayerAndroid* to = toRoot->findById(layerId);
+ if (!from || !to || !from->contentIsScrollable() || !to->contentIsScrollable())
+ return;
+ // TODO: Support this for iframes.
+ if (to->isIFrameContent() || from->isIFrameContent())
+ return;
+ to->setScrollOffset(from->getScrollOffset());
}
#endif
-void registerPageSwapCallback()
-{
- m_pageSwapCallbackRegistered = true;
-}
+BaseLayerAndroid* getBaseLayer() const { return m_baseLayer; }
-void setBaseLayer(BaseLayerAndroid* layer, SkRegion& inval, bool showVisualIndicator,
- bool isPictureAfterFirstLayout, bool registerPageSwapCallback)
+bool setBaseLayer(BaseLayerAndroid* newBaseLayer, bool showVisualIndicator,
+ bool isPictureAfterFirstLayout, int scrollingLayer)
{
+ bool queueFull = false;
#if USE(ACCELERATED_COMPOSITING)
if (m_glWebViewState)
- m_glWebViewState->setBaseLayer(layer, inval, showVisualIndicator,
- isPictureAfterFirstLayout);
- m_pageSwapCallbackRegistered |= registerPageSwapCallback;
+ queueFull = m_glWebViewState->setBaseLayer(newBaseLayer, showVisualIndicator,
+ isPictureAfterFirstLayout);
#endif
#if ENABLE(ANDROID_OVERFLOW_SCROLL)
- if (layer) {
- // TODO: the below tree copies are only necessary in software rendering
- LayerAndroid* newCompositeRoot = static_cast<LayerAndroid*>(layer->getChild(0));
- copyScrollPositionRecursive(compositeRoot(), newCompositeRoot);
- }
+ copyScrollPosition(m_baseLayer, newBaseLayer, scrollingLayer);
#endif
SkSafeUnref(m_baseLayer);
- m_baseLayer = layer;
- CachedRoot* root = getFrameCache(DontAllowNewer);
- if (!root)
- return;
- root->resetLayers();
- root->setRootLayer(compositeRoot());
-}
-
-void getTextSelectionRegion(SkRegion *region)
-{
- m_selectText.getSelectionRegion(getVisibleRect(), region, compositeRoot());
-}
-
-void getTextSelectionHandles(int* handles)
-{
- m_selectText.getSelectionHandles(handles, compositeRoot());
-}
+ m_baseLayer = newBaseLayer;
-void replaceBaseContent(PictureSet* set)
-{
- if (!m_baseLayer)
- return;
- m_baseLayer->setContent(*set);
- delete set;
+ return queueFull;
}
void copyBaseContentToPicture(SkPicture* picture)
{
- if (!m_baseLayer)
+ if (!m_baseLayer || !m_baseLayer->content())
return;
- PictureSet* content = m_baseLayer->content();
- m_baseLayer->drawCanvas(picture->beginRecording(content->width(), content->height(),
- SkPicture::kUsePathBoundsForClip_RecordingFlag));
+ LayerContent* content = m_baseLayer->content();
+ SkCanvas* canvas = picture->beginRecording(content->width(), content->height(),
+ SkPicture::kUsePathBoundsForClip_RecordingFlag);
+
+ // clear the BaseLayerAndroid's previous matrix (set at each draw)
+ SkMatrix baseMatrix;
+ baseMatrix.reset();
+ m_baseLayer->setMatrix(baseMatrix);
+
+ m_baseLayer->draw(canvas, 0);
+
picture->endRecording();
}
bool hasContent() {
- if (!m_baseLayer)
+ if (!m_baseLayer || !m_baseLayer->content())
return false;
return !m_baseLayer->content()->isEmpty();
}
@@ -1522,37 +556,197 @@ Functor* getFunctor() {
return m_glDrawFunctor;
}
-BaseLayerAndroid* getBaseLayer() {
- return m_baseLayer;
+void setVisibleContentRect(SkRect& visibleContentRect) {
+ m_visibleContentRect = visibleContentRect;
+}
+
+void setDrawExtra(DrawExtra *extra, DrawExtras type)
+{
+ if (type == DrawExtrasNone)
+ return;
+ DrawExtra* old = m_extras[type - 1];
+ m_extras[type - 1] = extra;
+ if (old != extra) {
+ delete old;
+ }
+}
+
+void setTextSelection(SelectText *selection) {
+ setDrawExtra(selection, DrawExtrasSelection);
}
-void setVisibleRect(SkRect& visibleRect) {
- m_visibleRect = visibleRect;
+const TransformationMatrix* getLayerTransform(int layerId) {
+ if (layerId != -1 && m_baseLayer) {
+ LayerAndroid* layer = m_baseLayer->findById(layerId);
+ // We need to make sure the drawTransform is up to date as this is
+ // called before a draw() or drawGL()
+ if (layer) {
+ m_baseLayer->updatePositionsRecursive(m_visibleContentRect);
+ return layer->drawTransform();
+ }
+ }
+ return 0;
+}
+
+int getHandleLayerId(SelectText::HandleId handleId, SkIPoint& cursorPoint,
+ FloatQuad& textBounds) {
+ SelectText* selectText = static_cast<SelectText*>(getDrawExtra(DrawExtrasSelection));
+ if (!selectText || !m_baseLayer)
+ return -1;
+ int layerId = selectText->caretLayerId(handleId);
+ IntRect cursorRect = selectText->caretRect(handleId);
+ IntRect textRect = selectText->textRect(handleId);
+ // Rects exclude the last pixel on right/bottom. We want only included pixels.
+ cursorPoint.set(cursorRect.x(), cursorRect.maxY() - 1);
+ textRect.setHeight(std::max(1, textRect.height() - 1));
+ textRect.setWidth(std::max(1, textRect.width() - 1));
+ textBounds = FloatQuad(textRect);
+
+ const TransformationMatrix* transform = getLayerTransform(layerId);
+ if (transform) {
+ // We're overloading the concept of Rect to be just the two
+ // points (bottom-left and top-right.
+ cursorPoint = transform->mapPoint(cursorPoint);
+ textBounds = transform->mapQuad(textBounds);
+ }
+ return layerId;
+}
+
+void mapLayerRect(int layerId, SkIRect& rect) {
+ const TransformationMatrix* transform = getLayerTransform(layerId);
+ if (transform)
+ rect = transform->mapRect(rect);
+}
+
+void floatQuadToQuadF(JNIEnv* env, const FloatQuad& nativeTextQuad,
+ jobject textQuad)
+{
+ jobject p1 = env->GetObjectField(textQuad, m_javaGlue.m_quadFP1);
+ jobject p2 = env->GetObjectField(textQuad, m_javaGlue.m_quadFP2);
+ jobject p3 = env->GetObjectField(textQuad, m_javaGlue.m_quadFP3);
+ jobject p4 = env->GetObjectField(textQuad, m_javaGlue.m_quadFP4);
+ GraphicsJNI::point_to_jpointf(nativeTextQuad.p1(), env, p1);
+ GraphicsJNI::point_to_jpointf(nativeTextQuad.p2(), env, p2);
+ GraphicsJNI::point_to_jpointf(nativeTextQuad.p3(), env, p3);
+ GraphicsJNI::point_to_jpointf(nativeTextQuad.p4(), env, p4);
+ env->DeleteLocalRef(p1);
+ env->DeleteLocalRef(p2);
+ env->DeleteLocalRef(p3);
+ env->DeleteLocalRef(p4);
+}
+
+// This is called when WebView switches rendering modes in a more permanent fashion
+// such as when the layer type is set or the view is attached/detached from the window
+int setHwAccelerated(bool hwAccelerated) {
+ if (!m_glWebViewState)
+ return 0;
+ LayerAndroid* root = m_baseLayer;
+ if (root)
+ return root->setHwAccelerated(hwAccelerated);
+ return 0;
+}
+
+void setDrawingPaused(bool isPaused)
+{
+ m_isDrawingPaused = isPaused;
+ if (m_viewImpl)
+ m_viewImpl->setPrerenderingEnabled(!isPaused);
+}
+
+// Finds the rectangles within world to the left, right, top, and bottom
+// of rect and adds them to rects. If no intersection exists, false is returned.
+static bool findMaskedRects(const FloatRect& world,
+ const FloatRect& rect, Vector<FloatRect>& rects) {
+ if (!world.intersects(rect))
+ return false; // nothing to subtract
+
+ // left rectangle
+ if (rect.x() > world.x())
+ rects.append(FloatRect(world.x(), world.y(),
+ rect.x() - world.x(), world.height()));
+ // top rectangle
+ if (rect.y() > world.y())
+ rects.append(FloatRect(world.x(), world.y(),
+ world.width(), rect.y() - world.y()));
+ // right rectangle
+ if (rect.maxX() < world.maxX())
+ rects.append(FloatRect(rect.maxX(), world.y(),
+ world.maxX() - rect.maxX(), world.height()));
+ // bottom rectangle
+ if (rect.maxY() < world.maxY())
+ rects.append(FloatRect(world.x(), rect.maxY(),
+ world.width(), world.maxY() - rect.maxY()));
+ return true;
+}
+
+// Returns false if layerId is a fixed position layer, otherwise
+// all fixed position layer rectangles are subtracted from those within
+// rects. Rects will be modified to contain rectangles that don't include
+// the fixed position layer rectangles.
+static bool findMaskedRectsForLayer(LayerAndroid* layer,
+ Vector<FloatRect>& rects, int layerId)
+{
+ if (layer->isPositionFixed()) {
+ if (layerId == layer->uniqueId())
+ return false;
+ FloatRect layerRect = layer->fullContentAreaMapped();
+ for (int i = rects.size() - 1; i >= 0; i--)
+ if (findMaskedRects(rects[i], layerRect, rects))
+ rects.remove(i);
+ }
+
+ int childIndex = 0;
+ while (LayerAndroid* child = layer->getChild(childIndex++))
+ if (!findMaskedRectsForLayer(child, rects, layerId))
+ return false;
+
+ return true;
+}
+
+// Finds the largest rectangle not masked by any fixed layer.
+void findMaxVisibleRect(int movingLayerId, SkIRect& visibleContentRect)
+{
+ if (!m_baseLayer)
+ return;
+
+ FloatRect visibleContentFloatRect(visibleContentRect);
+ m_baseLayer->updatePositionsRecursive(visibleContentFloatRect);
+ Vector<FloatRect> rects;
+ rects.append(visibleContentFloatRect);
+ if (findMaskedRectsForLayer(m_baseLayer, rects, movingLayerId)) {
+ float maxSize = 0.0;
+ const FloatRect* largest = 0;
+ for (int i = 0; i < rects.size(); i++) {
+ const FloatRect& rect = rects[i];
+ float size = rect.width() * rect.height();
+ if (size > maxSize) {
+ maxSize = size;
+ largest = &rect;
+ }
+ }
+ if (largest) {
+ SkRect largeRect = *largest;
+ largeRect.round(&visibleContentRect);
+ }
+ }
}
- bool m_isDrawingPaused;
private: // local state for WebView
+ bool m_isDrawingPaused;
// private to getFrameCache(); other functions operate in a different thread
- CachedRoot* m_frameCacheUI; // navigation data ready for use
WebViewCore* m_viewImpl;
int m_generation; // associate unique ID with sent kit focus to match with ui
- SkPicture* m_navPictureUI;
- SkMSec m_ringAnimationEnd;
// Corresponds to the same-named boolean on the java side.
bool m_heightCanMeasure;
int m_lastDx;
SkMSec m_lastDxTime;
- SelectText m_selectText;
- FindOnPage m_findOnPage;
- CursorRing m_ring;
+ DrawExtra* m_extras[DRAW_EXTRAS_SIZE];
BaseLayerAndroid* m_baseLayer;
Functor* m_glDrawFunctor;
#if USE(ACCELERATED_COMPOSITING)
GLWebViewState* m_glWebViewState;
- bool m_pageSwapCallbackRegistered;
#endif
- RenderSkinButton* m_buttonSkin;
- SkRect m_visibleRect;
+ SkRect m_visibleContentRect;
bool m_isHighEndGfx;
}; // end of WebView class
@@ -1565,45 +759,54 @@ private: // local state for WebView
class GLDrawFunctor : Functor {
public:
GLDrawFunctor(WebView* _wvInstance,
- bool(WebView::*_funcPtr)(WebCore::IntRect&, WebCore::IntRect*,
- WebCore::IntRect&, int, WebCore::IntRect&,
- jfloat, jint),
- WebCore::IntRect _viewRect, float _scale, int _extras) {
+ int (WebView::*_funcPtr)(WebCore::IntRect&, WebCore::IntRect*,
+ WebCore::IntRect&, int, WebCore::IntRect&, jfloat, jint, bool),
+ WebCore::IntRect _invScreenRect, float _scale, int _extras) {
wvInstance = _wvInstance;
funcPtr = _funcPtr;
- viewRect = _viewRect;
+ invScreenRect = _invScreenRect;
scale = _scale;
extras = _extras;
};
+
status_t operator()(int messageId, void* data) {
- if (viewRect.isEmpty()) {
+ TRACE_METHOD();
+ bool shouldDraw = (messageId == uirenderer::DrawGlInfo::kModeDraw);
+ if (shouldDraw)
+ wvInstance->updateRectsForGL();
+
+ if (invScreenRect.isEmpty()) {
// NOOP operation if viewport is empty
return 0;
}
WebCore::IntRect inval;
- int titlebarHeight = webViewRect.height() - viewRect.height();
+ int titlebarHeight = screenRect.height() - invScreenRect.height();
uirenderer::DrawGlInfo* info = reinterpret_cast<uirenderer::DrawGlInfo*>(data);
- WebCore::IntRect localViewRect = viewRect;
- if (info->isLayer)
- localViewRect.move(-1 * localViewRect.x(), -1 * localViewRect.y());
-
- WebCore::IntRect clip(info->clipLeft, info->clipTop,
- info->clipRight - info->clipLeft,
- info->clipBottom - info->clipTop);
- TilesManager::instance()->shader()->setWebViewMatrix(info->transform, info->isLayer);
-
- bool retVal = (*wvInstance.*funcPtr)(localViewRect, &inval, webViewRect,
- titlebarHeight, clip, scale, extras);
- if (retVal) {
+ WebCore::IntRect screenClip(info->clipLeft, info->clipTop,
+ info->clipRight - info->clipLeft,
+ info->clipBottom - info->clipTop);
+
+ WebCore::IntRect localInvScreenRect = invScreenRect;
+ if (info->isLayer) {
+ // When webview is on a layer, we need to use the viewport relative
+ // to the FBO, rather than the screen(which will use invScreenRect).
+ localInvScreenRect.setX(screenClip.x());
+ localInvScreenRect.setY(info->height - screenClip.y() - screenClip.height());
+ }
+ // Send the necessary info to the shader.
+ TilesManager::instance()->shader()->setGLDrawInfo(info);
+
+ int returnFlags = (*wvInstance.*funcPtr)(localInvScreenRect, &inval, screenRect,
+ titlebarHeight, screenClip, scale, extras, shouldDraw);
+ if ((returnFlags & uirenderer::DrawGlInfo::kStatusDraw) != 0) {
IntRect finalInval;
- if (inval.isEmpty()) {
- finalInval = webViewRect;
- retVal = true;
- } else {
- finalInval.setX(webViewRect.x() + inval.x());
- finalInval.setY(webViewRect.y() + titlebarHeight + inval.y());
+ if (inval.isEmpty())
+ finalInval = screenRect;
+ else {
+ finalInval.setX(screenRect.x() + inval.x());
+ finalInval.setY(screenRect.y() + titlebarHeight + inval.y());
finalInval.setWidth(inval.width());
finalInval.setHeight(inval.height());
}
@@ -1612,201 +815,45 @@ class GLDrawFunctor : Functor {
info->dirtyRight = finalInval.maxX();
info->dirtyBottom = finalInval.maxY();
}
- // return 1 if invalidation needed, 0 otherwise
- return retVal ? 1 : 0;
+ // return 1 if invalidation needed, 2 to request non-drawing functor callback, 0 otherwise
+ ALOGV("returnFlags are %d, shouldDraw %d", returnFlags, shouldDraw);
+ return returnFlags;
+ }
+ void updateScreenRect(WebCore::IntRect& _screenRect) {
+ screenRect = _screenRect;
}
- void updateRect(WebCore::IntRect& _viewRect) {
- viewRect = _viewRect;
+ void updateInvScreenRect(WebCore::IntRect& _invScreenRect) {
+ invScreenRect = _invScreenRect;
}
- void updateViewRect(WebCore::IntRect& _viewRect) {
- webViewRect = _viewRect;
+ void updateScale(float _scale) {
+ scale = _scale;
+ }
+ void updateExtras(jint _extras) {
+ extras = _extras;
}
private:
WebView* wvInstance;
- bool (WebView::*funcPtr)(WebCore::IntRect&, WebCore::IntRect*,
- WebCore::IntRect&, int, WebCore::IntRect&, float, int);
- WebCore::IntRect viewRect;
- WebCore::IntRect webViewRect;
+ int (WebView::*funcPtr)(WebCore::IntRect&, WebCore::IntRect*,
+ WebCore::IntRect&, int, WebCore::IntRect&, float, int, bool);
+ WebCore::IntRect invScreenRect;
+ WebCore::IntRect screenRect;
jfloat scale;
jint extras;
};
-static jobject createJavaRect(JNIEnv* env, int x, int y, int right, int bottom)
-{
- jclass rectClass = env->FindClass("android/graphics/Rect");
- jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
- jobject rect = env->NewObject(rectClass, init, x, y, right, bottom);
- env->DeleteLocalRef(rectClass);
- return rect;
-}
-
/*
* Native JNI methods
*/
-static int nativeCacheHitFramePointer(JNIEnv *env, jobject obj)
-{
- return reinterpret_cast<int>(GET_NATIVE_VIEW(env, obj)
- ->m_cacheHitFrame->framePointer());
-}
-
-static jobject nativeCacheHitNodeBounds(JNIEnv *env, jobject obj)
-{
- WebCore::IntRect bounds = GET_NATIVE_VIEW(env, obj)
- ->m_cacheHitNode->originalAbsoluteBounds();
- return createJavaRect(env, bounds.x(), bounds.y(),
- bounds.maxX(), bounds.maxY());
-}
-
-static int nativeCacheHitNodePointer(JNIEnv *env, jobject obj)
-{
- return reinterpret_cast<int>(GET_NATIVE_VIEW(env, obj)
- ->m_cacheHitNode->nodePointer());
-}
-
-static bool nativeCacheHitIsPlugin(JNIEnv *env, jobject obj)
-{
- return GET_NATIVE_VIEW(env, obj)->m_cacheHitNode->isPlugin();
-}
-
-static void nativeClearCursor(JNIEnv *env, jobject obj)
-{
- WebView* view = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
- view->clearCursor();
-}
static void nativeCreate(JNIEnv *env, jobject obj, int viewImpl,
jstring drawableDir, jboolean isHighEndGfx)
{
WTF::String dir = jstringToWtfString(env, drawableDir);
- WebView* webview = new WebView(env, obj, viewImpl, dir, isHighEndGfx);
+ new WebView(env, obj, viewImpl, dir, isHighEndGfx);
// NEED THIS OR SOMETHING LIKE IT!
//Release(obj);
}
-static jint nativeCursorFramePointer(JNIEnv *env, jobject obj)
-{
- WebView* view = GET_NATIVE_VIEW(env, obj);
- CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
- if (!root)
- return 0;
- const CachedFrame* frame = 0;
- (void) root->currentCursor(&frame);
- return reinterpret_cast<int>(frame ? frame->framePointer() : 0);
-}
-
-static const CachedNode* getCursorNode(JNIEnv *env, jobject obj)
-{
- WebView* view = GET_NATIVE_VIEW(env, obj);
- CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
- return root ? root->currentCursor() : 0;
-}
-
-static const CachedNode* getCursorNode(JNIEnv *env, jobject obj,
- const CachedFrame** frame)
-{
- WebView* view = GET_NATIVE_VIEW(env, obj);
- CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
- return root ? root->currentCursor(frame) : 0;
-}
-
-static const CachedNode* getFocusCandidate(JNIEnv *env, jobject obj,
- const CachedFrame** frame)
-{
- WebView* view = GET_NATIVE_VIEW(env, obj);
- CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
- if (!root)
- return 0;
- const CachedNode* cursor = root->currentCursor(frame);
- if (cursor && cursor->wantsKeyEvents())
- return cursor;
- return root->currentFocus(frame);
-}
-
-static bool focusCandidateHasNextTextfield(JNIEnv *env, jobject obj)
-{
- WebView* view = GET_NATIVE_VIEW(env, obj);
- CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
- if (!root)
- return false;
- const CachedNode* cursor = root->currentCursor();
- if (!cursor || !cursor->isTextInput())
- cursor = root->currentFocus();
- if (!cursor || !cursor->isTextInput()) return false;
- return root->nextTextField(cursor, 0);
-}
-
-static const CachedNode* getFocusNode(JNIEnv *env, jobject obj)
-{
- WebView* view = GET_NATIVE_VIEW(env, obj);
- CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
- return root ? root->currentFocus() : 0;
-}
-
-static const CachedNode* getFocusNode(JNIEnv *env, jobject obj,
- const CachedFrame** frame)
-{
- WebView* view = GET_NATIVE_VIEW(env, obj);
- CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
- return root ? root->currentFocus(frame) : 0;
-}
-
-static const CachedInput* getInputCandidate(JNIEnv *env, jobject obj)
-{
- WebView* view = GET_NATIVE_VIEW(env, obj);
- CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
- if (!root)
- return 0;
- const CachedFrame* frame;
- const CachedNode* cursor = root->currentCursor(&frame);
- if (!cursor || !cursor->wantsKeyEvents())
- cursor = root->currentFocus(&frame);
- return cursor ? frame->textInput(cursor) : 0;
-}
-
-static jboolean nativePageShouldHandleShiftAndArrows(JNIEnv *env, jobject obj)
-{
- const CachedNode* focus = getFocusNode(env, obj);
- if (!focus) return false;
- // Plugins handle shift and arrows whether or not they have focus.
- if (focus->isPlugin()) return true;
- const CachedNode* cursor = getCursorNode(env, obj);
- // ContentEditable nodes should only receive shift and arrows if they have
- // both the cursor and the focus.
- return cursor && cursor->nodePointer() == focus->nodePointer()
- && cursor->isContentEditable();
-}
-
-static jobject nativeCursorNodeBounds(JNIEnv *env, jobject obj)
-{
- const CachedFrame* frame;
- const CachedNode* node = getCursorNode(env, obj, &frame);
- WebCore::IntRect bounds = node ? node->bounds(frame)
- : WebCore::IntRect(0, 0, 0, 0);
- return createJavaRect(env, bounds.x(), bounds.y(),
- bounds.maxX(), bounds.maxY());
-}
-
-static jint nativeCursorNodePointer(JNIEnv *env, jobject obj)
-{
- const CachedNode* node = getCursorNode(env, obj);
- return reinterpret_cast<int>(node ? node->nodePointer() : 0);
-}
-
-static jobject nativeCursorPosition(JNIEnv *env, jobject obj)
-{
- WebView* view = GET_NATIVE_VIEW(env, obj);
- const CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
- WebCore::IntPoint pos = WebCore::IntPoint(0, 0);
- if (root)
- root->getSimulatedMousePosition(&pos);
- jclass pointClass = env->FindClass("android/graphics/Point");
- jmethodID init = env->GetMethodID(pointClass, "<init>", "(II)V");
- jobject point = env->NewObject(pointClass, init, pos.x(), pos.y());
- env->DeleteLocalRef(pointClass);
- return point;
-}
-
static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj)
{
if (obj) {
@@ -1825,88 +872,67 @@ static SkRect jrectf_to_rect(JNIEnv* env, jobject obj)
return rect;
}
-static bool nativeCursorIntersects(JNIEnv *env, jobject obj, jobject visRect)
-{
- const CachedFrame* frame;
- const CachedNode* node = getCursorNode(env, obj, &frame);
- return node ? node->bounds(frame).intersects(
- jrect_to_webrect(env, visRect)) : false;
-}
-
-static bool nativeCursorIsAnchor(JNIEnv *env, jobject obj)
-{
- const CachedNode* node = getCursorNode(env, obj);
- return node ? node->isAnchor() : false;
-}
-
-static bool nativeCursorIsTextInput(JNIEnv *env, jobject obj)
-{
- const CachedNode* node = getCursorNode(env, obj);
- return node ? node->isTextInput() : false;
-}
-
-static jobject nativeCursorText(JNIEnv *env, jobject obj)
-{
- const CachedNode* node = getCursorNode(env, obj);
- if (!node)
- return 0;
- WTF::String value = node->getExport();
- return wtfStringToJstring(env, value);
-}
-
-static void nativeDebugDump(JNIEnv *env, jobject obj)
-{
-#if DUMP_NAV_CACHE
- WebView* view = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
- view->debugDump();
-#endif
-}
-
-static jint nativeDraw(JNIEnv *env, jobject obj, jobject canv,
+static void nativeDraw(JNIEnv *env, jobject obj, jobject canv,
jobject visible, jint color,
- jint extras, jboolean split) {
+ jint extras) {
SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv);
WebView* webView = GET_NATIVE_VIEW(env, obj);
- SkRect visibleRect = jrectf_to_rect(env, visible);
- webView->setVisibleRect(visibleRect);
- PictureSet* pictureSet = webView->draw(canvas, color, extras, split);
- return reinterpret_cast<jint>(pictureSet);
-}
+ SkRect visibleContentRect = jrectf_to_rect(env, visible);
+ webView->setVisibleContentRect(visibleContentRect);
+ webView->draw(canvas, color, static_cast<WebView::DrawExtras>(extras));
+}
+
+static jint nativeCreateDrawGLFunction(JNIEnv *env, jobject obj, jint nativeView,
+ jobject jinvscreenrect, jobject jscreenrect,
+ jobject jvisiblecontentrect,
+ jfloat scale, jint extras) {
+ WebCore::IntRect invScreenRect = jrect_to_webrect(env, jinvscreenrect);
+ WebView *wvInstance = reinterpret_cast<WebView*>(nativeView);
+ SkRect visibleContentRect = jrectf_to_rect(env, jvisiblecontentrect);
+ wvInstance->setVisibleContentRect(visibleContentRect);
+
+ GLDrawFunctor* functor = (GLDrawFunctor*) wvInstance->getFunctor();
+ if (!functor) {
+ functor = new GLDrawFunctor(wvInstance, &android::WebView::drawGL,
+ invScreenRect, scale, extras);
+ wvInstance->setFunctor((Functor*) functor);
+ } else {
+ functor->updateInvScreenRect(invScreenRect);
+ functor->updateScale(scale);
+ functor->updateExtras(extras);
+ }
-static jint nativeGetDrawGLFunction(JNIEnv *env, jobject obj, jint nativeView,
- jobject jrect, jobject jviewrect,
- jobject jvisiblerect,
- jfloat scale, jint extras) {
- WebCore::IntRect viewRect = jrect_to_webrect(env, jrect);
- WebView *wvInstance = (WebView*) nativeView;
- SkRect visibleRect = jrectf_to_rect(env, jvisiblerect);
- wvInstance->setVisibleRect(visibleRect);
+ WebCore::IntRect rect = jrect_to_webrect(env, jscreenrect);
+ functor->updateScreenRect(rect);
- GLDrawFunctor* functor = new GLDrawFunctor(wvInstance,
- &android::WebView::drawGL, viewRect, scale, extras);
- wvInstance->setFunctor((Functor*) functor);
+ return (jint)functor;
+}
- WebCore::IntRect webViewRect = jrect_to_webrect(env, jviewrect);
- functor->updateViewRect(webViewRect);
+static jint nativeGetDrawGLFunction(JNIEnv *env, jobject obj, jint nativeView) {
+ WebView *wvInstance = reinterpret_cast<WebView*>(nativeView);
+ if (!wvInstance)
+ return 0;
- return (jint)functor;
+ return (jint) wvInstance->getFunctor();
}
-static void nativeUpdateDrawGLFunction(JNIEnv *env, jobject obj, jobject jrect,
- jobject jviewrect, jobject jvisiblerect) {
- WebView *wvInstance = GET_NATIVE_VIEW(env, obj);
+static void nativeUpdateDrawGLFunction(JNIEnv *env, jobject obj, jint nativeView,
+ jobject jinvscreenrect, jobject jscreenrect,
+ jobject jvisiblecontentrect, jfloat scale) {
+ WebView *wvInstance = reinterpret_cast<WebView*>(nativeView);
if (wvInstance) {
GLDrawFunctor* functor = (GLDrawFunctor*) wvInstance->getFunctor();
if (functor) {
- WebCore::IntRect viewRect = jrect_to_webrect(env, jrect);
- functor->updateRect(viewRect);
+ WebCore::IntRect invScreenRect = jrect_to_webrect(env, jinvscreenrect);
+ functor->updateInvScreenRect(invScreenRect);
+
+ SkRect visibleContentRect = jrectf_to_rect(env, jvisiblecontentrect);
+ wvInstance->setVisibleContentRect(visibleContentRect);
- SkRect visibleRect = jrectf_to_rect(env, jvisiblerect);
- wvInstance->setVisibleRect(visibleRect);
+ WebCore::IntRect screenRect = jrect_to_webrect(env, jscreenrect);
+ functor->updateScreenRect(screenRect);
- WebCore::IntRect webViewRect = jrect_to_webrect(env, jviewrect);
- functor->updateViewRect(webViewRect);
+ functor->updateScale(scale);
}
}
}
@@ -1915,56 +941,29 @@ static bool nativeEvaluateLayersAnimations(JNIEnv *env, jobject obj, jint native
{
// only call in software rendering, initialize and evaluate animations
#if USE(ACCELERATED_COMPOSITING)
- LayerAndroid* root = ((WebView*)nativeView)->compositeRoot();
- if (root) {
- root->initAnimations();
- return root->evaluateAnimations();
+ BaseLayerAndroid* baseLayer = reinterpret_cast<WebView*>(nativeView)->getBaseLayer();
+ if (baseLayer) {
+ baseLayer->initAnimations();
+ return baseLayer->evaluateAnimations();
}
#endif
return false;
}
-static void nativeSetBaseLayer(JNIEnv *env, jobject obj, jint layer, jobject inval,
- jboolean showVisualIndicator,
- jboolean isPictureAfterFirstLayout,
- jboolean registerPageSwapCallback)
+static bool nativeSetBaseLayer(JNIEnv *env, jobject obj, jint nativeView, jint layer,
+ jboolean showVisualIndicator,
+ jboolean isPictureAfterFirstLayout,
+ jint scrollingLayer)
{
BaseLayerAndroid* layerImpl = reinterpret_cast<BaseLayerAndroid*>(layer);
- SkRegion invalRegion;
- if (inval)
- invalRegion = *GraphicsJNI::getNativeRegion(env, inval);
- GET_NATIVE_VIEW(env, obj)->setBaseLayer(layerImpl, invalRegion, showVisualIndicator,
- isPictureAfterFirstLayout,
- registerPageSwapCallback);
-}
-
-static void nativeGetTextSelectionRegion(JNIEnv *env, jobject obj, jint view,
- jobject region)
-{
- if (!region)
- return;
- SkRegion* nregion = GraphicsJNI::getNativeRegion(env, region);
- ((WebView*)view)->getTextSelectionRegion(nregion);
-}
-
-static void nativeGetSelectionHandles(JNIEnv *env, jobject obj, jint view,
- jintArray arr)
-{
- int handles[4];
- ((WebView*)view)->getTextSelectionHandles(handles);
- env->SetIntArrayRegion(arr, 0, 4, handles);
- checkException(env);
-}
-
-static BaseLayerAndroid* nativeGetBaseLayer(JNIEnv *env, jobject obj)
-{
- return GET_NATIVE_VIEW(env, obj)->getBaseLayer();
+ return reinterpret_cast<WebView*>(nativeView)->setBaseLayer(layerImpl, showVisualIndicator,
+ isPictureAfterFirstLayout,
+ scrollingLayer);
}
-static void nativeReplaceBaseContent(JNIEnv *env, jobject obj, jint content)
+static BaseLayerAndroid* nativeGetBaseLayer(JNIEnv *env, jobject obj, jint nativeView)
{
- PictureSet* set = reinterpret_cast<PictureSet*>(content);
- GET_NATIVE_VIEW(env, obj)->replaceBaseContent(set);
+ return reinterpret_cast<WebView*>(nativeView)->getBaseLayer();
}
static void nativeCopyBaseContentToPicture(JNIEnv *env, jobject obj, jobject pict)
@@ -1978,549 +977,40 @@ static bool nativeHasContent(JNIEnv *env, jobject obj)
return GET_NATIVE_VIEW(env, obj)->hasContent();
}
-static jobject nativeImageURI(JNIEnv *env, jobject obj, jint x, jint y)
-{
- WebView* view = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
- WTF::String uri = view->imageURI(x, y);
- return wtfStringToJstring(env, uri);
-}
-
-static jint nativeFocusCandidateFramePointer(JNIEnv *env, jobject obj)
-{
- WebView* view = GET_NATIVE_VIEW(env, obj);
- CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
- if (!root)
- return 0;
- const CachedFrame* frame = 0;
- const CachedNode* cursor = root->currentCursor(&frame);
- if (!cursor || !cursor->wantsKeyEvents())
- (void) root->currentFocus(&frame);
- return reinterpret_cast<int>(frame ? frame->framePointer() : 0);
-}
-
-static bool nativeFocusCandidateIsPassword(JNIEnv *env, jobject obj)
-{
- const CachedInput* input = getInputCandidate(env, obj);
- return input && input->getType() == CachedInput::PASSWORD;
-}
-
-static bool nativeFocusCandidateIsRtlText(JNIEnv *env, jobject obj)
-{
- const CachedInput* input = getInputCandidate(env, obj);
- return input ? input->isRtlText() : false;
-}
-
-static bool nativeFocusCandidateIsTextInput(JNIEnv *env, jobject obj)
-{
- const CachedNode* node = getFocusCandidate(env, obj, 0);
- return node ? node->isTextInput() : false;
-}
-
-static jint nativeFocusCandidateMaxLength(JNIEnv *env, jobject obj)
-{
- const CachedInput* input = getInputCandidate(env, obj);
- return input ? input->maxLength() : false;
-}
-
-static jint nativeFocusCandidateIsAutoComplete(JNIEnv *env, jobject obj)
-{
- const CachedInput* input = getInputCandidate(env, obj);
- return input ? input->autoComplete() : false;
-}
-
-static jobject nativeFocusCandidateName(JNIEnv *env, jobject obj)
-{
- const CachedInput* input = getInputCandidate(env, obj);
- if (!input)
- return 0;
- const WTF::String& name = input->name();
- return wtfStringToJstring(env, name);
-}
-
-static jobject nativeFocusCandidateNodeBounds(JNIEnv *env, jobject obj)
-{
- const CachedFrame* frame;
- const CachedNode* node = getFocusCandidate(env, obj, &frame);
- WebCore::IntRect bounds = node ? node->originalAbsoluteBounds()
- : WebCore::IntRect(0, 0, 0, 0);
- // Inset the rect by 1 unit, so that the focus candidate's border can still
- // be seen behind it.
- return createJavaRect(env, bounds.x(), bounds.y(),
- bounds.maxX(), bounds.maxY());
-}
-
-static jobject nativeFocusCandidatePaddingRect(JNIEnv *env, jobject obj)
-{
- const CachedInput* input = getInputCandidate(env, obj);
- if (!input)
- return 0;
- // Note that the Java Rect is being used to pass four integers, rather than
- // being used as an actual rectangle.
- return createJavaRect(env, input->paddingLeft(), input->paddingTop(),
- input->paddingRight(), input->paddingBottom());
-}
-
-static jint nativeFocusCandidatePointer(JNIEnv *env, jobject obj)
-{
- const CachedNode* node = getFocusCandidate(env, obj, 0);
- return reinterpret_cast<int>(node ? node->nodePointer() : 0);
-}
-
-static jint nativeFocusCandidateIsSpellcheck(JNIEnv *env, jobject obj)
-{
- const CachedInput* input = getInputCandidate(env, obj);
- return input ? input->spellcheck() : false;
-}
-
-static jobject nativeFocusCandidateText(JNIEnv *env, jobject obj)
-{
- const CachedNode* node = getFocusCandidate(env, obj, 0);
- if (!node)
- return 0;
- WTF::String value = node->getExport();
- return wtfStringToJstring(env, value);
-}
-
-static int nativeFocusCandidateLineHeight(JNIEnv *env, jobject obj)
-{
- const CachedInput* input = getInputCandidate(env, obj);
- return input ? input->lineHeight() : 0;
-}
-
-static jfloat nativeFocusCandidateTextSize(JNIEnv *env, jobject obj)
-{
- const CachedInput* input = getInputCandidate(env, obj);
- return input ? input->textSize() : 0.f;
-}
-
-static int nativeFocusCandidateType(JNIEnv *env, jobject obj)
-{
- const CachedInput* input = getInputCandidate(env, obj);
- if (!input)
- return CachedInput::NONE;
-
- if (input->isTextArea())
- return CachedInput::TEXT_AREA;
-
- return input->getType();
-}
-
-static int nativeFocusCandidateLayerId(JNIEnv *env, jobject obj)
-{
- const CachedFrame* frame = 0;
- const CachedNode* node = getFocusNode(env, obj, &frame);
- if (!node || !frame)
- return -1;
- const CachedLayer* layer = frame->layer(node);
- if (!layer)
- return -1;
- return layer->uniqueId();
-}
-
-static bool nativeFocusIsPlugin(JNIEnv *env, jobject obj)
-{
- const CachedNode* node = getFocusNode(env, obj);
- return node ? node->isPlugin() : false;
-}
-
-static jobject nativeFocusNodeBounds(JNIEnv *env, jobject obj)
-{
- const CachedFrame* frame;
- const CachedNode* node = getFocusNode(env, obj, &frame);
- WebCore::IntRect bounds = node ? node->bounds(frame)
- : WebCore::IntRect(0, 0, 0, 0);
- return createJavaRect(env, bounds.x(), bounds.y(),
- bounds.maxX(), bounds.maxY());
-}
-
-static jint nativeFocusNodePointer(JNIEnv *env, jobject obj)
-{
- const CachedNode* node = getFocusNode(env, obj);
- return node ? reinterpret_cast<int>(node->nodePointer()) : 0;
-}
-
-static bool nativeCursorWantsKeyEvents(JNIEnv* env, jobject jwebview) {
- WebView* view = GET_NATIVE_VIEW(env, jwebview);
- LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
- return view->cursorWantsKeyEvents();
-}
-
-static void nativeHideCursor(JNIEnv *env, jobject obj)
-{
- WebView* view = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
- view->hideCursor();
-}
-
-static void nativeInstrumentReport(JNIEnv *env, jobject obj)
-{
-#ifdef ANDROID_INSTRUMENT
- TimeCounter::reportNow();
-#endif
-}
-
-static void nativeSelectBestAt(JNIEnv *env, jobject obj, jobject jrect)
-{
- WebView* view = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
- WebCore::IntRect rect = jrect_to_webrect(env, jrect);
- view->selectBestAt(rect);
-}
-
-static void nativeSelectAt(JNIEnv *env, jobject obj, jint x, jint y)
-{
- WebView* view = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
- WebCore::IntRect rect = IntRect(x, y , 1, 1);
- view->selectBestAt(rect);
- if (view->hasCursorNode())
- view->showCursorUntimed();
-}
-
-static jobject nativeLayerBounds(JNIEnv* env, jobject obj, jint jlayer)
-{
- SkRect r;
-#if USE(ACCELERATED_COMPOSITING)
- LayerAndroid* layer = (LayerAndroid*) jlayer;
- r = layer->bounds();
-#else
- r.setEmpty();
-#endif
- SkIRect irect;
- r.round(&irect);
- jclass rectClass = env->FindClass("android/graphics/Rect");
- jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
- jobject rect = env->NewObject(rectClass, init, irect.fLeft, irect.fTop,
- irect.fRight, irect.fBottom);
- env->DeleteLocalRef(rectClass);
- return rect;
-}
-
-static jobject nativeSubtractLayers(JNIEnv* env, jobject obj, jobject jrect)
-{
- SkIRect irect = jrect_to_webrect(env, jrect);
-#if USE(ACCELERATED_COMPOSITING)
- LayerAndroid* root = GET_NATIVE_VIEW(env, obj)->compositeRoot();
- if (root) {
- SkRect rect;
- rect.set(irect);
- rect = root->subtractLayers(rect);
- rect.round(&irect);
- }
-#endif
- jclass rectClass = env->FindClass("android/graphics/Rect");
- jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
- jobject rect = env->NewObject(rectClass, init, irect.fLeft, irect.fTop,
- irect.fRight, irect.fBottom);
- env->DeleteLocalRef(rectClass);
- return rect;
-}
-
-static jint nativeTextGeneration(JNIEnv *env, jobject obj)
-{
- WebView* view = GET_NATIVE_VIEW(env, obj);
- CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
- return root ? root->textGeneration() : 0;
-}
-
-static bool nativePointInNavCache(JNIEnv *env, jobject obj,
- int x, int y, int slop)
-{
- return GET_NATIVE_VIEW(env, obj)->pointInNavCache(x, y, slop);
-}
-
-static bool nativeMotionUp(JNIEnv *env, jobject obj,
- int x, int y, int slop)
-{
- WebView* view = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
- return view->motionUp(x, y, slop);
-}
-
-static bool nativeHasCursorNode(JNIEnv *env, jobject obj)
-{
- return GET_NATIVE_VIEW(env, obj)->hasCursorNode();
-}
-
-static bool nativeHasFocusNode(JNIEnv *env, jobject obj)
-{
- return GET_NATIVE_VIEW(env, obj)->hasFocusNode();
-}
-
-static bool nativeMoveCursor(JNIEnv *env, jobject obj,
- int key, int count, bool ignoreScroll)
-{
- WebView* view = GET_NATIVE_VIEW(env, obj);
- DBG_NAV_LOGD("env=%p obj=%p view=%p", env, obj, view);
- LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
- return view->moveCursor(key, count, ignoreScroll);
-}
-
-static void nativeSetFindIsUp(JNIEnv *env, jobject obj, jboolean isUp)
-{
- WebView* view = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
- view->setFindIsUp(isUp);
-}
-
-static void nativeSetFindIsEmpty(JNIEnv *env, jobject obj)
-{
- GET_NATIVE_VIEW(env, obj)->setFindIsEmpty();
-}
-
-static void nativeShowCursorTimed(JNIEnv *env, jobject obj)
-{
- GET_NATIVE_VIEW(env, obj)->showCursorTimed();
-}
-
static void nativeSetHeightCanMeasure(JNIEnv *env, jobject obj, bool measure)
{
WebView* view = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(view, "view not set in nativeSetHeightCanMeasure");
+ ALOG_ASSERT(view, "view not set in nativeSetHeightCanMeasure");
view->setHeightCanMeasure(measure);
}
-static jobject nativeGetCursorRingBounds(JNIEnv *env, jobject obj)
-{
- WebView* view = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
- jclass rectClass = env->FindClass("android/graphics/Rect");
- LOG_ASSERT(rectClass, "Could not find Rect class!");
- jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
- LOG_ASSERT(init, "Could not find constructor for Rect");
- WebCore::IntRect webRect;
- view->cursorRingBounds(&webRect);
- jobject rect = env->NewObject(rectClass, init, webRect.x(),
- webRect.y(), webRect.maxX(), webRect.maxY());
- env->DeleteLocalRef(rectClass);
- return rect;
-}
-
-static int nativeFindAll(JNIEnv *env, jobject obj, jstring findLower,
- jstring findUpper, jboolean sameAsLastSearch)
-{
- // If one or the other is null, do not search.
- if (!(findLower && findUpper))
- return 0;
- // Obtain the characters for both the lower case string and the upper case
- // string representing the same word.
- const jchar* findLowerChars = env->GetStringChars(findLower, 0);
- const jchar* findUpperChars = env->GetStringChars(findUpper, 0);
- // If one or the other is null, do not search.
- if (!(findLowerChars && findUpperChars)) {
- if (findLowerChars)
- env->ReleaseStringChars(findLower, findLowerChars);
- if (findUpperChars)
- env->ReleaseStringChars(findUpper, findUpperChars);
- checkException(env);
- return 0;
- }
- WebView* view = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(view, "view not set in nativeFindAll");
- CachedRoot* root = view->getFrameCache(WebView::AllowNewer);
- if (!root) {
- env->ReleaseStringChars(findLower, findLowerChars);
- env->ReleaseStringChars(findUpper, findUpperChars);
- checkException(env);
- return 0;
- }
- int length = env->GetStringLength(findLower);
- // If the lengths of the strings do not match, then they are not the same
- // word, so do not search.
- if (!length || env->GetStringLength(findUpper) != length) {
- env->ReleaseStringChars(findLower, findLowerChars);
- env->ReleaseStringChars(findUpper, findUpperChars);
- checkException(env);
- return 0;
- }
- int width = root->documentWidth();
- int height = root->documentHeight();
- // Create a FindCanvas, which allows us to fake draw into it so we can
- // figure out where our search string is rendered (and how many times).
- FindCanvas canvas(width, height, (const UChar*) findLowerChars,
- (const UChar*) findUpperChars, length << 1);
- SkBitmap bitmap;
- bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
- canvas.setBitmapDevice(bitmap);
- root->draw(canvas);
- WTF::Vector<MatchInfo>* matches = canvas.detachMatches();
- // With setMatches, the WebView takes ownership of matches
- view->setMatches(matches, sameAsLastSearch);
-
- env->ReleaseStringChars(findLower, findLowerChars);
- env->ReleaseStringChars(findUpper, findUpperChars);
- checkException(env);
- return canvas.found();
-}
-
-static void nativeFindNext(JNIEnv *env, jobject obj, bool forward)
+static void nativeDestroy(JNIEnv *env, jobject obj, jint ptr)
{
- WebView* view = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(view, "view not set in nativeFindNext");
- view->findNext(forward);
-}
-
-static int nativeFindIndex(JNIEnv *env, jobject obj)
-{
- WebView* view = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(view, "view not set in nativeFindIndex");
- return view->currentMatchIndex();
-}
-
-static void nativeUpdateCachedTextfield(JNIEnv *env, jobject obj, jstring updatedText, jint generation)
-{
- WebView* view = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(view, "view not set in nativeUpdateCachedTextfield");
- CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
- if (!root)
- return;
- const CachedNode* cachedFocusNode = root->currentFocus();
- if (!cachedFocusNode || !cachedFocusNode->isTextInput())
- return;
- WTF::String webcoreString = jstringToWtfString(env, updatedText);
- (const_cast<CachedNode*>(cachedFocusNode))->setExport(webcoreString);
- root->setTextGeneration(generation);
- checkException(env);
-}
-
-static jint nativeGetBlockLeftEdge(JNIEnv *env, jobject obj, jint x, jint y,
- jfloat scale)
-{
- WebView* view = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
- if (!view)
- return -1;
- return view->getBlockLeftEdge(x, y, scale);
-}
-
-static void nativeDestroy(JNIEnv *env, jobject obj)
-{
- WebView* view = GET_NATIVE_VIEW(env, obj);
- LOGD("nativeDestroy view: %p", view);
- LOG_ASSERT(view, "view not set in nativeDestroy");
+ WebView* view = reinterpret_cast<WebView*>(ptr);
+ ALOGD("nativeDestroy view: %p", view);
+ ALOG_ASSERT(view, "view not set in nativeDestroy");
delete view;
}
-static void nativeStopGL(JNIEnv *env, jobject obj)
+static void nativeStopGL(JNIEnv *env, jobject obj, jint ptr)
{
- GET_NATIVE_VIEW(env, obj)->stopGL();
-}
-
-static bool nativeMoveCursorToNextTextInput(JNIEnv *env, jobject obj)
-{
- WebView* view = GET_NATIVE_VIEW(env, obj);
- CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
- if (!root)
- return false;
- const CachedNode* current = root->currentCursor();
- if (!current || !current->isTextInput())
- current = root->currentFocus();
- if (!current || !current->isTextInput())
- return false;
- const CachedFrame* frame;
- const CachedNode* next = root->nextTextField(current, &frame);
- if (!next)
- return false;
- const WebCore::IntRect& bounds = next->bounds(frame);
- root->rootHistory()->setMouseBounds(bounds);
- view->getWebViewCore()->updateCursorBounds(root, frame, next);
- view->showCursorUntimed();
- root->setCursor(const_cast<CachedFrame*>(frame),
- const_cast<CachedNode*>(next));
- view->sendMoveFocus(static_cast<WebCore::Frame*>(frame->framePointer()),
- static_cast<WebCore::Node*>(next->nodePointer()));
- if (!next->isInLayer())
- view->scrollRectOnScreen(bounds);
- view->getWebViewCore()->m_moveGeneration++;
- return true;
-}
-
-static int nativeMoveGeneration(JNIEnv *env, jobject obj)
-{
- WebView* view = GET_NATIVE_VIEW(env, obj);
- if (!view)
- return 0;
- return view->moveGeneration();
-}
-
-static void nativeMoveSelection(JNIEnv *env, jobject obj, int x, int y)
-{
- GET_NATIVE_VIEW(env, obj)->moveSelection(x, y);
-}
-
-static void nativeResetSelection(JNIEnv *env, jobject obj)
-{
- return GET_NATIVE_VIEW(env, obj)->resetSelection();
-}
-
-static jobject nativeSelectableText(JNIEnv* env, jobject obj)
-{
- IntPoint pos = GET_NATIVE_VIEW(env, obj)->selectableText();
- jclass pointClass = env->FindClass("android/graphics/Point");
- jmethodID init = env->GetMethodID(pointClass, "<init>", "(II)V");
- jobject point = env->NewObject(pointClass, init, pos.x(), pos.y());
- env->DeleteLocalRef(pointClass);
- return point;
-}
-
-static void nativeSelectAll(JNIEnv* env, jobject obj)
-{
- GET_NATIVE_VIEW(env, obj)->selectAll();
-}
-
-static void nativeSetExtendSelection(JNIEnv *env, jobject obj)
-{
- GET_NATIVE_VIEW(env, obj)->setExtendSelection();
-}
-
-static jboolean nativeStartSelection(JNIEnv *env, jobject obj, int x, int y)
-{
- return GET_NATIVE_VIEW(env, obj)->startSelection(x, y);
-}
-
-static jboolean nativeWordSelection(JNIEnv *env, jobject obj, int x, int y)
-{
- return GET_NATIVE_VIEW(env, obj)->wordSelection(x, y);
-}
-
-static void nativeExtendSelection(JNIEnv *env, jobject obj, int x, int y)
-{
- GET_NATIVE_VIEW(env, obj)->extendSelection(x, y);
+ if (ptr)
+ reinterpret_cast<WebView*>(ptr)->stopGL();
}
static jobject nativeGetSelection(JNIEnv *env, jobject obj)
{
WebView* view = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
+ ALOG_ASSERT(view, "view not set in %s", __FUNCTION__);
String selection = view->getSelection();
return wtfStringToJstring(env, selection);
}
-static jboolean nativeHitSelection(JNIEnv *env, jobject obj, int x, int y)
-{
- return GET_NATIVE_VIEW(env, obj)->hitSelection(x, y);
-}
-
-static jint nativeSelectionX(JNIEnv *env, jobject obj)
-{
- return GET_NATIVE_VIEW(env, obj)->selectionX();
-}
-
-static jint nativeSelectionY(JNIEnv *env, jobject obj)
-{
- return GET_NATIVE_VIEW(env, obj)->selectionY();
-}
-
-static void nativeSetSelectionPointer(JNIEnv *env, jobject obj, jint nativeView,
- jboolean set, jfloat scale, jint x, jint y)
-{
- ((WebView*)nativeView)->setSelectionPointer(set, scale, x, y);
-}
-
-static void nativeRegisterPageSwapCallback(JNIEnv *env, jobject obj)
+static void nativeDiscardAllTextures(JNIEnv *env, jobject obj)
{
- GET_NATIVE_VIEW(env, obj)->registerPageSwapCallback();
+ //discard all textures for debugging/test purposes, but not gl backing memory
+ bool allTextures = true, deleteGLTextures = false;
+ TilesManager::instance()->discardTextures(allTextures, deleteGLTextures);
}
static void nativeTileProfilingStart(JNIEnv *env, jobject obj)
@@ -2581,15 +1071,14 @@ static void dumpToFile(const char text[], void* file) {
}
#endif
+// Return true to view invalidate WebView
static bool nativeSetProperty(JNIEnv *env, jobject obj, jstring jkey, jstring jvalue)
{
WTF::String key = jstringToWtfString(env, jkey);
WTF::String value = jstringToWtfString(env, jvalue);
if (key == "inverted") {
- if (value == "true")
- TilesManager::instance()->setInvertedScreen(true);
- else
- TilesManager::instance()->setInvertedScreen(false);
+ bool shouldInvert = (value == "true");
+ TilesManager::instance()->setInvertedScreen(shouldInvert);
return true;
}
else if (key == "inverted_contrast") {
@@ -2600,25 +1089,47 @@ static bool nativeSetProperty(JNIEnv *env, jobject obj, jstring jkey, jstring jv
else if (key == "enable_cpu_upload_path") {
TilesManager::instance()->transferQueue()->setTextureUploadType(
value == "true" ? CpuUpload : GpuUpload);
- return true;
}
else if (key == "use_minimal_memory") {
TilesManager::instance()->setUseMinimalMemory(value == "true");
- return true;
+ }
+ else if (key == "use_double_buffering") {
+ TilesManager::instance()->setUseDoubleBuffering(value == "true");
+ }
+ else if (key == "tree_updates") {
+ TilesManager::instance()->clearContentUpdates();
}
return false;
}
-static jstring nativeGetProperty(JNIEnv *env, jobject obj, jstring key)
+static jstring nativeGetProperty(JNIEnv *env, jobject obj, jstring jkey)
{
+ WTF::String key = jstringToWtfString(env, jkey);
+ if (key == "tree_updates") {
+ int updates = TilesManager::instance()->getContentUpdates();
+ WTF::String wtfUpdates = WTF::String::number(updates);
+ return wtfStringToJstring(env, wtfUpdates);
+ }
return 0;
}
static void nativeOnTrimMemory(JNIEnv *env, jobject obj, jint level)
{
if (TilesManager::hardwareAccelerationEnabled()) {
- bool freeAllTextures = (level > TRIM_MEMORY_UI_HIDDEN);
- TilesManager::instance()->deallocateTextures(freeAllTextures);
+ // When we got TRIM_MEMORY_MODERATE or TRIM_MEMORY_COMPLETE, we should
+ // make sure the transfer queue is empty and then abandon the Surface
+ // Texture to avoid ANR b/c framework may destroy the EGL context.
+ // Refer to WindowManagerImpl.java for conditions we followed.
+ TilesManager* tilesManager = TilesManager::instance();
+ if ((level >= TRIM_MEMORY_MODERATE
+ && !tilesManager->highEndGfx())
+ || level >= TRIM_MEMORY_COMPLETE) {
+ ALOGD("OnTrimMemory with EGL Context %p", eglGetCurrentContext());
+ tilesManager->cleanupGLResources();
+ }
+
+ bool freeAllTextures = (level > TRIM_MEMORY_UI_HIDDEN), glTextures = true;
+ tilesManager->discardTextures(freeAllTextures, glTextures);
}
}
@@ -2626,7 +1137,7 @@ static void nativeDumpDisplayTree(JNIEnv* env, jobject jwebview, jstring jurl)
{
#ifdef ANDROID_DUMP_DISPLAY_TREE
WebView* view = GET_NATIVE_VIEW(env, jwebview);
- LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
+ ALOG_ASSERT(view, "view not set in %s", __FUNCTION__);
if (view && view->getWebViewCore()) {
FILE* file = fopen(DISPLAY_TREE_LOG_FILE, "w");
@@ -2643,17 +1154,17 @@ static void nativeDumpDisplayTree(JNIEnv* env, jobject jwebview, jstring jurl)
SkDumpCanvas canvas(&dumper);
// this will playback the picture into the canvas, which will
// spew its contents to the dumper
- view->draw(&canvas, 0, 0, false);
+ view->draw(&canvas, 0, WebView::DrawExtrasNone);
// we're done with the file now
fwrite("\n", 1, 1, file);
fclose(file);
}
#if USE(ACCELERATED_COMPOSITING)
- const LayerAndroid* rootLayer = view->compositeRoot();
- if (rootLayer) {
+ const LayerAndroid* baseLayer = view->getBaseLayer();
+ if (baseLayer) {
FILE* file = fopen(LAYERS_TREE_LOG_FILE,"w");
if (file) {
- rootLayer->dumpLayers(file, 0);
+ baseLayer->dumpLayers(file, 0);
fclose(file);
}
}
@@ -2662,13 +1173,13 @@ static void nativeDumpDisplayTree(JNIEnv* env, jobject jwebview, jstring jurl)
#endif
}
-static int nativeScrollableLayer(JNIEnv* env, jobject jwebview, jint x, jint y,
- jobject rect, jobject bounds)
+static int nativeScrollableLayer(JNIEnv* env, jobject jwebview, jint nativeView,
+ jint x, jint y, jobject rect, jobject bounds)
{
- WebView* view = GET_NATIVE_VIEW(env, jwebview);
- LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
+ WebView* webview = reinterpret_cast<WebView*>(nativeView);
+ ALOG_ASSERT(webview, "webview not set in %s", __FUNCTION__);
SkIRect nativeRect, nativeBounds;
- int id = view->scrollableLayer(x, y, &nativeRect, &nativeBounds);
+ int id = webview->scrollableLayer(x, y, &nativeRect, &nativeBounds);
if (rect)
GraphicsJNI::irect_to_jrect(nativeRect, env, rect);
if (bounds)
@@ -2676,18 +1187,18 @@ static int nativeScrollableLayer(JNIEnv* env, jobject jwebview, jint x, jint y,
return id;
}
-static bool nativeScrollLayer(JNIEnv* env, jobject obj, jint layerId, jint x,
- jint y)
+static bool nativeScrollLayer(JNIEnv* env, jobject obj,
+ jint nativeView, jint layerId, jint x, jint y)
{
#if ENABLE(ANDROID_OVERFLOW_SCROLL)
- WebView* view = GET_NATIVE_VIEW(env, obj);
- view->scrollLayer(layerId, x, y);
+ WebView* webview = reinterpret_cast<WebView*>(nativeView);
+ webview->scrollLayer(layerId, x, y);
//TODO: the below only needed for the SW rendering path
- LayerAndroid* root = view->compositeRoot();
- if (!root)
+ LayerAndroid* baseLayer = webview->getBaseLayer();
+ if (!baseLayer)
return false;
- LayerAndroid* layer = root->findById(layerId);
+ LayerAndroid* layer = baseLayer->findById(layerId);
if (!layer || !layer->contentIsScrollable())
return false;
return static_cast<ScrollableLayerAndroid*>(layer)->scrollTo(x, y);
@@ -2697,9 +1208,10 @@ static bool nativeScrollLayer(JNIEnv* env, jobject obj, jint layerId, jint x,
static void nativeSetIsScrolling(JNIEnv* env, jobject jwebview, jboolean isScrolling)
{
+ // TODO: Pass in the native pointer instead
WebView* view = GET_NATIVE_VIEW(env, jwebview);
- LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
- view->setIsScrolling(isScrolling);
+ if (view)
+ view->setIsScrolling(isScrolling);
}
static void nativeUseHardwareAccelSkia(JNIEnv*, jobject, jboolean enabled)
@@ -2707,9 +1219,9 @@ static void nativeUseHardwareAccelSkia(JNIEnv*, jobject, jboolean enabled)
BaseRenderer::setCurrentRendererType(enabled ? BaseRenderer::Ganesh : BaseRenderer::Raster);
}
-static int nativeGetBackgroundColor(JNIEnv* env, jobject obj)
+static int nativeGetBackgroundColor(JNIEnv* env, jobject obj, jint nativeView)
{
- WebView* view = GET_NATIVE_VIEW(env, obj);
+ WebView* view = reinterpret_cast<WebView*>(nativeView);
BaseLayerAndroid* baseLayer = view->getBaseLayer();
if (baseLayer) {
WebCore::Color color = baseLayer->getBackgroundColor();
@@ -2723,179 +1235,93 @@ static int nativeGetBackgroundColor(JNIEnv* env, jobject obj)
static void nativeSetPauseDrawing(JNIEnv *env, jobject obj, jint nativeView,
jboolean pause)
{
- ((WebView*)nativeView)->m_isDrawingPaused = pause;
+ reinterpret_cast<WebView*>(nativeView)->setDrawingPaused(pause);
+}
+
+static void nativeSetTextSelection(JNIEnv *env, jobject obj, jint nativeView,
+ jint selectionPtr)
+{
+ SelectText* selection = reinterpret_cast<SelectText*>(selectionPtr);
+ reinterpret_cast<WebView*>(nativeView)->setTextSelection(selection);
+}
+
+static jint nativeGetHandleLayerId(JNIEnv *env, jobject obj, jint nativeView,
+ jint handleIndex, jobject cursorPoint,
+ jobject textQuad)
+{
+ WebView* webview = reinterpret_cast<WebView*>(nativeView);
+ SkIPoint nativePoint;
+ FloatQuad nativeTextQuad;
+ int layerId = webview->getHandleLayerId((SelectText::HandleId) handleIndex,
+ nativePoint, nativeTextQuad);
+ if (cursorPoint)
+ GraphicsJNI::ipoint_to_jpoint(nativePoint, env, cursorPoint);
+ if (textQuad)
+ webview->floatQuadToQuadF(env, nativeTextQuad, textQuad);
+ return layerId;
+}
+
+static void nativeMapLayerRect(JNIEnv *env, jobject obj, jint nativeView,
+ jint layerId, jobject rect)
+{
+ WebView* webview = reinterpret_cast<WebView*>(nativeView);
+ SkIRect nativeRect;
+ GraphicsJNI::jrect_to_irect(env, rect, &nativeRect);
+ webview->mapLayerRect(layerId, nativeRect);
+ GraphicsJNI::irect_to_jrect(nativeRect, env, rect);
+}
+
+static jint nativeSetHwAccelerated(JNIEnv *env, jobject obj, jint nativeView,
+ jboolean hwAccelerated)
+{
+ WebView* webview = reinterpret_cast<WebView*>(nativeView);
+ return webview->setHwAccelerated(hwAccelerated);
+}
+
+static void nativeFindMaxVisibleRect(JNIEnv *env, jobject obj, jint nativeView,
+ jint movingLayerId, jobject visibleContentRect)
+{
+ WebView* webview = reinterpret_cast<WebView*>(nativeView);
+ SkIRect nativeRect;
+ GraphicsJNI::jrect_to_irect(env, visibleContentRect, &nativeRect);
+ webview->findMaxVisibleRect(movingLayerId, nativeRect);
+ GraphicsJNI::irect_to_jrect(nativeRect, env, visibleContentRect);
}
/*
* JNI registration
*/
static JNINativeMethod gJavaWebViewMethods[] = {
- { "nativeCacheHitFramePointer", "()I",
- (void*) nativeCacheHitFramePointer },
- { "nativeCacheHitIsPlugin", "()Z",
- (void*) nativeCacheHitIsPlugin },
- { "nativeCacheHitNodeBounds", "()Landroid/graphics/Rect;",
- (void*) nativeCacheHitNodeBounds },
- { "nativeCacheHitNodePointer", "()I",
- (void*) nativeCacheHitNodePointer },
- { "nativeClearCursor", "()V",
- (void*) nativeClearCursor },
{ "nativeCreate", "(ILjava/lang/String;Z)V",
(void*) nativeCreate },
- { "nativeCursorFramePointer", "()I",
- (void*) nativeCursorFramePointer },
- { "nativePageShouldHandleShiftAndArrows", "()Z",
- (void*) nativePageShouldHandleShiftAndArrows },
- { "nativeCursorNodeBounds", "()Landroid/graphics/Rect;",
- (void*) nativeCursorNodeBounds },
- { "nativeCursorNodePointer", "()I",
- (void*) nativeCursorNodePointer },
- { "nativeCursorIntersects", "(Landroid/graphics/Rect;)Z",
- (void*) nativeCursorIntersects },
- { "nativeCursorIsAnchor", "()Z",
- (void*) nativeCursorIsAnchor },
- { "nativeCursorIsTextInput", "()Z",
- (void*) nativeCursorIsTextInput },
- { "nativeCursorPosition", "()Landroid/graphics/Point;",
- (void*) nativeCursorPosition },
- { "nativeCursorText", "()Ljava/lang/String;",
- (void*) nativeCursorText },
- { "nativeCursorWantsKeyEvents", "()Z",
- (void*)nativeCursorWantsKeyEvents },
- { "nativeDebugDump", "()V",
- (void*) nativeDebugDump },
- { "nativeDestroy", "()V",
+ { "nativeDestroy", "(I)V",
(void*) nativeDestroy },
- { "nativeDraw", "(Landroid/graphics/Canvas;Landroid/graphics/RectF;IIZ)I",
+ { "nativeDraw", "(Landroid/graphics/Canvas;Landroid/graphics/RectF;II)V",
(void*) nativeDraw },
- { "nativeGetDrawGLFunction", "(ILandroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/RectF;FI)I",
+ { "nativeCreateDrawGLFunction", "(ILandroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/RectF;FI)I",
+ (void*) nativeCreateDrawGLFunction },
+ { "nativeGetDrawGLFunction", "(I)I",
(void*) nativeGetDrawGLFunction },
- { "nativeUpdateDrawGLFunction", "(Landroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/RectF;)V",
+ { "nativeUpdateDrawGLFunction", "(ILandroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/RectF;F)V",
(void*) nativeUpdateDrawGLFunction },
{ "nativeDumpDisplayTree", "(Ljava/lang/String;)V",
(void*) nativeDumpDisplayTree },
{ "nativeEvaluateLayersAnimations", "(I)Z",
(void*) nativeEvaluateLayersAnimations },
- { "nativeExtendSelection", "(II)V",
- (void*) nativeExtendSelection },
- { "nativeFindAll", "(Ljava/lang/String;Ljava/lang/String;Z)I",
- (void*) nativeFindAll },
- { "nativeFindNext", "(Z)V",
- (void*) nativeFindNext },
- { "nativeFindIndex", "()I",
- (void*) nativeFindIndex},
- { "nativeFocusCandidateFramePointer", "()I",
- (void*) nativeFocusCandidateFramePointer },
- { "nativeFocusCandidateHasNextTextfield", "()Z",
- (void*) focusCandidateHasNextTextfield },
- { "nativeFocusCandidateIsPassword", "()Z",
- (void*) nativeFocusCandidateIsPassword },
- { "nativeFocusCandidateIsRtlText", "()Z",
- (void*) nativeFocusCandidateIsRtlText },
- { "nativeFocusCandidateIsTextInput", "()Z",
- (void*) nativeFocusCandidateIsTextInput },
- { "nativeFocusCandidateLineHeight", "()I",
- (void*) nativeFocusCandidateLineHeight },
- { "nativeFocusCandidateMaxLength", "()I",
- (void*) nativeFocusCandidateMaxLength },
- { "nativeFocusCandidateIsAutoComplete", "()Z",
- (void*) nativeFocusCandidateIsAutoComplete },
- { "nativeFocusCandidateIsSpellcheck", "()Z",
- (void*) nativeFocusCandidateIsSpellcheck },
- { "nativeFocusCandidateName", "()Ljava/lang/String;",
- (void*) nativeFocusCandidateName },
- { "nativeFocusCandidateNodeBounds", "()Landroid/graphics/Rect;",
- (void*) nativeFocusCandidateNodeBounds },
- { "nativeFocusCandidatePaddingRect", "()Landroid/graphics/Rect;",
- (void*) nativeFocusCandidatePaddingRect },
- { "nativeFocusCandidatePointer", "()I",
- (void*) nativeFocusCandidatePointer },
- { "nativeFocusCandidateText", "()Ljava/lang/String;",
- (void*) nativeFocusCandidateText },
- { "nativeFocusCandidateTextSize", "()F",
- (void*) nativeFocusCandidateTextSize },
- { "nativeFocusCandidateType", "()I",
- (void*) nativeFocusCandidateType },
- { "nativeFocusCandidateLayerId", "()I",
- (void*) nativeFocusCandidateLayerId },
- { "nativeFocusIsPlugin", "()Z",
- (void*) nativeFocusIsPlugin },
- { "nativeFocusNodeBounds", "()Landroid/graphics/Rect;",
- (void*) nativeFocusNodeBounds },
- { "nativeFocusNodePointer", "()I",
- (void*) nativeFocusNodePointer },
- { "nativeGetCursorRingBounds", "()Landroid/graphics/Rect;",
- (void*) nativeGetCursorRingBounds },
{ "nativeGetSelection", "()Ljava/lang/String;",
(void*) nativeGetSelection },
- { "nativeHasCursorNode", "()Z",
- (void*) nativeHasCursorNode },
- { "nativeHasFocusNode", "()Z",
- (void*) nativeHasFocusNode },
- { "nativeHideCursor", "()V",
- (void*) nativeHideCursor },
- { "nativeHitSelection", "(II)Z",
- (void*) nativeHitSelection },
- { "nativeImageURI", "(II)Ljava/lang/String;",
- (void*) nativeImageURI },
- { "nativeInstrumentReport", "()V",
- (void*) nativeInstrumentReport },
- { "nativeLayerBounds", "(I)Landroid/graphics/Rect;",
- (void*) nativeLayerBounds },
- { "nativeMotionUp", "(III)Z",
- (void*) nativeMotionUp },
- { "nativeMoveCursor", "(IIZ)Z",
- (void*) nativeMoveCursor },
- { "nativeMoveCursorToNextTextInput", "()Z",
- (void*) nativeMoveCursorToNextTextInput },
- { "nativeMoveGeneration", "()I",
- (void*) nativeMoveGeneration },
- { "nativeMoveSelection", "(II)V",
- (void*) nativeMoveSelection },
- { "nativePointInNavCache", "(III)Z",
- (void*) nativePointInNavCache },
- { "nativeResetSelection", "()V",
- (void*) nativeResetSelection },
- { "nativeSelectableText", "()Landroid/graphics/Point;",
- (void*) nativeSelectableText },
- { "nativeSelectAll", "()V",
- (void*) nativeSelectAll },
- { "nativeSelectBestAt", "(Landroid/graphics/Rect;)V",
- (void*) nativeSelectBestAt },
- { "nativeSelectAt", "(II)V",
- (void*) nativeSelectAt },
- { "nativeSelectionX", "()I",
- (void*) nativeSelectionX },
- { "nativeSelectionY", "()I",
- (void*) nativeSelectionY },
- { "nativeSetExtendSelection", "()V",
- (void*) nativeSetExtendSelection },
- { "nativeSetFindIsEmpty", "()V",
- (void*) nativeSetFindIsEmpty },
- { "nativeSetFindIsUp", "(Z)V",
- (void*) nativeSetFindIsUp },
{ "nativeSetHeightCanMeasure", "(Z)V",
(void*) nativeSetHeightCanMeasure },
- { "nativeSetBaseLayer", "(ILandroid/graphics/Region;ZZZ)V",
+ { "nativeSetBaseLayer", "(IIZZI)Z",
(void*) nativeSetBaseLayer },
- { "nativeGetTextSelectionRegion", "(ILandroid/graphics/Region;)V",
- (void*) nativeGetTextSelectionRegion },
- { "nativeGetSelectionHandles", "(I[I)V",
- (void*) nativeGetSelectionHandles },
- { "nativeGetBaseLayer", "()I",
+ { "nativeGetBaseLayer", "(I)I",
(void*) nativeGetBaseLayer },
- { "nativeReplaceBaseContent", "(I)V",
- (void*) nativeReplaceBaseContent },
{ "nativeCopyBaseContentToPicture", "(Landroid/graphics/Picture;)V",
(void*) nativeCopyBaseContentToPicture },
{ "nativeHasContent", "()Z",
(void*) nativeHasContent },
- { "nativeSetSelectionPointer", "(IZFII)V",
- (void*) nativeSetSelectionPointer },
- { "nativeShowCursorTimed", "()V",
- (void*) nativeShowCursorTimed },
- { "nativeRegisterPageSwapCallback", "()V",
- (void*) nativeRegisterPageSwapCallback },
+ { "nativeDiscardAllTextures", "()V",
+ (void*) nativeDiscardAllTextures },
{ "nativeTileProfilingStart", "()V",
(void*) nativeTileProfilingStart },
{ "nativeTileProfilingStop", "()F",
@@ -2910,29 +1336,17 @@ static JNINativeMethod gJavaWebViewMethods[] = {
(void*) nativeTileProfilingGetInt },
{ "nativeTileProfilingGetFloat", "(IILjava/lang/String;)F",
(void*) nativeTileProfilingGetFloat },
- { "nativeStartSelection", "(II)Z",
- (void*) nativeStartSelection },
- { "nativeStopGL", "()V",
+ { "nativeStopGL", "(I)V",
(void*) nativeStopGL },
- { "nativeSubtractLayers", "(Landroid/graphics/Rect;)Landroid/graphics/Rect;",
- (void*) nativeSubtractLayers },
- { "nativeTextGeneration", "()I",
- (void*) nativeTextGeneration },
- { "nativeUpdateCachedTextfield", "(Ljava/lang/String;I)V",
- (void*) nativeUpdateCachedTextfield },
- { "nativeWordSelection", "(II)Z",
- (void*) nativeWordSelection },
- { "nativeGetBlockLeftEdge", "(IIF)I",
- (void*) nativeGetBlockLeftEdge },
- { "nativeScrollableLayer", "(IILandroid/graphics/Rect;Landroid/graphics/Rect;)I",
+ { "nativeScrollableLayer", "(IIILandroid/graphics/Rect;Landroid/graphics/Rect;)I",
(void*) nativeScrollableLayer },
- { "nativeScrollLayer", "(III)Z",
+ { "nativeScrollLayer", "(IIII)Z",
(void*) nativeScrollLayer },
{ "nativeSetIsScrolling", "(Z)V",
(void*) nativeSetIsScrolling },
{ "nativeUseHardwareAccelSkia", "(Z)V",
(void*) nativeUseHardwareAccelSkia },
- { "nativeGetBackgroundColor", "()I",
+ { "nativeGetBackgroundColor", "(I)I",
(void*) nativeGetBackgroundColor },
{ "nativeSetProperty", "(Ljava/lang/String;Ljava/lang/String;)Z",
(void*) nativeSetProperty },
@@ -2942,17 +1356,27 @@ static JNINativeMethod gJavaWebViewMethods[] = {
(void*) nativeOnTrimMemory },
{ "nativeSetPauseDrawing", "(IZ)V",
(void*) nativeSetPauseDrawing },
+ { "nativeSetTextSelection", "(II)V",
+ (void*) nativeSetTextSelection },
+ { "nativeGetHandleLayerId", "(IILandroid/graphics/Point;Landroid/webkit/QuadF;)I",
+ (void*) nativeGetHandleLayerId },
+ { "nativeMapLayerRect", "(IILandroid/graphics/Rect;)V",
+ (void*) nativeMapLayerRect },
+ { "nativeSetHwAccelerated", "(IZ)I",
+ (void*) nativeSetHwAccelerated },
+ { "nativeFindMaxVisibleRect", "(IILandroid/graphics/Rect;)V",
+ (void*) nativeFindMaxVisibleRect },
};
int registerWebView(JNIEnv* env)
{
- jclass clazz = env->FindClass("android/webkit/WebView");
- LOG_ASSERT(clazz, "Unable to find class android/webkit/WebView");
+ jclass clazz = env->FindClass("android/webkit/WebViewClassic");
+ ALOG_ASSERT(clazz, "Unable to find class android/webkit/WebViewClassic");
gWebViewField = env->GetFieldID(clazz, "mNativeClass", "I");
- LOG_ASSERT(gWebViewField, "Unable to find android/webkit/WebView.mNativeClass");
+ ALOG_ASSERT(gWebViewField, "Unable to find android/webkit/WebViewClassic.mNativeClass");
env->DeleteLocalRef(clazz);
- return jniRegisterNativeMethods(env, "android/webkit/WebView", gJavaWebViewMethods, NELEM(gJavaWebViewMethods));
+ return jniRegisterNativeMethods(env, "android/webkit/WebViewClassic", gJavaWebViewMethods, NELEM(gJavaWebViewMethods));
}
} // namespace android
diff --git a/Source/WebKit/android/plugins/ANPSoundInterface.cpp b/Source/WebKit/android/plugins/ANPSoundInterface.cpp
index c238872..9d19443 100644
--- a/Source/WebKit/android/plugins/ANPSoundInterface.cpp
+++ b/Source/WebKit/android/plugins/ANPSoundInterface.cpp
@@ -38,7 +38,7 @@ struct ANPAudioTrack {
android::AudioTrack* mTrack;
};
-static ANPSampleFormat toANPFormat(int fm) {
+static ANPSampleFormat toANPFormat(audio_format_t fm) {
switch (fm) {
case AUDIO_FORMAT_PCM_16_BIT:
return kPCM16Bit_ANPSampleFormat;
@@ -49,7 +49,7 @@ static ANPSampleFormat toANPFormat(int fm) {
}
}
-static int fromANPFormat(ANPSampleFormat fm) {
+static audio_format_t fromANPFormat(ANPSampleFormat fm) {
switch (fm) {
case kPCM16Bit_ANPSampleFormat:
return AUDIO_FORMAT_PCM_16_BIT;
@@ -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
@@ -102,7 +102,7 @@ static ANPAudioTrack* ANPCreateTrack(uint32_t sampleRate,
fromANPFormat(format),
(channelCount > 1) ? AUDIO_CHANNEL_OUT_STEREO : AUDIO_CHANNEL_OUT_MONO,
0, // frameCount
- 0, // flags
+ (audio_output_flags_t) 0, // AUDIO_OUTPUT_FLAG_NONE,
callbackProc,
track,
0);
diff --git a/Source/WebKit/android/plugins/ANPSurfaceInterface.cpp b/Source/WebKit/android/plugins/ANPSurfaceInterface.cpp
index 4b99b31..92dbbcd 100644
--- a/Source/WebKit/android/plugins/ANPSurfaceInterface.cpp
+++ b/Source/WebKit/android/plugins/ANPSurfaceInterface.cpp
@@ -32,7 +32,7 @@
#include "SkANP.h"
#include "android_graphics.h"
#include <JNIUtility.h>
-#include <surfaceflinger/Surface.h>
+#include <gui/Surface.h>
#include <ui/Rect.h>
#include <ui/Region.h>
#include <utils/RefBase.h>
@@ -47,7 +47,7 @@ static struct ANPSurfaceInterfaceJavaGlue {
jfieldID surfacePointer;
} gSurfaceJavaGlue;
-static inline sp<Surface> getSurface(JNIEnv* env, jobject view) {
+static inline sp<android::Surface> getSurface(JNIEnv* env, jobject view) {
if (!env || !view) {
return NULL;
}
@@ -80,7 +80,7 @@ static inline sp<Surface> getSurface(JNIEnv* env, jobject view) {
env->DeleteLocalRef(holder);
env->DeleteLocalRef(surface);
- return sp<Surface>((Surface*) surfacePointer);
+ return sp<android::Surface>((android::Surface*) surfacePointer);
}
static inline ANPBitmapFormat convertPixelFormat(PixelFormat format) {
@@ -96,9 +96,9 @@ static bool anp_lock(JNIEnv* env, jobject surfaceView, ANPBitmap* bitmap, ANPRec
return false;
}
- sp<Surface> surface = getSurface(env, surfaceView);
+ sp<android::Surface> surface = getSurface(env, surfaceView);
- if (!bitmap || !Surface::isValid(surface)) {
+ if (!bitmap || !android::Surface::isValid(surface)) {
return false;
}
@@ -112,7 +112,7 @@ static bool anp_lock(JNIEnv* env, jobject surfaceView, ANPBitmap* bitmap, ANPRec
dirtyRegion.set(Rect(0x3FFF, 0x3FFF));
}
- Surface::SurfaceInfo info;
+ android::Surface::SurfaceInfo info;
status_t err = surface->lock(&info, &dirtyRegion);
if (err < 0) {
return false;
@@ -150,9 +150,9 @@ static void anp_unlock(JNIEnv* env, jobject surfaceView) {
return;
}
- sp<Surface> surface = getSurface(env, surfaceView);
+ sp<android::Surface> surface = getSurface(env, surfaceView);
- if (!Surface::isValid(surface)) {
+ if (!android::Surface::isValid(surface)) {
return;
}
diff --git a/Source/WebKit/android/plugins/PluginWidgetAndroid.cpp b/Source/WebKit/android/plugins/PluginWidgetAndroid.cpp
index fc98837..09bb24e 100644
--- a/Source/WebKit/android/plugins/PluginWidgetAndroid.cpp
+++ b/Source/WebKit/android/plugins/PluginWidgetAndroid.cpp
@@ -160,7 +160,8 @@ bool PluginWidgetAndroid::setDrawingModel(ANPDrawingModel model) {
if (model == kOpenGL_ANPDrawingModel && m_layer == 0) {
jobject webview = m_core->getWebViewJavaObject();
- m_layer = new WebCore::MediaLayer(webview);
+ AutoJObject webViewCore = m_core->getJavaObject();
+ m_layer = new WebCore::MediaLayer(webview, webViewCore.get());
}
else if (model != kOpenGL_ANPDrawingModel && m_layer != 0) {
m_layer->unref();
@@ -596,9 +597,9 @@ void PluginWidgetAndroid::scrollToVisiblePluginRect() {
android::WebViewCore* core = android::WebViewCore::getWebViewCore(scrollView);
#if DEBUG_VISIBLE_RECTS
PLUGIN_LOG("%s call scrollTo (%d,%d) to center (%d,%d)", __FUNCTION__,
- scrollDocX, scrollDocX, rectCenterX, rectCenterY);
+ scrollDocX, scrollDocY, rectCenterX, rectCenterY);
#endif
- core->scrollTo(scrollDocX, scrollDocX, true);
+ core->scrollTo(scrollDocX, scrollDocY, true);
}
void PluginWidgetAndroid::requestFullScreen() {
diff --git a/Source/WebKit/android/smoke/MessageThread.cpp b/Source/WebKit/android/smoke/MessageThread.cpp
index 48f2222..97ab18c 100644
--- a/Source/WebKit/android/smoke/MessageThread.cpp
+++ b/Source/WebKit/android/smoke/MessageThread.cpp
@@ -79,7 +79,7 @@ void MessageQueue::post(Message* message) {
AutoMutex lock(m_mutex);
double when = message->m_when;
- LOG_ASSERT(when > 0, "Message time may not be 0");
+ ALOG_ASSERT(when > 0, "Message time may not be 0");
list<Message*>::iterator it;
for (it = m_messages.begin(); it != m_messages.end(); ++it) {
diff --git a/Source/WebKit/android/wds/Command.cpp b/Source/WebKit/android/wds/Command.cpp
index bd8536f..1a365e5 100644
--- a/Source/WebKit/android/wds/Command.cpp
+++ b/Source/WebKit/android/wds/Command.cpp
@@ -95,7 +95,7 @@ public:
virtual ~InternalCommand() { delete m_connection; }
void doCommand() const {
- LOGD("Executing command '%s' (%s)", m_name, m_description);
+ ALOGD("Executing command '%s' (%s)", m_name, m_description);
if (!m_dispatch(m_frame, m_connection))
// XXX: Have useful failure messages
m_connection->write("EPIC FAIL!\n", 11);
diff --git a/Source/WebKit/android/wds/Connection.cpp b/Source/WebKit/android/wds/Connection.cpp
index d7e55ac..52193e5 100644
--- a/Source/WebKit/android/wds/Connection.cpp
+++ b/Source/WebKit/android/wds/Connection.cpp
@@ -35,7 +35,7 @@
#if ENABLE(WDS)
#define MAX_CONNECTION_QUEUE 5
-#define log_errno(x) LOGE("%s: %d", x, strerror(errno))
+#define log_errno(x) ALOGE("%s: %d", x, strerror(errno))
namespace android {
diff --git a/Source/WebKit/android/wds/DebugServer.cpp b/Source/WebKit/android/wds/DebugServer.cpp
index f33a65b..2fde6bd 100644
--- a/Source/WebKit/android/wds/DebugServer.cpp
+++ b/Source/WebKit/android/wds/DebugServer.cpp
@@ -42,7 +42,7 @@
#if ENABLE(WDS)
#define DEFAULT_PORT 9999
-#define log_errno(x) LOGE("%s: %d", x, strerror(errno))
+#define log_errno(x) ALOGE("%s: %d", x, strerror(errno))
namespace android {
@@ -70,7 +70,7 @@ DebugServer::DebugServer() {
char buf[PROPERTY_VALUE_MAX];
int ret = property_get("webcore.wds.enable", buf, NULL);
if (ret != -1 && strcmp(buf, "1") == 0) {
- LOGD("WDS Enabled");
+ ALOGD("WDS Enabled");
m_threadId = createThread(mainThread, this, "WDS");
}
// Initialize the available commands.
@@ -78,26 +78,26 @@ DebugServer::DebugServer() {
}
void DebugServer::start() {
- LOGD("DebugServer thread started");
+ ALOGD("DebugServer thread started");
ConnectionServer cs;
if (!cs.connect(DEFAULT_PORT)) {
- LOGE("Failed to start the server socket connection");
+ ALOGE("Failed to start the server socket connection");
return;
}
while (true ) {
- LOGD("Waiting for incoming connections...");
+ ALOGD("Waiting for incoming connections...");
Connection* conn = cs.accept();
if (!conn) {
log_errno("Failed to accept new connections");
return;
}
- LOGD("...Connection established");
+ ALOGD("...Connection established");
Command* c = Command::Find(conn);
if (!c) {
- LOGE("Could not find matching command");
+ ALOGE("Could not find matching command");
delete conn;
} else {
// Dispatch the command, it will handle cleaning up the connection
@@ -106,7 +106,7 @@ void DebugServer::start() {
}
}
- LOGD("DebugServer thread finished");
+ ALOGD("DebugServer thread finished");
}
} // end namespace WDS
diff --git a/Source/WebKit/android/wds/client/AdbConnection.cpp b/Source/WebKit/android/wds/client/AdbConnection.cpp
index 465f9c3..7d02ecc 100644
--- a/Source/WebKit/android/wds/client/AdbConnection.cpp
+++ b/Source/WebKit/android/wds/client/AdbConnection.cpp
@@ -78,7 +78,7 @@ bool AdbConnection::connect() {
bool AdbConnection::sendRequest(const char* fmt, ...) const {
if (m_fd == -1) {
- LOGE("Connection is closed");
+ ALOGE("Connection is closed");
return false;
}
@@ -89,7 +89,7 @@ bool AdbConnection::sendRequest(const char* fmt, ...) const {
int res = vsnprintf(buf, MAX_COMMAND_LENGTH, fmt, args);
va_end(args);
- LOGV("Sending command: %04X%.*s", res, res, buf);
+ ALOGV("Sending command: %04X%.*s", res, res, buf);
// Construct the payload length
char payloadLen[PAYLOAD_LENGTH + 1];
@@ -115,7 +115,7 @@ static void printFailureMessage(int fd) {
// Grab the payload length
char lenStr[PAYLOAD_LENGTH + 1];
int payloadLen = recv(fd, lenStr, sizeof(lenStr) - 1, 0);
- LOG_ASSERT(payloadLen == PAYLOAD_LENGTH, "Incorrect payload size");
+ ALOG_ASSERT(payloadLen == PAYLOAD_LENGTH, "Incorrect payload size");
lenStr[PAYLOAD_LENGTH] = 0;
// Parse the hex payload
@@ -130,13 +130,13 @@ static void printFailureMessage(int fd) {
log_errno("Failure reading failure message from adb");
return;
} else if (res != payloadLen) {
- LOGE("Incorrect payload length %d - expected %d", res, payloadLen);
+ ALOGE("Incorrect payload length %d - expected %d", res, payloadLen);
return;
}
msg[res] = 0;
// Tell somebody about it
- LOGE("Received failure from adb: %s", msg);
+ ALOGE("Received failure from adb: %s", msg);
// Cleanup
delete[] msg;
@@ -145,7 +145,7 @@ static void printFailureMessage(int fd) {
#define ADB_RESPONSE_LENGTH 4
bool AdbConnection::checkOkayResponse() const {
- LOG_ASSERT(m_fd != -1, "Connection has been closed!");
+ ALOG_ASSERT(m_fd != -1, "Connection has been closed!");
char buf[ADB_RESPONSE_LENGTH];
int res = recv(m_fd, buf, sizeof(buf), 0);
@@ -156,14 +156,14 @@ bool AdbConnection::checkOkayResponse() const {
// Check for a response other than OKAY/FAIL
if ((res == ADB_RESPONSE_LENGTH) && (strncmp(buf, "OKAY", res) == 0)) {
- LOGV("Command OKAY");
+ ALOGV("Command OKAY");
return true;
} else if (strncmp(buf, "FAIL", ADB_RESPONSE_LENGTH) == 0) {
// Something happened, print out the reason for failure
printFailureMessage(m_fd);
return false;
}
- LOGE("Incorrect response from adb - '%.*s'", res, buf);
+ ALOGE("Incorrect response from adb - '%.*s'", res, buf);
return false;
}
@@ -178,13 +178,13 @@ const DeviceList& AdbConnection::getDeviceList() {
clearDevices();
if (m_fd == -1) {
- LOGE("Connection is closed");
+ ALOGE("Connection is closed");
return m_devices;
}
// Try to send the device list request
if (!sendRequest("host:devices")) {
- LOGE("Failed to get device list from adb");
+ ALOGE("Failed to get device list from adb");
return m_devices;
}
@@ -210,7 +210,7 @@ const DeviceList& AdbConnection::getDeviceList() {
log_errno("Failure reading the device list");
return m_devices;
} else if (res != payloadLen) {
- LOGE("Incorrect payload length %d - expected %d", res, payloadLen);
+ ALOGE("Incorrect payload length %d - expected %d", res, payloadLen);
return m_devices;
}
msg[res] = 0;
@@ -224,7 +224,7 @@ const DeviceList& AdbConnection::getDeviceList() {
static const char emulator[] = "emulator-";
if (strncmp(serial, emulator, sizeof(emulator) - 1) == 0)
t = Device::EMULATOR;
- LOGV("Adding device %s (%s)", serial, state);
+ ALOGV("Adding device %s (%s)", serial, state);
m_devices.add(new Device(serial, t, this));
// Reset for the next line
diff --git a/Source/WebKit/android/wds/client/ClientUtils.h b/Source/WebKit/android/wds/client/ClientUtils.h
index 7d0db30..7c4b9ce 100644
--- a/Source/WebKit/android/wds/client/ClientUtils.h
+++ b/Source/WebKit/android/wds/client/ClientUtils.h
@@ -37,7 +37,7 @@
#endif
// Callers need to include Log.h and errno.h to use this macro
-#define log_errno(str) LOGE("%s: %s", str, strerror(errno))
+#define log_errno(str) ALOGE("%s: %s", str, strerror(errno))
// Fill in the sockaddr_in structure for binding to the localhost on the given
// port
diff --git a/Source/WebKit/android/wds/client/main.cpp b/Source/WebKit/android/wds/client/main.cpp
index 1c7d856..276affe 100644
--- a/Source/WebKit/android/wds/client/main.cpp
+++ b/Source/WebKit/android/wds/client/main.cpp
@@ -74,7 +74,7 @@ int main(int argc, char** argv) {
Device::DeviceType type = Device::NONE;
if (argc <= 1) {
- LOGE("wdsclient takes at least 1 argument");
+ ALOGE("wdsclient takes at least 1 argument");
return 1;
} else {
// Parse the options, look for -e or -d to choose a device.
@@ -94,7 +94,7 @@ int main(int argc, char** argv) {
}
}
if (optind == argc) {
- LOGE("No command specified");
+ ALOGE("No command specified");
return 1;
}
}
@@ -109,10 +109,10 @@ int main(int argc, char** argv) {
// No device specified and more than one connected, bail
if (type == Device::NONE && devices.size() > 1) {
- LOGE("More than one device/emulator, please specify with -e or -d");
+ ALOGE("More than one device/emulator, please specify with -e or -d");
return 1;
} else if (devices.size() == 0) {
- LOGE("No devices connected");
+ ALOGE("No devices connected");
return 1;
}
@@ -131,23 +131,23 @@ int main(int argc, char** argv) {
}
if (!device) {
- LOGE("No device found!");
+ ALOGE("No device found!");
return 1;
}
// Forward tcp:9999
if (!device->sendRequest("forward:tcp:" PORT_STR ";tcp:" PORT_STR)) {
- LOGE("Failed to send forwarding request");
+ ALOGE("Failed to send forwarding request");
return 1;
}
- LOGV("Connecting to localhost port " PORT_STR);
+ ALOGV("Connecting to localhost port " PORT_STR);
const char* command = argv[optind];
int commandLen = strlen(command);
#define WDS_COMMAND_LENGTH 4
if (commandLen != WDS_COMMAND_LENGTH) {
- LOGE("Commands must be 4 characters '%s'", command);
+ ALOGE("Commands must be 4 characters '%s'", command);
return 1;
}