summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk66
-rw-r--r--CleanSpec.mk2
-rw-r--r--Source/JavaScriptCore/wtf/Platform.h5
-rw-r--r--Source/WebCore/Android.mk2
-rw-r--r--Source/WebCore/dom/DOMTextContentWalker.cpp90
-rw-r--r--Source/WebCore/dom/DOMTextContentWalker.h60
-rw-r--r--Source/WebCore/dom/Document.cpp5
-rw-r--r--Source/WebCore/editing/TextIterator.cpp71
-rw-r--r--Source/WebCore/editing/TextIterator.h22
-rw-r--r--Source/WebCore/page/EventHandler.cpp6
-rw-r--r--Source/WebCore/platform/graphics/GraphicsContext.cpp2
-rw-r--r--Source/WebCore/platform/graphics/GraphicsContext.h4
-rw-r--r--Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp2
-rw-r--r--Source/WebCore/platform/graphics/android/GLExtras.cpp33
-rw-r--r--Source/WebCore/platform/graphics/android/GLExtras.h7
-rw-r--r--Source/WebCore/platform/graphics/android/GLUtils.cpp75
-rw-r--r--Source/WebCore/platform/graphics/android/GLUtils.h3
-rw-r--r--Source/WebCore/platform/graphics/android/GLWebViewState.cpp2
-rw-r--r--Source/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp20
-rw-r--r--Source/WebCore/platform/graphics/android/LayerAndroid.cpp11
-rw-r--r--Source/WebCore/platform/graphics/android/ShaderProgram.cpp9
-rw-r--r--Source/WebCore/platform/graphics/android/TextureOwner.h4
-rw-r--r--Source/WebCore/platform/graphics/android/TexturesGenerator.cpp39
-rw-r--r--Source/WebCore/platform/graphics/android/TexturesGenerator.h10
-rw-r--r--Source/WebCore/platform/graphics/android/TiledPage.cpp78
-rw-r--r--Source/WebCore/platform/graphics/android/TiledPage.h5
-rw-r--r--Source/WebCore/platform/graphics/android/TiledTexture.cpp5
-rw-r--r--Source/WebCore/platform/graphics/android/TilesManager.h8
-rw-r--r--Source/WebCore/platform/graphics/android/TilesProfiler.cpp10
-rw-r--r--Source/WebCore/platform/graphics/android/TilesProfiler.h2
-rw-r--r--Source/WebCore/platform/graphics/android/TransferQueue.cpp44
-rw-r--r--Source/WebCore/platform/graphics/android/TransferQueue.h4
-rw-r--r--Source/WebCore/platform/graphics/android/android_graphics.cpp185
-rw-r--r--Source/WebCore/platform/graphics/android/android_graphics.h46
-rw-r--r--Source/WebCore/platform/network/android/ResourceRequestAndroid.cpp7
-rw-r--r--Source/WebCore/rendering/InlineTextBox.cpp4
-rw-r--r--Source/WebCore/rendering/RenderBlockLineLayout.cpp4
-rw-r--r--Source/WebKit/Android.mk15
-rw-r--r--Source/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp1
-rw-r--r--Source/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.h6
-rw-r--r--Source/WebKit/android/WebCoreSupport/PlatformBridge.cpp30
-rw-r--r--Source/WebKit/android/WebCoreSupport/ResourceLoaderAndroid.cpp9
-rw-r--r--Source/WebKit/android/content/PhoneEmailDetector.cpp369
-rw-r--r--Source/WebKit/android/content/PhoneEmailDetector.h75
-rw-r--r--Source/WebKit/android/content/address_detector.cpp938
-rw-r--r--Source/WebKit/android/content/address_detector.h131
-rw-r--r--Source/WebKit/android/content/content_detector.cpp86
-rw-r--r--Source/WebKit/android/content/content_detector.h103
-rw-r--r--Source/WebKit/android/jni/AndroidHitTestResult.cpp36
-rw-r--r--Source/WebKit/android/jni/AndroidHitTestResult.h3
-rw-r--r--Source/WebKit/android/jni/CacheManager.cpp4
-rw-r--r--Source/WebKit/android/jni/CookieManager.cpp41
-rw-r--r--Source/WebKit/android/jni/JavaBridge.cpp2
-rw-r--r--Source/WebKit/android/jni/JniUtil.cpp58
-rw-r--r--Source/WebKit/android/jni/WebCoreFrameBridge.cpp133
-rw-r--r--Source/WebKit/android/jni/WebCoreFrameBridge.h6
-rw-r--r--Source/WebKit/android/jni/WebCoreJni.cpp4
-rw-r--r--Source/WebKit/android/jni/WebCoreJni.h2
-rw-r--r--Source/WebKit/android/jni/WebCoreJniOnLoad.cpp7
-rw-r--r--Source/WebKit/android/jni/WebCoreResourceLoader.cpp327
-rw-r--r--Source/WebKit/android/jni/WebCoreResourceLoader.h78
-rw-r--r--Source/WebKit/android/jni/WebSettings.cpp8
-rw-r--r--Source/WebKit/android/jni/WebViewCore.cpp315
-rw-r--r--Source/WebKit/android/jni/WebViewCore.h18
-rw-r--r--Source/WebKit/android/nav/CacheBuilder.cpp3137
-rw-r--r--Source/WebKit/android/nav/CacheBuilder.h297
-rw-r--r--Source/WebKit/android/nav/CachedNode.h1
-rw-r--r--Source/WebKit/android/nav/WebView.cpp143
-rw-r--r--Source/WebKit/android/plugins/ANPSurfaceInterface.cpp2
-rw-r--r--Source/WebKit/chromium/public/WebRange.h6
-rw-r--r--Source/WebKit/chromium/public/android/WebDOMTextContentWalker.h69
-rw-r--r--Source/WebKit/chromium/public/android/WebHitTestInfo.h76
-rw-r--r--Source/WebKit/chromium/src/WebRange.cpp9
-rw-r--r--Source/WebKit/chromium/src/android/WebDOMTextContentWalker.cpp85
-rw-r--r--Source/WebKit/chromium/src/android/WebHitTestInfo.cpp95
75 files changed, 2679 insertions, 4998 deletions
diff --git a/Android.mk b/Android.mk
index fd01fbb..e46cd93 100644
--- a/Android.mk
+++ b/Android.mk
@@ -35,32 +35,12 @@ ifneq ($(SUPPORT_COMPLEX_SCRIPTS),false)
SUPPORT_COMPLEX_SCRIPTS = true
endif
-# See if the desired HTTP stack has been specified.
-HTTP_STACK = $(HTTP)
-# We default to the Chrome HTTP stack.
-DEFAULT_HTTP = chrome
-ALT_HTTP = android
-
-ifneq ($(HTTP_STACK),chrome)
- ifneq ($(HTTP_STACK),android)
- # No HTTP stack is specified, pickup the one we want as default.
- ifeq ($(USE_ALT_HTTP),true)
- HTTP_STACK = $(ALT_HTTP)
- else
- HTTP_STACK = $(DEFAULT_HTTP)
- endif
- endif
-endif
-
# Read the environment variable to determine if Autofill is compiled.
-# The default is on. Chrome HTTP stack must be used when Autofill
+# The default is on.
# is turned on.
ifneq ($(ENABLE_AUTOFILL),false)
ENABLE_AUTOFILL = true
endif
-ifneq ($(HTTP_STACK),chrome)
- ENABLE_AUTOFILL = false
-endif
BASE_PATH := $(call my-dir)
include $(CLEAR_VARS)
@@ -213,6 +193,8 @@ LOCAL_C_INCLUDES := $(LOCAL_C_INCLUDES) \
external/chromium/chrome \
external/skia
+LOCAL_CFLAGS += -DWEBKIT_IMPLEMENTATION=1
+
# Include WTF source file.
d := Source/JavaScriptCore
LOCAL_PATH := $(BASE_PATH)/$d
@@ -252,10 +234,7 @@ LOCAL_CFLAGS += -fvisibility=hidden
LOCAL_CFLAGS += -DALWAYS_INLINE=inline
# Make sure assert.h is included before assert is defined
LOCAL_CFLAGS += -include "assert.h"
-ifeq ($(HTTP_STACK),chrome)
LOCAL_CFLAGS += -DGOOGLEURL
-LOCAL_CFLAGS += -DWTF_USE_CHROME_NETWORK_STACK
-endif # HTTP_STACK == chrome
LOCAL_CPPFLAGS := -Wno-sign-promo
LOCAL_CPPFLAGS := -Wno-c++0x-compat
@@ -291,25 +270,30 @@ endif
LOCAL_LDLIBS += -lpthread -ldl
# Build the list of shared libraries
+# We have to use the android version of libdl
LOCAL_SHARED_LIBRARIES := \
+ libEGL \
+ libGLESv2 \
libandroid \
libandroidfw \
libandroid_runtime \
- libnativehelper \
- libsqlite \
- libskia \
- libutils \
- libui \
+ libchromium_net \
+ libcrypto \
libcutils \
+ libdl \
+ libgui \
libicuuc \
libicui18n \
libmedia \
- libEGL \
- libGLESv2 \
- libgui
+ libnativehelper \
+ libskia \
+ libsqlite \
+ libssl \
+ libstlport \
+ libutils \
+ libui \
+ libz
-# We have to use the android version of libdl
-LOCAL_SHARED_LIBRARIES += libdl libstlport
# We have to fake out some headers when using stlport.
LOCAL_C_INCLUDES += \
external/chromium/android
@@ -327,10 +311,6 @@ endif
# Build the list of static libraries
LOCAL_STATIC_LIBRARIES := libxml2 libxslt libhyphenation libskiagpu libv8
-ifeq ($(HTTP_STACK),chrome)
-LOCAL_SHARED_LIBRARIES += libcrypto libssl libz libchromium_net
-endif # HTTP_STACK == chrome
-
ifeq ($(ENABLE_AUTOFILL),true)
LOCAL_SHARED_LIBRARIES += libexpat
endif
@@ -367,18 +347,20 @@ LOCAL_CPPFLAGS := $(WEBKIT_CPPFLAGS)
LOCAL_C_INCLUDES := $(WEBKIT_C_INCLUDES)
LOCAL_PATH := $(BASE_PATH)
LOCAL_SRC_FILES := \
- Source/WebKit/android/jni/WebCoreJniOnLoad.cpp
+ Source/WebKit/android/jni/WebCoreJniOnLoad.cpp \
+ Source/WebKit/chromium/src/android/WebDOMTextContentWalker.cpp \
+ Source/WebKit/chromium/src/android/WebHitTestInfo.cpp \
+ Source/WebKit/chromium/src/WebRange.cpp \
+ Source/WebKit/chromium/src/WebString.cpp
ifeq ($(ENABLE_AUTOFILL),true)
# AutoFill requires some cpp files from Chromium to link with
# libchromium_net. We cannot compile them into libchromium_net
# because they have cpp file extensions, not .cc.
-LOCAL_CFLAGS += -DWEBKIT_IMPLEMENTATION=1
LOCAL_SRC_FILES += \
Source/WebKit/android/WebCoreSupport/autofill/MainThreadProxy.cpp \
Source/WebKit/chromium/src/WebCString.cpp \
- Source/WebKit/chromium/src/WebRegularExpression.cpp \
- Source/WebKit/chromium/src/WebString.cpp
+ Source/WebKit/chromium/src/WebRegularExpression.cpp
endif
# Do this dependency by hand. The reason we have to do this is because the
diff --git a/CleanSpec.mk b/CleanSpec.mk
index a910d37..fda2cf9 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -79,6 +79,8 @@ $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libwebcore_int
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libwebcore_intermediates)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libwebcore_intermediates)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libwebcore_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libwebcore_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libwebcore_intermediates)
# ************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
diff --git a/Source/JavaScriptCore/wtf/Platform.h b/Source/JavaScriptCore/wtf/Platform.h
index 3043e56..7c59f1b 100644
--- a/Source/JavaScriptCore/wtf/Platform.h
+++ b/Source/JavaScriptCore/wtf/Platform.h
@@ -691,7 +691,6 @@
#define ENABLE_3D_RENDERING 1
#endif
-#define ENABLE_ANDROID_NAVCACHE 1
// ENABLE guards
#define ENABLE_JAVA_BRIDGE 1
// Prevents Webkit from drawing the caret in textfields and textareas
@@ -782,10 +781,6 @@
// track changes to the style that may change what is drawn
#define ANDROID_STYLE_VERSION
-#if !defined(WTF_USE_CHROME_NETWORK_STACK)
-#define WTF_USE_CHROME_NETWORK_STACK 0
-#endif /* !defined(WTF_USE_CHROME_NETWORK_STACK) */
-
// This is present in JavaScriptCore/config.h, which Android does not use.
#define WTF_CHANGES 1
#endif /* PLATFORM(ANDROID) */
diff --git a/Source/WebCore/Android.mk b/Source/WebCore/Android.mk
index bdf6410..af56e7e 100644
--- a/Source/WebCore/Android.mk
+++ b/Source/WebCore/Android.mk
@@ -124,6 +124,7 @@ LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \
dom/DOMImplementation.cpp \
dom/DOMStringList.cpp \
dom/DOMStringMap.cpp \
+ dom/DOMTextContentWalker.cpp \
dom/DatasetDOMStringMap.cpp \
dom/DecodedDataDocumentParser.cpp \
dom/DeviceMotionController.cpp \
@@ -685,7 +686,6 @@ LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \
platform/graphics/android/VideoLayerAndroid.cpp \
platform/graphics/android/VideoLayerManager.cpp \
platform/graphics/android/ZoomManager.cpp \
- platform/graphics/android/android_graphics.cpp \
ifeq ($(ENABLE_SVG), true)
LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \
diff --git a/Source/WebCore/dom/DOMTextContentWalker.cpp b/Source/WebCore/dom/DOMTextContentWalker.cpp
new file mode 100644
index 0000000..ccbe1ec
--- /dev/null
+++ b/Source/WebCore/dom/DOMTextContentWalker.cpp
@@ -0,0 +1,90 @@
+/*
+ * 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 INC. 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 INC. 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"
+#include "DOMTextContentWalker.h"
+
+#if OS(ANDROID)
+
+#include "Range.h"
+#include "TextIterator.h"
+#include "VisiblePosition.h"
+#include "VisibleSelection.h"
+#include "visible_units.h"
+
+namespace WebCore {
+
+static PassRefPtr<Range> getRange(const Position& start, const Position& end)
+{
+ return VisibleSelection(start.parentAnchoredEquivalent(), end.parentAnchoredEquivalent(), DOWNSTREAM).firstRange();
+}
+
+DOMTextContentWalker::DOMTextContentWalker(const VisiblePosition& position, unsigned maxLength)
+ : m_hitOffsetInContent(0)
+{
+ const unsigned halfMaxLength = maxLength / 2;
+ CharacterIterator forwardChar(makeRange(position, endOfDocument(position)).get(), TextIteratorStopsOnFormControls);
+ forwardChar.advance(maxLength - halfMaxLength);
+
+ // No forward contents, started inside form control.
+ RefPtr<Range> range = getRange(position.deepEquivalent(), forwardChar.range()->startPosition());
+ if (!range.get() || range->text().length() == 0)
+ return;
+
+ BackwardsCharacterIterator backwardsChar(makeRange(startOfDocument(position), position).get(), TextIteratorStopsOnFormControls);
+ backwardsChar.advance(halfMaxLength);
+
+ m_hitOffsetInContent = getRange(backwardsChar.range()->endPosition(), position.deepEquivalent())->text().length();
+ m_contentRange = getRange(backwardsChar.range()->endPosition(), forwardChar.range()->startPosition());
+}
+
+PassRefPtr<Range> DOMTextContentWalker::contentOffsetsToRange(unsigned startInContent, unsigned endInContent)
+{
+ if (startInContent >= endInContent || endInContent > content().length())
+ return 0;
+
+ CharacterIterator iterator(m_contentRange.get());
+ iterator.advance(startInContent);
+
+ Position start = iterator.range()->startPosition();
+ iterator.advance(endInContent - startInContent);
+ Position end = iterator.range()->startPosition();
+ return getRange(start, end);
+}
+
+String DOMTextContentWalker::content() const
+{
+ if (m_contentRange)
+ return m_contentRange->text();
+ return String();
+}
+
+unsigned DOMTextContentWalker::hitOffsetInContent() const
+{
+ return m_hitOffsetInContent;
+}
+
+} // namespace WebCore
+
+#endif // OS(ANDROID)
diff --git a/Source/WebCore/dom/DOMTextContentWalker.h b/Source/WebCore/dom/DOMTextContentWalker.h
new file mode 100644
index 0000000..0d4259b
--- /dev/null
+++ b/Source/WebCore/dom/DOMTextContentWalker.h
@@ -0,0 +1,60 @@
+/*
+ * 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 INC. 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 INC. 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.
+ */
+
+#ifndef DOMTextContentWalker_h
+#define DOMTextContentWalker_h
+
+#if OS(ANDROID)
+
+#include "PlatformString.h"
+
+namespace WebCore {
+
+class Range;
+class VisiblePosition;
+
+// Explore the DOM tree to find the text contents up to a limit
+// around a position in a given text node.
+class DOMTextContentWalker {
+ WTF_MAKE_NONCOPYABLE(DOMTextContentWalker);
+public:
+ DOMTextContentWalker(const VisiblePosition& position, unsigned maxLength);
+
+ String content() const;
+ unsigned hitOffsetInContent() const;
+
+ // Convert start/end positions in the content text string into a text range.
+ PassRefPtr<Range> contentOffsetsToRange(unsigned startInContent, unsigned endInContent);
+
+private:
+ RefPtr<Range> m_contentRange;
+ size_t m_hitOffsetInContent;
+};
+
+} // namespace WebCore
+
+#endif // OS(ANDROID)
+
+#endif // DOMTextContentWalker_h
+
diff --git a/Source/WebCore/dom/Document.cpp b/Source/WebCore/dom/Document.cpp
index 20dad55..1b5f55b 100644
--- a/Source/WebCore/dom/Document.cpp
+++ b/Source/WebCore/dom/Document.cpp
@@ -189,11 +189,6 @@
#include "Settings.h"
#endif
-#ifdef ANDROID_RESET_SELECTION
-#include "CacheBuilder.h"
-#include "HTMLTextAreaElement.h"
-#endif
-
#if ENABLE(TOUCH_EVENTS)
#if USE(V8)
#include "RuntimeEnabledFeatures.h"
diff --git a/Source/WebCore/editing/TextIterator.cpp b/Source/WebCore/editing/TextIterator.cpp
index c3be277..3aa68af 100644
--- a/Source/WebCore/editing/TextIterator.cpp
+++ b/Source/WebCore/editing/TextIterator.cpp
@@ -239,6 +239,20 @@ static void setUpFullyClippedStack(BitStack& stack, Node* node)
ASSERT(stack.size() == 1 + depthCrossingShadowBoundaries(node));
}
+#if OS(ANDROID)
+static bool checkFormControlElement(Node* startNode)
+{
+ Node* node = startNode;
+ while (node) {
+ if (node->isElementNode() && static_cast<Element*>(node)->isFormControlElement())
+ return true;
+ node = node->parentNode();
+ }
+ return false;
+}
+#endif
+
+
// --------
TextIterator::TextIterator()
@@ -258,6 +272,10 @@ TextIterator::TextIterator()
, m_handledFirstLetter(false)
, m_ignoresStyleVisibility(false)
, m_emitsObjectReplacementCharacters(false)
+#if OS(ANDROID)
+ , m_stopsOnFormControls(false)
+ , m_shouldStop(false)
+#endif
{
}
@@ -277,6 +295,10 @@ TextIterator::TextIterator(const Range* r, TextIteratorBehavior behavior)
, m_handledFirstLetter(false)
, m_ignoresStyleVisibility(behavior & TextIteratorIgnoresStyleVisibility)
, m_emitsObjectReplacementCharacters(behavior & TextIteratorEmitsObjectReplacementCharacters)
+#if OS(ANDROID)
+ , m_stopsOnFormControls(behavior & TextIteratorStopsOnFormControls)
+ , m_shouldStop(false)
+#endif
{
if (!r)
return;
@@ -334,8 +356,21 @@ TextIterator::~TextIterator()
{
}
+bool TextIterator::atEnd() const
+{
+#if OS(ANDROID)
+ return !m_positionNode || m_shouldStop;
+#else
+ return !m_positionNode;
+#endif
+}
+
void TextIterator::advance()
{
+#if OS(ANDROID)
+ if (m_shouldStop)
+ return;
+#endif
// reset the run information
m_positionNode = 0;
m_textLength = 0;
@@ -368,6 +403,10 @@ void TextIterator::advance()
}
while (m_node && m_node != m_pastEndNode) {
+#if OS(ANDROID)
+ if (!m_shouldStop && m_stopsOnFormControls && checkFormControlElement(m_node))
+ m_shouldStop = true;
+#endif
// if the range ends at offset 0 of an element, represent the
// position, but not the content, of that element e.g. if the
// node is a blockflow element, emit a newline that
@@ -1034,6 +1073,10 @@ SimplifiedBackwardsTextIterator::SimplifiedBackwardsTextIterator()
: m_behavior(TextIteratorDefaultBehavior)
, m_node(0)
, m_positionNode(0)
+#if OS(ANDROID)
+ , m_stopsOnFormControls(false)
+ , m_shouldStop(false)
+#endif
{
}
@@ -1041,8 +1084,16 @@ SimplifiedBackwardsTextIterator::SimplifiedBackwardsTextIterator(const Range* r,
: m_behavior(behavior)
, m_node(0)
, m_positionNode(0)
+#if OS(ANDROID)
+ , m_stopsOnFormControls(behavior & TextIteratorStopsOnFormControls)
+ , m_shouldStop(false)
+#endif
{
+#if OS(ANDROID)
+ ASSERT(m_behavior == TextIteratorDefaultBehavior || m_behavior == TextIteratorStopsOnFormControls);
+#else
ASSERT(m_behavior == TextIteratorDefaultBehavior);
+#endif
if (!r)
return;
@@ -1091,10 +1142,30 @@ SimplifiedBackwardsTextIterator::SimplifiedBackwardsTextIterator(const Range* r,
advance();
}
+bool SimplifiedBackwardsTextIterator::atEnd() const
+{
+#if OS(ANDROID)
+ return !m_positionNode || m_shouldStop;
+#else
+ return !m_positionNode;
+#endif
+}
+
void SimplifiedBackwardsTextIterator::advance()
{
ASSERT(m_positionNode);
+#if OS(ANDROID)
+ if (m_shouldStop)
+ return;
+
+ // Prevent changing the iterator position if a form control element was found and advance should stop on it.
+ if (m_stopsOnFormControls && checkFormControlElement(m_node)) {
+ m_shouldStop = true;
+ return;
+ }
+#endif
+
m_positionNode = 0;
m_textLength = 0;
diff --git a/Source/WebCore/editing/TextIterator.h b/Source/WebCore/editing/TextIterator.h
index 9fe4ceb..c4fc264 100644
--- a/Source/WebCore/editing/TextIterator.h
+++ b/Source/WebCore/editing/TextIterator.h
@@ -42,7 +42,10 @@ enum TextIteratorBehavior {
TextIteratorEntersTextControls = 1 << 1,
TextIteratorEmitsTextsWithoutTranscoding = 1 << 2,
TextIteratorIgnoresStyleVisibility = 1 << 3,
- TextIteratorEmitsObjectReplacementCharacters = 1 << 4
+ TextIteratorEmitsObjectReplacementCharacters = 1 << 4,
+#if OS(ANDROID)
+ TextIteratorStopsOnFormControls = 1 << 6
+#endif
};
// FIXME: Can't really answer this question correctly without knowing the white-space mode.
@@ -88,7 +91,7 @@ public:
~TextIterator();
explicit TextIterator(const Range*, TextIteratorBehavior = TextIteratorDefaultBehavior);
- bool atEnd() const { return !m_positionNode; }
+ bool atEnd() const;
void advance();
int length() const { return m_textLength; }
@@ -182,6 +185,12 @@ private:
bool m_ignoresStyleVisibility;
// Used when emitting the special 0xFFFC character is required.
bool m_emitsObjectReplacementCharacters;
+#if OS(ANDROID)
+ // Used when the iteration should stop if form controls are reached.
+ bool m_stopsOnFormControls;
+ // Used when m_stopsOnFormControls is set to determine if the iterator should keep advancing.
+ bool m_shouldStop;
+#endif
};
// Iterates through the DOM range, returning all the text, and 0-length boundaries
@@ -192,7 +201,7 @@ public:
SimplifiedBackwardsTextIterator();
explicit SimplifiedBackwardsTextIterator(const Range*, TextIteratorBehavior = TextIteratorDefaultBehavior);
- bool atEnd() const { return !m_positionNode; }
+ bool atEnd() const;
void advance();
int length() const { return m_textLength; }
@@ -240,6 +249,13 @@ private:
// Whether m_node has advanced beyond the iteration range (i.e. m_startNode).
bool m_havePassedStartNode;
+
+#if OS(ANDROID)
+ // Used when the iteration should stop if form controls are reached.
+ bool m_stopsOnFormControls;
+ // Used when m_stopsOnFormControls is set to determine if the iterator should keep advancing.
+ bool m_shouldStop;
+#endif
};
// Builds on the text iterator, adding a character position so we can walk one
diff --git a/Source/WebCore/page/EventHandler.cpp b/Source/WebCore/page/EventHandler.cpp
index e77809c..a737754 100644
--- a/Source/WebCore/page/EventHandler.cpp
+++ b/Source/WebCore/page/EventHandler.cpp
@@ -2415,16 +2415,10 @@ static Node* eventTargetNodeForDocument(Document* doc)
if (!doc)
return 0;
Node* node = doc->focusedNode();
-#if defined(ANDROID_PLUGINS)
- if (!node && doc->frame() && doc->frame()->view())
- node = android::WebViewCore::getWebViewCore(doc->frame()->view())
- ->cursorNodeIsPlugin();
-#else
if (!node && doc->isPluginDocument()) {
PluginDocument* pluginDocument = static_cast<PluginDocument*>(doc);
node = pluginDocument->pluginNode();
}
-#endif
if (!node && doc->isHTMLDocument())
node = doc->body();
if (!node)
diff --git a/Source/WebCore/platform/graphics/GraphicsContext.cpp b/Source/WebCore/platform/graphics/GraphicsContext.cpp
index 65cc6df..e032714 100644
--- a/Source/WebCore/platform/graphics/GraphicsContext.cpp
+++ b/Source/WebCore/platform/graphics/GraphicsContext.cpp
@@ -432,6 +432,7 @@ void GraphicsContext::drawBidiText(const Font& font, const TextRun& run, const F
bidiRuns.deleteRuns();
}
+#if !PLATFORM(ANDROID)
void GraphicsContext::drawHighlightForText(const Font& font, const TextRun& run, const FloatPoint& point, int h, const Color& backgroundColor, ColorSpace colorSpace, int from, int to)
{
if (paintingDisabled())
@@ -439,6 +440,7 @@ void GraphicsContext::drawHighlightForText(const Font& font, const TextRun& run,
fillRect(font.selectionRectForText(run, point, h, from, to), backgroundColor, colorSpace);
}
+#endif
void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const FloatRect& dest, const FloatRect& src, CompositeOperator op, bool useLowQualityScale)
{
diff --git a/Source/WebCore/platform/graphics/GraphicsContext.h b/Source/WebCore/platform/graphics/GraphicsContext.h
index 2b41c2e..ed43cf0 100644
--- a/Source/WebCore/platform/graphics/GraphicsContext.h
+++ b/Source/WebCore/platform/graphics/GraphicsContext.h
@@ -382,7 +382,11 @@ namespace WebCore {
void drawText(const Font&, const TextRun&, const FloatPoint&, int from = 0, int to = -1);
void drawEmphasisMarks(const Font&, const TextRun& , const AtomicString& mark, const FloatPoint&, int from = 0, int to = -1);
void drawBidiText(const Font&, const TextRun&, const FloatPoint&);
+#if PLATFORM(ANDROID)
+ void drawHighlightForText(const Font&, const TextRun&, const FloatPoint&, int h, const Color& backgroundColor, ColorSpace, int from = 0, int to = -1, bool isActive = true);
+#else
void drawHighlightForText(const Font&, const TextRun&, const FloatPoint&, int h, const Color& backgroundColor, ColorSpace, int from = 0, int to = -1);
+#endif
enum RoundingMode {
RoundAllSides,
diff --git a/Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp b/Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp
index 7208380..524f986 100644
--- a/Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp
+++ b/Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp
@@ -247,7 +247,7 @@ bool BaseLayerAndroid::prepareBasePictureInGL(SkRect& viewport, float scale,
nextTiledPage->prepare(goingDown, goingLeft, viewportTileBounds,
TiledPage::VisibleBounds);
// Cancel pending paints for the foreground page
- TilesManager::instance()->removePaintOperationsForPage(tiledPage);
+ TilesManager::instance()->removePaintOperationsForPage(tiledPage, false);
}
// If we fired a request, let's check if it's ready to use
diff --git a/Source/WebCore/platform/graphics/android/GLExtras.cpp b/Source/WebCore/platform/graphics/android/GLExtras.cpp
index 8a1d2fa..dc983a6 100644
--- a/Source/WebCore/platform/graphics/android/GLExtras.cpp
+++ b/Source/WebCore/platform/graphics/android/GLExtras.cpp
@@ -51,14 +51,9 @@
// Touch ring border width. This is doubled if the ring is not pressed
#define RING_BORDER_WIDTH 1
-// Put a cap on the number of matches to draw. If the current page has more
-// matches than this, only draw the focused match. This both prevents clutter
-// on the page and keeps the performance happy
-#define MAX_NUMBER_OF_MATCHES_TO_DRAW 101
GLExtras::GLExtras()
- : m_ring(0)
- , m_drawExtra(0)
+ : m_drawExtra(0)
, m_viewport()
{
}
@@ -150,30 +145,8 @@ void GLExtras::drawRegion(const SkRegion& region, bool fill, bool drawBorder,
}
}
-void GLExtras::drawCursorRings(const LayerAndroid* layer)
-{
- int layerId = layer ? layer->uniqueId() : -1;
- if (layerId != m_ring->layerId())
- return;
-
- SkRegion region;
- for (size_t i = 0; i < m_ring->rings().size(); i++) {
- IntRect rect = m_ring->rings().at(i);
- if (i == 0)
- region.setRect(rect);
- else
- region.op(rect, SkRegion::kUnion_Op);
- }
- drawRegion(region, m_ring->m_isPressed, !m_ring->m_isButton,
- layer ? layer->drawTransform() : 0);
-}
-
void GLExtras::drawGL(const LayerAndroid* layer)
{
- if (m_drawExtra) {
- if (m_drawExtra == m_ring)
- drawCursorRings(layer);
- else
- m_drawExtra->drawGL(this, layer);
- }
+ if (m_drawExtra)
+ m_drawExtra->drawGL(this, layer);
}
diff --git a/Source/WebCore/platform/graphics/android/GLExtras.h b/Source/WebCore/platform/graphics/android/GLExtras.h
index 72ee41c..59a7c3c 100644
--- a/Source/WebCore/platform/graphics/android/GLExtras.h
+++ b/Source/WebCore/platform/graphics/android/GLExtras.h
@@ -31,10 +31,6 @@
#include "SkRect.h"
#include "SkRegion.h"
-namespace android {
- class CursorRing;
-}
-
namespace WebCore {
class LayerAndroid;
@@ -46,7 +42,6 @@ public:
virtual ~GLExtras();
void drawGL(const LayerAndroid* layer);
- void setCursorRingExtra(android::CursorRing* ring) { m_ring = ring; }
void setDrawExtra(android::DrawExtra* extra) { m_drawExtra = extra; }
void setViewport(const SkRect & viewport) { m_viewport = viewport; }
@@ -55,9 +50,7 @@ public:
private:
void drawRing(SkRect& srcRect, Color color, const TransformationMatrix* drawMat);
- void drawCursorRings(const LayerAndroid* layer);
- android::CursorRing* m_ring;
android::DrawExtra* m_drawExtra;
SkRect m_viewport;
};
diff --git a/Source/WebCore/platform/graphics/android/GLUtils.cpp b/Source/WebCore/platform/graphics/android/GLUtils.cpp
index 39d8755..3024d28 100644
--- a/Source/WebCore/platform/graphics/android/GLUtils.cpp
+++ b/Source/WebCore/platform/graphics/android/GLUtils.cpp
@@ -36,9 +36,6 @@
#include <wtf/CurrentTime.h>
#include <wtf/text/CString.h>
-#include <cutils/log.h>
-#include <wtf/text/CString.h>
-
#undef XLOGC
#define XLOGC(...) android_printLog(ANDROID_LOG_DEBUG, "GLUtils", __VA_ARGS__)
@@ -54,6 +51,11 @@
#endif // DEBUG
+// We will limit GL error logging for LOG_VOLUME_PER_CYCLE times every
+// LOG_VOLUME_PER_CYCLE seconds.
+#define LOG_CYCLE 30.0
+#define LOG_VOLUME_PER_CYCLE 20
+
struct ANativeWindowBuffer;
namespace WebCore {
@@ -118,10 +120,35 @@ void GLUtils::setOrthographicMatrix(TransformationMatrix& ortho, float left, flo
// GL & EGL error checks
/////////////////////////////////////////////////////////////////////////////////////////
-static void crashIfOOM(GLint errorCode) {
+double GLUtils::m_previousLogTime = 0;
+int GLUtils::m_currentLogCounter = 0;
+
+bool GLUtils::allowGLLog()
+{
+ if (m_currentLogCounter < LOG_VOLUME_PER_CYCLE) {
+ m_currentLogCounter++;
+ return true;
+ }
+
+ // when we are in Log cycle and over the log limit, just return false
+ double currentTime = WTF::currentTime();
+ double delta = currentTime - m_previousLogTime;
+ bool inLogCycle = (delta <= LOG_CYCLE) && (delta > 0);
+ if (inLogCycle)
+ return false;
+
+ // When we are out of Log Cycle and over the log limit, we need to reset
+ // the counter and timer.
+ m_previousLogTime = currentTime;
+ m_currentLogCounter = 0;
+ return false;
+}
+
+static void crashIfOOM(GLint errorCode)
+{
const GLint OOM_ERROR_CODE = 0x505;
if (errorCode == OOM_ERROR_CODE) {
- XLOG("Fatal OOM detected.");
+ XLOGC("ERROR: Fatal OOM detected.");
CRASH();
}
}
@@ -129,11 +156,17 @@ static void crashIfOOM(GLint errorCode) {
void GLUtils::checkEglError(const char* op, EGLBoolean returnVal)
{
if (returnVal != EGL_TRUE) {
- XLOG("EGL ERROR - %s() returned %d\n", op, returnVal);
+#ifndef DEBUG
+ if (allowGLLog())
+#endif
+ XLOGC("EGL ERROR - %s() returned %d\n", op, returnVal);
}
for (EGLint error = eglGetError(); error != EGL_SUCCESS; error = eglGetError()) {
- XLOG("after %s() eglError (0x%x)\n", op, error);
+#ifndef DEBUG
+ if (allowGLLog())
+#endif
+ XLOGC("after %s() eglError (0x%x)\n", op, error);
crashIfOOM(error);
}
}
@@ -142,7 +175,10 @@ bool GLUtils::checkGlError(const char* op)
{
bool ret = false;
for (GLint error = glGetError(); error; error = glGetError()) {
- XLOG("GL ERROR - after %s() glError (0x%x)\n", op, error);
+#ifndef DEBUG
+ if (allowGLLog())
+#endif
+ XLOGC("GL ERROR - after %s() glError (0x%x)\n", op, error);
crashIfOOM(error);
ret = true;
}
@@ -153,7 +189,10 @@ bool GLUtils::checkGlErrorOn(void* p, const char* op)
{
bool ret = false;
for (GLint error = glGetError(); error; error = glGetError()) {
- XLOG("GL ERROR on %x - after %s() glError (0x%x)\n", p, op, error);
+#ifndef DEBUG
+ if (allowGLLog())
+#endif
+ XLOGC("GL ERROR on %x - after %s() glError (0x%x)\n", p, op, error);
crashIfOOM(error);
ret = true;
}
@@ -163,7 +202,10 @@ bool GLUtils::checkGlErrorOn(void* p, const char* op)
void GLUtils::checkSurfaceTextureError(const char* functionName, int status)
{
if (status != NO_ERROR) {
- XLOG("ERROR at calling %s status is (%d)", functionName, status);
+#ifndef DEBUG
+ if (allowGLLog())
+#endif
+ XLOGC("ERROR at calling %s status is (%d)", functionName, status);
}
}
/////////////////////////////////////////////////////////////////////////////////////////
@@ -315,7 +357,8 @@ void GLUtils::deleteTexture(GLuint* texture)
*texture = 0;
}
-GLuint GLUtils::createSampleColorTexture(int r, int g, int b) {
+GLuint GLUtils::createSampleColorTexture(int r, int g, int b)
+{
GLuint texture;
glGenTextures(1, &texture);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
@@ -501,7 +544,10 @@ void GLUtils::createTextureWithBitmap(GLuint texture, const SkBitmap& bitmap, GL
0, internalformat, type, bitmap.getPixels());
bitmap.unlockPixels();
if (GLUtils::checkGlError("glTexImage2D")) {
- XLOG("GL ERROR: glTexImage2D parameters are : bitmap.width() %d, bitmap.height() %d,"
+#ifndef DEBUG
+ if (allowGLLog())
+#endif
+ XLOGC("GL ERROR: glTexImage2D parameters are : bitmap.width() %d, bitmap.height() %d,"
" internalformat 0x%x, type 0x%x, bitmap.getPixels() %p",
bitmap.width(), bitmap.height(), internalformat, type, bitmap.getPixels());
}
@@ -538,7 +584,10 @@ void GLUtils::updateTextureWithBitmap(GLuint texture, const SkBitmap& bitmap,
}
bitmap.unlockPixels();
if (GLUtils::checkGlError("glTexSubImage2D")) {
- XLOG("GL ERROR: glTexSubImage2D parameters are : bitmap.width() %d, bitmap.height() %d,"
+#ifndef DEBUG
+ if (allowGLLog())
+#endif
+ XLOGC("GL ERROR: glTexSubImage2D parameters are : bitmap.width() %d, bitmap.height() %d,"
" internalformat 0x%x, type 0x%x, bitmap.getPixels() %p",
bitmap.width(), bitmap.height(), internalformat, type, bitmap.getPixels());
}
diff --git a/Source/WebCore/platform/graphics/android/GLUtils.h b/Source/WebCore/platform/graphics/android/GLUtils.h
index b198d35..e001aee 100644
--- a/Source/WebCore/platform/graphics/android/GLUtils.h
+++ b/Source/WebCore/platform/graphics/android/GLUtils.h
@@ -85,6 +85,9 @@ public:
static bool isPureColorBitmap(const SkBitmap& bitmap, Color& pureColor);
static bool skipTransferForPureColor(const TileRenderInfo* renderInfo,
const SkBitmap& bitmap);
+ static bool allowGLLog();
+ static double m_previousLogTime;
+ static int m_currentLogCounter;
};
} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/android/GLWebViewState.cpp b/Source/WebCore/platform/graphics/android/GLWebViewState.cpp
index e0d48ee..76d7324 100644
--- a/Source/WebCore/platform/graphics/android/GLWebViewState.cpp
+++ b/Source/WebCore/platform/graphics/android/GLWebViewState.cpp
@@ -141,7 +141,7 @@ bool GLWebViewState::setBaseLayer(BaseLayerAndroid* layer, bool showVisualIndica
m_layersRenderingMode = kAllTextures;
}
if (layer) {
- XLOG("new base layer %p, (inval region empty %d) with child %p", layer, inval.isEmpty(), layer->getChild(0));
+ XLOG("new base layer %p, with child %p", layer, layer->getChild(0));
layer->setState(this);
}
bool queueFull = m_treeManager.updateWithTree(layer, isPictureAfterFirstLayout);
diff --git a/Source/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp b/Source/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp
index 9cfed60..0aa1ae6 100644
--- a/Source/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp
+++ b/Source/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp
@@ -26,6 +26,7 @@
#include "GraphicsContext.h"
#include "AffineTransform.h"
+#include "Font.h"
#include "Gradient.h"
#include "NotImplemented.h"
#include "Path.h"
@@ -1265,6 +1266,25 @@ void GraphicsContext::clipConvexPolygon(size_t numPoints, const FloatPoint*, boo
// FIXME: IMPLEMENT!
}
+void GraphicsContext::drawHighlightForText(const Font& font, const TextRun& run, const FloatPoint& point, int h, const Color& backgroundColor, ColorSpace colorSpace, int from, int to, bool isActive)
+{
+ if (paintingDisabled())
+ return;
+
+ IntRect rect = (IntRect)font.selectionRectForText(run, point, h, from, to);
+ if (isActive)
+ fillRect(rect, backgroundColor, colorSpace);
+ else {
+ int x = rect.x(), y = rect.y(), w = rect.width(), h = rect.height();
+ const int t = 3, t2 = t * 2;
+
+ fillRect(IntRect(x, y, w, t), backgroundColor, colorSpace);
+ fillRect(IntRect(x, y+h-t, w, t), backgroundColor, colorSpace);
+ fillRect(IntRect(x, y+t, t, h-t2), backgroundColor, colorSpace);
+ fillRect(IntRect(x+w-t, y+t, t, h-t2), backgroundColor, colorSpace);
+ }
+}
+
} // namespace WebCore
///////////////////////////////////////////////////////////////////////////////
diff --git a/Source/WebCore/platform/graphics/android/LayerAndroid.cpp b/Source/WebCore/platform/graphics/android/LayerAndroid.cpp
index 79c02eb..83fb414 100644
--- a/Source/WebCore/platform/graphics/android/LayerAndroid.cpp
+++ b/Source/WebCore/platform/graphics/android/LayerAndroid.cpp
@@ -685,13 +685,16 @@ void LayerAndroid::updateGLPositionsAndScale(const TransformationMatrix& parentM
// now apply it to our children
+ TransformationMatrix childMatrix;
+ childMatrix = localMatrix;
+ childMatrix.translate3d(m_offset.x(), m_offset.y(), 0);
if (!m_childrenTransform.isIdentity()) {
- localMatrix.translate(getSize().width() * 0.5f, getSize().height() * 0.5f);
- localMatrix.multiply(m_childrenTransform);
- localMatrix.translate(-getSize().width() * 0.5f, -getSize().height() * 0.5f);
+ childMatrix.translate(getSize().width() * 0.5f, getSize().height() * 0.5f);
+ childMatrix.multiply(m_childrenTransform);
+ childMatrix.translate(-getSize().width() * 0.5f, -getSize().height() * 0.5f);
}
for (int i = 0; i < count; i++)
- this->getChild(i)->updateGLPositionsAndScale(localMatrix, drawClip(), opacity, scale);
+ this->getChild(i)->updateGLPositionsAndScale(childMatrix, drawClip(), opacity, scale);
}
void LayerAndroid::setContentsImage(SkBitmapRef* img)
diff --git a/Source/WebCore/platform/graphics/android/ShaderProgram.cpp b/Source/WebCore/platform/graphics/android/ShaderProgram.cpp
index 59c1271..4925bd6 100644
--- a/Source/WebCore/platform/graphics/android/ShaderProgram.cpp
+++ b/Source/WebCore/platform/graphics/android/ShaderProgram.cpp
@@ -38,6 +38,9 @@
#include <wtf/CurrentTime.h>
#include <wtf/text/CString.h>
+#undef XLOGC
+#define XLOGC(...) android_printLog(ANDROID_LOG_DEBUG, "ShaderProgram", __VA_ARGS__)
+
#ifdef DEBUG
#undef XLOG
@@ -45,10 +48,10 @@
#else
-#undef XLOGC
-#define XLOGC(...) android_printLog(ANDROID_LOG_DEBUG, "ShaderProgram", __VA_ARGS__)
+#undef XLOG
+#define XLOG(...)
-#endif
+#endif // DEBUG
namespace WebCore {
diff --git a/Source/WebCore/platform/graphics/android/TextureOwner.h b/Source/WebCore/platform/graphics/android/TextureOwner.h
index 25d234b..5434dbf 100644
--- a/Source/WebCore/platform/graphics/android/TextureOwner.h
+++ b/Source/WebCore/platform/graphics/android/TextureOwner.h
@@ -26,8 +26,6 @@
#ifndef TextureOwner_h
#define TextureOwner_h
-#include "SkRefCnt.h"
-
class SkCanvas;
class Layer;
@@ -37,7 +35,7 @@ class TiledPage;
class BaseTileTexture;
class GLWebViewState;
-class TextureOwner : public SkRefCnt {
+class TextureOwner {
public:
virtual ~TextureOwner() { }
virtual bool removeTexture(BaseTileTexture* texture) = 0;
diff --git a/Source/WebCore/platform/graphics/android/TexturesGenerator.cpp b/Source/WebCore/platform/graphics/android/TexturesGenerator.cpp
index d27631b..bccb99b 100644
--- a/Source/WebCore/platform/graphics/android/TexturesGenerator.cpp
+++ b/Source/WebCore/platform/graphics/android/TexturesGenerator.cpp
@@ -65,13 +65,18 @@ void TexturesGenerator::removeOperationsForPage(TiledPage* page)
removeOperationsForFilter(new PageFilter(page));
}
-void TexturesGenerator::removePaintOperationsForPage(TiledPage* page)
+void TexturesGenerator::removePaintOperationsForPage(TiledPage* page, bool waitForRunning)
{
- removeOperationsForFilter(new PagePaintFilter(page));
+ removeOperationsForFilter(new PagePaintFilter(page), waitForRunning);
}
void TexturesGenerator::removeOperationsForFilter(OperationFilter* filter)
{
+ removeOperationsForFilter(filter, true);
+}
+
+void TexturesGenerator::removeOperationsForFilter(OperationFilter* filter, bool waitForRunning)
+{
if (!filter)
return;
@@ -85,7 +90,34 @@ void TexturesGenerator::removeOperationsForFilter(OperationFilter* filter)
i++;
}
}
- delete filter;
+
+ if (waitForRunning && m_currentOperation) {
+ QueuedOperation* operation = m_currentOperation;
+
+ if (operation && filter->check(operation)) {
+ m_waitForCompletion = true;
+ // The reason we are signaling the transferQueue is :
+ // TransferQueue may be waiting a slot to work on, but now UI
+ // thread is waiting for Tex Gen thread to finish first before the
+ // UI thread can free a slot for the transferQueue.
+ // Therefore, it could be a deadlock.
+ // The solution is use this as a flag to tell Tex Gen thread that
+ // UI thread is waiting now, Tex Gen thread should not wait for the
+ // queue any more.
+ TilesManager::instance()->transferQueue()->interruptTransferQueue(true);
+ }
+
+ delete filter;
+
+ // At this point, it means that we are currently executing an operation that
+ // we want to be removed -- we should wait until it is done, so that
+ // when we return our caller can be sure that there is no more operations
+ // in the queue matching the given filter.
+ while (m_waitForCompletion)
+ mRequestedOperationsCond.wait(mRequestedOperationsLock);
+ } else {
+ delete filter;
+ }
}
status_t TexturesGenerator::readyToRun()
@@ -160,6 +192,7 @@ bool TexturesGenerator::threadLoop()
stop = true;
if (m_waitForCompletion) {
m_waitForCompletion = false;
+ TilesManager::instance()->transferQueue()->interruptTransferQueue(false);
mRequestedOperationsCond.signal();
}
mRequestedOperationsLock.unlock();
diff --git a/Source/WebCore/platform/graphics/android/TexturesGenerator.h b/Source/WebCore/platform/graphics/android/TexturesGenerator.h
index c7924cc..2e3b6b4 100644
--- a/Source/WebCore/platform/graphics/android/TexturesGenerator.h
+++ b/Source/WebCore/platform/graphics/android/TexturesGenerator.h
@@ -42,18 +42,16 @@ class LayerAndroid;
class TexturesGenerator : public Thread {
public:
- TexturesGenerator()
- : Thread(false)
+ TexturesGenerator() : Thread(false)
, m_waitForCompletion(false)
- , m_currentOperation(0)
- {}
-
+ , m_currentOperation(0) { }
virtual ~TexturesGenerator() { }
virtual status_t readyToRun();
void removeOperationsForPage(TiledPage* page);
- void removePaintOperationsForPage(TiledPage* page);
+ void removePaintOperationsForPage(TiledPage* page, bool waitForRunning);
void removeOperationsForFilter(OperationFilter* filter);
+ void removeOperationsForFilter(OperationFilter* filter, bool waitForRunning);
void scheduleOperation(QueuedOperation* operation);
diff --git a/Source/WebCore/platform/graphics/android/TiledPage.cpp b/Source/WebCore/platform/graphics/android/TiledPage.cpp
index 80d2c3f..7aac242 100644
--- a/Source/WebCore/platform/graphics/android/TiledPage.cpp
+++ b/Source/WebCore/platform/graphics/android/TiledPage.cpp
@@ -59,7 +59,8 @@ namespace WebCore {
using namespace android;
TiledPage::TiledPage(int id, GLWebViewState* state)
- : m_baseTileSize(0)
+ : m_baseTiles(0)
+ , m_baseTileSize(0)
, m_id(id)
, m_scale(1)
, m_invScale(1)
@@ -69,11 +70,7 @@ TiledPage::TiledPage(int id, GLWebViewState* state)
, m_isPrefetchPage(false)
, m_willDraw(false)
{
- int maxTiles = TilesManager::getMaxTextureAllocation() + 1;
- m_baseTiles = new BaseTile*[maxTiles];
- for (int i = 0; i < maxTiles; i++)
- m_baseTiles[i] = new BaseTile();
-
+ m_baseTiles = new BaseTile[TilesManager::getMaxTextureAllocation() + 1];
#ifdef DEBUG_COUNT
ClassTracker::instance()->increment("TiledPage");
#endif
@@ -97,14 +94,13 @@ void TiledPage::updateBaseTileSize()
TiledPage::~TiledPage()
{
TilesManager* tilesManager = TilesManager::instance();
- // remove as many painting operations for this page as possible, to avoid
- // unnecessary work.
+ // In order to delete the page we must ensure that none of its BaseTiles are
+ // currently painting or scheduled to be painted by the TextureGenerator
tilesManager->removeOperationsForPage(this);
-
- int maxTiles = TilesManager::getMaxTextureAllocation() + 1;
- for (int i = 0; i < maxTiles; i++)
- SkSafeUnref(m_baseTiles[i]);
- delete m_baseTiles;
+ // Discard the transfer queue after the removal operation to make sure
+ // no tiles for this page will be left in the transfer queue.
+ tilesManager->transferQueue()->setPendingDiscardWithLock();
+ delete[] m_baseTiles;
#ifdef DEBUG_COUNT
ClassTracker::instance()->decrement("TiledPage");
#endif
@@ -114,9 +110,9 @@ BaseTile* TiledPage::getBaseTile(int x, int y) const
{
// TODO: replace loop over array with HashMap indexing
for (int j = 0; j < m_baseTileSize; j++) {
- BaseTile* tile = m_baseTiles[j];
- if (tile->x() == x && tile->y() == y)
- return tile;
+ BaseTile& tile = m_baseTiles[j];
+ if (tile.x() == x && tile.y() == y)
+ return &tile;
}
return 0;
}
@@ -124,8 +120,8 @@ BaseTile* TiledPage::getBaseTile(int x, int y) const
void TiledPage::discardTextures()
{
for (int j = 0; j < m_baseTileSize; j++) {
- BaseTile* tile = m_baseTiles[j];
- tile->discardTextures();
+ BaseTile& tile = m_baseTiles[j];
+ tile.discardTextures();
}
return;
}
@@ -165,14 +161,14 @@ void TiledPage::prepareRow(bool goingLeft, int tilesInRow, int firstTileX, int y
BaseTile* currentTile = 0;
BaseTile* availableTile = 0;
for (int j = 0; j < m_baseTileSize; j++) {
- BaseTile* tile = m_baseTiles[j];
- if (tile->x() == x && tile->y() == y) {
- currentTile = tile;
+ BaseTile& tile = m_baseTiles[j];
+ if (tile.x() == x && tile.y() == y) {
+ currentTile = &tile;
break;
}
- if (!availableTile || (tile->drawCount() < availableTile->drawCount()))
- availableTile = tile;
+ if (!availableTile || (tile.drawCount() < availableTile->drawCount()))
+ availableTile = &tile;
}
if (!currentTile && availableTile) {
@@ -220,12 +216,12 @@ bool TiledPage::updateTileDirtiness(const SkIRect& tileBounds)
bool visibleTileIsDirty = false;
for (int x = 0; x < m_baseTileSize; x++) {
- BaseTile* tile = m_baseTiles[x];
+ BaseTile& tile = m_baseTiles[x];
// if the tile is in the dirty region then we must invalidate it
- if (m_invalRegion.contains(tile->x(), tile->y())) {
- tile->markAsDirty(m_latestPictureInval, m_invalTilesRegion);
- if (tileBounds.contains(tile->x(), tile->y()))
+ if (m_invalRegion.contains(tile.x(), tile.y())) {
+ tile.markAsDirty(m_latestPictureInval, m_invalTilesRegion);
+ if (tileBounds.contains(tile.x(), tile.y()))
visibleTileIsDirty = true;
}
}
@@ -305,9 +301,9 @@ bool TiledPage::hasMissingContent(const SkIRect& tileBounds)
{
int neededTiles = tileBounds.width() * tileBounds.height();
for (int j = 0; j < m_baseTileSize; j++) {
- BaseTile* tile = m_baseTiles[j];
- if (tileBounds.contains(tile->x(), tile->y())) {
- if (tile->frontTexture())
+ BaseTile& tile = m_baseTiles[j];
+ if (tileBounds.contains(tile.x(), tile.y())) {
+ if (tile.frontTexture())
neededTiles--;
}
}
@@ -319,9 +315,9 @@ bool TiledPage::isReady(const SkIRect& tileBounds)
int neededTiles = tileBounds.width() * tileBounds.height();
XLOG("tiled page %p needs %d ready tiles", this, neededTiles);
for (int j = 0; j < m_baseTileSize; j++) {
- BaseTile* tile = m_baseTiles[j];
- if (tileBounds.contains(tile->x(), tile->y())) {
- if (tile->isTileReady())
+ BaseTile& tile = m_baseTiles[j];
+ if (tileBounds.contains(tile.x(), tile.y())) {
+ if (tile.isTileReady())
neededTiles--;
}
}
@@ -352,12 +348,12 @@ bool TiledPage::swapBuffersIfReady(const SkIRect& tileBounds, float scale)
// swap every tile on page (even if off screen)
for (int j = 0; j < m_baseTileSize; j++) {
- BaseTile* tile = m_baseTiles[j];
- if (tile->swapTexturesIfNeeded())
+ BaseTile& tile = m_baseTiles[j];
+ if (tile.swapTexturesIfNeeded())
swaps++;
}
- XLOG("%p greedy swapped %d textures, returning true", this, swaps);
+ XLOG("%p greedy swapped %d textures, returning %d", this, swaps, fullSwap);
return fullSwap;
}
@@ -377,16 +373,16 @@ void TiledPage::drawGL()
const float tileHeight = TilesManager::tileHeight() * m_invScale;
for (int j = 0; j < m_baseTileSize; j++) {
- BaseTile* tile = m_baseTiles[j];
- bool tileInView = m_tileBounds.contains(tile->x(), tile->y());
+ BaseTile& tile = m_baseTiles[j];
+ bool tileInView = m_tileBounds.contains(tile.x(), tile.y());
if (tileInView) {
SkRect rect;
- rect.fLeft = tile->x() * tileWidth;
- rect.fTop = tile->y() * tileHeight;
+ rect.fLeft = tile.x() * tileWidth;
+ rect.fTop = tile.y() * tileHeight;
rect.fRight = rect.fLeft + tileWidth;
rect.fBottom = rect.fTop + tileHeight;
- tile->draw(m_transparency, rect, m_scale);
+ tile.draw(m_transparency, rect, m_scale);
}
TilesManager::instance()->getProfiler()->nextTile(tile, m_invScale, tileInView);
diff --git a/Source/WebCore/platform/graphics/android/TiledPage.h b/Source/WebCore/platform/graphics/android/TiledPage.h
index d858cc2..791e1f6 100644
--- a/Source/WebCore/platform/graphics/android/TiledPage.h
+++ b/Source/WebCore/platform/graphics/android/TiledPage.h
@@ -105,10 +105,9 @@ private:
BaseTile* getBaseTile(int x, int y) const;
- // array of tile ptrs used to compose a page. The tiles are allocated in the
+ // array of tiles used to compose a page. The tiles are allocated in the
// constructor to prevent them from potentially being allocated on the stack
- BaseTile** m_baseTiles;
-
+ BaseTile* m_baseTiles;
// stores the number of tiles in the m_baseTiles array. This enables us to
// quickly iterate over the array without have to check it's size
int m_baseTileSize;
diff --git a/Source/WebCore/platform/graphics/android/TiledTexture.cpp b/Source/WebCore/platform/graphics/android/TiledTexture.cpp
index 4b872a3..1e8b946 100644
--- a/Source/WebCore/platform/graphics/android/TiledTexture.cpp
+++ b/Source/WebCore/platform/graphics/android/TiledTexture.cpp
@@ -317,8 +317,9 @@ const TransformationMatrix* TiledTexture::transform()
void TiledTexture::removeTiles()
{
- for (unsigned int i = 0; i < m_tiles.size(); i++)
- SkSafeUnref(m_tiles[i]);
+ for (unsigned int i = 0; i < m_tiles.size(); i++) {
+ delete m_tiles[i];
+ }
m_tiles.clear();
}
diff --git a/Source/WebCore/platform/graphics/android/TilesManager.h b/Source/WebCore/platform/graphics/android/TilesManager.h
index d3852d9..b670055 100644
--- a/Source/WebCore/platform/graphics/android/TilesManager.h
+++ b/Source/WebCore/platform/graphics/android/TilesManager.h
@@ -58,9 +58,9 @@ public:
return gInstance != 0;
}
- void removeOperationsForFilter(OperationFilter* filter)
+ void removeOperationsForFilter(OperationFilter* filter, bool waitForRunning = false)
{
- m_pixmapsGenerationThread->removeOperationsForFilter(filter);
+ m_pixmapsGenerationThread->removeOperationsForFilter(filter, waitForRunning);
}
void removeOperationsForPage(TiledPage* page)
@@ -68,9 +68,9 @@ public:
m_pixmapsGenerationThread->removeOperationsForPage(page);
}
- void removePaintOperationsForPage(TiledPage* page)
+ void removePaintOperationsForPage(TiledPage* page, bool waitForCompletion)
{
- m_pixmapsGenerationThread->removePaintOperationsForPage(page);
+ m_pixmapsGenerationThread->removePaintOperationsForPage(page, waitForCompletion);
}
void scheduleOperation(QueuedOperation* operation)
diff --git a/Source/WebCore/platform/graphics/android/TilesProfiler.cpp b/Source/WebCore/platform/graphics/android/TilesProfiler.cpp
index d422904..0271ee3 100644
--- a/Source/WebCore/platform/graphics/android/TilesProfiler.cpp
+++ b/Source/WebCore/platform/graphics/android/TilesProfiler.cpp
@@ -103,14 +103,14 @@ void TilesProfiler::nextFrame(int left, int top, int right, int bottom, float sc
scale, true, (int)(timeDelta * 1000)));
}
-void TilesProfiler::nextTile(BaseTile* tile, float scale, bool inView)
+void TilesProfiler::nextTile(BaseTile& tile, float scale, bool inView)
{
if (!m_enabled || (m_records.size() > MAX_PROF_FRAMES) || (m_records.size() == 0))
return;
- bool isReady = tile->isTileReady();
- int left = tile->x() * TilesManager::tileWidth();
- int top = tile->y() * TilesManager::tileWidth();
+ bool isReady = tile.isTileReady();
+ int left = tile.x() * TilesManager::tileWidth();
+ int top = tile.y() * TilesManager::tileWidth();
int right = left + TilesManager::tileWidth();
int bottom = top + TilesManager::tileWidth();
@@ -122,7 +122,7 @@ void TilesProfiler::nextTile(BaseTile* tile, float scale, bool inView)
}
m_records.last().append(TileProfileRecord(
left, top, right, bottom,
- scale, isReady, (int)tile->drawCount()));
+ scale, isReady, (int)tile.drawCount()));
XLOG("adding tile %d %d %d %d, scale %f", left, top, right, bottom, scale);
}
diff --git a/Source/WebCore/platform/graphics/android/TilesProfiler.h b/Source/WebCore/platform/graphics/android/TilesProfiler.h
index 7a3fe59..286d350 100644
--- a/Source/WebCore/platform/graphics/android/TilesProfiler.h
+++ b/Source/WebCore/platform/graphics/android/TilesProfiler.h
@@ -58,7 +58,7 @@ public:
float stop();
void clear();
void nextFrame(int left, int top, int right, int bottom, float scale);
- void nextTile(BaseTile* tile, float scale, bool inView);
+ void nextTile(BaseTile& tile, float scale, bool inView);
void nextInval(const IntRect& rect, float scale);
int numFrames() {
return m_records.size();
diff --git a/Source/WebCore/platform/graphics/android/TransferQueue.cpp b/Source/WebCore/platform/graphics/android/TransferQueue.cpp
index 3c2ed1b..2d5be64 100644
--- a/Source/WebCore/platform/graphics/android/TransferQueue.cpp
+++ b/Source/WebCore/platform/graphics/android/TransferQueue.cpp
@@ -67,6 +67,7 @@ TransferQueue::TransferQueue(bool useMinimalMem)
, m_fboID(0)
, m_sharedSurfaceTextureId(0)
, m_hasGLContext(true)
+ , m_interruptedByRemovingOp(false)
, m_currentDisplay(EGL_NO_DISPLAY)
, m_currentUploadType(DEFAULT_UPLOAD_TYPE)
{
@@ -245,8 +246,17 @@ void TransferQueue::blitTileFromQueue(GLuint fboID, BaseTileTexture* destTex,
#endif
}
+void TransferQueue::interruptTransferQueue(bool interrupt)
+{
+ m_transferQueueItemLocks.lock();
+ m_interruptedByRemovingOp = interrupt;
+ if (m_interruptedByRemovingOp)
+ m_transferQueueItemCond.signal();
+ m_transferQueueItemLocks.unlock();
+}
+
// This function must be called inside the m_transferQueueItemLocks, for the
-// wait and getHasGLContext().
+// wait, m_interruptedByRemovingOp and getHasGLContext().
// Only called by updateQueueWithBitmap() for now.
bool TransferQueue::readyForUpdate()
{
@@ -254,8 +264,13 @@ bool TransferQueue::readyForUpdate()
return false;
// Don't use a while loop since when the WebView tear down, the emptyCount
// will still be 0, and we bailed out b/c of GL context lost.
- if (!m_emptyItemCount)
+ if (!m_emptyItemCount) {
+ if (m_interruptedByRemovingOp)
+ return false;
m_transferQueueItemCond.wait(m_transferQueueItemLocks);
+ if (m_interruptedByRemovingOp)
+ return false;
+ }
if (!getHasGLContext())
return false;
@@ -315,8 +330,6 @@ void TransferQueue::setPendingDiscard()
if (m_transferQueue[i].status == pendingBlit)
m_transferQueue[i].status = pendingDiscard;
- for (unsigned int i = 0 ; i < m_pureColorTileQueue.size(); i++)
- SkSafeUnref(m_pureColorTileQueue[i].savedBaseTilePtr);
m_pureColorTileQueue.clear();
bool GLContextExisted = getHasGLContext();
@@ -345,7 +358,6 @@ void TransferQueue::updatePureColorTiles()
// The queue should be clear instead of setting to different status.
XLOG("Warning: Don't expect an emptyItem here.");
}
- SkSafeUnref(data->savedBaseTilePtr);
}
m_pureColorTileQueue.clear();
}
@@ -386,11 +398,6 @@ void TransferQueue::updateDirtyBaseTiles()
if (result != OK)
XLOGC("unexpected error: updateTexImage return %d", result);
}
-
- XLOG("removing tile %p from %p, update",
- m_transferQueue[index].savedBaseTilePtr,
- &m_transferQueue[index]);
- SkSafeUnref(m_transferQueue[index].savedBaseTilePtr);
m_transferQueue[index].savedBaseTilePtr = 0;
m_transferQueue[index].status = emptyItem;
if (obsoleteBaseTile) {
@@ -511,7 +518,7 @@ bool TransferQueue::tryUpdateQueueWithBitmap(const TileRenderInfo* renderInfo,
ANativeWindow_unlockAndPost(m_ANW.get());
}
- // b) After update the Surface Texture, now update the transfer queue info.
+ // b) After update the Surface Texture, now udpate the transfer queue info.
addItemInTransferQueue(renderInfo, currentUploadType, &bitmap);
XLOG("Bitmap updated x, y %d %d, baseTile %p",
@@ -536,19 +543,8 @@ void TransferQueue::addItemCommon(const TileRenderInfo* renderInfo,
TextureUploadType type,
TileTransferData* data)
{
- BaseTile* old = data->savedBaseTilePtr;
- SkSafeRef(renderInfo->baseTile);
- SkSafeUnref(data->savedBaseTilePtr);
-
data->savedBaseTileTexturePtr = renderInfo->baseTile->backTexture();
data->savedBaseTilePtr = renderInfo->baseTile;
- XLOG("adding tile %p, %d by %d, refs %d, removed %p, dataPtr %p",
- data->savedBaseTilePtr,
- data->savedBaseTilePtr->x(),
- data->savedBaseTilePtr->y(),
- data->savedBaseTilePtr->getRefCnt(),
- old,
- data);
data->status = pendingBlit;
data->uploadType = type;
@@ -642,10 +638,6 @@ void TransferQueue::cleanupPendingDiscard()
XLOG("transfer queue discarded tile %p, removed texture", tile);
}
- XLOG("removing tile %p from %p, cleanup",
- m_transferQueue[index].savedBaseTilePtr,
- &m_transferQueue[index]);
- SkSafeUnref(m_transferQueue[index].savedBaseTilePtr);
m_transferQueue[index].savedBaseTilePtr = 0;
m_transferQueue[index].savedBaseTileTexturePtr = 0;
m_transferQueue[index].status = emptyItem;
diff --git a/Source/WebCore/platform/graphics/android/TransferQueue.h b/Source/WebCore/platform/graphics/android/TransferQueue.h
index 30dd0c6..5dd2e0a 100644
--- a/Source/WebCore/platform/graphics/android/TransferQueue.h
+++ b/Source/WebCore/platform/graphics/android/TransferQueue.h
@@ -129,6 +129,8 @@ public:
// The lock will be done when returning true.
bool readyForUpdate();
+ void interruptTransferQueue(bool);
+
void lockQueue() { m_transferQueueItemLocks.lock(); }
void unlockQueue() { m_transferQueueItemLocks.unlock(); }
@@ -194,6 +196,8 @@ private:
int m_emptyItemCount;
+ bool m_interruptedByRemovingOp;
+
// We are using wait/signal to handle our own queue sync.
// First of all, if we don't have our own lock, then while WebView is
// destroyed, the UI thread will wait for the Tex Gen to get out from
diff --git a/Source/WebCore/platform/graphics/android/android_graphics.cpp b/Source/WebCore/platform/graphics/android/android_graphics.cpp
deleted file mode 100644
index d76d581..0000000
--- a/Source/WebCore/platform/graphics/android/android_graphics.cpp
+++ /dev/null
@@ -1,185 +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 "CachedRoot.h"
-#include "IntRect.h"
-#include "LayerAndroid.h"
-#include "SkCanvas.h"
-#include "SkCornerPathEffect.h"
-#include "SkPath.h"
-#include "SkRegion.h"
-#include "WebViewCore.h"
-
-namespace android {
-
-#define RING_OUTSET 3
-#define RING_RADIUS 1
-#define RING_INNER_WIDTH 16
-#define RING_OUTER_WIDTH 16
-
-static const RGBA32 ringFill = 0x666699FF;
-static const RGBA32 ringPressedInner = 0x006699FF;
-static const RGBA32 ringPressedOuter = 0x336699FF;
-static const RGBA32 ringSelectedInner = 0xAA6699FF;
-static const RGBA32 ringSelectedOuter = 0x336699FF;
-
-
-CursorRing::CursorRing(WebViewCore* core)
- : m_viewImpl(core)
- , m_layerId(-1)
-{
-}
-
-// The CSS values for the inner and outer widths may be specified as fractions
-#define WIDTH_SCALE 0.0625f // 1/16, to offset the scale in CSSStyleSelector
-
-void CursorRing::drawLegacy(SkCanvas* canvas, LayerAndroid* layer, IntRect* inval)
-{
- if (!m_lastBounds.isEmpty()) {
- *inval = m_lastBounds;
- m_lastBounds = IntRect(0, 0, 0, 0);
- }
-#if USE(ACCELERATED_COMPOSITING)
- int layerId = m_node->isInLayer() ? m_frame->layer(m_node)->uniqueId() : -1;
- int drawingLayerId = layer ? layer->uniqueId() : -1;
- if (drawingLayerId != layerId)
- return;
-#endif
- if (canvas->quickReject(m_bounds, SkCanvas::kAA_EdgeType)) {
- DBG_NAV_LOGD("canvas->quickReject cursorNode=%d (nodePointer=%p)"
- " bounds=(%d,%d,w=%d,h=%d)", m_node->index(), m_node->nodePointer(),
- m_bounds.x(), m_bounds.y(), m_bounds.width(), m_bounds.height());
- return;
- }
- unsigned rectCount = m_rings.size();
- SkRegion rgn;
- SkPath path;
- for (unsigned i = 0; i < rectCount; i++)
- {
- SkRect r(m_rings[i]);
- SkIRect ir;
-
- r.round(&ir);
- ir.inset(-RING_OUTSET, -RING_OUTSET);
- rgn.op(ir, SkRegion::kUnion_Op);
- }
- rgn.getBoundaryPath(&path);
-
- SkPaint paint;
- paint.setAntiAlias(true);
- paint.setPathEffect(new SkCornerPathEffect(
- SkIntToScalar(RING_RADIUS)))->unref();
- SkColor outer;
- SkColor inner;
- if (m_isPressed) {
- SkColor pressed;
- pressed = ringFill;
- paint.setColor(pressed);
- canvas->drawPath(path, paint);
- outer = ringPressedInner;
- inner = ringPressedOuter;
- } else {
- outer = ringSelectedOuter;
- inner = ringSelectedInner;
- }
- paint.setStyle(SkPaint::kStroke_Style);
- paint.setStrokeWidth(RING_OUTER_WIDTH * WIDTH_SCALE);
- paint.setColor(outer);
- canvas->drawPath(path, paint);
- paint.setStrokeWidth(RING_INNER_WIDTH * WIDTH_SCALE);
- paint.setColor(inner);
- canvas->drawPath(path, paint);
- SkRect localBounds, globalBounds;
- localBounds = path.getBounds();
- float width = std::max(RING_INNER_WIDTH, RING_OUTER_WIDTH);
- width *= WIDTH_SCALE;
- localBounds.inset(-width, -width);
- const SkMatrix& matrix = canvas->getTotalMatrix();
- matrix.mapRect(&globalBounds, localBounds);
- SkIRect globalIBounds;
- globalBounds.round(&globalIBounds);
- m_lastBounds = globalIBounds;
- inval->unite(m_lastBounds);
-}
-
-void CursorRing::setIsButton(const CachedNode* node)
-{
- m_isButton = false;
-}
-
-bool CursorRing::setup()
-{
- m_layerId = -1;
- if (m_frame && m_root) {
- const CachedLayer* cachedLayer = m_frame->layer(m_node);
- if (cachedLayer) {
- const WebCore::LayerAndroid* rootLayer = m_root->rootLayer();
- const LayerAndroid* aLayer = cachedLayer->layer(rootLayer);
- if (aLayer)
- m_layerId = aLayer->uniqueId();
- }
- }
- if (m_layerId == -1)
- m_node->cursorRings(m_frame, &m_rings);
- else
- m_node->localCursorRings(m_frame, &m_rings);
-
- if (!m_rings.size()) {
- DBG_NAV_LOG("!rings.size()");
- m_viewImpl->m_hasCursorBounds = false;
- return false;
- }
-
- setIsButton(m_node);
- m_bounds = m_node->bounds(m_frame);
- m_viewImpl->updateCursorBounds(m_root, m_frame, m_node);
-
- bool useHitBounds = m_node->useHitBounds();
- if (useHitBounds)
- m_bounds = m_node->hitBounds(m_frame);
- if (useHitBounds || m_node->useBounds()) {
- m_rings.clear();
- m_rings.append(m_bounds);
- }
- m_absBounds = m_node->bounds(m_frame);
- m_bounds.inflate(SkScalarCeil(RING_OUTER_WIDTH));
- m_absBounds.inflate(SkScalarCeil(RING_OUTER_WIDTH));
- if (!m_node->hasCursorRing() || (m_node->isPlugin() && m_node->isFocus()))
- return false;
-#if DEBUG_NAV_UI
- const WebCore::IntRect& ring = m_rings[0];
- DBG_NAV_LOGD("cursorNode=%d (nodePointer=%p) pressed=%s rings=%d"
- " (%d, %d, %d, %d) isPlugin=%s",
- m_node->index(), m_node->nodePointer(),
- m_isPressed ? "true" : "false",
- m_rings.size(), ring.x(), ring.y(), ring.width(), ring.height(),
- m_node->isPlugin() ? "true" : "false");
-#endif
- return true;
-}
-
-}
diff --git a/Source/WebCore/platform/graphics/android/android_graphics.h b/Source/WebCore/platform/graphics/android/android_graphics.h
index 68207d7..7faa781 100644
--- a/Source/WebCore/platform/graphics/android/android_graphics.h
+++ b/Source/WebCore/platform/graphics/android/android_graphics.h
@@ -26,55 +26,17 @@
#ifndef android_graphics_DEFINED
#define android_graphics_DEFINED
-#include "DrawExtra.h"
-#include "IntRect.h"
-#include "SkTypes.h"
-#include "wtf/Vector.h"
-
namespace WebCore {
class GraphicsContext;
- class GLExtras;
}
+class SkCanvas;
-SkCanvas* android_gc2canvas(GraphicsContext* gc);
-
-namespace android {
-
-class CachedFrame;
-class CachedNode;
-class CachedRoot;
-class WebViewCore;
-
-// Data and methods for cursor rings
+// TODO: Move this somewhere else. The implementation for this is actually in
+// GraphicsContextAndroid.cpp, but this is used by a handful of other files
+SkCanvas* android_gc2canvas(WebCore::GraphicsContext* gc);
// used to inflate node cache entry
#define CURSOR_RING_HIT_TEST_RADIUS 5
-class CursorRing : public DrawExtra {
-public:
- CursorRing(WebViewCore* core);
- virtual ~CursorRing() {}
- virtual void drawLegacy(SkCanvas* , LayerAndroid* , IntRect* );
- void setIsButton(const CachedNode* );
- bool setup();
- WTF::Vector<IntRect>& rings() { return m_rings; }
- int layerId() const { return m_layerId; }
-private:
- friend class WebView;
- friend class WebCore::GLExtras;
- WebViewCore* m_viewImpl; // copy for convenience
- WTF::Vector<IntRect> m_rings;
- IntRect m_bounds;
- IntRect m_absBounds;
- IntRect m_lastBounds;
- const CachedRoot* m_root;
- const CachedFrame* m_frame;
- const CachedNode* m_node;
- bool m_isButton;
- bool m_isPressed;
- int m_layerId;
-};
-
-}
#endif
diff --git a/Source/WebCore/platform/network/android/ResourceRequestAndroid.cpp b/Source/WebCore/platform/network/android/ResourceRequestAndroid.cpp
index 00735f3..1519e9c 100644
--- a/Source/WebCore/platform/network/android/ResourceRequestAndroid.cpp
+++ b/Source/WebCore/platform/network/android/ResourceRequestAndroid.cpp
@@ -30,17 +30,10 @@ namespace WebCore {
unsigned initializeMaximumHTTPConnectionCountPerHost()
{
-#if USE(CHROME_NETWORK_STACK)
// The chromium network stack already handles limiting the number of
// parallel requests per host, so there's no need to do it here. Therefore,
// this is set to a high value that should never be hit in practice.
return 10000;
-#else
- // This is used by the loader to control the number of parallel load
- // requests. Our java framework has 4 threads that can each pipeline up to
- // 5 requests. Use 20 as a maximum number.
- return 20;
-#endif
}
} // namespace WebCore
diff --git a/Source/WebCore/rendering/InlineTextBox.cpp b/Source/WebCore/rendering/InlineTextBox.cpp
index e8a9c7f..d5eeeae 100644
--- a/Source/WebCore/rendering/InlineTextBox.cpp
+++ b/Source/WebCore/rendering/InlineTextBox.cpp
@@ -1070,8 +1070,12 @@ void InlineTextBox::paintTextMatchMarker(GraphicsContext* pt, const FloatPoint&
renderer()->theme()->platformInactiveTextSearchHighlightColor();
pt->save();
updateGraphicsContext(pt, color, color, 0, style->colorSpace()); // Don't draw text at all!
+#if PLATFORM(ANDROID)
+ pt->drawHighlightForText(font, run, FloatPoint(boxOrigin.x(), boxOrigin.y() - deltaY), selHeight, color, style->colorSpace(), sPos, ePos, marker.activeMatch);
+#else
pt->clip(FloatRect(boxOrigin.x(), boxOrigin.y() - deltaY, m_logicalWidth, selHeight));
pt->drawHighlightForText(font, run, FloatPoint(boxOrigin.x(), boxOrigin.y() - deltaY), selHeight, color, style->colorSpace(), sPos, ePos);
+#endif
pt->restore();
}
}
diff --git a/Source/WebCore/rendering/RenderBlockLineLayout.cpp b/Source/WebCore/rendering/RenderBlockLineLayout.cpp
index df20063..a2469a0 100644
--- a/Source/WebCore/rendering/RenderBlockLineLayout.cpp
+++ b/Source/WebCore/rendering/RenderBlockLineLayout.cpp
@@ -895,6 +895,10 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintLogica
m_minPreferredLogicalWidth = min(m_minPreferredLogicalWidth, maxWidth);
m_maxPreferredLogicalWidth = min(m_maxPreferredLogicalWidth, maxWidth);
+ // if overflow isn't visible, block elements may get clipped
+ // due to the limited content width. disable overflow clipping.
+ setHasOverflowClip(false);
+
IntRect overflow = layoutOverflowRect();
if (overflow.width() > maxWidth) {
overflow.setWidth(maxWidth);
diff --git a/Source/WebKit/Android.mk b/Source/WebKit/Android.mk
index 36664dd..c6f429b 100644
--- a/Source/WebKit/Android.mk
+++ b/Source/WebKit/Android.mk
@@ -16,8 +16,10 @@
##
LOCAL_SRC_FILES := \
+ android/WebCoreSupport/CacheResult.cpp \
android/WebCoreSupport/CachedFramePlatformDataAndroid.cpp \
android/WebCoreSupport/ChromeClientAndroid.cpp \
+ android/WebCoreSupport/ChromiumInit.cpp \
android/WebCoreSupport/ContextMenuClientAndroid.cpp \
android/WebCoreSupport/DeviceMotionClientAndroid.cpp \
android/WebCoreSupport/DeviceOrientationClientAndroid.cpp \
@@ -31,11 +33,6 @@ LOCAL_SRC_FILES := \
android/WebCoreSupport/PlatformBridge.cpp \
android/WebCoreSupport/ResourceLoaderAndroid.cpp \
android/WebCoreSupport/UrlInterceptResponse.cpp \
-
-ifeq ($(HTTP_STACK),chrome)
-LOCAL_SRC_FILES += \
- android/WebCoreSupport/ChromiumInit.cpp \
- android/WebCoreSupport/CacheResult.cpp \
android/WebCoreSupport/WebCache.cpp \
android/WebCoreSupport/WebCookieJar.cpp \
android/WebCoreSupport/WebUrlLoader.cpp \
@@ -45,7 +42,6 @@ LOCAL_SRC_FILES += \
android/WebCoreSupport/WebResourceRequest.cpp \
android/WebCoreSupport/WebResponse.cpp \
android/WebCoreSupport/WebViewClientError.cpp
-endif # HTTP_STACK == chrome
LOCAL_SRC_FILES += \
android/RenderSkinAndroid.cpp \
@@ -54,6 +50,10 @@ LOCAL_SRC_FILES += \
\
android/icu/unicode/ucnv.cpp \
\
+ android/content/address_detector.cpp \
+ android/content/content_detector.cpp \
+ android/content/PhoneEmailDetector.cpp \
+ \
android/jni/AndroidHitTestResult.cpp \
android/jni/CacheManager.cpp \
android/jni/CookieManager.cpp \
@@ -63,13 +63,11 @@ LOCAL_SRC_FILES += \
android/jni/GeolocationPermissionsBridge.cpp \
android/jni/JavaBridge.cpp \
android/jni/JavaSharedClient.cpp \
- android/jni/JniUtil.cpp \
android/jni/MIMETypeRegistry.cpp \
android/jni/MockGeolocation.cpp \
android/jni/PictureSet.cpp \
android/jni/WebCoreFrameBridge.cpp \
android/jni/WebCoreJni.cpp \
- android/jni/WebCoreResourceLoader.cpp \
android/jni/WebFrameView.cpp \
android/jni/WebHistory.cpp \
android/jni/WebIconDatabase.cpp \
@@ -78,7 +76,6 @@ LOCAL_SRC_FILES += \
android/jni/WebViewCore.cpp \
android/jni/ViewStateSerializer.cpp \
\
- android/nav/CacheBuilder.cpp \
android/nav/CachedFrame.cpp \
android/nav/CachedHistory.cpp \
android/nav/CachedInput.cpp \
diff --git a/Source/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp b/Source/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp
index 64799a8..c573b4e 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"
diff --git a/Source/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.h b/Source/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.h
index 51b67ba..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"
@@ -216,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();
@@ -227,7 +223,6 @@ namespace android {
virtual void didSaveToPageCache() { }
virtual void didRestoreFromPageCache() { }
private:
- CacheBuilder m_cacheBuilder;
Frame* m_frame;
WebFrame* m_webFrame;
PluginManualLoader* m_manualLoader;
@@ -263,7 +258,6 @@ namespace android {
ErrorFileNotFound = -14,
ErrorTooManyRequests = -15
};
- friend class CacheBuilder;
};
}
diff --git a/Source/WebKit/android/WebCoreSupport/PlatformBridge.cpp b/Source/WebKit/android/WebCoreSupport/PlatformBridge.cpp
index 8e4f56c..b684a1a 100644
--- a/Source/WebKit/android/WebCoreSupport/PlatformBridge.cpp
+++ b/Source/WebKit/android/WebCoreSupport/PlatformBridge.cpp
@@ -43,7 +43,7 @@
#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>
@@ -73,49 +73,25 @@ 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
}
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());
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)
@@ -173,15 +149,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)
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/content/PhoneEmailDetector.cpp b/Source/WebKit/android/content/PhoneEmailDetector.cpp
new file mode 100644
index 0000000..d188c0b
--- /dev/null
+++ b/Source/WebKit/android/content/PhoneEmailDetector.cpp
@@ -0,0 +1,369 @@
+/*
+ * 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 "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::FindContent(const string16::const_iterator& begin,
+ const string16::const_iterator& end,
+ size_t* start_pos,
+ size_t* end_pos)
+{
+ FindReset(&m_findState);
+ m_foundResult = FindPartialNumber(begin, end - begin, &m_findState);
+ if (m_foundResult == FOUND_COMPLETE)
+ m_prefix = kTelSchemaPrefix;
+ else {
+ FindReset(&m_findState);
+ 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..b61de62
--- /dev/null
+++ b/Source/WebKit/android/content/PhoneEmailDetector.h
@@ -0,0 +1,75 @@
+/*
+ * 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;
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(PhoneEmailDetector);
+
+ FindState m_findState;
+ FoundState m_foundResult;
+ const char* m_prefix;
+};
diff --git a/Source/WebKit/android/content/address_detector.cpp b/Source/WebKit/android/content/address_detector.cpp
new file mode 100644
index 0000000..504d37a
--- /dev/null
+++ b/Source/WebKit/android/content/address_detector.cpp
@@ -0,0 +1,938 @@
+/*
+ * 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 "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
+};
+
+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::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", "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..be34375
--- /dev/null
+++ b/Source/WebKit/android/content/address_detector.h
@@ -0,0 +1,131 @@
+/*
+ * 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;
+
+ // 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..b29a457
--- /dev/null
+++ b/Source/WebKit/android/content/content_detector.cpp
@@ -0,0 +1,86 @@
+/*
+ * 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"
+
+using WebKit::WebDOMTextContentWalker;
+using WebKit::WebRange;
+
+ContentDetector::Result ContentDetector::FindTappedContent(
+ const WebKit::WebHitTestInfo& hit_test) {
+ 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();
+}
diff --git a/Source/WebKit/android/content/content_detector.h b/Source/WebKit/android/content/content_detector.h
new file mode 100644
index 0000000..041cbc9
--- /dev/null
+++ b/Source/WebKit/android/content/content_detector.h
@@ -0,0 +1,103 @@
+/*
+ * 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;
+}
+
+// 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;
+
+ // 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
index 6f94488..f5dcc48 100644
--- a/Source/WebKit/android/jni/AndroidHitTestResult.cpp
+++ b/Source/WebKit/android/jni/AndroidHitTestResult.cpp
@@ -28,6 +28,9 @@
#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"
@@ -63,6 +66,7 @@ static struct {
jfieldID m_TapHighlightColor;
jfieldID m_EnclosingParentRects;
jfieldID m_HasFocus;
+ jfieldID m_IntentUrl;
} gHitTestGlue;
struct field {
@@ -89,6 +93,7 @@ static void InitJni(JNIEnv* env)
{ 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 },
@@ -135,13 +140,29 @@ void AndroidHitTestResult::buildHighlightRects()
RenderObject* renderer = node->renderer();
Vector<FloatQuad> quads;
renderer->absoluteFocusRingQuads(quads);
- for (int i = 0; i < quads.size(); i++) {
+ 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;
+ 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);
@@ -149,6 +170,13 @@ void setStringField(JNIEnv* env, jobject obj, jfieldID field, const String& str)
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);
@@ -176,6 +204,8 @@ jobject AndroidHitTestResult::createJavaObject(JNIEnv* env)
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;
@@ -201,8 +231,8 @@ jobject AndroidHitTestResult::createJavaObject(JNIEnv* env)
Vector<IntRect> AndroidHitTestResult::enclosingParentRects(Node* node)
{
- int lastX;
int count = 0;
+ int lastX = 0;
Vector<IntRect> rects;
while (node && count < 5) {
@@ -214,7 +244,7 @@ Vector<IntRect> AndroidHitTestResult::enclosingParentRects(Node* node)
node->document()->frame());
IntRect rect = render->absoluteBoundingBoxRect();
rect.move(-frameOffset.x(), -frameOffset.y());
- if (rect.x() != lastX) {
+ if (count == 0 || rect.x() != lastX) {
rects.append(rect);
lastX = rect.x();
count++;
diff --git a/Source/WebKit/android/jni/AndroidHitTestResult.h b/Source/WebKit/android/jni/AndroidHitTestResult.h
index f9709ac..5bbfc6b 100644
--- a/Source/WebKit/android/jni/AndroidHitTestResult.h
+++ b/Source/WebKit/android/jni/AndroidHitTestResult.h
@@ -26,6 +26,7 @@
#ifndef AndroidHitTestResult_h
#define AndroidHitTestResult_h
+#include "content/content_detector.h"
#include "Element.h"
#include "HitTestResult.h"
#include "IntRect.h"
@@ -48,6 +49,7 @@ public:
void setURLElement(WebCore::Element* element);
void buildHighlightRects();
+ void searchContentDetectors();
jobject createJavaObject(JNIEnv*);
@@ -57,6 +59,7 @@ private:
WebViewCore* m_webViewCore;
WebCore::HitTestResult m_hitTestResult;
Vector<WebCore::IntRect> m_highlightRects;
+ ContentDetector::Result m_searchResult;
};
} // namespace android
diff --git a/Source/WebKit/android/jni/CacheManager.cpp b/Source/WebKit/android/jni/CacheManager.cpp
index d319054..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"
@@ -140,5 +138,3 @@ int registerCacheManager(JNIEnv* env)
}
} // namespace android
-
-#endif // USE(CHROME_NETWORK_STACK)
diff --git a/Source/WebKit/android/jni/CookieManager.cpp b/Source/WebKit/android/jni/CookieManager.cpp
index 357d158..fca612f 100644
--- a/Source/WebKit/android/jni/CookieManager.cpp
+++ b/Source/WebKit/android/jni/CookieManager.cpp
@@ -40,49 +40,30 @@ static const char* javaCookieManagerClass = "android/webkit/CookieManager";
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[] = {
diff --git a/Source/WebKit/android/jni/JavaBridge.cpp b/Source/WebKit/android/jni/JavaBridge.cpp
index 204ac4e..4c8234b 100644
--- a/Source/WebKit/android/jni/JavaBridge.cpp
+++ b/Source/WebKit/android/jni/JavaBridge.cpp
@@ -472,12 +472,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/JniUtil.cpp b/Source/WebKit/android/jni/JniUtil.cpp
deleted file mode 100644
index 651016e..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);
- ALOG_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/WebCoreFrameBridge.cpp b/Source/WebKit/android/jni/WebCoreFrameBridge.cpp
index 2724d6b..d0f3830 100644
--- a/Source/WebKit/android/jni/WebCoreFrameBridge.cpp
+++ b/Source/WebKit/android/jni/WebCoreFrameBridge.cpp
@@ -83,7 +83,6 @@
#include "WebArchiveAndroid.h"
#include "WebCache.h"
#include "WebCoreJni.h"
-#include "WebCoreResourceLoader.h"
#include "WebHistory.h"
#include "WebIconDatabase.h"
#include "WebFrameView.h"
@@ -229,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 =
@@ -286,7 +283,6 @@ WebFrame::WebFrame(JNIEnv* env, jobject obj, jobject historyList, WebCore::Page*
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
env->DeleteLocalRef(clazz);
- ALOG_ASSERT(mJavaFrame->mStartLoadingResource, "Could not find method startLoadingResource");
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");
@@ -401,94 +397,6 @@ private:
int m_size;
};
-PassRefPtr<WebCore::ResourceLoaderAndroid>
-WebFrame::startLoadingResource(WebCore::ResourceHandle* loader,
- const WebCore::ResourceRequest& request,
- bool mainResource,
- bool synchronous)
-{
- ALOGV("::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);
- }
- }
- ALOGV("%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;
- }
-
- ALOGV("::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;
-
- RefPtr<WebCore::ResourceLoaderAndroid> h;
- if (jLoadListener)
- h = WebCoreResourceLoader::create(env, jLoadListener);
- env->DeleteLocalRef(jLoadListener);
- return h;
-}
-
UrlInterceptResponse*
WebFrame::shouldInterceptRequest(const WTF::String& url)
{
@@ -529,7 +437,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;
@@ -542,7 +449,6 @@ WebFrame::convertIDNToUnicode(const WebCore::KURL& url) {
newUrl.setHost(convertedHost);
converted = newUrl.string();
}
-#endif
return converted;
}
@@ -886,7 +792,6 @@ 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)
{
@@ -998,7 +903,6 @@ void WebFrame::setCertificate(const std::string& cert)
checkException(env);
}
-#endif // USE(CHROME_NETWORK_STACK)
void WebFrame::autoLogin(const std::string& loginHeader)
{
@@ -1188,10 +1092,8 @@ 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
// Create a new page
ChromeClientAndroid* chromeC = new ChromeClientAndroid;
@@ -1722,12 +1624,7 @@ 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)
@@ -1902,8 +1799,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);
@@ -2008,34 +1903,6 @@ static void SslClientCert(JNIEnv *env, jobject obj, int handle, jbyteArray pkey,
client->sslClientCert(privateKey.release(), certificate);
}
-#else
-
-static void AuthenticationProceed(JNIEnv *env, jobject obj, int handle, jstring jUsername, jstring jPassword)
-{
- ALOGW("Chromium authentication API called, but libchromium is not available");
-}
-
-static void AuthenticationCancel(JNIEnv *env, jobject obj, int handle)
-{
- ALOGW("Chromium authentication API called, but libchromium is not available");
-}
-
-static void SslCertErrorProceed(JNIEnv *env, jobject obj, int handle)
-{
- ALOGW("Chromium SSL API called, but libchromium is not available");
-}
-
-static void SslCertErrorCancel(JNIEnv *env, jobject obj, int handle, int cert_error)
-{
- ALOGW("Chromium SSL API called, but libchromium is not available");
-}
-
-static void SslClientCert(JNIEnv *env, jobject obj, int handle, jbyteArray privateKey, jobjectArray chain)
-{
- ALOGW("Chromium SSL API called, but libchromium is not available");
-}
-#endif // USE(CHROME_NETWORK_STACK)
-
// ----------------------------------------------------------------------------
/*
diff --git a/Source/WebKit/android/jni/WebCoreFrameBridge.h b/Source/WebKit/android/jni/WebCoreFrameBridge.h
index eaee63c..13f99af 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);
diff --git a/Source/WebKit/android/jni/WebCoreJni.cpp b/Source/WebKit/android/jni/WebCoreJni.cpp
index 65b6d20..5a142c8 100644
--- a/Source/WebKit/android/jni/WebCoreJni.cpp
+++ b/Source/WebKit/android/jni/WebCoreJni.cpp
@@ -79,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)
@@ -114,8 +112,6 @@ jstring stdStringToJstring(JNIEnv* env, const std::string& str, bool validOnZero
return !str.empty() || validOnZeroLength ? env->NewStringUTF(str.c_str()) : 0;
}
-#endif
-
jobjectArray intRectVectorToRectArray(JNIEnv* env, Vector<WebCore::IntRect>& rects)
{
jclass rectClass = env->FindClass("android/graphics/Rect");
diff --git a/Source/WebKit/android/jni/WebCoreJni.h b/Source/WebKit/android/jni/WebCoreJni.h
index 7a46f7b..25aa986 100644
--- a/Source/WebKit/android/jni/WebCoreJni.h
+++ b/Source/WebKit/android/jni/WebCoreJni.h
@@ -82,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);
@@ -90,7 +89,6 @@ 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>&);
diff --git a/Source/WebKit/android/jni/WebCoreJniOnLoad.cpp b/Source/WebKit/android/jni/WebCoreJniOnLoad.cpp
index 64aeb7e..2644dab 100644
--- a/Source/WebKit/android/jni/WebCoreJniOnLoad.cpp
+++ b/Source/WebKit/android/jni/WebCoreJniOnLoad.cpp
@@ -73,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*);
@@ -92,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
}
@@ -105,9 +102,7 @@ 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 },
@@ -125,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)
diff --git a/Source/WebKit/android/jni/WebCoreResourceLoader.cpp b/Source/WebKit/android/jni/WebCoreResourceLoader.cpp
deleted file mode 100644
index f0861ff..0000000
--- a/Source/WebKit/android/jni/WebCoreResourceLoader.cpp
+++ /dev/null
@@ -1,327 +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"
-#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)
-{
- WebCore::ResourceResponse* response = (WebCore::ResourceResponse*)nativeResponse;
- ALOG_ASSERT(response, "nativeSetResponseHeader must take a valid response pointer!");
-
- ALOG_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)
-{
- ALOG_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);
- ALOGV("Response setMIMEType: %s", mimeTypeStr.latin1().data());
- }
- if (encoding) {
- encodingStr = jstringToWtfString(env, encoding);
- ALOGV("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);
- ALOGV("Response setStatusText: %s", status.latin1().data());
- }
- return (int)response;
-}
-
-void WebCoreResourceLoader::ReceivedResponse(JNIEnv* env, jobject obj, jint nativeResponse)
-{
- WebCore::ResourceHandle* handle = GET_NATIVE_HANDLE(env, obj);
- ALOG_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;
- ALOG_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)
-{
- ALOGV("webcore_resourceloader data(%d)", length);
-
- WebCore::ResourceHandle* handle = GET_NATIVE_HANDLE(env, obj);
- ALOG_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);
-
- ALOG_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)
-{
- ALOGV("webcore_resourceloader finished");
- WebCore::ResourceHandle* handle = GET_NATIVE_HANDLE(env, obj);
- ALOG_ASSERT(handle, "nativeFinished must take a valid handle!");
- // ResourceLoader::didFail() can set handle to be NULL, we need to check
- if (!handle)
- return;
-
- ALOG_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)
-{
- ALOGV("webcore_resourceloader redirectedToUrl");
- WebCore::ResourceHandle* handle = GET_NATIVE_HANDLE(env, obj);
- ALOG_ASSERT(handle, "nativeRedirectedToUrl must take a valid handle!");
- // ResourceLoader::didFail() can set handle to be NULL, we need to check
- if (!handle)
- return NULL;
-
- ALOG_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)
-{
- ALOGV("webcore_resourceloader error");
- WebCore::ResourceHandle* handle = GET_NATIVE_HANDLE(env, obj);
- ALOG_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/WebSettings.cpp b/Source/WebKit/android/jni/WebSettings.cpp
index 9f7c2fa..1a1cc33 100644
--- a/Source/WebKit/android/jni/WebSettings.cpp
+++ b/Source/WebKit/android/jni/WebSettings.cpp
@@ -144,9 +144,7 @@ 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
ALOG_ASSERT(mLayoutAlgorithm, "Could not find field mLayoutAlgorithm");
ALOG_ASSERT(mTextSize, "Could not find field mTextSize");
@@ -265,9 +263,7 @@ struct FieldIds {
jfieldID mAutoFillProfileCountry;
jfieldID mAutoFillProfilePhoneNumber;
#endif
-#if USE(CHROME_NETWORK_STACK)
jfieldID mOverrideCacheMode;
-#endif
};
static struct FieldIds* gFieldIds;
@@ -367,7 +363,6 @@ public:
str = (jstring)env->GetObjectField(obj, gFieldIds->mUserAgent);
WebFrame::getWebFrame(pFrame)->setUserAgent(jstringToWtfString(env, str));
-#if USE(CHROME_NETWORK_STACK)
WebViewCore::getWebViewCore(pFrame->view())->setWebRequestContextUserAgent();
jint cacheMode = env->GetIntField(obj, gFieldIds->mOverrideCacheMode);
@@ -375,7 +370,6 @@ public:
str = (jstring)env->GetObjectField(obj, gFieldIds->mAcceptLanguage);
WebRequestContext::setAcceptLanguage(jstringToWtfString(env, str));
-#endif
jint size = env->GetIntField(obj, gFieldIds->mMinimumFontSize);
s->setMinimumFontSize(size);
@@ -589,9 +583,7 @@ 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);
-#if !ENABLE(ANDROID_NAVCACHE)
s->setSpatialNavigationEnabled(true);
-#endif
}
};
diff --git a/Source/WebKit/android/jni/WebViewCore.cpp b/Source/WebKit/android/jni/WebViewCore.cpp
index 2a81bd5..b9a21de 100644
--- a/Source/WebKit/android/jni/WebViewCore.cpp
+++ b/Source/WebKit/android/jni/WebViewCore.cpp
@@ -34,6 +34,7 @@
#include "BaseLayerAndroid.h"
#include "CachedNode.h"
#include "CachedRoot.h"
+#include "content/address_detector.h"
#include "Chrome.h"
#include "ChromeClientAndroid.h"
#include "ChromiumIncludes.h"
@@ -96,6 +97,7 @@
#include "ProgressTracker.h"
#include "Range.h"
#include "RenderBox.h"
+#include "RenderImage.h"
#include "RenderInline.h"
#include "RenderLayer.h"
#include "RenderPart.h"
@@ -176,6 +178,69 @@ FILE* gRenderTreeFile = 0;
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();
+ }
+ 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 SkTDArray<WebViewCore*> gInstanceList;
void WebViewCore::addInstance(WebViewCore* inst) {
@@ -386,9 +451,7 @@ 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
{
ALOG_ASSERT(m_mainFrame, "Uh oh, somehow a frameview was made without an initial frame!");
@@ -460,9 +523,7 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m
WebViewCore::addInstance(this);
-#if USE(CHROME_NETWORK_STACK)
AndroidNetworkLibraryImpl::InitWithApplicationContext(env, 0);
-#endif
// 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
@@ -530,13 +591,6 @@ static bool layoutIfNeededRecursive(WebCore::Frame* f)
return success && !v->needsLayout();
}
-#if ENABLE(ANDROID_NAVCACHE)
-CacheBuilder& WebViewCore::cacheBuilder()
-{
- return FrameLoaderClientAndroid::get(m_mainFrame)->getCacheBuilder();
-}
-#endif
-
WebCore::Node* WebViewCore::currentFocus()
{
return focusedFrame()->document()->focusedNode();
@@ -660,11 +714,6 @@ void WebViewCore::recordPictureSet(PictureSet* content)
height = view->contentsHeight();
}
-#if ENABLE(ANDROID_NAVCACHE)
- if (cacheBuilder().pictureSetDisabled())
- content->clear();
-#endif
-
#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
@@ -703,56 +752,6 @@ void WebViewCore::recordPictureSet(PictureSet* content)
// Rebuild the pictureset (webkit repaint)
rebuildPictureSet(content);
-
-#if ENABLE(ANDROID_NAVCACHE)
- WebCore::Node* oldFocusNode = currentFocus();
- m_frameCacheOutOfDate = true;
- WebCore::IntRect oldBounds;
- int oldSelStart = 0;
- int oldSelEnd = 0;
- if (oldFocusNode) {
- oldBounds = oldFocusNode->getRect();
- getSelectionOffsets(oldFocusNode, oldSelStart, oldSelEnd);
- } 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();
-#endif
}
// note: updateCursorBounds is called directly by the WebView thread
@@ -1088,11 +1087,6 @@ void WebViewCore::didFirstLayout()
|| loadType == WebCore::FrameLoadTypeSame);
checkException(env);
-#if ENABLE(ANDROID_NAVCACHE)
- DBG_NAV_LOG("call updateFrameCache");
- m_check_domtree_version = false;
- updateFrameCache();
-#endif
m_history.setDidFirstLayout(true);
}
@@ -1380,13 +1374,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)
{
@@ -1452,7 +1439,7 @@ WTF::String WebViewCore::retrieveImageSource(int x, int y)
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++) {
@@ -1508,104 +1495,6 @@ void WebViewCore::revealSelection()
focusedFrame->selection()->revealSelection(ScrollAlignment::alignToEdgeIfNeeded);
}
-#if ENABLE(ANDROID_NAVCACHE)
-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()) {
- ALOGW("updateFrameCache: pending style recalc, ignoring.");
- return;
- }
- m_frameCacheOutOfDate = false;
- CachedRoot* tempCacheRoot = new CachedRoot();
- tempCacheRoot->init(m_mainFrame, &m_history);
-#if USE(ACCELERATED_COMPOSITING)
- GraphicsLayerAndroid* graphicsLayer = graphicsRootLayer();
- if (graphicsLayer)
- tempCacheRoot->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(tempCacheRoot);
- SkPicture* tempPict = new SkPicture();
- recordPicture(tempPict);
- tempCacheRoot->setPicture(tempPict);
- SkSafeUnref(tempPict);
- tempPict = 0;
- tempCacheRoot->setTextGeneration(m_textGeneration);
- WebCoreViewBridge* window = m_mainFrame->view()->platformWidget();
- tempCacheRoot->setVisibleRect(WebCore::IntRect(m_scrollOffsetX,
- m_scrollOffsetY, window->width(), window->height()));
- gFrameCacheMutex.lock();
- delete m_frameCacheKit;
- m_frameCacheKit = tempCacheRoot;
- 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();
-}
-#endif
-
struct TouchNodeData {
Node* mUrlNode;
Node* mInnerNode;
@@ -2018,6 +1907,7 @@ AndroidHitTestResult WebViewCore::hitTestAtPoint(int x, int y, int slop, bool do
}
}
if (!nodeDataList.size()) {
+ androidHitResult.searchContentDetectors();
return androidHitResult;
}
// finally select the node with the largest overlap with the fat point
@@ -2065,6 +1955,8 @@ AndroidHitTestResult WebViewCore::hitTestAtPoint(int x, int y, int slop, bool do
m_scrollOffsetX, m_scrollOffsetY);
}
}
+ } else {
+ androidHitResult.searchContentDetectors();
}
return androidHitResult;
}
@@ -2243,7 +2135,7 @@ Node* WebViewCore::cursorNodeIsPlugin() {
Frame* frame = (Frame*) m_cursorFrame;
Node* node = (Node*) m_cursorNode;
gCursorBoundsMutex.unlock();
- if (hasCursorBounds && CacheBuilder::validNode(m_mainFrame, frame, node)
+ if (hasCursorBounds && validNode(m_mainFrame, frame, node)
&& nodeIsPlugin(node)) {
return node;
}
@@ -2269,7 +2161,7 @@ void WebViewCore::moveMouseIfLatest(int moveGeneration,
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)
+ if (!node || !validNode(m_mainFrame, frame, node)
|| !node->isElementNode())
return;
// Code borrowed from FocusController::advanceFocus
@@ -2290,7 +2182,7 @@ void WebViewCore::moveMouse(WebCore::Frame* frame, int x, int y, HitTestResult*
{
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))
+ if (!frame || !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);
@@ -2300,9 +2192,6 @@ void WebViewCore::moveMouse(WebCore::Frame* frame, int x, int y, HitTestResult*
WebCore::NoButton, WebCore::MouseEventMoved, 1, false, false, false,
false, WTF::currentTime());
frame->eventHandler()->handleMouseMoveEvent(mouseEvent, hoveredNode);
-#if ENABLE(ANDROID_NAVCACHE)
- updateCacheOnNodeChange();
-#endif
}
Position WebViewCore::getPositionForOffset(Node* node, int offset)
@@ -2426,7 +2315,7 @@ 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)) {
RefPtr<Range> rangeRef =
selection->frame()->document()->createRange();
@@ -2438,7 +2327,7 @@ String WebViewCore::modifySelectionTextNavigationAxis(DOMSelection* selection, i
} else if (currentFocus()) {
selection->setPosition(currentFocus(), 0, ec);
} else if (m_cursorNode
- && CacheBuilder::validNode(m_mainFrame,
+ && validNode(m_mainFrame,
m_mainFrame, m_cursorNode)) {
RefPtr<Range> rangeRef =
selection->frame()->document()->createRange();
@@ -2858,7 +2747,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;
@@ -2959,7 +2848,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();
@@ -3145,7 +3034,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();
@@ -3427,7 +3316,7 @@ void WebViewCore::touchUp(int touchGeneration,
moveMouse(frame, x, y);
m_lastGeneration = touchGeneration;
}
- if (frame && CacheBuilder::validNode(m_mainFrame, frame, 0)) {
+ if (frame && validNode(m_mainFrame, frame, 0)) {
frame->loader()->resetMultipleFormSubmissionProtection();
}
DBG_NAV_LOGD("touchGeneration=%d handleMouseClick frame=%p node=%p"
@@ -3456,7 +3345,7 @@ static bool shouldSuppressKeyboard(const WebCore::Node* node) {
// 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);
+ bool valid = !framePtr || 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
@@ -3501,15 +3390,8 @@ bool WebViewCore::handleMouseClick(WebCore::Frame* framePtr, WebCore::Node* node
autoFill->formFieldFocused(static_cast<HTMLFormControlElement*>(focusNode));
}
#endif
- if (!fake) {
-#if ENABLE(ANDROID_NAVCACHE)
- // 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();
-#endif
+ if (!fake)
initEditField(focusNode);
- }
} else if (!fake) {
requestKeyboard(false);
}
@@ -3943,14 +3825,14 @@ void WebViewCore::updateTextSelection()
AutoJObject javaObject = m_javaGlue->object(env);
if (!javaObject.get())
return;
- WebCore::Node* focusNode = currentFocus();
+ VisibleSelection selection = focusedFrame()->selection()->selection();
int start = 0;
int end = 0;
- if (focusNode)
- getSelectionOffsets(focusNode, start, end);
- SelectText* selectText = createSelectText(focusedFrame()->selection()->selection());
+ if (selection.isCaretOrRange())
+ getSelectionOffsets(selection.start().anchorNode(), start, end);
+ SelectText* selectText = createSelectText(selection);
env->CallVoidMethod(javaObject.get(),
- m_javaGlue->m_updateTextSelection, reinterpret_cast<int>(focusNode),
+ m_javaGlue->m_updateTextSelection, reinterpret_cast<int>(currentFocus()),
start, end, m_textGeneration, reinterpret_cast<int>(selectText));
checkException(env);
}
@@ -4128,14 +4010,14 @@ void WebViewCore::keepScreenOn(bool screenOn) {
bool WebViewCore::validNodeAndBounds(Frame* frame, Node* node,
const IntRect& originalAbsoluteBounds)
{
- bool valid = CacheBuilder::validNode(m_mainFrame, frame, node);
+ bool valid = 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))
+ ? getAreaRect(static_cast<HTMLAreaElement*>(node))
: renderer->absoluteBoundingBoxRect();
return absBounds == originalAbsoluteBounds;
}
@@ -4232,7 +4114,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
@@ -4260,7 +4141,6 @@ WebRequestContext* WebViewCore::webRequestContext()
}
return m_webRequestContext.get();
}
-#endif
void WebViewCore::scrollRenderLayer(int layer, const SkRect& rect)
{
@@ -4506,9 +4386,6 @@ static void ClearContent(JNIEnv* env, jobject obj, jint nativeClass)
static void UpdateFrameCacheIfLoading(JNIEnv* env, jobject obj, jint nativeClass)
{
-#if ENABLE(ANDROID_NAVCACHE)
- reinterpret_cast<WebViewCore*>(nativeClass)->updateFrameCacheIfLoading();
-#endif
}
static void SetSize(JNIEnv* env, jobject obj, jint nativeClass, jint width,
@@ -4705,6 +4582,7 @@ static void SendListBoxChoices(JNIEnv* env, jobject obj, jint nativeClass,
viewImpl->popupReply(array, count);
}
+// TODO: Move this to WebView.cpp since it is only needed there
static jstring FindAddress(JNIEnv* env, jobject obj, jstring addr,
jboolean caseInsensitive)
{
@@ -4714,9 +4592,9 @@ static jstring FindAddress(JNIEnv* env, jobject obj, jstring 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);
@@ -4813,11 +4691,6 @@ static void MoveMouseIfLatest(JNIEnv* env, jobject obj, jint nativeClass,
static void UpdateFrameCache(JNIEnv* env, jobject obj, jint nativeClass)
{
-#if ENABLE(ANDROID_NAVCACHE)
- WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
- ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
- viewImpl->updateFrameCache();
-#endif
}
static jint GetContentMinPrefWidth(JNIEnv* env, jobject obj, jint nativeClass)
@@ -4888,10 +4761,6 @@ static void DumpRenderTree(JNIEnv* env, jobject obj, jint nativeClass,
static void DumpNavTree(JNIEnv* env, jobject obj, jint nativeClass)
{
- WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
- ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
-
- viewImpl->dumpNavTree();
}
static void SetJsFlags(JNIEnv* env, jobject obj, jint nativeClass, jstring flags)
@@ -5090,10 +4959,8 @@ static void AutoFillForm(JNIEnv* env, jobject obj, jint nativeClass,
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 nativeCertTrustChanged(JNIEnv *env, jobject obj)
diff --git a/Source/WebKit/android/jni/WebViewCore.h b/Source/WebKit/android/jni/WebViewCore.h
index 785b659..bf7c36b 100644
--- a/Source/WebKit/android/jni/WebViewCore.h
+++ b/Source/WebKit/android/jni/WebViewCore.h
@@ -26,9 +26,6 @@
#ifndef WebViewCore_h
#define WebViewCore_h
-#ifndef DISABLE_NAVCACHE
-#include "CacheBuilder.h"
-#endif
#include "CachedHistory.h"
#include "DeviceMotionAndOrientationManager.h"
#include "DOMSelection.h"
@@ -430,14 +427,9 @@ namespace android {
jobject getWebViewJavaObject();
void setBackgroundColor(SkColor c);
-#ifndef DISABLE_NAVCACHE
- void updateFrameCache();
- void updateCacheOnNodeChange();
- void updateFrameCacheIfLoading();
-#endif
+
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
@@ -584,11 +576,9 @@ namespace android {
// 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);
@@ -653,9 +643,6 @@ namespace android {
URL = 7,
};
-#ifndef DISABLE_NAVCACHE
- CacheBuilder& cacheBuilder();
-#endif
WebCore::Node* currentFocus();
// Create a set of pictures to represent the drawn DOM, driven by
// the invalidated region and the time required to draw (used to draw)
@@ -808,10 +795,7 @@ namespace android {
bool m_forwardingTouchEvents;
#endif
-#if USE(CHROME_NETWORK_STACK)
scoped_refptr<WebRequestContext> m_webRequestContext;
-#endif
-
};
} // namespace android
diff --git a/Source/WebKit/android/nav/CacheBuilder.cpp b/Source/WebKit/android/nav/CacheBuilder.cpp
deleted file mode 100644
index 9759819..0000000
--- a/Source/WebKit/android/nav/CacheBuilder.cpp
+++ /dev/null
@@ -1,3137 +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 "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();
- 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
-
-// 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));
-#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(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 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;
- 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;
- 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;
- }
- }
- keepNode:
- cachedNode.init(node);
- cachedNode.setBounds(bounds);
- cachedNode.mCursorRing.append(bounds);
- keepTextNode:
- 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.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)
-{
- 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 (!zipPtr || !zipPtr[0] || !zipPtr[1] || !zipPtr[2])
- return false;
- 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] == stateIndex;
-}
-
-#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;
-}
-
-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/CachedNode.h b/Source/WebKit/android/nav/CachedNode.h
index 321b7fd..82d55ed 100644
--- a/Source/WebKit/android/nav/CachedNode.h
+++ b/Source/WebKit/android/nav/CachedNode.h
@@ -184,7 +184,6 @@ public:
bool wantsKeyEvents() const { return isTextInput() || isPlugin()
|| isContentEditable() || isFrame(); }
private:
- friend class CacheBuilder;
WTF::String mExport;
WebCore::IntRect mBounds;
WebCore::IntRect mHitBounds;
diff --git a/Source/WebKit/android/nav/WebView.cpp b/Source/WebKit/android/nav/WebView.cpp
index 2bd76f5..162d6bd 100644
--- a/Source/WebKit/android/nav/WebView.cpp
+++ b/Source/WebKit/android/nav/WebView.cpp
@@ -144,9 +144,8 @@ struct JavaGlue {
} 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)
{
memset(m_extras, 0, DRAW_EXTRAS_SIZE * sizeof(DrawExtra*));
jclass clazz = env->FindClass("android/webkit/WebView");
@@ -193,7 +192,6 @@ WebView(JNIEnv* env, jobject javaWebView, int viewImpl, WTF::String drawableDir,
m_heightCanMeasure = false;
m_lastDx = 0;
m_lastDxTime = 0;
- m_ringAnimationEnd = 0;
m_baseLayer = 0;
m_glDrawFunctor = 0;
m_isDrawingPaused = false;
@@ -230,33 +228,6 @@ DrawExtra* getDrawExtra(DrawExtras extras)
return m_extras[extras - 1];
}
-DrawExtra* getDrawExtraLegacy(DrawExtras extras)
-{
- CachedRoot* root = getFrameCache(AllowNewer);
- if (!root) {
- DBG_NAV_LOG("!root");
- if (extras == DrawExtrasCursorRing)
- resetCursorRing();
- }
- DrawExtra* extra = getDrawExtra(extras);
- if (!extra) {
- switch (extras) {
- case DrawExtrasCursorRing:
- if (drawCursorPreamble(root) && m_ring.setup()) {
- if (m_ring.m_isPressed || m_ringAnimationEnd == UINT_MAX)
- extra = &m_ring;
- drawCursorPostamble();
- }
- break;
- // Just to prevent compiler warnings
- case DrawExtrasSelection:
- case DrawExtrasNone:
- break;
- }
- }
- return extra;
-}
-
void stopGL()
{
#if USE(ACCELERATED_COMPOSITING)
@@ -335,60 +306,6 @@ void scrollRectOnScreen(const IntRect& rect)
viewInvalidate();
}
-void resetCursorRing()
-{
- 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));
- }
-}
-
bool drawGL(WebCore::IntRect& viewRect, WebCore::IntRect* invalRect,
WebCore::IntRect& webViewRect, int titleBarHeight,
WebCore::IntRect& clip, float scale, int extras)
@@ -400,7 +317,6 @@ bool drawGL(WebCore::IntRect& viewRect, WebCore::IntRect* invalRect,
if (!m_glWebViewState) {
TilesManager::instance()->setHighEndGfx(m_isHighEndGfx);
m_glWebViewState = new GLWebViewState();
- m_glWebViewState->glExtras()->setCursorRingExtra(&m_ring);
if (m_baseLayer->content()) {
SkRegion region;
SkIRect rect;
@@ -411,7 +327,7 @@ bool drawGL(WebCore::IntRect& viewRect, WebCore::IntRect* invalRect,
}
}
- DrawExtra* extra = getDrawExtraLegacy((DrawExtras) extras);
+ DrawExtra* extra = getDrawExtra((DrawExtras) extras);
unsigned int pic = m_glWebViewState->currentPictureCounter();
m_glWebViewState->glExtras()->setDrawExtra(extra);
@@ -459,7 +375,7 @@ PictureSet* draw(SkCanvas* canvas, SkColor bgColor, DrawExtras extras, bool spli
if (content->draw(canvas))
ret = split ? new PictureSet(*content) : 0;
- DrawExtra* extra = getDrawExtraLegacy(extras);
+ DrawExtra* extra = getDrawExtra(extras);
if (extra)
extra->draw(canvas, 0);
@@ -778,7 +694,6 @@ bool moveCursor(int keyCode, int count, bool ignoreScroll)
}
bool result = false;
if (cachedNode) {
- showCursorUntimed();
m_viewImpl->updateCursorBounds(root, cachedFrame, cachedNode);
root->setCursor(const_cast<CachedFrame*>(cachedFrame),
const_cast<CachedNode*>(cachedNode));
@@ -860,7 +775,6 @@ void selectBestAt(const WebCore::IntRect& rect)
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));
}
@@ -921,11 +835,6 @@ bool motionUp(int x, int y, int slop)
(WebCore::Frame*) frame->framePointer(),
(WebCore::Node*) result->nodePointer(), rx, ry);
}
- if (result->isTextInput() || result->isSelect()
- || result->isContentEditable()) {
- showCursorUntimed();
- } else
- showCursorTimed();
return pageScrolled;
}
@@ -1012,21 +921,6 @@ void setFindIsUp(bool up)
m_viewImpl->m_findIsUp = up;
}
-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;
@@ -1311,7 +1205,8 @@ int getHandleLayerId(SelectText::HandleId handleId, SkIRect& cursorRect) {
m_baseLayer->updateLayerPositions(m_visibleRect);
LayerAndroid* root = compositeRoot();
LayerAndroid* layer = root ? root->findById(layerId) : 0;
- rect = layer->drawTransform()->mapRect(rect);
+ if (layer && layer->drawTransform())
+ rect = layer->drawTransform()->mapRect(rect);
}
cursorRect.set(rect.x(), rect.y(), rect.maxX(), rect.maxY());
return layerId;
@@ -1323,12 +1218,10 @@ private: // local state for WebView
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
- SkMSec m_ringAnimationEnd;
// Corresponds to the same-named boolean on the java side.
bool m_heightCanMeasure;
int m_lastDx;
SkMSec m_lastDxTime;
- CursorRing m_ring;
DrawExtra* m_extras[DRAW_EXTRAS_SIZE];
BaseLayerAndroid* m_baseLayer;
Functor* m_glDrawFunctor;
@@ -1551,19 +1444,7 @@ static const CachedInput* getInputCandidate(JNIEnv *env, jobject obj)
static jboolean nativePageShouldHandleShiftAndArrows(JNIEnv *env, jobject obj)
{
-#if ENABLE(ANDROID_NAVCACHE)
- 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();
-#else
return true;
-#endif
}
static jobject nativeCursorNodeBounds(JNIEnv *env, jobject obj)
@@ -1954,12 +1835,6 @@ static void nativeSelectBestAt(JNIEnv *env, jobject obj, jobject jrect)
static void nativeSelectAt(JNIEnv *env, jobject obj, jint x, jint y)
{
- WebView* view = GET_NATIVE_VIEW(env, obj);
- ALOG_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)
@@ -2050,7 +1925,6 @@ static void nativeSetFindIsUp(JNIEnv *env, jobject obj, jboolean isUp)
static void nativeShowCursorTimed(JNIEnv *env, jobject obj)
{
- GET_NATIVE_VIEW(env, obj)->showCursorTimed();
}
static void nativeSetHeightCanMeasure(JNIEnv *env, jobject obj, bool measure)
@@ -2133,7 +2007,6 @@ static bool nativeMoveCursorToNextTextInput(JNIEnv *env, jobject obj)
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()),
@@ -2392,11 +2265,7 @@ static void nativeSetPauseDrawing(JNIEnv *env, jobject obj, jint nativeView,
static bool nativeDisableNavcache(JNIEnv *env, jobject obj)
{
-#if ENABLE(ANDROID_NAVCACHE)
- return false;
-#else
return true;
-#endif
}
static void nativeSetTextSelection(JNIEnv *env, jobject obj, jint nativeView,
diff --git a/Source/WebKit/android/plugins/ANPSurfaceInterface.cpp b/Source/WebKit/android/plugins/ANPSurfaceInterface.cpp
index 4b99b31..513d251 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>
diff --git a/Source/WebKit/chromium/public/WebRange.h b/Source/WebKit/chromium/public/WebRange.h
index 89fc8f6..3da3d95 100644
--- a/Source/WebKit/chromium/public/WebRange.h
+++ b/Source/WebKit/chromium/public/WebRange.h
@@ -37,10 +37,10 @@
namespace WebCore { class Range; }
namespace WTF { template <typename T> class PassRefPtr; }
#endif
+namespace WebCore { class Node; }
namespace WebKit {
-class WebNode;
class WebRangePrivate;
class WebString;
@@ -64,8 +64,8 @@ public:
WEBKIT_API int startOffset() const;
WEBKIT_API int endOffset() const;
- WEBKIT_API WebNode startContainer(int& exceptionCode) const;
- WEBKIT_API WebNode endContainer(int& exceptionCode) const;
+ WEBKIT_API WebCore::Node* startContainer(int& exceptionCode) const;
+ WEBKIT_API WebCore::Node* endContainer(int& exceptionCode) const;
WEBKIT_API WebString toHTMLText() const;
WEBKIT_API WebString toPlainText() const;
diff --git a/Source/WebKit/chromium/public/android/WebDOMTextContentWalker.h b/Source/WebKit/chromium/public/android/WebDOMTextContentWalker.h
new file mode 100644
index 0000000..26ba589
--- /dev/null
+++ b/Source/WebKit/chromium/public/android/WebDOMTextContentWalker.h
@@ -0,0 +1,69 @@
+/*
+ * 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 INC. 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 INC. 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.
+ */
+
+#ifndef WebDOMTextContentWalker_h
+#define WebDOMTextContentWalker_h
+
+#include "../WebPrivateOwnPtr.h"
+#include "../WebRange.h"
+#include "../WebString.h"
+
+namespace WebCore {
+class DOMTextContentWalker;
+class Node;
+}
+
+namespace WebKit {
+
+class WebHitTestInfo;
+
+class WebDOMTextContentWalker {
+public:
+ WebDOMTextContentWalker();
+ ~WebDOMTextContentWalker();
+
+ // Creates a new text content walker centered in the position described by the hit test.
+ // The maximum length of the contents retrieved by the walker is defined by maxLength.
+ WEBKIT_API WebDOMTextContentWalker(const WebHitTestInfo&, size_t maxLength);
+
+ // Creates a new text content walker centered in the selected offset of the given text node.
+ // The maximum length of the contents retrieved by the walker is defined by maxLength.
+ WEBKIT_API WebDOMTextContentWalker(WebCore::Node* textNode, size_t offset, size_t maxLength);
+
+ // Text content retrieved by the walker.
+ WEBKIT_API WebString content() const;
+
+ // Position of the initial text node offset in the content string.
+ WEBKIT_API size_t hitOffsetInContent() const;
+
+ // Convert start/end positions in the content text string into a WebKit text range.
+ WEBKIT_API WebRange contentOffsetsToRange(size_t startInContent, size_t endInContent);
+
+protected:
+ WebPrivateOwnPtr<WebCore::DOMTextContentWalker> m_private;
+};
+
+} // namespace WebKit
+
+#endif
diff --git a/Source/WebKit/chromium/public/android/WebHitTestInfo.h b/Source/WebKit/chromium/public/android/WebHitTestInfo.h
new file mode 100644
index 0000000..79b354e
--- /dev/null
+++ b/Source/WebKit/chromium/public/android/WebHitTestInfo.h
@@ -0,0 +1,76 @@
+/*
+* 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.
+ */
+
+#ifndef WebHitTestInfo_h
+#define WebHitTestInfo_h
+
+#include "../WebPoint.h"
+#include "../WebPrivateOwnPtr.h"
+#include "../WebURL.h"
+
+namespace WebCore {
+class HitTestResult;
+class Node;
+}
+
+namespace WebKit {
+
+// Properties of a hit test result, i.e. properties of the nodes at a given point
+// (the hit point) on the page. Both urls may be populated at the same time, for
+// example in the instance of an <img> inside an <a>.
+class WebHitTestInfo {
+public:
+ WebHitTestInfo();
+ WebHitTestInfo(const WebHitTestInfo&);
+ ~WebHitTestInfo();
+
+ // The absolute URL of the link returned by the hit test.
+ WEBKIT_API WebURL linkURL() const;
+
+ // The absolute URL of the image returned by the hit test.
+ WEBKIT_API WebURL imageURL() const;
+
+ // The node that got hit.
+ WEBKIT_API WebCore::Node* node() const;
+
+ // Point coordinates of the hit.
+ WEBKIT_API WebPoint point() const;
+
+ // True iff the hit was on an editable field or node.
+ WEBKIT_API bool isContentEditable() const;
+
+#if WEBKIT_IMPLEMENTATION
+ WebHitTestInfo(const WebCore::HitTestResult&);
+ WebHitTestInfo& operator=(const WebCore::HitTestResult&);
+ operator WebCore::HitTestResult() const;
+#endif
+
+protected:
+ WebPrivateOwnPtr<WebCore::HitTestResult> m_private;
+};
+
+} // namespace WebKit
+
+#endif
diff --git a/Source/WebKit/chromium/src/WebRange.cpp b/Source/WebKit/chromium/src/WebRange.cpp
index 3dd000d..5ea3990 100644
--- a/Source/WebKit/chromium/src/WebRange.cpp
+++ b/Source/WebKit/chromium/src/WebRange.cpp
@@ -32,7 +32,6 @@
#include "WebRange.h"
#include "Range.h"
-#include "WebNode.h"
#include "WebString.h"
#include <wtf/PassRefPtr.h>
@@ -66,14 +65,14 @@ int WebRange::endOffset() const
return m_private->endOffset();
}
-WebNode WebRange::startContainer(int& exceptionCode) const
+Node* WebRange::startContainer(int& exceptionCode) const
{
- return PassRefPtr<Node>(m_private->startContainer(exceptionCode));
+ return m_private->startContainer(exceptionCode);
}
-WebNode WebRange::endContainer(int& exceptionCode) const
+Node* WebRange::endContainer(int& exceptionCode) const
{
- return PassRefPtr<Node>(m_private->endContainer(exceptionCode));
+ return m_private->endContainer(exceptionCode);
}
WebString WebRange::toHTMLText() const
diff --git a/Source/WebKit/chromium/src/android/WebDOMTextContentWalker.cpp b/Source/WebKit/chromium/src/android/WebDOMTextContentWalker.cpp
new file mode 100644
index 0000000..80155fb
--- /dev/null
+++ b/Source/WebKit/chromium/src/android/WebDOMTextContentWalker.cpp
@@ -0,0 +1,85 @@
+/*
+ * 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 INC. 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 INC. 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"
+#include "android/WebDOMTextContentWalker.h"
+
+#include "DOMTextContentWalker.h"
+#include "Element.h"
+#include "Node.h"
+#include "Range.h"
+#include "RenderObject.h"
+#include "Text.h"
+#include "VisiblePosition.h"
+#include "android/WebHitTestInfo.h"
+
+using namespace WebCore;
+
+namespace WebKit {
+
+WebDOMTextContentWalker::WebDOMTextContentWalker()
+{
+}
+
+WebDOMTextContentWalker::~WebDOMTextContentWalker()
+{
+ m_private.reset(0);
+}
+
+WebDOMTextContentWalker::WebDOMTextContentWalker(const WebHitTestInfo& hitTestInfo, size_t maxLength)
+{
+ Node* node = hitTestInfo.node();
+ if (!node)
+ return;
+
+ Element* element = node->parentElement();
+ if (!node->inDocument() && element && element->inDocument())
+ node = element;
+ m_private.reset(new DOMTextContentWalker(node->renderer()->positionForPoint(hitTestInfo.point()), maxLength));
+}
+
+WebDOMTextContentWalker::WebDOMTextContentWalker(Node* node, size_t offset, size_t maxLength)
+{
+ if (!node || !node->isTextNode() || offset >= node->nodeValue().length())
+ return;
+
+ m_private.reset(new DOMTextContentWalker(VisiblePosition(Position(static_cast<Text*>(node), offset).parentAnchoredEquivalent(), DOWNSTREAM), maxLength));
+}
+
+WebString WebDOMTextContentWalker::content() const
+{
+ return m_private->content();
+}
+
+size_t WebDOMTextContentWalker::hitOffsetInContent() const
+{
+ return m_private->hitOffsetInContent();
+}
+
+WebRange WebDOMTextContentWalker::contentOffsetsToRange(size_t startInContent, size_t endInContent)
+{
+ return m_private->contentOffsetsToRange(startInContent, endInContent);
+}
+
+} // namespace WebKit
diff --git a/Source/WebKit/chromium/src/android/WebHitTestInfo.cpp b/Source/WebKit/chromium/src/android/WebHitTestInfo.cpp
new file mode 100644
index 0000000..948c6fb
--- /dev/null
+++ b/Source/WebKit/chromium/src/android/WebHitTestInfo.cpp
@@ -0,0 +1,95 @@
+/*
+* 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"
+#include "android/WebHitTestInfo.h"
+
+#include "Element.h"
+#include "HitTestResult.h"
+#include "KURL.h"
+#include "Node.h"
+#include "RenderObject.h"
+#include "VisiblePosition.h"
+
+using namespace WebCore;
+
+namespace WebKit {
+
+WebHitTestInfo::WebHitTestInfo()
+{
+}
+
+WebHitTestInfo::WebHitTestInfo(const WebHitTestInfo& testInfo)
+ : m_private(new HitTestResult(testInfo))
+{
+}
+
+WebURL WebHitTestInfo::linkURL() const
+{
+ return m_private->absoluteLinkURL();
+}
+
+WebHitTestInfo::~WebHitTestInfo()
+{
+ m_private.reset(0);
+}
+
+WebURL WebHitTestInfo::imageURL() const
+{
+ return m_private->absoluteImageURL();
+}
+
+Node* WebHitTestInfo::node() const
+{
+ return m_private->innerNode();
+}
+
+WebPoint WebHitTestInfo::point() const
+{
+ return WebPoint(m_private->localPoint());
+}
+
+bool WebHitTestInfo::isContentEditable() const
+{
+ return m_private->isContentEditable();
+}
+
+WebHitTestInfo::WebHitTestInfo(const HitTestResult& result)
+{
+ m_private.reset(new HitTestResult(result));
+}
+
+WebHitTestInfo& WebHitTestInfo::operator=(const HitTestResult& result)
+{
+ m_private.reset(new HitTestResult(result));
+ return *this;
+}
+
+WebHitTestInfo::operator HitTestResult() const
+{
+ return *m_private.get();
+}
+
+} // namespace WebKit