diff options
Diffstat (limited to 'Source')
285 files changed, 8044 insertions, 22691 deletions
diff --git a/Source/Android.mk b/Source/Android.mk deleted file mode 100644 index fd1f622..0000000 --- a/Source/Android.mk +++ /dev/null @@ -1,320 +0,0 @@ -## -## Copyright 2009, The Android Open Source Project -## -## Redistribution and use in source and binary forms, with or without -## modification, are permitted provided that the following conditions -## are met: -## * Redistributions of source code must retain the above copyright -## notice, this list of conditions and the following disclaimer. -## * Redistributions in binary form must reproduce the above copyright -## notice, this list of conditions and the following disclaimer in the -## documentation and/or other materials provided with the distribution. -## -## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY -## EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -## IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -## CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -## EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -## PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -## PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY -## OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -## - -LOCAL_PATH := $(call my-dir) - -# Two ways to control which JS engine is used: -# 1. use JS_ENGINE environment variable, value can be either 'jsc' or 'v8' -# This is the preferred way. -# 2. if JS_ENGINE is not set, or is not 'jsc' or 'v8', this makefile picks -# up a default engine to build. -# To help setup buildbot, a new environment variable, USE_ALT_JS_ENGINE, -# can be set to true, so that two builds can be different but without -# specifying which JS engine to use. -# To enable JIT in Android's JSC, please set ENABLE_JSC_JIT environment -# variable to true. - -# Read JS_ENGINE environment variable -JAVASCRIPT_ENGINE = $(JS_ENGINE) - -ifneq ($(JAVASCRIPT_ENGINE),jsc) - ifneq ($(JAVASCRIPT_ENGINE),v8) - # No JS engine is specified, pickup the one we want as default. - ifeq ($(USE_ALT_JS_ENGINE),true) - JAVASCRIPT_ENGINE = v8 - else - JAVASCRIPT_ENGINE = jsc - endif - endif -endif - -BASE_PATH := $(call my-dir) -include $(CLEAR_VARS) - -# Define our module and find the intermediates directory -LOCAL_MODULE := libwebcore -LOCAL_MODULE_CLASS := STATIC_LIBRARIES -base_intermediates := $(call local-intermediates-dir) - -# Using := here prevents recursive expansion -WEBKIT_SRC_FILES := - -# We have to use bison 2.3 -include $(BASE_PATH)/bison_check.mk - -# Build our list of include paths. We include WebKit/android/icu first so that -# any files that include <unicode/ucnv.h> will include our ucnv.h first. We -# also add external/ as an include directory so that we can specify the real -# icu header directory as a more exact reference to avoid including our ucnv.h. -# -# Note that JavasCriptCore/ must be included after WebCore/, so that we pick up -# the right config.h. -LOCAL_C_INCLUDES := \ - $(JNI_H_INCLUDE) \ - $(LOCAL_PATH)/WebKit/android/icu \ - external/ \ - external/icu4c/common \ - external/icu4c/i18n \ - external/libxml2/include \ - external/skia/emoji \ - external/skia/include/core \ - external/skia/include/effects \ - external/skia/include/images \ - external/skia/include/ports \ - external/skia/include/utils \ - external/skia/src/ports \ - external/sqlite/dist \ - frameworks/base/core/jni/android/graphics - -LOCAL_C_INCLUDES := $(LOCAL_C_INCLUDES) \ - $(LOCAL_PATH)/WebCore \ - $(LOCAL_PATH)/WebCore/accessibility \ - $(LOCAL_PATH)/WebCore/bindings/generic \ - $(LOCAL_PATH)/WebCore/css \ - $(LOCAL_PATH)/WebCore/dom \ - $(LOCAL_PATH)/WebCore/editing \ - $(LOCAL_PATH)/WebCore/history \ - $(LOCAL_PATH)/WebCore/history/android \ - $(LOCAL_PATH)/WebCore/html \ - $(LOCAL_PATH)/WebCore/html/canvas \ - $(LOCAL_PATH)/WebCore/inspector \ - $(LOCAL_PATH)/WebCore/loader \ - $(LOCAL_PATH)/WebCore/loader/appcache \ - $(LOCAL_PATH)/WebCore/loader/icon \ - $(LOCAL_PATH)/WebCore/notifications \ - $(LOCAL_PATH)/WebCore/page \ - $(LOCAL_PATH)/WebCore/page/android \ - $(LOCAL_PATH)/WebCore/page/animation \ - $(LOCAL_PATH)/WebCore/platform \ - $(LOCAL_PATH)/WebCore/platform/android \ - $(LOCAL_PATH)/WebCore/platform/animation \ - $(LOCAL_PATH)/WebCore/platform/graphics \ - $(LOCAL_PATH)/WebCore/platform/graphics/android \ - $(LOCAL_PATH)/WebCore/platform/graphics/network \ - $(LOCAL_PATH)/WebCore/platform/graphics/skia \ - $(LOCAL_PATH)/WebCore/platform/graphics/transforms \ - $(LOCAL_PATH)/WebCore/platform/image-decoders \ - $(LOCAL_PATH)/WebCore/platform/leveldb \ - $(LOCAL_PATH)/WebCore/platform/mock \ - $(LOCAL_PATH)/WebCore/platform/network \ - $(LOCAL_PATH)/WebCore/platform/network/android \ - $(LOCAL_PATH)/WebCore/platform/sql \ - $(LOCAL_PATH)/WebCore/platform/text \ - $(LOCAL_PATH)/WebCore/plugins \ - $(LOCAL_PATH)/WebCore/plugins/android \ - $(LOCAL_PATH)/WebCore/rendering \ - $(LOCAL_PATH)/WebCore/rendering/style \ - $(LOCAL_PATH)/WebCore/storage \ - $(LOCAL_PATH)/WebCore/workers \ - $(LOCAL_PATH)/WebCore/xml - -LOCAL_C_INCLUDES := $(LOCAL_C_INCLUDES) \ - $(LOCAL_PATH)/WebKit/android \ - $(LOCAL_PATH)/WebKit/android/WebCoreSupport \ - $(LOCAL_PATH)/WebKit/android/jni \ - $(LOCAL_PATH)/WebKit/android/nav \ - $(LOCAL_PATH)/WebKit/android/plugins \ - $(LOCAL_PATH)/WebKit/android/stl - -LOCAL_C_INCLUDES := $(LOCAL_C_INCLUDES) \ - $(LOCAL_PATH)/JavaScriptCore \ - $(LOCAL_PATH)/JavaScriptCore/wtf \ - $(LOCAL_PATH)/JavaScriptCore/wtf/unicode \ - $(LOCAL_PATH)/JavaScriptCore/wtf/unicode/icu - -LOCAL_C_INCLUDES := $(LOCAL_C_INCLUDES) \ - $(base_intermediates)/WebCore/ \ - $(base_intermediates)/WebCore/css \ - $(base_intermediates)/WebCore/html \ - $(base_intermediates)/WebCore/platform - -ifeq ($(ENABLE_SVG), true) -LOCAL_C_INCLUDES := $(LOCAL_C_INCLUDES) \ - $(LOCAL_PATH)/WebCore/platform/graphics/filters \ - $(LOCAL_PATH)/WebCore/svg \ - $(LOCAL_PATH)/WebCore/svg/animation \ - $(LOCAL_PATH)/WebCore/svg/graphics \ - $(LOCAL_PATH)/WebCore/svg/graphics/filters \ - $(base_intermediates)/WebCore/svg -endif - -ifeq ($(JAVASCRIPT_ENGINE),v8) -# Include WTF source file. -d := JavaScriptCore -LOCAL_PATH := $(BASE_PATH)/$d -intermediates := $(base_intermediates)/$d -include $(LOCAL_PATH)/Android.v8.wtf.mk -WEBKIT_SRC_FILES += $(addprefix $d/,$(LOCAL_SRC_FILES)) -endif # JAVASCRIPT_ENGINE == v8 - -# Include source files for WebCore -d := WebCore -LOCAL_PATH := $(BASE_PATH)/$d -JAVASCRIPTCORE_PATH := $(BASE_PATH)/JavaScriptCore -intermediates := $(base_intermediates)/$d -include $(LOCAL_PATH)/Android.mk -ifeq ($(JAVASCRIPT_ENGINE),jsc) -include $(LOCAL_PATH)/Android.jscbindings.mk -endif -ifeq ($(JAVASCRIPT_ENGINE),v8) -include $(LOCAL_PATH)/Android.v8bindings.mk -endif -WEBKIT_SRC_FILES += $(addprefix $d/,$(LOCAL_SRC_FILES)) -LOCAL_C_INCLUDES += $(BINDING_C_INCLUDES) - -# Include the derived source files for WebCore. Uses the same path as -# WebCore -include $(LOCAL_PATH)/Android.derived.mk -ifeq ($(JAVASCRIPT_ENGINE),jsc) -include $(LOCAL_PATH)/Android.derived.jscbindings.mk -endif -ifeq ($(JAVASCRIPT_ENGINE),v8) -include $(LOCAL_PATH)/Android.derived.v8bindings.mk -endif - -# Redefine LOCAL_PATH here so the build system is not confused -LOCAL_PATH := $(BASE_PATH) - -# Define our compiler flags -LOCAL_CFLAGS += -Wno-endif-labels -Wno-import -Wno-format -LOCAL_CFLAGS += -fno-strict-aliasing -LOCAL_CFLAGS += -include "WebCorePrefix.h" -LOCAL_CFLAGS += -fvisibility=hidden - -# Enable JSC JIT if JSC is used and ENABLE_JSC_JIT environment -# variable is set to true -ifeq ($(JAVASCRIPT_ENGINE),jsc) -ifeq ($(ENABLE_JSC_JIT),true) -LOCAL_CFLAGS += -DENABLE_ANDROID_JSC_JIT=1 -endif -endif - -ifeq ($(TARGET_ARCH),arm) -LOCAL_CFLAGS += -Darm -endif - -ifeq ($(ENABLE_SVG),true) -LOCAL_CFLAGS += -DENABLE_SVG=1 -endif - -# Temporary disable SVG_ANIMATION. -ifeq ($(ENABLE_SVG_ANIMATION),true) -LOCAL_CFLAGS += -DENABLE_SVG_ANIMATION=1 -endif - -ifeq ($(WEBCORE_INSTRUMENTATION),true) -LOCAL_CFLAGS += -DANDROID_INSTRUMENT -endif - -# LOCAL_LDLIBS is used in simulator builds only and simulator builds are only -# valid on Linux -LOCAL_LDLIBS += -lpthread -ldl - -# Build the list of shared libraries -LOCAL_SHARED_LIBRARIES := \ - libandroid_runtime \ - libnativehelper \ - libsqlite \ - libskia \ - libutils \ - libui \ - libcutils \ - libicuuc \ - libicudata \ - libicui18n \ - libmedia - -ifeq ($(WEBCORE_INSTRUMENTATION),true) -LOCAL_SHARED_LIBRARIES += libhardware_legacy -endif - -# We have to use the android version of libdl. -LOCAL_SHARED_LIBRARIES += libdl - -# Build the list of static libraries -LOCAL_STATIC_LIBRARIES := libxml2 -ifeq ($(JAVASCRIPT_ENGINE),v8) -LOCAL_STATIC_LIBRARIES += libv8 -endif - -# Redefine LOCAL_SRC_FILES to be all the WebKit source files -LOCAL_SRC_FILES := $(WEBKIT_SRC_FILES) - -# Define this for use in other makefiles. -WEBKIT_C_INCLUDES := $(LOCAL_C_INCLUDES) -WEBKIT_CFLAGS := $(LOCAL_CFLAGS) -WEBKIT_GENERATED_SOURCES := $(LOCAL_GENERATED_SOURCES) -WEBKIT_LDLIBS := $(LOCAL_LDLIBS) -WEBKIT_SHARED_LIBRARIES := $(LOCAL_SHARED_LIBRARIES) -WEBKIT_STATIC_LIBRARIES := $(LOCAL_STATIC_LIBRARIES) - -# Build the library all at once -include $(BUILD_STATIC_LIBRARY) - -ifeq ($(JAVASCRIPT_ENGINE),jsc) -# Now build libjs as a static library. -include $(CLEAR_VARS) -LOCAL_MODULE := libjs -LOCAL_LDLIBS := $(WEBKIT_LDLIBS) -LOCAL_SHARED_LIBRARIES := $(WEBKIT_SHARED_LIBRARIES) -LOCAL_STATIC_LIBRARIES := $(WEBKIT_STATIC_LIBRARIES) -LOCAL_CFLAGS := $(WEBKIT_CFLAGS) -# Include source files for JavaScriptCore -d := JavaScriptCore -LOCAL_PATH := $(BASE_PATH)/$d -LOCAL_MODULE_CLASS := STATIC_LIBRARIES -# Cannot use base_intermediates as this is a new module -intermediates := $(call local-intermediates-dir) -include $(LOCAL_PATH)/Android.mk -# Redefine LOCAL_SRC_FILES with the correct prefix -LOCAL_SRC_FILES := $(addprefix $d/,$(LOCAL_SRC_FILES)) -# Use the base path to resolve file names -LOCAL_PATH := $(BASE_PATH) -# Append jsc intermediate include paths to the WebKit include list. -LOCAL_C_INCLUDES := $(WEBKIT_C_INCLUDES) \ - $(intermediates) \ - $(intermediates)/parser \ - $(intermediates)/runtime \ -# Build libjs -include $(BUILD_STATIC_LIBRARY) -endif # JAVASCRIPT_ENGINE == jsc - -# Now build the shared library using only the exported jni entry point. This -# will strip out any unused code from the entry point. -include $(CLEAR_VARS) -# if you need to make webcore huge (for debugging), enable this line -#LOCAL_PRELINK_MODULE := false -LOCAL_MODULE := libwebcore -LOCAL_LDLIBS := $(WEBKIT_LDLIBS) -LOCAL_SHARED_LIBRARIES := $(WEBKIT_SHARED_LIBRARIES) -LOCAL_STATIC_LIBRARIES := libwebcore $(WEBKIT_STATIC_LIBRARIES) -ifeq ($(JAVASCRIPT_ENGINE),jsc) -LOCAL_STATIC_LIBRARIES += libjs -endif -LOCAL_LDFLAGS := -fvisibility=hidden -LOCAL_CFLAGS := $(WEBKIT_CFLAGS) -LOCAL_C_INCLUDES := $(WEBKIT_C_INCLUDES) -LOCAL_PATH := $(BASE_PATH) -include $(BUILD_SHARED_LIBRARY) diff --git a/Source/JavaScriptCore/Android.mk b/Source/JavaScriptCore/Android.mk deleted file mode 100644 index 48f326a..0000000 --- a/Source/JavaScriptCore/Android.mk +++ /dev/null @@ -1,251 +0,0 @@ -## -## Copyright 2009, The Android Open Source Project -## -## Redistribution and use in source and binary forms, with or without -## modification, are permitted provided that the following conditions -## are met: -## * Redistributions of source code must retain the above copyright -## notice, this list of conditions and the following disclaimer. -## * Redistributions in binary form must reproduce the above copyright -## notice, this list of conditions and the following disclaimer in the -## documentation and/or other materials provided with the distribution. -## -## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY -## EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -## IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -## CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -## EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -## PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -## PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY -## OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -## - -LOCAL_SRC_FILES := \ - API/JSValueRef.cpp \ - API/JSCallbackConstructor.cpp \ - API/JSCallbackFunction.cpp \ - API/JSCallbackObject.cpp \ - API/JSClassRef.cpp \ - API/JSObjectRef.cpp \ - API/JSStringRef.cpp \ - API/OpaqueJSString.cpp \ - \ - assembler/ARMv7Assembler.cpp \ - \ - bytecode/CodeBlock.cpp \ - bytecode/JumpTable.cpp \ - bytecode/Opcode.cpp \ - bytecode/SamplingTool.cpp \ - bytecode/StructureStubInfo.cpp \ - \ - bytecompiler/BytecodeGenerator.cpp \ - bytecompiler/NodesCodegen.cpp \ - \ - debugger/Debugger.cpp \ - debugger/DebuggerActivation.cpp \ - debugger/DebuggerCallFrame.cpp \ - \ - heap/ConservativeRoots.cpp \ - heap/HandleHeap.cpp \ - heap/HandleStack.cpp \ - heap/Heap.cpp \ - heap/MachineStackMarker.cpp \ - heap/MarkStack.cpp \ - heap/MarkStackPosix.cpp \ - heap/MarkedBlock.cpp \ - heap/MarkedSpace.cpp \ - \ - interpreter/CallFrame.cpp \ - interpreter/Interpreter.cpp \ - interpreter/RegisterFile.cpp \ - \ - jit/ExecutableAllocator.cpp\ - jit/ExecutableAllocatorFixedVMPool.cpp \ - jit/JIT.cpp \ - jit/JITArithmetic.cpp \ - jit/JITArithmetic32_64.cpp \ - jit/JITCall.cpp \ - jit/JITCall32_64.cpp \ - jit/JITOpcodes.cpp \ - jit/JITPropertyAccess.cpp \ - jit/JITStubs.cpp \ - jit/ThunkGenerators.cpp \ - \ - parser/JSParser.cpp \ - parser/Lexer.cpp \ - parser/Nodes.cpp \ - parser/Parser.cpp \ - parser/ParserArena.cpp \ - parser/SourceProviderCache.cpp \ - \ - profiler/Profile.cpp \ - profiler/ProfileGenerator.cpp \ - profiler/ProfileNode.cpp \ - profiler/Profiler.cpp \ - \ - runtime/ArgList.cpp \ - runtime/Arguments.cpp \ - runtime/ArrayConstructor.cpp \ - runtime/ArrayPrototype.cpp \ - runtime/BooleanConstructor.cpp \ - runtime/BooleanObject.cpp \ - runtime/BooleanPrototype.cpp \ - runtime/CallData.cpp \ - runtime/CommonIdentifiers.cpp \ - runtime/Completion.cpp \ - runtime/ConstructData.cpp \ - runtime/DateConstructor.cpp \ - runtime/DateConversion.cpp \ - runtime/DateInstance.cpp \ - runtime/DatePrototype.cpp \ - runtime/Error.cpp \ - runtime/ErrorConstructor.cpp \ - runtime/ErrorInstance.cpp \ - runtime/ErrorPrototype.cpp \ - runtime/ExceptionHelpers.cpp \ - runtime/Executable.cpp \ - runtime/FunctionConstructor.cpp \ - runtime/FunctionPrototype.cpp \ - runtime/GCActivityCallback.cpp \ - runtime/GetterSetter.cpp \ - runtime/Identifier.cpp \ - runtime/InitializeThreading.cpp \ - runtime/InternalFunction.cpp \ - runtime/JSAPIValueWrapper.cpp \ - runtime/JSActivation.cpp \ - runtime/JSArray.cpp \ - runtime/JSByteArray.cpp \ - runtime/JSCell.cpp \ - runtime/JSChunk.cpp \ - runtime/JSFunction.cpp \ - runtime/JSGlobalData.cpp \ - runtime/JSGlobalObject.cpp \ - runtime/JSGlobalObjectFunctions.cpp \ - runtime/JSLock.cpp \ - runtime/JSNotAnObject.cpp \ - runtime/JSONObject.cpp \ - runtime/JSObject.cpp \ - runtime/JSObjectWithGlobalObject.cpp \ - runtime/JSPropertyNameIterator.cpp \ - runtime/JSStaticScopeObject.cpp \ - runtime/JSString.cpp \ - runtime/JSValue.cpp \ - runtime/JSVariableObject.cpp \ - runtime/JSWrapperObject.cpp \ - runtime/LiteralParser.cpp \ - runtime/Lookup.cpp \ - runtime/MathObject.cpp \ - runtime/NativeErrorConstructor.cpp \ - runtime/NativeErrorPrototype.cpp \ - runtime/NumberConstructor.cpp \ - runtime/NumberObject.cpp \ - runtime/NumberPrototype.cpp \ - runtime/ObjectConstructor.cpp \ - runtime/ObjectPrototype.cpp \ - runtime/Operations.cpp \ - runtime/PropertyDescriptor.cpp \ - runtime/PropertyNameArray.cpp \ - runtime/PropertySlot.cpp \ - runtime/RegExp.cpp \ - runtime/RegExpCache.cpp \ - runtime/RegExpConstructor.cpp \ - runtime/RegExpObject.cpp \ - runtime/RegExpPrototype.cpp \ - runtime/RopeImpl.cpp \ - runtime/ScopeChain.cpp \ - runtime/SmallStrings.cpp \ - runtime/StrictEvalActivation.cpp \ - runtime/StringConstructor.cpp \ - runtime/StringObject.cpp \ - runtime/StringPrototype.cpp \ - runtime/StringRecursionChecker.cpp \ - runtime/Structure.cpp \ - runtime/StructureChain.cpp \ - runtime/TimeoutChecker.cpp \ - runtime/UString.cpp \ - \ - wtf/Assertions.cpp \ - wtf/ByteArray.cpp \ - wtf/CryptographicallyRandomNumber.cpp \ - wtf/CurrentTime.cpp \ - wtf/DateMath.cpp \ - wtf/DecimalNumber.cpp \ - wtf/FastMalloc.cpp \ - wtf/HashTable.cpp \ - wtf/MD5.cpp \ - wtf/MainThread.cpp \ - wtf/OSAllocatorPosix.cpp \ - wtf/OSRandomSource.cpp \ - wtf/PageAllocationAligned.cpp\ - wtf/PageBlock.cpp\ - wtf/RandomNumber.cpp \ - wtf/RefCountedLeakCounter.cpp \ - wtf/SHA1.cpp \ - wtf/StackBounds.cpp \ - wtf/TCSystemAlloc.cpp \ - wtf/ThreadIdentifierDataPthreads.cpp \ - wtf/Threading.cpp \ - wtf/ThreadingPthreads.cpp \ - wtf/TypeTraits.cpp \ - wtf/WTFThreadData.cpp \ - wtf/dtoa.cpp \ - \ - wtf/android/MainThreadAndroid.cpp \ - \ - wtf/text/AtomicString.cpp \ - wtf/text/CString.cpp \ - wtf/text/StringBuilder.cpp \ - wtf/text/StringImpl.cpp \ - wtf/text/StringStatics.cpp \ - wtf/text/WTFString.cpp \ - \ - wtf/unicode/CollatorDefault.cpp \ - wtf/unicode/UTF8.cpp \ - \ - wtf/unicode/icu/CollatorICU.cpp \ - \ - wtf/url/src/URLCharacterTypes.cpp \ - wtf/url/src/URLEscape.cpp \ - wtf/url/src/URLSegments.cpp \ - \ - yarr/YarrPattern.cpp \ - yarr/YarrInterpreter.cpp \ - yarr/YarrJIT.cpp \ - yarr/YarrSyntaxChecker.cpp - -# generated headers -JSC_OBJECTS := $(addprefix $(intermediates)/runtime/, \ - ArrayPrototype.lut.h \ - DatePrototype.lut.h \ - JSONObject.lut.h \ - MathObject.lut.h \ - NumberConstructor.lut.h \ - ObjectConstructor.lut.h \ - RegExpConstructor.lut.h \ - RegExpObject.lut.h \ - StringPrototype.lut.h \ - ) -$(JSC_OBJECTS): PRIVATE_PATH := $(LOCAL_PATH) -$(JSC_OBJECTS): PRIVATE_CUSTOM_TOOL = perl $(PRIVATE_PATH)/create_hash_table $< -i > $@ -$(JSC_OBJECTS): $(LOCAL_PATH)/create_hash_table -$(JSC_OBJECTS): $(intermediates)/%.lut.h : $(LOCAL_PATH)/%.cpp - $(transform-generated-source) - - -LEXER_HEADER := $(intermediates)/Lexer.lut.h -$(LEXER_HEADER): PRIVATE_PATH := $(LOCAL_PATH) -$(LEXER_HEADER): PRIVATE_CUSTOM_TOOL = perl $(PRIVATE_PATH)/create_hash_table $< -i > $@ -$(LEXER_HEADER): $(LOCAL_PATH)/create_hash_table -$(LEXER_HEADER): $(intermediates)/%.lut.h : $(LOCAL_PATH)/parser/Keywords.table - $(transform-generated-source) - -REGEXP_JIT_TABLES := $(intermediates)/RegExpJitTables.h -$(REGEXP_JIT_TABLES): PRIVATE_PATH := $(LOCAL_PATH) -$(REGEXP_JIT_TABLES): PRIVATE_CUSTOM_TOOL = python $(PRIVATE_PATH)/create_regex_tables > $@ -$(REGEXP_JIT_TABLES): $(LOCAL_PATH)/create_regex_tables - $(transform-generated-source) - -LOCAL_GENERATED_SOURCES += $(JSC_OBJECTS) $(LEXER_HEADER) $(REGEXP_JIT_TABLES) diff --git a/Source/JavaScriptCore/parser/Parser.cpp b/Source/JavaScriptCore/parser/Parser.cpp index dc15e4f..fc1e986 100644 --- a/Source/JavaScriptCore/parser/Parser.cpp +++ b/Source/JavaScriptCore/parser/Parser.cpp @@ -27,17 +27,10 @@ #include "JSParser.h" #include "Lexer.h" -#ifdef ANDROID_INSTRUMENT -#include "TimeCounter.h" -#endif - namespace JSC { void Parser::parse(JSGlobalData* globalData, FunctionParameters* parameters, JSParserStrictness strictness, JSParserMode mode, int* errLine, UString* errMsg) { -#ifdef ANDROID_INSTRUMENT - android::TimeCounter::start(android::TimeCounter::JavaScriptParseTimeCounter); -#endif ASSERT(globalData); m_sourceElements = 0; @@ -65,9 +58,6 @@ void Parser::parse(JSGlobalData* globalData, FunctionParameters* parameters, JSP *errMsg = parseError ? parseError : "Parse error"; m_sourceElements = 0; } -#ifdef ANDROID_INSTRUMENT - android::TimeCounter::record(android::TimeCounter::JavaScriptParseTimeCounter, __FUNCTION__); -#endif } void Parser::didFinishParsing(SourceElements* sourceElements, ParserArenaData<DeclarationStacks::VarStack>* varStack, diff --git a/Source/JavaScriptCore/runtime/TimeoutChecker.h b/Source/JavaScriptCore/runtime/TimeoutChecker.h index 71ce169..5925641 100644 --- a/Source/JavaScriptCore/runtime/TimeoutChecker.h +++ b/Source/JavaScriptCore/runtime/TimeoutChecker.h @@ -31,10 +31,6 @@ #include <wtf/Assertions.h> -#ifdef ANDROID_INSTRUMENT -#include "TimeCounter.h" -#endif - namespace JSC { class ExecState; @@ -52,10 +48,6 @@ namespace JSC { { if (!m_startCount) reset(); -#ifdef ANDROID_INSTRUMENT - if (!m_startCount) - android::TimeCounter::start(android::TimeCounter::JavaScriptTimeCounter); -#endif ++m_startCount; } @@ -63,10 +55,6 @@ namespace JSC { { ASSERT(m_startCount); --m_startCount; -#ifdef ANDROID_INSTRUMENT - if (!m_startCount) - android::TimeCounter::record(android::TimeCounter::JavaScriptTimeCounter, __FUNCTION__); -#endif } void reset(); diff --git a/Source/JavaScriptCore/wtf/Assertions.cpp b/Source/JavaScriptCore/wtf/Assertions.cpp index 930368c..0642414 100644 --- a/Source/JavaScriptCore/wtf/Assertions.cpp +++ b/Source/JavaScriptCore/wtf/Assertions.cpp @@ -66,6 +66,10 @@ #include <execinfo.h> #endif +#if OS(ANDROID) +#include <utils/Log.h> +#endif + extern "C" { #if PLATFORM(BREWMP) @@ -124,7 +128,9 @@ static void vprintf_stderr_common(const char* format, va_list args) vsnprintf(buffer.data(), size, format, args); printLog(buffer); } - +#elif OS(ANDROID) + LOG_PRI_VA(ANDROID_LOG_DEBUG, "WebKit", format, args); + return; #elif HAVE(ISDEBUGGERPRESENT) if (IsDebuggerPresent()) { size_t size = 1024; diff --git a/Source/JavaScriptCore/wtf/Platform.h b/Source/JavaScriptCore/wtf/Platform.h index e92af89..7c59f1b 100644 --- a/Source/JavaScriptCore/wtf/Platform.h +++ b/Source/JavaScriptCore/wtf/Platform.h @@ -676,7 +676,10 @@ #if PLATFORM(ANDROID) #define WEBCORE_NAVIGATOR_VENDOR "Google Inc." -#define LOG_DISABLED 1 +// Force LOG_ERROR() to be enabled in all builds. All other logging and +// assertions are enabled in debug builds only. +#define ERROR_DISABLED 0 + // This must be defined before we include FastMalloc.h in config.h. #define USE_SYSTEM_MALLOC 1 @@ -750,11 +753,8 @@ // Passes the webkit-originated changes of a focused textfield to our UI // thread #define ANDROID_ACCEPT_CHANGES_TO_FOCUSED_TEXTFIELDS -// Allow us to turn off the blinking caret as desired. -#define ANDROID_ALLOW_TURNING_OFF_CARET #define ANDROID_META_SUPPORT #define ANDROID_MULTIPLE_WINDOWS -#define ANDROID_CSS_RING #define ANDROID_CSS_TAP_HIGHLIGHT_COLOR #define ANDROID_BLOCK_NETWORK_IMAGE // Changes needed to support native plugins (npapi.h). If the change is generic, @@ -781,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.derived.jscbindings.mk b/Source/WebCore/Android.derived.jscbindings.mk deleted file mode 100644 index d859b15..0000000 --- a/Source/WebCore/Android.derived.jscbindings.mk +++ /dev/null @@ -1,752 +0,0 @@ - -## -## Copyright 2009, The Android Open Source Project -## -## Redistribution and use in source and binary forms, with or without -## modification, are permitted provided that the following conditions -## are met: -## * Redistributions of source code must retain the above copyright -## notice, this list of conditions and the following disclaimer. -## * Redistributions in binary form must reproduce the above copyright -## notice, this list of conditions and the following disclaimer in the -## documentation and/or other materials provided with the distribution. -## -## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY -## EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -## IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -## CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -## EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -## PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -## PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY -## OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -## - -# lookup tables for old-style JavaScript bindings -create_hash_table := $(LOCAL_PATH)/../JavaScriptCore/create_hash_table - -GEN := $(addprefix $(intermediates)/, \ - bindings/js/JSDOMWindowBase.lut.h \ - ) -$(GEN): PRIVATE_CUSTOM_TOOL = perl $(create_hash_table) $< > $@ -$(GEN): $(intermediates)/bindings/js/%.lut.h: $(LOCAL_PATH)/bindings/js/%.cpp $(create_hash_table) - $(transform-generated-source) -LOCAL_GENERATED_SOURCES += $(GEN) - - -GEN := $(intermediates)/bindings/js/JSHTMLInputElementBaseTable.cpp -$(GEN): PRIVATE_CUSTOM_TOOL = perl $(create_hash_table) $< > $@ -$(GEN): $(intermediates)/bindings/js/%Table.cpp: $(LOCAL_PATH)/bindings/js/%.cpp $(create_hash_table) - $(transform-generated-source) -$(intermediates)/bindings/js/JSHTMLInputElementBase.o : $(GEN) - -# lookup tables for old-style JavaScript bindings -js_binding_scripts := $(addprefix $(LOCAL_PATH)/,\ - bindings/scripts/CodeGenerator.pm \ - bindings/scripts/IDLParser.pm \ - bindings/scripts/IDLStructure.pm \ - bindings/scripts/generate-bindings.pl \ - ) - -FEATURE_DEFINES := ENABLE_ORIENTATION_EVENTS=1 ENABLE_TOUCH_EVENTS=1 ENABLE_DATABASE=1 ENABLE_OFFLINE_WEB_APPLICATIONS=1 ENABLE_DOM_STORAGE=1 ENABLE_VIDEO=1 ENABLE_GEOLOCATION=1 ENABLE_CONNECTION=1 ENABLE_APPLICATION_INSTALLED=1 ENABLE_XPATH=1 ENABLE_XSLT=1 ENABLE_DEVICE_ORIENTATION=1 ENABLE_FILE_READER=1 ENABLE_BLOB=1 ENABLE_WEB_TIMING=1 - -ifeq ($(ENABLE_SVG), true) - FEATURE_DEFINES += ENABLE_SVG=1 -endif - -# CSS -GEN := \ - $(intermediates)/css/JSCSSCharsetRule.h \ - $(intermediates)/css/JSCSSFontFaceRule.h \ - $(intermediates)/css/JSCSSImportRule.h \ - $(intermediates)/css/JSCSSMediaRule.h \ - $(intermediates)/css/JSCSSPageRule.h \ - $(intermediates)/css/JSCSSPrimitiveValue.h \ - $(intermediates)/css/JSCSSRule.h \ - $(intermediates)/css/JSCSSRuleList.h \ - $(intermediates)/css/JSCSSStyleDeclaration.h \ - $(intermediates)/css/JSCSSStyleRule.h \ - $(intermediates)/css/JSCSSStyleSheet.h \ - $(intermediates)/css/JSCSSValue.h \ - $(intermediates)/css/JSCSSValueList.h \ - $(intermediates)/css/JSCounter.h \ - $(intermediates)/css/JSMediaList.h \ - $(intermediates)/css/JSMediaQueryList.h \ - $(intermediates)/css/JSRGBColor.h \ - $(intermediates)/css/JSRect.h \ - $(intermediates)/css/JSStyleMedia.h \ - $(intermediates)/css/JSStyleSheet.h \ - $(intermediates)/css/JSStyleSheetList.h \ - $(intermediates)/css/JSWebKitCSSKeyframeRule.h \ - $(intermediates)/css/JSWebKitCSSKeyframesRule.h \ - $(intermediates)/css/JSWebKitCSSMatrix.h \ - $(intermediates)/css/JSWebKitCSSTransformValue.h -$(GEN): PRIVATE_PATH := $(LOCAL_PATH) -$(GEN): PRIVATE_CUSTOM_TOOL = perl -I$(PRIVATE_PATH)/bindings/scripts $(PRIVATE_PATH)/bindings/scripts/generate-bindings.pl --defines "$(FEATURE_DEFINES) LANGUAGE_JAVASCRIPT" --generator JS --include dom --include html --outputdir $(dir $@) $< -$(GEN): $(intermediates)/css/JS%.h : $(LOCAL_PATH)/css/%.idl $(js_binding_scripts) - $(transform-generated-source) -LOCAL_GENERATED_SOURCES += $(GEN) $(GEN:%.h=%.cpp) - - -# We also need the .cpp files, which are generated as side effects of the -# above rules. Specifying this explicitly makes -j2 work. -$(patsubst %.h,%.cpp,$(GEN)): $(intermediates)/css/%.cpp : $(intermediates)/css/%.h - -# DOM -GEN := \ - $(intermediates)/dom/JSAttr.h \ - $(intermediates)/dom/JSBeforeLoadEvent.h \ - $(intermediates)/dom/JSCDATASection.h \ - $(intermediates)/dom/JSCharacterData.h \ - $(intermediates)/dom/JSClientRect.h \ - $(intermediates)/dom/JSClientRectList.h \ - $(intermediates)/dom/JSClipboard.h \ - $(intermediates)/dom/JSComment.h \ - $(intermediates)/dom/JSCustomEvent.h \ - $(intermediates)/dom/JSCompositionEvent.h \ - $(intermediates)/dom/JSDOMCoreException.h \ - $(intermediates)/dom/JSDOMImplementation.h \ - $(intermediates)/dom/JSDOMStringList.h \ - $(intermediates)/dom/JSDOMStringMap.h \ - $(intermediates)/dom/JSDataTransferItems.h \ - $(intermediates)/dom/JSDeviceMotionEvent.h \ - $(intermediates)/dom/JSDeviceOrientationEvent.h \ - $(intermediates)/dom/JSDocument.h \ - $(intermediates)/dom/JSDocumentFragment.h \ - $(intermediates)/dom/JSDocumentType.h \ - $(intermediates)/dom/JSElement.h \ - $(intermediates)/dom/JSEntity.h \ - $(intermediates)/dom/JSEntityReference.h \ - $(intermediates)/dom/JSErrorEvent.h \ - $(intermediates)/dom/JSEvent.h \ - $(intermediates)/dom/JSEventException.h \ - $(intermediates)/dom/JSHashChangeEvent.h \ - $(intermediates)/dom/JSKeyboardEvent.h \ - $(intermediates)/dom/JSMessageChannel.h \ - $(intermediates)/dom/JSMessageEvent.h \ - $(intermediates)/dom/JSMessagePort.h \ - $(intermediates)/dom/JSMouseEvent.h \ - $(intermediates)/dom/JSMutationEvent.h \ - $(intermediates)/dom/JSNamedNodeMap.h \ - $(intermediates)/dom/JSNode.h \ - $(intermediates)/dom/JSNodeFilter.h \ - $(intermediates)/dom/JSNodeIterator.h \ - $(intermediates)/dom/JSNodeList.h \ - $(intermediates)/dom/JSNotation.h \ - $(intermediates)/dom/JSOverflowEvent.h \ - $(intermediates)/dom/JSPageTransitionEvent.h \ - $(intermediates)/dom/JSPopStateEvent.h \ - $(intermediates)/dom/JSProcessingInstruction.h \ - $(intermediates)/dom/JSProgressEvent.h \ - $(intermediates)/dom/JSRange.h \ - $(intermediates)/dom/JSRangeException.h \ - $(intermediates)/dom/JSText.h \ - $(intermediates)/dom/JSTextEvent.h \ - $(intermediates)/dom/JSTouch.h \ - $(intermediates)/dom/JSTouchEvent.h \ - $(intermediates)/dom/JSTouchList.h \ - $(intermediates)/dom/JSTreeWalker.h \ - $(intermediates)/dom/JSUIEvent.h \ - $(intermediates)/dom/JSWebKitAnimationEvent.h \ - $(intermediates)/dom/JSWebKitTransitionEvent.h \ - $(intermediates)/dom/JSWheelEvent.h -$(GEN): PRIVATE_PATH := $(LOCAL_PATH) -$(GEN): PRIVATE_CUSTOM_TOOL = perl -I$(PRIVATE_PATH)/bindings/scripts $(PRIVATE_PATH)/bindings/scripts/generate-bindings.pl --defines "$(FEATURE_DEFINES) LANGUAGE_JAVASCRIPT" --generator JS --include dom --include html --outputdir $(dir $@) $< -$(GEN): $(intermediates)/dom/JS%.h : $(LOCAL_PATH)/dom/%.idl $(js_binding_scripts) - $(transform-generated-source) -LOCAL_GENERATED_SOURCES += $(GEN) $(GEN:%.h=%.cpp) - -# We also need the .cpp files, which are generated as side effects of the -# above rules. Specifying this explicitly makes -j2 work. -$(patsubst %.h,%.cpp,$(GEN)): $(intermediates)/dom/%.cpp : $(intermediates)/dom/%.h - -# Fileapi -GEN := \ - $(intermediates)/fileapi/JSBlob.h \ - $(intermediates)/fileapi/JSDOMFileSystem.h \ - $(intermediates)/fileapi/JSDOMFileSystemSync.h \ - $(intermediates)/fileapi/JSDirectoryEntry.h \ - $(intermediates)/fileapi/JSDirectoryEntrySync.h \ - $(intermediates)/fileapi/JSDirectoryReader.h \ - $(intermediates)/fileapi/JSDirectoryReaderSync.h \ - $(intermediates)/fileapi/JSEntriesCallback.h \ - $(intermediates)/fileapi/JSEntry.h \ - $(intermediates)/fileapi/JSEntryArray.h \ - $(intermediates)/fileapi/JSEntryArraySync.h \ - $(intermediates)/fileapi/JSEntryCallback.h \ - $(intermediates)/fileapi/JSEntrySync.h \ - $(intermediates)/fileapi/JSErrorCallback.h \ - $(intermediates)/fileapi/JSFile.h \ - $(intermediates)/fileapi/JSFileCallback.h \ - $(intermediates)/fileapi/JSFileEntry.h \ - $(intermediates)/fileapi/JSFileEntrySync.h \ - $(intermediates)/fileapi/JSFileError.h \ - $(intermediates)/fileapi/JSFileException.h \ - $(intermediates)/fileapi/JSFileList.h \ - $(intermediates)/fileapi/JSFileReader.h \ - $(intermediates)/fileapi/JSFileReaderSync.h \ - $(intermediates)/fileapi/JSFileSystemCallback.h \ - $(intermediates)/fileapi/JSFileWriter.h \ - $(intermediates)/fileapi/JSFileWriterCallback.h \ - $(intermediates)/fileapi/JSMetadata.h \ - $(intermediates)/fileapi/JSMetadataCallback.h \ - $(intermediates)/fileapi/JSWebKitBlobBuilder.h \ - $(intermediates)/fileapi/JSWebKitFlags.h - -$(GEN): PRIVATE_PATH := $(LOCAL_PATH) -$(GEN): PRIVATE_CUSTOM_TOOL = perl -I$(PRIVATE_PATH)/bindings/scripts $(PRIVATE_PATH)/bindings/scripts/generate-bindings.pl --defines "$(FEATURE_DEFINES) LANGUAGE_JAVASCRIPT" --generator JS --include dom --include html --include fileapi --outputdir $(dir $@) $< -$(GEN): $(intermediates)/fileapi/JS%.h : $(LOCAL_PATH)/fileapi/%.idl $(js_binding_scripts) - $(transform-generated-source) -LOCAL_GENERATED_SOURCES += $(GEN) $(GEN:%.h=%.cpp) - -# We also need the .cpp files, which are generated as side effects of the -# above rules. Specifying this explicitly makes -j2 work. -$(patsubst %.h,%.cpp,$(GEN)): $(intermediates)/fileapi/%.cpp : $(intermediates)/fileapi/%.h - -# HTML -GEN := \ - $(intermediates)/html/JSDOMFormData.h \ - $(intermediates)/html/JSDOMSettableTokenList.h \ - $(intermediates)/html/JSDOMTokenList.h \ - $(intermediates)/html/JSDOMURL.h \ - $(intermediates)/html/JSDataGridColumn.h \ - $(intermediates)/html/JSDataGridColumnList.h \ - $(intermediates)/html/JSHTMLAllCollection.h \ - $(intermediates)/html/JSHTMLAnchorElement.h \ - $(intermediates)/html/JSHTMLAppletElement.h \ - $(intermediates)/html/JSHTMLAreaElement.h \ - $(intermediates)/html/JSHTMLAudioElement.h \ - $(intermediates)/html/JSHTMLBRElement.h \ - $(intermediates)/html/JSHTMLBaseElement.h \ - $(intermediates)/html/JSHTMLBaseFontElement.h \ - $(intermediates)/html/JSHTMLBlockquoteElement.h \ - $(intermediates)/html/JSHTMLBodyElement.h \ - $(intermediates)/html/JSHTMLButtonElement.h \ - $(intermediates)/html/JSHTMLCanvasElement.h \ - $(intermediates)/html/JSHTMLCollection.h \ - $(intermediates)/html/JSHTMLDataGridElement.h \ - $(intermediates)/html/JSHTMLDataGridCellElement.h \ - $(intermediates)/html/JSHTMLDataGridColElement.h \ - $(intermediates)/html/JSHTMLDataGridRowElement.h \ - $(intermediates)/html/JSHTMLDataListElement.h \ - $(intermediates)/html/JSHTMLDetailsElement.h \ - $(intermediates)/html/JSHTMLDListElement.h \ - $(intermediates)/html/JSHTMLDirectoryElement.h \ - $(intermediates)/html/JSHTMLDivElement.h \ - $(intermediates)/html/JSHTMLDocument.h \ - $(intermediates)/html/JSHTMLElement.h \ - $(intermediates)/html/JSHTMLEmbedElement.h \ - $(intermediates)/html/JSHTMLFieldSetElement.h \ - $(intermediates)/html/JSHTMLFontElement.h \ - $(intermediates)/html/JSHTMLFormElement.h \ - $(intermediates)/html/JSHTMLFrameElement.h \ - $(intermediates)/html/JSHTMLFrameSetElement.h \ - $(intermediates)/html/JSHTMLHRElement.h \ - $(intermediates)/html/JSHTMLHeadElement.h \ - $(intermediates)/html/JSHTMLHeadingElement.h \ - $(intermediates)/html/JSHTMLHtmlElement.h \ - $(intermediates)/html/JSHTMLIFrameElement.h \ - $(intermediates)/html/JSHTMLImageElement.h \ - $(intermediates)/html/JSHTMLInputElement.h \ - $(intermediates)/html/JSHTMLIsIndexElement.h \ - $(intermediates)/html/JSHTMLKeygenElement.h \ - $(intermediates)/html/JSHTMLLIElement.h \ - $(intermediates)/html/JSHTMLLabelElement.h \ - $(intermediates)/html/JSHTMLLegendElement.h \ - $(intermediates)/html/JSHTMLLinkElement.h \ - $(intermediates)/html/JSHTMLMapElement.h \ - $(intermediates)/html/JSHTMLMarqueeElement.h \ - $(intermediates)/html/JSHTMLMediaElement.h \ - $(intermediates)/html/JSHTMLMenuElement.h \ - $(intermediates)/html/JSHTMLMetaElement.h \ - $(intermediates)/html/JSHTMLMeterElement.h \ - $(intermediates)/html/JSHTMLModElement.h \ - $(intermediates)/html/JSHTMLOListElement.h \ - $(intermediates)/html/JSHTMLObjectElement.h \ - $(intermediates)/html/JSHTMLOptGroupElement.h \ - $(intermediates)/html/JSHTMLOptionElement.h \ - $(intermediates)/html/JSHTMLOptionsCollection.h \ - $(intermediates)/html/JSHTMLOutputElement.h \ - $(intermediates)/html/JSHTMLParagraphElement.h \ - $(intermediates)/html/JSHTMLParamElement.h \ - $(intermediates)/html/JSHTMLPreElement.h \ - $(intermediates)/html/JSHTMLProgressElement.h \ - $(intermediates)/html/JSHTMLQuoteElement.h \ - $(intermediates)/html/JSHTMLScriptElement.h \ - $(intermediates)/html/JSHTMLSelectElement.h \ - $(intermediates)/html/JSHTMLSourceElement.h \ - $(intermediates)/html/JSHTMLStyleElement.h \ - $(intermediates)/html/JSHTMLTableCaptionElement.h \ - $(intermediates)/html/JSHTMLTableCellElement.h \ - $(intermediates)/html/JSHTMLTableColElement.h \ - $(intermediates)/html/JSHTMLTableElement.h \ - $(intermediates)/html/JSHTMLTableRowElement.h \ - $(intermediates)/html/JSHTMLTableSectionElement.h \ - $(intermediates)/html/JSHTMLTextAreaElement.h \ - $(intermediates)/html/JSHTMLTitleElement.h \ - $(intermediates)/html/JSHTMLUListElement.h \ - $(intermediates)/html/JSHTMLVideoElement.h \ - $(intermediates)/html/JSImageData.h \ - $(intermediates)/html/JSMediaError.h \ - $(intermediates)/html/JSTextMetrics.h \ - $(intermediates)/html/JSTimeRanges.h \ - $(intermediates)/html/JSValidityState.h \ - $(intermediates)/html/JSVoidCallback.h - - -$(GEN): PRIVATE_PATH := $(LOCAL_PATH) -$(GEN): PRIVATE_CUSTOM_TOOL = perl -I$(PRIVATE_PATH)/bindings/scripts $(PRIVATE_PATH)/bindings/scripts/generate-bindings.pl --defines "$(FEATURE_DEFINES) LANGUAGE_JAVASCRIPT" --generator JS --include dom --include html --outputdir $(dir $@) $< -$(GEN): $(intermediates)/html/JS%.h : $(LOCAL_PATH)/html/%.idl $(js_binding_scripts) - $(transform-generated-source) -LOCAL_GENERATED_SOURCES += $(GEN) $(GEN:%.h=%.cpp) - -# We also need the .cpp files, which are generated as side effects of the -# above rules. Specifying this explicitly makes -j2 work. -$(patsubst %.h,%.cpp,$(GEN)): $(intermediates)/html/%.cpp : $(intermediates)/html/%.h - -# Canvas -GEN := \ - $(intermediates)/html/canvas/JSArrayBuffer.h \ - $(intermediates)/html/canvas/JSArrayBufferView.h \ - $(intermediates)/html/canvas/JSCanvasGradient.h \ - $(intermediates)/html/canvas/JSCanvasPattern.h \ - $(intermediates)/html/canvas/JSCanvasRenderingContext.h \ - $(intermediates)/html/canvas/JSCanvasRenderingContext2D.h \ - $(intermediates)/html/canvas/JSDataView.h \ - $(intermediates)/html/canvas/JSFloat32Array.h \ - $(intermediates)/html/canvas/JSInt8Array.h \ - $(intermediates)/html/canvas/JSInt16Array.h \ - $(intermediates)/html/canvas/JSInt32Array.h \ - $(intermediates)/html/canvas/JSOESTextureFloat.h \ - $(intermediates)/html/canvas/JSOESVertexArrayObject.h \ - $(intermediates)/html/canvas/JSUint8Array.h \ - $(intermediates)/html/canvas/JSUint16Array.h \ - $(intermediates)/html/canvas/JSUint32Array.h \ - $(intermediates)/html/canvas/JSWebGLActiveInfo.h \ - $(intermediates)/html/canvas/JSWebGLBuffer.h \ - $(intermediates)/html/canvas/JSWebGLFramebuffer.h \ - $(intermediates)/html/canvas/JSWebGLProgram.h \ - $(intermediates)/html/canvas/JSWebGLRenderbuffer.h \ - $(intermediates)/html/canvas/JSWebGLRenderingContext.h \ - $(intermediates)/html/canvas/JSWebGLShader.h \ - $(intermediates)/html/canvas/JSWebGLTexture.h \ - $(intermediates)/html/canvas/JSWebGLUniformLocation.h \ - $(intermediates)/html/canvas/JSWebGLVertexArrayObjectOES.h - -$(GEN): PRIVATE_PATH := $(LOCAL_PATH) -$(GEN): PRIVATE_CUSTOM_TOOL = perl -I$(PRIVATE_PATH)/bindings/scripts $(PRIVATE_PATH)/bindings/scripts/generate-bindings.pl --defines "$(FEATURE_DEFINES) LANGUAGE_JAVASCRIPT" --generator JS --include dom --include html --outputdir $(dir $@) $< -$(GEN): $(intermediates)/html/canvas/JS%.h : $(LOCAL_PATH)/html/canvas/%.idl $(js_binding_scripts) - $(transform-generated-source) -LOCAL_GENERATED_SOURCES += $(GEN) $(GEN:%.h=%.cpp) - -# We also need the .cpp files, which are generated as side effects of the -# above rules. Specifying this explicitly makes -j2 work. -$(patsubst %.h,%.cpp,$(GEN)): $(intermediates)/html/canvas/%.cpp : $(intermediates)/html/canvas/%.h - -# Appcache -GEN := \ - $(intermediates)/loader/appcache/JSDOMApplicationCache.h - -$(GEN): PRIVATE_PATH := $(LOCAL_PATH) -$(GEN): PRIVATE_CUSTOM_TOOL = perl -I$(PRIVATE_PATH)/bindings/scripts $(PRIVATE_PATH)/bindings/scripts/generate-bindings.pl --defines "$(FEATURE_DEFINES) LANGUAGE_JAVASCRIPT" --generator JS --include dom --include html --outputdir $(dir $@) $< -$(GEN): $(intermediates)/loader/appcache/JS%.h : $(LOCAL_PATH)/loader/appcache/%.idl $(js_binding_scripts) - $(transform-generated-source) -LOCAL_GENERATED_SOURCES += $(GEN) $(GEN:%.h=%.cpp) - -# We also need the .cpp files, which are generated as side effects of the -# above rules. Specifying this explicitly makes -j2 work. -$(patsubst %.h,%.cpp,$(GEN)): $(intermediates)/loader/appcache/%.cpp : $(intermediates)/loader/appcache/%.h - -# page -GEN := \ - $(intermediates)/page/JSBarInfo.h \ - $(intermediates)/page/JSConnection.h \ - $(intermediates)/page/JSConsole.h \ - $(intermediates)/page/JSCoordinates.h \ - $(intermediates)/page/JSCrypto.h \ - $(intermediates)/page/JSDOMSelection.h \ - $(intermediates)/page/JSDOMWindow.h \ - $(intermediates)/page/JSEventSource.h \ - $(intermediates)/page/JSGeolocation.h \ - $(intermediates)/page/JSGeoposition.h \ - $(intermediates)/page/JSHistory.h \ - $(intermediates)/page/JSLocation.h \ - $(intermediates)/page/JSMemoryInfo.h \ - $(intermediates)/page/JSNavigator.h \ - $(intermediates)/page/JSNavigatorUserMediaError.h \ - $(intermediates)/page/JSNavigatorUserMediaErrorCallback.h \ - $(intermediates)/page/JSNavigatorUserMediaSuccessCallback.h \ - $(intermediates)/page/JSPerformance.h \ - $(intermediates)/page/JSPerformanceNavigation.h \ - $(intermediates)/page/JSPerformanceTiming.h \ - $(intermediates)/page/JSPositionError.h \ - $(intermediates)/page/JSScreen.h \ - $(intermediates)/page/JSSpeechInputEvent.h \ - $(intermediates)/page/JSWebKitAnimation.h \ - $(intermediates)/page/JSWebKitAnimationList.h \ - $(intermediates)/page/JSWebKitPoint.h \ - $(intermediates)/page/JSWorkerNavigator.h - -$(GEN): PRIVATE_PATH := $(LOCAL_PATH) -$(GEN): PRIVATE_CUSTOM_TOOL = perl -I$(PRIVATE_PATH)/bindings/scripts $(PRIVATE_PATH)/bindings/scripts/generate-bindings.pl --defines "$(FEATURE_DEFINES) LANGUAGE_JAVASCRIPT" --generator JS --include dom --include html --outputdir $(dir $@) $< -$(GEN): $(intermediates)/page/JS%.h : $(LOCAL_PATH)/page/%.idl $(js_binding_scripts) - $(transform-generated-source) -LOCAL_GENERATED_SOURCES += $(GEN) $(GEN:%.h=%.cpp) - -# We also need the .cpp files, which are generated as side effects of the -# above rules. Specifying this explicitly makes -j2 work. -$(patsubst %.h,%.cpp,$(GEN)): $(intermediates)/page/%.cpp : $(intermediates)/page/%.h - -GEN := \ - $(intermediates)/plugins/JSDOMMimeType.h \ - $(intermediates)/plugins/JSDOMMimeTypeArray.h \ - $(intermediates)/plugins/JSDOMPlugin.h \ - $(intermediates)/plugins/JSDOMPluginArray.h - -$(GEN): PRIVATE_PATH := $(LOCAL_PATH) -$(GEN): PRIVATE_CUSTOM_TOOL = perl -I$(PRIVATE_PATH)/bindings/scripts $(PRIVATE_PATH)/bindings/scripts/generate-bindings.pl --defines "$(FEATURE_DEFINES) LANGUAGE_JAVASCRIPT" --generator JS --include dom --include html --outputdir $(dir $@) $< -$(GEN): $(intermediates)/plugins/JS%.h : $(LOCAL_PATH)/plugins/%.idl $(js_binding_scripts) - $(transform-generated-source) -LOCAL_GENERATED_SOURCES += $(GEN) $(GEN:%.h=%.cpp) - -# We also need the .cpp files, which are generated as side effects of the -# above rules. Specifying this explicitly makes -j2 work. -$(patsubst %.h,%.cpp,$(GEN)): $(intermediates)/plugins/%.cpp : $(intermediates)/plugins/%.h - -# Database -GEN := \ - $(intermediates)/storage/JSDatabase.h \ - $(intermediates)/storage/JSDatabaseCallback.h \ - $(intermediates)/storage/JSDatabaseSync.h \ - $(intermediates)/storage/JSSQLError.h \ - $(intermediates)/storage/JSSQLException.h \ - $(intermediates)/storage/JSSQLResultSet.h \ - $(intermediates)/storage/JSSQLResultSetRowList.h \ - $(intermediates)/storage/JSSQLStatementCallback.h \ - $(intermediates)/storage/JSSQLStatementErrorCallback.h \ - $(intermediates)/storage/JSSQLTransaction.h \ - $(intermediates)/storage/JSSQLTransactionCallback.h \ - $(intermediates)/storage/JSSQLTransactionSync.h \ - $(intermediates)/storage/JSSQLTransactionSyncCallback.h \ - $(intermediates)/storage/JSSQLTransactionErrorCallback.h - -$(GEN): PRIVATE_PATH := $(LOCAL_PATH) -$(GEN): PRIVATE_CUSTOM_TOOL = perl -I$(PRIVATE_PATH)/bindings/scripts $(PRIVATE_PATH)/bindings/scripts/generate-bindings.pl --defines "$(FEATURE_DEFINES) LANGUAGE_JAVASCRIPT" --generator JS --include dom --include html --include storage --outputdir $(dir $@) $< -$(GEN): $(intermediates)/storage/JS%.h : $(LOCAL_PATH)/storage/%.idl $(js_binding_scripts) - $(transform-generated-source) -LOCAL_GENERATED_SOURCES += $(GEN) $(GEN:%.h=%.cpp) - -# We also need the .cpp files, which are generated as side effects of the -# above rules. Specifying this explicitly makes -j2 work. -$(patsubst %.h,%.cpp,$(GEN)): $(intermediates)/storage/%.cpp : $(intermediates)/storage/%.h - -# DOM Storage -GEN := \ - $(intermediates)/storage/JSStorage.h \ - $(intermediates)/storage/JSStorageEvent.h - -$(GEN): PRIVATE_PATH := $(LOCAL_PATH) -$(GEN): PRIVATE_CUSTOM_TOOL = perl -I$(PRIVATE_PATH)/bindings/scripts $(PRIVATE_PATH)/bindings/scripts/generate-bindings.pl --defines "$(FEATURE_DEFINES) LANGUAGE_JAVASCRIPT" --generator JS --include dom --include html --outputdir $(dir $@) $< -$(GEN): $(intermediates)/storage/JS%.h : $(LOCAL_PATH)/storage/%.idl $(js_binding_scripts) - $(transform-generated-source) -LOCAL_GENERATED_SOURCES += $(GEN) $(GEN:%.h=%.cpp) - -# We also need the .cpp files, which are generated as side effects of the -# above rules. Specifying this explicitly makes -j2 work. -$(patsubst %.h,%.cpp,$(GEN)): $(intermediates)/storage/%.cpp : $(intermediates)/storage/%.h - -# Indexed Database -GEN := \ - $(intermediates)/storage/JSIDBAny.h \ - $(intermediates)/storage/JSIDBCursor.h \ - $(intermediates)/storage/JSIDBCursorWithValue.h \ - $(intermediates)/storage/JSIDBDatabaseError.h \ - $(intermediates)/storage/JSIDBDatabaseException.h \ - $(intermediates)/storage/JSIDBDatabase.h \ - $(intermediates)/storage/JSIDBFactory.h \ - $(intermediates)/storage/JSIDBIndex.h \ - $(intermediates)/storage/JSIDBKey.h \ - $(intermediates)/storage/JSIDBKeyRange.h \ - $(intermediates)/storage/JSIDBObjectStore.h \ - $(intermediates)/storage/JSIDBRequest.h \ - $(intermediates)/storage/JSIDBTransaction.h \ - $(intermediates)/storage/JSIDBVersionChangeEvent.h \ - $(intermediates)/storage/JSIDBVersionChangeRequest.h - -$(GEN): PRIVATE_PATH := $(LOCAL_PATH) -$(GEN): PRIVATE_CUSTOM_TOOL = perl -I$(PRIVATE_PATH)/bindings/scripts $(PRIVATE_PATH)/bindings/scripts/generate-bindings.pl --defines "$(FEATURE_DEFINES) LANGUAGE_JAVASCRIPT" --generator JS --include dom --include html --include storage --outputdir $(dir $@) $< -$(GEN): $(intermediates)/storage/JS%.h : $(LOCAL_PATH)/storage/%.idl $(js_binding_scripts) - $(transform-generated-source) -LOCAL_GENERATED_SOURCES += $(GEN) $(GEN:%.h=%.cpp) - -# We also need the .cpp files, which are generated as side effects of the -# above rules. Specifying this explicitly makes -j2 work. -$(patsubst %.h,%.cpp,$(GEN)): $(intermediates)/storage/%.cpp : $(intermediates)/storage/%.h - -# SVG -ifeq ($(ENABLE_SVG), true) -GEN := \ - $(intermediates)/svg/JSSVGAElement.h \ - $(intermediates)/svg/JSSVGAltGlyphElement.h \ - $(intermediates)/svg/JSSVGAngle.h \ - $(intermediates)/svg/JSSVGAnimateColorElement.h \ - $(intermediates)/svg/JSSVGAnimateElement.h \ - $(intermediates)/svg/JSSVGAnimateTransformElement.h \ - $(intermediates)/svg/JSSVGAnimatedAngle.h \ - $(intermediates)/svg/JSSVGAnimatedBoolean.h \ - $(intermediates)/svg/JSSVGAnimatedEnumeration.h \ - $(intermediates)/svg/JSSVGAnimatedInteger.h \ - $(intermediates)/svg/JSSVGAnimatedLength.h \ - $(intermediates)/svg/JSSVGAnimatedLengthList.h \ - $(intermediates)/svg/JSSVGAnimatedNumber.h \ - $(intermediates)/svg/JSSVGAnimatedNumberList.h \ - $(intermediates)/svg/JSSVGAnimatedPreserveAspectRatio.h \ - $(intermediates)/svg/JSSVGAnimatedRect.h \ - $(intermediates)/svg/JSSVGAnimatedString.h \ - $(intermediates)/svg/JSSVGAnimatedTransformList.h \ - $(intermediates)/svg/JSSVGAnimationElement.h \ - $(intermediates)/svg/JSSVGCircleElement.h \ - $(intermediates)/svg/JSSVGClipPathElement.h \ - $(intermediates)/svg/JSSVGColor.h \ - $(intermediates)/svg/JSSVGComponentTransferFunctionElement.h \ - $(intermediates)/svg/JSSVGCursorElement.h \ - $(intermediates)/svg/JSSVGDefsElement.h \ - $(intermediates)/svg/JSSVGDescElement.h \ - $(intermediates)/svg/JSSVGDocument.h \ - $(intermediates)/svg/JSSVGElement.h \ - $(intermediates)/svg/JSSVGElementInstance.h \ - $(intermediates)/svg/JSSVGElementInstanceList.h \ - $(intermediates)/svg/JSSVGEllipseElement.h \ - $(intermediates)/svg/JSSVGException.h \ - $(intermediates)/svg/JSSVGFEBlendElement.h \ - $(intermediates)/svg/JSSVGFEColorMatrixElement.h \ - $(intermediates)/svg/JSSVGFEComponentTransferElement.h \ - $(intermediates)/svg/JSSVGFECompositeElement.h \ - $(intermediates)/svg/JSSVGFEConvolveMatrixElement.h \ - $(intermediates)/svg/JSSVGFEDiffuseLightingElement.h \ - $(intermediates)/svg/JSSVGFEDisplacementMapElement.h \ - $(intermediates)/svg/JSSVGFEDistantLightElement.h \ - $(intermediates)/svg/JSSVGFEFloodElement.h \ - $(intermediates)/svg/JSSVGFEFuncAElement.h \ - $(intermediates)/svg/JSSVGFEFuncBElement.h \ - $(intermediates)/svg/JSSVGFEFuncGElement.h \ - $(intermediates)/svg/JSSVGFEFuncRElement.h \ - $(intermediates)/svg/JSSVGFEGaussianBlurElement.h \ - $(intermediates)/svg/JSSVGFEImageElement.h \ - $(intermediates)/svg/JSSVGFEMergeElement.h \ - $(intermediates)/svg/JSSVGFEMergeNodeElement.h \ - $(intermediates)/svg/JSSVGFEOffsetElement.h \ - $(intermediates)/svg/JSSVGFEPointLightElement.h \ - $(intermediates)/svg/JSSVGFESpecularLightingElement.h \ - $(intermediates)/svg/JSSVGFESpotLightElement.h \ - $(intermediates)/svg/JSSVGFETileElement.h \ - $(intermediates)/svg/JSSVGFETurbulenceElement.h \ - $(intermediates)/svg/JSSVGFilterElement.h \ - $(intermediates)/svg/JSSVGFontElement.h \ - $(intermediates)/svg/JSSVGFontFaceElement.h \ - $(intermediates)/svg/JSSVGFontFaceFormatElement.h \ - $(intermediates)/svg/JSSVGFontFaceNameElement.h \ - $(intermediates)/svg/JSSVGFontFaceSrcElement.h \ - $(intermediates)/svg/JSSVGFontFaceUriElement.h \ - $(intermediates)/svg/JSSVGForeignObjectElement.h \ - $(intermediates)/svg/JSSVGGElement.h \ - $(intermediates)/svg/JSSVGGlyphElement.h \ - $(intermediates)/svg/JSSVGGradientElement.h \ - $(intermediates)/svg/JSSVGHKernElement.h \ - $(intermediates)/svg/JSSVGImageElement.h \ - $(intermediates)/svg/JSSVGLength.h \ - $(intermediates)/svg/JSSVGLengthList.h \ - $(intermediates)/svg/JSSVGLineElement.h \ - $(intermediates)/svg/JSSVGLinearGradientElement.h \ - $(intermediates)/svg/JSSVGMarkerElement.h \ - $(intermediates)/svg/JSSVGMaskElement.h \ - $(intermediates)/svg/JSSVGMatrix.h \ - $(intermediates)/svg/JSSVGMetadataElement.h \ - $(intermediates)/svg/JSSVGMissingGlyphElement.h \ - $(intermediates)/svg/JSSVGNumber.h \ - $(intermediates)/svg/JSSVGNumberList.h \ - $(intermediates)/svg/JSSVGPaint.h \ - $(intermediates)/svg/JSSVGPathElement.h \ - $(intermediates)/svg/JSSVGPathSeg.h \ - $(intermediates)/svg/JSSVGPathSegArcAbs.h \ - $(intermediates)/svg/JSSVGPathSegArcRel.h \ - $(intermediates)/svg/JSSVGPathSegClosePath.h \ - $(intermediates)/svg/JSSVGPathSegCurvetoCubicAbs.h \ - $(intermediates)/svg/JSSVGPathSegCurvetoCubicRel.h \ - $(intermediates)/svg/JSSVGPathSegCurvetoCubicSmoothAbs.h \ - $(intermediates)/svg/JSSVGPathSegCurvetoCubicSmoothRel.h \ - $(intermediates)/svg/JSSVGPathSegCurvetoQuadraticAbs.h \ - $(intermediates)/svg/JSSVGPathSegCurvetoQuadraticRel.h \ - $(intermediates)/svg/JSSVGPathSegCurvetoQuadraticSmoothAbs.h \ - $(intermediates)/svg/JSSVGPathSegCurvetoQuadraticSmoothRel.h \ - $(intermediates)/svg/JSSVGPathSegLinetoAbs.h \ - $(intermediates)/svg/JSSVGPathSegLinetoHorizontalAbs.h \ - $(intermediates)/svg/JSSVGPathSegLinetoHorizontalRel.h \ - $(intermediates)/svg/JSSVGPathSegLinetoRel.h \ - $(intermediates)/svg/JSSVGPathSegLinetoVerticalAbs.h \ - $(intermediates)/svg/JSSVGPathSegLinetoVerticalRel.h \ - $(intermediates)/svg/JSSVGPathSegList.h \ - $(intermediates)/svg/JSSVGPathSegMovetoAbs.h \ - $(intermediates)/svg/JSSVGPathSegMovetoRel.h \ - $(intermediates)/svg/JSSVGPatternElement.h \ - $(intermediates)/svg/JSSVGPoint.h \ - $(intermediates)/svg/JSSVGPointList.h \ - $(intermediates)/svg/JSSVGPolygonElement.h \ - $(intermediates)/svg/JSSVGPolylineElement.h \ - $(intermediates)/svg/JSSVGPreserveAspectRatio.h \ - $(intermediates)/svg/JSSVGRadialGradientElement.h \ - $(intermediates)/svg/JSSVGRect.h \ - $(intermediates)/svg/JSSVGRectElement.h \ - $(intermediates)/svg/JSSVGRenderingIntent.h \ - $(intermediates)/svg/JSSVGSVGElement.h \ - $(intermediates)/svg/JSSVGScriptElement.h \ - $(intermediates)/svg/JSSVGSetElement.h \ - $(intermediates)/svg/JSSVGStopElement.h \ - $(intermediates)/svg/JSSVGStringList.h \ - $(intermediates)/svg/JSSVGStyleElement.h \ - $(intermediates)/svg/JSSVGSwitchElement.h \ - $(intermediates)/svg/JSSVGSymbolElement.h \ - $(intermediates)/svg/JSSVGTRefElement.h \ - $(intermediates)/svg/JSSVGTSpanElement.h \ - $(intermediates)/svg/JSSVGTextContentElement.h \ - $(intermediates)/svg/JSSVGTextElement.h \ - $(intermediates)/svg/JSSVGTextPathElement.h \ - $(intermediates)/svg/JSSVGTextPositioningElement.h \ - $(intermediates)/svg/JSSVGTitleElement.h \ - $(intermediates)/svg/JSSVGTransform.h \ - $(intermediates)/svg/JSSVGTransformList.h \ - $(intermediates)/svg/JSSVGUnitTypes.h \ - $(intermediates)/svg/JSSVGUseElement.h \ - $(intermediates)/svg/JSSVGViewElement.h \ - $(intermediates)/svg/JSSVGVKernElement.h \ - $(intermediates)/svg/JSSVGZoomEvent.h -$(GEN): PRIVATE_PATH := $(LOCAL_PATH) -$(GEN): PRIVATE_CUSTOM_TOOL = perl -I$(PRIVATE_PATH)/bindings/scripts $(PRIVATE_PATH)/bindings/scripts/generate-bindings.pl --defines "$(FEATURE_DEFINES) LANGUAGE_JAVASCRIPT" --generator JS --include external/webkit/Source/WebCore/dom --include external/webkit/Source/WebCore/html --include external/webkit/Source/WebCore/svg --outputdir $(dir $@) $< -$(GEN): $(intermediates)/svg/JS%.h : $(LOCAL_PATH)/svg/%.idl $(js_binding_scripts) - $(transform-generated-source) -LOCAL_GENERATED_SOURCES += $(GEN) $(GEN:%.h=%.cpp) - -# We also need the .cpp files, which are generated as side effects of the -# above rules. Specifying this explicitly makes -j2 work. -$(patsubst %.h,%.cpp,$(GEN)): $(intermediates)/svg/%.cpp : $(intermediates)/svg/%.h -endif - -# Workers -GEN := \ - $(intermediates)/workers/JSAbstractWorker.h \ - $(intermediates)/workers/JSDedicatedWorkerContext.h \ - $(intermediates)/workers/JSSharedWorker.h \ - $(intermediates)/workers/JSSharedWorkerContext.h \ - $(intermediates)/workers/JSWorker.h \ - $(intermediates)/workers/JSWorkerContext.h \ - $(intermediates)/workers/JSWorkerLocation.h - -$(GEN): PRIVATE_PATH := $(LOCAL_PATH) -$(GEN): PRIVATE_CUSTOM_TOOL = perl -I$(PRIVATE_PATH)/bindings/scripts $(PRIVATE_PATH)/bindings/scripts/generate-bindings.pl --defines "$(FEATURE_DEFINES) LANGUAGE_JAVASCRIPT" --generator JS --include dom --include html --outputdir $(dir $@) $< -$(GEN): $(intermediates)/workers/JS%.h : $(LOCAL_PATH)/workers/%.idl $(js_binding_scripts) - $(transform-generated-source) -LOCAL_GENERATED_SOURCES += $(GEN) $(GEN:%.h=%.cpp) - -# We also need the .cpp files, which are generated as side effects of the -# above rules. Specifying this explicitly makes -j2 work. -$(patsubst %.h,%.cpp,$(GEN)): $(intermediates)/workers/%.cpp : $(intermediates)/workers/%.h - -# XML -GEN := \ - $(intermediates)/xml/JSDOMParser.h \ - $(intermediates)/xml/JSXMLHttpRequest.h \ - $(intermediates)/xml/JSXMLHttpRequestException.h \ - $(intermediates)/xml/JSXMLHttpRequestProgressEvent.h \ - $(intermediates)/xml/JSXMLHttpRequestUpload.h \ - $(intermediates)/xml/JSXMLSerializer.h \ - $(intermediates)/xml/JSXPathException.h \ - $(intermediates)/xml/JSXPathExpression.h \ - $(intermediates)/xml/JSXPathEvaluator.h \ - $(intermediates)/xml/JSXPathNSResolver.h \ - $(intermediates)/xml/JSXPathResult.h \ - $(intermediates)/xml/JSXSLTProcessor.h -$(GEN): PRIVATE_PATH := $(LOCAL_PATH) -$(GEN): PRIVATE_CUSTOM_TOOL = perl -I$(PRIVATE_PATH)/bindings/scripts $(PRIVATE_PATH)/bindings/scripts/generate-bindings.pl --defines "$(FEATURE_DEFINES) LANGUAGE_JAVASCRIPT" --generator JS --include dom --include html --outputdir $(dir $@) $< -$(GEN): $(intermediates)/xml/JS%.h : $(LOCAL_PATH)/xml/%.idl $(js_binding_scripts) - $(transform-generated-source) -LOCAL_GENERATED_SOURCES += $(GEN) $(GEN:%.h=%.cpp) - -# We also need the .cpp files, which are generated as side effects of the -# above rules. Specifying this explicitly makes -j2 work. -$(patsubst %.h,%.cpp,$(GEN)): $(intermediates)/xml/%.cpp : $(intermediates)/xml/%.h -#end - -# Inspector -# These headers are required even when Inspector is disabled. -# Note that Inspector.idl should not be processed using the JS generator. -GEN := \ - $(intermediates)/inspector/JSScriptProfile.h - -$(GEN): PRIVATE_PATH := $(LOCAL_PATH) -$(GEN): PRIVATE_CUSTOM_TOOL = perl -I$(PRIVATE_PATH)/bindings/scripts $(PRIVATE_PATH)/bindings/scripts/generate-bindings.pl --defines "$(FEATURE_DEFINES) LANGUAGE_JAVASCRIPT" --generator JS --include dom --include html --outputdir $(dir $@) $< -$(GEN): $(intermediates)/inspector/JS%.h : $(LOCAL_PATH)/inspector/%.idl $(js_binding_scripts) - $(transform-generated-source) -LOCAL_GENERATED_SOURCES += $(GEN) $(GEN:%.h=%.cpp) - -# We also need the .cpp files, which are generated as side effects of the -# above rules. Specifying this explicitly makes -j2 work. -$(patsubst %.h,%.cpp,$(GEN)): $(intermediates)/inspector/%.cpp : $(intermediates)/inspector/%.h - -# WebAudio -# These headers are required even when WebAudio is disabled -GEN := \ - $(intermediates)/webaudio/JSAudioContext.h \ - $(intermediates)/webaudio/JSAudioPannerNode.h - -$(GEN): PRIVATE_PATH := $(LOCAL_PATH) -$(GEN): PRIVATE_CUSTOM_TOOL = perl -I$(PRIVATE_PATH)/bindings/scripts $(PRIVATE_PATH)/bindings/scripts/generate-bindings.pl --defines "$(FEATURE_DEFINES) LANGUAGE_JAVASCRIPT" --generator JS --include dom --include html --outputdir $(dir $@) $< -$(GEN): $(intermediates)/webaudio/JS%.h : $(LOCAL_PATH)/webaudio/%.idl $(js_binding_scripts) - $(transform-generated-source) -LOCAL_GENERATED_SOURCES += $(GEN) $(GEN:%.h=%.cpp) - -# We also need the .cpp files, which are generated as side effects of the -# above rules. Specifying this explicitly makes -j2 work. -$(patsubst %.h,%.cpp,$(GEN)): $(intermediates)/webaudio/%.cpp : $(intermediates)/webaudio/%.h - -# HTML tag and attribute names - -GEN:= $(intermediates)/HTMLNames.cpp $(intermediates)/HTMLNames.h $(intermediates)/HTMLElementFactory.cpp $(intermediates)/HTMLElementFactory.h $(intermediates)/JSHTMLElementWrapperFactory.cpp $(intermediates)/JSHTMLElementWrapperFactory.h -$(GEN): PRIVATE_PATH := $(LOCAL_PATH) -$(GEN): PRIVATE_CUSTOM_TOOL = perl -I $(PRIVATE_PATH)/bindings/scripts $< --tags $(PRIVATE_PATH)/html/HTMLTagNames.in --attrs $(PRIVATE_PATH)/html/HTMLAttributeNames.in --extraDefines "$(FEATURE_DEFINES)" --factory --wrapperFactory --output $(dir $@) -$(GEN): $(LOCAL_PATH)/dom/make_names.pl $(LOCAL_PATH)/html/HTMLTagNames.in $(LOCAL_PATH)/html/HTMLAttributeNames.in - $(transform-generated-source) -LOCAL_GENERATED_SOURCES += $(GEN) - -# SVG tag and attribute names - -# Note that if SVG is not used, we still need the headers and SVGNames.cpp as -# the HTML5 parser still requires these. The factory .cpp files are also -# generated in this case, but since these are not needed, they are excluded -# from GEN so that they don't get compiled. -ifeq ($(ENABLE_SVG), true) -GEN:= $(intermediates)/SVGNames.cpp $(intermediates)/SVGNames.h $(intermediates)/SVGElementFactory.cpp $(intermediates)/SVGElementFactory.h $(intermediates)/JSSVGElementWrapperFactory.cpp $(intermediates)/JSSVGElementWrapperFactory.h -else -GEN:= $(intermediates)/SVGNames.h $(intermediates)/SVGNames.cpp $(intermediates)/SVGElementFactory.h $(intermediates)/JSSVGElementWrapperFactory.h -endif -SVG_FLAGS:=ENABLE_SVG_ANIMATION=1 ENABLE_SVG_AS_IMAGE=1 ENABLE_SVG_FILTERS=1 ENABLE_SVG_FONTS=1 ENABLE_SVG_FOREIGN_OBJECT=1 ENABLE_SVG_USE=1 -$(GEN): PRIVATE_PATH := $(LOCAL_PATH) -$(GEN): PRIVATE_CUSTOM_TOOL = perl -I $(PRIVATE_PATH)/bindings/scripts $< --tags $(PRIVATE_PATH)/svg/svgtags.in --attrs $(PRIVATE_PATH)/svg/svgattrs.in --extraDefines "$(SVG_FLAGS)" --factory --wrapperFactory --output $(dir $@) -$(GEN): $(LOCAL_PATH)/dom/make_names.pl $(LOCAL_PATH)/svg/svgtags.in $(LOCAL_PATH)/svg/svgattrs.in - $(transform-generated-source) -LOCAL_GENERATED_SOURCES += $(GEN) - -# MathML tag and attribute names - -# Note that MathML is never used but we still need the headers and -# MathMLames.cpp as the HTML5 parser still requires these. The factory -# .cpp files are also generated in this case, but since these are not -# needed, they are excluded from GEN so that they don't get compiled. -GEN:= $(intermediates)/MathMLNames.h $(intermediates)/MathMLNames.cpp $(intermediates)/MathMLElementFactory.h $(intermediates)/JSMathMLElementWrapperFactory.h -$(GEN): PRIVATE_PATH := $(LOCAL_PATH) -$(GEN): PRIVATE_CUSTOM_TOOL = perl -I $(PRIVATE_PATH)/bindings/scripts $< --tags $(PRIVATE_PATH)/mathml/mathtags.in --attrs $(PRIVATE_PATH)/mathml/mathattrs.in --factory --wrapperFactory --output $(dir $@) -$(GEN): $(LOCAL_PATH)/dom/make_names.pl $(LOCAL_PATH)/mathml/mathtags.in $(LOCAL_PATH)/mathml/mathattrs.in - $(transform-generated-source) -LOCAL_GENERATED_SOURCES += $(GEN) - diff --git a/Source/WebCore/Android.derived.v8bindings.mk b/Source/WebCore/Android.derived.v8bindings.mk index 992cc40..546cefe 100644 --- a/Source/WebCore/Android.derived.v8bindings.mk +++ b/Source/WebCore/Android.derived.v8bindings.mk @@ -301,6 +301,7 @@ GEN := \ $(intermediates)/bindings/V8CanvasRenderingContext2D.h \ $(intermediates)/bindings/V8DataView.h \ $(intermediates)/bindings/V8Float32Array.h \ + $(intermediates)/bindings/V8Float64Array.h \ $(intermediates)/bindings/V8Int8Array.h \ $(intermediates)/bindings/V8Int16Array.h \ $(intermediates)/bindings/V8Int32Array.h \ diff --git a/Source/WebCore/Android.jscbindings.mk b/Source/WebCore/Android.jscbindings.mk deleted file mode 100644 index bdd6d92..0000000 --- a/Source/WebCore/Android.jscbindings.mk +++ /dev/null @@ -1,240 +0,0 @@ -## -## Copyright 2009, The Android Open Source Project -## -## Redistribution and use in source and binary forms, with or without -## modification, are permitted provided that the following conditions -## are met: -## * Redistributions of source code must retain the above copyright -## notice, this list of conditions and the following disclaimer. -## * Redistributions in binary form must reproduce the above copyright -## notice, this list of conditions and the following disclaimer in the -## documentation and/or other materials provided with the distribution. -## -## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY -## EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -## IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -## CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -## EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -## PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -## PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY -## OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -## - -BINDING_C_INCLUDES := \ - $(LOCAL_PATH)/bindings/js \ - $(LOCAL_PATH)/bindings/js/specialization \ - $(LOCAL_PATH)/bridge \ - $(LOCAL_PATH)/bridge/c \ - $(LOCAL_PATH)/bridge/jni \ - $(LOCAL_PATH)/bridge/jni/jsc \ - $(LOCAL_PATH)/bridge/jsc \ - \ - $(JAVASCRIPTCORE_PATH)/API \ - $(JAVASCRIPTCORE_PATH)/assembler \ - $(JAVASCRIPTCORE_PATH)/bytecode \ - $(JAVASCRIPTCORE_PATH)/bytecompiler \ - $(JAVASCRIPTCORE_PATH)/debugger \ - $(JAVASCRIPTCORE_PATH)/parser \ - $(JAVASCRIPTCORE_PATH)/jit \ - $(JAVASCRIPTCORE_PATH)/interpreter \ - $(JAVASCRIPTCORE_PATH)/profiler \ - $(JAVASCRIPTCORE_PATH)/runtime \ - $(JAVASCRIPTCORE_PATH)/yarr \ - $(JAVASCRIPTCORE_PATH)/ForwardingHeaders \ - \ - $(WEBCORE_INTERMEDIATES_PATH)/bindings/js \ - $(WEBCORE_INTERMEDIATES_PATH)/dom \ - $(WEBCORE_INTERMEDIATES_PATH)/fileapi \ - $(WEBCORE_INTERMEDIATES_PATH)/html/canvas \ - $(WEBCORE_INTERMEDIATES_PATH)/inspector \ - $(WEBCORE_INTERMEDIATES_PATH)/loader/appcache \ - $(WEBCORE_INTERMEDIATES_PATH)/page \ - $(WEBCORE_INTERMEDIATES_PATH)/plugins \ - $(WEBCORE_INTERMEDIATES_PATH)/storage \ - $(WEBCORE_INTERMEDIATES_PATH)/svg \ - $(WEBCORE_INTERMEDIATES_PATH)/webaudio \ - $(WEBCORE_INTERMEDIATES_PATH)/workers \ - $(WEBCORE_INTERMEDIATES_PATH)/xml - -LOCAL_SRC_FILES += \ - bindings/js/CallbackFunction.cpp \ - bindings/js/DOMObjectHashTableMap.cpp \ - bindings/js/DOMWrapperWorld.cpp \ - bindings/js/GCController.cpp \ - bindings/js/IDBBindingUtilities.cpp \ - bindings/js/JSArrayBufferCustom.cpp \ - bindings/js/JSAttrCustom.cpp \ - bindings/js/JSAudioBufferSourceNodeCustom.cpp \ - bindings/js/JSAudioConstructor.cpp \ - bindings/js/JSCDATASectionCustom.cpp \ - bindings/js/JSCSSFontFaceRuleCustom.cpp \ - bindings/js/JSCSSImportRuleCustom.cpp \ - bindings/js/JSCSSMediaRuleCustom.cpp \ - bindings/js/JSCSSPageRuleCustom.cpp \ - bindings/js/JSCSSRuleCustom.cpp \ - bindings/js/JSCSSRuleListCustom.cpp \ - bindings/js/JSCSSStyleDeclarationCustom.cpp \ - bindings/js/JSCSSStyleRuleCustom.cpp \ - bindings/js/JSCSSValueCustom.cpp \ - bindings/js/JSCallbackData.cpp \ - bindings/js/JSCanvasRenderingContext2DCustom.cpp \ - bindings/js/JSCanvasRenderingContextCustom.cpp \ - bindings/js/JSClipboardCustom.cpp \ - bindings/js/JSConsoleCustom.cpp \ - bindings/js/JSConvolverNodeCustom.cpp \ - bindings/js/JSCoordinatesCustom.cpp \ - bindings/js/JSCustomApplicationInstalledCallback.cpp \ - bindings/js/JSCustomPositionCallback.cpp \ - bindings/js/JSCustomPositionErrorCallback.cpp \ - bindings/js/JSCustomSQLStatementErrorCallback.cpp \ - bindings/js/JSCustomVoidCallback.cpp \ - bindings/js/JSDOMApplicationCacheCustom.cpp \ - bindings/js/JSDOMBinding.cpp \ - bindings/js/JSDOMFormDataCustom.cpp \ - bindings/js/JSDOMGlobalObject.cpp \ - bindings/js/JSDOMImplementationCustom.cpp \ - bindings/js/JSDOMMimeTypeArrayCustom.cpp \ - bindings/js/JSDOMPluginArrayCustom.cpp \ - bindings/js/JSDOMPluginCustom.cpp \ - bindings/js/JSDOMStringMapCustom.cpp \ - bindings/js/JSDOMWindowBase.cpp \ - bindings/js/JSDOMWindowCustom.cpp \ - bindings/js/JSDOMWindowShell.cpp \ - bindings/js/JSDOMWrapper.cpp \ - bindings/js/JSDataGridColumnListCustom.cpp \ - bindings/js/JSDataGridDataSource.cpp \ - bindings/js/JSDataViewCustom.cpp \ - bindings/js/JSDedicatedWorkerContextCustom.cpp \ - bindings/js/JSDesktopNotificationsCustom.cpp \ - bindings/js/JSDeviceMotionEventCustom.cpp \ - bindings/js/JSDeviceOrientationEventCustom.cpp \ - bindings/js/JSDirectoryEntrySyncCustom.cpp \ - bindings/js/JSDocumentCustom.cpp \ - bindings/js/JSElementCustom.cpp \ - bindings/js/JSEntrySyncCustom.cpp \ - bindings/js/JSErrorHandler.cpp \ - bindings/js/JSEventCustom.cpp \ - bindings/js/JSEventListener.cpp \ - bindings/js/JSEventTarget.cpp \ - bindings/js/JSExceptionBase.cpp \ - bindings/js/JSFloat32ArrayCustom.cpp \ - bindings/js/JSFileReaderCustom.cpp \ - bindings/js/JSGeolocationCustom.cpp \ - bindings/js/JSHTMLAllCollectionCustom.cpp \ - bindings/js/JSHTMLAppletElementCustom.cpp \ - bindings/js/JSHTMLCanvasElementCustom.cpp \ - bindings/js/JSHTMLCollectionCustom.cpp \ - bindings/js/JSHTMLDataGridElementCustom.cpp \ - bindings/js/JSHTMLDocumentCustom.cpp \ - bindings/js/JSHTMLElementCustom.cpp \ - bindings/js/JSHTMLEmbedElementCustom.cpp \ - bindings/js/JSHTMLFormElementCustom.cpp \ - bindings/js/JSHTMLFrameElementCustom.cpp \ - bindings/js/JSHTMLFrameSetElementCustom.cpp \ - bindings/js/JSHTMLInputElementCustom.cpp \ - bindings/js/JSHTMLLinkElementCustom.cpp \ - bindings/js/JSHTMLObjectElementCustom.cpp \ - bindings/js/JSHTMLOptionsCollectionCustom.cpp \ - bindings/js/JSHTMLOutputElementCustom.cpp \ - bindings/js/JSHTMLSelectElementCustom.cpp \ - bindings/js/JSHTMLStyleElementCustom.cpp \ - bindings/js/JSHistoryCustom.cpp \ - bindings/js/JSIDBAnyCustom.cpp \ - bindings/js/JSIDBKeyCustom.cpp \ - bindings/js/JSImageConstructor.cpp \ - bindings/js/JSImageDataCustom.cpp \ - bindings/js/JSInt16ArrayCustom.cpp \ - bindings/js/JSInt32ArrayCustom.cpp \ - bindings/js/JSInt8ArrayCustom.cpp \ - bindings/js/JSJavaScriptAudioNodeCustom.cpp \ - bindings/js/JSLazyEventListener.cpp \ - bindings/js/JSLocationCustom.cpp \ - bindings/js/JSMainThreadExecState.cpp \ - bindings/js/JSMemoryInfoCustom.cpp \ - bindings/js/JSMessageChannelCustom.cpp \ - bindings/js/JSMessageEventCustom.cpp \ - bindings/js/JSMessagePortCustom.cpp \ - bindings/js/JSNamedNodeMapCustom.cpp \ - bindings/js/JSNavigatorCustom.cpp \ - bindings/js/JSNodeCustom.cpp \ - bindings/js/JSNodeFilterCondition.cpp \ - bindings/js/JSNodeFilterCustom.cpp \ - bindings/js/JSNodeIteratorCustom.cpp \ - bindings/js/JSNodeListCustom.cpp \ - bindings/js/JSOptionConstructor.cpp \ - bindings/js/JSPluginElementFunctions.cpp \ - bindings/js/JSProcessingInstructionCustom.cpp \ - bindings/js/JSSQLResultSetRowListCustom.cpp \ - bindings/js/JSSQLTransactionCustom.cpp \ - bindings/js/JSSQLTransactionSyncCustom.cpp \ - bindings/js/JSSVGElementInstanceCustom.cpp \ - bindings/js/JSSVGLengthCustom.cpp \ - bindings/js/JSSVGPathSegCustom.cpp \ - bindings/js/JSSharedWorkerCustom.cpp \ - bindings/js/JSStorageCustom.cpp \ - bindings/js/JSStyleSheetCustom.cpp \ - bindings/js/JSStyleSheetListCustom.cpp \ - bindings/js/JSTextCustom.cpp \ - bindings/js/JSTouchCustom.cpp \ - bindings/js/JSTouchListCustom.cpp \ - bindings/js/JSTreeWalkerCustom.cpp \ - bindings/js/JSUint16ArrayCustom.cpp \ - bindings/js/JSUint32ArrayCustom.cpp \ - bindings/js/JSUint8ArrayCustom.cpp \ - bindings/js/JSWebKitAnimationCustom.cpp \ - bindings/js/JSWebKitAnimationListCustom.cpp \ - bindings/js/JSWebKitCSSKeyframeRuleCustom.cpp \ - bindings/js/JSWebKitCSSKeyframesRuleCustom.cpp \ - bindings/js/JSWebKitCSSMatrixCustom.cpp \ - bindings/js/JSWebKitPointCustom.cpp \ - bindings/js/JSWorkerContextBase.cpp \ - bindings/js/JSWorkerContextCustom.cpp \ - bindings/js/JSWorkerCustom.cpp \ - bindings/js/JSXMLHttpRequestCustom.cpp \ - bindings/js/JSXMLHttpRequestUploadCustom.cpp \ - bindings/js/JSXSLTProcessorCustom.cpp \ - bindings/js/ScheduledAction.cpp \ - bindings/js/ScriptCachedFrameData.cpp \ - bindings/js/ScriptCallStackFactory.cpp \ - bindings/js/ScriptController.cpp \ - bindings/js/ScriptControllerAndroid.cpp \ - bindings/js/ScriptEventListener.cpp \ - bindings/js/ScriptFunctionCall.cpp \ - bindings/js/ScriptObject.cpp \ - bindings/js/ScriptProfile.cpp \ - bindings/js/ScriptState.cpp \ - bindings/js/ScriptValue.cpp \ - bindings/js/SerializedScriptValue.cpp \ - bindings/js/WorkerScriptController.cpp \ - \ - bindings/ScriptControllerBase.cpp \ - \ - bridge/IdentifierRep.cpp \ - bridge/NP_jsobject.cpp \ - bridge/c/CRuntimeObject.cpp \ - bridge/c/c_class.cpp \ - bridge/c/c_instance.cpp \ - bridge/c/c_runtime.cpp \ - bridge/c/c_utility.cpp \ - bridge/jni/JNIUtility.cpp \ - bridge/jni/JavaMethodJobject.cpp \ - bridge/jni/JobjectWrapper.cpp \ - bridge/jni/jsc/JNIUtilityPrivate.cpp \ - bridge/jni/jsc/JavaArrayJSC.cpp \ - bridge/jni/jsc/JavaClassJSC.cpp \ - bridge/jni/jsc/JavaFieldJSC.cpp \ - bridge/jni/jsc/JavaInstanceJSC.cpp \ - bridge/jni/jsc/JavaRuntimeObject.cpp \ - bridge/jsc/BridgeJSC.cpp \ - bridge/npruntime.cpp \ - bridge/runtime_array.cpp \ - bridge/runtime_method.cpp \ - bridge/runtime_object.cpp \ - bridge/runtime_root.cpp - -# For XPath. -LOCAL_SRC_FILES += \ - bindings/js/JSCustomXPathNSResolver.cpp diff --git a/Source/WebCore/Android.mk b/Source/WebCore/Android.mk index 6542931..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 \ @@ -378,6 +379,7 @@ LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \ html/canvas/CanvasStyle.cpp \ html/canvas/DataView.cpp \ html/canvas/Float32Array.cpp \ + html/canvas/Float64Array.cpp \ html/canvas/Int16Array.cpp \ html/canvas/Int32Array.cpp \ html/canvas/Int8Array.cpp \ @@ -638,7 +640,6 @@ LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \ platform/graphics/android/BaseTileTexture.cpp \ platform/graphics/android/BitmapAllocatorAndroid.cpp \ platform/graphics/android/ClassTracker.cpp \ - platform/graphics/android/DoubleBufferedTexture.cpp \ platform/graphics/android/FontAndroid.cpp \ platform/graphics/android/FontCacheAndroid.cpp \ platform/graphics/android/FontCustomPlatformData.cpp \ @@ -658,6 +659,7 @@ LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \ platform/graphics/android/ImageSourceAndroid.cpp \ platform/graphics/android/ImagesManager.cpp \ platform/graphics/android/ImageTexture.cpp \ + platform/graphics/android/InspectorCanvas.cpp \ platform/graphics/android/Layer.cpp \ platform/graphics/android/LayerAndroid.cpp \ platform/graphics/android/MediaLayer.cpp \ @@ -672,7 +674,6 @@ LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \ platform/graphics/android/ScrollableLayerAndroid.cpp \ platform/graphics/android/SharedBufferStream.cpp \ platform/graphics/android/ShaderProgram.cpp \ - platform/graphics/android/SharedTexture.cpp \ platform/graphics/android/TextureInfo.cpp \ platform/graphics/android/TexturesGenerator.cpp \ platform/graphics/android/TilesManager.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) \ @@ -811,6 +811,7 @@ LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \ plugins/DOMPluginArray.cpp \ plugins/PluginData.cpp \ plugins/PluginDatabase.cpp \ + plugins/PluginDebug.cpp \ plugins/PluginMainThreadScheduler.cpp \ plugins/PluginPackage.cpp \ plugins/PluginStream.cpp \ diff --git a/Source/WebCore/Android.v8bindings.mk b/Source/WebCore/Android.v8bindings.mk index 283a212..7858ef3 100644 --- a/Source/WebCore/Android.v8bindings.mk +++ b/Source/WebCore/Android.v8bindings.mk @@ -130,6 +130,7 @@ LOCAL_SRC_FILES += \ bindings/v8/custom/V8EventSourceConstructor.cpp \ bindings/v8/custom/V8FileReaderCustom.cpp \ bindings/v8/custom/V8Float32ArrayCustom.cpp \ + bindings/v8/custom/V8Float64ArrayCustom.cpp \ bindings/v8/custom/V8GeolocationCustom.cpp \ bindings/v8/custom/V8HistoryCustom.cpp \ bindings/v8/custom/V8HTMLAllCollectionCustom.cpp \ diff --git a/Source/WebCore/DerivedSources.cpp b/Source/WebCore/DerivedSources.cpp index 3bba78c..45a425c 100644 --- a/Source/WebCore/DerivedSources.cpp +++ b/Source/WebCore/DerivedSources.cpp @@ -130,6 +130,7 @@ #include "JSFileWriterSync.cpp" #include "JSWebKitFlags.cpp" #include "JSFloat32Array.cpp" +#include "JSFloat64Array.cpp" #include "JSGeolocation.cpp" #include "JSGeoposition.cpp" #include "JSHashChangeEvent.cpp" diff --git a/Source/WebCore/bindings/js/JSBindingsAllInOne.cpp b/Source/WebCore/bindings/js/JSBindingsAllInOne.cpp index a457ce8..82367b2 100644 --- a/Source/WebCore/bindings/js/JSBindingsAllInOne.cpp +++ b/Source/WebCore/bindings/js/JSBindingsAllInOne.cpp @@ -81,6 +81,7 @@ #include "JSEventTarget.cpp" #include "JSExceptionBase.cpp" #include "JSFloat32ArrayCustom.cpp" +#include "JSFloat64ArrayCustom.cpp" #include "JSGeolocationCustom.cpp" #include "JSHTMLAllCollectionCustom.cpp" #include "JSHTMLAppletElementCustom.cpp" diff --git a/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp b/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp index 4bde9e5..938be96 100644 --- a/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp +++ b/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp @@ -31,6 +31,7 @@ #include "JSEventListener.h" #include "JSEventSource.h" #include "JSFloat32Array.h" +#include "JSFloat64Array.h" #include "JSHTMLCollection.h" #include "JSHistory.h" #include "JSImageConstructor.h" @@ -569,6 +570,11 @@ JSValue JSDOMWindow::float32Array(ExecState* exec) const return getDOMConstructor<JSFloat32ArrayConstructor>(exec, this); } +JSValue JSDOMWindow::float64Array(ExecState* exec) const +{ + return getDOMConstructor<JSFloat64ArrayConstructor>(exec, this); +} + JSValue JSDOMWindow::dataView(ExecState* exec) const { return getDOMConstructor<JSDataViewConstructor>(exec, this); diff --git a/Source/WebCore/bindings/js/JSFloat64ArrayCustom.cpp b/Source/WebCore/bindings/js/JSFloat64ArrayCustom.cpp new file mode 100644 index 0000000..446b0ec --- /dev/null +++ b/Source/WebCore/bindings/js/JSFloat64ArrayCustom.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2011 Apple 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 COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "JSFloat64Array.h" + +#include "Float64Array.h" +#include "JSArrayBufferViewHelper.h" + +using namespace JSC; + +namespace WebCore { + +void JSFloat64Array::indexSetter(JSC::ExecState* exec, unsigned index, JSC::JSValue value) +{ + impl()->set(index, value.toNumber(exec)); +} + +JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, Float64Array* object) +{ + return toJSArrayBufferView<JSFloat64Array>(exec, globalObject, object); +} + +JSC::JSValue JSFloat64Array::set(JSC::ExecState* exec) +{ + return setWebGLArrayHelper(exec, impl(), toFloat64Array); +} + +EncodedJSValue JSC_HOST_CALL JSFloat64ArrayConstructor::constructJSFloat64Array(ExecState* exec) +{ + JSFloat64ArrayConstructor* jsConstructor = static_cast<JSFloat64ArrayConstructor*>(exec->callee()); + RefPtr<Float64Array> array = constructArrayBufferView<Float64Array, double>(exec); + if (!array.get()) + // Exception has already been thrown. + return JSValue::encode(JSValue()); + return JSValue::encode(asObject(toJS(exec, jsConstructor->globalObject(), array.get()))); +} + +} // namespace WebCore diff --git a/Source/WebCore/bindings/v8/V8DOMWindowShell.cpp b/Source/WebCore/bindings/v8/V8DOMWindowShell.cpp index e025008..c3a0cbb 100644 --- a/Source/WebCore/bindings/v8/V8DOMWindowShell.cpp +++ b/Source/WebCore/bindings/v8/V8DOMWindowShell.cpp @@ -76,10 +76,6 @@ #include <wtf/UnusedParam.h> #include <wtf/text/CString.h> -#ifdef ANDROID_INSTRUMENT -#include "TimeCounter.h" -#endif - namespace WebCore { static void handleFatalErrorInV8() @@ -283,10 +279,6 @@ bool V8DOMWindowShell::initContextIfNeeded() if (!m_context.IsEmpty()) return false; -#ifdef ANDROID_INSTRUMENT - android::TimeCounter::start(android::TimeCounter::JavaScriptInitTimeCounter); -#endif - // Create a handle scope for all local handles. v8::HandleScope handleScope; @@ -352,10 +344,6 @@ bool V8DOMWindowShell::initContextIfNeeded() // we do isolated worlds the WebCore way. m_frame->loader()->dispatchDidClearWindowObjectInWorld(0); -#ifdef ANDROID_INSTRUMENT - android::TimeCounter::record(android::TimeCounter::JavaScriptInitTimeCounter, __FUNCTION__); -#endif - return true; } diff --git a/Source/WebCore/bindings/v8/V8Proxy.cpp b/Source/WebCore/bindings/v8/V8Proxy.cpp index ca57fa8..d90cf1c 100644 --- a/Source/WebCore/bindings/v8/V8Proxy.cpp +++ b/Source/WebCore/bindings/v8/V8Proxy.cpp @@ -83,14 +83,6 @@ #include <wtf/UnusedParam.h> #include <wtf/text/StringConcatenate.h> -#ifdef ANDROID_INSTRUMENT -#include "TimeCounter.h" -#endif - -#if PLATFORM(ANDROID) -#include <wtf/text/CString.h> -#endif - namespace WebCore { // Static list of registered extensions @@ -209,16 +201,6 @@ V8Proxy::~V8Proxy() } v8::Handle<v8::Script> V8Proxy::compileScript(v8::Handle<v8::String> code, const String& fileName, const TextPosition0& scriptStartPosition, v8::ScriptData* scriptData) -#ifdef ANDROID_INSTRUMENT -{ - android::TimeCounter::start(android::TimeCounter::JavaScriptParseTimeCounter); - v8::Handle<v8::Script> script = compileScriptInternal(code, fileName, scriptStartPosition, scriptData); - android::TimeCounter::record(android::TimeCounter::JavaScriptParseTimeCounter, __FUNCTION__); - return script; -} - -v8::Handle<v8::Script> V8Proxy::compileScriptInternal(v8::Handle<v8::String> code, const String& fileName, const TextPosition0& scriptStartPosition, v8::ScriptData* scriptData) -#endif { const uint16_t* fileNameString = fromWebCoreString(fileName); v8::Handle<v8::String> name = v8::String::New(fileNameString, fileName.length()); @@ -398,16 +380,6 @@ v8::Local<v8::Value> V8Proxy::evaluate(const ScriptSourceCode& source, Node* nod } v8::Local<v8::Value> V8Proxy::runScript(v8::Handle<v8::Script> script, bool isInlineCode) -#ifdef ANDROID_INSTRUMENT -{ - android::TimeCounter::start(android::TimeCounter::JavaScriptExecuteTimeCounter); - v8::Local<v8::Value> result = runScriptInternal(script, isInlineCode); - android::TimeCounter::record(android::TimeCounter::JavaScriptExecuteTimeCounter, __FUNCTION__); - return result; -} - -v8::Local<v8::Value> V8Proxy::runScriptInternal(v8::Handle<v8::Script> script, bool isInlineCode) -#endif { if (script.IsEmpty()) return notHandledByInterceptor(); @@ -472,9 +444,6 @@ v8::Local<v8::Value> V8Proxy::runScriptInternal(v8::Handle<v8::Script> script, b v8::Local<v8::Value> V8Proxy::callFunction(v8::Handle<v8::Function> function, v8::Handle<v8::Object> receiver, int argc, v8::Handle<v8::Value> args[]) { -#ifdef ANDROID_INSTRUMENT - android::TimeCounter::start(android::TimeCounter::JavaScriptExecuteTimeCounter); -#endif V8GCController::checkMemoryUsage(); v8::Local<v8::Value> result; { @@ -521,9 +490,6 @@ v8::Local<v8::Value> V8Proxy::callFunction(v8::Handle<v8::Function> function, v8 if (v8::V8::IsDead()) handleFatalErrorInV8(); -#ifdef ANDROID_INSTRUMENT - android::TimeCounter::record(android::TimeCounter::JavaScriptExecuteTimeCounter, __FUNCTION__); -#endif return result; } diff --git a/Source/WebCore/bindings/v8/V8Proxy.h b/Source/WebCore/bindings/v8/V8Proxy.h index fc52b19..777815b 100644 --- a/Source/WebCore/bindings/v8/V8Proxy.h +++ b/Source/WebCore/bindings/v8/V8Proxy.h @@ -171,10 +171,6 @@ namespace WebCore { // Run an already compiled script. v8::Local<v8::Value> runScript(v8::Handle<v8::Script>, bool isInlineCode); -#ifdef ANDROID_INSTRUMENT - v8::Local<v8::Value> runScriptInternal(v8::Handle<v8::Script> script, bool inline_code); -#endif - // Call the function with the given receiver and arguments. v8::Local<v8::Value> callFunction(v8::Handle<v8::Function>, v8::Handle<v8::Object>, int argc, v8::Handle<v8::Value> argv[]); @@ -244,10 +240,6 @@ namespace WebCore { static v8::Handle<v8::Script> compileScript(v8::Handle<v8::String> code, const String& fileName, const TextPosition0& scriptStartPosition, v8::ScriptData* = 0); -#ifdef ANDROID_INSTRUMENT - static v8::Handle<v8::Script> compileScriptInternal(v8::Handle<v8::String> code, const String& fileName, int baseLine, v8::ScriptData* scriptData); -#endif - // If the exception code is different from zero, a DOM exception is // schedule to be thrown. static void setDOMException(int exceptionCode); diff --git a/Source/WebCore/bindings/v8/custom/V8Float64ArrayCustom.cpp b/Source/WebCore/bindings/v8/custom/V8Float64ArrayCustom.cpp new file mode 100644 index 0000000..429e962 --- /dev/null +++ b/Source/WebCore/bindings/v8/custom/V8Float64ArrayCustom.cpp @@ -0,0 +1,61 @@ +/* + * 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 COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "Float64Array.h" + +#include "ArrayBuffer.h" +#include "V8ArrayBuffer.h" +#include "V8ArrayBufferViewCustom.h" +#include "V8Binding.h" +#include "V8Float64Array.h" +#include "V8Proxy.h" + +namespace WebCore { + +v8::Handle<v8::Value> V8Float64Array::constructorCallback(const v8::Arguments& args) +{ + INC_STATS("DOM.Float64Array.Contructor"); + + return constructWebGLArray<Float64Array, double>(args, &info, v8::kExternalDoubleArray); +} + +v8::Handle<v8::Value> V8Float64Array::setCallback(const v8::Arguments& args) +{ + INC_STATS("DOM.Float64Array.set()"); + return setWebGLArrayHelper<Float64Array, V8Float64Array>(args); +} + +v8::Handle<v8::Value> toV8(Float64Array* impl) +{ + if (!impl) + return v8::Null(); + v8::Handle<v8::Object> wrapper = V8Float64Array::wrap(impl); + if (!wrapper.IsEmpty()) + wrapper->SetIndexedPropertiesToExternalArrayData(impl->baseAddress(), v8::kExternalDoubleArray, impl->length()); + return wrapper; +} + +} // namespace WebCore diff --git a/Source/WebCore/bridge/jni/JavaMethodJobject.cpp b/Source/WebCore/bridge/jni/JavaMethodJobject.cpp index 01a0b5b..f93e197 100644 --- a/Source/WebCore/bridge/jni/JavaMethodJobject.cpp +++ b/Source/WebCore/bridge/jni/JavaMethodJobject.cpp @@ -131,9 +131,9 @@ const char* JavaMethodJobject::signature() const else { signatureBuilder.append(signatureFromJavaType(type)); if (type == JavaTypeObject -#if USE(V8) +// ANDROID || type == JavaTypeString -#endif +// ANDROID ) { appendClassName(signatureBuilder, javaClassName.data()); signatureBuilder.append(';'); @@ -148,9 +148,9 @@ const char* JavaMethodJobject::signature() const else { signatureBuilder.append(signatureFromJavaType(m_returnType)); if (m_returnType == JavaTypeObject -#if USE(V8) +// ANDROID || m_returnType == JavaTypeString -#endif +// ANDROID ) { appendClassName(signatureBuilder, returnType); signatureBuilder.append(';'); diff --git a/Source/WebCore/bridge/jni/v8/JNIUtilityPrivate.cpp b/Source/WebCore/bridge/jni/v8/JNIUtilityPrivate.cpp index 42efaac..15b4bda 100644 --- a/Source/WebCore/bridge/jni/v8/JNIUtilityPrivate.cpp +++ b/Source/WebCore/bridge/jni/v8/JNIUtilityPrivate.cpp @@ -72,11 +72,16 @@ JavaValue convertNPVariantToJavaValue(NPVariant value, const String& javaClass) break; } - jsize length = 0; - if (NPVARIANT_IS_INT32(npvLength)) - length = static_cast<jsize>(NPVARIANT_TO_INT32(npvLength)); - else if (NPVARIANT_IS_DOUBLE(npvLength)) - length = static_cast<jsize>(NPVARIANT_TO_DOUBLE(npvLength)); + // Convert to null if the length property is not a number. + if (!NPVARIANT_IS_INT32(npvLength) && !NPVARIANT_IS_DOUBLE(npvLength)) + break; + + // Convert to null if the length property is out of bounds. + double doubleLength = NPVARIANT_IS_INT32(npvLength) ? NPVARIANT_TO_INT32(npvLength) : NPVARIANT_TO_DOUBLE(npvLength); + if (doubleLength < 0.0 || doubleLength > INT32_MAX) + break; + + jsize length = static_cast<jsize>(doubleLength); if (!strcmp(javaClassName.data(), "[Ljava.lang.String;")) { // Match JSC behavior by only allowing Object arrays if they are Strings. @@ -85,7 +90,7 @@ JavaValue convertNPVariantToJavaValue(NPVariant value, const String& javaClass) for (jsize i = 0; i < length; i++) { NPVariant npvValue; _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue); - if(NPVARIANT_IS_STRING(npvValue)) { + if (NPVARIANT_IS_STRING(npvValue)) { NPString str = NPVARIANT_TO_STRING(npvValue); env->SetObjectArrayElement(static_cast<jobjectArray>(javaArray), i, env->NewStringUTF(str.UTF8Characters)); } @@ -100,11 +105,10 @@ JavaValue convertNPVariantToJavaValue(NPVariant value, const String& javaClass) NPVariant npvValue; _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue); jbyte bVal = 0; - if (NPVARIANT_IS_INT32(npvValue)) { + if (NPVARIANT_IS_INT32(npvValue)) bVal = static_cast<jbyte>(NPVARIANT_TO_INT32(npvValue)); - } else if (NPVARIANT_IS_DOUBLE(npvValue)) { + else if (NPVARIANT_IS_DOUBLE(npvValue)) bVal = static_cast<jbyte>(NPVARIANT_TO_DOUBLE(npvValue)); - } env->SetByteArrayRegion(static_cast<jbyteArray>(javaArray), i, 1, &bVal); } } else if (!strcmp(javaClassName.data(), "[C")) { @@ -115,12 +119,8 @@ JavaValue convertNPVariantToJavaValue(NPVariant value, const String& javaClass) NPVariant npvValue; _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue); jchar cVal = 0; - if (NPVARIANT_IS_INT32(npvValue)) { + if (NPVARIANT_IS_INT32(npvValue)) cVal = static_cast<jchar>(NPVARIANT_TO_INT32(npvValue)); - } else if (NPVARIANT_IS_STRING(npvValue)) { - NPString str = NPVARIANT_TO_STRING(npvValue); - cVal = str.UTF8Characters[0]; - } env->SetCharArrayRegion(static_cast<jcharArray>(javaArray), i, 1, &cVal); } } else if (!strcmp(javaClassName.data(), "[D")) { @@ -155,11 +155,10 @@ JavaValue convertNPVariantToJavaValue(NPVariant value, const String& javaClass) NPVariant npvValue; _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue); jint iVal = 0; - if (NPVARIANT_IS_INT32(npvValue)) { + if (NPVARIANT_IS_INT32(npvValue)) iVal = NPVARIANT_TO_INT32(npvValue); - } else if (NPVARIANT_IS_DOUBLE(npvValue)) { + else if (NPVARIANT_IS_DOUBLE(npvValue)) iVal = static_cast<jint>(NPVARIANT_TO_DOUBLE(npvValue)); - } env->SetIntArrayRegion(static_cast<jintArray>(javaArray), i, 1, &iVal); } } else if (!strcmp(javaClassName.data(), "[J")) { @@ -170,11 +169,10 @@ JavaValue convertNPVariantToJavaValue(NPVariant value, const String& javaClass) NPVariant npvValue; _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue); jlong jVal = 0; - if (NPVARIANT_IS_INT32(npvValue)) { + if (NPVARIANT_IS_INT32(npvValue)) jVal = static_cast<jlong>(NPVARIANT_TO_INT32(npvValue)); - } else if (NPVARIANT_IS_DOUBLE(npvValue)) { + else if (NPVARIANT_IS_DOUBLE(npvValue)) jVal = static_cast<jlong>(NPVARIANT_TO_DOUBLE(npvValue)); - } env->SetLongArrayRegion(static_cast<jlongArray>(javaArray), i, 1, &jVal); } } else if (!strcmp(javaClassName.data(), "[S")) { @@ -185,11 +183,10 @@ JavaValue convertNPVariantToJavaValue(NPVariant value, const String& javaClass) NPVariant npvValue; _NPN_GetProperty(0, object, _NPN_GetIntIdentifier(i), &npvValue); jshort sVal = 0; - if (NPVARIANT_IS_INT32(npvValue)) { + if (NPVARIANT_IS_INT32(npvValue)) sVal = static_cast<jshort>(NPVARIANT_TO_INT32(npvValue)); - } else if (NPVARIANT_IS_DOUBLE(npvValue)) { + else if (NPVARIANT_IS_DOUBLE(npvValue)) sVal = static_cast<jshort>(NPVARIANT_TO_DOUBLE(npvValue)); - } env->SetShortArrayRegion(static_cast<jshortArray>(javaArray), i, 1, &sVal); } } else if (!strcmp(javaClassName.data(), "[Z")) { diff --git a/Source/WebCore/bridge/jni/v8/JavaValueV8.h b/Source/WebCore/bridge/jni/v8/JavaValueV8.h index 3e1c623..c6ff315 100644 --- a/Source/WebCore/bridge/jni/v8/JavaValueV8.h +++ b/Source/WebCore/bridge/jni/v8/JavaValueV8.h @@ -49,7 +49,18 @@ class JavaInstance; // currently used only with V8. // See https://bugs.webkit.org/show_bug.cgi?id=57023. struct JavaValue { - JavaValue() : m_type(JavaTypeInvalid) {} +// ANDROID + JavaValue() + : m_type(JavaTypeInvalid) + , m_booleanValue(false) + , m_byteValue(0) + , m_charValue(0) + , m_shortValue(0) + , m_intValue(0) + , m_longValue(0) + , m_floatValue(0.0) + , m_doubleValue(0.0) {} +// ANDROID JavaType m_type; // We don't use a union because we want to be able to ref-count some of the diff --git a/Source/WebCore/css/AndroidCSSPropertyNames.in b/Source/WebCore/css/AndroidCSSPropertyNames.in index ef67d6b..be751da 100644 --- a/Source/WebCore/css/AndroidCSSPropertyNames.in +++ b/Source/WebCore/css/AndroidCSSPropertyNames.in @@ -21,14 +21,5 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # --webkit-ring --webkit-ring-fill-color --webkit-ring-inner-width --webkit-ring-outer-width --webkit-ring-outset --webkit-ring-pressed-inner-color --webkit-ring-pressed-outer-color --webkit-ring-radius --webkit-ring-selected-inner-color --webkit-ring-selected-outer-color + -webkit-tap-highlight-color diff --git a/Source/WebCore/css/CSSComputedStyleDeclaration.cpp b/Source/WebCore/css/CSSComputedStyleDeclaration.cpp index 4c0571d..4922109 100644 --- a/Source/WebCore/css/CSSComputedStyleDeclaration.cpp +++ b/Source/WebCore/css/CSSComputedStyleDeclaration.cpp @@ -291,18 +291,6 @@ static const int computedProperties[] = { CSSPropertyWebkitSvgShadow, CSSPropertyVectorEffect #endif -#ifdef ANDROID_CSS_RING - , - CSSPropertyWebkitRingFillColor, - CSSPropertyWebkitRingInnerWidth, - CSSPropertyWebkitRingOuterWidth, - CSSPropertyWebkitRingOutset, - CSSPropertyWebkitRingPressedInnerColor, - CSSPropertyWebkitRingPressedOuterColor, - CSSPropertyWebkitRingRadius, - CSSPropertyWebkitRingSelectedInnerColor, - CSSPropertyWebkitRingSelectedOuterColor -#endif #ifdef ANDROID_CSS_TAP_HIGHLIGHT_COLOR , CSSPropertyWebkitTapHighlightColor @@ -1818,29 +1806,6 @@ PassRefPtr<CSSValue> CSSComputedStyleDeclaration::getPropertyCSSValue(int proper case CSSPropertyWebkitTransformOriginZ: case CSSPropertyWebkitTransition: break; -#ifdef ANDROID_CSS_RING - case CSSPropertyWebkitRing: - // shorthand property currently not supported see bug 13658 - break; - case CSSPropertyWebkitRingFillColor: - return primitiveValueCache->createColorValue(style->ringFillColor().rgb()); - case CSSPropertyWebkitRingInnerWidth: - return primitiveValueCache->createValue(style->ringInnerWidth()); - case CSSPropertyWebkitRingOuterWidth: - return primitiveValueCache->createValue(style->ringOuterWidth()); - case CSSPropertyWebkitRingOutset: - return primitiveValueCache->createValue(style->ringOutset()); - case CSSPropertyWebkitRingPressedInnerColor: - return primitiveValueCache->createColorValue(style->ringPressedInnerColor().rgb()); - case CSSPropertyWebkitRingPressedOuterColor: - return primitiveValueCache->createColorValue(style->ringPressedOuterColor().rgb()); - case CSSPropertyWebkitRingRadius: - return primitiveValueCache->createValue(style->ringRadius()); - case CSSPropertyWebkitRingSelectedInnerColor: - return primitiveValueCache->createColorValue(style->ringSelectedInnerColor().rgb()); - case CSSPropertyWebkitRingSelectedOuterColor: - return primitiveValueCache->createColorValue(style->ringSelectedOuterColor().rgb()); -#endif #ifdef ANDROID_CSS_TAP_HIGHLIGHT_COLOR case CSSPropertyWebkitTapHighlightColor: return primitiveValueCache->createColorValue(style->tapHighlightColor().rgb()); diff --git a/Source/WebCore/css/CSSImportRule.cpp b/Source/WebCore/css/CSSImportRule.cpp index 09e313e..81ade39 100644 --- a/Source/WebCore/css/CSSImportRule.cpp +++ b/Source/WebCore/css/CSSImportRule.cpp @@ -170,26 +170,4 @@ void CSSImportRule::addSubresourceStyleURLs(ListHashSet<KURL>& urls) addSubresourceURL(urls, m_styleSheet->baseURL()); } -#ifdef ANDROID_INSTRUMENT -void* CSSImportRule::operator new(size_t size) -{ - return StyleBase::operator new(size); -} - -void* CSSImportRule::operator new[](size_t size) -{ - return StyleBase::operator new[](size); -} - -void CSSImportRule::operator delete(void* p, size_t size) -{ - StyleBase::operator delete(p, size); -} - -void CSSImportRule::operator delete[](void* p, size_t size) -{ - StyleBase::operator delete[](p, size); -} -#endif - } // namespace WebCore diff --git a/Source/WebCore/css/CSSImportRule.h b/Source/WebCore/css/CSSImportRule.h index 3f44f5b..ad4e97d 100644 --- a/Source/WebCore/css/CSSImportRule.h +++ b/Source/WebCore/css/CSSImportRule.h @@ -66,14 +66,6 @@ private: // from CachedResourceClient virtual void setCSSStyleSheet(const String& href, const KURL& baseURL, const String& charset, const CachedCSSStyleSheet*); -#ifdef ANDROID_INSTRUMENT - // Overridden to resolve the ambiguous - void* operator new(size_t size); - void* operator new[](size_t size); - void operator delete(void* p, size_t size); - void operator delete[](void* p, size_t size); -#endif - String m_strHref; RefPtr<MediaList> m_lstMedia; RefPtr<CSSStyleSheet> m_styleSheet; diff --git a/Source/WebCore/css/CSSMutableStyleDeclaration.cpp b/Source/WebCore/css/CSSMutableStyleDeclaration.cpp index ba3332d..ece418a 100644 --- a/Source/WebCore/css/CSSMutableStyleDeclaration.cpp +++ b/Source/WebCore/css/CSSMutableStyleDeclaration.cpp @@ -261,20 +261,6 @@ String CSSMutableStyleDeclaration::getPropertyValue(int propertyID) const return value->cssText(); } #endif -#ifdef ANDROID_CSS_RING - case CSSPropertyWebkitRing: { - const int properties[9] = { CSSPropertyWebkitRingFillColor, - CSSPropertyWebkitRingInnerWidth, - CSSPropertyWebkitRingOuterWidth, - CSSPropertyWebkitRingOutset, - CSSPropertyWebkitRingPressedInnerColor, - CSSPropertyWebkitRingPressedOuterColor, - CSSPropertyWebkitRingRadius, - CSSPropertyWebkitRingSelectedInnerColor, - CSSPropertyWebkitRingSelectedOuterColor }; - return getLayeredShorthandValue(properties, 9); - } -#endif } return String(); } diff --git a/Source/WebCore/css/CSSParser.cpp b/Source/WebCore/css/CSSParser.cpp index 831e438..b78a6d0 100644 --- a/Source/WebCore/css/CSSParser.cpp +++ b/Source/WebCore/css/CSSParser.cpp @@ -92,10 +92,6 @@ extern int cssyyparse(void* parser); using namespace std; using namespace WTF; -#ifdef ANDROID_INSTRUMENT -#include "TimeCounter.h" -#endif - namespace WebCore { static const unsigned INVALID_NUM_PARSED_PROPERTIES = UINT_MAX; @@ -230,9 +226,6 @@ void CSSParser::setupParser(const char* prefix, const String& string, const char void CSSParser::parseSheet(CSSStyleSheet* sheet, const String& string, int startLineNumber, StyleRuleRangeMap* ruleRangeMap) { -#ifdef ANDROID_INSTRUMENT - android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter); -#endif setStyleSheet(sheet); m_defaultNamespace = starAtom; // Reset the default namespace. m_ruleRangeMap = ruleRangeMap; @@ -247,37 +240,22 @@ void CSSParser::parseSheet(CSSStyleSheet* sheet, const String& string, int start m_ruleRangeMap = 0; m_currentRuleData = 0; m_rule = 0; -#ifdef ANDROID_INSTRUMENT - android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__); -#endif } PassRefPtr<CSSRule> CSSParser::parseRule(CSSStyleSheet* sheet, const String& string) { -#ifdef ANDROID_INSTRUMENT - android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter); -#endif setStyleSheet(sheet); m_allowNamespaceDeclarations = false; setupParser("@-webkit-rule{", string, "} "); cssyyparse(this); -#ifdef ANDROID_INSTRUMENT - android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__); -#endif return m_rule.release(); } PassRefPtr<CSSRule> CSSParser::parseKeyframeRule(CSSStyleSheet *sheet, const String &string) { -#ifdef ANDROID_INSTRUMENT - android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter); -#endif setStyleSheet(sheet); setupParser("@-webkit-keyframe-rule{ ", string, "} "); cssyyparse(this); -#ifdef ANDROID_INSTRUMENT - android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__); -#endif return m_keyframe.release(); } @@ -440,9 +418,6 @@ bool CSSParser::parseValue(CSSMutableStyleDeclaration* declaration, int property bool CSSParser::parseValue(CSSMutableStyleDeclaration* declaration, int propertyId, const String& string, bool important) { -#ifdef ANDROID_INSTRUMENT - android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter); -#endif ASSERT(!declaration->stylesheet() || declaration->stylesheet()->isCSSStyleSheet()); setStyleSheet(static_cast<CSSStyleSheet*>(declaration->stylesheet())); @@ -464,9 +439,6 @@ bool CSSParser::parseValue(CSSMutableStyleDeclaration* declaration, int property clearProperties(); } -#ifdef ANDROID_INSTRUMENT - android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__); -#endif return ok; } @@ -499,9 +471,6 @@ bool CSSParser::parseColor(RGBA32& color, const String& string, bool strict) bool CSSParser::parseColor(CSSMutableStyleDeclaration* declaration, const String& string) { -#ifdef ANDROID_INSTRUMENT - android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter); -#endif ASSERT(!declaration->stylesheet() || declaration->stylesheet()->isCSSStyleSheet()); setStyleSheet(static_cast<CSSStyleSheet*>(declaration->stylesheet())); @@ -509,9 +478,6 @@ bool CSSParser::parseColor(CSSMutableStyleDeclaration* declaration, const String cssyyparse(this); m_rule = 0; -#ifdef ANDROID_INSTRUMENT - android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__); -#endif return (m_numParsedProperties && m_parsedProperties[0]->m_id == CSSPropertyColor); } @@ -533,9 +499,6 @@ bool CSSParser::parseSystemColor(RGBA32& color, const String& string, Document* void CSSParser::parseSelector(const String& string, Document* doc, CSSSelectorList& selectorList) { -#ifdef ANDROID_INSTRUMENT - android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter); -#endif RefPtr<CSSStyleSheet> dummyStyleSheet = CSSStyleSheet::create(doc); setStyleSheet(dummyStyleSheet.get()); @@ -549,18 +512,10 @@ void CSSParser::parseSelector(const String& string, Document* doc, CSSSelectorLi // The style sheet will be deleted right away, so it won't outlive the document. ASSERT(dummyStyleSheet->hasOneRef()); - -#ifdef ANDROID_INSTRUMENT - android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__); -#endif } bool CSSParser::parseDeclaration(CSSMutableStyleDeclaration* declaration, const String& string, RefPtr<CSSStyleSourceData>* styleSourceData) { -#ifdef ANDROID_INSTRUMENT - android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter); -#endif - // Length of the "@-webkit-decls{" prefix. static const unsigned prefixLength = 15; @@ -599,9 +554,6 @@ bool CSSParser::parseDeclaration(CSSMutableStyleDeclaration* declaration, const m_currentRuleData = 0; m_inStyleRuleOrDeclaration = false; } -#ifdef ANDROID_INSTRUMENT - android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__); -#endif return ok; } @@ -610,9 +562,6 @@ bool CSSParser::parseMediaQuery(MediaList* queries, const String& string) if (string.isEmpty()) return true; -#ifdef ANDROID_INSTRUMENT - android::TimeCounter::start(android::TimeCounter::CSSParseTimeCounter); -#endif ASSERT(!m_mediaQuery); // can't use { because tokenizer state switches from mediaquery to initial state when it sees { token. @@ -626,9 +575,6 @@ bool CSSParser::parseMediaQuery(MediaList* queries, const String& string) queries->appendMediaQuery(m_mediaQuery.release()); } -#ifdef ANDROID_INSTRUMENT - android::TimeCounter::record(android::TimeCounter::CSSParseTimeCounter, __FUNCTION__); -#endif return ok; } @@ -2016,7 +1962,6 @@ bool CSSParser::parseValue(int propId, bool important) case CSSPropertyTextOverline: case CSSPropertyTextUnderline: return false; - #if ENABLE(WCSS) case CSSPropertyWapInputFormat: validPrimitive = true; @@ -2063,36 +2008,6 @@ bool CSSParser::parseValue(int propId, bool important) return parseLineBoxContain(important); break; -#ifdef ANDROID_CSS_RING - case CSSPropertyWebkitRing: - { - const int properties[9] = { CSSPropertyWebkitRingFillColor, - CSSPropertyWebkitRingInnerWidth, - CSSPropertyWebkitRingOuterWidth, - CSSPropertyWebkitRingOutset, - CSSPropertyWebkitRingPressedInnerColor, - CSSPropertyWebkitRingPressedOuterColor, - CSSPropertyWebkitRingRadius, - CSSPropertyWebkitRingSelectedInnerColor, - CSSPropertyWebkitRingSelectedOuterColor }; - return parseShorthand(propId, properties, 9, important); - } - case CSSPropertyWebkitRingFillColor: - case CSSPropertyWebkitRingPressedInnerColor: - case CSSPropertyWebkitRingPressedOuterColor: - case CSSPropertyWebkitRingSelectedInnerColor: - case CSSPropertyWebkitRingSelectedOuterColor: - parsedValue = parseColor(); - if (parsedValue) - m_valueList->next(); - break; - case CSSPropertyWebkitRingInnerWidth: - case CSSPropertyWebkitRingOuterWidth: - case CSSPropertyWebkitRingOutset: - case CSSPropertyWebkitRingRadius: - validPrimitive = validUnit(value, FLength | FNonNeg, m_strict); - break; -#endif #ifdef ANDROID_CSS_TAP_HIGHLIGHT_COLOR case CSSPropertyWebkitTapHighlightColor: parsedValue = parseColor(); diff --git a/Source/WebCore/css/CSSStyleDeclaration.cpp b/Source/WebCore/css/CSSStyleDeclaration.cpp index 1c465e5..d4acc2a 100644 --- a/Source/WebCore/css/CSSStyleDeclaration.cpp +++ b/Source/WebCore/css/CSSStyleDeclaration.cpp @@ -27,6 +27,7 @@ #include "CSSPropertyNames.h" #include "CSSRule.h" #include <wtf/ASCIICType.h> +#include <wtf/text/CString.h> using namespace WTF; diff --git a/Source/WebCore/css/CSSStyleSelector.cpp b/Source/WebCore/css/CSSStyleSelector.cpp index b79f2dc..0b6fd35 100644 --- a/Source/WebCore/css/CSSStyleSelector.cpp +++ b/Source/WebCore/css/CSSStyleSelector.cpp @@ -6054,138 +6054,6 @@ void CSSStyleSelector::applyProperty(int id, CSSValue *value) ASSERT_NOT_REACHED(); return; -#ifdef ANDROID_CSS_RING - case CSSPropertyWebkitRing: - if (valueType != CSSValue::CSS_INHERIT || !m_parentNode) return; - m_style->setRingFillColor(m_parentStyle->ringFillColor()); - m_style->setRingInnerWidth(m_parentStyle->ringInnerWidth()); - m_style->setRingOuterWidth(m_parentStyle->ringOuterWidth()); - m_style->setRingOutset(m_parentStyle->ringOutset()); - m_style->setRingPressedInnerColor(m_parentStyle->ringPressedInnerColor()); - m_style->setRingPressedOuterColor(m_parentStyle->ringPressedOuterColor()); - m_style->setRingRadius(m_parentStyle->ringRadius()); - m_style->setRingSelectedInnerColor(m_parentStyle->ringSelectedInnerColor()); - m_style->setRingSelectedOuterColor(m_parentStyle->ringSelectedOuterColor()); - return; - case CSSPropertyWebkitRingFillColor: { - HANDLE_INHERIT_AND_INITIAL(ringFillColor, RingFillColor); - if (!primitiveValue) - break; - Color col = getColorFromPrimitiveValue(primitiveValue).blendWithWhite(); - m_style->setRingFillColor(col); - return; - } - case CSSPropertyWebkitRingInnerWidth: { - HANDLE_INHERIT_AND_INITIAL(ringInnerWidth, RingInnerWidth) - if (!primitiveValue) - break; - Length l; - int type = primitiveValue->primitiveType(); - if (CSSPrimitiveValue::isUnitTypeLength(type)) { - // width can be specified with fractional px - // scale by 16 here (and unscale in android_graphics) to keep - // 4 bits of fraction - RefPtr<CSSPrimitiveValue> scaledValue = CSSPrimitiveValue::create( - primitiveValue->getFloatValue() * 16, - (CSSPrimitiveValue::UnitTypes) type); - l = Length(scaledValue->computeLengthIntForLength(style(), - m_rootElementStyle, zoomFactor), Fixed); - scaledValue.release(); - } else if (type == CSSPrimitiveValue::CSS_PERCENTAGE) - l = Length(primitiveValue->getDoubleValue(), Percent); - else - return; - m_style->setRingInnerWidth(l); - return; - } - case CSSPropertyWebkitRingOuterWidth: { - HANDLE_INHERIT_AND_INITIAL(ringOuterWidth, RingOuterWidth) - if (!primitiveValue) - break; - Length l; - int type = primitiveValue->primitiveType(); - if (CSSPrimitiveValue::isUnitTypeLength(type)) { - // width can be specified with fractional px - // scale by 16 here (and unscale in android_graphics) to keep - // 4 bits of fraction - RefPtr<CSSPrimitiveValue> scaledValue = CSSPrimitiveValue::create( - primitiveValue->getFloatValue() * 16, - (CSSPrimitiveValue::UnitTypes) type); - l = Length(scaledValue->computeLengthIntForLength(style(), - m_rootElementStyle, zoomFactor), Fixed); - scaledValue.release(); - } else if (type == CSSPrimitiveValue::CSS_PERCENTAGE) - l = Length(primitiveValue->getDoubleValue(), Percent); - else - return; - m_style->setRingOuterWidth(l); - return; - } - case CSSPropertyWebkitRingOutset: { - HANDLE_INHERIT_AND_INITIAL(ringOutset, RingOutset) - if (!primitiveValue) - break; - Length l; - int type = primitiveValue->primitiveType(); - if (CSSPrimitiveValue::isUnitTypeLength(type)) - l = Length(primitiveValue->computeLengthIntForLength(style(), - m_rootElementStyle, zoomFactor), Fixed); - else if (type == CSSPrimitiveValue::CSS_PERCENTAGE) - l = Length(primitiveValue->getDoubleValue(), Percent); - else - return; - m_style->setRingOutset(l); - return; - } - case CSSPropertyWebkitRingPressedInnerColor: { - HANDLE_INHERIT_AND_INITIAL(ringPressedInnerColor, RingPressedInnerColor); - if (!primitiveValue) - break; - Color col = getColorFromPrimitiveValue(primitiveValue).blendWithWhite(); - m_style->setRingPressedInnerColor(col); - return; - } - case CSSPropertyWebkitRingPressedOuterColor: { - HANDLE_INHERIT_AND_INITIAL(ringPressedOuterColor, RingPressedOuterColor); - if (!primitiveValue) - break; - Color col = getColorFromPrimitiveValue(primitiveValue).blendWithWhite(); - m_style->setRingPressedOuterColor(col); - return; - } - case CSSPropertyWebkitRingRadius: { - HANDLE_INHERIT_AND_INITIAL(ringRadius, RingRadius) - if (!primitiveValue) - break; - Length l; - int type = primitiveValue->primitiveType(); - if (CSSPrimitiveValue::isUnitTypeLength(type)) - l = Length(primitiveValue->computeLengthIntForLength(style(), - m_rootElementStyle, zoomFactor), Fixed); - else if (type == CSSPrimitiveValue::CSS_PERCENTAGE) - l = Length(primitiveValue->getDoubleValue(), Percent); - else - return; - m_style->setRingRadius(l); - return; - } - case CSSPropertyWebkitRingSelectedInnerColor: { - HANDLE_INHERIT_AND_INITIAL(ringSelectedInnerColor, RingSelectedInnerColor); - if (!primitiveValue) - break; - Color col = getColorFromPrimitiveValue(primitiveValue).blendWithWhite(); - m_style->setRingSelectedInnerColor(col); - return; - } - case CSSPropertyWebkitRingSelectedOuterColor: { - HANDLE_INHERIT_AND_INITIAL(ringSelectedOuterColor, RingSelectedOuterColor); - if (!primitiveValue) - break; - Color col = getColorFromPrimitiveValue(primitiveValue).blendWithWhite(); - m_style->setRingSelectedOuterColor(col); - return; - } -#endif #ifdef ANDROID_CSS_TAP_HIGHLIGHT_COLOR case CSSPropertyWebkitTapHighlightColor: { HANDLE_INHERIT_AND_INITIAL(tapHighlightColor, TapHighlightColor); diff --git a/Source/WebCore/css/StyleBase.cpp b/Source/WebCore/css/StyleBase.cpp index 5d9d79d..93dbda0 100644 --- a/Source/WebCore/css/StyleBase.cpp +++ b/Source/WebCore/css/StyleBase.cpp @@ -65,37 +65,4 @@ KURL StyleBase::baseURL() const return sheet->ownerNode()->document()->baseURL(); } -#ifdef ANDROID_INSTRUMENT -static size_t styleSize = 0; - -void* StyleBase::operator new(size_t size) -{ - styleSize += size; - return ::operator new(size); -} - -void* StyleBase::operator new[](size_t size) -{ - styleSize += size; - return ::operator new[](size); -} - -void StyleBase::operator delete(void* p, size_t size) -{ - styleSize -= size; - ::operator delete(p); -} - -void StyleBase::operator delete[](void* p, size_t size) -{ - styleSize -= size; - ::operator delete[](p); -} - -size_t StyleBase::reportStyleSize() -{ - return styleSize; -} -#endif - } diff --git a/Source/WebCore/css/StyleBase.h b/Source/WebCore/css/StyleBase.h index 94efa01..63c671e 100644 --- a/Source/WebCore/css/StyleBase.h +++ b/Source/WebCore/css/StyleBase.h @@ -72,18 +72,6 @@ namespace WebCore { StyleSheet* stylesheet(); -#ifdef ANDROID_INSTRUMENT - // Overridden to prevent the normal new from being called. - void* operator new(size_t size); - void* operator new[](size_t size); - - // Overridden to prevent the normal delete from being called. - void operator delete(void* p, size_t size); - void operator delete[](void* p, size_t size); - - static size_t reportStyleSize(); -#endif - protected: StyleBase(StyleBase* parent) : m_parent(parent) diff --git a/Source/WebCore/css/mediaControlsAndroid.css b/Source/WebCore/css/mediaControlsAndroid.css index 77f8b08..614c92f 100644 --- a/Source/WebCore/css/mediaControlsAndroid.css +++ b/Source/WebCore/css/mediaControlsAndroid.css @@ -49,10 +49,7 @@ video:-webkit-full-page-media::-webkit-media-controls-panel { } audio::-webkit-media-controls-mute-button, video::-webkit-media-controls-mute-button { - -webkit-appearance: media-mute-button; - display: -webkit-box; - width: 48px; - height: 48px; + display: none; } audio::-webkit-media-controls-play-button, video::-webkit-media-controls-play-button { diff --git a/Source/WebCore/dom/DOMTextContentWalker.cpp b/Source/WebCore/dom/DOMTextContentWalker.cpp new file mode 100644 index 0000000..5e77db1 --- /dev/null +++ b/Source/WebCore/dom/DOMTextContentWalker.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 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; + RefPtr<Range> forwardRange = makeRange(position, endOfDocument(position)); + if (!forwardRange) + return; + CharacterIterator forwardChar(forwardRange.get(), TextIteratorStopsOnFormControls); + forwardChar.advance(maxLength - halfMaxLength); + + // No forward contents, started inside form control. + if (getRange(position.deepEquivalent(), forwardChar.range()->startPosition())->text().length() == 0) + return; + + RefPtr<Range> backwardsRange = makeRange(startOfDocument(position), position); + if (!backwardsRange) + return; + BackwardsCharacterIterator backwardsChar(backwardsRange.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 6e21dc3..1b5f55b 100644 --- a/Source/WebCore/dom/Document.cpp +++ b/Source/WebCore/dom/Document.cpp @@ -189,15 +189,6 @@ #include "Settings.h" #endif -#ifdef ANDROID_RESET_SELECTION -#include "CacheBuilder.h" -#include "HTMLTextAreaElement.h" -#endif - -#ifdef ANDROID_INSTRUMENT -#include "TimeCounter.h" -#endif - #if ENABLE(TOUCH_EVENTS) #if USE(V8) #include "RuntimeEnabledFeatures.h" @@ -1475,10 +1466,6 @@ void Document::recalcStyle(StyleChange change) frameView->beginDeferredRepaints(); } -#ifdef ANDROID_INSTRUMENT - android::TimeCounter::start(android::TimeCounter::CalculateStyleTimeCounter); -#endif - ASSERT(!renderer() || renderArena()); if (!renderer() || !renderArena()) goto bail_out; @@ -1500,10 +1487,6 @@ void Document::recalcStyle(StyleChange change) if (change >= Inherit || n->childNeedsStyleRecalc() || n->needsStyleRecalc()) n->recalcStyle(change); -#ifdef ANDROID_INSTRUMENT - android::TimeCounter::record(android::TimeCounter::CalculateStyleTimeCounter, __FUNCTION__); -#endif - #if USE(ACCELERATED_COMPOSITING) if (view()) { bool layoutPending = view()->layoutPending() || renderer()->needsLayout(); @@ -2729,8 +2712,8 @@ void Document::processArguments(const String& features, void* data, ArgumentsCal #ifdef ANDROID_META_SUPPORT if (frame()) frame()->settings()->setMetadataSettings(keyString, valueString); -#endif if (callback && data) +#endif callback(keyString, valueString, this, data); } } diff --git a/Source/WebCore/dom/Node.cpp b/Source/WebCore/dom/Node.cpp index 1fd4b92..0967ef5 100644 --- a/Source/WebCore/dom/Node.cpp +++ b/Source/WebCore/dom/Node.cpp @@ -2498,39 +2498,6 @@ Node* Node::enclosingLinkEventParentOrSelf() return 0; } -#ifdef ANDROID_INSTRUMENT -static size_t nodeSize = 0; - -void* Node::operator new(size_t size) -{ - nodeSize += size; - return ::operator new(size); -} - -void* Node::operator new[](size_t size) -{ - nodeSize += size; - return ::operator new[](size); -} - -void Node::operator delete(void* p, size_t size) -{ - nodeSize -= size; - ::operator delete(p); -} - -void Node::operator delete[](void* p, size_t size) -{ - nodeSize -= size; - ::operator delete[](p); -} - -size_t Node::reportDOMNodesSize() -{ - return nodeSize; -} -#endif - // -------- ScriptExecutionContext* Node::scriptExecutionContext() const diff --git a/Source/WebCore/dom/Node.h b/Source/WebCore/dom/Node.h index 1fe30ad..08b1921 100644 --- a/Source/WebCore/dom/Node.h +++ b/Source/WebCore/dom/Node.h @@ -528,18 +528,6 @@ public: unsigned short compareDocumentPosition(Node*); -#ifdef ANDROID_INSTRUMENT - // Overridden to prevent the normal new from being called. - void* operator new(size_t size); - void* operator new[](size_t size); - - // Overridden to prevent the normal delete from being called. - void operator delete(void* p, size_t size); - void operator delete[](void* p, size_t size); - - static size_t reportDOMNodesSize(); -#endif - virtual Node* toNode() { return this; } virtual InputElement* toInputElement(); diff --git a/Source/WebCore/dom/ProcessingInstruction.cpp b/Source/WebCore/dom/ProcessingInstruction.cpp index 7135644..30111d8 100644 --- a/Source/WebCore/dom/ProcessingInstruction.cpp +++ b/Source/WebCore/dom/ProcessingInstruction.cpp @@ -297,26 +297,4 @@ void ProcessingInstruction::finishParsingChildren() ContainerNode::finishParsingChildren(); } -#ifdef ANDROID_INSTRUMENT -void* ProcessingInstruction::operator new(size_t size) -{ - return Node::operator new(size); -} - -void* ProcessingInstruction::operator new[](size_t size) -{ - return Node::operator new[](size); -} - -void ProcessingInstruction::operator delete(void* p, size_t size) -{ - Node::operator delete(p, size); -} - -void ProcessingInstruction::operator delete[](void* p, size_t size) -{ - Node::operator delete[](p, size); -} -#endif - } // namespace diff --git a/Source/WebCore/dom/ProcessingInstruction.h b/Source/WebCore/dom/ProcessingInstruction.h index fd98566..1be8710 100644 --- a/Source/WebCore/dom/ProcessingInstruction.h +++ b/Source/WebCore/dom/ProcessingInstruction.h @@ -56,14 +56,6 @@ public: private: ProcessingInstruction(Document*, const String& target, const String& data); -#ifdef ANDROID_INSTRUMENT - // Overridden to resolve the ambiguous - void* operator new(size_t size); - void* operator new[](size_t size); - void operator delete(void* p, size_t size); - void operator delete[](void* p, size_t size); -#endif - virtual String nodeName() const; virtual NodeType nodeType() const; virtual String nodeValue() const; diff --git a/Source/WebCore/dom/Text.cpp b/Source/WebCore/dom/Text.cpp index 906e421..c4ea0a6 100644 --- a/Source/WebCore/dom/Text.cpp +++ b/Source/WebCore/dom/Text.cpp @@ -31,6 +31,8 @@ #include "SVGNames.h" #endif +#include <wtf/text/CString.h> + #if ENABLE(WML) #include "WMLDocument.h" #include "WMLVariables.h" diff --git a/Source/WebCore/editing/InsertIntoTextNodeCommand.cpp b/Source/WebCore/editing/InsertIntoTextNodeCommand.cpp index b1a455b..bd6fb60 100644 --- a/Source/WebCore/editing/InsertIntoTextNodeCommand.cpp +++ b/Source/WebCore/editing/InsertIntoTextNodeCommand.cpp @@ -28,6 +28,8 @@ #include "AXObjectCache.h" #include "Text.h" +#include "RenderText.h" +#include "Settings.h" namespace WebCore { @@ -46,7 +48,13 @@ void InsertIntoTextNodeCommand::doApply() { if (!m_node->rendererIsEditable()) return; - + + if (document()->settings() && document()->settings()->passwordEchoEnabled()) { + RenderText* renderText = toRenderText(m_node->renderer()); + if (renderText && renderText->isSecure()) + renderText->momentarilyRevealLastTypedCharacter(m_offset + m_text.length() - 1); + } + ExceptionCode ec; m_node->insertData(m_offset, m_text, ec); diff --git a/Source/WebCore/editing/SelectionController.cpp b/Source/WebCore/editing/SelectionController.cpp index c5a33d3..acae6bf 100644 --- a/Source/WebCore/editing/SelectionController.cpp +++ b/Source/WebCore/editing/SelectionController.cpp @@ -1217,10 +1217,6 @@ void SelectionController::invalidateCaretRect() void SelectionController::paintCaret(GraphicsContext* context, int tx, int ty, const IntRect& clipRect) { -#ifdef ANDROID_ALLOW_TURNING_OFF_CARET - if (m_frame && !android::WebViewCore::getWebViewCore(m_frame->view())->shouldPaintCaret()) - return; -#endif #if ENABLE(TEXT_CARET) if (!m_caretVisible) return; @@ -1592,6 +1588,10 @@ void SelectionController::updateAppearance() // We need to update style in case the node containing the selection is made display:none. m_frame->document()->updateStyleIfNeeded(); +#if PLATFORM(ANDROID) + return; +#endif + RenderView* view = m_frame->contentRenderer(); if (!view) return; 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/html/HTMLAnchorElement.cpp b/Source/WebCore/html/HTMLAnchorElement.cpp index 60f5b4a..4636f20 100644 --- a/Source/WebCore/html/HTMLAnchorElement.cpp +++ b/Source/WebCore/html/HTMLAnchorElement.cpp @@ -531,7 +531,11 @@ bool HTMLAnchorElement::treatLinkAsLiveForEventType(EventType eventType) const bool isEnterKeyKeydownEvent(Event* event) { +#if OS(ANDROID) + return event->type() == eventNames().keyupEvent && event->isKeyboardEvent() && static_cast<KeyboardEvent*>(event)->keyIdentifier() == "Enter"; +#else return event->type() == eventNames().keydownEvent && event->isKeyboardEvent() && static_cast<KeyboardEvent*>(event)->keyIdentifier() == "Enter"; +#endif } bool isMiddleMouseButtonEvent(Event* event) diff --git a/Source/WebCore/html/HTMLCanvasElement.h b/Source/WebCore/html/HTMLCanvasElement.h index 9eab209..207c384 100644 --- a/Source/WebCore/html/HTMLCanvasElement.h +++ b/Source/WebCore/html/HTMLCanvasElement.h @@ -128,22 +128,6 @@ public: void makeRenderingResultsAvailable(); -#ifdef ANDROID_INSTRUMENT - void* operator new(size_t size) { - return HTMLElement::operator new(size); - } - void* operator new[](size_t size) { - return HTMLElement::operator new[](size); - } - - void operator delete(void* p, size_t size) { - HTMLElement::operator delete(p, size); - } - void operator delete[](void* p, size_t size) { - HTMLElement::operator delete[](p, size); - } -#endif - private: HTMLCanvasElement(const QualifiedName&, Document*); diff --git a/Source/WebCore/html/HTMLDocument.cpp b/Source/WebCore/html/HTMLDocument.cpp index dd41514..a1be93d 100644 --- a/Source/WebCore/html/HTMLDocument.cpp +++ b/Source/WebCore/html/HTMLDocument.cpp @@ -438,26 +438,4 @@ bool HTMLDocument::isFrameSet() const return bodyElement && bodyElement->hasTagName(framesetTag); } -#ifdef ANDROID_INSTRUMENT -void* HTMLDocument::operator new(size_t size) -{ - return Node::operator new(size); -} - -void* HTMLDocument::operator new[](size_t size) -{ - return Node::operator new[](size); -} - -void HTMLDocument::operator delete(void* p, size_t size) -{ - Node::operator delete(p, size); -} - -void HTMLDocument::operator delete[](void* p, size_t size) -{ - Node::operator delete[](p, size); -} -#endif - } diff --git a/Source/WebCore/html/HTMLDocument.h b/Source/WebCore/html/HTMLDocument.h index 3310b71..d39f392 100644 --- a/Source/WebCore/html/HTMLDocument.h +++ b/Source/WebCore/html/HTMLDocument.h @@ -82,14 +82,6 @@ public: protected: HTMLDocument(Frame*, const KURL&); -#ifdef ANDROID_INSTRUMENT - // Overridden to resolve the ambiguous - void* operator new(size_t size); - void* operator new[](size_t size); - void operator delete(void* p, size_t size); - void operator delete[](void* p, size_t size); -#endif - private: virtual PassRefPtr<Element> createElement(const AtomicString& tagName, ExceptionCode&); diff --git a/Source/WebCore/html/HTMLLinkElement.cpp b/Source/WebCore/html/HTMLLinkElement.cpp index 7cbf38b..4673109 100644 --- a/Source/WebCore/html/HTMLLinkElement.cpp +++ b/Source/WebCore/html/HTMLLinkElement.cpp @@ -504,28 +504,6 @@ void HTMLLinkElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const styleSheet->addSubresourceStyleURLs(urls); } -#ifdef ANDROID_INSTRUMENT -void* HTMLLinkElement::operator new(size_t size) -{ - return Node::operator new(size); -} - -void* HTMLLinkElement::operator new[](size_t size) -{ - return Node::operator new[](size); -} - -void HTMLLinkElement::operator delete(void* p, size_t size) -{ - Node::operator delete(p, size); -} - -void HTMLLinkElement::operator delete[](void* p, size_t size) -{ - Node::operator delete[](p, size); -} -#endif - void HTMLLinkElement::addPendingSheet(PendingSheetType type) { if (type <= m_pendingSheetType) diff --git a/Source/WebCore/html/HTMLLinkElement.h b/Source/WebCore/html/HTMLLinkElement.h index f602d38..1a6eba9 100644 --- a/Source/WebCore/html/HTMLLinkElement.h +++ b/Source/WebCore/html/HTMLLinkElement.h @@ -120,14 +120,6 @@ private: void addPendingSheet(PendingSheetType); void removePendingSheet(); -#ifdef ANDROID_INSTRUMENT - // Overridden to resolve the ambiguous - void* operator new(size_t size); - void* operator new[](size_t size); - void operator delete(void* p, size_t size); - void operator delete[](void* p, size_t size); -#endif - private: HTMLLinkElement(const QualifiedName&, Document*, bool createdByParser); diff --git a/Source/WebCore/html/HTMLMediaElement.cpp b/Source/WebCore/html/HTMLMediaElement.cpp index 023e8d2..5cd2ddd 100644 --- a/Source/WebCore/html/HTMLMediaElement.cpp +++ b/Source/WebCore/html/HTMLMediaElement.cpp @@ -178,6 +178,7 @@ HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document* docum , m_completelyLoaded(false) #if PLATFORM(ANDROID) , m_lastTouch(0) + , m_userGestureInitiated(false) #endif { LOG(Media, "HTMLMediaElement::HTMLMediaElement"); @@ -187,8 +188,8 @@ HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document* docum #if PLATFORM(ANDROID) && ENABLE(TOUCH_EVENTS) // Enable the Media Element to listen to all the touch events document->addListenerTypeIfNeeded(eventNames().touchstartEvent); + m_restrictions |= RequireUserGestureForRateChangeRestriction; #endif - } HTMLMediaElement::~HTMLMediaElement() @@ -515,6 +516,9 @@ void HTMLMediaElement::load(bool isUserGesture, ExceptionCode& ec) ec = INVALID_STATE_ERR; else { m_loadInitiatedByUserGesture = isUserGesture; +#if PLATFORM(ANDROID) + m_userGestureInitiated |= isUserGesture; +#endif prepareForLoad(); loadInternal(); } @@ -1417,9 +1421,19 @@ void HTMLMediaElement::play(bool isUserGesture) { LOG(Media, "HTMLMediaElement::play(isUserGesture : %s)", boolString(isUserGesture)); - if (m_restrictions & RequireUserGestureForRateChangeRestriction && !isUserGesture) + if (m_restrictions & RequireUserGestureForRateChangeRestriction && !isUserGesture +#if PLATFORM(ANDROID) + && !m_userGestureInitiated +#endif + ) return; +#if PLATFORM(ANDROID) + // B/c we set the restriction to require gesture for rate change for + // Android, when we don't early return, we can safely set this to true. + m_userGestureInitiated = true; +#endif + Document* doc = document(); Settings* settings = doc->settings(); if (settings && settings->needsSiteSpecificQuirks() && m_dispatchingCanPlayEvent && !m_loadInitiatedByUserGesture) { @@ -1466,9 +1480,17 @@ void HTMLMediaElement::pause(bool isUserGesture) { LOG(Media, "HTMLMediaElement::pause(isUserGesture : %s)", boolString(isUserGesture)); - if (m_restrictions & RequireUserGestureForRateChangeRestriction && !isUserGesture) + if (m_restrictions & RequireUserGestureForRateChangeRestriction && !isUserGesture +#if PLATFORM(ANDROID) + && !m_userGestureInitiated +#endif + ) return; - +#if PLATFORM(ANDROID) + // B/c we set the restriction to require gesture for rate change for + // Android, when we don't early return, we can safely set this to true. + m_userGestureInitiated = true; +#endif pauseInternal(); } @@ -2402,6 +2424,15 @@ void HTMLMediaElement::defaultEventHandler(Event* event) } #endif +#if PLATFORM(ANDROID) + // It is really hard to hit the play/pause button on mobile devices. + // This allows user to click the video area to toggle play/pause state. + if (event->type() == eventNames().clickEvent + && !hasEventListeners(eventNames().clickEvent)) { + m_userGestureInitiated = processingUserGesture(); + togglePlayState(); + } +#endif HTMLElement::defaultEventHandler(event); #endif } diff --git a/Source/WebCore/html/HTMLMediaElement.h b/Source/WebCore/html/HTMLMediaElement.h index 987cf87..2144ea1 100644 --- a/Source/WebCore/html/HTMLMediaElement.h +++ b/Source/WebCore/html/HTMLMediaElement.h @@ -420,6 +420,10 @@ private: #if PLATFORM(ANDROID) double m_lastTouch; + // When user gesture invoke load, play or pause, this turns to be true. + // After this becomes true, we ignore the user gesture requirement for play + // and pause. + bool m_userGestureInitiated; #endif }; diff --git a/Source/WebCore/html/canvas/ArrayBufferView.h b/Source/WebCore/html/canvas/ArrayBufferView.h index 701abbc..d06fc8d 100644 --- a/Source/WebCore/html/canvas/ArrayBufferView.h +++ b/Source/WebCore/html/canvas/ArrayBufferView.h @@ -46,6 +46,7 @@ class ArrayBufferView : public RefCounted<ArrayBufferView> { virtual bool isIntArray() const { return false; } virtual bool isUnsignedIntArray() const { return false; } virtual bool isFloatArray() const { return false; } + virtual bool isDoubleArray() const { return false; } virtual bool isDataView() const { return false; } PassRefPtr<ArrayBuffer> buffer() const diff --git a/Source/WebCore/html/canvas/Float64Array.cpp b/Source/WebCore/html/canvas/Float64Array.cpp new file mode 100644 index 0000000..2dcb373 --- /dev/null +++ b/Source/WebCore/html/canvas/Float64Array.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * 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 COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "Float64Array.h" + +namespace WebCore { + +PassRefPtr<Float64Array> Float64Array::create(unsigned length) +{ + return TypedArrayBase<double>::create<Float64Array>(length); +} + +PassRefPtr<Float64Array> Float64Array::create(const double* array, unsigned length) +{ + return TypedArrayBase<double>::create<Float64Array>(array, length); +} + +PassRefPtr<Float64Array> Float64Array::create(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned length) +{ + return TypedArrayBase<double>::create<Float64Array>(buffer, byteOffset, length); +} + +Float64Array::Float64Array(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned length) + : TypedArrayBase<double>(buffer, byteOffset, length) +{ +} + +PassRefPtr<Float64Array> Float64Array::subarray(int start) const +{ + return subarray(start, length()); +} + +PassRefPtr<Float64Array> Float64Array::subarray(int start, int end) const +{ + return subarrayImpl<Float64Array>(start, end); +} + +} diff --git a/Source/WebCore/html/canvas/Float64Array.h b/Source/WebCore/html/canvas/Float64Array.h new file mode 100644 index 0000000..f45a21c --- /dev/null +++ b/Source/WebCore/html/canvas/Float64Array.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * 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 COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef Float64Array_h +#define Float64Array_h + +#include "TypedArrayBase.h" +#include <wtf/MathExtras.h> + +namespace WebCore { + +class Float64Array : public TypedArrayBase<double> { +public: + static PassRefPtr<Float64Array> create(unsigned length); + static PassRefPtr<Float64Array> create(const double* array, unsigned length); + static PassRefPtr<Float64Array> create(PassRefPtr<ArrayBuffer>, unsigned byteOffset, unsigned length); + + using TypedArrayBase<double>::set; + + void set(unsigned index, double value) + { + if (index >= TypedArrayBase<double>::m_length) + return; + TypedArrayBase<double>::data()[index] = static_cast<double>(value); + } + + // Invoked by the indexed getter. Does not perform range checks; caller + // is responsible for doing so and returning undefined as necessary. + double item(unsigned index) const + { + ASSERT(index < TypedArrayBase<double>::m_length); + double result = TypedArrayBase<double>::data()[index]; + return result; + } + + PassRefPtr<Float64Array> subarray(int start) const; + PassRefPtr<Float64Array> subarray(int start, int end) const; + +private: + Float64Array(PassRefPtr<ArrayBuffer>, + unsigned byteOffset, + unsigned length); + // Make constructor visible to superclass. + friend class TypedArrayBase<double>; + + // Overridden from ArrayBufferView. + virtual bool isDoubleArray() const { return true; } +}; + +} // namespace WebCore + +#endif // Float64Array_h diff --git a/Source/WebKit/android/benchmark/MyJavaVM.h b/Source/WebCore/html/canvas/Float64Array.idl index 3092161..6057253 100644 --- a/Source/WebKit/android/benchmark/MyJavaVM.h +++ b/Source/WebCore/html/canvas/Float64Array.idl @@ -1,16 +1,17 @@ /* - * Copyright 2009, The Android Open Source Project + * Copyright (C) 2011 Apple Inc. All rights reserved. + * 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: - * * Redistributions of source code must retain the above copyright + * 1. 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 + * 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 THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR @@ -23,12 +24,25 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef MyJavaVM_h -#define MyJavaVM_h +module html { + interface [ + CanBeConstructed, + CustomConstructFunction, + V8CustomConstructor, + HasNumericIndexGetter, + HasCustomIndexSetter, + GenerateNativeConverter, + NoStaticTables, + CustomToJS, + DontCheckEnums + ] Float64Array : ArrayBufferView { + const unsigned int BYTES_PER_ELEMENT = 8; -// Make it 1 just to appease any assertions or checks for valid objects -#define MY_JOBJECT ((jobject) 1) + readonly attribute unsigned long length; + Float64Array subarray(in long start, in [Optional] long end); -void InitializeJavaVM(); - -#endif + // void set(in Float64Array array, [Optional] in unsigned long offset); + // void set(in sequence<long> array, [Optional] in unsigned long offset); + [Custom] void set(); + }; +} diff --git a/Source/WebCore/html/parser/HTMLDocumentParser.cpp b/Source/WebCore/html/parser/HTMLDocumentParser.cpp index 8f95cc5..46dddf0 100644 --- a/Source/WebCore/html/parser/HTMLDocumentParser.cpp +++ b/Source/WebCore/html/parser/HTMLDocumentParser.cpp @@ -41,10 +41,6 @@ #include "NestingLevelIncrementer.h" #include "Settings.h" -#ifdef ANDROID_INSTRUMENT -#include "TimeCounter.h" -#endif - namespace WebCore { using namespace HTMLNames; @@ -318,10 +314,6 @@ void HTMLDocumentParser::insert(const SegmentedString& source) if (isStopped()) return; -#ifdef ANDROID_INSTRUMENT - android::TimeCounter::start(android::TimeCounter::ParsingTimeCounter); -#endif - // pumpTokenizer can cause this parser to be detached from the Document, // but we need to ensure it isn't deleted yet. RefPtr<HTMLDocumentParser> protect(this); @@ -369,18 +361,12 @@ void HTMLDocumentParser::append(const SegmentedString& source) // We've gotten data off the network in a nested write. // We don't want to consume any more of the input stream now. Do // not worry. We'll consume this data in a less-nested write(). -#ifdef ANDROID_INSTRUMENT - android::TimeCounter::record(android::TimeCounter::ParsingTimeCounter, __FUNCTION__); -#endif return; } pumpTokenizerIfPossible(AllowYield); endIfDelayed(); -#ifdef ANDROID_INSTRUMENT - android::TimeCounter::record(android::TimeCounter::ParsingTimeCounter, __FUNCTION__); -#endif } void HTMLDocumentParser::end() diff --git a/Source/WebCore/loader/FrameLoader.cpp b/Source/WebCore/loader/FrameLoader.cpp index 85b1541..f999fdb 100644 --- a/Source/WebCore/loader/FrameLoader.cpp +++ b/Source/WebCore/loader/FrameLoader.cpp @@ -119,11 +119,6 @@ #include "ArchiveFactory.h" #endif -#ifdef ANDROID_INSTRUMENT -#include "TimeCounter.h" -#include "RenderArena.h" -#endif - namespace WebCore { using namespace HTMLNames; @@ -1114,11 +1109,7 @@ void FrameLoader::handleFallbackContent() } void FrameLoader::provisionalLoadStarted() -{ -#ifdef ANDROID_INSTRUMENT - if (!m_frame->tree()->parent()) - android::TimeCounter::reset(); -#endif +{ if (m_stateMachine.firstLayoutDone()) m_stateMachine.advanceTo(FrameLoaderStateMachine::CommittedFirstRealLoad); m_frame->navigationScheduler()->cancel(true); @@ -2308,7 +2299,7 @@ void FrameLoader::finishedLoadingDocument(DocumentLoader* loader) if (m_stateMachine.creatingInitialEmptyDocument()) return; #endif - + #if !ENABLE(WEB_ARCHIVE) m_client->finishedLoading(loader); #else @@ -2499,12 +2490,6 @@ void FrameLoader::checkLoadCompleteForThisFrame() if (Page* page = m_frame->page()) page->progress()->progressCompleted(m_frame); - -#ifdef ANDROID_INSTRUMENT - if (!m_frame->tree()->parent() && m_frame->document()->renderArena()) - android::TimeCounter::report(m_URL, cache()->getLiveSize(), cache()->getDeadSize(), - m_frame->document()->renderArena()->reportPoolSize()); -#endif return; } diff --git a/Source/WebCore/loader/archive/android/WebArchiveAndroid.cpp b/Source/WebCore/loader/archive/android/WebArchiveAndroid.cpp index 55d7cec..5f60163 100644 --- a/Source/WebCore/loader/archive/android/WebArchiveAndroid.cpp +++ b/Source/WebCore/loader/archive/android/WebArchiveAndroid.cpp @@ -36,6 +36,7 @@ #include <libxml/tree.h> #include <libxml/xmlstring.h> #include <libxml/xmlwriter.h> +#include <utils/Log.h> #include <wtf/text/CString.h> namespace WebCore { @@ -117,7 +118,7 @@ static bool loadArchiveResourceField(xmlNodePtr resourceNode, const xmlChar* fie } } if (!base64Data) { - LOGD("loadArchiveResourceField: Failed to load field."); + ALOGD("loadArchiveResourceField: Failed to load field."); return false; } @@ -125,7 +126,7 @@ static bool loadArchiveResourceField(xmlNodePtr resourceNode, const xmlChar* fie const int result = base64Decode(base64Data, base64Size, *outputData); if (!result) { - LOGD("loadArchiveResourceField: Failed to decode field."); + ALOGD("loadArchiveResourceField: Failed to decode field."); return false; } @@ -165,37 +166,37 @@ static KURL loadArchiveResourceFieldURL(xmlNodePtr resourceNode, const xmlChar* static PassRefPtr<ArchiveResource> loadArchiveResource(xmlNodePtr resourceNode) { if (!xmlStrEqual(resourceNode->name, archiveResourceTag)) { - LOGD("loadArchiveResource: Malformed resource."); + ALOGD("loadArchiveResource: Malformed resource."); return 0; } KURL url = loadArchiveResourceFieldURL(resourceNode, urlFieldTag); if (url.isNull()) { - LOGD("loadArchiveResource: Failed to load resource."); + ALOGD("loadArchiveResource: Failed to load resource."); return 0; } String mimeType = loadArchiveResourceFieldString(resourceNode, mimeFieldTag); if (mimeType.isNull()) { - LOGD("loadArchiveResource: Failed to load resource."); + ALOGD("loadArchiveResource: Failed to load resource."); return 0; } String textEncoding = loadArchiveResourceFieldString(resourceNode, encodingFieldTag); if (textEncoding.isNull()) { - LOGD("loadArchiveResource: Failed to load resource."); + ALOGD("loadArchiveResource: Failed to load resource."); return 0; } String frameName = loadArchiveResourceFieldString(resourceNode, frameFieldTag); if (frameName.isNull()) { - LOGD("loadArchiveResource: Failed to load resource."); + ALOGD("loadArchiveResource: Failed to load resource."); return 0; } PassRefPtr<SharedBuffer> data = loadArchiveResourceFieldBuffer(resourceNode, dataFieldTag); if (!data) { - LOGD("loadArchiveResource: Failed to load resource."); + ALOGD("loadArchiveResource: Failed to load resource."); return 0; } @@ -211,7 +212,7 @@ static PassRefPtr<WebArchiveAndroid> loadArchive(xmlNodePtr archiveNode) Vector<PassRefPtr<Archive> > subframes; if (!xmlStrEqual(archiveNode->name, archiveTag)) { - LOGD("loadArchive: Malformed archive."); + ALOGD("loadArchive: Malformed archive."); return 0; } @@ -227,7 +228,7 @@ static PassRefPtr<WebArchiveAndroid> loadArchive(xmlNodePtr archiveNode) } } if (!mainResource) { - LOGD("loadArchive: Failed to load main resource."); + ALOGD("loadArchive: Failed to load main resource."); return 0; } @@ -240,7 +241,7 @@ static PassRefPtr<WebArchiveAndroid> loadArchive(xmlNodePtr archiveNode) resourceNode = resourceNode->next) { PassRefPtr<ArchiveResource> subresource = loadArchiveResource(resourceNode); if (!subresource) { - LOGD("loadArchive: Failed to load subresource."); + ALOGD("loadArchive: Failed to load subresource."); break; } subresources.append(subresource); @@ -258,7 +259,7 @@ static PassRefPtr<WebArchiveAndroid> loadArchive(xmlNodePtr archiveNode) resourceNode = resourceNode->next) { PassRefPtr<WebArchiveAndroid> subframe = loadArchive(resourceNode); if (!subframe) { - LOGD("loadArchive: Failed to load subframe."); + ALOGD("loadArchive: Failed to load subframe."); break; } subframes.append(subframe); @@ -290,20 +291,20 @@ PassRefPtr<WebArchiveAndroid> WebArchiveAndroid::create(SharedBuffer* buffer) xmlDocPtr doc = xmlReadMemory(buffer->data(), buffer->size(), noBaseUrl, defaultEncoding, noParserOptions); if (!doc) { - LOGD("create: Failed to parse document."); + ALOGD("create: Failed to parse document."); return createArchiveForError(); } xmlNodePtr root = xmlDocGetRootElement(doc); if (!root) { - LOGD("create: Empty document."); + ALOGD("create: Empty document."); xmlFreeDoc(doc); return createArchiveForError(); } RefPtr<WebArchiveAndroid> archive = loadArchive(root); if (!archive) { - LOGD("create: Failed to load archive."); + ALOGD("create: Failed to load archive."); xmlFreeDoc(doc); return createArchiveForError(); } @@ -316,7 +317,7 @@ static bool saveArchiveResourceField(xmlTextWriterPtr writer, const xmlChar* tag { int result = xmlTextWriterStartElement(writer, tag); if (result < 0) { - LOGD("saveArchiveResourceField: Failed to start element."); + ALOGD("saveArchiveResourceField: Failed to start element."); return false; } @@ -324,20 +325,20 @@ static bool saveArchiveResourceField(xmlTextWriterPtr writer, const xmlChar* tag Vector<char> base64Data; base64Encode(data, size, base64Data, false); if (base64Data.isEmpty()) { - LOGD("saveArchiveResourceField: Failed to base64 encode data."); + ALOGD("saveArchiveResourceField: Failed to base64 encode data."); return false; } result = xmlTextWriterWriteRawLen(writer, BAD_CAST base64Data.data(), base64Data.size()); if (result < 0) { - LOGD("saveArchiveResourceField: Failed to write data."); + ALOGD("saveArchiveResourceField: Failed to write data."); return false; } } result = xmlTextWriterEndElement(writer); if (result < 0) { - LOGD("saveArchiveResourceField: Failed to end element."); + ALOGD("saveArchiveResourceField: Failed to end element."); return false; } @@ -360,7 +361,7 @@ static bool saveArchiveResource(xmlTextWriterPtr writer, PassRefPtr<ArchiveResou { int result = xmlTextWriterStartElement(writer, archiveResourceTag); if (result < 0) { - LOGD("saveArchiveResource: Failed to start element."); + ALOGD("saveArchiveResource: Failed to start element."); return false; } @@ -373,7 +374,7 @@ static bool saveArchiveResource(xmlTextWriterPtr writer, PassRefPtr<ArchiveResou result = xmlTextWriterEndElement(writer); if (result < 0) { - LOGD("saveArchiveResource: Failed to end element."); + ALOGD("saveArchiveResource: Failed to end element."); return false; } @@ -384,13 +385,13 @@ static bool saveArchive(xmlTextWriterPtr writer, PassRefPtr<Archive> archive) { int result = xmlTextWriterStartElement(writer, archiveTag); if (result < 0) { - LOGD("saveArchive: Failed to start element."); + ALOGD("saveArchive: Failed to start element."); return false; } result = xmlTextWriterStartElement(writer, mainResourceTag); if (result < 0) { - LOGD("saveArchive: Failed to start element."); + ALOGD("saveArchive: Failed to start element."); return false; } @@ -399,13 +400,13 @@ static bool saveArchive(xmlTextWriterPtr writer, PassRefPtr<Archive> archive) result = xmlTextWriterEndElement(writer); if (result < 0) { - LOGD("saveArchive: Failed to end element."); + ALOGD("saveArchive: Failed to end element."); return false; } result = xmlTextWriterStartElement(writer, subresourcesTag); if (result < 0) { - LOGD("saveArchive: Failed to start element."); + ALOGD("saveArchive: Failed to start element."); return false; } @@ -418,13 +419,13 @@ static bool saveArchive(xmlTextWriterPtr writer, PassRefPtr<Archive> archive) result = xmlTextWriterEndElement(writer); if (result < 0) { - LOGD("saveArchive: Failed to end element."); + ALOGD("saveArchive: Failed to end element."); return false; } result = xmlTextWriterStartElement(writer, subframesTag); if (result < 0) { - LOGD("saveArchive: Failed to start element."); + ALOGD("saveArchive: Failed to start element."); return false; } @@ -437,7 +438,7 @@ static bool saveArchive(xmlTextWriterPtr writer, PassRefPtr<Archive> archive) result = xmlTextWriterEndElement(writer); if (result < 0) { - LOGD("saveArchive: Failed to end element."); + ALOGD("saveArchive: Failed to end element."); return true; } @@ -452,7 +453,7 @@ bool WebArchiveAndroid::saveWebArchive(xmlTextWriterPtr writer) int result = xmlTextWriterStartDocument(writer, defaultXmlVersion, defaultEncoding, defaultStandalone); if (result < 0) { - LOGD("saveWebArchive: Failed to start document."); + ALOGD("saveWebArchive: Failed to start document."); return false; } @@ -461,7 +462,7 @@ bool WebArchiveAndroid::saveWebArchive(xmlTextWriterPtr writer) result = xmlTextWriterEndDocument(writer); if (result< 0) { - LOGD("saveWebArchive: Failed to end document."); + ALOGD("saveWebArchive: Failed to end document."); return false; } diff --git a/Source/WebCore/loader/cache/MemoryCache.h b/Source/WebCore/loader/cache/MemoryCache.h index a092eac..c9b91f9 100644 --- a/Source/WebCore/loader/cache/MemoryCache.h +++ b/Source/WebCore/loader/cache/MemoryCache.h @@ -171,12 +171,6 @@ public: void removeResourcesWithOrigin(SecurityOrigin*); void getOriginsWithCache(SecurityOriginSet& origins); -#ifdef ANDROID_INSTRUMENT - unsigned getLiveSize() { return m_liveSize; } - unsigned getDeadSize() { return m_deadSize; } -#endif - - private: MemoryCache(); ~MemoryCache(); // Not implemented to make sure nobody accidentally calls delete -- WebCore does not delete singletons. diff --git a/Source/WebCore/loader/icon/IconDatabase.cpp b/Source/WebCore/loader/icon/IconDatabase.cpp index 3cefea7..2bb22ec 100644 --- a/Source/WebCore/loader/icon/IconDatabase.cpp +++ b/Source/WebCore/loader/icon/IconDatabase.cpp @@ -73,7 +73,7 @@ static const int updateTimerDelay = 5; static bool checkIntegrityOnOpen = false; -#ifndef NDEBUG +#if !LOG_DISABLED || !ERROR_DISABLED static String urlForLogging(const String& url) { static unsigned urlTruncationLength = 120; @@ -967,7 +967,7 @@ void* IconDatabase::iconDatabaseSyncThread() LOG(IconDatabase, "(THREAD) IconDatabase sync thread started"); -#ifndef NDEBUG +#if !LOG_DISABLED double startTime = currentTime(); #endif @@ -993,7 +993,7 @@ void* IconDatabase::iconDatabaseSyncThread() if (shouldStopThreadActivity()) return syncThreadMainLoop(); -#ifndef NDEBUG +#if !LOG_DISABLED double timeStamp = currentTime(); LOG(IconDatabase, "(THREAD) Open took %.4f seconds", timeStamp - startTime); #endif @@ -1002,7 +1002,7 @@ void* IconDatabase::iconDatabaseSyncThread() if (shouldStopThreadActivity()) return syncThreadMainLoop(); -#ifndef NDEBUG +#if !LOG_DISABLED double newStamp = currentTime(); LOG(IconDatabase, "(THREAD) performOpenInitialization() took %.4f seconds, now %.4f seconds from thread start", newStamp - timeStamp, newStamp - startTime); timeStamp = newStamp; @@ -1025,7 +1025,7 @@ void* IconDatabase::iconDatabaseSyncThread() if (shouldStopThreadActivity()) return syncThreadMainLoop(); -#ifndef NDEBUG +#if !LOG_DISABLED newStamp = currentTime(); LOG(IconDatabase, "(THREAD) performImport() took %.4f seconds, now %.4f seconds from thread start", newStamp - timeStamp, newStamp - startTime); timeStamp = newStamp; @@ -1042,7 +1042,7 @@ void* IconDatabase::iconDatabaseSyncThread() if (shouldStopThreadActivity()) return syncThreadMainLoop(); -#ifndef NDEBUG +#if !LOG_DISABLED newStamp = currentTime(); LOG(IconDatabase, "(THREAD) performURLImport() took %.4f seconds. Entering main loop %.4f seconds from thread start", newStamp - timeStamp, newStamp - startTime); #endif @@ -1358,7 +1358,7 @@ void* IconDatabase::syncThreadMainLoop() while (!m_threadTerminationRequested) { m_syncLock.unlock(); -#ifndef NDEBUG +#if !LOG_DISABLED double timeStamp = currentTime(); #endif LOG(IconDatabase, "(THREAD) Main work loop starting"); @@ -1391,7 +1391,7 @@ void* IconDatabase::syncThreadMainLoop() // has asked to delay pruning static bool prunedUnretainedIcons = false; if (didWrite && !m_privateBrowsingEnabled && !prunedUnretainedIcons && !databaseCleanupCounter) { -#ifndef NDEBUG +#if !LOG_DISABLED double time = currentTime(); #endif LOG(IconDatabase, "(THREAD) Starting pruneUnretainedIcons()"); @@ -1410,7 +1410,7 @@ void* IconDatabase::syncThreadMainLoop() break; } -#ifndef NDEBUG +#if !LOG_DISABLED double newstamp = currentTime(); LOG(IconDatabase, "(THREAD) Main work loop ran for %.4f seconds, %s requested to terminate", newstamp - timeStamp, shouldStopThreadActivity() ? "was" : "was not"); #endif @@ -1458,7 +1458,7 @@ bool IconDatabase::readFromDatabase() { ASSERT_ICON_SYNC_THREAD(); -#ifndef NDEBUG +#if !LOG_DISABLED double timeStamp = currentTime(); #endif @@ -1567,7 +1567,7 @@ bool IconDatabase::writeToDatabase() { ASSERT_ICON_SYNC_THREAD(); -#ifndef NDEBUG +#if !LOG_DISABLED double timeStamp = currentTime(); #endif @@ -1772,7 +1772,7 @@ void* IconDatabase::cleanupSyncThread() { ASSERT_ICON_SYNC_THREAD(); -#ifndef NDEBUG +#if !LOG_DISABLED double timeStamp = currentTime(); #endif @@ -1792,7 +1792,7 @@ void* IconDatabase::cleanupSyncThread() deleteAllPreparedStatements(); m_syncDB.close(); -#ifndef NDEBUG +#if !LOG_DISABLED LOG(IconDatabase, "(THREAD) Final closure took %.4f seconds", currentTime() - timeStamp); #endif diff --git a/Source/WebCore/page/DOMWindow.idl b/Source/WebCore/page/DOMWindow.idl index 9f7313c..d5d3413 100644 --- a/Source/WebCore/page/DOMWindow.idl +++ b/Source/WebCore/page/DOMWindow.idl @@ -510,6 +510,7 @@ module window { attribute [JSCCustomGetter] Int32ArrayConstructor Int32Array; // Usable with new operator attribute [JSCCustomGetter] Uint32ArrayConstructor Uint32Array; // Usable with new operator attribute [JSCCustomGetter] Float32ArrayConstructor Float32Array; // Usable with new operator + attribute [JSCCustomGetter] Float64ArrayConstructor Float64Array; // Usable with new operator attribute [JSCCustomGetter] DataViewConstructor DataView; // Usable with new operator attribute [JSCCustomGetter,Conditional=WEB_AUDIO,EnabledAtRuntime] AudioContextConstructor webkitAudioContext; // Usable with new operator 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/page/Frame.cpp b/Source/WebCore/page/Frame.cpp index 8a1ad69..049f08b 100644 --- a/Source/WebCore/page/Frame.cpp +++ b/Source/WebCore/page/Frame.cpp @@ -113,10 +113,6 @@ #include "WMLNames.h" #endif -#if PLATFORM(ANDROID) -#include "WebViewCore.h" -#endif - using namespace std; namespace WebCore { diff --git a/Source/WebCore/page/FrameView.cpp b/Source/WebCore/page/FrameView.cpp index 49a7d0c..a79910b 100644 --- a/Source/WebCore/page/FrameView.cpp +++ b/Source/WebCore/page/FrameView.cpp @@ -62,11 +62,6 @@ #include "TextResourceDecoder.h" #include <wtf/CurrentTime.h> -#ifdef ANDROID_INSTRUMENT -#include "FrameTree.h" -#include "TimeCounter.h" -#endif - #if USE(ACCELERATED_COMPOSITING) #include "RenderLayerCompositor.h" #endif @@ -872,11 +867,6 @@ void FrameView::layout(bool allowSubtree) return; } -#ifdef ANDROID_INSTRUMENT - if (!m_frame->tree() || !m_frame->tree()->parent()) - android::TimeCounter::start(android::TimeCounter::LayoutTimeCounter); -#endif - m_nestedLayoutCount++; if (!m_layoutRoot) { @@ -1014,10 +1004,6 @@ void FrameView::layout(bool allowSubtree) updateDashboardRegions(); #endif -#ifdef ANDROID_INSTRUMENT - if (!m_frame->tree()->parent()) - android::TimeCounter::record(android::TimeCounter::LayoutTimeCounter, __FUNCTION__); -#endif ASSERT(!root->needsLayout()); updateCanBlitOnScrollRecursively(); diff --git a/Source/WebCore/page/Settings.cpp b/Source/WebCore/page/Settings.cpp index e2312a9..c26a0fc 100644 --- a/Source/WebCore/page/Settings.cpp +++ b/Source/WebCore/page/Settings.cpp @@ -98,6 +98,7 @@ Settings::Settings(Page* page) #ifdef ANDROID_LAYOUT , m_layoutAlgorithm(kLayoutFitColumnToScreen) #endif + , m_passwordEchoDurationInSeconds(1) , m_isSpatialNavigationEnabled(false) , m_isJavaEnabled(false) , m_loadsImagesAutomatically(false) @@ -192,6 +193,11 @@ Settings::Settings(Page* page) #ifdef ANDROID_PLUGINS , m_pluginsOnDemand(false) #endif +#if OS(SYMBIAN) + , m_passwordEchoEnabled(true) +#else + , m_passwordEchoEnabled(false) +#endif { // A Frame may not have been created yet, so we initialize the AtomicString // hash before trying to use it. diff --git a/Source/WebCore/page/Settings.h b/Source/WebCore/page/Settings.h index 31a5ad9..2bb222d 100644 --- a/Source/WebCore/page/Settings.h +++ b/Source/WebCore/page/Settings.h @@ -458,6 +458,12 @@ namespace WebCore { void setShouldInjectUserScriptsInInitialEmptyDocument(bool flag) { m_shouldInjectUserScriptsInInitialEmptyDocument = flag; } bool shouldInjectUserScriptsInInitialEmptyDocument() { return m_shouldInjectUserScriptsInInitialEmptyDocument; } + void setPasswordEchoEnabled(bool flag) { m_passwordEchoEnabled = flag; } + bool passwordEchoEnabled() const { return m_passwordEchoEnabled; } + + void setPasswordEchoDurationInSeconds(double durationInSeconds) { m_passwordEchoDurationInSeconds = durationInSeconds; } + double passwordEchoDurationInSeconds() const { return m_passwordEchoDurationInSeconds; } + #if ENABLE(WEB_AUTOFILL) void setAutoFillEnabled(bool flag) { m_autoFillEnabled = flag; } bool autoFillEnabled() { return m_autoFillEnabled; } @@ -511,6 +517,8 @@ namespace WebCore { #ifdef ANDROID_LAYOUT LayoutAlgorithm m_layoutAlgorithm; #endif + double m_passwordEchoDurationInSeconds; + bool m_isSpatialNavigationEnabled : 1; bool m_isJavaEnabled : 1; bool m_loadsImagesAutomatically : 1; @@ -617,6 +625,7 @@ namespace WebCore { #ifdef ANDROID_PLUGINS bool m_pluginsOnDemand : 1; #endif + bool m_passwordEchoEnabled : 1; #if USE(SAFARI_THEME) static bool gShouldPaintNativeControls; diff --git a/Source/WebCore/platform/Arena.cpp b/Source/WebCore/platform/Arena.cpp index 231e1b6..33980ed 100644 --- a/Source/WebCore/platform/Arena.cpp +++ b/Source/WebCore/platform/Arena.cpp @@ -255,16 +255,4 @@ void FinishArenaPool(ArenaPool *pool) FreeArenaList(pool, &pool->first, true); } -#ifdef ANDROID_INSTRUMENT -size_t ReportPoolSize(const ArenaPool* pool) -{ - size_t total = 0; - for (const Arena *a = &pool->first; a; a = a->next) - total += (a->limit - a->base); - for (const Arena *fa = arena_freelist; fa; fa = fa->next ) - total += (fa->limit - fa->base); - return total; -} -#endif - } diff --git a/Source/WebCore/platform/Arena.h b/Source/WebCore/platform/Arena.h index e937955..06e09f2 100644 --- a/Source/WebCore/platform/Arena.h +++ b/Source/WebCore/platform/Arena.h @@ -134,10 +134,6 @@ void* ArenaAllocate(ArenaPool *pool, unsigned int nb); fastFree(a); \ (a) = 0; -#ifdef ANDROID_INSTRUMENT -size_t ReportPoolSize(const ArenaPool* pool); -#endif - } #endif diff --git a/Source/WebCore/platform/NotImplemented.h b/Source/WebCore/platform/NotImplemented.h index a71e99c..e9758b0 100644 --- a/Source/WebCore/platform/NotImplemented.h +++ b/Source/WebCore/platform/NotImplemented.h @@ -38,21 +38,7 @@ #define supressNotImplementedWarning() false #endif -#if OS(ANDROID) - -#include <cutils/log.h> -#ifndef LOG_TAG -#define LOG_TAG "WebCore" -#endif -#define notImplemented() do { \ - static bool havePrinted = false; \ - if (!havePrinted && !supressNotImplementedWarning()) { \ - LOGV("%s: notImplemented", __PRETTY_FUNCTION__); \ - havePrinted = true; \ - } \ - } while (0) - -#elif defined(NDEBUG) +#if defined(NDEBUG) #define notImplemented() ((void)0) #else diff --git a/Source/WebCore/platform/ScrollView.cpp b/Source/WebCore/platform/ScrollView.cpp index e79f049..58a1fbf 100644 --- a/Source/WebCore/platform/ScrollView.cpp +++ b/Source/WebCore/platform/ScrollView.cpp @@ -27,6 +27,9 @@ #include "ScrollView.h" #include "AXObjectCache.h" +#if PLATFORM(ANDROID) +#include "FrameView.h" +#endif #include "GraphicsContext.h" #include "GraphicsLayer.h" #include "HostWindow.h" @@ -328,6 +331,14 @@ int ScrollView::actualScrollY() const return platformActualScrollY(); return scrollY(); } + +FrameView* ScrollView::frameView() { + if (this->isFrameView()) { + FrameView* frameView = reinterpret_cast<FrameView*>(this); + return frameView; + } + return 0; +} #endif IntPoint ScrollView::maximumScrollPosition() const diff --git a/Source/WebCore/platform/ScrollView.h b/Source/WebCore/platform/ScrollView.h index 558aee2..3228870 100644 --- a/Source/WebCore/platform/ScrollView.h +++ b/Source/WebCore/platform/ScrollView.h @@ -53,6 +53,10 @@ namespace WebCore { class HostWindow; class Scrollbar; +#if PLATFORM(ANDROID) +class FrameView; +#endif + class ScrollView : public Widget, public ScrollableArea { public: ~ScrollView(); @@ -172,6 +176,7 @@ public: int actualHeight() const; int actualScrollX() const; int actualScrollY() const; + FrameView* frameView(); #endif // Functions for querying the current scrolled position (both as a point, a size, or as individual X and Y values). diff --git a/Source/WebCore/platform/android/KeyEventAndroid.cpp b/Source/WebCore/platform/android/KeyEventAndroid.cpp index eaf34a9..dd1f37d 100644 --- a/Source/WebCore/platform/android/KeyEventAndroid.cpp +++ b/Source/WebCore/platform/android/KeyEventAndroid.cpp @@ -33,7 +33,7 @@ #include "NotImplemented.h" #include "WindowsKeyboardCodes.h" -#include <ui/KeycodeLabels.h> +#include <androidfw/KeycodeLabels.h> namespace WebCore { @@ -191,7 +191,7 @@ static String keyIdentifierForAndroidKeyCode(int keyCode) return "U+00007F"; default: char upper[16]; - sprintf(upper, "U+%06X", windowsKeyCodeForKeyEvent(keyCode)); + sprintf(upper, "U+%04X", windowsKeyCodeForKeyEvent(keyCode)); return String(upper); } } diff --git a/Source/WebCore/platform/android/PopupMenuAndroid.cpp b/Source/WebCore/platform/android/PopupMenuAndroid.cpp index f4c351f..a5758bb 100644 --- a/Source/WebCore/platform/android/PopupMenuAndroid.cpp +++ b/Source/WebCore/platform/android/PopupMenuAndroid.cpp @@ -25,10 +25,13 @@ #include "config.h" #include "PopupMenuAndroid.h" +#include "IntRect.h" #include "PopupMenuClient.h" #include "SkTDArray.h" #include "WebViewCore.h" +using namespace WebCore; + class PopupReply : public android::WebCoreReply { public: PopupReply(const IntRect& rect, android::WebViewCore* view, ListPopupMenuClient* client) diff --git a/Source/WebCore/platform/android/RenderThemeAndroid.cpp b/Source/WebCore/platform/android/RenderThemeAndroid.cpp index 93c99a4..ee406c2 100644 --- a/Source/WebCore/platform/android/RenderThemeAndroid.cpp +++ b/Source/WebCore/platform/android/RenderThemeAndroid.cpp @@ -38,10 +38,8 @@ #include "RenderMediaControls.h" #endif #include "RenderSkinAndroid.h" -#include "RenderSkinButton.h" -#include "RenderSkinCombo.h" #include "RenderSkinMediaButton.h" -#include "RenderSkinRadio.h" +#include "RoundedIntRect.h" #include "SkCanvas.h" #include "UserAgentStyleSheets.h" #include "WebCoreFrameBridge.h" @@ -63,6 +61,31 @@ const int listboxPadding = 5; const RGBA32 selectionColor = makeRGB(181, 224, 136); +// Colors copied from the holo resources +const RGBA32 defaultBgColor = makeRGBA(204, 204, 204, 197); +const RGBA32 defaultBgBright = makeRGBA(213, 213, 213, 221); +const RGBA32 defaultBgDark = makeRGBA(92, 92, 92, 160); +const RGBA32 defaultBgMedium = makeRGBA(132, 132, 132, 111); +const RGBA32 defaultFgColor = makeRGBA(101, 101, 101, 225); +const RGBA32 defaultCheckColor = makeRGBA(154, 204, 2, 255); + +const RGBA32 disabledBgColor = makeRGBA(205, 205, 205, 107); +const RGBA32 disabledBgBright = makeRGBA(213, 213, 213, 133); +const RGBA32 disabledBgDark = makeRGBA(92, 92, 92, 96); +const RGBA32 disabledBgMedium = makeRGBA(132, 132, 132, 111); +const RGBA32 disabledFgColor = makeRGBA(148, 148, 148, 137); + +const int paddingButton = 2; +const int cornerButton = 2; + +// scale factors for various resolutions +const float scaleFactor[RenderSkinAndroid::ResolutionCount] = { + 1.0f, // medium res + 1.5f, // high res + 2.0f // extra high res +}; + + static SkCanvas* getCanvasFromInfo(const PaintInfo& info) { return info.context->platformContext()->mCanvas; @@ -158,6 +181,16 @@ Color RenderThemeAndroid::platformInactiveListBoxSelectionForegroundColor() cons return Color(Color::transparent); } +Color RenderThemeAndroid::platformActiveTextSearchHighlightColor() const +{ + return Color(0x00, 0x99, 0xcc, 0x99); // HOLO_DARK +} + +Color RenderThemeAndroid::platformInactiveTextSearchHighlightColor() const +{ + return Color(0x33, 0xb5, 0xe5, 0x66); // HOLO_LIGHT +} + int RenderThemeAndroid::baselinePosition(const RenderObject* obj) const { // From the description of this function in RenderTheme.h: @@ -166,7 +199,7 @@ int RenderThemeAndroid::baselinePosition(const RenderObject* obj) const // controls that need to do this. // // Our checkboxes and radio buttons need to be offset to line up properly. - return RenderTheme::baselinePosition(obj) - 2; + return RenderTheme::baselinePosition(obj) - 8; } void RenderThemeAndroid::addIntrinsicMargins(RenderStyle* style) const @@ -174,10 +207,10 @@ void RenderThemeAndroid::addIntrinsicMargins(RenderStyle* style) const // Cut out the intrinsic margins completely if we end up using a small font size if (style->fontSize() < 11) return; - + // Intrinsic margin value. const int m = 2; - + // FIXME: Using width/height alone and not also dealing with min-width/max-width is flawed. if (style->width().isIntrinsicOrAuto()) { if (style->marginLeft().quirk()) @@ -210,22 +243,11 @@ bool RenderThemeAndroid::supportsFocus(ControlPart appearance) void RenderThemeAndroid::adjustButtonStyle(CSSStyleSelector*, RenderStyle* style, WebCore::Element*) const { - // Code is taken from RenderThemeSafari.cpp - // It makes sure we have enough space for the button text. - const int paddingHoriz = 12; - const int paddingVert = 8; - style->setPaddingLeft(Length(paddingHoriz, Fixed)); - style->setPaddingRight(Length(paddingHoriz, Fixed)); - style->setPaddingTop(Length(paddingVert, Fixed)); - style->setPaddingBottom(Length(paddingVert, Fixed)); - - // Set a min-height so that we can't get smaller than the mini button. - style->setMinHeight(Length(15, Fixed)); } bool RenderThemeAndroid::paintCheckbox(RenderObject* obj, const PaintInfo& info, const IntRect& rect) { - RenderSkinRadio::Draw(getCanvasFromInfo(info), obj->node(), rect, true); + paintRadio(obj, info, rect); return false; } @@ -237,16 +259,50 @@ bool RenderThemeAndroid::paintButton(RenderObject* obj, const PaintInfo& info, c if (formControlElement) { android::WebFrame* webFrame = getWebFrame(node); if (webFrame) { - RenderSkinAndroid* skins = webFrame->renderSkins(); - if (skins) { - RenderSkinAndroid::State state = RenderSkinAndroid::kNormal; - if (!formControlElement->isEnabledFormControl()) - state = RenderSkinAndroid::kDisabled; - skins->renderSkinButton()->draw(getCanvasFromInfo(info), rect, state); + GraphicsContext *context = info.context; + IntRect innerrect = IntRect(rect.x() + paddingButton, rect.y() + paddingButton, + rect.width() - 2 * paddingButton, rect.height() - 2 * paddingButton); + IntSize cornerrect = IntSize(cornerButton, cornerButton); + Color bg, bright, dark, medium; + if (formControlElement->isEnabledFormControl()) { + bg = Color(defaultBgColor); + bright = Color(defaultBgBright); + dark = Color(defaultBgDark); + medium = Color(defaultBgMedium); + } else { + bg = Color(disabledBgColor); + bright = Color(disabledBgBright); + dark = Color(disabledBgDark); + medium = Color(disabledBgMedium); } + context->save(); + context->clip( + IntRect(innerrect.x(), innerrect.y(), innerrect.width(), 1)); + context->fillRoundedRect(innerrect, cornerrect, cornerrect, + cornerrect, cornerrect, bright, context->fillColorSpace()); + context->restore(); + context->save(); + context->clip(IntRect(innerrect.x(), innerrect.y() + innerrect.height() - 1, + innerrect.width(), 1)); + context->fillRoundedRect(innerrect, cornerrect, cornerrect, + cornerrect, cornerrect, dark, context->fillColorSpace()); + context->restore(); + context->save(); + context->clip(IntRect(innerrect.x(), innerrect.y() + 1, innerrect.width(), + innerrect.height() - 2)); + context->fillRoundedRect(innerrect, cornerrect, cornerrect, + cornerrect, cornerrect, bg, context->fillColorSpace()); + context->restore(); + context->setStrokeColor(medium, context->strokeColorSpace()); + context->setStrokeThickness(1.0f); + context->drawLine(IntPoint(innerrect.x(), innerrect.y() + cornerButton), + IntPoint(innerrect.x(), innerrect.y() + innerrect.height() - cornerButton)); + context->drawLine(IntPoint(innerrect.x() + innerrect.width(), innerrect.y() + cornerButton), + IntPoint(innerrect.x() + innerrect.width(), innerrect.y() + innerrect.height() - cornerButton)); } } + // We always return false so we do not request to be redrawn. return false; } @@ -336,7 +392,9 @@ bool RenderThemeAndroid::paintMediaControlsBackground(RenderObject* o, const Pai bool translucent = false; if (o && toParentMediaElement(o) && toParentMediaElement(o)->hasTagName(HTMLNames::videoTag)) translucent = true; - RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, RenderSkinMediaButton::BACKGROUND_SLIDER, translucent); + RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, + RenderSkinMediaButton::BACKGROUND_SLIDER, + translucent, 0, false); return false; } @@ -355,7 +413,9 @@ bool RenderThemeAndroid::paintMediaSliderThumb(RenderObject* o, const PaintInfo& bool translucent = false; if (o && toParentMediaElement(o) && toParentMediaElement(o)->hasTagName(HTMLNames::videoTag)) translucent = true; - RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, RenderSkinMediaButton::SLIDER_THUMB, translucent); + RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, + RenderSkinMediaButton::SLIDER_THUMB, + translucent, 0, false); return false; } @@ -373,7 +433,49 @@ void RenderThemeAndroid::adjustSliderThumbSize(RenderObject* o) const bool RenderThemeAndroid::paintRadio(RenderObject* obj, const PaintInfo& info, const IntRect& rect) { - RenderSkinRadio::Draw(getCanvasFromInfo(info), obj->node(), rect, false); + Node* node = obj->node(); + Element* element = static_cast<Element*>(node); + if (element) { + InputElement* input = element->toInputElement(); + GraphicsContext* context = info.context; + if (!element->isEnabledFormControl()) { + context->setAlpha(0.5f); + } + const IntRect inner = IntRect(rect.x() - 2, rect.y() - 2, rect.width() - 4, rect.height() - 4); + context->setFillColor(Color(defaultBgBright), context->fillColorSpace()); + context->setStrokeColor(Color(defaultBgBright), context->strokeColorSpace()); + context->setStrokeThickness(1.0f); + if (input->isCheckbox()) { + context->drawRect(inner); + } else { + context->drawEllipse(inner); + } + context->setStrokeColor(Color(defaultFgColor), context->strokeColorSpace()); + if (input->isCheckbox()) { + context->drawRect(IntRect(inner.x() + 2, inner.y() + 2, inner.width() -4, inner.height() - 4)); + } else { + context->drawEllipse(IntRect(inner.x() + 2, inner.y() + 2, inner.width() -4, inner.height() - 4)); + } + if (input->isChecked()) { + context->setFillColor(Color(defaultCheckColor), context->fillColorSpace()); + context->setStrokeColor(Color(defaultCheckColor), context->strokeColorSpace()); + if (input->isCheckbox()) { + const float w2 = ((float) rect.width() / 2); + const float cx = ((float) rect.x()); + const float cy = ((float) rect.y()); + context->save(); + // magic numbers due to weird scale in context + context->translate(cx + w2 / 2.2f, cy + w2 / 1.2f); + context->rotate(3.93f); // 225 degrees + context->drawRect(IntRect(0, 0, rect.width() / 4, 2)); + context->rotate(1.57f); // 90 degrees + context->drawRect(IntRect(0, 0, rect.width() / 2, 2)); + context->restore(); + } else { + context->drawEllipse(IntRect(inner.x() + 5, inner.y() + 5, inner.width() - 10, inner.height() - 10)); + } + } + } return false; } @@ -396,7 +498,7 @@ void RenderThemeAndroid::adjustTextFieldStyle(CSSStyleSelector*, RenderStyle* st bool RenderThemeAndroid::paintTextField(RenderObject*, const PaintInfo&, const IntRect&) { - return true; + return true; } void RenderThemeAndroid::adjustTextAreaStyle(CSSStyleSelector*, RenderStyle* style, WebCore::Element*) const @@ -418,25 +520,29 @@ void RenderThemeAndroid::adjustSearchFieldStyle(CSSStyleSelector*, RenderStyle* bool RenderThemeAndroid::paintSearchField(RenderObject*, const PaintInfo&, const IntRect&) { - return true; + return true; } static void adjustMenuListStyleCommon(RenderStyle* style) { // Added to make room for our arrow and make the touch target less cramped. - style->setPaddingLeft(Length(RenderSkinCombo::padding(), Fixed)); - style->setPaddingTop(Length(RenderSkinCombo::padding(), Fixed)); - style->setPaddingBottom(Length(RenderSkinCombo::padding(), Fixed)); - style->setPaddingRight(Length(RenderSkinCombo::extraWidth(), Fixed)); - style->setMinHeight(Length(RenderSkinCombo::minHeight(), Fixed)); + const int padding = (int)(scaleFactor[RenderSkinAndroid::DrawableResolution()] + 0.5f); + style->setPaddingLeft(Length(padding,Fixed)); + style->setPaddingTop(Length(padding, Fixed)); + style->setPaddingBottom(Length(padding, Fixed)); + // allocate height as arrow size + int arrow = std::max(18, style->fontMetrics().height() + 2 * padding); + style->setPaddingRight(Length(arrow, Fixed)); + style->setMinHeight(Length(arrow, Fixed)); + style->setHeight(Length(arrow, Fixed)); } -void RenderThemeAndroid::adjustListboxStyle(CSSStyleSelector*, RenderStyle* style, Element*) const +void RenderThemeAndroid::adjustListboxStyle(CSSStyleSelector*, RenderStyle* style, Element* e) const { adjustMenuListButtonStyle(0, style, 0); } -void RenderThemeAndroid::adjustMenuListStyle(CSSStyleSelector*, RenderStyle* style, Element* e) const +void RenderThemeAndroid::adjustMenuListStyle(CSSStyleSelector*, RenderStyle* style, Element*) const { adjustMenuListStyleCommon(style); addIntrinsicMargins(style); @@ -446,11 +552,55 @@ bool RenderThemeAndroid::paintCombo(RenderObject* obj, const PaintInfo& info, c { if (obj->style() && !obj->style()->visitedDependentColor(CSSPropertyBackgroundColor).alpha()) return true; - return RenderSkinCombo::Draw(getCanvasFromInfo(info), obj->node(), rect.x(), rect.y(), rect.width(), rect.height()); + Node* node = obj->node(); + Element* element = static_cast<Element*>(node); + if (element) { + InputElement* input = element->toInputElement(); + GraphicsContext* context = info.context; + if (!element->isEnabledFormControl()) { + context->setAlpha(0.5f); + } + IntRect bounds = IntRect(rect.x(), rect.y(), rect.width(), rect.height()); + // paint bg color + RenderStyle* style = obj->style(); + context->setFillColor(style->visitedDependentColor(CSSPropertyBackgroundColor), + context->fillColorSpace()); + context->fillRect(FloatRect(bounds)); + // copied form the original RenderSkinCombo: + // If this is an appearance where RenderTheme::paint returns true + // without doing anything, this means that + // RenderBox::PaintBoxDecorationWithSize will end up painting the + // border, so we shouldn't paint a border here. + if (style->appearance() != MenulistButtonPart && + style->appearance() != ListboxPart && + style->appearance() != TextFieldPart && + style->appearance() != TextAreaPart) { + const int arrowSize = bounds.height(); + // dropdown button bg + context->setFillColor(Color(defaultBgColor), context->fillColorSpace()); + context->fillRect(FloatRect(bounds.maxX() - arrowSize + 0.5f, bounds.y() + .5f, + arrowSize - 1, bounds.height() - 1)); + // outline + context->setStrokeThickness(1.0f); + context->setStrokeColor(Color(defaultBgDark), context->strokeColorSpace()); + context->strokeRect(bounds, 1.0f); + // arrow + context->setFillColor(Color(defaultFgColor), context->fillColorSpace()); + Path tri = Path(); + tri.clear(); + const float aw = arrowSize - 10; + FloatPoint br = FloatPoint(bounds.maxX() - 4, bounds.maxY() - 4); + tri.moveTo(br); + tri.addLineTo(FloatPoint(br.x() - aw, br.y())); + tri.addLineTo(FloatPoint(br.x(), br.y() - aw)); + context->fillPath(tri); + } + } + return false; } -bool RenderThemeAndroid::paintMenuList(RenderObject* obj, const PaintInfo& info, const IntRect& rect) -{ +bool RenderThemeAndroid::paintMenuList(RenderObject* obj, const PaintInfo& info, const IntRect& rect) +{ return paintCombo(obj, info, rect); } @@ -461,13 +611,13 @@ void RenderThemeAndroid::adjustMenuListButtonStyle(CSSStyleSelector*, const float baseFontSize = 11.0f; const int baseBorderRadius = 5; float fontScale = style->fontSize() / baseFontSize; - + style->resetPadding(); style->setBorderRadius(IntSize(int(baseBorderRadius + fontScale - 1), int(baseBorderRadius + fontScale - 1))); // FIXME: Round up? const int minHeight = 15; style->setMinHeight(Length(minHeight, Fixed)); - + style->setLineHeight(RenderStyle::initialLineHeight()); // Found these padding numbers by trial and error. const int padding = 4; @@ -476,26 +626,23 @@ void RenderThemeAndroid::adjustMenuListButtonStyle(CSSStyleSelector*, adjustMenuListStyleCommon(style); } -bool RenderThemeAndroid::paintMenuListButton(RenderObject* obj, const PaintInfo& info, const IntRect& rect) +bool RenderThemeAndroid::paintMenuListButton(RenderObject* obj, const PaintInfo& info, const IntRect& rect) { return paintCombo(obj, info, rect); } +Color RenderThemeAndroid::platformFocusRingColor() const +{ + static Color focusRingColor(0x33, 0xB5, 0xE5, 0x66); + return focusRingColor; +} + bool RenderThemeAndroid::supportsFocusRing(const RenderStyle* style) const { - return style->opacity() > 0 - && style->hasAppearance() - && style->appearance() != TextFieldPart - && style->appearance() != SearchFieldPart - && style->appearance() != TextAreaPart - && style->appearance() != CheckboxPart - && style->appearance() != RadioPart - && style->appearance() != PushButtonPart - && style->appearance() != SquareButtonPart - && style->appearance() != ButtonPart - && style->appearance() != ButtonBevelPart - && style->appearance() != MenulistPart - && style->appearance() != MenulistButtonPart; + // Draw the focus ring ourselves unless it is a text area (webkit does borders better) + if (!style || !style->hasAppearance()) + return true; + return style->appearance() != TextFieldPart && style->appearance() != TextAreaPart; } } // namespace WebCore diff --git a/Source/WebCore/platform/android/RenderThemeAndroid.h b/Source/WebCore/platform/android/RenderThemeAndroid.h index e3922a1..ed4d07f 100644 --- a/Source/WebCore/platform/android/RenderThemeAndroid.h +++ b/Source/WebCore/platform/android/RenderThemeAndroid.h @@ -31,10 +31,6 @@ namespace WebCore { -class RenderSkinButton; -class RenderSkinRadio; -class RenderSkinCombo; - struct ThemeData { ThemeData() : m_part(0) @@ -52,7 +48,7 @@ public: ~RenderThemeAndroid(); virtual bool stateChanged(RenderObject*, ControlState) const; - + virtual bool supportsFocusRing(const RenderStyle*) const; // A method asking if the theme's controls actually care about redrawing when hovered. virtual bool supportsHover(const RenderStyle* style) const { return style->affectedByHoverRules(); } @@ -64,12 +60,16 @@ public: virtual Color platformActiveSelectionForegroundColor() const; virtual Color platformInactiveSelectionForegroundColor() const; virtual Color platformTextSearchHighlightColor() const; + virtual Color platformFocusRingColor() const; virtual Color platformActiveListBoxSelectionBackgroundColor() const; virtual Color platformInactiveListBoxSelectionBackgroundColor() const; virtual Color platformActiveListBoxSelectionForegroundColor() const; virtual Color platformInactiveListBoxSelectionForegroundColor() const; + virtual Color platformActiveTextSearchHighlightColor() const; + virtual Color platformInactiveTextSearchHighlightColor() const; + virtual void systemFont(int, WebCore::FontDescription&) const {} virtual int minimumMenuListSize(RenderStyle*) const { return 0; } diff --git a/Source/WebCore/platform/android/ScrollViewAndroid.cpp b/Source/WebCore/platform/android/ScrollViewAndroid.cpp index f29e998..8df0c2f 100644 --- a/Source/WebCore/platform/android/ScrollViewAndroid.cpp +++ b/Source/WebCore/platform/android/ScrollViewAndroid.cpp @@ -98,8 +98,6 @@ int ScrollView::platformActualScrollY() const void ScrollView::platformSetScrollPosition(const WebCore::IntPoint& pt) { - if (parent()) // don't attempt to scroll subframes; they're fully visible - return; PlatformBridge::setScrollPosition(this, m_scrollOrigin.x() + pt.x(), m_scrollOrigin.y() + pt.y()); } diff --git a/Source/WebCore/platform/android/SharedTimerAndroid.cpp b/Source/WebCore/platform/android/SharedTimerAndroid.cpp index e4f3b36..a3f3db5 100644 --- a/Source/WebCore/platform/android/SharedTimerAndroid.cpp +++ b/Source/WebCore/platform/android/SharedTimerAndroid.cpp @@ -51,7 +51,7 @@ void setSharedTimerFireTime(double fireTime) { long long timeInMs = static_cast<long long>((fireTime - WTF::currentTime()) * 1000); - LOGV("setSharedTimerFireTime: in %ld millisec", timeInMs); + ALOGV("setSharedTimerFireTime: in %ld millisec", timeInMs); if (JavaSharedClient::GetTimerClient()) JavaSharedClient::GetTimerClient()->setSharedTimer(timeInMs); } diff --git a/Source/WebCore/platform/android/TemporaryLinkStubs.cpp b/Source/WebCore/platform/android/TemporaryLinkStubs.cpp index ca9f24d..7df3e8c 100644 --- a/Source/WebCore/platform/android/TemporaryLinkStubs.cpp +++ b/Source/WebCore/platform/android/TemporaryLinkStubs.cpp @@ -80,13 +80,6 @@ #include <wtf/MainThread.h> #include <wtf/text/CString.h> -#if USE(JSC) -#include "API/JSClassRef.h" -#include "JNIUtilityPrivate.h" -#include "JavaScriptCallFrame.h" -#include "ScriptDebugServer.h" -#endif - using namespace WebCore; /********************************************************/ @@ -394,18 +387,6 @@ PassRefPtr<SharedBuffer> SharedBuffer::createWithContentsOfFile(const String&) } -#if USE(JSC) -namespace JSC { namespace Bindings { -bool dispatchJNICall(ExecState*, const void* targetAppletView, jobject obj, bool isStatic, JavaType returnType, - jmethodID methodID, jvalue* args, jvalue& result, const char* callingURL, JSValue& exceptionDescription) -{ - notImplemented(); - return false; -} - -} } // namespace Bindings -#endif - char* dirname(const char*) { notImplemented(); diff --git a/Source/WebCore/platform/graphics/Color.h b/Source/WebCore/platform/graphics/Color.h index 02ec005..0fb355b 100644 --- a/Source/WebCore/platform/graphics/Color.h +++ b/Source/WebCore/platform/graphics/Color.h @@ -162,15 +162,8 @@ public: static const RGBA32 lightGray = 0xFFC0C0C0; static const RGBA32 transparent = 0x00000000; -#ifdef ANDROID_CSS_RING - 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; -#endif #ifdef ANDROID_CSS_TAP_HIGHLIGHT_COLOR - static const RGBA32 tap = 0x4D1A1A1A; + static const RGBA32 tap = 0x6633B5E5; #endif private: 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 9c7716c..524f986 100644 --- a/Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp @@ -131,7 +131,7 @@ void BaseLayerAndroid::prefetchBasePicture(SkRect& viewport, float currentScale, viewport.fTop, viewport.fRight, viewport.fBottom, - scale); + currentScale); bounds.fLeft = static_cast<int>(floorf(viewport.fLeft * invTileWidth)) - PREFETCH_X_DIST; bounds.fTop = static_cast<int>(floorf(viewport.fTop * invTileHeight)) - PREFETCH_Y_DIST; @@ -141,7 +141,7 @@ void BaseLayerAndroid::prefetchBasePicture(SkRect& viewport, float currentScale, XLOG("prefetch rect %d %d %d %d, scale %f, preparing page %p", bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, - scale * PREFETCH_SCALE, + prefetchScale, prefetchTiledPage); prefetchTiledPage->setScale(prefetchScale); @@ -290,8 +290,8 @@ bool BaseLayerAndroid::prepareBasePictureInGL(SkRect& viewport, float scale, tiledPage->prepare(goingDown, goingLeft, preZoomBounds, TiledPage::ExpandedBounds); - XLOG("scrolling %d, zooming %d, needsRedraw %d", - scrolling, zooming, needsRedraw); + XLOG("scrollState %d, zooming %d, needsRedraw %d", + m_scrollState, zooming, needsRedraw); // prefetch in the nextTiledPage if unused by zooming (even if not scrolling // since we want the tiles to be ready before they're needed) @@ -320,6 +320,8 @@ void BaseLayerAndroid::drawBasePictureInGL() void BaseLayerAndroid::updateLayerPositions(SkRect& visibleRect) { LayerAndroid* compositedRoot = static_cast<LayerAndroid*>(getChild(0)); + if (!compositedRoot) + return; TransformationMatrix ident; compositedRoot->updateFixedLayersPositions(visibleRect); FloatRect clip(0, 0, content()->width(), content()->height()); @@ -361,6 +363,7 @@ bool BaseLayerAndroid::drawGL(IntRect& viewRect, SkRect& visibleRect, // TODO: consider moving drawBackground outside of prepare (into tree manager) m_state->drawBackground(m_color); drawBasePictureInGL(); + m_state->glExtras()->drawGL(0); bool needsRedraw = false; diff --git a/Source/WebCore/platform/graphics/android/BaseRenderer.cpp b/Source/WebCore/platform/graphics/android/BaseRenderer.cpp index 57baee8..b708ad1 100644 --- a/Source/WebCore/platform/graphics/android/BaseRenderer.cpp +++ b/Source/WebCore/platform/graphics/android/BaseRenderer.cpp @@ -141,7 +141,13 @@ int BaseRenderer::renderTiledContent(const TileRenderInfo& renderInfo) // only color the invalidated area SkPaint invalPaint; invalPaint.setARGB(color, 0, 255, 0); - canvas.drawIRect(*renderInfo.invalRect, invalPaint); + if (renderInfo.invalRect) + canvas.drawIRect(*renderInfo.invalRect, invalPaint); + else { + SkIRect rect; + rect.set(0, 0, tileSize.width(), tileSize.height()); + canvas.drawIRect(rect, invalPaint); + } // paint the tile boundaries SkPaint paint; @@ -154,6 +160,18 @@ int BaseRenderer::renderTiledContent(const TileRenderInfo& renderInfo) canvas.drawLine(0, 0, tileSize.width(), 0, paint); canvas.drawLine(tileSize.width(), 0, tileSize.width(), tileSize.height(), paint); + if (renderInfo.invalRect) { + // if partial inval... + int x = renderInfo.invalRect->fLeft; + int y = renderInfo.invalRect->fTop; + int w = renderInfo.invalRect->width(); + int h = renderInfo.invalRect->height(); + + paint.setARGB(128, 255, 255, 0); + canvas.drawLine(x, y, x + w, y + h, paint); + canvas.drawLine(x, y + h, x + w, y, paint); + } + if (renderInfo.measurePerf) drawTileInfo(&canvas, renderInfo, pictureCount); } diff --git a/Source/WebCore/platform/graphics/android/BaseTile.cpp b/Source/WebCore/platform/graphics/android/BaseTile.cpp index 27bd482..42d02a5 100644 --- a/Source/WebCore/platform/graphics/android/BaseTile.cpp +++ b/Source/WebCore/platform/graphics/android/BaseTile.cpp @@ -54,6 +54,13 @@ #endif // DEBUG +// If the dirty portion of a tile exceeds this ratio, fully repaint. +// Lower values give fewer partial repaints, thus fewer front-to-back +// texture copies (cost will vary by device). It's a tradeoff between +// the rasterization cost and the FBO texture recopy cost when using +// GPU for the transfer queue. +#define MAX_INVAL_AREA 0.6 + namespace WebCore { BaseTile::BaseTile(bool isLayerTile) @@ -68,6 +75,7 @@ BaseTile::BaseTile(bool isLayerTile) , m_dirty(true) , m_repaintPending(false) , m_lastDirtyPicture(0) + , m_fullRepaint(true) , m_isTexturePainted(false) , m_isLayerTile(isLayerTile) , m_drawCount(0) @@ -76,20 +84,6 @@ BaseTile::BaseTile(bool isLayerTile) #ifdef DEBUG_COUNT ClassTracker::instance()->increment("BaseTile"); #endif - m_currentDirtyAreaIndex = 0; - - // For EglImage Mode, the internal buffer should be 2. - // For Surface Texture mode, we only need one. - if (TilesManager::instance()->getSharedTextureMode() == EglImageMode) - m_maxBufferNumber = 2; - else - m_maxBufferNumber = 1; - - m_dirtyArea = new SkRegion[m_maxBufferNumber]; - m_fullRepaint = new bool[m_maxBufferNumber]; - for (int i = 0; i < m_maxBufferNumber; i++) - m_fullRepaint[i] = true; - m_renderer = BaseRenderer::createRenderer(); } @@ -101,8 +95,6 @@ BaseTile::~BaseTile() m_frontTexture->release(this); delete m_renderer; - delete[] m_dirtyArea; - delete[] m_fullRepaint; #ifdef DEBUG_COUNT ClassTracker::instance()->decrement("BaseTile"); @@ -181,8 +173,7 @@ void BaseTile::markAsDirty(int unsigned pictureCount, return; android::AutoMutex lock(m_atomicSync); m_lastDirtyPicture = pictureCount; - for (int i = 0; i < m_maxBufferNumber; i++) - m_dirtyArea[i].op(dirtyArea, SkRegion::kUnion_Op); + m_dirtyArea.op(dirtyArea, SkRegion::kUnion_Op); // Check if we actually intersect with the area bool intersect = false; @@ -262,25 +253,11 @@ void BaseTile::draw(float transparency, SkRect& rect, float scale) if (!isTexturePainted) return; - TextureInfo* textureInfo = m_frontTexture->consumerLock(); - if (!textureInfo) { - m_frontTexture->consumerRelease(); - return; - } - - if (m_frontTexture->readyFor(this)) { - if (isLayerTile() && m_painter && m_painter->transform()) - TilesManager::instance()->shader()->drawLayerQuad(*m_painter->transform(), - rect, m_frontTexture->m_ownTextureId, - transparency, true); - else - TilesManager::instance()->shader()->drawQuad(rect, m_frontTexture->m_ownTextureId, - transparency); - } else { + if (m_frontTexture->readyFor(this)) + m_frontTexture->draw(isLayerTile(), m_painter, rect, transparency); + else { XLOG("tile %p at %d, %d not readyfor (at draw),", this, m_x, m_y); } - - m_frontTexture->consumerRelease(); } bool BaseTile::isTileReady() @@ -301,9 +278,7 @@ bool BaseTile::isTileReady() if (m_state != ReadyToSwap && m_state != UpToDate) return false; - texture->consumerLock(); bool ready = texture->readyFor(this); - texture->consumerRelease(); if (ready) return true; @@ -350,7 +325,7 @@ void BaseTile::paintBitmap() m_atomicSync.lock(); bool dirty = m_dirty; BaseTileTexture* texture = m_backTexture; - SkRegion dirtyArea = m_dirtyArea[m_currentDirtyAreaIndex]; + SkRegion dirtyArea = m_dirtyArea; float scale = m_scale; const int x = m_x; const int y = m_y; @@ -365,15 +340,12 @@ void BaseTile::paintBitmap() this, m_state, m_frontTexture, m_backTexture); } m_state = PaintingStarted; - - texture->producerAcquireContext(); - TextureInfo* textureInfo = texture->producerLock(); + TextureInfo* textureInfo = texture->getTextureInfo(); m_atomicSync.unlock(); // at this point we can safely check the ownership (if the texture got // transferred to another BaseTile under us) if (texture->owner() != this) { - texture->producerRelease(); return; } @@ -381,7 +353,6 @@ void BaseTile::paintBitmap() // swap out the renderer if necessary BaseRenderer::swapRendererIfNeeded(m_renderer); - // setup the common renderInfo fields; TileRenderInfo renderInfo; renderInfo.x = x; @@ -399,82 +370,81 @@ void BaseTile::paintBitmap() bool fullRepaint = false; - if (m_fullRepaint[m_currentDirtyAreaIndex] + if (m_fullRepaint || textureInfo->m_width != tileWidth || textureInfo->m_height != tileHeight) { fullRepaint = true; } - bool surfaceTextureMode = textureInfo->getSharedTextureMode() == SurfaceTextureMode; - - if (surfaceTextureMode) - fullRepaint = true; - - while (!fullRepaint && !cliperator.done()) { - SkRect realTileRect; - SkRect dirtyRect; - dirtyRect.set(cliperator.rect()); - bool intersect = intersectWithRect(x, y, tileWidth, tileHeight, - scale, dirtyRect, realTileRect); - - // With SurfaceTexture, just repaint the entire tile if we intersect - // TODO: Implement the partial invalidate in Surface Texture Mode - if (intersect && surfaceTextureMode) { - fullRepaint = true; - break; - } - - if (intersect && !surfaceTextureMode) { - // initialize finalRealRect to the rounded values of realTileRect - SkIRect finalRealRect; - realTileRect.roundOut(&finalRealRect); - - // stash the int values of the current width and height - const int iWidth = finalRealRect.width(); - const int iHeight = finalRealRect.height(); - - if (iWidth == tileWidth || iHeight == tileHeight) { - fullRepaint = true; - break; + // For now, only do full repaint + fullRepaint = true; + + if (!fullRepaint) { + // compute the partial inval area + SkIRect totalRect; + totalRect.set(0, 0, 0, 0); + float tileSurface = tileWidth * tileHeight; + float tileSurfaceCap = MAX_INVAL_AREA * tileSurface; + + // We join all the invals in the same tile for now + while (!fullRepaint && !cliperator.done()) { + SkRect realTileRect; + SkRect dirtyRect; + dirtyRect.set(cliperator.rect()); + bool intersect = intersectWithRect(x, y, tileWidth, tileHeight, + scale, dirtyRect, realTileRect); + if (intersect) { + // initialize finalRealRect to the rounded values of realTileRect + SkIRect finalRealRect; + realTileRect.roundOut(&finalRealRect); + + // stash the int values of the current width and height + const int iWidth = finalRealRect.width(); + const int iHeight = finalRealRect.height(); + + if (iWidth == tileWidth || iHeight == tileHeight) { + fullRepaint = true; + break; + } + + // translate the rect into tile space coordinates + finalRealRect.fLeft = finalRealRect.fLeft % static_cast<int>(tileWidth); + finalRealRect.fTop = finalRealRect.fTop % static_cast<int>(tileHeight); + finalRealRect.fRight = finalRealRect.fLeft + iWidth; + finalRealRect.fBottom = finalRealRect.fTop + iHeight; + totalRect.join(finalRealRect); + float repaintSurface = totalRect.width() * totalRect.height(); + + if (repaintSurface > tileSurfaceCap) { + fullRepaint = true; + break; + } } - // translate the rect into tile space coordinates - finalRealRect.fLeft = finalRealRect.fLeft % static_cast<int>(tileWidth); - finalRealRect.fTop = finalRealRect.fTop % static_cast<int>(tileHeight); - finalRealRect.fRight = finalRealRect.fLeft + iWidth; - finalRealRect.fBottom = finalRealRect.fTop + iHeight; + cliperator.next(); + } - renderInfo.invalRect = &finalRealRect; + if (!fullRepaint) { + renderInfo.invalRect = &totalRect; renderInfo.measurePerf = false; - pictureCount = m_renderer->renderTiledContent(renderInfo); } - - cliperator.next(); } // Do a full repaint if needed if (fullRepaint) { - SkIRect rect; - rect.set(0, 0, tileWidth, tileHeight); - - renderInfo.invalRect = ▭ + renderInfo.invalRect = 0; renderInfo.measurePerf = TilesManager::instance()->getShowVisualIndicator(); - pictureCount = m_renderer->renderTiledContent(renderInfo); } m_atomicSync.lock(); -#if DEPRECATED_SURFACE_TEXTURE_MODE - texture->setTile(textureInfo, x, y, scale, painter, pictureCount); -#endif - texture->producerReleaseAndSwap(); if (texture == m_backTexture) { m_isTexturePainted = true; // set the fullrepaint flags - m_fullRepaint[m_currentDirtyAreaIndex] = false; + m_fullRepaint = false; // The various checks to see if we are still dirty... @@ -484,19 +454,11 @@ void BaseTile::paintBitmap() m_dirty = true; if (fullRepaint) - m_dirtyArea[m_currentDirtyAreaIndex].setEmpty(); + m_dirtyArea.setEmpty(); else - m_dirtyArea[m_currentDirtyAreaIndex].op(dirtyArea, SkRegion::kDifference_Op); - - if (!m_dirtyArea[m_currentDirtyAreaIndex].isEmpty()) - m_dirty = true; - - // Now we can swap the dirty areas - // TODO: For surface texture in Async mode, the index will be updated - // according to the current buffer just dequeued. - m_currentDirtyAreaIndex = (m_currentDirtyAreaIndex+1) % m_maxBufferNumber; + m_dirtyArea.op(dirtyArea, SkRegion::kDifference_Op); - if (!m_dirtyArea[m_currentDirtyAreaIndex].isEmpty()) + if (!m_dirtyArea.isEmpty()) m_dirty = true; XLOG("painted tile %p (%d, %d), texture %p, dirty=%d", this, x, y, texture, m_dirty); @@ -522,10 +484,9 @@ void BaseTile::discardTextures() { m_backTexture->release(this); m_backTexture = 0; } - for (int i = 0; i < m_maxBufferNumber; i++) { - m_dirtyArea[i].setEmpty(); - m_fullRepaint[i] = true; - } + m_dirtyArea.setEmpty(); + m_fullRepaint = true; + m_dirty = true; m_state = Unpainted; } @@ -589,9 +550,12 @@ void BaseTile::validatePaint() { // when both have happened, mark as 'ReadyToSwap' if (m_state == PaintingStarted) m_state = ValidatedUntransferred; - else if (m_state == TransferredUnvalidated) + else if (m_state == TransferredUnvalidated) { + // When the backTexture has been marked pureColor, we will skip the + // transfer and marked as ReadyToSwap, in this case, we don't want + // to reset m_dirty bit to true. m_state = ReadyToSwap; - else { + } else { XLOG("Note: validated tile %p at %d %d, state wasn't paintingstarted or transferred %d", this, m_x, m_y, m_state); // failed transferring, in which case mark dirty (since diff --git a/Source/WebCore/platform/graphics/android/BaseTile.h b/Source/WebCore/platform/graphics/android/BaseTile.h index 685ca43..ed06332 100644 --- a/Source/WebCore/platform/graphics/android/BaseTile.h +++ b/Source/WebCore/platform/graphics/android/BaseTile.h @@ -172,10 +172,8 @@ private: unsigned int m_lastDirtyPicture; // store the dirty region - SkRegion* m_dirtyArea; - bool* m_fullRepaint; - int m_maxBufferNumber; - int m_currentDirtyAreaIndex; + SkRegion m_dirtyArea; + bool m_fullRepaint; // flag used to know if we have a texture that was painted at least once bool m_isTexturePainted; diff --git a/Source/WebCore/platform/graphics/android/BaseTileTexture.cpp b/Source/WebCore/platform/graphics/android/BaseTileTexture.cpp index caaf116..04d0fc9 100644 --- a/Source/WebCore/platform/graphics/android/BaseTileTexture.cpp +++ b/Source/WebCore/platform/graphics/android/BaseTileTexture.cpp @@ -53,17 +53,12 @@ namespace WebCore { BaseTileTexture::BaseTileTexture(uint32_t w, uint32_t h) - : DoubleBufferedTexture(eglGetCurrentContext(), - TilesManager::instance()->getSharedTextureMode()) - , m_owner(0) - , m_busy(false) + : m_owner(0) + , m_isPureColor(false) { m_size.set(w, h); m_ownTextureId = 0; - // Make sure they are created on the UI thread. - TilesManager::instance()->transferQueue()->initSharedSurfaceTextures(w, h); - #ifdef DEBUG_COUNT ClassTracker::instance()->increment("BaseTileTexture"); #endif @@ -71,10 +66,6 @@ BaseTileTexture::BaseTileTexture(uint32_t w, uint32_t h) BaseTileTexture::~BaseTileTexture() { - if (m_sharedTextureMode == EglImageMode) { - SharedTexture* textures[3] = { m_textureA, m_textureB, 0 }; - destroyTextures(textures); - } #ifdef DEBUG_COUNT ClassTracker::instance()->decrement("BaseTileTexture"); #endif @@ -98,71 +89,6 @@ void BaseTileTexture::discardGLTexture() } } -void BaseTileTexture::destroyTextures(SharedTexture** textures) -{ - int x = 0; - while (textures[x]) { - // We need to delete the source texture and EGLImage in the texture - // generation thread. In theory we should be able to delete the EGLImage - // from either thread, but it currently throws an error if not deleted - // in the same EGLContext from which it was created. - textures[x]->lock(); - DeleteTextureOperation* operation = new DeleteTextureOperation( - textures[x]->getSourceTextureId(), textures[x]->getEGLImage()); - textures[x]->unlock(); - TilesManager::instance()->scheduleOperation(operation); - x++; - } -} - -TextureInfo* BaseTileTexture::producerLock() -{ - m_busyLock.lock(); - m_busy = true; - m_busyLock.unlock(); - return DoubleBufferedTexture::producerLock(); -} - -void BaseTileTexture::producerRelease() -{ - DoubleBufferedTexture::producerRelease(); - setNotBusy(); -} - -void BaseTileTexture::producerReleaseAndSwap() -{ - DoubleBufferedTexture::producerReleaseAndSwap(); - setNotBusy(); -} - -void BaseTileTexture::setNotBusy() -{ - android::Mutex::Autolock lock(m_busyLock); - m_busy = false; - m_busyCond.signal(); -} - -bool BaseTileTexture::busy() -{ - android::Mutex::Autolock lock(m_busyLock); - return m_busy; -} - -void BaseTileTexture::producerUpdate(TextureInfo* textureInfo, const SkBitmap& bitmap) -{ - // no need to upload a texture since the bitmap is empty - if (!bitmap.width() && !bitmap.height()) { - producerRelease(); - return; - } - - // After the tiled layer checked in, this is not called anyway. - // TODO: cleanup the old code path for layer painting - // GLUtils::paintTextureWithBitmap(info, m_size, bitmap, 0, 0); - - producerReleaseAndSwap(); -} - bool BaseTileTexture::acquire(TextureOwner* owner, bool force) { if (m_owner == owner) @@ -173,39 +99,21 @@ bool BaseTileTexture::acquire(TextureOwner* owner, bool force) bool BaseTileTexture::setOwner(TextureOwner* owner, bool force) { - // if the writable texture is busy (i.e. currently being written to) then we - // can't change the owner out from underneath that texture - m_busyLock.lock(); - while (m_busy && force) - m_busyCond.wait(m_busyLock); - bool busy = m_busy; - m_busyLock.unlock(); - - if (!busy) { - // if we are not busy we can try to remove the texture from the layer; - // LayerAndroid::removeTexture() is protected by the same lock as - // LayerAndroid::paintBitmapGL(), so either we execute removeTexture() - // first and paintBitmapGL() will bail out, or we execute it after, - // and paintBitmapGL() will mark the texture as busy before - // relinquishing the lock. LayerAndroid::removeTexture() will call - // BaseTileTexture::release(), which will then do nothing - // if the texture is busy and we then don't return true. - bool proceed = true; - if (m_owner && m_owner != owner) - proceed = m_owner->removeTexture(this); - - if (proceed) { - m_owner = owner; - return true; - } + bool proceed = true; + if (m_owner && m_owner != owner) + proceed = m_owner->removeTexture(this); + + if (proceed) { + m_owner = owner; + return true; } + return false; } bool BaseTileTexture::release(TextureOwner* owner) { - android::Mutex::Autolock lock(m_busyLock); - XLOG("texture %p releasing tile %p, m_owner %p, m_busy %d", this, owner, m_owner, m_busy); + XLOG("texture %p releasing tile %p, m_owner %p", this, owner, m_owner); if (m_owner != owner) return false; @@ -213,22 +121,6 @@ bool BaseTileTexture::release(TextureOwner* owner) return true; } -void BaseTileTexture::setTile(TextureInfo* info, int x, int y, - float scale, TilePainter* painter, - unsigned int pictureCount) -{ - TextureTileInfo* textureInfo = m_texturesInfo.get(getWriteableTexture()); - if (!textureInfo) { - textureInfo = new TextureTileInfo(); - } - textureInfo->m_x = x; - textureInfo->m_y = y; - textureInfo->m_scale = scale; - textureInfo->m_painter = painter; - textureInfo->m_picture = pictureCount; - m_texturesInfo.set(getWriteableTexture(), textureInfo); -} - float BaseTileTexture::scale() { TextureTileInfo* textureInfo = &m_ownTextureTileInfo; @@ -255,6 +147,13 @@ void BaseTileTexture::setOwnTextureTileInfoFromQueue(const TextureTileInfo* info bool BaseTileTexture::readyFor(BaseTile* baseTile) { const TextureTileInfo* info = &m_ownTextureTileInfo; + + if (isPureColor() && info->m_painter == baseTile->painter()) { + XLOG("ReadyFor saw a pureColor tile (%p) at (%d, %d), rgb %x", + this, baseTile->x(), baseTile->y(), pureColor().rgb()); + return true; + } + if (info && (info->m_x == baseTile->x()) && (info->m_y == baseTile->y()) && @@ -270,4 +169,24 @@ bool BaseTileTexture::readyFor(BaseTile* baseTile) return false; } +void BaseTileTexture::draw(bool isLayer, TilePainter* painter, + SkRect& rect, float transparency) +{ + ShaderProgram* shader = TilesManager::instance()->shader(); + if (isLayer && painter && painter->transform()) { + if (isPureColor()) { + shader->drawLayerQuad(*painter->transform(), rect, 0, transparency, + true, GL_TEXTURE_2D, pureColor()); + } else { + shader->drawLayerQuad(*painter->transform(), rect, m_ownTextureId, + transparency, true); + } + } else { + if (isPureColor()) + shader->drawQuad(rect, 0,transparency, pureColor()); + else + shader->drawQuad(rect, m_ownTextureId, transparency); + } +} + } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/BaseTileTexture.h b/Source/WebCore/platform/graphics/android/BaseTileTexture.h index cd8e78b..67eeeb9 100644 --- a/Source/WebCore/platform/graphics/android/BaseTileTexture.h +++ b/Source/WebCore/platform/graphics/android/BaseTileTexture.h @@ -26,10 +26,11 @@ #ifndef BaseTileTexture_h #define BaseTileTexture_h -#include "DoubleBufferedTexture.h" #include "GLWebViewState.h" +#include "TextureInfo.h" #include "TextureOwner.h" #include "TilePainter.h" +#include <GLES2/gl2.h> #include <SkBitmap.h> class SkCanvas; @@ -59,46 +60,29 @@ public: TilePainter* m_painter; unsigned int m_picture; bool m_inverted; + IntRect m_inval; }; -// DoubleBufferedTexture using a SkBitmap as backing mechanism -class BaseTileTexture : public DoubleBufferedTexture { +class BaseTileTexture { public: // This object is to be constructed on the consumer's thread and must have // a width and height greater than 0. BaseTileTexture(uint32_t w, uint32_t h); virtual ~BaseTileTexture(); - // these functions override their parent - virtual TextureInfo* producerLock(); - virtual void producerRelease(); - virtual void producerReleaseAndSwap(); - - // updates the texture with current bitmap and releases (and if needed also - // swaps) the texture. - virtual void producerUpdate(TextureInfo* textureInfo, const SkBitmap& bitmap); - // allows consumer thread to assign ownership of the texture to the tile. It // returns false if ownership cannot be transferred because the tile is busy bool acquire(TextureOwner* owner, bool force = false); bool release(TextureOwner* owner); - // removes Tile->Texture, and Texture->Tile links to fully discard the texture - void releaseAndRemoveFromTile(); - // set the texture owner if not busy. Return false if busy, true otherwise. bool setOwner(TextureOwner* owner, bool force = false); // private member accessor functions TextureOwner* owner() { return m_owner; } // only used by the consumer thread - bool busy(); - void setNotBusy(); - const SkSize& getSize() const { return m_size; } - void setTile(TextureInfo* info, int x, int y, float scale, - TilePainter* painter, unsigned int pictureCount); bool readyFor(BaseTile* baseTile); float scale(); @@ -110,29 +94,31 @@ public: void setOwnTextureTileInfoFromQueue(const TextureTileInfo* info); -protected: - HashMap<SharedTexture*, TextureTileInfo*> m_texturesInfo; + TextureInfo* getTextureInfo() { return &m_ownTextureInfo; } + + // Make sure the following pureColor getter/setter are only read/written + // in UI thread. Therefore no need for a lock. + void setPure(bool pure) { m_isPureColor = pure; } + bool isPureColor() {return m_isPureColor; } + void setPureColor(const Color& color) { m_pureColor = color; setPure(true); } + Color pureColor() { return m_pureColor; } + void draw(bool isLayer, TilePainter* painter, SkRect& rect, + float transparency); private: - void destroyTextures(SharedTexture** textures); TextureTileInfo m_ownTextureTileInfo; - + // TODO: Merge this info into the TextureTileInfo. + TextureInfo m_ownTextureInfo; SkSize m_size; SkBitmap::Config m_config; // BaseTile owning the texture, only modified by UI thread TextureOwner* m_owner; - // This values signals that the texture is currently in use by the consumer. - // This allows us to prevent the owner of the texture from changing while the - // consumer is holding a lock on the texture. - bool m_busy; - // We mutex protect the reads/writes of m_busy to ensure that we are reading - // the most up-to-date value even across processors in an SMP system. - android::Mutex m_busyLock; - // We use this condition variable to signal that the texture - // is not busy anymore - android::Condition m_busyCond; + // When the whole tile is single color, skip the transfer queue and draw + // it directly through shader. + bool m_isPureColor; + Color m_pureColor; }; } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/DoubleBufferedTexture.cpp b/Source/WebCore/platform/graphics/android/DoubleBufferedTexture.cpp deleted file mode 100644 index 4c5af9e..0000000 --- a/Source/WebCore/platform/graphics/android/DoubleBufferedTexture.cpp +++ /dev/null @@ -1,217 +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 "DoubleBufferedTexture.h" - -#include "ClassTracker.h" -#include "GLUtils.h" - -#define LOG_NDEBUG 1 -#define LOG_TAG "DoubleBufferedTexture.cpp" -#include <utils/Log.h> - -namespace WebCore { - -DoubleBufferedTexture::DoubleBufferedTexture(EGLContext sharedContext, SharedTextureMode mode) -{ - m_sharedTextureMode = mode; - - m_textureA = new SharedTexture(m_sharedTextureMode); - if (m_sharedTextureMode == EglImageMode) - m_textureB = new SharedTexture(m_sharedTextureMode); - else - m_textureB = 0; - - m_display = eglGetCurrentDisplay(); - m_pContext = EGL_NO_CONTEXT; - m_cContext = sharedContext; - m_writeableTexture = m_textureA; - m_lockedConsumerTexture = GL_NO_TEXTURE; - m_supportsEGLImage = GLUtils::isEGLImageSupported(); -#ifdef DEBUG_COUNT - ClassTracker::instance()->increment("DoubleBufferedTexture"); -#endif -} - -DoubleBufferedTexture::~DoubleBufferedTexture() -{ -#ifdef DEBUG_COUNT - ClassTracker::instance()->decrement("DoubleBufferedTexture"); -#endif - delete m_textureA; - delete m_textureB; -} - -SharedTexture* DoubleBufferedTexture::getWriteableTexture() -{ - if (m_sharedTextureMode == SurfaceTextureMode) - return m_textureA; - return reinterpret_cast<SharedTexture*>( - android_atomic_release_load((int32_t*)&m_writeableTexture)); -} - -SharedTexture* DoubleBufferedTexture::getReadableTexture() -{ - if (m_sharedTextureMode == SurfaceTextureMode) - return m_textureA; - return (getWriteableTexture() != m_textureA) ? m_textureA : m_textureB; -} - -EGLContext DoubleBufferedTexture::producerAcquireContext() -{ - if (m_sharedTextureMode == SurfaceTextureMode) - return EGL_NO_CONTEXT; - - if (m_pContext != EGL_NO_CONTEXT) { - LOGV("AquireContext has previously generated a context.\n"); - return m_pContext; - } - - // check to see if a context already exists on this thread - EGLContext context = eglGetCurrentContext(); - - // if no context exists then create one - if (context == EGL_NO_CONTEXT) { - EGLContext sharedContext = m_supportsEGLImage ? EGL_NO_CONTEXT : m_cContext; - context = GLUtils::createBackgroundContext(sharedContext); - } - - if (context == EGL_NO_CONTEXT) { - LOGE("eglCreateContext failed"); - return EGL_NO_CONTEXT; - } - - // initialize the producer's textures - m_textureA->lock(); - if (m_sharedTextureMode == EglImageMode) - m_textureB->lock(); - - m_textureA->initSourceTexture(); - LOGV("Initialized Textures A (%d)", m_textureA->getSourceTextureId()); - if (m_sharedTextureMode == EglImageMode) { - m_textureB->initSourceTexture(); - LOGV("Initialized Textures B (%d)", m_textureB->getSourceTextureId()); - } - - m_textureA->unlock(); - if (m_sharedTextureMode == EglImageMode) - m_textureB->unlock(); - - m_pContext = context; - return context; -} - -// For MediaTexture only -void DoubleBufferedTexture::producerDeleteTextures() -{ - m_textureA->lock(); - if (m_sharedTextureMode == EglImageMode) - m_textureB->lock(); - - LOGV("Deleting Producer Textures A (%d)", m_textureA->getSourceTextureId()); - m_textureA->deleteSourceTexture(); - if (m_sharedTextureMode == EglImageMode){ - LOGV("Deleting Producer Textures B (%d)", m_textureB->getSourceTextureId()); - m_textureB->deleteSourceTexture(); - } - - m_textureA->unlock(); - if (m_sharedTextureMode == EglImageMode) - m_textureB->unlock(); -} - -// For MediaTexture only -void DoubleBufferedTexture::consumerDeleteTextures() -{ - m_textureA->lock(); - if (m_sharedTextureMode == EglImageMode) - m_textureB->lock(); - - LOGV("Deleting Consumer Textures A (%d)", m_textureA->getTargetTextureId()); - m_textureA->deleteTargetTexture(); - if (m_sharedTextureMode == EglImageMode) { - LOGV("Deleting Consumer Textures B (%d)", m_textureB->getTargetTextureId()); - m_textureB->deleteTargetTexture(); - } - - m_textureA->unlock(); - if (m_sharedTextureMode == EglImageMode) - m_textureB->unlock(); -} - -TextureInfo* DoubleBufferedTexture::producerLock() -{ - SharedTexture* sharedTex = getWriteableTexture(); - LOGV("Acquiring P Lock (%d)", sharedTex->getSourceTextureId()); - TextureInfo* texInfo = sharedTex->lockSource(); - LOGV("Acquired P Lock"); - - return texInfo; -} - -void DoubleBufferedTexture::producerRelease() -{ - // get the writable texture and unlock it - SharedTexture* sharedTex = getWriteableTexture(); - LOGV("Releasing P Lock (%d)", sharedTex->getSourceTextureId()); - sharedTex->releaseSource(); - LOGV("Released P Lock (%d)", sharedTex->getSourceTextureId()); -} - -void DoubleBufferedTexture::producerReleaseAndSwap() -{ - producerRelease(); - if (m_sharedTextureMode == EglImageMode) { - // swap the front and back buffers using an atomic op for the memory barrier - android_atomic_acquire_store((int32_t)getReadableTexture(), (int32_t*)&m_writeableTexture); - } -} - -TextureInfo* DoubleBufferedTexture::consumerLock() -{ - SharedTexture* sharedTex = getReadableTexture(); - LOGV("Acquiring C Lock (%d)", sharedTex->getSourceTextureId()); - m_lockedConsumerTexture = sharedTex; - - TextureInfo* texInfo = sharedTex->lockTarget(); - LOGV("Acquired C Lock"); - - if (!texInfo) - LOGV("Released C Lock (Empty)"); - - return texInfo; -} - -void DoubleBufferedTexture::consumerRelease() -{ - // we must check to see what texture the consumer had locked since the - // producer may have swapped out the readable buffer - SharedTexture* sharedTex = m_lockedConsumerTexture; - sharedTex->releaseTarget(); - LOGV("Released C Lock (%d)", sharedTex->getSourceTextureId()); -} - -} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/DoubleBufferedTexture.h b/Source/WebCore/platform/graphics/android/DoubleBufferedTexture.h deleted file mode 100644 index 821b79b..0000000 --- a/Source/WebCore/platform/graphics/android/DoubleBufferedTexture.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2010, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef DoubleBufferedTexture_h -#define DoubleBufferedTexture_h - -#include "SharedTexture.h" -#include <EGL/egl.h> - -namespace WebCore { - -class DoubleBufferedTexture { -public: - // consumer thread functions - DoubleBufferedTexture(EGLContext sharedContext, SharedTextureMode mode); - virtual ~DoubleBufferedTexture(); - - // provider thread functions - virtual TextureInfo* producerLock(); - virtual void producerRelease(); - virtual void producerReleaseAndSwap(); - EGLContext producerAcquireContext(); - void producerDeleteTextures(); - - // consumer thread functions - TextureInfo* consumerLock(); - void consumerRelease(); - void consumerDeleteTextures(); - -protected: - SharedTexture* getReadableTexture(); - SharedTexture* getWriteableTexture(); - - SharedTexture* m_textureA; - SharedTexture* m_textureB; - - SharedTextureMode m_sharedTextureMode; -private: - - SharedTexture* m_writeableTexture; - SharedTexture* m_lockedConsumerTexture; // only used by the consumer - - EGLDisplay m_display; - EGLContext m_pContext; - EGLContext m_cContext; - - bool m_supportsEGLImage; -}; - -} // namespace WebCore - -#endif // DoubleBufferedTexture_h diff --git a/Source/WebCore/platform/graphics/android/FontAndroid.cpp b/Source/WebCore/platform/graphics/android/FontAndroid.cpp index 0a8c0c1..ef7740c 100644 --- a/Source/WebCore/platform/graphics/android/FontAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/FontAndroid.cpp @@ -52,6 +52,7 @@ #include <wtf/OwnPtr.h> #include <wtf/PassOwnArrayPtr.h> #include <wtf/PassOwnPtr.h> +#include <wtf/unicode/CharacterNames.h> #include <wtf/unicode/Unicode.h> #endif @@ -379,7 +380,7 @@ static int truncateFixedPointToInteger(HB_Fixed value) // can call |reset| to start over again. class TextRunWalker { public: - TextRunWalker(const TextRun&, unsigned, const Font*); + TextRunWalker(const TextRun&, int, int, const Font*); ~TextRunWalker(); bool isWordBreak(unsigned, bool); @@ -425,10 +426,10 @@ public: // Return the length of the array returned by |glyphs| unsigned length() const { return m_item.num_glyphs; } - // Return the x offset for each of the glyphs. Note that this is translated + // Return the offset for each of the glyphs. Note that this is translated // by the current x offset and that the x offset is updated for each script // run. - const SkScalar* xPositions() const { return m_xPositions; } + const SkPoint* positions() const { return m_positions; } // Get the advances (widths) for each glyph. const HB_Fixed* advances() const { return m_item.advances; } @@ -472,7 +473,7 @@ private: void createGlyphArrays(int); void resetGlyphArrays(); void shapeGlyphs(); - void setGlyphXPositions(bool); + void setGlyphPositions(bool); static void normalizeSpacesAndMirrorChars(const UChar* source, bool rtl, UChar* destination, int length); @@ -485,10 +486,11 @@ private: const Font* const m_font; HB_ShaperItem m_item; uint16_t* m_glyphs16; // A vector of 16-bit glyph ids. - SkScalar* m_xPositions; // A vector of x positions for each glyph. + SkPoint* m_positions; // A vector of positions for each glyph. ssize_t m_indexOfNextScriptRun; // Indexes the script run in |m_run|. - const unsigned m_startingX; // Offset in pixels of the first script run. - unsigned m_offsetX; // Offset in pixels to the start of the next script run. + const int m_startingX; // Offset in pixels of the first script run. + const int m_startingY; // Offset in pixels of the first script run. + int m_offsetX; // Offset in pixels to the start of the next script run. unsigned m_pixelWidth; // Width (in px) of the current script run. unsigned m_numCodePoints; // Code points in current script run. unsigned m_glyphsArrayCapacity; // Current size of all the Harfbuzz arrays. @@ -519,9 +521,10 @@ const char* TextRunWalker::paths[] = { "/system/fonts/DroidSansThai.ttf" }; -TextRunWalker::TextRunWalker(const TextRun& run, unsigned startingX, const Font* font) +TextRunWalker::TextRunWalker(const TextRun& run, int startingX, int startingY, const Font* font) : m_font(font) , m_startingX(startingX) + , m_startingY(startingY) , m_offsetX(m_startingX) , m_run(getNormalizedTextRun(run, m_normalizedRun, m_normalizedBuffer)) , m_iterateBackwards(m_run.rtl()) @@ -650,7 +653,7 @@ bool TextRunWalker::nextScriptRun() setupFontForScriptRun(); shapeGlyphs(); - setGlyphXPositions(rtl()); + setGlyphPositions(rtl()); return true; } @@ -737,6 +740,16 @@ void TextRunWalker::setupFontForScriptRun() } m_item.face = complexPlatformData->harfbuzzFace(); m_item.font->userData = const_cast<FontPlatformData*>(complexPlatformData); + + int size = complexPlatformData->size(); + m_item.font->x_ppem = size; + m_item.font->y_ppem = size; + // x_ and y_scale are the conversion factors from font design space (fEmSize) to 1/64th of device pixels in 16.16 format. + const int devicePixelFraction = 64; + const int multiplyFor16Dot16 = 1 << 16; + int scale = devicePixelFraction * size * multiplyFor16Dot16 / complexPlatformData->emSizeInFontUnits(); + m_item.font->x_scale = scale; + m_item.font->y_scale = scale; } HB_FontRec* TextRunWalker::allocHarfbuzzFont() @@ -745,13 +758,6 @@ HB_FontRec* TextRunWalker::allocHarfbuzzFont() memset(font, 0, sizeof(HB_FontRec)); font->klass = &harfbuzzSkiaClass; font->userData = 0; - // The values which harfbuzzSkiaClass returns are already scaled to - // pixel units, so we just set all these to one to disable further - // scaling. - font->x_ppem = 1; - font->y_ppem = 1; - font->x_scale = 1; - font->y_scale = 1; return font; } @@ -763,7 +769,7 @@ void TextRunWalker::deleteGlyphArrays() delete[] m_item.advances; delete[] m_item.offsets; delete[] m_glyphs16; - delete[] m_xPositions; + delete[] m_positions; } void TextRunWalker::createGlyphArrays(int size) @@ -774,7 +780,7 @@ void TextRunWalker::createGlyphArrays(int size) m_item.offsets = new HB_FixedPoint[size]; m_glyphs16 = new uint16_t[size]; - m_xPositions = new SkScalar[size]; + m_positions = new SkPoint[size]; m_item.num_glyphs = size; m_glyphsArrayCapacity = size; // Save the GlyphArrays size. @@ -790,7 +796,7 @@ void TextRunWalker::resetGlyphArrays() memset(m_item.advances, 0, size * sizeof(m_item.advances[0])); memset(m_item.offsets, 0, size * sizeof(m_item.offsets[0])); memset(m_glyphs16, 0, size * sizeof(m_glyphs16[0])); - memset(m_xPositions, 0, size * sizeof(m_xPositions[0])); + memset(m_positions, 0, size * sizeof(m_positions[0])); } void TextRunWalker::shapeGlyphs() @@ -810,7 +816,7 @@ void TextRunWalker::shapeGlyphs() } } -void TextRunWalker::setGlyphXPositions(bool isRTL) +void TextRunWalker::setGlyphPositions(bool isRTL) { int position = 0; // logClustersIndex indexes logClusters for the first (or last when @@ -825,7 +831,9 @@ void TextRunWalker::setGlyphXPositions(bool isRTL) int i = isRTL ? m_item.num_glyphs - iter - 1 : iter; m_glyphs16[i] = m_item.glyphs[i]; - m_xPositions[i] = SkIntToScalar(m_offsetX + position); + int offsetX = truncateFixedPointToInteger(m_item.offsets[i].x); + int offsetY = truncateFixedPointToInteger(m_item.offsets[i].y); + m_positions[i].set(SkIntToScalar(m_offsetX + position) + offsetX, m_startingY + offsetY); int advance = truncateFixedPointToInteger(m_item.advances[i]); // The first half of the conjunction works around the case where @@ -846,6 +854,21 @@ void TextRunWalker::setGlyphXPositions(bool isRTL) } } + // ZeroWidthJoiners and ZeroWidthNonJoiners should be stripped by + // Harfbuzz, but aren't. Check for zwj and zwnj and replace with a + // zero width space. We get the glyph data for space instead of + // zeroWidthSpace because the latter was seen to render with an + // unexpected code point (the symbol for a cloud). Since the standard + // space is in page zero and since we've also confirmed that there is + // no advance on this glyph, that should be ok. + if (0 == m_item.advances[i]) { + const HB_UChar16 c = m_item.string[m_item.item.pos + logClustersIndex]; + if ((c == zeroWidthJoiner) || (c == zeroWidthNonJoiner)) { + static Glyph spaceGlyph = m_font->glyphDataForCharacter(space, false).glyph; + m_glyphs16[i] = spaceGlyph; + } + } + // TODO We would like to add m_letterSpacing after each cluster, but I // don't know where the cluster information is. This is typically // fine for Roman languages, but breaks more complex languages @@ -878,10 +901,14 @@ void TextRunWalker::normalizeSpacesAndMirrorChars(const UChar* source, bool rtl, UChar32 character; int nextPosition = position; U16_NEXT(source, nextPosition, length, character); + if (Font::treatAsSpace(character)) - character = ' '; + character = space; + else if (Font::treatAsZeroWidthSpaceInComplexScript(character)) + character = zeroWidthSpace; else if (rtl) character = u_charMirror(character); + U16_APPEND(destination, position, length, character, error); ASSERT(!error); position = nextPosition; @@ -947,7 +974,7 @@ FloatRect Font::selectionRectForComplexText(const TextRun& run, { int fromX = -1, toX = -1, fromAdvance = -1, toAdvance = -1; - TextRunWalker walker(run, 0, this); + TextRunWalker walker(run, 0, 0, this); walker.setWordAndLetterSpacing(wordSpacing(), letterSpacing()); // Base will point to the x offset for the current script run. Note that, in @@ -974,14 +1001,14 @@ FloatRect Font::selectionRectForComplexText(const TextRun& run, // find which glyph this code-point contributed to and find its x // position. int glyph = walker.logClusters()[from]; - fromX = base + walker.xPositions()[glyph]; + fromX = base + walker.positions()[glyph].x(); fromAdvance = walker.advances()[glyph]; } else from -= numCodePoints; if (toX == -1 && to < numCodePoints) { int glyph = walker.logClusters()[to]; - toX = base + walker.xPositions()[glyph]; + toX = base + walker.positions()[glyph].x(); toAdvance = walker.advances()[glyph]; } else to -= numCodePoints; @@ -1028,7 +1055,7 @@ void Font::drawComplexText(GraphicsContext* gc, TextRun const& run, SkCanvas* canvas = gc->platformContext()->mCanvas; bool haveMultipleLayers = isCanvasMultiLayered(canvas); - TextRunWalker walker(run, point.x(), this); + TextRunWalker walker(run, point.x(), point.y(), this); walker.setWordAndLetterSpacing(wordSpacing(), letterSpacing()); walker.setPadding(run.expansion()); @@ -1036,14 +1063,14 @@ void Font::drawComplexText(GraphicsContext* gc, TextRun const& run, if (fill) { walker.fontPlatformDataForScriptRun()->setupPaint(&fillPaint); adjustTextRenderMode(&fillPaint, haveMultipleLayers); - canvas->drawPosTextH(walker.glyphs(), walker.length() << 1, - walker.xPositions(), point.y(), fillPaint); + canvas->drawPosText(walker.glyphs(), walker.length() << 1, + walker.positions(), fillPaint); } if (stroke) { walker.fontPlatformDataForScriptRun()->setupPaint(&strokePaint); adjustTextRenderMode(&strokePaint, haveMultipleLayers); - canvas->drawPosTextH(walker.glyphs(), walker.length() << 1, - walker.xPositions(), point.y(), strokePaint); + canvas->drawPosText(walker.glyphs(), walker.length() << 1, + walker.positions(), strokePaint); } } } @@ -1051,7 +1078,7 @@ void Font::drawComplexText(GraphicsContext* gc, TextRun const& run, float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>*, GlyphOverflow*) const { - TextRunWalker walker(run, 0, this); + TextRunWalker walker(run, 0, 0, this); walker.setWordAndLetterSpacing(wordSpacing(), letterSpacing()); return walker.widthOfFullRun(); } @@ -1083,7 +1110,7 @@ int Font::offsetForPositionForComplexText(const TextRun& run, float x, { // (Mac code ignores includePartialGlyphs, and they don't know what it's // supposed to do, so we just ignore it as well.) - TextRunWalker walker(run, 0, this); + TextRunWalker walker(run, 0, 0, this); walker.setWordAndLetterSpacing(wordSpacing(), letterSpacing()); // If this is RTL text, the first glyph from the left is actually the last diff --git a/Source/WebCore/platform/graphics/android/FontPlatformData.h b/Source/WebCore/platform/graphics/android/FontPlatformData.h index 5c3313e..1e46971 100644 --- a/Source/WebCore/platform/graphics/android/FontPlatformData.h +++ b/Source/WebCore/platform/graphics/android/FontPlatformData.h @@ -82,6 +82,7 @@ public: float size() const { return mTextSize; } unsigned hash() const; + int emSizeInFontUnits() const; bool isFixedPitch() const; #ifndef NDEBUG @@ -113,6 +114,7 @@ private: SkTypeface* mTypeface; float mTextSize; + mutable int mEmSizeInFontUnits; bool mFakeBold; bool mFakeItalic; FontOrientation mOrientation; diff --git a/Source/WebCore/platform/graphics/android/FontPlatformDataAndroid.cpp b/Source/WebCore/platform/graphics/android/FontPlatformDataAndroid.cpp index 3c90246..fc254c0 100644 --- a/Source/WebCore/platform/graphics/android/FontPlatformDataAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/FontPlatformDataAndroid.cpp @@ -33,6 +33,7 @@ #ifdef SUPPORT_COMPLEX_SCRIPTS #include "HarfbuzzSkia.h" #endif +#include "SkAdvancedTypefaceMetrics.h" #include "SkPaint.h" #include "SkTypeface.h" @@ -74,7 +75,7 @@ FontPlatformData::RefCountedHarfbuzzFace::~RefCountedHarfbuzzFace() } FontPlatformData::FontPlatformData() - : mTypeface(NULL), mTextSize(0), mFakeBold(false), mFakeItalic(false), + : mTypeface(NULL), mTextSize(0), mEmSizeInFontUnits(0), mFakeBold(false), mFakeItalic(false), mOrientation(Horizontal), mTextOrientation(TextOrientationVerticalRight) { inc_count(); @@ -87,10 +88,10 @@ FontPlatformData::FontPlatformData(const FontPlatformData& src) SkSafeRef(src.mTypeface); } - mTypeface = src.mTypeface; - - mTextSize = src.mTextSize; - mFakeBold = src.mFakeBold; + mTypeface = src.mTypeface; + mTextSize = src.mTextSize; + mEmSizeInFontUnits = src.mEmSizeInFontUnits; + mFakeBold = src.mFakeBold; mFakeItalic = src.mFakeItalic; m_harfbuzzFace = src.m_harfbuzzFace; mOrientation = src.mOrientation; @@ -102,7 +103,7 @@ FontPlatformData::FontPlatformData(const FontPlatformData& src) FontPlatformData::FontPlatformData(SkTypeface* tf, float textSize, bool fakeBold, bool fakeItalic, FontOrientation orientation, TextOrientation textOrientation) - : mTypeface(tf), mTextSize(textSize), mFakeBold(fakeBold), mFakeItalic(fakeItalic), + : mTypeface(tf), mTextSize(textSize), mEmSizeInFontUnits(0), mFakeBold(fakeBold), mFakeItalic(fakeItalic), mOrientation(orientation), mTextOrientation(textOrientation) { if (hashTableDeletedFontValue() != mTypeface) { @@ -114,8 +115,8 @@ FontPlatformData::FontPlatformData(SkTypeface* tf, float textSize, bool fakeBold } FontPlatformData::FontPlatformData(const FontPlatformData& src, float textSize) - : mTypeface(src.mTypeface), mTextSize(textSize), mFakeBold(src.mFakeBold), mFakeItalic(src.mFakeItalic), - m_harfbuzzFace(src.m_harfbuzzFace), mOrientation(src.mOrientation), mTextOrientation(src.mTextOrientation) + : mTypeface(src.mTypeface), mTextSize(textSize), mEmSizeInFontUnits(src.mEmSizeInFontUnits), mFakeBold(src.mFakeBold), mFakeItalic(src.mFakeItalic), + mOrientation(src.mOrientation), mTextOrientation(src.mTextOrientation), m_harfbuzzFace(src.m_harfbuzzFace) { if (hashTableDeletedFontValue() != mTypeface) { SkSafeRef(mTypeface); @@ -126,7 +127,7 @@ FontPlatformData::FontPlatformData(const FontPlatformData& src, float textSize) } FontPlatformData::FontPlatformData(float size, bool bold, bool oblique) - : mTypeface(NULL), mTextSize(size), mFakeBold(bold), mFakeItalic(oblique), + : mTypeface(NULL), mTextSize(size), mEmSizeInFontUnits(0), mFakeBold(bold), mFakeItalic(oblique), mOrientation(Horizontal), mTextOrientation(TextOrientationVerticalRight) { inc_count(); @@ -134,7 +135,7 @@ FontPlatformData::FontPlatformData(float size, bool bold, bool oblique) } FontPlatformData::FontPlatformData(const FontPlatformData& src, SkTypeface* tf) - : mTypeface(tf), mTextSize(src.mTextSize), mFakeBold(src.mFakeBold), + : mTypeface(tf), mTextSize(src.mTextSize), mEmSizeInFontUnits(0), mFakeBold(src.mFakeBold), mFakeItalic(src.mFakeItalic), mOrientation(src.mOrientation), mTextOrientation(src.mTextOrientation) { @@ -158,6 +159,22 @@ FontPlatformData::~FontPlatformData() } } +int FontPlatformData::emSizeInFontUnits() const +{ + if (mEmSizeInFontUnits) + return mEmSizeInFontUnits; + + SkAdvancedTypefaceMetrics* metrics = 0; + if (mTypeface) + metrics = mTypeface->getAdvancedTypefaceMetrics(SkAdvancedTypefaceMetrics::kNo_PerGlyphInfo); + if (metrics) { + mEmSizeInFontUnits = metrics->fEmSize; + metrics->unref(); + } else + mEmSizeInFontUnits = 1000; // default value copied from Skia. + return mEmSizeInFontUnits; +} + FontPlatformData& FontPlatformData::operator=(const FontPlatformData& src) { if (hashTableDeletedFontValue() != src.mTypeface) { @@ -167,9 +184,10 @@ FontPlatformData& FontPlatformData::operator=(const FontPlatformData& src) SkSafeUnref(mTypeface); } - mTypeface = src.mTypeface; - mTextSize = src.mTextSize; - mFakeBold = src.mFakeBold; + mTypeface = src.mTypeface; + mEmSizeInFontUnits = src.mEmSizeInFontUnits; + mTextSize = src.mTextSize; + mFakeBold = src.mFakeBold; mFakeItalic = src.mFakeItalic; m_harfbuzzFace = src.m_harfbuzzFace; mOrientation = src.mOrientation; @@ -180,10 +198,6 @@ FontPlatformData& FontPlatformData::operator=(const FontPlatformData& src) void FontPlatformData::setupPaint(SkPaint* paint) const { - float ts = mTextSize; - if (!(ts > 0)) - ts = 12; - if (hashTableDeletedFontValue() == mTypeface) paint->setTypeface(0); else @@ -192,7 +206,7 @@ void FontPlatformData::setupPaint(SkPaint* paint) const paint->setAntiAlias(true); paint->setSubpixelText(true); paint->setHinting(SkPaint::kSlight_Hinting); - paint->setTextSize(SkFloatToScalar(ts)); + paint->setTextSize(SkFloatToScalar(mTextSize)); paint->setFakeBoldText(mFakeBold); paint->setTextSkewX(mFakeItalic ? -SK_Scalar1/4 : 0); #ifndef SUPPORT_COMPLEX_SCRIPTS diff --git a/Source/WebCore/platform/graphics/android/GLExtras.cpp b/Source/WebCore/platform/graphics/android/GLExtras.cpp index 873ea33..dc983a6 100644 --- a/Source/WebCore/platform/graphics/android/GLExtras.cpp +++ b/Source/WebCore/platform/graphics/android/GLExtras.cpp @@ -26,7 +26,6 @@ #include "config.h" #include "DrawExtra.h" -#include "FindCanvas.h" #include "GLExtras.h" #include "IntRect.h" #include "TilesManager.h" @@ -52,21 +51,10 @@ // Touch ring border width. This is doubled if the ring is not pressed #define RING_BORDER_WIDTH 1 -// Color of the ring is 0x6633b5e5 (copied from framework's holo_light) -#define COLOR_HOLO_LIGHT &m_lightRingTexture, 0x33, 0xb5, 0xe5, 0.4f -// Color of the ring is 0x660099cc (copied from framework's holo_dark) -#define COLOR_HOLO_DARK &m_darkRingTexture, 0x00, 0x99, 0xcc, 0.6f -// 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_findOnPage(0) - , m_ring(0) - , m_drawExtra(0) - , m_lightRingTexture(-1) - , m_darkRingTexture(-1) + : m_drawExtra(0) + , m_viewport() { } @@ -74,22 +62,28 @@ GLExtras::~GLExtras() { } -void GLExtras::drawRing(SkRect& srcRect, int* texture, int r, int g, int b, float a) +void GLExtras::drawRing(SkRect& srcRect, Color color, const TransformationMatrix* drawMat) { - if (*texture == -1) - *texture = GLUtils::createSampleColorTexture(r, g, b); - if (srcRect.fRight <= srcRect.fLeft || srcRect.fBottom <= srcRect.fTop) { // Invalid rect, reject it return; } XLOG("drawQuad [%fx%f, %f, %f]", srcRect.fLeft, srcRect.fTop, srcRect.width(), srcRect.height()); - TilesManager::instance()->shader()->drawQuad(srcRect, *texture, a); + // Pull the alpha out of the color so that the shader applies it correctly. + // Otherwise we either don't have blending enabled, or the alpha will get + // double applied + Color colorWithoutAlpha(0xFF000000 | color.rgb()); + float alpha = color.alpha() / (float) 255; + if (drawMat) { + TilesManager::instance()->shader()->drawLayerQuad(*drawMat, srcRect, 0, + alpha, false, 0, colorWithoutAlpha); + } else + TilesManager::instance()->shader()->drawQuad(srcRect, 0, alpha, colorWithoutAlpha); } -void GLExtras::drawRegion(const SkRegion& region, bool fill, - bool drawBorder, bool useDark) +void GLExtras::drawRegion(const SkRegion& region, bool fill, bool drawBorder, + const TransformationMatrix* drawMat, Color color) { if (region.isEmpty()) return; @@ -99,10 +93,7 @@ void GLExtras::drawRegion(const SkRegion& region, bool fill, const SkIRect& ir = rgnIter.rect(); SkRect r; r.set(ir.fLeft, ir.fTop, ir.fRight, ir.fBottom); - if (useDark) - drawRing(r, COLOR_HOLO_DARK); - else - drawRing(r, COLOR_HOLO_LIGHT); + drawRing(r, color, drawMat); rgnIter.next(); } } @@ -143,10 +134,7 @@ void GLExtras::drawRegion(const SkRegion& region, bool fill, clip.setRect(line); } r.set(line.fLeft, line.fTop, line.fRight, line.fBottom); - if (useDark) - drawRing(r, COLOR_HOLO_DARK); - else - drawRing(r, COLOR_HOLO_LIGHT); + drawRing(r, color, drawMat); if (startRect.isEmpty()) { startRect.set(line.fLeft, line.fTop, line.fRight, line.fBottom); } @@ -157,57 +145,8 @@ void GLExtras::drawRegion(const SkRegion& region, bool fill, } } -void GLExtras::drawCursorRings() -{ - 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, false); -} - -void GLExtras::drawFindOnPage(SkRect& viewport) -{ - WTF::Vector<MatchInfo>* matches = m_findOnPage->matches(); - XLOG("drawFindOnPage, matches: %p", matches); - if (!matches || !m_findOnPage->isCurrentLocationValid()) - return; - int count = matches->size(); - int current = m_findOnPage->currentMatchIndex(); - XLOG("match count: %d", count); - if (count < MAX_NUMBER_OF_MATCHES_TO_DRAW) - for (int i = 0; i < count; i++) { - MatchInfo& info = matches->at(i); - const SkRegion& region = info.getLocation(); - SkIRect rect = region.getBounds(); - if (rect.intersect(viewport.fLeft, viewport.fTop, - viewport.fRight, viewport.fBottom)) - drawRegion(region, i == current, false, true); -#ifdef DEBUG - else - XLOG("Quick rejecting [%dx%d, %d, %d", rect.fLeft, rect.fTop, - rect.width(), rect.height()); -#endif // DEBUG - } - else { - MatchInfo& info = matches->at(current); - drawRegion(info.getLocation(), true, false, true); - } -} - -void GLExtras::drawGL(IntRect& webViewRect, SkRect& viewport, int titleBarHeight) +void GLExtras::drawGL(const LayerAndroid* layer) { - if (m_drawExtra) { - if (m_drawExtra == m_ring) - drawCursorRings(); - else if (m_drawExtra == m_findOnPage) - drawFindOnPage(viewport); - else - XLOGC("m_drawExtra %p is unknown! (cursor: %p, find: %p", - m_drawExtra, m_ring, m_findOnPage); - } + 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 c52e951..59a7c3c 100644 --- a/Source/WebCore/platform/graphics/android/GLExtras.h +++ b/Source/WebCore/platform/graphics/android/GLExtras.h @@ -26,41 +26,33 @@ #ifndef GLExtras_h #define GLExtras_h +#include "Color.h" +#include "DrawExtra.h" #include "SkRect.h" #include "SkRegion.h" -namespace android { - class FindOnPage; - class CursorRing; - class DrawExtra; -} - namespace WebCore { +class LayerAndroid; +class TransformationMatrix; + class GLExtras { public: GLExtras(); virtual ~GLExtras(); - void drawGL(IntRect& webViewRect, SkRect& viewport, int titleBarHeight); - void setFindOnPageExtra(android::FindOnPage* findOnPage) { - m_findOnPage = findOnPage; - } - void setCursorRingExtra(android::CursorRing* ring) { m_ring = ring; } + void drawGL(const LayerAndroid* layer); void setDrawExtra(android::DrawExtra* extra) { m_drawExtra = extra; } + void setViewport(const SkRect & viewport) { m_viewport = viewport; } -private: - void drawRing(SkRect& srcRect, int* texture, int r, int g, int b, float a); void drawRegion(const SkRegion& region, bool fill, bool drawBorder, - bool useDark = false); - void drawCursorRings(); - void drawFindOnPage(SkRect& viewport); + const TransformationMatrix* drawMat, Color color = COLOR_HOLO_LIGHT); + +private: + void drawRing(SkRect& srcRect, Color color, const TransformationMatrix* drawMat); - android::FindOnPage* m_findOnPage; - android::CursorRing* m_ring; android::DrawExtra* m_drawExtra; - int m_lightRingTexture; - int m_darkRingTexture; + SkRect m_viewport; }; } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/GLUtils.cpp b/Source/WebCore/platform/graphics/android/GLUtils.cpp index 97a53fe..3024d28 100644 --- a/Source/WebCore/platform/graphics/android/GLUtils.cpp +++ b/Source/WebCore/platform/graphics/android/GLUtils.cpp @@ -36,12 +36,11 @@ #include <wtf/CurrentTime.h> #include <wtf/text/CString.h> +#undef XLOGC +#define XLOGC(...) android_printLog(ANDROID_LOG_DEBUG, "GLUtils", __VA_ARGS__) #ifdef DEBUG -#include <cutils/log.h> -#include <wtf/text/CString.h> - #undef XLOG #define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "GLUtils", __VA_ARGS__) @@ -52,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 { @@ -116,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(); } } @@ -127,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); } } @@ -140,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; } @@ -151,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; } @@ -161,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); } } ///////////////////////////////////////////////////////////////////////////////////////// @@ -237,7 +281,7 @@ static EGLConfig defaultPbufferConfig(EGLDisplay display) eglChooseConfig(display, configAttribs, &config, 1, &numConfigs); GLUtils::checkEglError("eglPbufferConfig"); if (numConfigs != 1) - LOGI("eglPbufferConfig failed (%d)\n", numConfigs); + ALOGI("eglPbufferConfig failed (%d)\n", numConfigs); return config; } @@ -313,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); @@ -370,126 +415,120 @@ GLuint GLUtils::createBaseTileGLTexture(int width, int height) GLUtils::checkGlError("glTexImage2D"); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); +#ifdef DEBUG + delete pixels; +#endif return texture; } +bool GLUtils::isPureColorBitmap(const SkBitmap& bitmap, Color& pureColor) +{ + // If the bitmap is the pure color, skip the transfer step, and update the BaseTile Info. + // This check is taking < 1ms if we do full bitmap check per tile. + // TODO: use the SkPicture to determine whether or not a tile is single color. + pureColor = Color(Color::transparent); + bitmap.lockPixels(); + bool sameColor = true; + int bitmapWidth = bitmap.width(); + + // Create a row of pure color using the first pixel. + // TODO: improve the perf here, by either picking a random pixel, or + // creating an array of rows with pre-defined commonly used color, add + // smart LUT to speed things up if possible. + int* firstPixelPtr = static_cast<int*> (bitmap.getPixels()); + int* pixelsRow = new int[bitmapWidth]; + for (int i = 0; i < bitmapWidth; i++) + pixelsRow[i] = (*firstPixelPtr); + + // Then compare the pure color row with each row of the bitmap. + for (int j = 0; j < bitmap.height(); j++) { + if (memcmp(pixelsRow, &firstPixelPtr[bitmapWidth * j], 4 * bitmapWidth)) { + sameColor = false; + break; + } + } + delete pixelsRow; + pixelsRow = 0; + + if (sameColor) { + char* rgbaPtr = static_cast<char*>(bitmap.getPixels()); + pureColor = Color(rgbaPtr[0], rgbaPtr[1], rgbaPtr[2], rgbaPtr[3]); + XLOG("sameColor tile found , %x at (%d, %d, %d, %d)", + *firstPixelPtr, rgbaPtr[0], rgbaPtr[1], rgbaPtr[2], rgbaPtr[3]); + } + bitmap.unlockPixels(); + + return sameColor; +} + +// Return true when the tile is pure color. +bool GLUtils::skipTransferForPureColor(const TileRenderInfo* renderInfo, + const SkBitmap& bitmap) +{ + bool skipTransfer = false; + BaseTile* tilePtr = renderInfo->baseTile; + + // TODO: use pure color for partial invals as well + if (renderInfo->invalRect) + return false; + + if (tilePtr) { + BaseTileTexture* tileTexture = tilePtr->backTexture(); + // Check the bitmap, and make everything ready here. + Color pureColor; + if (tileTexture && isPureColorBitmap(bitmap, pureColor)) { + // update basetile's info + // Note that we are skipping the whole TransferQueue. + renderInfo->textureInfo->m_width = bitmap.width(); + renderInfo->textureInfo->m_height = bitmap.height(); + renderInfo->textureInfo->m_internalFormat = GL_RGBA; + + TilesManager::instance()->transferQueue()->addItemInPureColorQueue(renderInfo, + pureColor); + + skipTransfer = true; + } + } + return skipTransfer; +} + void GLUtils::paintTextureWithBitmap(const TileRenderInfo* renderInfo, const SkBitmap& bitmap) { if (!renderInfo) return; - const int x = renderInfo->invalRect->fLeft; - const int y = renderInfo->invalRect->fTop; const SkSize& requiredSize = renderInfo->tileSize; TextureInfo* textureInfo = renderInfo->textureInfo; - SharedTextureMode mode = textureInfo->getSharedTextureMode(); - if (requiredSize.equals(textureInfo->m_width, textureInfo->m_height)) { - if (mode == EglImageMode) - GLUtils::updateTextureWithBitmap(textureInfo->m_textureId, x, y, bitmap); - else if (mode == SurfaceTextureMode) -#if DEPRECATED_SURFACE_TEXTURE_MODE - GLUtils::updateSurfaceTextureWithBitmap(renderInfo, x, y, bitmap); -#else - GLUtils::updateSharedSurfaceTextureWithBitmap(renderInfo, x, y, bitmap); -#endif - } else { + if (skipTransferForPureColor(renderInfo, bitmap)) + return; + + if (requiredSize.equals(textureInfo->m_width, textureInfo->m_height)) + GLUtils::updateSharedSurfaceTextureWithBitmap(renderInfo, bitmap); + else { if (!requiredSize.equals(bitmap.width(), bitmap.height())) { XLOG("The bitmap size (%d,%d) does not equal the texture size (%d,%d)", bitmap.width(), bitmap.height(), requiredSize.width(), requiredSize.height()); } + GLUtils::updateSharedSurfaceTextureWithBitmap(renderInfo, bitmap); - if (mode == EglImageMode) - GLUtils::createTextureWithBitmap(textureInfo->m_textureId, bitmap); - else if (mode == SurfaceTextureMode) -#if DEPRECATED_SURFACE_TEXTURE_MODE - GLUtils::createSurfaceTextureWithBitmap(renderInfo, bitmap); -#else - GLUtils::updateSharedSurfaceTextureWithBitmap(renderInfo, 0, 0, bitmap); -#endif textureInfo->m_width = bitmap.width(); textureInfo->m_height = bitmap.height(); textureInfo->m_internalFormat = GL_RGBA; } } -#if DEPRECATED_SURFACE_TEXTURE_MODE -void GLUtils::createSurfaceTextureWithBitmap(const TileRenderInfo* renderInfo, const SkBitmap& bitmap, GLint filter) -{ - - TextureInfo* texture = renderInfo->textureInfo; - - texture->m_width = bitmap.width(); - texture->m_height = bitmap.height(); - texture->m_internalFormat = GL_RGBA; - - sp<android::SurfaceTexture> surfaceTexture = texture->m_surfaceTexture; - sp<ANativeWindow> ANW = texture->m_ANW; - - int result; - result = native_window_set_buffers_geometry(ANW.get(), - texture->m_width, texture->m_height, HAL_PIXEL_FORMAT_RGBA_8888); - checkSurfaceTextureError("native_window_set_buffers_geometry", result); - result = native_window_set_usage(ANW.get(), - GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN); - checkSurfaceTextureError("native_window_set_usage", result); - - updateSurfaceTextureWithBitmap(renderInfo, 0, 0, bitmap, filter); -} - -void GLUtils::updateSurfaceTextureWithBitmap(const TileRenderInfo* renderInfo, int x, int y, const SkBitmap& bitmap, GLint filter) -{ - TextureInfo* texture = renderInfo->textureInfo; - sp<android::SurfaceTexture> surfaceTexture = texture->m_surfaceTexture; - sp<ANativeWindow> ANW = texture->m_ANW; - - ANativeWindowBuffer* anb; - int status = ANW->dequeueBuffer(ANW.get(), &anb); - checkSurfaceTextureError("dequeueBuffer", status); - - if (status != NO_ERROR) { // FIXME: add proper error handling! - native_window_set_buffer_count(ANW.get(), 3); - return; - } - - sp<android::GraphicBuffer> buf(new android::GraphicBuffer(anb, false)); - status |= ANW->lockBuffer(ANW.get(), buf->getNativeBuffer()); - checkSurfaceTextureError("lockBuffer", status); - - // Fill the buffer with the content of the bitmap - uint8_t* img = 0; - status |= buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img)); - checkSurfaceTextureError("lock", status); - - if (status == NO_ERROR) { - int row, col; - int bpp = 4; // Now only deal with RGBA8888 format. - - bitmap.lockPixels(); - uint8_t* bitmapOrigin = static_cast<uint8_t*>(bitmap.getPixels()); - // Copied line by line since we need to handle the offsets and stride. - for (row = 0 ; row < bitmap.height(); row ++) { - uint8_t* dst = &(img[(buf->getStride() * (row + x) + y) * bpp]); - uint8_t* src = &(bitmapOrigin[bitmap.width() * row * bpp]); - memcpy(dst, src, bpp * bitmap.width()); - } - bitmap.unlockPixels(); - } - buf->unlock(); - status = ANW->queueBuffer(ANW.get(), buf->getNativeBuffer()); - checkSurfaceTextureError("queueBuffer", status); -} -#endif - -void GLUtils::updateSharedSurfaceTextureWithBitmap(const TileRenderInfo* renderInfo, int x, int y, const SkBitmap& bitmap) +void GLUtils::updateSharedSurfaceTextureWithBitmap(const TileRenderInfo* renderInfo, const SkBitmap& bitmap) { if (!renderInfo || !renderInfo->textureInfo || !renderInfo->baseTile) return; - TilesManager::instance()->transferQueue()->updateQueueWithBitmap(renderInfo, x, y, bitmap); + TilesManager::instance()->transferQueue()->updateQueueWithBitmap(renderInfo, bitmap); } void GLUtils::createTextureWithBitmap(GLuint texture, const SkBitmap& bitmap, GLint filter) @@ -505,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()); } @@ -523,7 +565,8 @@ void GLUtils::createTextureWithBitmap(GLuint texture, const SkBitmap& bitmap, GL glDeleteFramebuffers(1, &fboID); } -void GLUtils::updateTextureWithBitmap(GLuint texture, int x, int y, const SkBitmap& bitmap, GLint filter) +void GLUtils::updateTextureWithBitmap(GLuint texture, const SkBitmap& bitmap, + const IntRect& inval, GLint filter) { glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glBindTexture(GL_TEXTURE_2D, texture); @@ -532,13 +575,21 @@ void GLUtils::updateTextureWithBitmap(GLuint texture, int x, int y, const SkBitm int internalformat = getInternalFormat(config); int type = getType(config); bitmap.lockPixels(); - glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, bitmap.width(), bitmap.height(), - internalformat, type, bitmap.getPixels()); + if (inval.isEmpty()) { + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap.width(), bitmap.height(), + internalformat, type, bitmap.getPixels()); + } else { + glTexSubImage2D(GL_TEXTURE_2D, 0, inval.x(), inval.y(), inval.width(), inval.height(), + internalformat, type, bitmap.getPixels()); + } bitmap.unlockPixels(); if (GLUtils::checkGlError("glTexSubImage2D")) { - XLOG("GL ERROR: glTexSubImage2D parameters are : bitmap.width() %d, bitmap.height() %d," - " x %d, y %d, internalformat 0x%x, type 0x%x, bitmap.getPixels() %p", - bitmap.width(), bitmap.height(), x, y, internalformat, type, bitmap.getPixels()); +#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()); } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); diff --git a/Source/WebCore/platform/graphics/android/GLUtils.h b/Source/WebCore/platform/graphics/android/GLUtils.h index 68acbab..e001aee 100644 --- a/Source/WebCore/platform/graphics/android/GLUtils.h +++ b/Source/WebCore/platform/graphics/android/GLUtils.h @@ -28,6 +28,7 @@ #if USE(ACCELERATED_COMPOSITING) +#include "Color.h" #include "SkBitmap.h" #include "SkMatrix.h" #include "SkSize.h" @@ -73,17 +74,20 @@ public: static GLuint createBaseTileGLTexture(int width, int height); static void createTextureWithBitmap(GLuint texture, const SkBitmap& bitmap, GLint filter = GL_LINEAR); - static void updateTextureWithBitmap(GLuint texture, int x, int y, const SkBitmap& bitmap, GLint filter = GL_LINEAR); + static void updateTextureWithBitmap(GLuint texture, const SkBitmap& bitmap, const IntRect&, GLint filter = GL_LINEAR); static void createEGLImageFromTexture(GLuint texture, EGLImageKHR* image); static void createTextureFromEGLImage(GLuint texture, EGLImageKHR image, GLint filter = GL_LINEAR); static void paintTextureWithBitmap(const TileRenderInfo* renderInfo, const SkBitmap& bitmap); -#if DEPRECATED_SURFACE_TEXTURE_MODE - static void createSurfaceTextureWithBitmap(const TileRenderInfo* , const SkBitmap& bitmap, GLint filter = GL_LINEAR); - static void updateSurfaceTextureWithBitmap(const TileRenderInfo* , int x, int y, const SkBitmap& bitmap, GLint filter = GL_LINEAR); -#endif - static void updateSharedSurfaceTextureWithBitmap(const TileRenderInfo* , int x, int y, const SkBitmap& bitmap); + static void updateSharedSurfaceTextureWithBitmap(const TileRenderInfo* , const SkBitmap& bitmap); static void convertToTransformationMatrix(const float* matrix, TransformationMatrix& transformMatrix); + + 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 3bcda9a..86f33e0 100644 --- a/Source/WebCore/platform/graphics/android/GLWebViewState.cpp +++ b/Source/WebCore/platform/graphics/android/GLWebViewState.cpp @@ -69,6 +69,13 @@ #define MIN_SCALE_WARNING 0.1 #define MAX_SCALE_WARNING 10 +// fps indicator is FPS_INDICATOR_HEIGHT pixels high. +// The max width is equal to MAX_FPS_VALUE fps. +#define FPS_INDICATOR_HEIGHT 10 +#define MAX_FPS_VALUE 60 + +#define TREE_SWAPPED_COUNTER_MODULE 10 + namespace WebCore { using namespace android; @@ -80,13 +87,14 @@ GLWebViewState::GLWebViewState() , m_frameworkInval(0, 0, 0, 0) , m_frameworkLayersInval(0, 0, 0, 0) , m_isScrolling(false) + , m_isViewportScrolling(false) , m_goingDown(true) , m_goingLeft(false) , m_expandedTileBoundsX(0) , m_expandedTileBoundsY(0) - , m_highEndGfx(false) , m_scale(1) , m_layersRenderingMode(kAllTextures) + , m_treeManager(this) { m_viewport.setEmpty(); m_futureViewportTileBounds.setEmpty(); @@ -108,9 +116,6 @@ GLWebViewState::GLWebViewState() GLWebViewState::~GLWebViewState() { - // Take care of the transfer queue such that Tex Gen thread will not stuck - TilesManager::instance()->unregisterGLWebViewState(this); - // We have to destroy the two tiled pages first as their destructor // may depend on the existence of this GLWebViewState and some of its // instance variables in order to complete. @@ -125,8 +130,8 @@ GLWebViewState::~GLWebViewState() } -void GLWebViewState::setBaseLayer(BaseLayerAndroid* layer, const SkRegion& inval, - bool showVisualIndicator, bool isPictureAfterFirstLayout) +bool GLWebViewState::setBaseLayer(BaseLayerAndroid* layer, bool showVisualIndicator, + bool isPictureAfterFirstLayout) { if (!layer || isPictureAfterFirstLayout) { // TODO: move this into TreeManager @@ -136,11 +141,10 @@ void GLWebViewState::setBaseLayer(BaseLayerAndroid* layer, const SkRegion& inval 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); - layer->markAsDirty(inval); // TODO: set in webview.cpp } - m_treeManager.updateWithTree(layer, isPictureAfterFirstLayout); + bool queueFull = m_treeManager.updateWithTree(layer, isPictureAfterFirstLayout); m_glExtras.setDrawExtra(0); #ifdef MEASURES_PERF @@ -150,6 +154,7 @@ void GLWebViewState::setBaseLayer(BaseLayerAndroid* layer, const SkRegion& inval #endif TilesManager::instance()->setShowVisualIndicator(showVisualIndicator); + return queueFull; } void GLWebViewState::scrollLayer(int layerId, int x, int y) @@ -238,14 +243,35 @@ int GLWebViewState::baseContentHeight() return m_treeManager.baseContentHeight(); } -void GLWebViewState::setViewport(SkRect& viewport, float scale) +void GLWebViewState::setViewport(const SkRect& viewport, float scale) { + // allocate max possible number of tiles visible with this viewport / expandedTileBounds + const float invTileContentWidth = scale / TilesManager::tileWidth(); + const float invTileContentHeight = scale / TilesManager::tileHeight(); + + int viewMaxTileX = static_cast<int>(ceilf((viewport.width()-1) * invTileContentWidth)) + 1; + int viewMaxTileY = static_cast<int>(ceilf((viewport.height()-1) * invTileContentHeight)) + 1; + + TilesManager* manager = TilesManager::instance(); + int maxTextureCount = (viewMaxTileX + m_expandedTileBoundsX * 2) * + (viewMaxTileY + m_expandedTileBoundsY * 2) * (manager->highEndGfx() ? 4 : 2); + + manager->setMaxTextureCount(maxTextureCount); + m_tiledPageA->updateBaseTileSize(); + m_tiledPageB->updateBaseTileSize(); + if ((m_viewport == viewport) && - (zoomManager()->futureScale() == scale)) + (zoomManager()->futureScale() == scale)) { + // everything below will stay the same, early return. + m_isViewportScrolling = false; return; + } m_goingDown = m_viewport.fTop - viewport.fTop <= 0; m_goingLeft = m_viewport.fLeft - viewport.fLeft >= 0; + + // detect viewport scrolling from short programmatic scrolls/jumps + m_isViewportScrolling = m_viewport != viewport && SkRect::Intersects(m_viewport, viewport); m_viewport = viewport; XLOG("New VIEWPORT %.2f - %.2f %.2f - %.2f (w: %2.f h: %.2f scale: %.2f currentScale: %.2f futureScale: %.2f)", @@ -253,25 +279,11 @@ void GLWebViewState::setViewport(SkRect& viewport, float scale) m_viewport.width(), m_viewport.height(), scale, zoomManager()->currentScale(), zoomManager()->futureScale()); - const float invTileContentWidth = scale / TilesManager::tileWidth(); - const float invTileContentHeight = scale / TilesManager::tileHeight(); - m_viewportTileBounds.set( static_cast<int>(floorf(viewport.fLeft * invTileContentWidth)), static_cast<int>(floorf(viewport.fTop * invTileContentHeight)), static_cast<int>(ceilf(viewport.fRight * invTileContentWidth)), static_cast<int>(ceilf(viewport.fBottom * invTileContentHeight))); - - // allocate max possible number of tiles visible with this viewport - int viewMaxTileX = static_cast<int>(ceilf((viewport.width()-1) * invTileContentWidth)) + 1; - int viewMaxTileY = static_cast<int>(ceilf((viewport.height()-1) * invTileContentHeight)) + 1; - - int maxTextureCount = (viewMaxTileX + m_expandedTileBoundsX * 2) * - (viewMaxTileY + m_expandedTileBoundsY * 2) * (m_highEndGfx ? 4 : 2); - - TilesManager::instance()->setMaxTextureCount(maxTextureCount); - m_tiledPageA->updateBaseTileSize(); - m_tiledPageB->updateBaseTileSize(); } #ifdef MEASURES_PERF @@ -331,27 +343,37 @@ void GLWebViewState::drawBackground(Color& backgroundColor) glClear(GL_COLOR_BUFFER_BIT); } -double GLWebViewState::setupDrawing(IntRect& viewRect, SkRect& visibleRect, - IntRect& webViewRect, int titleBarHeight, - IntRect& screenClip, float scale) +double GLWebViewState::setupDrawing(const IntRect& viewRect, const SkRect& visibleRect, + const IntRect& webViewRect, int titleBarHeight, + const IntRect& screenClip, float scale) { int left = viewRect.x(); int top = viewRect.y(); int width = viewRect.width(); int height = viewRect.height(); + TilesManager* tilesManager = TilesManager::instance(); + + // Make sure the GL Context has not changed, otherwise, re-create all GL + // resources. Only check this after onTrimMemory happens. + bool contextChanged = tilesManager->contextChanged(); + tilesManager->setContextChanged(false); - ShaderProgram* shader = TilesManager::instance()->shader(); - if (shader->program() == -1) { - XLOG("Reinit shader"); + // Make sure GL resources are created on the UI thread. + ShaderProgram* shader = tilesManager->shader(); + if (shader->needsInit() || contextChanged) { + XLOGC("Reinit shader"); shader->init(); } - shader->setViewport(visibleRect, scale); - shader->setViewRect(viewRect); - shader->setWebViewRect(webViewRect); - shader->setTitleBarHeight(titleBarHeight); - shader->setScreenClip(screenClip); - shader->resetBlending(); + TransferQueue* transferQueue = tilesManager->transferQueue(); + if (transferQueue->needsInit() || contextChanged) { + XLOGC("Reinit transferQueue"); + transferQueue->initGLResources(TilesManager::tileWidth(), + TilesManager::tileHeight()); + } + // TODO: Add the video GL resource re-initialization code here. + shader->setupDrawing(viewRect, visibleRect, webViewRect, + titleBarHeight, screenClip, scale); shader->calculateAnimationDelta(); glViewport(left + shader->getAnimationDeltaX(), @@ -449,23 +471,24 @@ bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect, IntRect& clip, float scale, bool* treesSwappedPtr, bool* newTreeHasAnimPtr) { + TilesManager* tilesManager = TilesManager::instance(); m_scale = scale; - TilesManager::instance()->getProfiler()->nextFrame(viewport.fLeft, + tilesManager->getProfiler()->nextFrame(viewport.fLeft, viewport.fTop, viewport.fRight, viewport.fBottom, scale); - TilesManager::instance()->incDrawGLCount(); + tilesManager->incDrawGLCount(); #ifdef DEBUG - TilesManager::instance()->getTilesTracker()->clear(); + tilesManager->getTilesTracker()->clear(); #endif float viewWidth = (viewport.fRight - viewport.fLeft) * TILE_PREFETCH_RATIO; float viewHeight = (viewport.fBottom - viewport.fTop) * TILE_PREFETCH_RATIO; - bool useMinimalMemory = TilesManager::instance()->useMinimalMemory(); - bool useHorzPrefetch = useMinimalMemory ? 0 : viewWidth < baseContentWidth(); - bool useVertPrefetch = useMinimalMemory ? 0 : viewHeight < baseContentHeight(); + bool noPrefetch = tilesManager->useMinimalMemory() || !tilesManager->highEndGfx(); + bool useHorzPrefetch = noPrefetch ? 0 : viewWidth < baseContentWidth(); + bool useVertPrefetch = noPrefetch ? 0 : viewHeight < baseContentHeight(); m_expandedTileBoundsX = (useHorzPrefetch) ? TILE_PREFETCH_DISTANCE : 0; m_expandedTileBoundsY = (useVertPrefetch) ? TILE_PREFETCH_DISTANCE : 0; @@ -484,24 +507,27 @@ bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect, // Here before we draw, update the BaseTile which has updated content. // Inside this function, just do GPU blits from the transfer queue into // the BaseTiles' texture. - TilesManager::instance()->transferQueue()->updateDirtyBaseTiles(); + tilesManager->transferQueue()->updateDirtyBaseTiles(); // Upload any pending ImageTexture // Return true if we still have some images to upload. // TODO: upload as many textures as possible within a certain time limit bool ret = ImagesManager::instance()->prepareTextures(this); - if (scale < MIN_SCALE_WARNING || scale > MAX_SCALE_WARNING) + if (scale < MIN_SCALE_WARNING || scale > MAX_SCALE_WARNING) { XLOGC("WARNING, scale seems corrupted after update: %e", scale); + CRASH(); + } // gather the textures we can use - TilesManager::instance()->gatherLayerTextures(); + tilesManager->gatherLayerTextures(); double currentTime = setupDrawing(rect, viewport, webViewRect, titleBarHeight, clip, scale); TexturesResult nbTexturesNeeded; bool fastSwap = isScrolling() || m_layersRenderingMode == kSingleSurfaceRendering; + m_glExtras.setViewport(viewport); ret |= m_treeManager.drawGL(currentTime, rect, viewport, scale, fastSwap, treesSwappedPtr, newTreeHasAnimPtr, @@ -518,16 +544,11 @@ bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect, nbTexturesNeeded.clipped += nbTexturesForImages; ret |= setLayersRenderingMode(nbTexturesNeeded); - FloatRect extrasclip(0, 0, rect.width(), rect.height()); - TilesManager::instance()->shader()->clip(extrasclip); - - m_glExtras.drawGL(webViewRect, viewport, titleBarHeight); - glBindBuffer(GL_ARRAY_BUFFER, 0); // Clean up GL textures for video layer. - TilesManager::instance()->videoLayerManager()->deleteUnusedTextures(); - ret |= TilesManager::instance()->invertedScreenSwitch(); + tilesManager->videoLayerManager()->deleteUnusedTextures(); + ret |= tilesManager->invertedScreenSwitch(); if (ret) { // ret==true && empty inval region means we've inval'd everything, @@ -535,13 +556,13 @@ bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect, // until tile generation catches up and we swap pages. bool fullScreenInval = m_frameworkInval.isEmpty(); - if (TilesManager::instance()->invertedScreenSwitch()) { + if (tilesManager->invertedScreenSwitch()) { fullScreenInval = true; - TilesManager::instance()->setInvertedScreenSwitch(false); + tilesManager->setInvertedScreenSwitch(false); } if (!fullScreenInval) { - FloatRect frameworkInval = TilesManager::instance()->shader()->rectInInvScreenCoord( + FloatRect frameworkInval = tilesManager->shader()->rectInInvScreenCoord( m_frameworkInval); // Inflate the invalidate rect to avoid precision lost. frameworkInval.inflate(1); @@ -574,6 +595,30 @@ bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect, resetFrameworkInval(); } + showFrameInfo(rect, *treesSwappedPtr); + +#ifdef DEBUG + tilesManager->getTilesTracker()->showTrackTextures(); +#endif + + return ret; +} + +void GLWebViewState::showFrameInfo(const IntRect& rect, bool treesSwapped) +{ + bool showVisualIndicator = TilesManager::instance()->getShowVisualIndicator(); + + bool drawOrDumpFrameInfo = showVisualIndicator; +#ifdef MEASURES_PERF + drawOrDumpFrameInfo |= m_measurePerfs; +#endif + if (!drawOrDumpFrameInfo) + return; + + double currentDrawTime = WTF::currentTime(); + double delta = currentDrawTime - m_prevDrawTime; + m_prevDrawTime = currentDrawTime; + #ifdef MEASURES_PERF if (m_measurePerfs) { m_delayTimes[m_timeCounter++] = delta; @@ -582,12 +627,37 @@ bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect, } #endif -#ifdef DEBUG - TilesManager::instance()->getTilesTracker()->showTrackTextures(); - ImagesManager::instance()->showImages(); -#endif + IntRect frameInfoRect = rect; + frameInfoRect.setHeight(FPS_INDICATOR_HEIGHT); + double ratio = (1.0 / delta) / MAX_FPS_VALUE; - return ret; + clearRectWithColor(frameInfoRect, 1, 1, 1, 1); + frameInfoRect.setWidth(frameInfoRect.width() * ratio); + clearRectWithColor(frameInfoRect, 1, 0, 0, 1); + + // Draw the tree swap counter as a circling progress bar. + // This will basically show how fast we are updating the tree. + static int swappedCounter = 0; + if (treesSwapped) + swappedCounter = (swappedCounter + 1) % TREE_SWAPPED_COUNTER_MODULE; + + frameInfoRect = rect; + frameInfoRect.setHeight(FPS_INDICATOR_HEIGHT); + frameInfoRect.move(0, FPS_INDICATOR_HEIGHT); + + clearRectWithColor(frameInfoRect, 1, 1, 1, 1); + ratio = (swappedCounter + 1.0) / TREE_SWAPPED_COUNTER_MODULE; + + frameInfoRect.setWidth(frameInfoRect.width() * ratio); + clearRectWithColor(frameInfoRect, 0, 1, 0, 1); +} + +void GLWebViewState::clearRectWithColor(const IntRect& rect, float r, float g, + float b, float a) +{ + glScissor(rect.x(), rect.y(), rect.width(), rect.height()); + glClearColor(r, g, b, a); + glClear(GL_COLOR_BUFFER_BIT); } } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/GLWebViewState.h b/Source/WebCore/platform/graphics/android/GLWebViewState.h index 8d89704..334cd8e 100644 --- a/Source/WebCore/platform/graphics/android/GLWebViewState.h +++ b/Source/WebCore/platform/graphics/android/GLWebViewState.h @@ -176,7 +176,7 @@ public: void setFutureViewport(const SkIRect& viewport) { m_futureViewportTileBounds = viewport; } unsigned int paintBaseLayerContent(SkCanvas* canvas); - void setBaseLayer(BaseLayerAndroid* layer, const SkRegion& inval, bool showVisualIndicator, + bool setBaseLayer(BaseLayerAndroid* layer, bool showVisualIndicator, bool isPictureAfterFirstLayout); void paintExtras(); @@ -191,8 +191,6 @@ public: int baseContentWidth(); int baseContentHeight(); - void setViewport(SkRect& viewport, float scale); - // a rect containing the coordinates of all tiles in the current viewport const SkIRect& viewportTileBounds() const { return m_viewportTileBounds; } // a rect containing the viewportTileBounds before there was a scale change @@ -202,12 +200,9 @@ public: unsigned int currentPictureCounter() const { return m_currentPictureCounter; } void setIsScrolling(bool isScrolling) { m_isScrolling = isScrolling; } - bool isScrolling() { return m_isScrolling; } + bool isScrolling() { return m_isScrolling || m_isViewportScrolling; } void drawBackground(Color& backgroundColor); - double setupDrawing(IntRect& viewRect, SkRect& visibleRect, - IntRect& webViewRect, int titleBarHeight, - IntRect& screenClip, float scale); bool setLayersRenderingMode(TexturesResult&); void fullInval(); @@ -234,7 +229,6 @@ public: int expandedTileBoundsX() { return m_expandedTileBoundsX; } int expandedTileBoundsY() { return m_expandedTileBoundsY; } - void setHighEndGfx(bool highEnd) { m_highEndGfx = highEnd; } float scale() { return m_scale; } @@ -254,6 +248,14 @@ public: private: void inval(const IntRect& rect); + void setViewport(const SkRect& viewport, float scale); + double setupDrawing(const IntRect& viewRect, const SkRect& visibleRect, + const IntRect& webViewRect, int titleBarHeight, + const IntRect& screenClip, float scale); + void showFrameInfo(const IntRect& rect, bool treesSwapped); + void clearRectWithColor(const IntRect& rect, float r, float g, + float b, float a); + double m_prevDrawTime; ZoomManager m_zoomManager; android::Mutex m_tiledPageLock; @@ -279,12 +281,12 @@ private: GLExtras m_glExtras; bool m_isScrolling; + bool m_isViewportScrolling; bool m_goingDown; bool m_goingLeft; int m_expandedTileBoundsX; int m_expandedTileBoundsY; - bool m_highEndGfx; float m_scale; diff --git a/Source/WebCore/platform/graphics/android/GaneshContext.cpp b/Source/WebCore/platform/graphics/android/GaneshContext.cpp index e67bcd4..1a5ce5e 100644 --- a/Source/WebCore/platform/graphics/android/GaneshContext.cpp +++ b/Source/WebCore/platform/graphics/android/GaneshContext.cpp @@ -95,11 +95,7 @@ SkDevice* GaneshContext::getDeviceForBaseTile(const TileRenderInfo& renderInfo) contextNeedsReset = true; } - SkDevice* device = 0; - if (renderInfo.textureInfo->getSharedTextureMode() == SurfaceTextureMode) - device = getDeviceForBaseTileSurface(renderInfo); - else if (renderInfo.textureInfo->getSharedTextureMode() == EglImageMode) - device = getDeviceForBaseTileFBO(renderInfo); + SkDevice* device = getDeviceForBaseTileSurface(renderInfo); // We must reset the Ganesh context only after we are sure we have // re-established our EGLContext as the current context. diff --git a/Source/WebCore/platform/graphics/android/GaneshRenderer.cpp b/Source/WebCore/platform/graphics/android/GaneshRenderer.cpp index 29acb2b..c90ddb3 100644 --- a/Source/WebCore/platform/graphics/android/GaneshRenderer.cpp +++ b/Source/WebCore/platform/graphics/android/GaneshRenderer.cpp @@ -84,20 +84,16 @@ void GaneshRenderer::setupCanvas(const TileRenderInfo& renderInfo, SkCanvas* can GaneshContext* ganesh = GaneshContext::instance(); -#if !DEPRECATED_SURFACE_TEXTURE_MODE - if (renderInfo.textureInfo->getSharedTextureMode() == SurfaceTextureMode) { - TransferQueue* tileQueue = TilesManager::instance()->transferQueue(); - - tileQueue->lockQueue(); - - bool ready = tileQueue->readyForUpdate(); - if (!ready) { - XLOG("!ready"); - tileQueue->unlockQueue(); - return; - } + TransferQueue* tileQueue = TilesManager::instance()->transferQueue(); + + tileQueue->lockQueue(); + + bool ready = tileQueue->readyForUpdate(); + if (!ready) { + XLOG("!ready"); + tileQueue->unlockQueue(); + return; } -#endif SkDevice* device = NULL; if (renderInfo.tileSize.width() == TilesManager::tileWidth() @@ -117,12 +113,6 @@ void GaneshRenderer::setupCanvas(const TileRenderInfo& renderInfo, SkCanvas* can // set the GPU device to the canvas canvas->setDevice(device); - - // invert canvas contents - if (renderInfo.textureInfo->getSharedTextureMode() == EglImageMode) { - canvas->scale(SK_Scalar1, -SK_Scalar1); - canvas->translate(0, -renderInfo.tileSize.height()); - } } void GaneshRenderer::setupPartialInval(const TileRenderInfo& renderInfo, SkCanvas* canvas) @@ -148,14 +138,10 @@ void GaneshRenderer::renderingComplete(const TileRenderInfo& renderInfo, SkCanva // In SurfaceTextureMode we must call swapBuffers to unlock and post the // tile's ANativeWindow (i.e. SurfaceTexture) buffer - if (renderInfo.textureInfo->getSharedTextureMode() == SurfaceTextureMode) { -#if !DEPRECATED_SURFACE_TEXTURE_MODE - TransferQueue* tileQueue = TilesManager::instance()->transferQueue(); - eglSwapBuffers(eglGetCurrentDisplay(), tileQueue->m_eglSurface); - tileQueue->addItemInTransferQueue(&renderInfo, GpuUpload, 0); - tileQueue->unlockQueue(); -#endif - } + TransferQueue* tileQueue = TilesManager::instance()->transferQueue(); + eglSwapBuffers(eglGetCurrentDisplay(), tileQueue->m_eglSurface); + tileQueue->addItemInTransferQueue(&renderInfo, GpuUpload, 0); + tileQueue->unlockQueue(); if (renderInfo.measurePerf) m_perfMon.stop(TAG_UPDATE_TEXTURE); diff --git a/Source/WebCore/platform/graphics/android/GradientAndroid.cpp b/Source/WebCore/platform/graphics/android/GradientAndroid.cpp index b8dc9dd..6007a0a 100644 --- a/Source/WebCore/platform/graphics/android/GradientAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/GradientAndroid.cpp @@ -113,7 +113,6 @@ SkShader* Gradient::getShader(SkShader::TileMode mode) void Gradient::fill(GraphicsContext* context, const FloatRect& rect) { - SkRect r; SkPaint paint; // we don't care about the mode, so try to use the existing one SkShader::TileMode mode = m_gradient ? m_gradient->m_tileMode : diff --git a/Source/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp b/Source/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp index a490d5f..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" @@ -36,6 +37,7 @@ #include "SkBlurMaskFilter.h" #include "SkCanvas.h" #include "SkColorPriv.h" +#include "SkCornerPathEffect.h" #include "SkDashPathEffect.h" #include "SkDevice.h" #include "SkGradientShader.h" @@ -127,9 +129,6 @@ public: SkColor fillColor; SkColor strokeColor; bool useAA; - // This is a list of clipping paths which are currently active, in the - // order in which they were pushed. - WTF::Vector<SkPath> antiAliasClipPaths; State() : pathEffect(0) @@ -246,9 +245,6 @@ public: void restore() { - if (!m_state->antiAliasClipPaths.isEmpty()) - applyAntiAliasedClipPaths(m_state->antiAliasClipPaths); - m_state->~State(); m_stateStack.pop_back(); m_state = static_cast<State*>(m_stateStack.back()); @@ -370,51 +366,6 @@ public: return false; } - void clipPathAntiAliased(const SkPath& clipPath) - { - // If we are currently tracking any anti-alias clip paths, then we already - // have a layer in place and don't need to add another. - bool haveLayerOutstanding = m_state->antiAliasClipPaths.size(); - - // See comments in applyAntiAliasedClipPaths about how this works. - m_state->antiAliasClipPaths.append(clipPath); - if (!haveLayerOutstanding) { - SkRect bounds = clipPath.getBounds(); - if (m_platformGfxCtx && m_platformGfxCtx->mCanvas) { - m_platformGfxCtx->mCanvas->saveLayerAlpha(&bounds, 255, - static_cast<SkCanvas::SaveFlags>(SkCanvas::kHasAlphaLayer_SaveFlag - | SkCanvas::kFullColorLayer_SaveFlag - | SkCanvas::kClipToLayer_SaveFlag)); - m_platformGfxCtx->mCanvas->save(); - } else - ASSERT(0); - } - } - - void applyAntiAliasedClipPaths(WTF::Vector<SkPath>& paths) - { - // Anti-aliased clipping: - // - // Refer to PlatformContextSkia.cpp's applyAntiAliasedClipPaths() for more details - - if (m_platformGfxCtx && m_platformGfxCtx->mCanvas) - m_platformGfxCtx->mCanvas->restore(); - - SkPaint paint; - paint.setXfermodeMode(SkXfermode::kClear_Mode); - paint.setAntiAlias(true); - paint.setStyle(SkPaint::kFill_Style); - - if (m_platformGfxCtx && m_platformGfxCtx->mCanvas) { - for (size_t i = paths.size() - 1; i < paths.size(); --i) { - paths[i].setFillType(SkPath::kInverseWinding_FillType); - m_platformGfxCtx->mCanvas->drawPath(paths[i], paint); - } - m_platformGfxCtx->mCanvas->restore(); - } else - ASSERT(0); - } - PlatformGraphicsContext* getPlatformGfxCtx() { return m_platformGfxCtx; @@ -848,7 +799,7 @@ void GraphicsContext::clip(const Path& path) if (paintingDisabled()) return; - m_data->clipPathAntiAliased(*path.platformPath()); + GC2CANVAS(this)->clipPath(*path.platformPath(), SkRegion::kIntersect_Op, true); } void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness) @@ -868,7 +819,7 @@ void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness r.inset(SkIntToScalar(thickness + 1), SkIntToScalar(thickness + 1)); path.addOval(r, SkPath::kCCW_Direction); } - m_data->clipPathAntiAliased(path); + GC2CANVAS(this)->clipPath(path, SkRegion::kIntersect_Op, true); } void GraphicsContext::canvasClip(const Path& path) @@ -1000,9 +951,33 @@ void GraphicsContext::clearPlatformShadow() /////////////////////////////////////////////////////////////////////////////// -void GraphicsContext::drawFocusRing(const Vector<IntRect>&, int, int, const Color&) +void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int /* width */, int /* offset */, const Color& color) { - // Do nothing, since we draw the focus ring independently. + if (paintingDisabled()) + return; + + unsigned rectCount = rects.size(); + if (!rectCount) + return; + + SkRegion focusRingRegion; + const SkScalar focusRingOutset = WebCoreFloatToSkScalar(0.8); + for (unsigned i = 0; i < rectCount; i++) { + SkIRect r = rects[i]; + r.inset(-focusRingOutset, -focusRingOutset); + focusRingRegion.op(r, SkRegion::kUnion_Op); + } + + SkPath path; + SkPaint paint; + paint.setAntiAlias(true); + paint.setStyle(SkPaint::kStroke_Style); + + paint.setColor(color.rgb()); + paint.setStrokeWidth(focusRingOutset * 2); + paint.setPathEffect(new SkCornerPathEffect(focusRingOutset * 2))->unref(); + focusRingRegion.getBoundaryPath(&path); + platformContext()->mCanvas->drawPath(path, paint); } void GraphicsContext::drawFocusRing(const Path&, int, int, const Color&) @@ -1291,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/GraphicsLayerAndroid.cpp b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp index 567b54b..bb17784 100644 --- a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp @@ -555,6 +555,18 @@ void GraphicsLayerAndroid::updateScrollingLayers() #endif } +void GraphicsLayerAndroid::updateScrollOffset() { + RenderLayer* layer = renderLayerFromClient(m_client); + if (!layer || !(m_foregroundLayer || m_contentLayer->contentIsScrollable())) + return; + IntSize scroll = layer->scrolledContentOffset(); + if (m_foregroundLayer) + m_foregroundLayer->setScrollOffset(IntPoint(scroll.width(), scroll.height())); + else if (m_contentLayer->contentIsScrollable()) + static_cast<ScrollableLayerAndroid*>(m_contentLayer)->scrollTo(scroll.width(), scroll.height()); + askForSync(); +} + bool GraphicsLayerAndroid::repaint() { LOG("(%x) repaint(), gPaused(%d) m_needsRepaint(%d) m_haveContents(%d) ", @@ -573,14 +585,16 @@ bool GraphicsLayerAndroid::repaint() phase.set(GraphicsLayerPaintBackground); if (!paintContext(m_contentLayer->recordContext(), layerBounds)) return false; - m_contentLayer->checkTextPresence(); + m_contentLayer->checkForPictureOptimizations(); // Construct the foreground layer and draw. RenderBox* box = layer->renderBox(); int outline = box->view()->maximalOutlineSize(); IntRect contentsRect(0, 0, - box->borderLeft() + box->borderRight() + layer->scrollWidth(), - box->borderTop() + box->borderBottom() + layer->scrollHeight()); + box->borderLeft() + box->borderRight() + layer->scrollWidth() + + layer->verticalScrollbarWidth(), + box->borderTop() + box->borderBottom() + layer->scrollHeight() + + layer->horizontalScrollbarHeight()); contentsRect.inflate(outline); // Update the foreground layer size. m_foregroundLayer->setSize(contentsRect.width(), contentsRect.height()); @@ -592,7 +606,7 @@ bool GraphicsLayerAndroid::repaint() layer->scrollToOffset(0, 0); // At this point, it doesn't matter if painting failed. (void) paintContext(m_foregroundLayer->recordContext(), contentsRect); - m_foregroundLayer->checkTextPresence(); + m_foregroundLayer->checkForPictureOptimizations(); layer->scrollToOffset(scroll.width(), scroll.height()); // Construct the clip layer for masking the contents. @@ -606,6 +620,11 @@ bool GraphicsLayerAndroid::repaint() m_foregroundClipLayer->setPosition(x, y); m_foregroundClipLayer->setSize(width, height); + int rtlOffset = 0; // LTR uses no offset. + if (!layer->renderer()->style()->isLeftToRightDirection()) + rtlOffset = layer->scrollWidth() - width; // Scroll all the way right. + m_foregroundLayer->setScrollOffset(IntPoint(scroll.width() + rtlOffset, + scroll.height())); // Need to offset the foreground layer by the clip layer in order // for the contents to be in the correct position. m_foregroundLayer->setPosition(-x, -y); @@ -621,17 +640,27 @@ bool GraphicsLayerAndroid::repaint() m_foregroundLayer->markAsDirty(region); m_foregroundLayer->needsRepaint(); } else { + // Paint at 0,0. + IntSize scroll = layer->scrolledContentOffset(); + layer->scrollToOffset(0, 0); // If there is no contents clip, we can draw everything into one // picture. - if (!paintContext(m_contentLayer->recordContext(), layerBounds)) + bool painting = paintContext(m_contentLayer->recordContext(), layerBounds); + // Move back to the scroll offset + layer->scrollToOffset(scroll.width(), scroll.height()); + if (!painting) return false; - m_contentLayer->checkTextPresence(); + // We painted new content + m_contentLayer->checkForPictureOptimizations(); // Check for a scrollable iframe and report the scrolling // limits based on the view size. if (m_contentLayer->contentIsScrollable()) { FrameView* view = layer->renderer()->frame()->view(); static_cast<ScrollableLayerAndroid*>(m_contentLayer)->setScrollLimits( m_position.x(), m_position.y(), view->layoutWidth(), view->layoutHeight()); + LOG("setScrollLimits(%.2f, %.2f, w: %d h: %d) layer %d, frame scroll position is %d, %d (%d, %d)", + m_position.x(), m_position.y(), view->layoutWidth(), view->layoutHeight(), + m_contentLayer->uniqueId(), view->scrollX(), view->scrollY(), view->actualScrollX(), view->actualScrollY()); } } @@ -749,7 +778,7 @@ bool GraphicsLayerAndroid::createAnimationFromKeyframes(const KeyframeValueList& KeyframeValueList* operationsList = new KeyframeValueList(AnimatedPropertyOpacity); for (unsigned int i = 0; i < valueList.size(); i++) { FloatAnimationValue* originalValue = (FloatAnimationValue*)valueList.at(i); - PassRefPtr<TimingFunction> timingFunction(const_cast<TimingFunction*>(originalValue->timingFunction())); + RefPtr<TimingFunction> timingFunction(const_cast<TimingFunction*>(originalValue->timingFunction())); FloatAnimationValue* value = new FloatAnimationValue(originalValue->keyTime(), originalValue->value(), timingFunction); @@ -791,7 +820,7 @@ bool GraphicsLayerAndroid::createTransformAnimationsFromKeyframes(const Keyframe KeyframeValueList* operationsList = new KeyframeValueList(AnimatedPropertyWebkitTransform); for (unsigned int i = 0; i < valueList.size(); i++) { TransformAnimationValue* originalValue = (TransformAnimationValue*)valueList.at(i); - PassRefPtr<TimingFunction> timingFunction(const_cast<TimingFunction*>(originalValue->timingFunction())); + RefPtr<TimingFunction> timingFunction(const_cast<TimingFunction*>(originalValue->timingFunction())); TransformAnimationValue* value = new TransformAnimationValue(originalValue->keyTime(), originalValue->value(), timingFunction); diff --git a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.h b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.h index e6d75b0..4c049cd 100644 --- a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.h +++ b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.h @@ -25,6 +25,7 @@ #include "GraphicsLayerClient.h" #include "LayerAndroid.h" #include "RefPtr.h" +#include "ScrollableLayerAndroid.h" #include "SkBitmapRef.h" #include "Vector.h" @@ -122,9 +123,12 @@ public: void notifyClientAnimationStarted(); LayerAndroid* contentLayer() { return m_contentLayer; } + ScrollableLayerAndroid* foregroundLayer() { return m_foregroundLayer; } static int instancesCount(); + virtual void updateScrollOffset(); + private: void askForSync(); diff --git a/Source/WebCore/platform/graphics/android/ImageAndroid.cpp b/Source/WebCore/platform/graphics/android/ImageAndroid.cpp index 01fe272..8e0c112 100644 --- a/Source/WebCore/platform/graphics/android/ImageAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/ImageAndroid.cpp @@ -44,7 +44,7 @@ #include "SkTemplates.h" #include "SkiaUtils.h" -#include <utils/AssetManager.h> +#include <androidfw/AssetManager.h> //#define TRACE_SUBSAMPLED_BITMAPS //#define TRACE_SKIPPED_BITMAPS diff --git a/Source/WebCore/platform/graphics/android/ImageBufferAndroid.cpp b/Source/WebCore/platform/graphics/android/ImageBufferAndroid.cpp index 751a08f..f148881 100644 --- a/Source/WebCore/platform/graphics/android/ImageBufferAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/ImageBufferAndroid.cpp @@ -196,7 +196,7 @@ void ImageBuffer::putUnmultipliedImageData(ByteArray* source, const IntSize& sou ASSERT(destx >= 0); ASSERT(destx < m_size.width()); ASSERT(originx >= 0); - ASSERT(originx <= sourceRect.right()); + ASSERT(originx <= sourceRect.maxX()); int endx = destPoint.x() + sourceRect.maxX(); ASSERT(endx <= m_size.width()); @@ -208,7 +208,7 @@ void ImageBuffer::putUnmultipliedImageData(ByteArray* source, const IntSize& sou ASSERT(desty >= 0); ASSERT(desty < m_size.height()); ASSERT(originy >= 0); - ASSERT(originy <= sourceRect.bottom()); + ASSERT(originy <= sourceRect.maxY()); int endy = destPoint.y() + sourceRect.maxY(); ASSERT(endy <= m_size.height()); diff --git a/Source/WebCore/platform/graphics/android/ImageTexture.cpp b/Source/WebCore/platform/graphics/android/ImageTexture.cpp index 577e7f0..0ca8ee7 100644 --- a/Source/WebCore/platform/graphics/android/ImageTexture.cpp +++ b/Source/WebCore/platform/graphics/android/ImageTexture.cpp @@ -240,8 +240,10 @@ void ImageTexture::drawGL(LayerAndroid* layer) // TiledTexture::draw() will call us back to know the // transform and opacity, so we need to set m_layer m_layer = layer; - if (m_texture) - m_texture->draw(); + if (m_texture) { + IntRect visibleArea = m_layer->visibleArea(); + m_texture->draw(visibleArea); + } m_layer = 0; } diff --git a/Source/WebCore/platform/graphics/android/InspectorCanvas.cpp b/Source/WebCore/platform/graphics/android/InspectorCanvas.cpp new file mode 100644 index 0000000..0137cec --- /dev/null +++ b/Source/WebCore/platform/graphics/android/InspectorCanvas.cpp @@ -0,0 +1,149 @@ +/* + * Copyright 2011, 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 "InspectorCanvas.h" + +#include "SkPicture.h" + +#include <cutils/log.h> +#include <wtf/CurrentTime.h> +#include <wtf/text/CString.h> + +#undef XLOGC +#define XLOGC(...) android_printLog(ANDROID_LOG_DEBUG, "InspectorCanvas", __VA_ARGS__) + +#ifdef DEBUG + +#undef XLOG +#define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "InspectorCanvas", __VA_ARGS__) + +#else + +#undef XLOG +#define XLOG(...) + +#endif // DEBUG + + +namespace WebCore { + + +void InspectorCanvas::setHasText() +{ + m_hasText = true; + setHasContent(); +} + +void InspectorCanvas::setHasContent() +{ + m_hasContent = true; + if (m_hasText) { + // has text. Have to paint properly, so no further + // information is useful + m_picture->abortPlayback(); + } +} + +void InspectorCanvas::setIsBackground(const SkPaint& paint) +{ + // TODO: if the paint is a solid color, opaque, and the last instruction in + // the picture, replace the picture with simple draw rect info + setHasContent(); +} + +void InspectorCanvas::commonDrawBitmap(const SkBitmap& bitmap, + const SkIRect* rect, + const SkMatrix&, + const SkPaint&) +{ + setHasContent(); +} + +void InspectorCanvas::drawPaint(const SkPaint& paint) +{ + setHasContent(); +} + +void InspectorCanvas::drawPath(const SkPath&, const SkPaint& paint) +{ + setHasContent(); +} +void InspectorCanvas::drawPoints(PointMode, size_t, + const SkPoint [], const SkPaint& paint) +{ + setHasContent(); +} + +void InspectorCanvas::drawRect(const SkRect& rect, const SkPaint& paint) +{ + if (rect.fLeft == 0 + && rect.fTop == 0 + && rect.width() >= m_picture->width() + && rect.height() >= m_picture->height()) { + // rect same size as canvas, treat layer as a single color rect until + // more content is drawn + setIsBackground(paint); + } else { + // regular rect drawing path + setHasContent(); + } + XLOG("draw rect at %f %f, size %f %f, picture size %d %d", + rect.fLeft, rect.fTop, rect.width(), rect.height(), + m_picture->width(), m_picture->height()); +} +void InspectorCanvas::drawSprite(const SkBitmap& , int , int , + const SkPaint* paint) +{ + setHasContent(); +} + +void InspectorCanvas::drawText(const void*, size_t byteLength, SkScalar, + SkScalar, const SkPaint& paint) +{ + setHasText(); +} + +void InspectorCanvas::drawPosText(const void* , size_t byteLength, + const SkPoint [], const SkPaint& paint) +{ + setHasText(); +} + +void InspectorCanvas::drawPosTextH(const void*, size_t byteLength, + const SkScalar [], SkScalar, + const SkPaint& paint) +{ + setHasText(); +} + +void InspectorCanvas::drawTextOnPath(const void*, size_t byteLength, + const SkPath&, const SkMatrix*, + const SkPaint& paint) +{ + setHasText(); +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/InspectorCanvas.h b/Source/WebCore/platform/graphics/android/InspectorCanvas.h new file mode 100644 index 0000000..415a579 --- /dev/null +++ b/Source/WebCore/platform/graphics/android/InspectorCanvas.h @@ -0,0 +1,102 @@ +/* + * Copyright 2011, 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 InspectorCanvas_h +#define InspectorCanvas_h + +#include "SkBounder.h" +#include "SkCanvas.h" + +namespace WebCore { + +class InspectorBounder : public SkBounder { + virtual bool onIRect(const SkIRect& rect) + { + return false; + } +}; + +class InspectorCanvas : public SkCanvas { +public: + InspectorCanvas(SkBounder* bounder, SkPicture* picture) + : m_picture(picture) + , m_hasText(false) + , m_hasContent(false) + { + setBounder(bounder); + } + + bool hasText() {return m_hasText;} + bool hasContent() {return m_hasContent;} + + virtual bool clipPath(const SkPath&, SkRegion::Op) { + return true; + } + + virtual void commonDrawBitmap(const SkBitmap& bitmap, + const SkIRect* rect, + const SkMatrix&, + const SkPaint&); + + virtual void drawPaint(const SkPaint& paint); + virtual void drawPath(const SkPath&, const SkPaint& paint); + virtual void drawPoints(PointMode, size_t, + const SkPoint [], const SkPaint& paint); + + virtual void drawRect(const SkRect& , const SkPaint& paint); + virtual void drawSprite(const SkBitmap& , int , int , + const SkPaint* paint = NULL); + + virtual void drawText(const void*, size_t byteLength, SkScalar, + SkScalar, const SkPaint& paint); + virtual void drawPosText(const void* , size_t byteLength, + const SkPoint [], const SkPaint& paint); + virtual void drawPosTextH(const void*, size_t byteLength, + const SkScalar [], SkScalar, + const SkPaint& paint); + virtual void drawTextOnPath(const void*, size_t byteLength, + const SkPath&, const SkMatrix*, + const SkPaint& paint); + +private: + + // vector instructions exist, must repaint at any scale + void setHasText(); + + // painting is required + void setHasContent(); + + // rect covering entire content, don't need to use a texture if nothing else + // is painted + void setIsBackground(const SkPaint& paint); + + SkPicture* m_picture; + bool m_hasText; + bool m_hasContent; +}; + +} // namespace WebCore + +#endif // InspectorCanvas_h diff --git a/Source/WebCore/platform/graphics/android/Layer.cpp b/Source/WebCore/platform/graphics/android/Layer.cpp index 9280461..f58d648 100644 --- a/Source/WebCore/platform/graphics/android/Layer.cpp +++ b/Source/WebCore/platform/graphics/android/Layer.cpp @@ -158,13 +158,13 @@ void Layer::localToAncestor(const Layer* ancestor, SkMatrix* matrix) const { /////////////////////////////////////////////////////////////////////////////// -void Layer::onDraw(SkCanvas*, SkScalar opacity) { +void Layer::onDraw(SkCanvas*, SkScalar opacity, android::DrawExtra* extra) { // SkDebugf("----- no onDraw for %p\n", this); } #include "SkString.h" -void Layer::draw(SkCanvas* canvas, SkScalar opacity) { +void Layer::draw(SkCanvas* canvas, android::DrawExtra* extra, SkScalar opacity) { #if 0 SkString str1, str2; // getMatrix().toDumpString(&str1); @@ -193,7 +193,7 @@ void Layer::draw(SkCanvas* canvas, SkScalar opacity) { canvas->concat(tmp); } - onDraw(canvas, opacity); + onDraw(canvas, opacity, extra); #ifdef DEBUG_DRAW_LAYER_BOUNDS { @@ -213,7 +213,7 @@ void Layer::draw(SkCanvas* canvas, SkScalar opacity) { if (count > 0) { canvas->concat(getChildrenMatrix()); for (int i = 0; i < count; i++) { - getChild(i)->draw(canvas, opacity); + getChild(i)->draw(canvas, extra, opacity); } } } diff --git a/Source/WebCore/platform/graphics/android/Layer.h b/Source/WebCore/platform/graphics/android/Layer.h index 5200a3d..876ca24 100644 --- a/Source/WebCore/platform/graphics/android/Layer.h +++ b/Source/WebCore/platform/graphics/android/Layer.h @@ -17,6 +17,7 @@ #ifndef Layer_DEFINED #define Layer_DEFINED +#include "DrawExtra.h" #include "TestExport.h" #include "SkRefCnt.h" #include "SkTDArray.h" @@ -165,17 +166,14 @@ public: // paint method virtual bool drawCanvas(SkCanvas*) { return false; } - void draw(SkCanvas*, SkScalar opacity); - void draw(SkCanvas* canvas) { - this->draw(canvas, SK_Scalar1); - } + void draw(SkCanvas*, android::DrawExtra* extra, SkScalar opacity = SK_Scalar1); void setHasOverflowChildren(bool value) { m_hasOverflowChildren = value; } virtual bool contentIsScrollable() const { return false; } protected: - virtual void onDraw(SkCanvas*, SkScalar opacity); + virtual void onDraw(SkCanvas*, SkScalar opacity, android::DrawExtra* extra); bool m_hasOverflowChildren; diff --git a/Source/WebCore/platform/graphics/android/LayerAndroid.cpp b/Source/WebCore/platform/graphics/android/LayerAndroid.cpp index 962bcdf..b4e20e8 100644 --- a/Source/WebCore/platform/graphics/android/LayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/LayerAndroid.cpp @@ -8,11 +8,11 @@ #include "DrawExtra.h" #include "GLUtils.h" #include "ImagesManager.h" +#include "InspectorCanvas.h" #include "MediaLayer.h" #include "PaintedSurface.h" #include "ParseCanvas.h" #include "SkBitmapRef.h" -#include "SkBounder.h" #include "SkDrawFilter.h" #include "SkPaint.h" #include "SkPicture.h" @@ -55,87 +55,6 @@ private: int m_opacity; }; -class HasTextBounder : public SkBounder { - virtual bool onIRect(const SkIRect& rect) - { - return false; - } -}; - -class HasTextCanvas : public SkCanvas { -public: - HasTextCanvas(SkBounder* bounder, SkPicture* picture) - : m_picture(picture) - , m_hasText(false) - { - setBounder(bounder); - } - - void setHasText() - { - m_hasText = true; - m_picture->abortPlayback(); - } - - bool hasText() - { - return m_hasText; - } - - virtual bool clipPath(const SkPath&, SkRegion::Op) { - return true; - } - - virtual void commonDrawBitmap(const SkBitmap& bitmap, - const SkIRect* rect, - const SkMatrix&, - const SkPaint&) {} - - virtual void drawPaint(const SkPaint& paint) {} - virtual void drawPath(const SkPath&, const SkPaint& paint) {} - virtual void drawPoints(PointMode, size_t, - const SkPoint [], const SkPaint& paint) {} - - virtual void drawRect(const SkRect& , const SkPaint& paint) {} - virtual void drawSprite(const SkBitmap& , int , int , - const SkPaint* paint = NULL) {} - - virtual void drawText(const void*, size_t byteLength, SkScalar, - SkScalar, const SkPaint& paint) - { - setHasText(); - } - - virtual void drawPosText(const void* , size_t byteLength, - const SkPoint [], const SkPaint& paint) - { - setHasText(); - } - - virtual void drawPosTextH(const void*, size_t byteLength, - const SkScalar [], SkScalar, - const SkPaint& paint) - { - setHasText(); - } - - virtual void drawTextOnPath(const void*, size_t byteLength, - const SkPath&, const SkMatrix*, - const SkPaint& paint) - { - setHasText(); - } - - virtual void drawPicture(SkPicture& picture) { - SkCanvas::drawPicture(picture); - } - -private: - - SkPicture* m_picture; - bool m_hasText; -}; - /////////////////////////////////////////////////////////////////////////////// LayerAndroid::LayerAndroid(RenderLayer* owner) : Layer(), @@ -198,6 +117,7 @@ LayerAndroid::LayerAndroid(const LayerAndroid& layer) : Layer(layer), m_fixedMarginBottom = layer.m_fixedMarginBottom; m_fixedRect = layer.m_fixedRect; m_iframeOffset = layer.m_iframeOffset; + m_offset = layer.m_offset; m_recordingPicture = layer.m_recordingPicture; SkSafeRef(m_recordingPicture); @@ -226,13 +146,13 @@ LayerAndroid::LayerAndroid(const LayerAndroid& layer) : Layer(layer), #endif } -void LayerAndroid::checkTextPresence() +void LayerAndroid::checkForPictureOptimizations() { if (m_recordingPicture) { // Let's check if we have text or not. If we don't, we can limit // ourselves to scale 1! - HasTextBounder hasTextBounder; - HasTextCanvas checker(&hasTextBounder, m_recordingPicture); + InspectorBounder inspectorBounder; + InspectorCanvas checker(&inspectorBounder, m_recordingPicture); SkBitmap bitmap; bitmap.setConfig(SkBitmap::kARGB_8888_Config, m_recordingPicture->width(), @@ -240,6 +160,12 @@ void LayerAndroid::checkTextPresence() checker.setBitmapDevice(bitmap); checker.drawPicture(*m_recordingPicture); m_hasText = checker.hasText(); + if (!checker.hasContent()) { + // no content to draw, discard picture so UI / tile generation + // doesn't bother with it + SkSafeUnref(m_recordingPicture); + m_recordingPicture = 0; + } } } @@ -395,8 +321,6 @@ void LayerAndroid::setBackgroundColor(SkColor color) m_backgroundColor = color; } -static int gDebugChildLevel; - FloatPoint LayerAndroid::translation() const { TransformationMatrix::DecomposedType tDecomp; @@ -685,9 +609,7 @@ void LayerAndroid::updateGLPositionsAndScale(const TransformationMatrix& parentM m_atomicSync.lock(); IntSize layerSize(getSize().width(), getSize().height()); FloatPoint anchorPoint(getAnchorPoint().fX, getAnchorPoint().fY); - FloatPoint position(getPosition().fX, getPosition().fY); - float centerOffsetX = (0.5f - anchorPoint.x()) * layerSize.width(); - float centerOffsetY = (0.5f - anchorPoint.y()) * layerSize.height(); + FloatPoint position(getPosition().fX - m_offset.x(), getPosition().fY - m_offset.y()); float originX = anchorPoint.x() * layerSize.width(); float originY = anchorPoint.y() * layerSize.height(); TransformationMatrix localMatrix; @@ -759,13 +681,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) @@ -1096,7 +1021,7 @@ bool LayerAndroid::drawCanvas(SkCanvas* canvas) layerRect.fTop = 0; layerRect.fRight = getWidth(); layerRect.fBottom = getHeight(); - onDraw(canvas, m_drawOpacity); + onDraw(canvas, m_drawOpacity, 0); } // When the layer is dirty, the UI thread should be notified to redraw. @@ -1129,6 +1054,8 @@ bool LayerAndroid::drawGL() } } + m_state->glExtras()->drawGL(this); + // When the layer is dirty, the UI thread should be notified to redraw. askScreenUpdate |= drawChildrenGL(); m_atomicSync.lock(); @@ -1205,7 +1132,7 @@ void LayerAndroid::contentDraw(SkCanvas* canvas) } } -void LayerAndroid::onDraw(SkCanvas* canvas, SkScalar opacity) +void LayerAndroid::onDraw(SkCanvas* canvas, SkScalar opacity, android::DrawExtra* extra) { if (m_haveClip) { SkRect r; @@ -1235,6 +1162,8 @@ void LayerAndroid::onDraw(SkCanvas* canvas, SkScalar opacity) ImagesManager::instance()->releaseImage(m_imageCRC); } contentDraw(canvas); + if (extra) + extra->draw(canvas, this); } SkPicture* LayerAndroid::recordContext() diff --git a/Source/WebCore/platform/graphics/android/LayerAndroid.h b/Source/WebCore/platform/graphics/android/LayerAndroid.h index c1f1bc9..d33eea1 100644 --- a/Source/WebCore/platform/graphics/android/LayerAndroid.h +++ b/Source/WebCore/platform/graphics/android/LayerAndroid.h @@ -199,6 +199,8 @@ public: setShouldInheritFromRootTransform(true); } + const IntPoint& scrollOffset() const { return m_offset; } + void setScrollOffset(IntPoint offset) { m_offset = offset; } void setBackgroundColor(SkColor color); void setMaskLayer(LayerAndroid*); void setMasksToBounds(bool masksToBounds) @@ -302,7 +304,7 @@ public: int type() { return m_type; } bool hasText() { return m_hasText; } - void checkTextPresence(); + void checkForPictureOptimizations(); void copyAnimationStartTimesRecursive(LayerAndroid* oldTree); @@ -314,8 +316,8 @@ public: bool isReady(); protected: - virtual void onDraw(SkCanvas*, SkScalar opacity); - + virtual void onDraw(SkCanvas*, SkScalar opacity, android::DrawExtra* extra); + IntPoint m_offset; TransformationMatrix m_drawTransform; private: diff --git a/Source/WebCore/platform/graphics/android/MediaPlayerPrivateAndroid.h b/Source/WebCore/platform/graphics/android/MediaPlayerPrivateAndroid.h index 404ef08..535e7ae 100644 --- a/Source/WebCore/platform/graphics/android/MediaPlayerPrivateAndroid.h +++ b/Source/WebCore/platform/graphics/android/MediaPlayerPrivateAndroid.h @@ -95,6 +95,7 @@ public: virtual void onPosterFetched(SkBitmap*) { } void onBuffering(int percent); void onTimeupdate(int position); + void onRestoreState(); // These following two functions are used to turn on inline video support bool supportsAcceleratedRendering() const { return true; } diff --git a/Source/WebCore/platform/graphics/android/MediaTexture.cpp b/Source/WebCore/platform/graphics/android/MediaTexture.cpp index 1676186..2582a53 100644 --- a/Source/WebCore/platform/graphics/android/MediaTexture.cpp +++ b/Source/WebCore/platform/graphics/android/MediaTexture.cpp @@ -191,8 +191,7 @@ void MediaTexture::draw(const TransformationMatrix& contentMatrix, bool forceAlphaBlending = !( PIXEL_FORMAT_RGBX_8888 == f || PIXEL_FORMAT_RGB_888 == f || - PIXEL_FORMAT_RGB_565 == f || - PIXEL_FORMAT_RGB_332 == f); + PIXEL_FORMAT_RGB_565 == f); TilesManager::instance()->shader()->drawLayerQuad(contentMatrix, mediaBounds, @@ -283,7 +282,6 @@ void MediaTexture::setDimensions(const ANativeWindow* window, void MediaTexture::setFramerateCallback(const ANativeWindow* window, FramerateCallbackProc callback) { - XLOG("Release ANW %p (%p):(%p)", this, m_surfaceTexture.get(), m_surfaceTextureClient.get()); android::Mutex::Autolock lock(m_mediaLock); for (unsigned int i = 0; i < m_videoTextures.size(); i++) { if (m_videoTextures[i]->nativeWindow.get() == window) { diff --git a/Source/WebCore/platform/graphics/android/PaintedSurface.cpp b/Source/WebCore/platform/graphics/android/PaintedSurface.cpp index 45c7579..b65c64a 100644 --- a/Source/WebCore/platform/graphics/android/PaintedSurface.cpp +++ b/Source/WebCore/platform/graphics/android/PaintedSurface.cpp @@ -99,7 +99,7 @@ void PaintedSurface::prepare(GLWebViewState* state) paintingLayer->uniqueId(), paintingLayer, paintingLayer->getScale()); - IntRect visibleArea = computeVisibleArea(paintingLayer); + IntRect prepareArea = computePrepareArea(paintingLayer); m_scale = state->scale(); @@ -109,7 +109,7 @@ void PaintedSurface::prepare(GLWebViewState* state) m_scale = 1; m_tiledTexture->prepare(state, m_scale, m_pictureUsed != paintingLayer->pictureUsed(), - startFastSwap, visibleArea); + startFastSwap, prepareArea); } bool PaintedSurface::draw() @@ -118,8 +118,10 @@ bool PaintedSurface::draw() return false; bool askRedraw = false; - if (m_tiledTexture) - askRedraw = m_tiledTexture->draw(); + if (m_tiledTexture) { + IntRect visibleArea = m_drawingLayer->visibleArea(); + askRedraw = m_tiledTexture->draw(visibleArea); + } return askRedraw; } @@ -196,7 +198,7 @@ void PaintedSurface::computeTexturesAmount(TexturesResult* result) result->full += nbTexturesUnclipped; } -IntRect PaintedSurface::computeVisibleArea(LayerAndroid* layer) { +IntRect PaintedSurface::computePrepareArea(LayerAndroid* layer) { IntRect area; if (!layer) return area; diff --git a/Source/WebCore/platform/graphics/android/PaintedSurface.h b/Source/WebCore/platform/graphics/android/PaintedSurface.h index b8ab7b8..0f201a7 100644 --- a/Source/WebCore/platform/graphics/android/PaintedSurface.h +++ b/Source/WebCore/platform/graphics/android/PaintedSurface.h @@ -67,7 +67,7 @@ public: bool owns(BaseTileTexture* texture); void computeTexturesAmount(TexturesResult*); - IntRect computeVisibleArea(LayerAndroid*); + IntRect computePrepareArea(LayerAndroid*); // TilePainter methods for TiledTexture virtual const TransformationMatrix* transform(); diff --git a/Source/WebCore/platform/graphics/android/PerformanceMonitor.cpp b/Source/WebCore/platform/graphics/android/PerformanceMonitor.cpp index 241cbef..902fa1e 100644 --- a/Source/WebCore/platform/graphics/android/PerformanceMonitor.cpp +++ b/Source/WebCore/platform/graphics/android/PerformanceMonitor.cpp @@ -69,7 +69,6 @@ void PerformanceMonitor::stop(const String &tag) float mtime = (seconds * 1000.0) + (useconds/1000.0); - float avg = 0; if (item->average_ms) { item->average_ms = (item->average_ms + mtime) / 2; } else diff --git a/Source/WebCore/platform/graphics/android/PlatformGraphicsContext.h b/Source/WebCore/platform/graphics/android/PlatformGraphicsContext.h index d22dbd8..80ea5d6 100644 --- a/Source/WebCore/platform/graphics/android/PlatformGraphicsContext.h +++ b/Source/WebCore/platform/graphics/android/PlatformGraphicsContext.h @@ -28,7 +28,6 @@ #include "IntRect.h" #include "RenderSkinAndroid.h" -#include "RenderSkinButton.h" #include "SkCanvas.h" #include "SkPicture.h" #include "SkTDArray.h" diff --git a/Source/WebCore/platform/graphics/android/RasterRenderer.cpp b/Source/WebCore/platform/graphics/android/RasterRenderer.cpp index 9991fbd..f52af60 100644 --- a/Source/WebCore/platform/graphics/android/RasterRenderer.cpp +++ b/Source/WebCore/platform/graphics/android/RasterRenderer.cpp @@ -112,8 +112,14 @@ void RasterRenderer::setupCanvas(const TileRenderInfo& renderInfo, SkCanvas* can device->unref(); - // ensure the canvas origin is translated to the coordinates of our inval rect - canvas->translate(-renderInfo.invalRect->fLeft, -renderInfo.invalRect->fTop); + // If we have a partially painted bitmap + if (renderInfo.invalRect) { + SkRect clipRect = SkRect::MakeWH(renderInfo.invalRect->width(), + renderInfo.invalRect->height()); + // ensure the canvas origin is translated to the coordinates of our inval rect + canvas->clipRect(clipRect); + canvas->translate(-renderInfo.invalRect->fLeft, -renderInfo.invalRect->fTop); + } } void RasterRenderer::renderingComplete(const TileRenderInfo& renderInfo, SkCanvas* canvas) diff --git a/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.cpp b/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.cpp index 3c2ced5..27a7df5 100644 --- a/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.cpp @@ -9,27 +9,33 @@ namespace WebCore { bool ScrollableLayerAndroid::scrollTo(int x, int y) { - SkIRect scrollBounds; - getScrollRect(&scrollBounds); - if (!scrollBounds.fRight && !scrollBounds.fBottom) + IntRect scrollBounds; + getScrollBounds(&scrollBounds); + if (!scrollBounds.width() && !scrollBounds.height()) return false; - - SkScalar newX = SkScalarPin(x, 0, scrollBounds.fRight); - SkScalar newY = SkScalarPin(y, 0, scrollBounds.fBottom); + SkScalar newX = SkScalarPin(x, scrollBounds.x(), scrollBounds.width()); + SkScalar newY = SkScalarPin(y, scrollBounds.y(), scrollBounds.height()); // Check for no change. - if (newX == scrollBounds.fLeft && newY == scrollBounds.fTop) + if (newX == m_offset.x() && newY == m_offset.y()) return false; - - setPosition(m_scrollLimits.fLeft - newX, m_scrollLimits.fTop - newY); - + setScrollOffset(IntPoint(newX, newY)); return true; } +void ScrollableLayerAndroid::getScrollBounds(IntRect* out) const +{ + const SkPoint& pos = getPosition(); + out->setX(m_scrollLimits.fLeft - pos.fX); + out->setY(m_scrollLimits.fTop - pos.fY); + out->setWidth(getSize().width() - m_scrollLimits.width()); + out->setHeight(getSize().height() - m_scrollLimits.height()); +} + void ScrollableLayerAndroid::getScrollRect(SkIRect* out) const { const SkPoint& pos = getPosition(); - out->fLeft = m_scrollLimits.fLeft - pos.fX; - out->fTop = m_scrollLimits.fTop - pos.fY; + out->fLeft = m_scrollLimits.fLeft - pos.fX + m_offset.x(); + out->fTop = m_scrollLimits.fTop - pos.fY + m_offset.y(); out->fRight = getSize().width() - m_scrollLimits.width(); out->fBottom = getSize().height() - m_scrollLimits.height(); } diff --git a/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.h b/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.h index 5cba5d9..b8ff299 100644 --- a/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.h +++ b/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.h @@ -71,6 +71,9 @@ public: friend LayerAndroid* android::deserializeLayer(SkStream* stream); private: + + void getScrollBounds(IntRect*) const; + // The position of the visible area of the layer, relative to the parent // layer. This is fixed during scrolling. We acheive scrolling by modifying // the position of the layer. diff --git a/Source/WebCore/platform/graphics/android/ShaderProgram.cpp b/Source/WebCore/platform/graphics/android/ShaderProgram.cpp index 2a6a488..4925bd6 100644 --- a/Source/WebCore/platform/graphics/android/ShaderProgram.cpp +++ b/Source/WebCore/platform/graphics/android/ShaderProgram.cpp @@ -38,9 +38,21 @@ #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 #define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "ShaderProgram", __VA_ARGS__) +#else + +#undef XLOG +#define XLOG(...) + +#endif // DEBUG + namespace WebCore { static const char gVertexShader[] = @@ -62,6 +74,26 @@ static const char gFragmentShader[] = " gl_FragColor *= alpha; " "}\n"; +// We could pass the pureColor into either Vertex or Frag Shader. +// The reason we passed the color into the Vertex Shader is that some driver +// might create redundant copy when uniforms in fragment shader changed. +static const char gPureColorVertexShader[] = + "attribute vec4 vPosition;\n" + "uniform mat4 projectionMatrix;\n" + "uniform vec4 inputColor;\n" + "varying vec4 v_color;\n" + "void main() {\n" + " gl_Position = projectionMatrix * vPosition;\n" + " v_color = inputColor;\n" + "}\n"; + +static const char gPureColorFragmentShader[] = + "precision mediump float;\n" + "varying vec4 v_color;\n" + "void main() {\n" + " gl_FragColor = v_color;\n" + "}\n"; + static const char gFragmentShaderInverted[] = "precision mediump float;\n" "varying vec2 v_texCoord; \n" @@ -140,7 +172,7 @@ GLuint ShaderProgram::loadShader(GLenum shaderType, const char* pSource) char* buf = (char*) malloc(infoLen); if (buf) { glGetShaderInfoLog(shader, infoLen, 0, buf); - XLOG("could not compile shader %d:\n%s\n", shaderType, buf); + XLOGC("could not compile shader %d:\n%s\n", shaderType, buf); free(buf); } glDeleteShader(shader); @@ -151,17 +183,17 @@ GLuint ShaderProgram::loadShader(GLenum shaderType, const char* pSource) return shader; } -GLuint ShaderProgram::createProgram(const char* pVertexSource, const char* pFragmentSource) +GLint ShaderProgram::createProgram(const char* pVertexSource, const char* pFragmentSource) { GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource); if (!vertexShader) { - XLOG("couldn't load the vertex shader!"); + XLOGC("couldn't load the vertex shader!"); return -1; } GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource); if (!pixelShader) { - XLOG("couldn't load the pixel shader!"); + XLOGC("couldn't load the pixel shader!"); return -1; } @@ -181,7 +213,7 @@ GLuint ShaderProgram::createProgram(const char* pVertexSource, const char* pFrag char* buf = (char*) malloc(bufLength); if (buf) { glGetProgramInfoLog(program, bufLength, 0, buf); - XLOG("could not link program:\n%s\n", buf); + XLOGC("could not link program:\n%s\n", buf); free(buf); } } @@ -197,57 +229,83 @@ ShaderProgram::ShaderProgram() , m_contrast(1) , m_alphaLayer(false) , m_currentScale(1.0f) + , m_needsInit(true) { - init(); } void ShaderProgram::init() { - m_program = createProgram(gVertexShader, gFragmentShader); - m_programInverted = createProgram(gVertexShader, gFragmentShaderInverted); - m_videoProgram = createProgram(gVideoVertexShader, gVideoFragmentShader); - m_surfTexOESProgram = + // To detect whether or not resources for ShaderProgram allocated + // successfully, we clean up pre-existing errors here and will check for + // new errors at the end of this function. + GLUtils::checkGlError("before init"); + + GLint tex2DProgram = createProgram(gVertexShader, gFragmentShader); + GLint pureColorProgram = createProgram(gPureColorVertexShader, gPureColorFragmentShader); + GLint tex2DInvProgram = createProgram(gVertexShader, gFragmentShaderInverted); + GLint videoProgram = createProgram(gVideoVertexShader, gVideoFragmentShader); + GLint texOESProgram = createProgram(gVertexShader, gSurfaceTextureOESFragmentShader); - m_surfTexOESProgramInverted = + GLint texOESInvProgram = createProgram(gVertexShader, gSurfaceTextureOESFragmentShaderInverted); - if (m_program == -1 - || m_programInverted == -1 - || m_videoProgram == -1 - || m_surfTexOESProgram == -1 - || m_surfTexOESProgramInverted == -1) + if (tex2DProgram == -1 + || pureColorProgram == -1 + || tex2DInvProgram == -1 + || videoProgram == -1 + || texOESProgram == -1 + || texOESInvProgram == -1) { + m_needsInit = true; return; + } - m_hProjectionMatrix = glGetUniformLocation(m_program, "projectionMatrix"); - m_hAlpha = glGetUniformLocation(m_program, "alpha"); - m_hTexSampler = glGetUniformLocation(m_program, "s_texture"); - m_hPosition = glGetAttribLocation(m_program, "vPosition"); - - m_hProjectionMatrixInverted = glGetUniformLocation(m_programInverted, "projectionMatrix"); - m_hAlphaInverted = glGetUniformLocation(m_programInverted, "alpha"); - m_hContrastInverted = glGetUniformLocation(m_surfTexOESProgramInverted, "contrast"); - m_hTexSamplerInverted = glGetUniformLocation(m_programInverted, "s_texture"); - m_hPositionInverted = glGetAttribLocation(m_programInverted, "vPosition"); - - m_hVideoProjectionMatrix = - glGetUniformLocation(m_videoProgram, "projectionMatrix"); - m_hVideoTextureMatrix = glGetUniformLocation(m_videoProgram, "textureMatrix"); - m_hVideoTexSampler = glGetUniformLocation(m_videoProgram, "s_yuvTexture"); - m_hVideoPosition = glGetAttribLocation(m_program, "vPosition"); - - m_hSTOESProjectionMatrix = - glGetUniformLocation(m_surfTexOESProgram, "projectionMatrix"); - m_hSTOESAlpha = glGetUniformLocation(m_surfTexOESProgram, "alpha"); - m_hSTOESTexSampler = glGetUniformLocation(m_surfTexOESProgram, "s_texture"); - m_hSTOESPosition = glGetAttribLocation(m_surfTexOESProgram, "vPosition"); - - m_hSTOESProjectionMatrixInverted = - glGetUniformLocation(m_surfTexOESProgramInverted, "projectionMatrix"); - m_hSTOESAlphaInverted = glGetUniformLocation(m_surfTexOESProgramInverted, "alpha"); - m_hSTOESContrastInverted = glGetUniformLocation(m_surfTexOESProgramInverted, "contrast"); - m_hSTOESTexSamplerInverted = glGetUniformLocation(m_surfTexOESProgramInverted, "s_texture"); - m_hSTOESPositionInverted = glGetAttribLocation(m_surfTexOESProgramInverted, "vPosition"); - + GLint pureColorPosition = glGetAttribLocation(pureColorProgram, "vPosition"); + GLint pureColorProjMtx = glGetUniformLocation(pureColorProgram, "projectionMatrix"); + GLint pureColorValue = glGetUniformLocation(pureColorProgram, "inputColor"); + m_handleArray[PureColor].init(-1, -1, pureColorPosition, pureColorProgram, + pureColorProjMtx, pureColorValue, -1, -1); + + GLint tex2DAlpha = glGetUniformLocation(tex2DProgram, "alpha"); + GLint tex2DPosition = glGetAttribLocation(tex2DProgram, "vPosition"); + GLint tex2DProjMtx = glGetUniformLocation(tex2DProgram, "projectionMatrix"); + GLint tex2DTexSampler = glGetUniformLocation(tex2DProgram, "s_texture"); + m_handleArray[Tex2D].init(tex2DAlpha, -1, tex2DPosition, tex2DProgram, + tex2DProjMtx, -1, tex2DTexSampler, -1); + + GLint tex2DInvAlpha = glGetUniformLocation(tex2DInvProgram, "alpha"); + GLint tex2DInvContrast = glGetUniformLocation(tex2DInvProgram, "contrast"); + GLint tex2DInvPosition = glGetAttribLocation(tex2DInvProgram, "vPosition"); + GLint tex2DInvProjMtx = glGetUniformLocation(tex2DInvProgram, "projectionMatrix"); + GLint tex2DInvTexSampler = glGetUniformLocation(tex2DInvProgram, "s_texture"); + m_handleArray[Tex2DInv].init(tex2DInvAlpha, tex2DInvContrast, + tex2DInvPosition, tex2DInvProgram, + tex2DInvProjMtx, -1, + tex2DInvTexSampler, -1); + + GLint texOESAlpha = glGetUniformLocation(texOESProgram, "alpha"); + GLint texOESPosition = glGetAttribLocation(texOESProgram, "vPosition"); + GLint texOESProjMtx = glGetUniformLocation(texOESProgram, "projectionMatrix"); + GLint texOESTexSampler = glGetUniformLocation(texOESProgram, "s_texture"); + m_handleArray[TexOES].init(texOESAlpha, -1, texOESPosition, texOESProgram, + texOESProjMtx, -1, texOESTexSampler, -1); + + GLint texOESInvAlpha = glGetUniformLocation(texOESInvProgram, "alpha"); + GLint texOESInvContrast = glGetUniformLocation(texOESInvProgram, "contrast"); + GLint texOESInvPosition = glGetAttribLocation(texOESInvProgram, "vPosition"); + GLint texOESInvProjMtx = glGetUniformLocation(texOESInvProgram, "projectionMatrix"); + GLint texOESInvTexSampler = glGetUniformLocation(texOESInvProgram, "s_texture"); + m_handleArray[TexOESInv].init(texOESInvAlpha, texOESInvContrast, + texOESInvPosition, texOESInvProgram, + texOESInvProjMtx, -1, + texOESInvTexSampler, -1); + + GLint videoPosition = glGetAttribLocation(videoProgram, "vPosition"); + GLint videoProjMtx = glGetUniformLocation(videoProgram, "projectionMatrix"); + GLint videoTexSampler = glGetUniformLocation(videoProgram, "s_yuvTexture"); + GLint videoTexMtx = glGetUniformLocation(videoProgram, "textureMatrix"); + m_handleArray[Video].init(-1, -1, videoPosition, videoProgram, + videoProjMtx, -1, videoTexSampler, + videoTexMtx); const GLfloat coord[] = { 0.0f, 0.0f, // C @@ -260,7 +318,18 @@ void ShaderProgram::init() glBindBuffer(GL_ARRAY_BUFFER, m_textureBuffer[0]); glBufferData(GL_ARRAY_BUFFER, 2 * 4 * sizeof(GLfloat), coord, GL_STATIC_DRAW); - GLUtils::checkGlError("init"); + TransformationMatrix matrix; + // Map x,y from (0,1) to (-1, 1) + matrix.scale3d(2, 2, 1); + matrix.translate3d(-0.5, -0.5, 0); + GLUtils::toGLMatrix(m_transferProjMtx, matrix); + + if (GLUtils::checkGlError("init")) + m_needsInit = true; + else + m_needsInit = false; + + return; } void ShaderProgram::resetBlending() @@ -288,17 +357,58 @@ void ShaderProgram::setBlendingState(bool enableBlending) // Drawing ///////////////////////////////////////////////////////////////////////////////////////// -void ShaderProgram::setViewport(SkRect& viewport, float scale) +void ShaderProgram::setupDrawing(const IntRect& viewRect, const SkRect& visibleRect, + const IntRect& webViewRect, int titleBarHeight, + const IntRect& screenClip, float scale) { + m_webViewRect = webViewRect; + m_titleBarHeight = titleBarHeight; + + //// viewport //// TransformationMatrix ortho; - GLUtils::setOrthographicMatrix(ortho, viewport.fLeft, viewport.fTop, - viewport.fRight, viewport.fBottom, -1000, 1000); + GLUtils::setOrthographicMatrix(ortho, visibleRect.fLeft, visibleRect.fTop, + visibleRect.fRight, visibleRect.fBottom, -1000, 1000); m_projectionMatrix = ortho; - m_viewport = viewport; + m_viewport = visibleRect; m_currentScale = scale; + + + //// viewRect //// + m_viewRect = viewRect; + + // We do clipping using glScissor, which needs to take + // coordinates in screen space. The following matrix transform + // content coordinates in screen coordinates. + TransformationMatrix viewTranslate; + viewTranslate.translate(1.0, 1.0); + + TransformationMatrix viewScale; + viewScale.scale3d(m_viewRect.width() * 0.5f, m_viewRect.height() * 0.5f, 1); + + m_documentToScreenMatrix = viewScale * viewTranslate * m_projectionMatrix; + + viewTranslate.scale3d(1, -1, 1); + m_documentToInvScreenMatrix = viewScale * viewTranslate * m_projectionMatrix; + + IntRect rect(0, 0, m_webViewRect.width(), m_webViewRect.height()); + m_documentViewport = m_documentToScreenMatrix.inverse().mapRect(rect); + + + //// clipping //// + IntRect mclip = screenClip; + + // the clip from frameworks is in full screen coordinates + mclip.setY(screenClip.y() - m_webViewRect.y() - m_titleBarHeight); + FloatRect tclip = convertInvScreenCoordToScreenCoord(mclip); + m_screenClip.setLocation(IntPoint(tclip.x(), tclip.y())); + // use ceilf to handle view -> doc -> view coord rounding errors + m_screenClip.setSize(IntSize(ceilf(tclip.width()), ceilf(tclip.height()))); + + resetBlending(); } -void ShaderProgram::setProjectionMatrix(SkRect& geometry, GLint projectionMatrixHandle) +// Calculate the matrix given the geometry. +void ShaderProgram::setProjectionMatrix(const SkRect& geometry, GLfloat* mtxPtr) { TransformationMatrix translate; translate.translate3d(geometry.fLeft, geometry.fTop, 0.0); @@ -312,113 +422,75 @@ void ShaderProgram::setProjectionMatrix(SkRect& geometry, GLint projectionMatrix else total = m_projectionMatrix * translate * scale; - GLfloat projectionMatrix[16]; - GLUtils::toGLMatrix(projectionMatrix, total); - glUniformMatrix4fv(projectionMatrixHandle, 1, GL_FALSE, projectionMatrix); + GLUtils::toGLMatrix(mtxPtr, total); } -void ShaderProgram::drawQuadInternal(SkRect& geometry, - GLint textureId, - float opacity, - GLint program, - GLint projectionMatrixHandle, - GLint texSampler, - GLenum textureTarget, - GLint position, - GLint alpha, - GLint texFilter, - GLint contrast) +// Calculate the right color value sent into the shader considering the (0,1) +// clamp and alpha blending. +Color ShaderProgram::shaderColor(Color pureColor, float opacity) { - glUseProgram(program); - - if (!geometry.isEmpty()) - setProjectionMatrix(geometry, projectionMatrixHandle); - else { - TransformationMatrix matrix; - // Map x,y from (0,1) to (-1, 1) - matrix.scale3d(2, 2, 1); - matrix.translate3d(-0.5, -0.5, 0); - GLfloat projectionMatrix[16]; - GLUtils::toGLMatrix(projectionMatrix, matrix); - glUniformMatrix4fv(projectionMatrixHandle, 1, GL_FALSE, projectionMatrix); + float r = pureColor.red() / 255.0; + float g = pureColor.green() / 255.0; + float b = pureColor.blue() / 255.0; + float a = pureColor.alpha() / 255.0; + + if (TilesManager::instance()->invertedScreen()) { + float intensity = a - (0.2989 * r + 0.5866 * g + 0.1145 * b); + intensity = ((intensity - a / 2.0) * m_contrast) + a / 2.0; + intensity *= opacity; + return Color(intensity, intensity, intensity, a * opacity); } - - glActiveTexture(GL_TEXTURE0); - glUniform1i(texSampler, 0); - glBindTexture(textureTarget, textureId); - glTexParameteri(textureTarget, GL_TEXTURE_MIN_FILTER, texFilter); - glTexParameteri(textureTarget, GL_TEXTURE_MAG_FILTER, texFilter); - glTexParameteri(textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glBindBuffer(GL_ARRAY_BUFFER, m_textureBuffer[0]); - glEnableVertexAttribArray(position); - glVertexAttribPointer(position, 2, GL_FLOAT, GL_FALSE, 0, 0); - glUniform1f(alpha, opacity); - if (contrast != -1) - glUniform1f(contrast, m_contrast); - - setBlendingState(opacity < 1.0); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + return Color(r * opacity, g * opacity, b * opacity, a * opacity); } -void ShaderProgram::drawQuad(SkRect& geometry, int textureId, float opacity, - GLenum textureTarget, GLint texFilter) +// For shaders using texture, it is easy to get the type from the textureTarget. +ShaderType ShaderProgram::getTextureShaderType(GLenum textureTarget) { + ShaderType type = UndefinedShader; if (textureTarget == GL_TEXTURE_2D) { - if (!TilesManager::instance()->invertedScreen()) { - drawQuadInternal(geometry, textureId, opacity, m_program, - m_hProjectionMatrix, - m_hTexSampler, GL_TEXTURE_2D, - m_hPosition, m_hAlpha, texFilter); - } else { + if (!TilesManager::instance()->invertedScreen()) + type = Tex2D; + else { // With the new GPU texture upload path, we do not use an FBO // to blit the texture we receive from the TexturesGenerator thread. // To implement inverted rendering, we thus have to do the rendering // live, by using a different shader. - drawQuadInternal(geometry, textureId, opacity, m_programInverted, - m_hProjectionMatrixInverted, - m_hTexSamplerInverted, GL_TEXTURE_2D, - m_hPositionInverted, m_hAlphaInverted, texFilter, - m_hContrastInverted); + type = Tex2DInv; } - } else if (textureTarget == GL_TEXTURE_EXTERNAL_OES - && !TilesManager::instance()->invertedScreen()) { - drawQuadInternal(geometry, textureId, opacity, m_surfTexOESProgram, - m_hSTOESProjectionMatrix, - m_hSTOESTexSampler, GL_TEXTURE_EXTERNAL_OES, - m_hSTOESPosition, m_hSTOESAlpha, texFilter); - } else if (textureTarget == GL_TEXTURE_EXTERNAL_OES - && TilesManager::instance()->invertedScreen()) { - drawQuadInternal(geometry, textureId, opacity, m_surfTexOESProgramInverted, - m_hSTOESProjectionMatrixInverted, - m_hSTOESTexSamplerInverted, GL_TEXTURE_EXTERNAL_OES, - m_hSTOESPositionInverted, m_hSTOESAlphaInverted, - texFilter, m_hSTOESContrastInverted); + } else if (textureTarget == GL_TEXTURE_EXTERNAL_OES) { + if (!TilesManager::instance()->invertedScreen()) + type = TexOES; + else + type = TexOESInv; } - GLUtils::checkGlError("drawQuad"); + return type; } -void ShaderProgram::setViewRect(const IntRect& viewRect) +void ShaderProgram::drawQuad(SkRect& geometry, int textureId, float opacity, + Color pureColor, GLenum textureTarget, GLint texFilter) { - m_viewRect = viewRect; - - // We do clipping using glScissor, which needs to take - // coordinates in screen space. The following matrix transform - // content coordinates in screen coordinates. - TransformationMatrix translate; - translate.translate(1.0, 1.0); - - TransformationMatrix scale; - scale.scale3d(m_viewRect.width() * 0.5f, m_viewRect.height() * 0.5f, 1); - - m_documentToScreenMatrix = scale * translate * m_projectionMatrix; - - translate.scale3d(1, -1, 1); - m_documentToInvScreenMatrix = scale * translate * m_projectionMatrix; - - IntRect rect(0, 0, m_webViewRect.width(), m_webViewRect.height()); - m_documentViewport = m_documentToScreenMatrix.inverse().mapRect(rect); + ShaderType type = UndefinedShader; + if (!textureId) { + pureColor = shaderColor(pureColor, opacity); + if (pureColor.rgb() == Color::transparent && opacity < 1.0) + return; + type = PureColor; + } else + type = getTextureShaderType(textureTarget); + + if (type != UndefinedShader) { + // The matrix is either for the transfer queue or the tiles + GLfloat* finalMatrix = m_transferProjMtx; + GLfloat projectionMatrix[16]; + if (!geometry.isEmpty()) { + setProjectionMatrix(geometry, projectionMatrix); + finalMatrix = projectionMatrix; + } + setBlendingState(opacity < 1.0); + drawQuadInternal(type, finalMatrix, textureId, opacity, textureTarget, + texFilter, pureColor); + } + GLUtils::checkGlError("drawQuad"); } // This function transform a clip rect extracted from the current layer @@ -465,18 +537,6 @@ FloatRect ShaderProgram::convertScreenCoordToInvScreenCoord(const FloatRect& rec return rectInInvScreenCoord(documentRect); } -void ShaderProgram::setScreenClip(const IntRect& clip) -{ - m_screenClip = clip; - IntRect mclip = clip; - - // the clip from frameworks is in full screen coordinates - mclip.setY(clip.y() - m_webViewRect.y() - m_titleBarHeight); - FloatRect tclip = convertInvScreenCoordToScreenCoord(mclip); - IntRect screenClip(tclip.x(), tclip.y(), tclip.width(), tclip.height()); - m_screenClip = screenClip; -} - // clip is in screen coordinates void ShaderProgram::clip(const FloatRect& clip) { @@ -530,40 +590,45 @@ float ShaderProgram::zValue(const TransformationMatrix& drawMatrix, float w, flo return result.z(); } -void ShaderProgram::drawLayerQuadInternal(const GLfloat* projectionMatrix, - int textureId, float opacity, - GLenum textureTarget, GLint program, - GLint matrix, GLint texSample, - GLint position, GLint alpha, - GLint contrast) +void ShaderProgram::drawQuadInternal(ShaderType type, const GLfloat* matrix, + int textureId, float opacity, + GLenum textureTarget, GLenum filter, + const Color& pureColor) { - glUseProgram(program); - glUniformMatrix4fv(matrix, 1, GL_FALSE, projectionMatrix); - - glActiveTexture(GL_TEXTURE0); - glUniform1i(texSample, 0); - glBindTexture(textureTarget, textureId); - glTexParameteri(textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - + glUseProgram(m_handleArray[type].programHandle); + glUniformMatrix4fv(m_handleArray[type].projMtxHandle, 1, GL_FALSE, matrix); + + if (type != PureColor) { + glActiveTexture(GL_TEXTURE0); + glUniform1i(m_handleArray[type].texSamplerHandle, 0); + glBindTexture(textureTarget, textureId); + glTexParameteri(textureTarget, GL_TEXTURE_MIN_FILTER, filter); + glTexParameteri(textureTarget, GL_TEXTURE_MAG_FILTER, filter); + glUniform1f(m_handleArray[type].alphaHandle, opacity); + + GLint contrastHandle = m_handleArray[type].contrastHandle; + if (contrastHandle != -1) + glUniform1f(contrastHandle, m_contrast); + } else { + glUniform4f(m_handleArray[type].pureColorHandle, + pureColor.red() / 255.0, pureColor.green() / 255.0, + pureColor.blue() / 255.0, pureColor.alpha() / 255.0); + } + GLint positionHandle = m_handleArray[type].positionHandle; glBindBuffer(GL_ARRAY_BUFFER, m_textureBuffer[0]); - glEnableVertexAttribArray(position); - glVertexAttribPointer(position, 2, GL_FLOAT, GL_FALSE, 0, 0); - glUniform1f(alpha, opacity); - if (contrast != -1) - glUniform1f(contrast, m_contrast); -} + glEnableVertexAttribArray(positionHandle); + glVertexAttribPointer(positionHandle, 2, GL_FLOAT, GL_FALSE, 0, 0); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); +} void ShaderProgram::drawLayerQuad(const TransformationMatrix& drawMatrix, const SkRect& geometry, int textureId, float opacity, bool forceBlending, - GLenum textureTarget) + GLenum textureTarget, + Color pureColor) { - TransformationMatrix modifiedDrawMatrix = drawMatrix; // move the drawing depending on where the texture is on the layer modifiedDrawMatrix.translate(geometry.fLeft, geometry.fTop); @@ -578,37 +643,23 @@ void ShaderProgram::drawLayerQuad(const TransformationMatrix& drawMatrix, GLfloat projectionMatrix[16]; GLUtils::toGLMatrix(projectionMatrix, renderMatrix); - if (textureTarget == GL_TEXTURE_2D) { - if (!TilesManager::instance()->invertedScreen()) { - drawLayerQuadInternal(projectionMatrix, textureId, opacity, - GL_TEXTURE_2D, m_program, - m_hProjectionMatrix, m_hTexSampler, - m_hPosition, m_hAlpha); - } else { - drawLayerQuadInternal(projectionMatrix, textureId, opacity, - GL_TEXTURE_2D, m_programInverted, - m_hProjectionMatrixInverted, m_hTexSamplerInverted, - m_hPositionInverted, m_hAlphaInverted, - m_hContrastInverted); - } - } else if (textureTarget == GL_TEXTURE_EXTERNAL_OES - && !TilesManager::instance()->invertedScreen()) { - drawLayerQuadInternal(projectionMatrix, textureId, opacity, - GL_TEXTURE_EXTERNAL_OES, m_surfTexOESProgram, - m_hSTOESProjectionMatrix, m_hSTOESTexSampler, - m_hSTOESPosition, m_hSTOESAlpha); - } else if (textureTarget == GL_TEXTURE_EXTERNAL_OES - && TilesManager::instance()->invertedScreen()) { - drawLayerQuadInternal(projectionMatrix, textureId, opacity, - GL_TEXTURE_EXTERNAL_OES, m_surfTexOESProgramInverted, - m_hSTOESProjectionMatrixInverted, m_hSTOESTexSamplerInverted, - m_hSTOESPositionInverted, m_hSTOESAlphaInverted, - m_hSTOESContrastInverted); + bool enableBlending = forceBlending || opacity < 1.0; + + ShaderType type = UndefinedShader; + if (!textureId) { + pureColor = shaderColor(pureColor, opacity); + if (pureColor.rgb() == Color::transparent && enableBlending) + return; + type = PureColor; + } else + type = getTextureShaderType(textureTarget); + + if (type != UndefinedShader) { + setBlendingState(enableBlending); + drawQuadInternal(type, projectionMatrix, textureId, opacity, + textureTarget, GL_LINEAR, pureColor); } - setBlendingState(forceBlending || opacity < 1.0); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - GLUtils::checkGlError("drawLayerQuad"); } @@ -617,7 +668,7 @@ void ShaderProgram::drawVideoLayerQuad(const TransformationMatrix& drawMatrix, int textureId) { // switch to our custom yuv video rendering program - glUseProgram(m_videoProgram); + glUseProgram(m_handleArray[Video].programHandle); TransformationMatrix modifiedDrawMatrix = drawMatrix; modifiedDrawMatrix.translate(geometry.fLeft, geometry.fTop); @@ -626,16 +677,19 @@ void ShaderProgram::drawVideoLayerQuad(const TransformationMatrix& drawMatrix, GLfloat projectionMatrix[16]; GLUtils::toGLMatrix(projectionMatrix, renderMatrix); - glUniformMatrix4fv(m_hVideoProjectionMatrix, 1, GL_FALSE, projectionMatrix); - glUniformMatrix4fv(m_hVideoTextureMatrix, 1, GL_FALSE, textureMatrix); + glUniformMatrix4fv(m_handleArray[Video].projMtxHandle, 1, GL_FALSE, + projectionMatrix); + glUniformMatrix4fv(m_handleArray[Video].videoMtxHandle, 1, GL_FALSE, + textureMatrix); glActiveTexture(GL_TEXTURE0); - glUniform1i(m_hVideoTexSampler, 0); + glUniform1i(m_handleArray[Video].texSamplerHandle, 0); glBindTexture(GL_TEXTURE_EXTERNAL_OES, textureId); + GLint videoPosition = m_handleArray[Video].positionHandle; glBindBuffer(GL_ARRAY_BUFFER, m_textureBuffer[0]); - glEnableVertexAttribArray(m_hVideoPosition); - glVertexAttribPointer(m_hVideoPosition, 2, GL_FLOAT, GL_FALSE, 0, 0); + glEnableVertexAttribArray(videoPosition); + glVertexAttribPointer(videoPosition, 2, GL_FLOAT, GL_FALSE, 0, 0); setBlendingState(false); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); diff --git a/Source/WebCore/platform/graphics/android/ShaderProgram.h b/Source/WebCore/platform/graphics/android/ShaderProgram.h index 9ab7a46..e528e60 100644 --- a/Source/WebCore/platform/graphics/android/ShaderProgram.h +++ b/Source/WebCore/platform/graphics/android/ShaderProgram.h @@ -19,6 +19,7 @@ #if USE(ACCELERATED_COMPOSITING) +#include "Color.h" #include "FloatRect.h" #include "IntRect.h" #include "SkRect.h" @@ -29,14 +30,65 @@ namespace WebCore { +enum ShaderType { + UndefinedShader = -1, + PureColor, + Tex2D, + Tex2DInv, + TexOES, + TexOESInv, + Video, + // When growing this enum list, make sure to insert before the + // MaxShaderNumber and init the m_handleArray accordingly. + MaxShaderNumber +}; + +struct ShaderHandles { + ShaderHandles() + : alphaHandle(-1) + , contrastHandle(-1) + , positionHandle(-1) + , programHandle(-1) + , projMtxHandle(-1) + , pureColorHandle(-1) + , texSamplerHandle(-1) + , videoMtxHandle(-1) + { + } + + void init(GLint alphaHdl, GLint contrastHdl, GLint posHdl, GLint pgmHdl, + GLint projMtxHdl, GLint colorHdl, GLint texSamplerHdl, + GLint videoMtxHdl) + { + alphaHandle = alphaHdl; + contrastHandle = contrastHdl; + positionHandle = posHdl; + programHandle = pgmHdl; + projMtxHandle = projMtxHdl; + pureColorHandle = colorHdl; + texSamplerHandle = texSamplerHdl; + videoMtxHandle = videoMtxHdl; + } + + GLint alphaHandle; + GLint contrastHandle; + GLint positionHandle; + GLint programHandle; + GLint projMtxHandle; + GLint pureColorHandle; + GLint texSamplerHandle; + GLint videoMtxHandle; +}; + class ShaderProgram { public: ShaderProgram(); void init(); - int program() { return m_program; } // Drawing - void setViewport(SkRect& viewport, float scale); + void setupDrawing(const IntRect& viewRect, const SkRect& visibleRect, + const IntRect& webViewRect, int titleBarHeight, + const IntRect& screenClip, float scale); float zValue(const TransformationMatrix& drawMatrix, float w, float h); // For drawQuad and drawLayerQuad, they can handle 3 cases for now: @@ -44,22 +96,18 @@ public: // Normal texture in GL_TEXTURE_2D target. // 2) textureTarget == GL_TEXTURE_EXTERNAL_OES // Surface texture in GL_TEXTURE_EXTERNAL_OES target. - // 3) textureTarget == 0 (Will be deprecated soon) - // Surface texture in GL_TEXTURE_2D target. - // - // TODO: Shrink the support modes into 2 (1 and 2) after media framework - // support Surface texture in GL_TEXTURE_EXTERNAL_OES target on all - // platforms. - void drawQuad(SkRect& geometry, int textureId, float opacity, + // 3) textureId == 0 + // No texture needed, just a pureColor quad. + void drawQuad(SkRect& geometry, int textureId, float opacity, Color pureColor = Color(), GLenum textureTarget = GL_TEXTURE_2D, GLint texFilter = GL_LINEAR); void drawLayerQuad(const TransformationMatrix& drawMatrix, const SkRect& geometry, int textureId, float opacity, bool forceBlending = false, - GLenum textureTarget = GL_TEXTURE_2D); + GLenum textureTarget = GL_TEXTURE_2D, + Color pureColor = Color()); void drawVideoLayerQuad(const TransformationMatrix& drawMatrix, float* textureMatrix, SkRect& geometry, int textureId); - void setViewRect(const IntRect& viewRect); FloatRect rectInScreenCoord(const TransformationMatrix& drawMatrix, const IntSize& size); FloatRect rectInInvScreenCoord(const TransformationMatrix& drawMatrix, @@ -71,14 +119,10 @@ public: FloatRect convertInvScreenCoordToScreenCoord(const FloatRect& rect); FloatRect convertScreenCoordToInvScreenCoord(const FloatRect& rect); - void setTitleBarHeight(int height) { m_titleBarHeight = height; } - void setWebViewRect(const IntRect& rect) { m_webViewRect = rect; } - void setScreenClip(const IntRect& clip); void clip(const FloatRect& rect); IntRect clippedRectWithViewport(const IntRect& rect, int margin = 0); FloatRect documentViewport() { return m_documentViewport; } - void resetBlending(); float contrast() { return m_contrast; } void setContrast(float c) { float contrast = c; @@ -100,33 +144,22 @@ public: void calculateAnimationDelta(); int getAnimationDeltaX() { return m_animationDelta.x(); } int getAnimationDeltaY() { return m_animationDelta.y(); } + bool needsInit() { return m_needsInit; } private: GLuint loadShader(GLenum shaderType, const char* pSource); - GLuint createProgram(const char* vertexSource, const char* fragmentSource); - void setProjectionMatrix(SkRect& geometry, GLint projectionMatrixHandle); - + GLint createProgram(const char* vertexSource, const char* fragmentSource); + void setProjectionMatrix(const SkRect& geometry, GLfloat* mtxPtr); void setBlendingState(bool enableBlending); - - void drawQuadInternal(SkRect& geometry, GLint textureId, float opacity, - GLint program, GLint projectionMatrixHandle, - GLint texSampler, GLenum textureTarget, - GLint position, GLint alpha, - GLint texFilter, GLint contrast = -1); - - void drawLayerQuadInternal(const GLfloat* projectionMatrix, int textureId, - float opacity, GLenum textureTarget, GLint program, - GLint matrix, GLint texSample, - GLint position, GLint alpha, GLint contrast = -1); + void drawQuadInternal(ShaderType type, const GLfloat* matrix, int textureId, + float opacity, GLenum textureTarget, GLenum filter, + const Color& pureColor); + Color shaderColor(Color pureColor, float opacity); + ShaderType getTextureShaderType(GLenum textureTarget); + void resetBlending(); bool m_blendingEnabled; - int m_program; - int m_programInverted; - int m_videoProgram; - int m_surfTexOESProgram; - int m_surfTexOESProgramInverted; - TransformationMatrix m_projectionMatrix; GLuint m_textureBuffer[1]; @@ -141,37 +174,9 @@ private: FloatRect m_documentViewport; - // uniforms - GLint m_hProjectionMatrix; - GLint m_hAlpha; - GLint m_hTexSampler; - GLint m_hProjectionMatrixInverted; - GLint m_hAlphaInverted; - GLint m_hContrastInverted; - GLint m_hTexSamplerInverted; - GLint m_hVideoProjectionMatrix; - GLint m_hVideoTextureMatrix; - GLint m_hVideoTexSampler; - - GLint m_hSTOESProjectionMatrix; - GLint m_hSTOESAlpha; - GLint m_hSTOESTexSampler; - GLint m_hSTOESPosition; - - GLint m_hSTOESProjectionMatrixInverted; - GLint m_hSTOESAlphaInverted; - GLint m_hSTOESContrastInverted; - GLint m_hSTOESTexSamplerInverted; - GLint m_hSTOESPositionInverted; - float m_contrast; - // attribs - GLint m_hPosition; - GLint m_hPositionInverted; - GLint m_hVideoPosition; - - bool m_alphaLayer; + bool m_alphaLayer; TransformationMatrix m_webViewMatrix; float m_currentScale; @@ -184,8 +189,21 @@ private: // TODO: Given that m_webViewMatrix contains most of the tranformation // information, we should be able to get rid of some parameter we got from // Java side and simplify our code. - TransformationMatrix m_repositionMatrix; + TransformationMatrix m_repositionMatrix; IntPoint m_animationDelta; + + // Put all the uniform location (handle) info into an array, and group them + // by the shader's type, this can help to clean up the interface. + // TODO: use the type and data comparison to skip GL call if possible. + ShaderHandles m_handleArray[MaxShaderNumber]; + + // If there is any GL error happens such that the Shaders are not initialized + // successfully at the first time, then we need to init again when we draw. + bool m_needsInit; + + // For transfer queue blitting, we need a special matrix map from (0,1) to + // (-1,1) + GLfloat m_transferProjMtx[16]; }; } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/SharedTexture.cpp b/Source/WebCore/platform/graphics/android/SharedTexture.cpp deleted file mode 100644 index 74cd2c6..0000000 --- a/Source/WebCore/platform/graphics/android/SharedTexture.cpp +++ /dev/null @@ -1,248 +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 "SharedTexture.h" - -#include "GLUtils.h" -#include <android/native_window.h> -#include <gui/SurfaceTexture.h> -#include <gui/SurfaceTextureClient.h> - -#define LOG_NDEBUG 1 -#define LOG_TAG "SharedTexture.cpp" -#include <utils/Log.h> - -namespace WebCore { - -SharedTexture::SharedTexture(SharedTextureMode mode) -{ - m_sharedTextureMode = mode; - - m_sourceTexture = new TextureInfo(m_sharedTextureMode); - m_targetTexture = 0; - - if (m_sharedTextureMode == EglImageMode) { - m_targetTexture = new TextureInfo(m_sharedTextureMode); - m_eglImage = EGL_NO_IMAGE_KHR; - m_isNewImage = true; - m_syncObject = EGL_NO_SYNC_KHR; - - // Defer initialization of these values until we initialize the source - // texture. This ensures that this initialization happens in the appropriate - // thread. - m_display = 0; - m_supportsEGLImage = false; - m_supportsEGLFenceSyncKHR = false; - } else if (m_sharedTextureMode == SurfaceTextureMode) { -#if DEPRECATED_SURFACE_TEXTURE_MODE - glGenTextures(1, &m_sourceTexture->m_textureId); - - m_sourceTexture->m_surfaceTexture = - new android::SurfaceTexture(m_sourceTexture->m_textureId, false); - m_sourceTexture->m_ANW = - new android::SurfaceTextureClient(m_sourceTexture->m_surfaceTexture); -#endif - } -} - -// called by the consumer when it no longer wants to consume and after it has -// terminated all providers. If EGLImages are used, the deletion of the -// source texture and EGLImage is the responsibility of the caller. -SharedTexture::~SharedTexture() -{ - if (m_sharedTextureMode == EglImageMode) - deleteTargetTexture(); - else if (m_sharedTextureMode == SurfaceTextureMode) { -#if DEPRECATED_SURFACE_TEXTURE_MODE - m_sourceTexture->m_surfaceTexture.clear(); - m_sourceTexture->m_ANW.clear(); - GLUtils::deleteTexture(&m_sourceTexture->m_textureId); -#endif - } - delete m_sourceTexture; - delete m_targetTexture; -} - - -void SharedTexture::initSourceTexture() -{ - if (m_sharedTextureMode == SurfaceTextureMode) - return; - - m_display = eglGetCurrentDisplay(); - m_supportsEGLImage = GLUtils::isEGLImageSupported(); - m_supportsEGLFenceSyncKHR = GLUtils::isEGLFenceSyncSupported(); - - // TODO temporarily disable fence sync until the EGL framework fixes - // performance issues that result from consistently adding/removing fences. - m_supportsEGLFenceSyncKHR = false; - - LOGI("imageEGL: %d syncKHR: %d", m_supportsEGLImage, m_supportsEGLFenceSyncKHR); - - glGenTextures(1, &m_sourceTexture->m_textureId); - -} - -// For MediaTexture only -void SharedTexture::deleteSourceTexture() -{ - if (m_sharedTextureMode == SurfaceTextureMode) - return; - // We need to delete the source texture and EGLImage in the thread in which - // it was created. In theory we should be able to delete the EGLImage - // from either thread, but it currently throws an error if not deleted - // in the same EGLContext from which it was created. - if (m_supportsEGLImage) { - GLUtils::deleteTexture(&m_sourceTexture->m_textureId); - if (m_eglImage != EGL_NO_IMAGE_KHR) { - eglDestroyImageKHR(eglGetCurrentDisplay(), m_eglImage); - m_eglImage = EGL_NO_IMAGE_KHR; - m_isNewImage = true; - } - LOGI("Deleted Source Texture and EGLImage"); - } -} - -// For MediaTexture only -void SharedTexture::deleteTargetTexture() -{ - if (m_sharedTextureMode == SurfaceTextureMode) - return; - - if (m_supportsEGLImage) - GLUtils::deleteTexture(&m_targetTexture->m_textureId); - else - GLUtils::deleteTexture(&m_sourceTexture->m_textureId); -} - -TextureInfo* SharedTexture::lockSource() -{ - if (m_sharedTextureMode == SurfaceTextureMode) - return m_sourceTexture; - - m_lock.lock(); - - if (m_supportsEGLFenceSyncKHR && m_syncObject != EGL_NO_SYNC_KHR) { - - EGLint status = eglClientWaitSyncKHR(m_display, m_syncObject, 0, 1000000); - - if (status == EGL_TIMEOUT_EXPIRED_KHR) - LOGE("Sync timeout for shared texture (%d)", m_sourceTexture->m_textureId); - - eglDestroySyncKHR(m_display, m_syncObject); - m_syncObject = EGL_NO_SYNC_KHR; - } - return m_sourceTexture; -} - -void SharedTexture::releaseSource() -{ - if (m_sharedTextureMode == SurfaceTextureMode) - return; - - if (m_supportsEGLImage) { - // delete the existing image if needed - if (!m_sourceTexture->equalsAttributes(m_targetTexture)) { - if (m_eglImage != EGL_NO_IMAGE_KHR) { - eglDestroyImageKHR(m_display, m_eglImage); - m_eglImage = EGL_NO_IMAGE_KHR; - m_isNewImage = true; - } - m_targetTexture->copyAttributes(m_sourceTexture); - } - - // create an image from the texture, only when the texture is valid - if (m_eglImage == EGL_NO_IMAGE_KHR && m_sourceTexture->m_width - && m_sourceTexture->m_height) { - GLUtils::createEGLImageFromTexture(m_sourceTexture->m_textureId, &m_eglImage); - LOGV("Generating Image (%d) 0x%x", m_sourceTexture->m_textureId, m_eglImage); - - glFinish(); // ensures the texture is ready to be used by the consumer - } - - } else { - - m_targetTexture = m_sourceTexture; - - // in the case of shared contexts we must flush the texture edits to the - // GPU. This ensures the edits complete prior to allowing the texture to - // be bound on the producers context. - glFlush(); - } - - m_lock.unlock(); -} - -TextureInfo* SharedTexture::lockTarget() -{ - // Note that the source and targe are the same when using Surface Texture. - if (m_sharedTextureMode == SurfaceTextureMode) { -#if DEPRECATED_SURFACE_TEXTURE_MODE - m_sourceTexture->m_surfaceTexture->updateTexImage(); -#endif - return m_sourceTexture; - } - - m_lock.lock(); - - if ((!m_supportsEGLImage && m_targetTexture->m_textureId == GL_NO_TEXTURE) - || (m_supportsEGLImage && m_eglImage == EGL_NO_IMAGE_KHR)) { - m_lock.unlock(); - return 0; - } - - if (m_supportsEGLImage && (m_isNewImage || m_targetTexture->m_textureId == GL_NO_TEXTURE)) { - if (m_targetTexture->m_textureId == GL_NO_TEXTURE) - glGenTextures(1, &m_targetTexture->m_textureId); - - GLUtils::createTextureFromEGLImage(m_targetTexture->m_textureId, m_eglImage); - LOGV("Generating Consumer Texture from 0x%x", m_eglImage); - m_isNewImage = false; - } - return m_targetTexture; -} - -void SharedTexture::releaseTarget() -{ - if (m_sharedTextureMode == SurfaceTextureMode) - return; - - if (m_supportsEGLFenceSyncKHR) { - if (m_syncObject != EGL_NO_SYNC_KHR) - eglDestroySyncKHR(m_display, m_syncObject); - m_syncObject = eglCreateSyncKHR(m_display, EGL_SYNC_FENCE_KHR, 0); - } else { - // TODO the flush currently prevents the screen from getting partial - // updates but the only way to guarantee this is to call glFinish. Until - // we support an EGL sync we will leave flush enable in order to test - // with modest performance. - glFlush(); - } - - m_lock.unlock(); -} - -} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/SharedTexture.h b/Source/WebCore/platform/graphics/android/SharedTexture.h deleted file mode 100644 index 305a442..0000000 --- a/Source/WebCore/platform/graphics/android/SharedTexture.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2010, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef SharedTexture_h -#define SharedTexture_h - -#include "TextureInfo.h" -#include <EGL/egl.h> -#include <EGL/eglext.h> -#include <GLES2/gl2.h> -#include <GLES2/gl2ext.h> -#include <utils/threads.h> - -namespace WebCore { - -/** - * SharedTexture is a class that encapsulates all the necessary variables - * needed to share a single texture across threads. In the case that threads - * communicate using EGL's sharedContext mechanism or do not support the proper - * EGLImage extensions the targetTexture, eglImage, and isNewImage variables are - * not used. - */ -class SharedTexture { -public: - // consumer thread functions - SharedTexture(SharedTextureMode mode); - ~SharedTexture(); - - TextureInfo* lockSource(); - void releaseSource(); - - TextureInfo* lockTarget(); - void releaseTarget(); - - // these locks are only used for the methods below - void lock() { m_lock.lock(); } - void unlock() { m_lock.unlock(); } - - void initSourceTexture(); // producer thread only - void deleteSourceTexture(); // producer thread only - void deleteTargetTexture(); // consumer thread only - GLuint getSourceTextureId() { return m_sourceTexture->m_textureId; } - GLuint getTargetTextureId() { return m_targetTexture->m_textureId; } - EGLImageKHR getEGLImage() { return m_eglImage; } - -private: - /** - * The mutex is used to ensure that the contents of the struct are current across - * threads and that only one thread is manipulating the texture at a given time. - */ - android::Mutex m_lock; - /** - * The texture and its associated metadata that is used by the producer. The - * texture is created in the producer's thread and can only be read by the - * consumer when the consumer shares the same context as the producer. The - * metadata is used to track changes to the texture that would orphan the - * target texture and require a new EGLImage to be constructed. - */ - TextureInfo* m_sourceTexture; - /** - * The target texture stores the id and metadata of the texture that is to be - * used by the consumer. In the case where EGLImages are supported this hold - * the current eglImage target. - */ - TextureInfo* m_targetTexture; - /** - * The EGLImage is used to share the texture between EGLContexts on two - * different threads. This serves as an alternative to sharing the contexts - * but is only used if GL and EGL support the required extensions. - */ - EGLImageKHR m_eglImage; - /** - * This flag is used to determine if the eglImage has been updated. This - * signals the consumer thread to rebind the targetTexture to the new image. - */ - bool m_isNewImage; - /** - * The sync allows the consumer to release the lock prior to the commands - * executing on the GPU. Prior to releasing the lock the consumer creates - * a sync object and stores it here. After locking the texture the client - * must check that the sync has completed prior to manipulating the texture. - * This value is only used if the proper EGL extensions are supported. - */ - EGLSyncKHR m_syncObject; - - EGLDisplay m_display; - - bool m_supportsEGLImage; - bool m_supportsEGLFenceSyncKHR; - - SharedTextureMode m_sharedTextureMode; -}; - -} // namespace WebCore - -#endif // SharedTexture_h diff --git a/Source/WebCore/platform/graphics/android/TextureInfo.cpp b/Source/WebCore/platform/graphics/android/TextureInfo.cpp index 5356dcb..3c4dde2 100644 --- a/Source/WebCore/platform/graphics/android/TextureInfo.cpp +++ b/Source/WebCore/platform/graphics/android/TextureInfo.cpp @@ -35,13 +35,12 @@ namespace WebCore { -TextureInfo::TextureInfo(SharedTextureMode mode) +TextureInfo::TextureInfo() { m_textureId = GL_NO_TEXTURE; m_width = 0; m_height = 0; m_internalFormat = 0; - m_sharedTextureMode = mode; m_eglSurface = EGL_NO_SURFACE; m_pictureCount = 0; } diff --git a/Source/WebCore/platform/graphics/android/TextureInfo.h b/Source/WebCore/platform/graphics/android/TextureInfo.h index 1c48937..8549365 100644 --- a/Source/WebCore/platform/graphics/android/TextureInfo.h +++ b/Source/WebCore/platform/graphics/android/TextureInfo.h @@ -34,8 +34,6 @@ #include "BaseTile.h" using android::sp; -#define DEPRECATED_SURFACE_TEXTURE_MODE 0 - namespace android { class SurfaceTexture; } @@ -47,20 +45,14 @@ static const GLuint GL_NO_TEXTURE = 0; * TextureInfo is a class that stores both the texture and metadata about the * texture. */ -enum SharedTextureMode { - EglImageMode, - SurfaceTextureMode -}; class TextureInfo { public: - - TextureInfo(SharedTextureMode mode); + TextureInfo(); bool equalsAttributes(const TextureInfo* otherTexture); void copyAttributes(const TextureInfo* sourceTexture); - SharedTextureMode getSharedTextureMode() { return m_sharedTextureMode; } bool operator==(const TextureInfo& otherTexture); GLuint m_textureId; @@ -68,18 +60,12 @@ public: int32_t m_height; GLenum m_internalFormat; - // Surface Texture specific data -#if DEPRECATED_SURFACE_TEXTURE_MODE - sp<android::SurfaceTexture> m_surfaceTexture; -#endif // TODO: Delete this after the Ganesh code path get fixed. sp<ANativeWindow> m_ANW; // The EGLSurface wraps the m_ANW to enable direct OpenGL rendering (e.g. Ganesh) EGLSurface m_eglSurface; int m_pictureCount; -private: - SharedTextureMode m_sharedTextureMode; }; } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/TiledPage.cpp b/Source/WebCore/platform/graphics/android/TiledPage.cpp index 31a0593..cd23a7f 100644 --- a/Source/WebCore/platform/graphics/android/TiledPage.cpp +++ b/Source/WebCore/platform/graphics/android/TiledPage.cpp @@ -93,9 +93,13 @@ void TiledPage::updateBaseTileSize() TiledPage::~TiledPage() { + TilesManager* tilesManager = TilesManager::instance(); // 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::instance()->removeOperationsForPage(this); + tilesManager->removeOperationsForPage(this); + // 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"); @@ -242,11 +246,6 @@ void TiledPage::prepare(bool goingDown, bool goingLeft, const SkIRect& tileBound int nbTilesWidth = tileBounds.width(); int nbTilesHeight = tileBounds.height(); - // Expand number of tiles to allow tiles outside of viewport to be prepared for - // smoother scrolling. - int nTilesToPrepare = nbTilesWidth * nbTilesHeight; - int nMaxTilesPerPage = m_baseTileSize / 2; - if (bounds == ExpandedBounds) { // prepare tiles outside of the visible bounds int expandX = m_glWebViewState->expandedTileBoundsX(); @@ -276,8 +275,8 @@ void TiledPage::prepare(bool goingDown, bool goingLeft, const SkIRect& tileBound nbTilesHeight += firstTileY; firstTileY = 0; } - nbTilesWidth = std::min(nbTilesWidth, maxX - firstTileX); - nbTilesHeight = std::min(nbTilesHeight, maxY - firstTileY); + nbTilesWidth = std::min(nbTilesWidth, maxX - firstTileX + 1); + nbTilesHeight = std::min(nbTilesHeight, maxY - firstTileY + 1); // check against corrupted scale values giving bad height/width (use float to avoid overflow) float numTiles = static_cast<float>(nbTilesHeight) * static_cast<float>(nbTilesWidth); @@ -349,7 +348,7 @@ bool TiledPage::swapBuffersIfReady(const SkIRect& tileBounds, float scale) swaps++; } - XLOG("%p greedy swapped %d textures, returning true", this, swaps); + XLOG("%p greedy swapped %d textures, returning %d", this, swaps, fullSwap); return fullSwap; } diff --git a/Source/WebCore/platform/graphics/android/TiledTexture.cpp b/Source/WebCore/platform/graphics/android/TiledTexture.cpp index d538416..1e8b946 100644 --- a/Source/WebCore/platform/graphics/android/TiledTexture.cpp +++ b/Source/WebCore/platform/graphics/android/TiledTexture.cpp @@ -99,13 +99,13 @@ void TiledTexture::swapTiles() XLOG("TT %p swapping, swaps = %d", this, swaps); } -IntRect TiledTexture::computeTilesArea(IntRect& visibleArea, float scale) +IntRect TiledTexture::computeTilesArea(IntRect& contentArea, float scale) { IntRect computedArea; - IntRect area(visibleArea.x() * scale, - visibleArea.y() * scale, - ceilf(visibleArea.width() * scale), - ceilf(visibleArea.height() * scale)); + IntRect area(contentArea.x() * scale, + contentArea.y() * scale, + ceilf(contentArea.width() * scale), + ceilf(contentArea.height() * scale)); XLOG("TT %p prepare, scale %f, area %d x %d", this, scale, area.width(), area.height()); @@ -128,21 +128,21 @@ IntRect TiledTexture::computeTilesArea(IntRect& visibleArea, float scale) } void TiledTexture::prepare(GLWebViewState* state, float scale, bool repaint, - bool startFastSwap, IntRect& visibleArea) + bool startFastSwap, IntRect& prepareArea) { if (!m_surface) return; // first, how many tiles do we need - m_area = computeTilesArea(visibleArea, scale); + m_area = computeTilesArea(prepareArea, scale); if (m_area.isEmpty()) return; - XLOG("for TiledTexture %p, we prepare with scale %.2f, have a visible area of " + XLOG("for TiledTexture %p, we prepare with scale %.2f, have a prepare area of " " %d, %d - %d x %d, corresponding to %d, %d x - %d x %d tiles", this, scale, - visibleArea.x(), visibleArea.y(), - visibleArea.width(), visibleArea.height(), + prepareArea.x(), prepareArea.y(), + prepareArea.width(), prepareArea.height(), m_area.x(), m_area.y(), m_area.width(), m_area.height()); @@ -239,7 +239,7 @@ int TiledTexture::nbTextures(IntRect& area, float scale) return numberTextures; } -bool TiledTexture::draw() +bool TiledTexture::draw(IntRect& visibleArea) { if (!m_surface) return true; @@ -250,6 +250,7 @@ bool TiledTexture::draw() TilesManager::instance()->getTilesTracker()->trackLayer(); #endif + m_area = computeTilesArea(visibleArea, m_scale); if (m_area.width() == 0 || m_area.height() == 0) return false; @@ -358,12 +359,17 @@ DualTiledTexture::~DualTiledTexture() } void DualTiledTexture::prepare(GLWebViewState* state, float scale, bool repaint, - bool startFastSwap, IntRect& visibleArea) + bool startFastSwap, IntRect& prepareArea) { // If we are zooming, we will use the previously used area, to prevent the // frontTexture to try to allocate more tiles than what it has already if (!m_zooming) - m_preZoomVisibleArea = visibleArea; + m_preZoomPrepareArea = prepareArea; + + if (m_scale == -1) { + m_scale = scale; + m_futureScale = scale; + } if (m_futureScale != scale) { m_futureScale = scale; @@ -375,11 +381,11 @@ void DualTiledTexture::prepare(GLWebViewState* state, float scale, bool repaint, this, scale, m_scale, m_futureScale, m_zooming); if (m_scale > 0) - m_frontTexture->prepare(state, m_scale, repaint, startFastSwap, m_preZoomVisibleArea); + m_frontTexture->prepare(state, m_scale, repaint, startFastSwap, m_preZoomPrepareArea); // If we had a scheduled update if (m_zooming && m_zoomUpdateTime < WTF::currentTime()) { - m_backTexture->prepare(state, m_futureScale, repaint, startFastSwap, visibleArea); + m_backTexture->prepare(state, m_futureScale, repaint, startFastSwap, prepareArea); if (m_backTexture->ready()) { m_backTexture->swapTiles(); swap(); @@ -396,9 +402,9 @@ void DualTiledTexture::swap() m_backTexture->discardTextures(); } -bool DualTiledTexture::draw() +bool DualTiledTexture::draw(IntRect& visibleArea) { - bool needsRepaint = m_frontTexture->draw(); + bool needsRepaint = m_frontTexture->draw(visibleArea); needsRepaint |= m_zooming; needsRepaint |= (m_scale <= 0); return needsRepaint; diff --git a/Source/WebCore/platform/graphics/android/TiledTexture.h b/Source/WebCore/platform/graphics/android/TiledTexture.h index 444ab14..971a99f 100644 --- a/Source/WebCore/platform/graphics/android/TiledTexture.h +++ b/Source/WebCore/platform/graphics/android/TiledTexture.h @@ -57,12 +57,12 @@ public: virtual ~TiledTexture(); - IntRect computeTilesArea(IntRect& visibleArea, float scale); + IntRect computeTilesArea(IntRect& contentArea, float scale); void prepare(GLWebViewState* state, float scale, bool repaint, - bool startFastSwap, IntRect& visibleArea); + bool startFastSwap, IntRect& prepareArea); void swapTiles(); - bool draw(); + bool draw(IntRect& visibleArea); void prepareTile(bool repaint, int x, int y); void update(const SkRegion& dirtyArea, SkPicture* picture); @@ -114,7 +114,7 @@ public: bool startFastSwap, IntRect& area); void swapTiles(); void swap(); - bool draw(); + bool draw(IntRect& visibleArea); void update(const SkRegion& dirtyArea, SkPicture* picture); bool owns(BaseTileTexture* texture); bool isReady() @@ -142,7 +142,7 @@ private: float m_futureScale; double m_zoomUpdateTime; bool m_zooming; - IntRect m_preZoomVisibleArea; + IntRect m_preZoomPrepareArea; }; } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/TilesManager.cpp b/Source/WebCore/platform/graphics/android/TilesManager.cpp index 62324d7..6640230 100644 --- a/Source/WebCore/platform/graphics/android/TilesManager.cpp +++ b/Source/WebCore/platform/graphics/android/TilesManager.cpp @@ -96,6 +96,7 @@ int TilesManager::getMaxTextureAllocation() TilesManager::TilesManager() : m_layerTexturesRemain(true) + , m_highEndGfx(false) , m_maxTextureCount(0) , m_maxLayerTextureCount(0) , m_generatorReady(false) @@ -103,9 +104,13 @@ TilesManager::TilesManager() , m_invertedScreen(false) , m_invertedScreenSwitch(false) , m_useMinimalMemory(true) + , m_useDoubleBuffering(true) + , m_treeUpdates(0) + , m_queue(0) , m_drawGLCount(1) , m_lastTimeLayersUsed(0) , m_hasLayerTextures(false) + , m_EGLContextChanged(true) { XLOG("TilesManager ctor"); m_textures.reserveCapacity(MAX_TEXTURE_ALLOCATION); @@ -155,7 +160,7 @@ void TilesManager::allocateTiles() m_tilesTextures.size() * LAYER_TILE_WIDTH * LAYER_TILE_HEIGHT * 4 / 1024 / 1024); } -void TilesManager::deallocateTextures(bool allTextures) +void TilesManager::discardTextures(bool allTextures, bool glTextures) { const unsigned int max = m_textures.size(); @@ -169,24 +174,52 @@ void TilesManager::deallocateTextures(bool allTextures) sparedDrawCount = std::max(sparedDrawCount, owner->drawCount()); } } - deallocateTexturesVector(sparedDrawCount, m_textures); - deallocateTexturesVector(sparedDrawCount, m_tilesTextures); + discardTexturesVector(sparedDrawCount, m_textures, glTextures); + discardTexturesVector(sparedDrawCount, m_tilesTextures, glTextures); } -void TilesManager::deallocateTexturesVector(unsigned long long sparedDrawCount, - WTF::Vector<BaseTileTexture*>& textures) +void TilesManager::discardTexturesVector(unsigned long long sparedDrawCount, + WTF::Vector<BaseTileTexture*>& textures, + bool deallocateGLTextures) { const unsigned int max = textures.size(); int dealloc = 0; + WTF::Vector<int> discardedIndex; for (unsigned int i = 0; i < max; i++) { TextureOwner* owner = textures[i]->owner(); if (!owner || owner->drawCount() < sparedDrawCount) { - textures[i]->discardGLTexture(); + if (deallocateGLTextures) { + // deallocate textures' gl memory + textures[i]->discardGLTexture(); + discardedIndex.append(i); + } else if (owner) { + // simply detach textures from owner + static_cast<BaseTile*>(owner)->discardTextures(); + } dealloc++; } } - XLOG("Deallocated %d gl textures (out of %d base tiles and %d layer tiles)", - dealloc, max, maxLayer); + + bool base = textures == m_textures; + // Clean up the vector of BaseTileTextures and reset the max texture count. + if (discardedIndex.size()) { + android::Mutex::Autolock lock(m_texturesLock); + for (int i = discardedIndex.size() - 1; i >= 0; i--) + textures.remove(discardedIndex[i]); + + int remainedTextureNumber = textures.size(); + int* countPtr = base ? &m_maxTextureCount : &m_maxLayerTextureCount; + if (remainedTextureNumber < *countPtr) { + XLOG("reset maxTextureCount for %s tiles from %d to %d", + base ? "base" : "layer", *countPtr, remainedTextureNumber); + *countPtr = remainedTextureNumber; + } + + } + + XLOG("Discarded %d %s textures (out of %d %s tiles)", + dealloc, (deallocateGLTextures ? "gl" : ""), + max, base ? "base" : "layer"); } void TilesManager::gatherTexturesNumbers(int* nbTextures, int* nbAllocatedTextures, @@ -221,9 +254,9 @@ void TilesManager::printTextures() x = o->x(); y = o->y(); } - XLOG("[%d] texture %x busy: %d owner: %x (%d, %d) page: %x scale: %.2f", + XLOG("[%d] texture %x owner: %x (%d, %d) page: %x scale: %.2f", i, texture, - texture->busy(), o, x, y, o ? o->page() : 0, o ? o->scale() : 0); + o, x, y, o ? o->page() : 0, o ? o->scale() : 0); } XLOG("------"); #endif // DEBUG @@ -285,12 +318,6 @@ BaseTileTexture* TilesManager::getAvailableTexture(BaseTile* owner) for (unsigned int i = 0; i < max; i++) { BaseTileTexture* texture = (*availableTexturePool)[i]; BaseTile* currentOwner = static_cast<BaseTile*>(texture->owner()); - - if (texture->busy()) { - // don't bother, since the acquire() will likely fail - continue; - } - if (!currentOwner) { // unused texture! take it! farthestTexture = texture; @@ -352,6 +379,16 @@ BaseTileTexture* TilesManager::getAvailableTexture(BaseTile* owner) return 0; } +void TilesManager::setHighEndGfx(bool highEnd) +{ + m_highEndGfx = highEnd; +} + +bool TilesManager::highEndGfx() +{ + return m_highEndGfx; +} + int TilesManager::maxTextureCount() { android::Mutex::Autolock lock(m_texturesLock); @@ -390,7 +427,8 @@ void TilesManager::setMaxLayerTextureCount(int max) double secondsSinceLayersUsed = WTF::currentTime() - m_lastTimeLayersUsed; if (secondsSinceLayersUsed > LAYER_TEXTURES_DESTROY_TIMEOUT) { unsigned long long sparedDrawCount = ~0; // by default, spare no textures - deallocateTexturesVector(sparedDrawCount, m_tilesTextures); + bool deleteGLTextures = true; + discardTexturesVector(sparedDrawCount, m_tilesTextures, deleteGLTextures); m_hasLayerTextures = false; } return; @@ -411,6 +449,14 @@ void TilesManager::setMaxLayerTextureCount(int max) m_hasLayerTextures = true; } +TransferQueue* TilesManager::transferQueue() +{ + // To minimize the memory usage, transfer queue can be set to minimal size + // if required. + if (!m_queue) + m_queue = new TransferQueue(m_useMinimalMemory); + return m_queue; +} float TilesManager::tileWidth() { @@ -476,13 +522,6 @@ void TilesManager::paintedSurfacesCleanup(GLWebViewState* state) } } -void TilesManager::unregisterGLWebViewState(GLWebViewState* state) -{ - // Discard the whole queue b/c we lost GL context already. - // Note the real updateTexImage will still wait for the next draw. - transferQueue()->discardQueue(); -} - TilesManager* TilesManager::instance() { if (!gInstance) { diff --git a/Source/WebCore/platform/graphics/android/TilesManager.h b/Source/WebCore/platform/graphics/android/TilesManager.h index 9782fbb..749ba98 100644 --- a/Source/WebCore/platform/graphics/android/TilesManager.h +++ b/Source/WebCore/platform/graphics/android/TilesManager.h @@ -82,7 +82,7 @@ public: void addPaintedSurface(PaintedSurface* surface); ShaderProgram* shader() { return &m_shader; } - TransferQueue* transferQueue() { return &m_queue; } + TransferQueue* transferQueue(); VideoLayerManager* videoLayerManager() { return &m_videoLayerManager; } void gatherLayerTextures(); @@ -106,6 +106,13 @@ public: void resetTextureUsage(TiledPage* page); + // m_highEndGfx is written/read only on UI thread, no need for a lock. + void setHighEndGfx(bool highEnd); + bool highEndGfx(); + + bool contextChanged() { return m_EGLContextChanged; } + void setContextChanged(bool changed) { m_EGLContextChanged = changed; } + int maxTextureCount(); int maxLayerTextureCount(); void setMaxTextureCount(int max); @@ -115,12 +122,11 @@ public: static float layerTileWidth(); static float layerTileHeight(); void paintedSurfacesCleanup(GLWebViewState* state = 0); - void unregisterGLWebViewState(GLWebViewState* state); void allocateTiles(); - // Called when webview is hidden to discard graphics memory - void deallocateTextures(bool allTextures); + // remove all tiles from textures (and optionally deallocate gl memory) + void discardTextures(bool allTextures, bool glTextures); bool getShowVisualIndicator() { @@ -132,11 +138,6 @@ public: m_showVisualIndicator = showVisualIndicator; } - SharedTextureMode getSharedTextureMode() - { - return SurfaceTextureMode; - } - TilesProfiler* getProfiler() { return &m_profiler; @@ -184,6 +185,16 @@ public: return m_useMinimalMemory; } + void setUseDoubleBuffering(bool useDoubleBuffering) + { + m_useDoubleBuffering = useDoubleBuffering; + } + bool useDoubleBuffering() { return m_useDoubleBuffering; } + + void incTreeUpdates() { m_treeUpdates++; } + unsigned int getTreeUpdates() { return m_treeUpdates; } + void clearTreeUpdates() { m_treeUpdates = 0; } + void incDrawGLCount() { m_drawGLCount++; @@ -209,8 +220,9 @@ private: m_generatorReadyCond.wait(m_generatorLock); } - void deallocateTexturesVector(unsigned long long sparedDrawCount, - WTF::Vector<BaseTileTexture*>& textures); + void discardTexturesVector(unsigned long long sparedDrawCount, + WTF::Vector<BaseTileTexture*>& textures, + bool deallocateGLTextures); Vector<BaseTileTexture*> m_textures; Vector<BaseTileTexture*> m_availableTextures; @@ -221,6 +233,7 @@ private: Vector<PaintedSurface*> m_paintedSurfaces; + bool m_highEndGfx; int m_maxTextureCount; int m_maxLayerTextureCount; @@ -232,6 +245,9 @@ private: bool m_useMinimalMemory; + bool m_useDoubleBuffering; + unsigned int m_treeUpdates; + sp<TexturesGenerator> m_pixmapsGenerationThread; android::Mutex m_texturesLock; @@ -241,7 +257,7 @@ private: static TilesManager* gInstance; ShaderProgram m_shader; - TransferQueue m_queue; + TransferQueue* m_queue; VideoLayerManager m_videoLayerManager; @@ -250,6 +266,8 @@ private: unsigned long long m_drawGLCount; double m_lastTimeLayersUsed; bool m_hasLayerTextures; + + bool m_EGLContextChanged; }; } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/TransferQueue.cpp b/Source/WebCore/platform/graphics/android/TransferQueue.cpp index b20ec7a..35a36dd 100644 --- a/Source/WebCore/platform/graphics/android/TransferQueue.cpp +++ b/Source/WebCore/platform/graphics/android/TransferQueue.cpp @@ -50,7 +50,10 @@ #endif // DEBUG -#define ST_BUFFER_NUMBER 6 +// For simple webView usage, MINIMAL_SIZE is recommended for memory saving. +// In browser case, EFFICIENT_SIZE is preferred. +#define MINIMAL_SIZE 1 +#define EFFICIENT_SIZE 6 // Set this to 1 if we would like to take the new GpuUpload approach which // relied on the glCopyTexSubImage2D instead of a glDraw call @@ -58,7 +61,7 @@ namespace WebCore { -TransferQueue::TransferQueue() +TransferQueue::TransferQueue(bool useMinimalMem) : m_eglSurface(EGL_NO_SURFACE) , m_transferQueueIndex(0) , m_fboID(0) @@ -69,35 +72,55 @@ TransferQueue::TransferQueue() , m_currentUploadType(DEFAULT_UPLOAD_TYPE) { memset(&m_GLStateBeforeBlit, 0, sizeof(m_GLStateBeforeBlit)); - - m_emptyItemCount = ST_BUFFER_NUMBER; - - m_transferQueue = new TileTransferData[ST_BUFFER_NUMBER]; + m_transferQueueSize = useMinimalMem ? MINIMAL_SIZE : EFFICIENT_SIZE; + m_emptyItemCount = m_transferQueueSize; + m_transferQueue = new TileTransferData[m_transferQueueSize]; } TransferQueue::~TransferQueue() { - glDeleteFramebuffers(1, &m_fboID); - m_fboID = 0; - glDeleteTextures(1, &m_sharedSurfaceTextureId); - m_sharedSurfaceTextureId = 0; - + android::Mutex::Autolock lock(m_transferQueueItemLocks); + cleanupGLResources(); delete[] m_transferQueue; } -void TransferQueue::initSharedSurfaceTextures(int width, int height) +// This should be called within the m_transferQueueItemLocks. +// Now only called by emptyQueue() and destructor. +void TransferQueue::cleanupGLResources() +{ + if (m_sharedSurfaceTexture.get()) { + m_sharedSurfaceTexture->abandon(); + m_sharedSurfaceTexture.clear(); + } + if (m_fboID) { + glDeleteFramebuffers(1, &m_fboID); + m_fboID = 0; + } + if (m_sharedSurfaceTextureId) { + glDeleteTextures(1, &m_sharedSurfaceTextureId); + m_sharedSurfaceTextureId = 0; + } +} + +void TransferQueue::initGLResources(int width, int height) { + android::Mutex::Autolock lock(m_transferQueueItemLocks); if (!m_sharedSurfaceTextureId) { glGenTextures(1, &m_sharedSurfaceTextureId); m_sharedSurfaceTexture = #if GPU_UPLOAD_WITHOUT_DRAW - new android::SurfaceTexture(m_sharedSurfaceTextureId, true, GL_TEXTURE_2D); + new android::SurfaceTexture(m_sharedSurfaceTextureId, true, + GL_TEXTURE_2D, false); #else new android::SurfaceTexture(m_sharedSurfaceTextureId); #endif m_ANW = new android::SurfaceTextureClient(m_sharedSurfaceTexture); m_sharedSurfaceTexture->setSynchronousMode(true); - m_sharedSurfaceTexture->setBufferCount(ST_BUFFER_NUMBER+1); + + int extraBuffersNeeded = 0; + m_ANW->query(m_ANW.get(), NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, + &extraBuffersNeeded); + m_sharedSurfaceTexture->setBufferCount(m_transferQueueSize + extraBuffersNeeded); int result = native_window_set_buffers_geometry(m_ANW.get(), width, height, HAL_PIXEL_FORMAT_RGBA_8888); @@ -114,9 +137,9 @@ void TransferQueue::initSharedSurfaceTextures(int width, int height) // When bliting, if the item from the transfer queue is mismatching b/t the // BaseTile and the content, then the item is considered as obsolete, and // the content is discarded. -bool TransferQueue::checkObsolete(int index) +bool TransferQueue::checkObsolete(const TileTransferData* data) { - BaseTile* baseTilePtr = m_transferQueue[index].savedBaseTilePtr; + BaseTile* baseTilePtr = data->savedBaseTilePtr; if (!baseTilePtr) { XLOG("Invalid savedBaseTilePtr , such that the tile is obsolete"); return true; @@ -128,7 +151,7 @@ bool TransferQueue::checkObsolete(int index) return true; } - const TextureTileInfo* tileInfo = &m_transferQueue[index].tileInfo; + const TextureTileInfo* tileInfo = &(data->tileInfo); if (tileInfo->m_x != baseTilePtr->x() || tileInfo->m_y != baseTilePtr->y() @@ -142,20 +165,46 @@ bool TransferQueue::checkObsolete(int index) } void TransferQueue::blitTileFromQueue(GLuint fboID, BaseTileTexture* destTex, + BaseTileTexture* frontTex, GLuint srcTexId, GLenum srcTexTarget, int index) { #if GPU_UPLOAD_WITHOUT_DRAW glBindFramebuffer(GL_FRAMEBUFFER, fboID); + glBindTexture(GL_TEXTURE_2D, destTex->m_ownTextureId); + + int textureWidth = destTex->getSize().width(); + int textureHeight = destTex->getSize().height(); + + IntRect inval = m_transferQueue[index].tileInfo.m_inval; + bool partialInval = !inval.isEmpty(); + + if (partialInval && frontTex) { + // recopy the previous texture to the new one, as + // the partial update will not cover the entire texture + glFramebufferTexture2D(GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, + frontTex->m_ownTextureId, + 0); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, + textureWidth, textureHeight); + } + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, srcTexId, 0); - glBindTexture(GL_TEXTURE_2D, destTex->m_ownTextureId); - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, - destTex->getSize().width(), - destTex->getSize().height()); + + if (!partialInval) { + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, + textureWidth, textureHeight); + } else { + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, inval.x(), inval.y(), 0, 0, + inval.width(), inval.height()); + } + #else // Then set up the FBO and copy the SurfTex content in. glBindFramebuffer(GL_FRAMEBUFFER, fboID); @@ -256,15 +305,33 @@ void TransferQueue::setHasGLContext(bool hasContext) m_hasGLContext = hasContext; } -// Only called when WebView is destroyed or switching the uploadType. -void TransferQueue::discardQueue() +void TransferQueue::setPendingDiscardWithLock() { android::Mutex::Autolock lock(m_transferQueueItemLocks); + setPendingDiscard(); +} - for (int i = 0 ; i < ST_BUFFER_NUMBER; i++) +void TransferQueue::emptyQueue() +{ + android::Mutex::Autolock lock(m_transferQueueItemLocks); + setPendingDiscard(); + cleanupPendingDiscard(); + cleanupGLResources(); +} + +// Set all the content in the queue to pendingDiscard, after this, there will +// be nothing added to the queue, and this can be called in any thread. +// However, in order to discard the content in the Surface Texture using +// updateTexImage, cleanupPendingDiscard need to be called on the UI thread. +// Must be called within a m_transferQueueItemLocks. +void TransferQueue::setPendingDiscard() +{ + for (int i = 0 ; i < m_transferQueueSize; i++) if (m_transferQueue[i].status == pendingBlit) m_transferQueue[i].status = pendingDiscard; + m_pureColorTileQueue.clear(); + bool GLContextExisted = getHasGLContext(); // Unblock the Tex Gen thread first before Tile Page deletion. // Otherwise, there will be a deadlock while removing operations. @@ -275,28 +342,57 @@ void TransferQueue::discardQueue() m_transferQueueItemCond.signal(); } +void TransferQueue::updatePureColorTiles() +{ + for (unsigned int i = 0 ; i < m_pureColorTileQueue.size(); i++) { + TileTransferData* data = &m_pureColorTileQueue[i]; + if (data->status == pendingBlit) { + BaseTileTexture* destTexture = 0; + bool obsoleteBaseTile = checkObsolete(data); + if (!obsoleteBaseTile) { + destTexture = data->savedBaseTilePtr->backTexture(); + destTexture->setPureColor(data->pureColor); + destTexture->setOwnTextureTileInfoFromQueue(&data->tileInfo); + } + } else if (data->status == emptyItem || data->status == pendingDiscard) { + // The queue should be clear instead of setting to different status. + XLOG("Warning: Don't expect an emptyItem here."); + } + } + m_pureColorTileQueue.clear(); +} + // Call on UI thread to copy from the shared Surface Texture to the BaseTile's texture. void TransferQueue::updateDirtyBaseTiles() { android::Mutex::Autolock lock(m_transferQueueItemLocks); - cleanupTransportQueue(); + cleanupPendingDiscard(); if (!getHasGLContext()) setHasGLContext(true); + // Check the pure color tile first, since it is simpler. + updatePureColorTiles(); + // Start from the oldest item, we call the updateTexImage to retrive // the texture and blit that into each BaseTile's texture. const int nextItemIndex = getNextTransferQueueIndex(); int index = nextItemIndex; bool usedFboForUpload = false; - for (int k = 0; k < ST_BUFFER_NUMBER ; k++) { + for (int k = 0; k < m_transferQueueSize ; k++) { if (m_transferQueue[index].status == pendingBlit) { - bool obsoleteBaseTile = checkObsolete(index); + bool obsoleteBaseTile = checkObsolete(&m_transferQueue[index]); // Save the needed info, update the Surf Tex, clean up the item in // the queue. Then either move on to next item or copy the content. BaseTileTexture* destTexture = 0; - if (!obsoleteBaseTile) + BaseTileTexture* frontTexture = 0; + if (!obsoleteBaseTile) { destTexture = m_transferQueue[index].savedBaseTilePtr->backTexture(); + // while destTexture is guaranteed to not be null, frontTexture + // might be (first transfer) + frontTexture = m_transferQueue[index].savedBaseTilePtr->frontTexture(); + } + if (m_transferQueue[index].uploadType == GpuUpload) { status_t result = m_sharedSurfaceTexture->updateTexImage(); if (result != OK) @@ -306,7 +402,7 @@ void TransferQueue::updateDirtyBaseTiles() m_transferQueue[index].status = emptyItem; if (obsoleteBaseTile) { XLOG("Warning: the texture is obsolete for this baseTile"); - index = (index + 1) % ST_BUFFER_NUMBER; + index = (index + 1) % m_transferQueueSize; continue; } @@ -315,14 +411,15 @@ void TransferQueue::updateDirtyBaseTiles() if (m_transferQueue[index].uploadType == CpuUpload) { // Here we just need to upload the bitmap content to the GL Texture - GLUtils::updateTextureWithBitmap(destTexture->m_ownTextureId, 0, 0, - *m_transferQueue[index].bitmap); + GLUtils::updateTextureWithBitmap(destTexture->m_ownTextureId, + *m_transferQueue[index].bitmap, + m_transferQueue[index].tileInfo.m_inval); } else { if (!usedFboForUpload) { saveGLState(); usedFboForUpload = true; } - blitTileFromQueue(m_fboID, destTexture, + blitTileFromQueue(m_fboID, destTexture, frontTexture, m_sharedSurfaceTextureId, m_sharedSurfaceTexture->getCurrentTextureTarget(), index); @@ -333,6 +430,7 @@ void TransferQueue::updateDirtyBaseTiles() // will find the latest texture's info // We don't need a map any more, each texture contains its own // texturesTileInfo. + destTexture->setPure(false); destTexture->setOwnTextureTileInfoFromQueue(&m_transferQueue[index].tileInfo); XLOG("Blit tile x, y %d %d with dest texture %p to destTexture->m_ownTextureId %d", @@ -341,7 +439,7 @@ void TransferQueue::updateDirtyBaseTiles() destTexture, destTexture->m_ownTextureId); } - index = (index + 1) % ST_BUFFER_NUMBER; + index = (index + 1) % m_transferQueueSize; } // Clean up FBO setup. Doing this for both CPU/GPU upload can make the @@ -353,14 +451,14 @@ void TransferQueue::updateDirtyBaseTiles() GLUtils::checkGlError("updateDirtyBaseTiles"); } - m_emptyItemCount = ST_BUFFER_NUMBER; + m_emptyItemCount = m_transferQueueSize; m_transferQueueItemCond.signal(); } void TransferQueue::updateQueueWithBitmap(const TileRenderInfo* renderInfo, - int x, int y, const SkBitmap& bitmap) + const SkBitmap& bitmap) { - if (!tryUpdateQueueWithBitmap(renderInfo, x, y, bitmap)) { + if (!tryUpdateQueueWithBitmap(renderInfo, bitmap)) { // failed placing bitmap in queue, discard tile's texture so it will be // re-enqueued (and repainted) BaseTile* tile = renderInfo->baseTile; @@ -370,12 +468,15 @@ void TransferQueue::updateQueueWithBitmap(const TileRenderInfo* renderInfo, } bool TransferQueue::tryUpdateQueueWithBitmap(const TileRenderInfo* renderInfo, - int x, int y, const SkBitmap& bitmap) + const SkBitmap& bitmap) { - m_transferQueueItemLocks.lock(); + // This lock need to cover the full update since it is possible that queue + // will be cleaned up in the middle of this update without the lock. + // The Surface Texture will not block us since the readyForUpdate will check + // availability of the slots in the queue first. + android::Mutex::Autolock lock(m_transferQueueItemLocks); bool ready = readyForUpdate(); TextureUploadType currentUploadType = m_currentUploadType; - m_transferQueueItemLocks.unlock(); if (!ready) { XLOG("Quit bitmap update: not ready! for tile x y %d %d", renderInfo->x, renderInfo->y); @@ -393,13 +494,14 @@ bool TransferQueue::tryUpdateQueueWithBitmap(const TileRenderInfo* renderInfo, return false; uint8_t* img = (uint8_t*)buffer.bits; - int row, col; + int row; int bpp = 4; // Now we only deal with RGBA8888 format. int width = TilesManager::instance()->tileWidth(); int height = TilesManager::instance()->tileHeight(); - if (!x && !y && bitmap.width() == width && bitmap.height() == height) { + if (bitmap.width() == width && bitmap.height() == height) { bitmap.lockPixels(); uint8_t* bitmapOrigin = static_cast<uint8_t*>(bitmap.getPixels()); + if (buffer.stride != bitmap.width()) // Copied line by line since we need to handle the offsets and stride. for (row = 0 ; row < bitmap.height(); row ++) { @@ -411,31 +513,68 @@ bool TransferQueue::tryUpdateQueueWithBitmap(const TileRenderInfo* renderInfo, memcpy(img, bitmapOrigin, bpp * bitmap.width() * bitmap.height()); bitmap.unlockPixels(); - } else { - // TODO: implement the partial invalidate here! - XLOG("ERROR: don't expect to get here yet before we support partial inval"); } ANativeWindow_unlockAndPost(m_ANW.get()); } - m_transferQueueItemLocks.lock(); // b) After update the Surface Texture, now udpate the transfer queue info. addItemInTransferQueue(renderInfo, currentUploadType, &bitmap); - m_transferQueueItemLocks.unlock(); XLOG("Bitmap updated x, y %d %d, baseTile %p", renderInfo->x, renderInfo->y, renderInfo->baseTile); return true; } +void TransferQueue::addItemInPureColorQueue(const TileRenderInfo* renderInfo, Color color) +{ + // The pure color tiles' queue will be read from UI thread and written in + // Tex Gen thread, thus we need to have a lock here. + android::Mutex::Autolock lock(m_transferQueueItemLocks); + TileTransferData data; + addItemCommon(renderInfo, GpuUpload, &data); + data.pureColor = color; + m_pureColorTileQueue.append(data); +} + +// Translates the info from TileRenderInfo and others to TileTransferData. +// This is used by pure color tiles and normal tiles. +void TransferQueue::addItemCommon(const TileRenderInfo* renderInfo, + TextureUploadType type, + TileTransferData* data) +{ + data->savedBaseTileTexturePtr = renderInfo->baseTile->backTexture(); + data->savedBaseTilePtr = renderInfo->baseTile; + data->status = pendingBlit; + data->uploadType = type; + + // Now fill the tileInfo. + TextureTileInfo* textureInfo = &(data->tileInfo); + + IntRect inval(0, 0, 0, 0); + if (renderInfo->invalRect) { + inval.setX(renderInfo->invalRect->fLeft); + inval.setY(renderInfo->invalRect->fTop); + inval.setWidth(renderInfo->invalRect->width()); + inval.setHeight(renderInfo->invalRect->height()); + } + textureInfo->m_inval = inval; + + textureInfo->m_x = renderInfo->x; + textureInfo->m_y = renderInfo->y; + textureInfo->m_scale = renderInfo->scale; + textureInfo->m_painter = renderInfo->tilePainter; + + textureInfo->m_picture = renderInfo->textureInfo->m_pictureCount; +} + // Note that there should be lock/unlock around this function call. // Currently only called by GLUtils::updateSharedSurfaceTextureWithBitmap. void TransferQueue::addItemInTransferQueue(const TileRenderInfo* renderInfo, TextureUploadType type, const SkBitmap* bitmap) { - m_transferQueueIndex = (m_transferQueueIndex + 1) % ST_BUFFER_NUMBER; + m_transferQueueIndex = (m_transferQueueIndex + 1) % m_transferQueueSize; int index = m_transferQueueIndex; if (m_transferQueue[index].savedBaseTilePtr @@ -443,10 +582,8 @@ void TransferQueue::addItemInTransferQueue(const TileRenderInfo* renderInfo, XLOG("ERROR update a tile which is dirty already @ index %d", index); } - m_transferQueue[index].savedBaseTileTexturePtr = renderInfo->baseTile->backTexture(); - m_transferQueue[index].savedBaseTilePtr = renderInfo->baseTile; - m_transferQueue[index].status = pendingBlit; - m_transferQueue[index].uploadType = type; + TileTransferData* data = &m_transferQueue[index]; + addItemCommon(renderInfo, type, data); if (type == CpuUpload && bitmap) { // Lazily create the bitmap if (!m_transferQueue[index].bitmap) { @@ -458,38 +595,28 @@ void TransferQueue::addItemInTransferQueue(const TileRenderInfo* renderInfo, bitmap->copyTo(m_transferQueue[index].bitmap, bitmap->config()); } - // Now fill the tileInfo. - TextureTileInfo* textureInfo = &m_transferQueue[index].tileInfo; - - textureInfo->m_x = renderInfo->x; - textureInfo->m_y = renderInfo->y; - textureInfo->m_scale = renderInfo->scale; - textureInfo->m_painter = renderInfo->tilePainter; - - textureInfo->m_picture = renderInfo->textureInfo->m_pictureCount; - m_emptyItemCount--; } void TransferQueue::setTextureUploadType(TextureUploadType type) { + android::Mutex::Autolock lock(m_transferQueueItemLocks); if (m_currentUploadType == type) return; - discardQueue(); + setPendingDiscard(); - android::Mutex::Autolock lock(m_transferQueueItemLocks); m_currentUploadType = type; XLOGC("Now we set the upload to %s", m_currentUploadType == GpuUpload ? "GpuUpload" : "CpuUpload"); } -// Note: this need to be called within th lock. -// Only called by updateDirtyBaseTiles() for now -void TransferQueue::cleanupTransportQueue() +// Note: this need to be called within the lock and on the UI thread. +// Only called by updateDirtyBaseTiles() and emptyQueue() for now +void TransferQueue::cleanupPendingDiscard() { int index = getNextTransferQueueIndex(); - for (int i = 0 ; i < ST_BUFFER_NUMBER; i++) { + for (int i = 0 ; i < m_transferQueueSize; i++) { if (m_transferQueue[index].status == pendingDiscard) { // No matter what the current upload type is, as long as there has // been a Surf Tex enqueue operation, this updateTexImage need to @@ -515,7 +642,7 @@ void TransferQueue::cleanupTransportQueue() m_transferQueue[index].savedBaseTileTexturePtr = 0; m_transferQueue[index].status = emptyItem; } - index = (index + 1) % ST_BUFFER_NUMBER; + index = (index + 1) % m_transferQueueSize; } } @@ -524,7 +651,7 @@ void TransferQueue::saveGLState() glGetIntegerv(GL_VIEWPORT, m_GLStateBeforeBlit.viewport); glGetBooleanv(GL_SCISSOR_TEST, m_GLStateBeforeBlit.scissor); glGetBooleanv(GL_DEPTH_TEST, m_GLStateBeforeBlit.depth); -#if DEBUG +#ifdef DEBUG glGetFloatv(GL_COLOR_CLEAR_VALUE, m_GLStateBeforeBlit.clearColor); #endif } @@ -536,7 +663,7 @@ void TransferQueue::setGLStateForCopy(int width, int height) glDisable(GL_SCISSOR_TEST); glDisable(GL_DEPTH_TEST); // Clear the content is only for debug purpose. -#if DEBUG +#ifdef DEBUG glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT); #endif @@ -554,7 +681,7 @@ void TransferQueue::restoreGLState() if (m_GLStateBeforeBlit.depth[0]) glEnable(GL_DEPTH_TEST); -#if DEBUG +#ifdef DEBUG glClearColor(m_GLStateBeforeBlit.clearColor[0], m_GLStateBeforeBlit.clearColor[1], m_GLStateBeforeBlit.clearColor[2], @@ -564,7 +691,7 @@ void TransferQueue::restoreGLState() int TransferQueue::getNextTransferQueueIndex() { - return (m_transferQueueIndex + 1) % ST_BUFFER_NUMBER; + return (m_transferQueueIndex + 1) % m_transferQueueSize; } } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/TransferQueue.h b/Source/WebCore/platform/graphics/android/TransferQueue.h index 63455de..5dd2e0a 100644 --- a/Source/WebCore/platform/graphics/android/TransferQueue.h +++ b/Source/WebCore/platform/graphics/android/TransferQueue.h @@ -32,6 +32,7 @@ #include "BaseTileTexture.h" #include "ShaderProgram.h" #include "TiledPage.h" +#include <EGL/eglext.h> namespace WebCore { @@ -92,6 +93,9 @@ public: // lazily allocated. SkBitmap* bitmap; + // Specific data to the pure color tiles' queue. + Color pureColor; + // Sync object for GPU fence, this is the only the info passed from UI // thread to Tex Gen thread. The reason of having this is due to the // missing sync mechanism on Surface Texture on some vendor. b/5122031. @@ -104,22 +108,20 @@ public: class TransferQueue { public: - TransferQueue(); + TransferQueue(bool useMinimalMem); ~TransferQueue(); // This will be called by the browser through nativeSetProperty void setTextureUploadType(TextureUploadType type); - + void cleanupGLResources(); void updateDirtyBaseTiles(); - void initSharedSurfaceTextures(int width, int height); + void initGLResources(int width, int height); // insert the bitmap into the queue, mark the tile dirty if failing - void updateQueueWithBitmap(const TileRenderInfo* renderInfo, int x, int y, + void updateQueueWithBitmap(const TileRenderInfo* renderInfo, const SkBitmap& bitmap); - void discardQueue(); - void addItemInTransferQueue(const TileRenderInfo* info, TextureUploadType type, const SkBitmap* bitmap); @@ -132,6 +134,12 @@ public: void lockQueue() { m_transferQueueItemLocks.lock(); } void unlockQueue() { m_transferQueueItemLocks.unlock(); } + void addItemInPureColorQueue(const TileRenderInfo* renderInfo, Color color); + + void setPendingDiscardWithLock(); + void emptyQueue(); + + bool needsInit() { return !m_sharedSurfaceTextureId; } // This queue can be accessed from UI and TexGen thread, therefore, we need // a lock to protect its access TileTransferData* m_transferQueue; @@ -143,7 +151,7 @@ public: private: // return true if successfully inserted into queue - bool tryUpdateQueueWithBitmap(const TileRenderInfo* renderInfo, int x, int y, + bool tryUpdateQueueWithBitmap(const TileRenderInfo* renderInfo, const SkBitmap& bitmap); bool getHasGLContext(); void setHasGLContext(bool hasContext); @@ -156,16 +164,22 @@ private: void restoreGLState(); // Check the current transfer queue item is obsolete or not. - bool checkObsolete(int index); + bool checkObsolete(const TileTransferData* data); + void setPendingDiscard(); // Before each draw call and the blit operation, clean up all the // pendingDiscard items. - void cleanupTransportQueue(); + void cleanupPendingDiscard(); void blitTileFromQueue(GLuint fboID, BaseTileTexture* destTex, + BaseTileTexture* frontTex, GLuint srcTexId, GLenum srcTexTarget, int index); + void addItemCommon(const TileRenderInfo* renderInfo, + TextureUploadType type, TileTransferData* data); + + void updatePureColorTiles(); // Note that the m_transferQueueIndex only changed in the TexGen thread // where we are going to move on to update the next item in the queue. int m_transferQueueIndex; @@ -201,6 +215,14 @@ private: // This should be GpuUpload for production, but for debug purpose or working // around driver/HW issue, we can set it to CpuUpload. TextureUploadType m_currentUploadType; + + // The non-pure-color tile are 1 to 1 mapping with Surface Texture which is + // resource limited. To get better performance, it is better to separate + // the pure color tile into another queue. + WTF::Vector<TileTransferData> m_pureColorTileQueue; + + // The number of items transfer queue can buffer up. + int m_transferQueueSize; }; } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/TreeManager.cpp b/Source/WebCore/platform/graphics/android/TreeManager.cpp index b7eaacf..fd5e525 100644 --- a/Source/WebCore/platform/graphics/android/TreeManager.cpp +++ b/Source/WebCore/platform/graphics/android/TreeManager.cpp @@ -52,8 +52,9 @@ namespace WebCore { -TreeManager::TreeManager() - : m_drawingTree(0) +TreeManager::TreeManager(GLWebViewState* state) + : m_state(state) + , m_drawingTree(0) , m_paintingTree(0) , m_queuedTree(0) , m_fastSwapMode(false) @@ -110,18 +111,13 @@ void TreeManager::clearTrees() { // remove painted surfaces from any tree in this view, and set trees as no // longer drawing, to clear ptrs from surfaces to layers - GLWebViewState* oldState = 0; - if (m_drawingTree) { - oldState = m_drawingTree->state(); + if (m_drawingTree) m_drawingTree->setIsDrawing(false); - } - if (m_paintingTree) { - oldState = m_paintingTree->state(); + if (m_paintingTree) m_paintingTree->setIsDrawing(false); - } - XLOG("TreeManager %p removing PS from state %p", this, oldState); - TilesManager::instance()->paintedSurfacesCleanup(oldState); + XLOG("TreeManager %p removing PS from state %p", this, m_state); + TilesManager::instance()->paintedSurfacesCleanup(m_state); SkSafeUnref(m_drawingTree); m_drawingTree = 0; @@ -132,8 +128,9 @@ void TreeManager::clearTrees() } // a new layer tree has arrived, queue it if we're painting something already, -// or start painting it if we aren't -void TreeManager::updateWithTree(Layer* newTree, bool brandNew) +// or start painting it if we aren't. Returns true if the manager has two trees +// already queued. +bool TreeManager::updateWithTree(Layer* newTree, bool brandNew) { XLOG("updateWithTree - %p, has children %d, has animations %d", newTree, newTree && newTree->countChildren(), @@ -153,16 +150,21 @@ void TreeManager::updateWithTree(Layer* newTree, bool brandNew) m_paintingTree = newTree; m_paintingTree->setIsPainting(m_drawingTree); } - return; + return false; } if (m_queuedTree || m_paintingTree) { // currently painting, so defer this new tree if (m_queuedTree) { - // have a queued tree, copy over invals so the regions are - // eventually repainted + // already have a queued tree, copy over invals so the regions are + // eventually repainted and let the old queued tree be discarded m_queuedTree->mergeInvalsInto(newTree); + if (!TilesManager::instance()->useDoubleBuffering()) { + // not double buffering, count discarded tree/webkit paint as an update + TilesManager::instance()->incTreeUpdates(); + } + XLOG("DISCARDING tree - %p, has children %d, has animations %d", newTree, newTree && newTree->countChildren(), newTree && newTree->countChildren() @@ -170,12 +172,12 @@ void TreeManager::updateWithTree(Layer* newTree, bool brandNew) } SkSafeUnref(m_queuedTree); m_queuedTree = newTree; - return; + } else { + // don't have painting tree, paint this one! + m_paintingTree = newTree; + m_paintingTree->setIsPainting(m_drawingTree); } - - // don't have painting tree, paint this one! - m_paintingTree = newTree; - m_paintingTree->setIsPainting(m_drawingTree); + return m_drawingTree && TilesManager::instance()->useDoubleBuffering(); } void TreeManager::updateScrollableLayerInTree(Layer* tree, int layerId, int x, int y) @@ -222,9 +224,10 @@ bool TreeManager::drawGL(double currentTime, IntRect& viewRect, if (laTree) laTree->computeTexturesAmount(texturesResultPtr); - if (/*!m_fastSwapMode && */ m_paintingTree->isReady()) { + if (!TilesManager::instance()->useDoubleBuffering() || m_paintingTree->isReady()) { XLOG("have painting tree %p ready, swapping!", m_paintingTree); didTreeSwap = true; + TilesManager::instance()->incTreeUpdates(); swap(); if (treesSwappedPtr) *treesSwappedPtr = true; @@ -245,6 +248,10 @@ bool TreeManager::drawGL(double currentTime, IntRect& viewRect, if (m_drawingTree) { bool drawingReady = didTreeSwap || m_drawingTree->isReady(); + // call the page swap callback if registration happened without more trees enqueued + if (treesSwappedPtr && drawingReady && !m_paintingTree) + *treesSwappedPtr = true; + if (didTreeSwap || m_fastSwapMode || (drawingReady && !m_paintingTree)) m_drawingTree->swapTiles(); diff --git a/Source/WebCore/platform/graphics/android/TreeManager.h b/Source/WebCore/platform/graphics/android/TreeManager.h index 83d5300..a571d1a 100644 --- a/Source/WebCore/platform/graphics/android/TreeManager.h +++ b/Source/WebCore/platform/graphics/android/TreeManager.h @@ -36,16 +36,17 @@ class SkCanvas; namespace WebCore { +class GLWebViewState; class IntRect; class TexturesResult; class TEST_EXPORT TreeManager { public: - TreeManager(); + TreeManager(GLWebViewState* state); ~TreeManager(); - void updateWithTree(Layer* tree, bool brandNew); + bool updateWithTree(Layer* tree, bool brandNew); void updateScrollableLayer(int layerId, int x, int y); @@ -70,6 +71,8 @@ private: android::Mutex m_paintSwapLock; + GLWebViewState* m_state; + Layer* m_drawingTree; Layer* m_paintingTree; Layer* m_queuedTree; diff --git a/Source/WebCore/platform/graphics/android/VerticalTextMap.cpp b/Source/WebCore/platform/graphics/android/VerticalTextMap.cpp index 6e715e2..42aa385 100644 --- a/Source/WebCore/platform/graphics/android/VerticalTextMap.cpp +++ b/Source/WebCore/platform/graphics/android/VerticalTextMap.cpp @@ -33,28 +33,29 @@ #include <wtf/RefPtr.h> static const UChar vTextCnvTable[][2] = { - // TODO: uncomment mappings once we add glyphs for vertical forms. - // {0x0021, 0xfe15}, // exclamation mark + {0x0021, 0xfe15}, // exclamation mark {0x0028, 0xfe35}, // left paren {0x0029, 0xfe36}, // right paren - // {0x002c, 0xfe10}, // comma + {0x002c, 0xfe10}, // comma + {0x002d, 0xfe32}, // hyphen {0x003a, 0xfe30}, // colon - {0x003b, 0x007c}, // hyphen - // {0x003f, 0xfe16}, // question mark - // {0x005b, 0xfe14}, // semicolon - {0x005d, 0xfe47}, // left square bracket - {0x005f, 0xfe48}, // right square bracket + {0x003b, 0xfe14}, // semicolon + {0x003f, 0xfe16}, // question mark + {0x005b, 0xfe47}, // left square bracket + {0x005d, 0xfe48}, // right square bracket {0x007b, 0xfe37}, // left curly bracket {0x007d, 0xfe38}, // right curly bracket {0x007e, 0x007c}, // tilde to vertical line + {0x00ab, 0xfe3d}, // left pointing double angle quotation mark + {0x00bb, 0xfe3e}, // right pointing double angle quotation mark + {0x2010, 0xfe32}, // hyphen {0x2013, 0xfe32}, // en dash {0x2014, 0xfe31}, // em dash {0x2015, 0xfe31}, // horizontal bar {0x2025, 0xfe30}, // two dot leader - // TODO: change the mapping 0x2026 -> 0xFE19 once Android has the glyph for 0xFE19. - {0x2026, 0xfe30}, // three dot leader - // {0x3001, 0xfe11}, // Ideographic comma - // {0x3002, 0xfe12}, // Ideographic full stop + {0x2026, 0xfe19}, // three dot leader + {0x3001, 0xfe11}, // Ideographic comma + {0x3002, 0xfe12}, // Ideographic full stop {0x3008, 0xfe3f}, // left angle bracket {0x3009, 0xfe40}, // right angle bracket {0x300a, 0xfe3d}, // left double angle bracket @@ -67,19 +68,21 @@ static const UChar vTextCnvTable[][2] = { {0x3011, 0xfe3c}, // right black lenticular bracket {0x3014, 0xfe39}, // left black lenticular bracket {0x3015, 0xfe3a}, // right tortise shell bracket - // {0x3016, 0xfe17}, // left white lenticular bracket - // {0x3017, 0xfe18}, // right white lenticular bracket - // {0x3019, 0xfe19}, // horizontal ellipses + {0x3016, 0xfe17}, // left white lenticular bracket + {0x3017, 0xfe18}, // right white lenticular bracket {0x30fc, 0x3021}, // prolonged sound {0xfe4f, 0xfe34}, // wavy low line {0xff08, 0xfe35}, // full width left paren {0xff09, 0xfe36}, // full width right paren + {0xff0c, 0xfe10}, // full width comma {0xff3b, 0xfe47}, // full width left square bracket {0xff3d, 0xfe48}, // full width right square bracket {0xff5b, 0xfe37}, // full width left curly bracket + {0xff5c, 0xfe31}, // fullwidth vertical line {0xff5d, 0xfe38}, // full width right curly bracket - // {0xff64, 0xfe11}, // halfwidth ideo comma - // {0xff61, 0xfe12}, // halfwidth ideo full stop + {0xff5e, 0x007c}, // tilde to vertical line + {0xff64, 0xfe11}, // halfwidth ideo comma + {0xff61, 0xfe12}, // halfwidth ideo full stop }; namespace WebCore { diff --git a/Source/WebCore/platform/graphics/android/VideoLayerAndroid.cpp b/Source/WebCore/platform/graphics/android/VideoLayerAndroid.cpp index 482d711..a527e6a 100644 --- a/Source/WebCore/platform/graphics/android/VideoLayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/VideoLayerAndroid.cpp @@ -53,6 +53,8 @@ GLuint VideoLayerAndroid::m_spinnerOuterTextureId = 0; GLuint VideoLayerAndroid::m_spinnerInnerTextureId = 0; GLuint VideoLayerAndroid::m_posterTextureId = 0; GLuint VideoLayerAndroid::m_backgroundTextureId = 0; +GLuint VideoLayerAndroid::m_playTextureId = 0; +GLuint VideoLayerAndroid::m_pauseTextureId = 0; bool VideoLayerAndroid::m_createdTexture = false; double VideoLayerAndroid::m_rotateDegree = 0; @@ -102,6 +104,16 @@ GLuint VideoLayerAndroid::createPosterTexture() return createTextureFromImage(RenderSkinMediaButton::VIDEO); } +GLuint VideoLayerAndroid::createPlayTexture() +{ + return createTextureFromImage(RenderSkinMediaButton::PLAY); +} + +GLuint VideoLayerAndroid::createPauseTexture() +{ + return createTextureFromImage(RenderSkinMediaButton::PAUSE); +} + GLuint VideoLayerAndroid::createTextureFromImage(int buttonType) { SkRect rect = SkRect(buttonRect); @@ -112,7 +124,8 @@ GLuint VideoLayerAndroid::createTextureFromImage(int buttonType) SkCanvas canvas(bitmap); canvas.drawARGB(0, 0, 0, 0, SkXfermode::kClear_Mode); - RenderSkinMediaButton::Draw(&canvas, buttonRect, buttonType, true); + RenderSkinMediaButton::Draw(&canvas, buttonRect, buttonType, true, 0, + false); GLuint texture; glGenTextures(1, &texture); @@ -142,6 +155,47 @@ GLuint VideoLayerAndroid::createBackgroundTexture() return texture; } +void VideoLayerAndroid::showPreparingAnimation(const SkRect& rect, + const SkRect innerRect) +{ + ShaderProgram* shader = TilesManager::instance()->shader(); + shader->drawLayerQuad(m_drawTransform, rect, m_backgroundTextureId, 1, true); + + TransformationMatrix addReverseRotation; + TransformationMatrix addRotation = m_drawTransform; + addRotation.translate(innerRect.fLeft, innerRect.fTop); + addRotation.translate(IMAGESIZE / 2, IMAGESIZE / 2); + addReverseRotation = addRotation; + addRotation.rotate(m_rotateDegree); + addRotation.translate(-IMAGESIZE / 2, -IMAGESIZE / 2); + + SkRect size = SkRect::MakeWH(innerRect.width(), innerRect.height()); + shader->drawLayerQuad(addRotation, size, m_spinnerOuterTextureId, 1, true); + + addReverseRotation.rotate(-m_rotateDegree); + addReverseRotation.translate(-IMAGESIZE / 2, -IMAGESIZE / 2); + + shader->drawLayerQuad(addReverseRotation, size, m_spinnerInnerTextureId, 1, true); + + m_rotateDegree += ROTATESTEP; +} + +SkRect VideoLayerAndroid::calVideoRect(const SkRect& rect) +{ + SkRect videoRect = rect; + VideoLayerManager* manager = TilesManager::instance()->videoLayerManager(); + float aspectRatio = manager->getAspectRatio(uniqueId()); + float deltaY = rect.height() - rect.width() / aspectRatio; + if (deltaY >= 0) + videoRect.inset(0, deltaY / 2); + else { + float deltaX = rect.width() - rect.height() * aspectRatio; + if (deltaX >= 0) + videoRect.inset(deltaX / 2, 0); + } + return videoRect; +} + bool VideoLayerAndroid::drawGL() { // Lazily allocated the textures. @@ -150,81 +204,88 @@ bool VideoLayerAndroid::drawGL() m_spinnerOuterTextureId = createSpinnerOuterTexture(); m_spinnerInnerTextureId = createSpinnerInnerTexture(); m_posterTextureId = createPosterTexture(); + m_playTextureId = createPlayTexture(); + m_pauseTextureId = createPauseTexture(); m_createdTexture = true; } + ShaderProgram* shader = TilesManager::instance()->shader(); + SkRect rect = SkRect::MakeSize(getSize()); GLfloat surfaceMatrix[16]; + // Calculate the video rect based on the aspect ratio and the element rect. + SkRect videoRect = calVideoRect(rect); + if (videoRect != rect) { + // Paint the whole video element with black color when video content + // can't cover the whole area. + shader->drawLayerQuad(m_drawTransform, rect, 0, 1, true, GL_TEXTURE_2D, + Color(0, 0, 0, 255)); + } + + // Inner rect is for the progressing / play / pause animation. SkRect innerRect = SkRect(buttonRect); - if (innerRect.contains(rect)) - innerRect = rect; + if (innerRect.contains(videoRect)) + innerRect = videoRect; + innerRect.offset(videoRect.fLeft + (videoRect.width() - IMAGESIZE) / 2, + videoRect.fTop + (videoRect.height() - IMAGESIZE) / 2); - innerRect.offset((rect.width() - IMAGESIZE) / 2 , (rect.height() - IMAGESIZE) / 2); + // When we are drawing the animation of the play/pause button in the + // middle of the video, we need to ask for redraw. + bool needRedraw = false; // Draw the poster image, the progressing image or the Video depending // on the player's state. + VideoLayerManager* manager = TilesManager::instance()->videoLayerManager(); if (m_playerState == PREPARING) { // Show the progressing animation, with two rotating circles - TilesManager::instance()->shader()->drawLayerQuad(m_drawTransform, rect, - m_backgroundTextureId, - 1, true); - - TransformationMatrix addReverseRotation; - TransformationMatrix addRotation = m_drawTransform; - addRotation.translate(innerRect.fLeft, innerRect.fTop); - addRotation.translate(IMAGESIZE / 2, IMAGESIZE / 2); - addReverseRotation = addRotation; - addRotation.rotate(m_rotateDegree); - addRotation.translate(-IMAGESIZE / 2, -IMAGESIZE / 2); - - SkRect size = SkRect::MakeWH(innerRect.width(), innerRect.height()); - TilesManager::instance()->shader()->drawLayerQuad(addRotation, size, - m_spinnerOuterTextureId, - 1, true); - - addReverseRotation.rotate(-m_rotateDegree); - addReverseRotation.translate(-IMAGESIZE / 2, -IMAGESIZE / 2); - - TilesManager::instance()->shader()->drawLayerQuad(addReverseRotation, size, - m_spinnerInnerTextureId, - 1, true); - - m_rotateDegree += ROTATESTEP; - + showPreparingAnimation(videoRect, innerRect); + needRedraw = true; } else if (m_playerState == PLAYING && m_surfaceTexture.get()) { // Show the real video. m_surfaceTexture->updateTexImage(); m_surfaceTexture->getTransformMatrix(surfaceMatrix); - GLuint textureId = - TilesManager::instance()->videoLayerManager()->getTextureId(uniqueId()); - TilesManager::instance()->shader()->drawVideoLayerQuad(m_drawTransform, - surfaceMatrix, - rect, textureId); - TilesManager::instance()->videoLayerManager()->updateMatrix(uniqueId(), - surfaceMatrix); + GLuint textureId = manager->getTextureId(uniqueId()); + shader->drawVideoLayerQuad(m_drawTransform, surfaceMatrix, + videoRect, textureId); + manager->updateMatrix(uniqueId(), surfaceMatrix); + + // Use the scale to control the fading the sizing during animation + double scale = manager->drawIcon(uniqueId(), PlayIcon); + if (scale) { + innerRect.inset(IMAGESIZE / 4 * scale, IMAGESIZE / 4 * scale); + shader->drawLayerQuad(m_drawTransform, innerRect, + m_playTextureId, scale, true); + needRedraw = true; + } + } else { - GLuint textureId = - TilesManager::instance()->videoLayerManager()->getTextureId(uniqueId()); - GLfloat* matrix = - TilesManager::instance()->videoLayerManager()->getMatrix(uniqueId()); + GLuint textureId = manager->getTextureId(uniqueId()); + GLfloat* matrix = manager->getMatrix(uniqueId()); if (textureId && matrix) { // Show the screen shot for each video. - TilesManager::instance()->shader()->drawVideoLayerQuad(m_drawTransform, - matrix, - rect, textureId); + shader->drawVideoLayerQuad(m_drawTransform, matrix, + videoRect, textureId); } else { // Show the static poster b/c there is no screen shot available. - TilesManager::instance()->shader()->drawLayerQuad(m_drawTransform, rect, - m_backgroundTextureId, - 1, true); - TilesManager::instance()->shader()->drawLayerQuad(m_drawTransform, innerRect, - m_posterTextureId, - 1, true); + shader->drawLayerQuad(m_drawTransform, videoRect, m_backgroundTextureId, + 1, true); + shader->drawLayerQuad(m_drawTransform, innerRect, m_posterTextureId, + 1, true); + } + + // Use the scale to control the fading and the sizing during animation. + double scale = manager->drawIcon(uniqueId(), PauseIcon); + if (scale) { + innerRect.inset(IMAGESIZE / 4 * scale, IMAGESIZE / 4 * scale); + shader->drawLayerQuad(m_drawTransform, innerRect, + m_pauseTextureId, scale, true); + needRedraw = true; } - } - return drawChildrenGL(); + } + // Don't short circuit here since we still want to draw the children. + return drawChildrenGL() || needRedraw; } } diff --git a/Source/WebCore/platform/graphics/android/VideoLayerAndroid.h b/Source/WebCore/platform/graphics/android/VideoLayerAndroid.h index 8a064bb..6bd9fa1 100644 --- a/Source/WebCore/platform/graphics/android/VideoLayerAndroid.h +++ b/Source/WebCore/platform/graphics/android/VideoLayerAndroid.h @@ -30,6 +30,7 @@ #include "GLUtils.h" #include "LayerAndroid.h" +#include "ShaderProgram.h" #include <jni.h> namespace android { @@ -62,10 +63,15 @@ public: GLuint createSpinnerOuterTexture(); GLuint createSpinnerInnerTexture(); GLuint createPosterTexture(); + GLuint createPlayTexture(); + GLuint createPauseTexture(); private: GLuint createTextureFromImage(int buttonType); void init(); + void showPreparingAnimation(const SkRect& rect, + const SkRect innerRect); + SkRect calVideoRect(const SkRect& rect); // Surface texture for showing the video is actually allocated in Java side // and passed into this native code. sp<android::SurfaceTexture> m_surfaceTexture; @@ -78,6 +84,8 @@ private: static GLuint m_posterTextureId; static GLuint m_spinnerOuterTextureId; static GLuint m_spinnerInnerTextureId; + static GLuint m_playTextureId; + static GLuint m_pauseTextureId; static double m_rotateDegree; diff --git a/Source/WebCore/platform/graphics/android/VideoLayerManager.cpp b/Source/WebCore/platform/graphics/android/VideoLayerManager.cpp index cec4d67..521b623 100644 --- a/Source/WebCore/platform/graphics/android/VideoLayerManager.cpp +++ b/Source/WebCore/platform/graphics/android/VideoLayerManager.cpp @@ -26,6 +26,8 @@ #include "config.h" #include "VideoLayerManager.h" +#include <wtf/CurrentTime.h> + #if USE(ACCELERATED_COMPOSITING) #ifdef DEBUG @@ -42,6 +44,10 @@ #endif // DEBUG +// The animation of the play/pause icon will last for PLAY_PAUSE_ICON_SHOW_TIME +// seconds. +#define PLAY_PAUSE_ICON_SHOW_TIME 1 + // Define the max sum of all the video's sizes. // Note that video_size = width * height. If there is no compression, then the // maximum memory consumption could be 4 * video_size. @@ -49,6 +55,10 @@ // screenshots would not be above 8M. #define MAX_VIDEOSIZE_SUM 2097152 +// We don't preload the video data, so we don't have the exact size yet. +// Assuming 16:9 by default, this will be corrected after video prepared. +#define DEFAULT_VIDEO_ASPECT_RATIO 1.78 + namespace WebCore { VideoLayerManager::VideoLayerManager() @@ -66,6 +76,16 @@ GLuint VideoLayerManager::getTextureId(const int layerId) return result; } +// Getting the aspect ratio for GL draw call, in the UI thread. +float VideoLayerManager::getAspectRatio(const int layerId) +{ + android::Mutex::Autolock lock(m_videoLayerInfoMapLock); + float result = 0; + if (m_videoLayerInfoMap.contains(layerId)) + result = m_videoLayerInfoMap.get(layerId)->aspectRatio; + return result; +} + // Getting matrix for GL draw call, in the UI thread. GLfloat* VideoLayerManager::getMatrix(const int layerId) { @@ -103,8 +123,11 @@ void VideoLayerManager::registerTexture(const int layerId, const GLuint textureI pInfo->textureId = textureId; memset(pInfo->surfaceMatrix, 0, sizeof(pInfo->surfaceMatrix)); pInfo->videoSize = 0; + pInfo->aspectRatio = DEFAULT_VIDEO_ASPECT_RATIO; m_currentTimeStamp++; pInfo->timeStamp = m_currentTimeStamp; + pInfo->lastIconShownTime = 0; + pInfo->iconState = Registered; m_videoLayerInfoMap.add(layerId, pInfo); XLOG("GL texture %d regisered for layerId %d", textureId, layerId); @@ -115,13 +138,16 @@ void VideoLayerManager::registerTexture(const int layerId, const GLuint textureI // Only when the video is prepared, we got the video size. So we should update // the size for the video accordingly. // This is called from webcore thread, from MediaPlayerPrivateAndroid. -void VideoLayerManager::updateVideoLayerSize(const int layerId, const int size ) +void VideoLayerManager::updateVideoLayerSize(const int layerId, const int size, + const float ratio) { android::Mutex::Autolock lock(m_videoLayerInfoMapLock); if (m_videoLayerInfoMap.contains(layerId)) { VideoLayerInfo* pInfo = m_videoLayerInfoMap.get(layerId); - if (pInfo) + if (pInfo) { pInfo->videoSize = size; + pInfo->aspectRatio = ratio; + } } // If the memory usage is out of bound, then just delete the oldest ones. @@ -238,5 +264,34 @@ void VideoLayerManager::removeLayerInternal(const int layerId) return; } +double VideoLayerManager::drawIcon(const int layerId, IconType type) +{ + // When ratio 0 is returned, the Icon should not be drawn. + double ratio = 0; + + android::Mutex::Autolock lock(m_videoLayerInfoMapLock); + if (m_videoLayerInfoMap.contains(layerId)) { + VideoLayerInfo* pInfo = m_videoLayerInfoMap.get(layerId); + // If this is state switching moment, reset the time and state + if ((type == PlayIcon && pInfo->iconState != PlayIconShown) + || (type == PauseIcon && pInfo->iconState != PauseIconShown)) { + pInfo->lastIconShownTime = WTF::currentTime(); + pInfo->iconState = (type == PlayIcon) ? PlayIconShown : PauseIconShown; + } + + // After switching the state, we calculate the ratio depending on the + // time interval. + if ((type == PlayIcon && pInfo->iconState == PlayIconShown) + || (type == PauseIcon && pInfo->iconState == PauseIconShown)) { + double delta = WTF::currentTime() - pInfo->lastIconShownTime; + ratio = 1.0 - (delta / PLAY_PAUSE_ICON_SHOW_TIME); + } + } + + if (ratio > 1 || ratio < 0) + ratio = 0; + return ratio; +} + } #endif // USE(ACCELERATED_COMPOSITING) diff --git a/Source/WebCore/platform/graphics/android/VideoLayerManager.h b/Source/WebCore/platform/graphics/android/VideoLayerManager.h index de2dafc..d554362 100644 --- a/Source/WebCore/platform/graphics/android/VideoLayerManager.h +++ b/Source/WebCore/platform/graphics/android/VideoLayerManager.h @@ -34,13 +34,28 @@ namespace WebCore { +enum IconState { + Registered, + PlayIconShown, + PauseIconShown +}; + +enum IconType { + PlayIcon, + PauseIcon +}; + // Every video layer can use its uniqueId to query VideoLayerManager about such // info globally. struct VideoLayerInfo { GLuint textureId; // GL texture bound with the surface texture. int videoSize; // The size of the video. + float aspectRatio; // The aspect ratio of the video. int timeStamp; // Used to decide which VideoLayerInfo is the oldest one. GLfloat surfaceMatrix[16]; + + double lastIconShownTime; + IconState iconState; }; @@ -54,7 +69,7 @@ public: // Register the texture when we got setSurfaceTexture call. void registerTexture(const int layerId, const GLuint textureId); // Update the size when the video is prepared. - void updateVideoLayerSize(const int layerId, const int size); + void updateVideoLayerSize(const int layerId, const int size, const float ratio); // At draw time, update the matrix for every video frame update. void updateMatrix(const int layerId, const GLfloat* matrix); // Remove the layer info from the mapping. @@ -64,10 +79,13 @@ public: GLuint getTextureId(const int layerId); // Return the matrix for surface texture corresponding to the layerId GLfloat* getMatrix(const int layerId); + // Return the aspect ratio for the video corresponding to the layerId + float getAspectRatio(const int layerId); // Delete the GL textures void deleteUnusedTextures(); + double drawIcon(const int layerId, IconType type); private: // Get the sum of all the video size stored in m_videoLayerInfoMap. int getTotalMemUsage(); 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 e88c65d..0000000 --- a/Source/WebCore/platform/graphics/android/android_graphics.cpp +++ /dev/null @@ -1,160 +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 "CachedColor.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 { - -// 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::draw(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; - if (layer->uniqueId() != 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; - } - const CachedColor& colors = m_frame->color(m_node); - 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(-colors.outset(), -colors.outset()); - rgn.op(ir, SkRegion::kUnion_Op); - } - rgn.getBoundaryPath(&path); - - SkPaint paint; - paint.setAntiAlias(true); - paint.setPathEffect(new SkCornerPathEffect( - SkIntToScalar(colors.radius())))->unref(); - SkColor outer; - SkColor inner; - if (m_isPressed) { - SkColor pressed; - pressed = colors.fillColor(); - paint.setColor(pressed); - canvas->drawPath(path, paint); - outer = colors.pressedOuterColor(); - inner = colors.pressedInnerColor(); - } else { - outer = colors.selectedOuterColor(); - inner = colors.selectedInnerColor(); - } - paint.setStyle(SkPaint::kStroke_Style); - paint.setStrokeWidth(colors.outerWidth() * WIDTH_SCALE); - paint.setColor(outer); - canvas->drawPath(path, paint); - paint.setStrokeWidth(colors.innerWidth() * WIDTH_SCALE); - paint.setColor(inner); - canvas->drawPath(path, paint); - SkRect localBounds, globalBounds; - localBounds = path.getBounds(); - float width = std::max(colors.innerWidth(), colors.outerWidth()); - 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_node->cursorRings(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); - const CachedColor& colors = m_frame->color(m_node); - m_bounds.inflate(SkScalarCeil(colors.outerWidth())); - m_absBounds.inflate(SkScalarCeil(colors.outerWidth())); - 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"); - DBG_NAV_LOGD("[%d] inner=%d outer=%d outset=%d radius=%d" - " fill=0x%08x pin=0x%08x pout=0x%08x sin=0x%08x sout=0x%08x", - m_node->colorIndex(), colors.innerWidth(), colors.outerWidth(), - colors.outset(), colors.radius(), colors.fillColor(), - colors.pressedInnerColor(), colors.pressedOuterColor(), - colors.selectedInnerColor(), colors.selectedInnerColor()); -#endif - return true; -} - -} diff --git a/Source/WebCore/platform/graphics/android/android_graphics.h b/Source/WebCore/platform/graphics/android/android_graphics.h index 60ac115..7faa781 100644 --- a/Source/WebCore/platform/graphics/android/android_graphics.h +++ b/Source/WebCore/platform/graphics/android/android_graphics.h @@ -26,53 +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) : m_viewImpl(core) {} - virtual ~CursorRing() {} - virtual void draw(SkCanvas* , LayerAndroid* , IntRect* ); - void setIsButton(const CachedNode* ); - bool setup(); - WTF::Vector<IntRect>& rings() { return m_rings; } -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; -}; - -} #endif diff --git a/Source/WebCore/platform/network/android/ResourceHandleAndroid.cpp b/Source/WebCore/platform/network/android/ResourceHandleAndroid.cpp index 13a26f0..4bc918b 100644 --- a/Source/WebCore/platform/network/android/ResourceHandleAndroid.cpp +++ b/Source/WebCore/platform/network/android/ResourceHandleAndroid.cpp @@ -96,9 +96,7 @@ void ResourceHandle::platformSetDefersLoading(bool) } // This static method is called to check to see if a POST response is in -// the cache. The JNI call through to the HTTP cache stored on the Java -// side may be slow, but is only used during a navigation to -// a POST response. +// the cache. bool ResourceHandle::willLoadFromCache(ResourceRequest& request, Frame*) { // set the cache policy correctly, copied from diff --git a/Source/WebCore/platform/network/android/ResourceLoaderAndroid.h b/Source/WebCore/platform/network/android/ResourceLoaderAndroid.h index f627d62..5ff2322 100644 --- a/Source/WebCore/platform/network/android/ResourceLoaderAndroid.h +++ b/Source/WebCore/platform/network/android/ResourceLoaderAndroid.h @@ -46,7 +46,6 @@ public: virtual void pauseLoad(bool) = 0; // END ANDROID TODO - // Call to java to find out if this URL is in the cache static bool willLoadFromCache(const WebCore::KURL&, int64_t identifier); protected: ResourceLoaderAndroid() { } 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/platform/text/android/HyphenationAndroid.cpp b/Source/WebCore/platform/text/android/HyphenationAndroid.cpp index d1bd839..9933715 100644 --- a/Source/WebCore/platform/text/android/HyphenationAndroid.cpp +++ b/Source/WebCore/platform/text/android/HyphenationAndroid.cpp @@ -28,7 +28,7 @@ // For external hyphenation library. #include "hyphen.h" -#include <utils/AssetManager.h> +#include <androidfw/AssetManager.h> #include <wtf/text/CString.h> #include <wtf/text/WTFString.h> diff --git a/Source/WebCore/plugins/PluginView.cpp b/Source/WebCore/plugins/PluginView.cpp index c39ceac..ffefc71 100644 --- a/Source/WebCore/plugins/PluginView.cpp +++ b/Source/WebCore/plugins/PluginView.cpp @@ -830,8 +830,6 @@ PassRefPtr<JSC::Bindings::Instance> PluginView::bindingInstance() } #endif -#if USE(V8) -// This is really JS engine independent NPObject* PluginView::getNPObject() { #if ENABLE(NETSCAPE_PLUGIN_API) if (!m_plugin || !m_plugin->pluginFuncs()->getvalue) @@ -859,7 +857,6 @@ NPObject* PluginView::getNPObject() { return 0; #endif // NETSCAPE_PLUGIN_API } -#endif // V8 void PluginView::disconnectStream(PluginStream* stream) { diff --git a/Source/WebCore/plugins/PluginView.h b/Source/WebCore/plugins/PluginView.h index 976c65c..bf77e51 100644 --- a/Source/WebCore/plugins/PluginView.h +++ b/Source/WebCore/plugins/PluginView.h @@ -202,9 +202,7 @@ namespace WebCore { void (*timerFunc)(NPP, uint32_t timerID)); void unscheduleTimer(NPP, uint32_t timerID); #endif -#if USE(V8) NPObject* getNPObject(); -#endif virtual void invalidateRect(const IntRect&); diff --git a/Source/WebCore/plugins/android/PluginViewAndroid.cpp b/Source/WebCore/plugins/android/PluginViewAndroid.cpp index dba7d3b..315d8a4 100644 --- a/Source/WebCore/plugins/android/PluginViewAndroid.cpp +++ b/Source/WebCore/plugins/android/PluginViewAndroid.cpp @@ -63,10 +63,6 @@ #include "ScriptController.h" #include "Settings.h" -#if USE(JSC) -#include <runtime/JSLock.h> -#endif - #include <wtf/ASCIICType.h> // #include "runtime.h" #include "WebViewCore.h" @@ -484,9 +480,6 @@ void PluginView::setNPWindowIfNeeded() m_npWindow.clipRect.bottom = m_pageRect.y() + m_pageRect.height(); if (m_plugin->pluginFuncs()->setwindow) { -#if USE(JSC) - JSC::JSLock::DropAllLocks dropAllLocks(false); -#endif setCallingPlugin(true); m_plugin->pluginFuncs()->setwindow(m_instance, &m_npWindow); setCallingPlugin(false); diff --git a/Source/WebCore/rendering/InlineTextBox.cpp b/Source/WebCore/rendering/InlineTextBox.cpp index 5815b8b..d5eeeae 100644 --- a/Source/WebCore/rendering/InlineTextBox.cpp +++ b/Source/WebCore/rendering/InlineTextBox.cpp @@ -43,6 +43,7 @@ #include "Text.h" #include "break_lines.h" #include <wtf/AlwaysInline.h> +#include <wtf/text/CString.h> using namespace std; @@ -1069,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/RenderArena.cpp b/Source/WebCore/rendering/RenderArena.cpp index 57ed978..e15101f 100644 --- a/Source/WebCore/rendering/RenderArena.cpp +++ b/Source/WebCore/rendering/RenderArena.cpp @@ -136,11 +136,4 @@ void RenderArena::free(size_t size, void* ptr) #endif } -#ifdef ANDROID_INSTRUMENT -size_t RenderArena::reportPoolSize() const -{ - return ReportPoolSize(&m_pool); -} -#endif - } // namespace WebCore diff --git a/Source/WebCore/rendering/RenderArena.h b/Source/WebCore/rendering/RenderArena.h index 5d2559a..e1ff535 100644 --- a/Source/WebCore/rendering/RenderArena.h +++ b/Source/WebCore/rendering/RenderArena.h @@ -53,10 +53,6 @@ public: void* allocate(size_t); void free(size_t, void*); -#ifdef ANDROID_INSTRUMENT - size_t reportPoolSize() const; -#endif - private: // Underlying arena pool ArenaPool m_pool; 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/WebCore/rendering/RenderHTMLCanvas.cpp b/Source/WebCore/rendering/RenderHTMLCanvas.cpp index de2a2c1..03b406b 100644 --- a/Source/WebCore/rendering/RenderHTMLCanvas.cpp +++ b/Source/WebCore/rendering/RenderHTMLCanvas.cpp @@ -47,6 +47,13 @@ RenderHTMLCanvas::RenderHTMLCanvas(HTMLCanvasElement* element) bool RenderHTMLCanvas::requiresLayer() const { +#if PLATFORM(ANDROID) + // All Canvas are drawn on their own composited layer + // This improves performances a lot (as this simplify + // the repaint/inval chain dealing with the PictureSet) + return true; +#endif + if (RenderReplaced::requiresLayer()) return true; diff --git a/Source/WebCore/rendering/RenderLayer.cpp b/Source/WebCore/rendering/RenderLayer.cpp index cdc4c05..66aab18 100644 --- a/Source/WebCore/rendering/RenderLayer.cpp +++ b/Source/WebCore/rendering/RenderLayer.cpp @@ -64,6 +64,7 @@ #include "HTMLNames.h" #if ENABLE(ANDROID_OVERFLOW_SCROLL) #include "HTMLTextAreaElement.h" +#include "GraphicsLayerAndroid.h" #endif #include "HitTestRequest.h" #include "HitTestResult.h" @@ -1389,11 +1390,27 @@ void RenderLayer::scrollTo(int x, int y) view->updateWidgetPositions(); } +#if PLATFORM(ANDROID) + GraphicsLayerAndroid* backingLayer = 0; + bool scrollableContent = false; +#endif + #if USE(ACCELERATED_COMPOSITING) if (compositor()->inCompositingMode()) { // Our stacking context is guaranteed to contain all of our descendants that may need // repositioning, so update compositing layers from there. +#if ENABLE(ANDROID_OVERFLOW_SCROLL) + if (view && backing() && backing()->graphicsLayer()) { + backingLayer = static_cast<GraphicsLayerAndroid*>(backing()->graphicsLayer()); + scrollableContent = backingLayer->contentLayer() + && backingLayer->contentLayer()->contentIsScrollable(); + } + // If we have a scrollable content, no need to do this + RenderLayer* compositingAncestor = enclosingCompositingLayer(); + if (!scrollableContent && compositingAncestor) { +#else if (RenderLayer* compositingAncestor = stackingContext()->enclosingCompositingLayer()) { +#endif if (compositor()->compositingConsultsOverlap()) compositor()->updateCompositingLayers(CompositingUpdateOnScroll, compositingAncestor); else { @@ -1422,8 +1439,10 @@ void RenderLayer::scrollTo(int x, int y) #if ENABLE(ANDROID_OVERFLOW_SCROLL) // On android, scrollable areas are put on composited layers, so we // do not need to repaint simply because we are scrolling - if (view && !hasOverflowScroll()) + if (view && !(hasOverflowScroll() || scrollableContent)) renderer()->repaintUsingContainer(repaintContainer, rectForRepaint); + if (backingLayer && (hasOverflowScroll() || scrollableContent)) + backingLayer->updateScrollOffset(); #else if (view) renderer()->repaintUsingContainer(repaintContainer, rectForRepaint); diff --git a/Source/WebCore/rendering/RenderLayerCompositor.cpp b/Source/WebCore/rendering/RenderLayerCompositor.cpp index 33bf2f7..25a08e7 100644 --- a/Source/WebCore/rendering/RenderLayerCompositor.cpp +++ b/Source/WebCore/rendering/RenderLayerCompositor.cpp @@ -92,6 +92,10 @@ struct CompositingState { RenderLayer* m_compositingAncestor; bool m_subtreeIsCompositing; + // m_compositingBounds is only used in computeCompositingRequirements. It can be either the + // ancestor bounds or the bounds for the sibling layers which are above the composited layer. + // It is used to reject creating unnecesary layers. + IntRect m_compositingBounds; #if ENABLE(COMPOSITED_FIXED_ELEMENTS) bool m_fixedSibling; bool m_hasFixedElement; @@ -693,7 +697,10 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, O if (absBounds.isEmpty()) absBounds.setSize(IntSize(1, 1)); haveComputedBounds = true; - mustOverlapCompositedLayers = overlapsCompositedLayers(*overlapMap, absBounds); + // If the current subtree is not compositing, and the layer is fully inside the current compositing bounnds, + // there is no need to do the overlap test. This reduces the total number of the composited layers. + if (compositingState.m_subtreeIsCompositing || !compositingState.m_compositingBounds.contains(absBounds)) + mustOverlapCompositedLayers = overlapsCompositedLayers(*overlapMap, absBounds); } #if ENABLE(COMPOSITED_FIXED_ELEMENTS) @@ -709,6 +716,10 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, O // a compositing layer among them, so start by inheriting the compositing // ancestor with m_subtreeIsCompositing set to false. CompositingState childState(compositingState.m_compositingAncestor); + if (compositingState.m_subtreeIsCompositing) + childState.m_compositingBounds = absBounds; + else + childState.m_compositingBounds = compositingState.m_compositingBounds; #ifndef NDEBUG ++childState.m_depth; #endif @@ -729,6 +740,7 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, O compositingState.m_subtreeIsCompositing = true; // This layer now acts as the ancestor for kids. childState.m_compositingAncestor = layer; + childState.m_compositingBounds = absBounds; if (overlapMap) addToOverlapMap(*overlapMap, layer, absBounds, haveComputedBounds); } @@ -1398,6 +1410,10 @@ bool RenderLayerCompositor::requiresCompositingForAndroidLayers(const RenderLaye if (layer->isFixed()) return true; #endif + + if (layer->renderer()->isCanvas()) + return true; + return false; } #endif diff --git a/Source/WebCore/rendering/RenderText.cpp b/Source/WebCore/rendering/RenderText.cpp index b35820a..6f4d3b7 100644 --- a/Source/WebCore/rendering/RenderText.cpp +++ b/Source/WebCore/rendering/RenderText.cpp @@ -37,6 +37,7 @@ #include "RenderCombineText.h" #include "RenderLayer.h" #include "RenderView.h" +#include "Settings.h" #include "Text.h" #include "TextBreakIterator.h" #include "TextResourceDecoder.h" @@ -53,6 +54,37 @@ using namespace Unicode; namespace WebCore { +class SecureTextTimer; +typedef HashMap<RenderText*, SecureTextTimer*> SecureTextTimerMap; +static SecureTextTimerMap* gSecureTextTimers = 0; + +class SecureTextTimer : public TimerBase { +public: + SecureTextTimer(RenderText* renderText) + : m_renderText(renderText) + , m_lastTypedCharacterOffset(-1) + { + } + + void restartWithNewText(unsigned lastTypedCharacterOffset) + { + m_lastTypedCharacterOffset = lastTypedCharacterOffset; + startOneShot(m_renderText->document()->settings()->passwordEchoDurationInSeconds()); + } + void invalidate() { m_lastTypedCharacterOffset = -1; } + unsigned lastTypedCharacterOffset() { return m_lastTypedCharacterOffset; } + +private: + virtual void fired() + { + ASSERT(gSecureTextTimers->contains(m_renderText)); + m_renderText->setText(m_renderText->text(), true /* forcing setting text as it may be masked later */); + } + + RenderText* m_renderText; + int m_lastTypedCharacterOffset; +}; + static void makeCapitalized(String* string, UChar previous) { if (string->isNull()) @@ -196,6 +228,9 @@ void RenderText::removeAndDestroyTextBoxes() void RenderText::destroy() { + if (SecureTextTimer* secureTextTimer = gSecureTextTimers ? gSecureTextTimers->take(this) : 0) + delete secureTextTimer; + removeAndDestroyTextBoxes(); RenderObject::destroy(); } @@ -1140,13 +1175,13 @@ void RenderText::setTextInternal(PassRefPtr<StringImpl> text) case TSNONE: break; case TSCIRCLE: - m_text.makeSecure(whiteBullet); + secureText(whiteBullet); break; case TSDISC: - m_text.makeSecure(bullet); + secureText(bullet); break; case TSSQUARE: - m_text.makeSecure(blackSquare); + secureText(blackSquare); } } @@ -1156,6 +1191,28 @@ void RenderText::setTextInternal(PassRefPtr<StringImpl> text) m_isAllASCII = m_text.containsOnlyASCII(); } +void RenderText::secureText(UChar mask) +{ + if (!m_text.length()) + return; + + int lastTypedCharacterOffsetToReveal = -1; + String revealedText; + SecureTextTimer* secureTextTimer = gSecureTextTimers ? gSecureTextTimers->get(this) : 0; + if (secureTextTimer && secureTextTimer->isActive()) { + lastTypedCharacterOffsetToReveal = secureTextTimer->lastTypedCharacterOffset(); + if (lastTypedCharacterOffsetToReveal >= 0) + revealedText.append(m_text[lastTypedCharacterOffsetToReveal]); + } + + m_text.makeSecure(mask); + if (lastTypedCharacterOffsetToReveal >= 0) { + m_text.replace(lastTypedCharacterOffsetToReveal, 1, revealedText); + // m_text may be updated later before timer fires. We invalidate the lastTypedCharacterOffset to avoid inconsistency. + secureTextTimer->invalidate(); + } +} + void RenderText::setText(PassRefPtr<StringImpl> text, bool force) { ASSERT(text); @@ -1590,4 +1647,17 @@ void RenderText::checkConsistency() const #endif +void RenderText::momentarilyRevealLastTypedCharacter(unsigned lastTypedCharacterOffset) +{ + if (!gSecureTextTimers) + gSecureTextTimers = new SecureTextTimerMap; + + SecureTextTimer* secureTextTimer = gSecureTextTimers->get(this); + if (!secureTextTimer) { + secureTextTimer = new SecureTextTimer(this); + gSecureTextTimers->add(this, secureTextTimer); + } + secureTextTimer->restartWithNewText(lastTypedCharacterOffset); +} + } // namespace WebCore diff --git a/Source/WebCore/rendering/RenderText.h b/Source/WebCore/rendering/RenderText.h index 2008dad..f89a762 100644 --- a/Source/WebCore/rendering/RenderText.h +++ b/Source/WebCore/rendering/RenderText.h @@ -117,6 +117,9 @@ public: bool containsReversedText() const { return m_containsReversedText; } + bool isSecure() const { return style()->textSecurity() != TSNONE; } + void momentarilyRevealLastTypedCharacter(unsigned lastTypedCharacterOffset); + InlineTextBox* findNextInlineTextBox(int offset, int& pos) const; bool allowTabs() const { return !style()->collapseWhiteSpace(); } @@ -158,6 +161,7 @@ private: void updateNeedsTranscoding(); inline void transformText(String&) const; + void secureText(UChar mask); float m_minWidth; // here to minimize padding in 64-bit. diff --git a/Source/WebCore/rendering/style/RenderStyle.h b/Source/WebCore/rendering/style/RenderStyle.h index fad5a7b..ea01064 100644 --- a/Source/WebCore/rendering/style/RenderStyle.h +++ b/Source/WebCore/rendering/style/RenderStyle.h @@ -786,19 +786,6 @@ public: ESpeak speak() { return static_cast<ESpeak>(rareInheritedData->speak); } -#ifdef ANDROID_CSS_RING - // called when building nav cache to determine if the ring data is unchanged - const void* ringData() const { return reinterpret_cast<const void*>(rareInheritedData.get()); } - Color ringFillColor() const { return rareInheritedData->ringFillColor; } - Length ringInnerWidth() const { return rareInheritedData->ringInnerWidth; } - Length ringOuterWidth() const { return rareInheritedData->ringOuterWidth; } - Length ringOutset() const { return rareInheritedData->ringOutset; } - Color ringPressedInnerColor() const { return rareInheritedData->ringPressedInnerColor; } - Color ringPressedOuterColor() const { return rareInheritedData->ringPressedOuterColor; } - Length ringRadius() const { return rareInheritedData->ringRadius; } - Color ringSelectedInnerColor() const { return rareInheritedData->ringSelectedInnerColor; } - Color ringSelectedOuterColor() const { return rareInheritedData->ringSelectedOuterColor; } -#endif #ifdef ANDROID_CSS_TAP_HIGHLIGHT_COLOR Color tapHighlightColor() const { return rareInheritedData->tapHighlightColor; } #endif @@ -1142,21 +1129,6 @@ public: void setTextSizeAdjust(bool b) { SET_VAR(rareInheritedData, textSizeAdjust, b); } void setTextSecurity(ETextSecurity aTextSecurity) { SET_VAR(rareInheritedData, textSecurity, aTextSecurity); } -#ifdef ANDROID_CSS_RING - void setRingFillColor(const Color& v) { SET_VAR(rareInheritedData, ringFillColor, v); } - void setRingInnerWidth(Length v) { SET_VAR(rareInheritedData, ringInnerWidth, v); } - void setRingOuterWidth(Length v) { SET_VAR(rareInheritedData, ringOuterWidth, v); } - void setRingOutset(Length v) { SET_VAR(rareInheritedData, ringOutset, v); } - void setRingPressedInnerColor(const Color& v) { - SET_VAR(rareInheritedData, ringPressedInnerColor, v); } - void setRingPressedOuterColor(const Color& v) { - SET_VAR(rareInheritedData, ringPressedOuterColor, v); } - void setRingRadius(Length v) { SET_VAR(rareInheritedData, ringRadius, v); } - void setRingSelectedInnerColor(const Color& v) { - SET_VAR(rareInheritedData, ringSelectedInnerColor, v); } - void setRingSelectedOuterColor(const Color& v) { - SET_VAR(rareInheritedData, ringSelectedOuterColor, v); } -#endif #ifdef ANDROID_CSS_TAP_HIGHLIGHT_COLOR void setTapHighlightColor(const Color& v) { SET_VAR(rareInheritedData, tapHighlightColor, v); } #endif @@ -1359,17 +1331,6 @@ public: static const Vector<StyleDashboardRegion>& noneDashboardRegions(); #endif -#ifdef ANDROID_CSS_RING - static Color initialRingFillColor() { return Color::ringFill; } - static Length initialRingInnerWidth() { return Length(16, Fixed); } // 1.0 - static Length initialRingOuterWidth() { return Length(40, Fixed); } // 2.5 - static Length initialRingOutset() { return Length(3, Fixed); } - static Color initialRingSelectedInnerColor() { return Color::ringSelectedInner; } - static Color initialRingSelectedOuterColor() { return Color::ringSelectedOuter; } - static Color initialRingPressedInnerColor() { return Color::ringPressedInner; } - static Color initialRingPressedOuterColor() { return Color::ringPressedOuter; } - static Length initialRingRadius() { return Length(1, Fixed); } -#endif #ifdef ANDROID_CSS_TAP_HIGHLIGHT_COLOR static Color initialTapHighlightColor() { return Color::tap; } #endif diff --git a/Source/WebCore/rendering/style/StyleRareInheritedData.cpp b/Source/WebCore/rendering/style/StyleRareInheritedData.cpp index 2253d1c..a7acc4a 100644 --- a/Source/WebCore/rendering/style/StyleRareInheritedData.cpp +++ b/Source/WebCore/rendering/style/StyleRareInheritedData.cpp @@ -32,17 +32,6 @@ namespace WebCore { StyleRareInheritedData::StyleRareInheritedData() : textStrokeWidth(RenderStyle::initialTextStrokeWidth()) -#ifdef ANDROID_CSS_RING - , ringFillColor(RenderStyle::initialRingFillColor()) - , ringInnerWidth(RenderStyle::initialRingInnerWidth()) - , ringOuterWidth(RenderStyle::initialRingOuterWidth()) - , ringOutset(RenderStyle::initialRingOutset()) - , ringPressedInnerColor(RenderStyle::initialRingPressedInnerColor()) - , ringPressedOuterColor(RenderStyle::initialRingPressedOuterColor()) - , ringRadius(RenderStyle::initialRingRadius()) - , ringSelectedInnerColor(RenderStyle::initialRingSelectedInnerColor()) - , ringSelectedOuterColor(RenderStyle::initialRingSelectedOuterColor()) -#endif #ifdef ANDROID_CSS_TAP_HIGHLIGHT_COLOR , tapHighlightColor(RenderStyle::initialTapHighlightColor()) #endif @@ -77,18 +66,6 @@ StyleRareInheritedData::StyleRareInheritedData(const StyleRareInheritedData& o) , textStrokeColor(o.textStrokeColor) , textStrokeWidth(o.textStrokeWidth) , textFillColor(o.textFillColor) - , textEmphasisColor(o.textEmphasisColor) -#ifdef ANDROID_CSS_RING - , ringFillColor(o.ringFillColor) - , ringInnerWidth(o.ringInnerWidth) - , ringOuterWidth(o.ringOuterWidth) - , ringOutset(o.ringOutset) - , ringPressedInnerColor(o.ringPressedInnerColor) - , ringPressedOuterColor(o.ringPressedOuterColor) - , ringRadius(o.ringRadius) - , ringSelectedInnerColor(o.ringSelectedInnerColor) - , ringSelectedOuterColor(o.ringSelectedOuterColor) -#endif #ifdef ANDROID_CSS_TAP_HIGHLIGHT_COLOR , tapHighlightColor(o.tapHighlightColor) #endif @@ -157,17 +134,6 @@ bool StyleRareInheritedData::operator==(const StyleRareInheritedData& o) const && nbspMode == o.nbspMode && khtmlLineBreak == o.khtmlLineBreak && textSizeAdjust == o.textSizeAdjust -#ifdef ANDROID_CSS_RING - && ringFillColor == o.ringFillColor - && ringInnerWidth == o.ringInnerWidth - && ringOuterWidth == o.ringOuterWidth - && ringOutset == o.ringOutset - && ringPressedInnerColor == o.ringPressedInnerColor - && ringPressedOuterColor == o.ringPressedOuterColor - && ringRadius == o.ringRadius - && ringSelectedInnerColor == o.ringSelectedInnerColor - && ringSelectedOuterColor == o.ringSelectedOuterColor -#endif #ifdef ANDROID_CSS_TAP_HIGHLIGHT_COLOR && tapHighlightColor == o.tapHighlightColor #endif diff --git a/Source/WebCore/rendering/style/StyleRareInheritedData.h b/Source/WebCore/rendering/style/StyleRareInheritedData.h index 39cfe3c..16fcc5f 100644 --- a/Source/WebCore/rendering/style/StyleRareInheritedData.h +++ b/Source/WebCore/rendering/style/StyleRareInheritedData.h @@ -58,17 +58,6 @@ public: Color textFillColor; Color textEmphasisColor; -#ifdef ANDROID_CSS_RING - Color ringFillColor; - Length ringInnerWidth; - Length ringOuterWidth; - Length ringOutset; - Color ringPressedInnerColor; - Color ringPressedOuterColor; - Length ringRadius; - Color ringSelectedInnerColor; - Color ringSelectedOuterColor; -#endif #ifdef ANDROID_CSS_TAP_HIGHLIGHT_COLOR Color tapHighlightColor; #endif diff --git a/Source/WebCore/storage/AbstractDatabase.h b/Source/WebCore/storage/AbstractDatabase.h index 9279adc..e0a277f 100644 --- a/Source/WebCore/storage/AbstractDatabase.h +++ b/Source/WebCore/storage/AbstractDatabase.h @@ -36,7 +36,7 @@ #include "SQLiteDatabase.h" #include <wtf/Forward.h> #include <wtf/ThreadSafeRefCounted.h> -#ifndef NDEBUG +#if !LOG_DISABLED || !ERROR_DISABLED #include "SecurityOrigin.h" #endif @@ -109,7 +109,7 @@ protected: unsigned long m_estimatedSize; String m_filename; -#ifndef NDEBUG +#if !LOG_DISABLED || !ERROR_DISABLED String databaseDebugName() const { return m_contextThreadSecurityOrigin->toString() + "::" + m_name; } #endif diff --git a/Source/WebCore/storage/DatabaseTask.cpp b/Source/WebCore/storage/DatabaseTask.cpp index 343ae1e..ad744e5 100644 --- a/Source/WebCore/storage/DatabaseTask.cpp +++ b/Source/WebCore/storage/DatabaseTask.cpp @@ -62,7 +62,7 @@ void DatabaseTaskSynchronizer::taskCompleted() DatabaseTask::DatabaseTask(Database* database, DatabaseTaskSynchronizer* synchronizer) : m_database(database) , m_synchronizer(synchronizer) -#ifndef NDEBUG +#if !LOG_DISABLED , m_complete(false) #endif { @@ -70,13 +70,17 @@ DatabaseTask::DatabaseTask(Database* database, DatabaseTaskSynchronizer* synchro DatabaseTask::~DatabaseTask() { +#if !LOG_DISABLED ASSERT(m_complete || !m_synchronizer); +#endif } void DatabaseTask::performTask() { // Database tasks are meant to be used only once, so make sure this one hasn't been performed before. +#if !LOG_DISABLED ASSERT(!m_complete); +#endif LOG(StorageAPI, "Performing %s %p\n", debugTaskName(), this); @@ -86,7 +90,7 @@ void DatabaseTask::performTask() if (m_synchronizer) m_synchronizer->taskCompleted(); -#ifndef NDEBUG +#if !LOG_DISABLED m_complete = true; #endif } @@ -108,7 +112,7 @@ void Database::DatabaseOpenTask::doPerformTask() m_success = database()->performOpenAndVerify(m_setVersionInNewDatabase, m_code); } -#ifndef NDEBUG +#if !LOG_DISABLED const char* Database::DatabaseOpenTask::debugTaskName() const { return "DatabaseOpenTask"; @@ -128,7 +132,7 @@ void Database::DatabaseCloseTask::doPerformTask() database()->close(); } -#ifndef NDEBUG +#if !LOG_DISABLED const char* Database::DatabaseCloseTask::debugTaskName() const { return "DatabaseCloseTask"; @@ -150,7 +154,7 @@ void Database::DatabaseTransactionTask::doPerformTask() m_transaction->database()->inProgressTransactionCompleted(); } -#ifndef NDEBUG +#if !LOG_DISABLED const char* Database::DatabaseTransactionTask::debugTaskName() const { return "DatabaseTransactionTask"; @@ -172,7 +176,7 @@ void Database::DatabaseTableNamesTask::doPerformTask() m_tableNames = database()->performGetTableNames(); } -#ifndef NDEBUG +#if !LOG_DISABLED const char* Database::DatabaseTableNamesTask::debugTaskName() const { return "DatabaseTableNamesTask"; diff --git a/Source/WebCore/storage/DatabaseTask.h b/Source/WebCore/storage/DatabaseTask.h index e1df591..faadc69 100644 --- a/Source/WebCore/storage/DatabaseTask.h +++ b/Source/WebCore/storage/DatabaseTask.h @@ -90,7 +90,7 @@ private: Database* m_database; DatabaseTaskSynchronizer* m_synchronizer; -#ifndef NDEBUG +#if !LOG_DISABLED virtual const char* debugTaskName() const = 0; bool m_complete; #endif @@ -107,7 +107,7 @@ private: DatabaseOpenTask(Database*, bool setVersionInNewDatabase, DatabaseTaskSynchronizer*, ExceptionCode&, bool& success); virtual void doPerformTask(); -#ifndef NDEBUG +#if !LOG_DISABLED virtual const char* debugTaskName() const; #endif @@ -127,7 +127,7 @@ private: DatabaseCloseTask(Database*, DatabaseTaskSynchronizer*); virtual void doPerformTask(); -#ifndef NDEBUG +#if !LOG_DISABLED virtual const char* debugTaskName() const; #endif }; @@ -146,7 +146,7 @@ private: DatabaseTransactionTask(PassRefPtr<SQLTransaction>); virtual void doPerformTask(); -#ifndef NDEBUG +#if !LOG_DISABLED virtual const char* debugTaskName() const; #endif @@ -164,7 +164,7 @@ private: DatabaseTableNamesTask(Database*, DatabaseTaskSynchronizer*, Vector<String>& names); virtual void doPerformTask(); -#ifndef NDEBUG +#if !LOG_DISABLED virtual const char* debugTaskName() const; #endif diff --git a/Source/WebCore/storage/SQLTransaction.cpp b/Source/WebCore/storage/SQLTransaction.cpp index dfcd568..0b1ad25 100644 --- a/Source/WebCore/storage/SQLTransaction.cpp +++ b/Source/WebCore/storage/SQLTransaction.cpp @@ -117,7 +117,7 @@ void SQLTransaction::enqueueStatement(PassRefPtr<SQLStatement> statement) m_statementQueue.append(statement); } -#ifndef NDEBUG +#if !LOG_DISABLED const char* SQLTransaction::debugStepName(SQLTransaction::TransactionStepMethod step) { if (step == &SQLTransaction::acquireLock) diff --git a/Source/WebCore/storage/SQLTransaction.h b/Source/WebCore/storage/SQLTransaction.h index 4c84f91..a0a83ed 100644 --- a/Source/WebCore/storage/SQLTransaction.h +++ b/Source/WebCore/storage/SQLTransaction.h @@ -105,7 +105,7 @@ private: void deliverTransactionErrorCallback(); void cleanupAfterTransactionErrorCallback(); -#ifndef NDEBUG +#if !LOG_DISABLED static const char* debugStepName(TransactionStepMethod); #endif diff --git a/Source/WebCore/svg/SVGFontFaceUriElement.h b/Source/WebCore/svg/SVGFontFaceUriElement.h index ad9ba97..3806315 100644 --- a/Source/WebCore/svg/SVGFontFaceUriElement.h +++ b/Source/WebCore/svg/SVGFontFaceUriElement.h @@ -45,22 +45,6 @@ private: virtual void childrenChanged(bool changedByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0); virtual void insertedIntoDocument(); -#ifdef ANDROID_INSTRUMENT - void* operator new(size_t size) { - return SVGElement::operator new(size); - } - void* operator new[](size_t size) { - return SVGElement::operator new[](size); - } - - void operator delete(void* p, size_t size) { - SVGElement::operator delete(p, size); - } - void operator delete[](void* p, size_t size) { - SVGElement::operator delete[](p, size); - } -#endif - void loadFont(); CachedResourceHandle<CachedFont> m_cachedFont; diff --git a/Source/WebCore/workers/WorkerContext.idl b/Source/WebCore/workers/WorkerContext.idl index e31f5ad..5a6c407 100644 --- a/Source/WebCore/workers/WorkerContext.idl +++ b/Source/WebCore/workers/WorkerContext.idl @@ -126,6 +126,7 @@ module threads { attribute Int32ArrayConstructor Int32Array; // Usable with new operator attribute Uint32ArrayConstructor Uint32Array; // Usable with new operator attribute Float32ArrayConstructor Float32Array; // Usable with new operator + attribute Float64ArrayConstructor Float64Array; // Usable with new operator }; } diff --git a/Source/WebCore/xml/XSLImportRule.h b/Source/WebCore/xml/XSLImportRule.h index 3c5939d..5c0ca8a 100644 --- a/Source/WebCore/xml/XSLImportRule.h +++ b/Source/WebCore/xml/XSLImportRule.h @@ -52,22 +52,6 @@ public: bool isLoading(); void loadSheet(); -#ifdef ANDROID_INSTRUMENT - void* operator new(size_t size) { - return StyleBase::operator new(size); - } - void* operator new[](size_t size) { - return StyleBase::operator new[](size); - } - - void operator delete(void* p, size_t size) { - StyleBase::operator delete(p, size); - } - void operator delete[](void* p, size_t size) { - StyleBase::operator delete[](p, size); - } -#endif - private: XSLImportRule(XSLStyleSheet* parentSheet, const String& href); diff --git a/Source/WebKit/Android.mk b/Source/WebKit/Android.mk index bbe212c..67da200 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,12 +33,6 @@ LOCAL_SRC_FILES := \ android/WebCoreSupport/PlatformBridge.cpp \ android/WebCoreSupport/ResourceLoaderAndroid.cpp \ android/WebCoreSupport/UrlInterceptResponse.cpp \ - android/WebCoreSupport/V8Counters.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 \ @@ -46,22 +42,19 @@ 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 \ - android/RenderSkinButton.cpp \ - android/RenderSkinCombo.cpp \ android/RenderSkinMediaButton.cpp \ android/RenderSkinNinePatch.cpp \ - android/RenderSkinRadio.cpp \ - android/TimeCounter.cpp \ - \ - android/benchmark/Intercept.cpp \ - android/benchmark/MyJavaVM.cpp \ \ 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 \ android/jni/DeviceMotionAndOrientationManager.cpp \ @@ -70,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 \ @@ -85,15 +76,7 @@ LOCAL_SRC_FILES += \ android/jni/WebViewCore.cpp \ android/jni/ViewStateSerializer.cpp \ \ - android/nav/CacheBuilder.cpp \ - android/nav/CachedColor.cpp \ - android/nav/CachedFrame.cpp \ - android/nav/CachedHistory.cpp \ - android/nav/CachedInput.cpp \ - android/nav/CachedLayer.cpp \ - android/nav/CachedNode.cpp \ - android/nav/CachedRoot.cpp \ - android/nav/FindCanvas.cpp \ + android/nav/DrawExtra.cpp \ android/nav/SelectText.cpp \ android/nav/WebView.cpp \ \ diff --git a/Source/WebKit/android/AndroidLog.h b/Source/WebKit/android/AndroidLog.h index 3d3eaaa..4090ab9 100644 --- a/Source/WebKit/android/AndroidLog.h +++ b/Source/WebKit/android/AndroidLog.h @@ -27,16 +27,17 @@ #define AndroidLog_h #ifdef ANDROID_DOM_LOGGING +#include <utils/Log.h> #include <stdio.h> extern FILE* gDomTreeFile; #define DOM_TREE_LOG_FILE "/sdcard/domTree.txt" #define DUMP_DOM_LOGD(...) { if (gDomTreeFile) \ - fprintf(gDomTreeFile, __VA_ARGS__); else LOGD(__VA_ARGS__); } + fprintf(gDomTreeFile, __VA_ARGS__); else ALOGD(__VA_ARGS__); } extern FILE* gRenderTreeFile; #define RENDER_TREE_LOG_FILE "/sdcard/renderTree.txt" #define DUMP_RENDER_LOGD(...) { if (gRenderTreeFile) \ - fprintf(gRenderTreeFile, __VA_ARGS__); else LOGD(__VA_ARGS__); } + fprintf(gRenderTreeFile, __VA_ARGS__); else ALOGD(__VA_ARGS__); } #else #define DUMP_DOM_LOGD(...) ((void)0) #define DUMP_RENDER_LOGD(...) ((void)0) diff --git a/Source/WebKit/android/RenderSkinAndroid.cpp b/Source/WebKit/android/RenderSkinAndroid.cpp index 4a9ce68..9529624 100644 --- a/Source/WebKit/android/RenderSkinAndroid.cpp +++ b/Source/WebKit/android/RenderSkinAndroid.cpp @@ -27,14 +27,11 @@ #include "config.h" #include "RenderSkinAndroid.h" -#include "RenderSkinButton.h" -#include "RenderSkinCombo.h" #include "RenderSkinMediaButton.h" -#include "RenderSkinRadio.h" #include "SkImageDecoder.h" -#include <utils/AssetManager.h> -#include <utils/Asset.h> +#include <androidfw/AssetManager.h> +#include <androidfw/Asset.h> namespace WebCore { @@ -43,7 +40,6 @@ RenderSkinAndroid::Resolution RenderSkinAndroid::s_drawableResolution = RenderSk RenderSkinAndroid::~RenderSkinAndroid() { - delete m_button; } RenderSkinAndroid::RenderSkinAndroid(String drawableDirectory) { @@ -56,7 +52,6 @@ RenderSkinAndroid::RenderSkinAndroid(String drawableDirectory) s_drawableDirectory = drawableDirectory; } - m_button = new RenderSkinButton(drawableDirectory); } bool RenderSkinAndroid::DecodeBitmap(android::AssetManager* am, const char* fileName, SkBitmap* bitmap) @@ -65,14 +60,14 @@ bool RenderSkinAndroid::DecodeBitmap(android::AssetManager* am, const char* file if (!asset) { asset = am->openNonAsset(fileName, android::Asset::ACCESS_BUFFER); if (!asset) { - LOGD("RenderSkinAndroid: File \"%s\" not found.\n", fileName); + ALOGD("RenderSkinAndroid: File \"%s\" not found.\n", fileName); return false; } } bool success = SkImageDecoder::DecodeMemory(asset->getBuffer(false), asset->getLength(), bitmap); if (!success) { - LOGD("RenderSkinAndroid: Failed to decode %s\n", fileName); + ALOGD("RenderSkinAndroid: Failed to decode %s\n", fileName); } delete asset; diff --git a/Source/WebKit/android/RenderSkinAndroid.h b/Source/WebKit/android/RenderSkinAndroid.h index bbc327d..1d3820d 100644 --- a/Source/WebKit/android/RenderSkinAndroid.h +++ b/Source/WebKit/android/RenderSkinAndroid.h @@ -36,7 +36,6 @@ class SkBitmap; namespace WebCore { class Node; -class RenderSkinButton; class RenderSkinAndroid { @@ -69,12 +68,9 @@ public: static String DrawableDirectory() { return s_drawableDirectory; } static Resolution DrawableResolution() { return s_drawableResolution; } - RenderSkinButton* renderSkinButton() const { return m_button; } - private: static String s_drawableDirectory; static Resolution s_drawableResolution; - RenderSkinButton* m_button; }; } // WebCore diff --git a/Source/WebKit/android/RenderSkinButton.cpp b/Source/WebKit/android/RenderSkinButton.cpp deleted file mode 100644 index 11e2fa8..0000000 --- a/Source/WebKit/android/RenderSkinButton.cpp +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2006, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#define LOG_TAG "WebCore" - -#include "config.h" -#include "android_graphics.h" -#include "Document.h" -#include "IntRect.h" -#include "Node.h" -#include "RenderSkinButton.h" -#include "RenderSkinNinePatch.h" -#include "SkCanvas.h" -#include "SkNinePatch.h" -#include "SkRect.h" -#include <utils/Asset.h> -#include <utils/AssetManager.h> -#include <utils/Debug.h> -#include <utils/Log.h> -#include <utils/ResourceTypes.h> -#include <wtf/text/CString.h> - -extern android::AssetManager* globalAssetManager(); - -static const char* gFiles[] = { - "btn_default_disabled_holo.9.png", - "btn_default_normal_holo.9.png", - "btn_default_focused_holo.9.png", - "btn_default_pressed_holo.9.png" - }; - -namespace WebCore { - -RenderSkinButton::RenderSkinButton(String drawableDirectory) - : m_decoded(false) - , m_decodingAttempted(false) - , m_drawableDirectory(drawableDirectory) -{ - // Ensure our enums properly line up with our arrays. - android::CompileTimeAssert<(RenderSkinAndroid::kDisabled == 0)> a1; - android::CompileTimeAssert<(RenderSkinAndroid::kNormal == 1)> a2; - android::CompileTimeAssert<(RenderSkinAndroid::kFocused == 2)> a3; - android::CompileTimeAssert<(RenderSkinAndroid::kPressed == 3)> a4; -} - -void RenderSkinButton::decode() -{ - m_decodingAttempted = true; - - android::AssetManager* am = globalAssetManager(); - - for (size_t i = 0; i < 4; i++) { - String path = m_drawableDirectory; - path.append(String(gFiles[i])); - if (!RenderSkinNinePatch::decodeAsset(am, path.utf8().data(), &m_buttons[i])) { - m_decoded = false; - LOGE("RenderSkinButton::decode: button assets failed to decode\n\tWebView buttons will not draw"); - return; - } - } - m_decoded = true; -} - -void RenderSkinButton::draw(SkCanvas* canvas, const IntRect& r, - RenderSkinAndroid::State newState) -{ - if (!m_decodingAttempted) - decode(); - - // If we failed to decode, do nothing. This way the browser still works, - // and webkit will still draw the label and layout space for us. - if (!m_decoded) { - return; - } - - // Ensure that the state is within the valid range of our array. - SkASSERT(static_cast<unsigned>(newState) < - static_cast<unsigned>(RenderSkinAndroid::kNumStates)); - - RenderSkinNinePatch::DrawNinePatch(canvas, SkRect(r), m_buttons[newState]); -} - -} //WebCore diff --git a/Source/WebKit/android/RenderSkinButton.h b/Source/WebKit/android/RenderSkinButton.h deleted file mode 100644 index 83c57dd..0000000 --- a/Source/WebKit/android/RenderSkinButton.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2006, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef RenderSkinButton_h -#define RenderSkinButton_h - -#include "RenderSkinAndroid.h" -#include "RenderSkinNinePatch.h" - -class SkCanvas; - -namespace WebCore { -class IntRect; - -class RenderSkinButton { -public: - RenderSkinButton(String drawableDirectory); - /** - * Draw the skin to the canvas, using the rectangle for its bounds and the - * State to determine which skin to use, i.e. focused or not focused. - */ - void draw(SkCanvas* , const IntRect& , RenderSkinAndroid::State); - - void decode(); -private: - bool m_decoded; - bool m_decodingAttempted; - NinePatch m_buttons[4]; - String m_drawableDirectory; -}; - -} // WebCore -#endif diff --git a/Source/WebKit/android/RenderSkinCombo.cpp b/Source/WebKit/android/RenderSkinCombo.cpp deleted file mode 100644 index 1711cfa..0000000 --- a/Source/WebKit/android/RenderSkinCombo.cpp +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Copyright 2006, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "RenderSkinCombo.h" - -#include "Document.h" -#include "Element.h" -#include "Node.h" -#include "NodeRenderStyle.h" -#include "RenderStyle.h" -#include "SkCanvas.h" -#include "SkNinePatch.h" -#include <utils/AssetManager.h> -#include <wtf/text/CString.h> - -extern android::AssetManager* globalAssetManager(); - -namespace WebCore { - -// Indicates if the entire asset is being drawn, or if the border is being -// excluded and just the arrow drawn. -enum BorderStyle { - FullAsset, - NoBorder, - BorderStyleCount // Keep at the end. -}; - -// There are 2.5 different concepts of a 'border' here, which results -// in rather a lot of magic constants. - -// Firstly, we have the extra padding that webkit needs to know about, -// which defines how much bigger this element is made by the -// asset. This is actually a bit broader than the actual border on the -// asset, to make things look less cramped. The border is the same -// width on all sides, except on the right when it's significantly -// wider to allow for the arrow. -const int RenderSkinCombo::arrowMargin[ResolutionCount] = { - 16, // Medium resolution - 25, // High resolution - 34 // Extra high resolution -}; -const int RenderSkinCombo::padMargin[ResolutionCount] = { - 1, // Medium resolution - 1, // High resolution - 1 // Extra high resolution -}; - -namespace { -// Then we have the borders used for the 9-patch stretch. The -// rectangle at the centre of these borders is entirely below and to -// the left of the arrow in the asset. Hence the border widths are the -// same for the bottom and left, but are different for the top. The -// right hand border width happens to be the same as arrowMargin -// defined above. -const int stretchMargin[RenderSkinAndroid::ResolutionCount] = { // border width for the bottom and left of the 9-patch - 2, // Medium resolution - 2, // High resolution - 3 // Extra high resolution - -}; -const int stretchTop[RenderSkinAndroid::ResolutionCount] = { // border width for the top of the 9-patch - 16, // Medium resolution - 23, // High resolution - 32 // Extra high resolution -}; - -// Finally, if the border is defined by the CSS, we only draw the -// arrow and not the border. We do this by drawing the relevant subset -// of the bitmap, which must now be precisely determined by what's in -// the asset with no extra padding to make things look properly -// spaced. The border to remove at the top, right and bottom of the -// image is the same as stretchMargin above, but we need to know the width -// of the arrow. -const int arrowWidth[RenderSkinAndroid::ResolutionCount] = { - 18, // Medium resolution - 27, // High resolution - 36 // Extra high resolution -}; - -// scale factors for various resolutions -const float scaleFactor[RenderSkinAndroid::ResolutionCount] = { - 1.0f, // medium res - 1.5f, // high res - 2.0f // extra high res -}; - -// Store the calculated 9 patch margins for each border style. -SkIRect margin[BorderStyleCount]; - -SkBitmap bitmaps[2][BorderStyleCount]; // Collection of assets for a combo box - 2 states (enabled/disabled) -bool isDecodingAttempted = false; // True if we've tried to decode the assets -bool isDecoded = false; // True if all assets were decoded - -} // namespace - -int RenderSkinCombo::minHeight() { - return SkScalarRound(stretchTop[RenderSkinAndroid::DrawableResolution()] - / scaleFactor[RenderSkinAndroid::DrawableResolution()]); -} - -void RenderSkinCombo::Decode() -{ - if (isDecodingAttempted) - return; - - isDecodingAttempted = true; - isDecoded = false; - - android::AssetManager* am = globalAssetManager(); - - String drawableDirectory = RenderSkinAndroid::DrawableDirectory(); - Resolution res = RenderSkinAndroid::DrawableResolution(); - - isDecoded = RenderSkinAndroid::DecodeBitmap(am, (drawableDirectory + "combobox_nohighlight.png").utf8().data(), &bitmaps[kNormal][FullAsset]); - isDecoded &= RenderSkinAndroid::DecodeBitmap(am, (drawableDirectory + "combobox_disabled.png").utf8().data(), &bitmaps[kDisabled][FullAsset]); - - int width = bitmaps[kNormal][FullAsset].width(); - int height = bitmaps[kNormal][FullAsset].height(); - SkIRect subset; - subset.set(width - arrowWidth[res], 0, width, height); - bitmaps[kNormal][FullAsset].extractSubset(&bitmaps[kNormal][NoBorder], subset); - bitmaps[kDisabled][FullAsset].extractSubset(&bitmaps[kDisabled][NoBorder], subset); - - // Calculate 9 patch margins. - SkIRect fullAssetMargin; - fullAssetMargin.fLeft = stretchMargin[res]; - fullAssetMargin.fTop = stretchMargin[res]; - fullAssetMargin.fRight = arrowMargin[res] + stretchMargin[res]; - fullAssetMargin.fBottom = stretchTop[res]; - - SkIRect noBorderMargin; - noBorderMargin.fLeft = 0; - noBorderMargin.fTop = stretchTop[res]; - noBorderMargin.fRight = 0; - noBorderMargin.fBottom = stretchMargin[res]; - - margin[FullAsset] = fullAssetMargin; - margin[NoBorder] = noBorderMargin; -} - -bool RenderSkinCombo::Draw(SkCanvas* canvas, Node* element, int x, int y, int width, int height) -{ - if (!isDecodingAttempted) - Decode(); - - if (!isDecoded) - return true; - - int resolution = RenderSkinAndroid::DrawableResolution(); - State state = (element->isElementNode() && static_cast<Element*>(element)->isEnabledFormControl()) ? kNormal : kDisabled; - height = std::max(height, (stretchMargin[resolution] * 2)); - - SkRect bounds; - BorderStyle drawBorder = FullAsset; - - bounds.set(SkIntToScalar(x+1), SkIntToScalar(y+1), SkIntToScalar(x + width-1), SkIntToScalar(y + height-1)); - RenderStyle* style = element->renderStyle(); - SkPaint paint; - paint.setColor(style->visitedDependentColor(CSSPropertyBackgroundColor).rgb()); - canvas->drawRect(bounds, paint); - - bounds.set(SkIntToScalar(x), SkIntToScalar(y), SkIntToScalar(x + width), SkIntToScalar(y + height)); - - // If this is an appearance where RenderTheme::paint returns true - // without doing anything, this means that - // RenderBox::PaintBoxDecorationWithSize will end up painting the - // border, so we shouldn't paint a border here. - if (style->appearance() == MenulistButtonPart || - style->appearance() == ListboxPart || - style->appearance() == TextFieldPart || - style->appearance() == TextAreaPart) { - bounds.fLeft += SkIntToScalar(width - RenderSkinCombo::extraWidth()); - bounds.fRight -= SkIntToScalar(style->borderRightWidth()); - bounds.fTop += SkIntToScalar(style->borderTopWidth()); - bounds.fBottom -= SkIntToScalar(style->borderBottomWidth()); - drawBorder = NoBorder; - } - float scale = scaleFactor[resolution]; - bounds.fLeft = bounds.fLeft * scale; - bounds.fRight = bounds.fRight * scale; - bounds.fTop = bounds.fTop * scale; - bounds.fBottom = bounds.fBottom * scale; - int count = canvas->save(); - canvas->scale(1.0f / scale, 1.0f / scale); - SkNinePatch::DrawNine(canvas, bounds, bitmaps[state][drawBorder], margin[drawBorder]); - canvas->restoreToCount(count); - return false; -} - -} // namspace WebCore diff --git a/Source/WebKit/android/RenderSkinCombo.h b/Source/WebKit/android/RenderSkinCombo.h deleted file mode 100644 index a11faac..0000000 --- a/Source/WebKit/android/RenderSkinCombo.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2006, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef RenderSkinCombo_h -#define RenderSkinCombo_h - -#include "RenderSkinAndroid.h" -#include "SkRect.h" - -class SkCanvas; - -namespace WebCore { - -// This is very similar to RenderSkinButton - maybe they should be the same class? -class RenderSkinCombo : public RenderSkinAndroid -{ -public: - - static void Decode(); - /** - * Draw the provided Node on the SkCanvas, using the dimensions provided by - * x,y,w,h. Return true if we did not draw, and WebKit needs to draw it, - * false otherwise. - */ - static bool Draw(SkCanvas* , Node* , int x, int y, int w, int h); - - // The image is wider than the RenderObject, so this accounts for that. - static int extraWidth() { return arrowMargin[RenderSkinAndroid::DrawableResolution()]; } - static int minHeight(); - static int padding() { return padMargin[RenderSkinAndroid::DrawableResolution()]; } - - -private: - const static int arrowMargin[ResolutionCount]; - const static int padMargin[ResolutionCount]; -}; - -} // WebCore - -#endif diff --git a/Source/WebKit/android/RenderSkinMediaButton.cpp b/Source/WebKit/android/RenderSkinMediaButton.cpp index ef4b313..febf575 100644 --- a/Source/WebKit/android/RenderSkinMediaButton.cpp +++ b/Source/WebKit/android/RenderSkinMediaButton.cpp @@ -36,7 +36,7 @@ #include "SkCanvas.h" #include "SkNinePatch.h" #include "SkRect.h" -#include <utils/AssetManager.h> +#include <androidfw/AssetManager.h> #include <utils/Debug.h> #include <utils/Log.h> #include <wtf/text/CString.h> @@ -82,14 +82,14 @@ void RenderSkinMediaButton::Decode() String path = drawableDirectory + gFiles[i].name; if (!RenderSkinAndroid::DecodeBitmap(am, path.utf8().data(), &gButton[i])) { gDecodingFailed = true; - LOGD("RenderSkinButton::Init: button assets failed to decode\n\tBrowser buttons will not draw"); + ALOGD("RenderSkinButton::Init: button assets failed to decode\n\tBrowser buttons will not draw"); break; } } } void RenderSkinMediaButton::Draw(SkCanvas* canvas, const IntRect& r, int buttonType, - bool translucent, RenderObject* o) + bool translucent, RenderObject* o, bool drawBackground) { if (!gDecoded) { Decode(); @@ -102,7 +102,6 @@ void RenderSkinMediaButton::Draw(SkCanvas* canvas, const IntRect& r, int buttonT bool drawsNinePatch = false; bool drawsImage = true; - bool drawsBackgroundColor = true; int ninePatchIndex = 0; int imageIndex = 0; @@ -136,13 +135,11 @@ void RenderSkinMediaButton::Draw(SkCanvas* canvas, const IntRect& r, int buttonT case SPINNER_INNER: case VIDEO: { - drawsBackgroundColor = false; imageIndex = buttonType + 1; break; } case BACKGROUND_SLIDER: { - drawsBackgroundColor = false; drawsImage = false; break; } @@ -155,7 +152,6 @@ void RenderSkinMediaButton::Draw(SkCanvas* canvas, const IntRect& r, int buttonT } case SLIDER_THUMB: { - drawsBackgroundColor = false; imageMargin = 0; imageIndex = buttonType + 1; break; @@ -164,7 +160,7 @@ void RenderSkinMediaButton::Draw(SkCanvas* canvas, const IntRect& r, int buttonT return; } - if (drawsBackgroundColor) { + if (drawBackground) { canvas->drawRect(r, paint); } diff --git a/Source/WebKit/android/RenderSkinMediaButton.h b/Source/WebKit/android/RenderSkinMediaButton.h index d8b7c8d..484b90c 100644 --- a/Source/WebKit/android/RenderSkinMediaButton.h +++ b/Source/WebKit/android/RenderSkinMediaButton.h @@ -42,7 +42,7 @@ public: * State to determine which skin to use, i.e. focused or not focused. */ static void Draw(SkCanvas* , const IntRect& , int buttonType, bool translucent = false, - RenderObject* o = 0); + RenderObject* o = 0, bool drawBackground = true); /** * Button types */ diff --git a/Source/WebKit/android/RenderSkinNinePatch.cpp b/Source/WebKit/android/RenderSkinNinePatch.cpp index faa9dc4..ec748f7 100644 --- a/Source/WebKit/android/RenderSkinNinePatch.cpp +++ b/Source/WebKit/android/RenderSkinNinePatch.cpp @@ -16,18 +16,18 @@ #include "config.h" -#include "RenderSkinNinePatch.h" #include "NinePatchPeeker.h" +#include "RenderSkinNinePatch.h" #include "SkCanvas.h" #include "SkImageDecoder.h" #include "SkNinePatch.h" #include "SkRect.h" #include "SkStream.h" #include "SkTemplates.h" -#include <utils/Asset.h> -#include <utils/AssetManager.h> +#include <androidfw/Asset.h> +#include <androidfw/AssetManager.h> +#include <androidfw/ResourceTypes.h> #include <utils/Log.h> -#include <utils/ResourceTypes.h> class SkPaint; class SkRegion; @@ -53,7 +53,7 @@ bool RenderSkinNinePatch::decodeAsset(AssetManager* am, const char* filename, Ni SkImageDecoder* decoder = SkImageDecoder::Factory(&stream); if (!decoder) { asset->close(); - LOGE("RenderSkinNinePatch::Failed to create an image decoder"); + ALOGE("RenderSkinNinePatch::Failed to create an image decoder"); return false; } @@ -68,13 +68,13 @@ bool RenderSkinNinePatch::decodeAsset(AssetManager* am, const char* filename, Ni decoder->setPeeker(&peeker); if (!decoder->decode(&stream, &ninepatch->m_bitmap, prefConfig, mode, true)) { asset->close(); - LOGE("RenderSkinNinePatch::Failed to decode nine patch asset"); + ALOGE("RenderSkinNinePatch::Failed to decode nine patch asset"); return false; } asset->close(); if (!peeker.fPatchIsValid) { - LOGE("RenderSkinNinePatch::Patch data not valid"); + ALOGE("RenderSkinNinePatch::Patch data not valid"); return false; } void** data = &ninepatch->m_serializedPatchData; diff --git a/Source/WebKit/android/RenderSkinNinePatch.h b/Source/WebKit/android/RenderSkinNinePatch.h index e4db260..8cda795 100644 --- a/Source/WebKit/android/RenderSkinNinePatch.h +++ b/Source/WebKit/android/RenderSkinNinePatch.h @@ -18,7 +18,7 @@ #define RenderSkinNinePatch_h #include "SkBitmap.h" -#include "utils/Asset.h" +#include "androidfw/Asset.h" namespace android { class AssetManager; diff --git a/Source/WebKit/android/RenderSkinRadio.cpp b/Source/WebKit/android/RenderSkinRadio.cpp deleted file mode 100644 index 3c29818..0000000 --- a/Source/WebKit/android/RenderSkinRadio.cpp +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright 2006, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "RenderSkinRadio.h" - -#include "android_graphics.h" -#include "Document.h" -#include "Element.h" -#include "InputElement.h" -#include "IntRect.h" -#include "Node.h" -#include "RenderSkinAndroid.h" -#include "SkBitmap.h" -#include "SkCanvas.h" -#include "SkRect.h" -#include <utils/AssetManager.h> -#include <wtf/text/CString.h> - -extern android::AssetManager* globalAssetManager(); - -static const char* checks[] = { "btn_check_off_holo.png", - "btn_check_on_holo.png", - "btn_radio_off_holo.png", - "btn_radio_on_holo.png"}; -// Matches the width of the bitmap -static SkScalar s_bitmapWidth; - -namespace WebCore { - -static SkBitmap s_bitmap[4]; -static bool s_decodingAttempted = false; -static bool s_decoded = false; - -void RenderSkinRadio::Decode() { - if (s_decodingAttempted) - return; - - s_decodingAttempted = true; - s_decoded = false; - - android::AssetManager* am = globalAssetManager(); - String drawableDir = RenderSkinAndroid::DrawableDirectory(); - for (int i = 0; i < 4; i++) { - String path = drawableDir + checks[i]; - if (!RenderSkinAndroid::DecodeBitmap(am, path.utf8().data(), &s_bitmap[i])) - return; - } - s_decoded = true; - s_bitmapWidth = SkIntToScalar(s_bitmap[0].width()); -} - -void RenderSkinRadio::Draw(SkCanvas* canvas, Node* element, const IntRect& ir, - bool isCheckBox) -{ - if (!element) - return; - - if (!s_decodingAttempted) - Decode(); - - if (!s_decoded) - return; - - SkRect r(ir); - // Set up a paint to with filtering to look better. - SkPaint paint; - paint.setFlags(SkPaint::kFilterBitmap_Flag); - int saveScaleCount = 0; - - if (!element->isElementNode() || - !static_cast<Element*>(element)->isEnabledFormControl()) { - paint.setAlpha(0x80); - } - SkScalar width = r.width(); - SkScalar scale = SkScalarDiv(width, s_bitmapWidth); - saveScaleCount = canvas->save(); - canvas->translate(r.fLeft, r.fTop); - canvas->scale(scale, scale); - - bool checked = false; - if (InputElement* inputElement = element->toInputElement()) { - checked = inputElement->isChecked(); - } - - canvas->drawBitmap(s_bitmap[checked + 2*(!isCheckBox)], - 0, 0, &paint); - canvas->restoreToCount(saveScaleCount); -} - -} //WebCore diff --git a/Source/WebKit/android/TimeCounter.cpp b/Source/WebKit/android/TimeCounter.cpp deleted file mode 100644 index 2393f8a..0000000 --- a/Source/WebKit/android/TimeCounter.cpp +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright 2009, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#define LOG_TAG "WebCore" - -#include "config.h" -#include "TimeCounter.h" - -#include "MemoryCache.h" -#include "KURL.h" -#include "Node.h" -#include "SystemTime.h" -#include "StyleBase.h" -#include <sys/time.h> -#include <time.h> -#include <utils/Log.h> -#include <wtf/CurrentTime.h> -#include <wtf/text/CString.h> - -#if USE(JSC) -#include "JSDOMWindow.h" -#include <runtime/JSGlobalObject.h> -#include <runtime/JSLock.h> -#endif - -using namespace WebCore; -using namespace WTF; -using namespace JSC; - -namespace android { - -uint32_t getThreadMsec() -{ -#if defined(HAVE_POSIX_CLOCKS) - struct timespec tm; - - clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tm); - return tm.tv_sec * 1000LL + tm.tv_nsec / 1000000; -#else - struct timeval now; - struct timezone zone; - - gettimeofday(&now, &zone); - return now.tv_sec * 1000LL + now.tv_usec / 1000; -#endif -} - -#ifdef ANDROID_INSTRUMENT - -static double sStartTotalTime; -static uint32_t sStartThreadTime; -static double sLastTotalTime; -static uint32_t sLastThreadTime; - -uint32_t TimeCounter::sStartWebCoreThreadTime; -uint32_t TimeCounter::sEndWebCoreThreadTime; -bool TimeCounter::sRecordWebCoreTime; -uint32_t TimeCounter::sTotalTimeUsed[TimeCounter::TotalTimeCounterCount]; -uint32_t TimeCounter::sLastTimeUsed[TimeCounter::TotalTimeCounterCount]; -uint32_t TimeCounter::sCounter[TimeCounter::TotalTimeCounterCount]; -uint32_t TimeCounter::sLastCounter[TimeCounter::TotalTimeCounterCount]; -uint32_t TimeCounter::sStartTime[TimeCounter::TotalTimeCounterCount]; - -int QemuTracerAuto::reentry_count = 0; - -static const char* timeCounterNames[] = { - "css parsing", - "javascript", - "javascript init", - "javascript parsing", - "javascript execution", - "calculate style", - "Java callback (frame bridge)", - "parsing (may include calcStyle, Java callback or inline script execution)", - "layout", - "native 1 (frame bridge)", - "native 2 (resource load)", - "native 3 (shared timer)", - "build nav (webview core)", - "record content (webview core)", - "native 4 (webview core)", - "draw content (webview ui)", -}; - -void TimeCounter::record(enum Type type, const char* functionName) -{ - recordNoCounter(type, functionName); - sCounter[type]++; -} - -void TimeCounter::recordNoCounter(enum Type type, const char* functionName) -{ - uint32_t time = sEndWebCoreThreadTime = getThreadMsec(); - uint32_t elapsed = time - sStartTime[type]; - sTotalTimeUsed[type] += elapsed; - if (elapsed > 1000) - LOGW("***** %s() used %d ms\n", functionName, elapsed); -} - -void TimeCounter::report(const KURL& url, int live, int dead, size_t arenaSize) -{ - String urlString = url; - int totalTime = static_cast<int>((currentTime() - sStartTotalTime) * 1000); - int threadTime = getThreadMsec() - sStartThreadTime; - LOGD("*-* Total load time: %d ms, thread time: %d ms for %s\n", - totalTime, threadTime, urlString.utf8().data()); - for (Type type = (Type) 0; type < TotalTimeCounterCount; type - = (Type) (type + 1)) { - char scratch[256]; - int index = sprintf(scratch, "*-* Total %s time: %d ms", - timeCounterNames[type], sTotalTimeUsed[type]); - if (sCounter[type] > 0) - sprintf(&scratch[index], " called %d times", sCounter[type]); - LOGD("%s", scratch); - } - LOGD("Current cache has %d bytes live and %d bytes dead", live, dead); - LOGD("Current render arena takes %d bytes", arenaSize); -#if USE(JSC) - JSLock lock(false); - Heap::Statistics jsHeapStatistics = JSDOMWindow::commonJSGlobalData()->heap.statistics(); - LOGD("Current JavaScript heap size is %d and has %d bytes free", - jsHeapStatistics.size, jsHeapStatistics.free); -#endif - LOGD("Current CSS styles use %d bytes", StyleBase::reportStyleSize()); - LOGD("Current DOM nodes use %d bytes", WebCore::Node::reportDOMNodesSize()); -} - -void TimeCounter::reportNow() -{ - double current = currentTime(); - uint32_t currentThread = getThreadMsec(); - int elapsedTime = static_cast<int>((current - sLastTotalTime) * 1000); - int elapsedThreadTime = currentThread - sLastThreadTime; - LOGD("*-* Elapsed time: %d ms, ui thread time: %d ms, webcore thread time:" - " %d ms\n", elapsedTime, elapsedThreadTime, sEndWebCoreThreadTime - - sStartWebCoreThreadTime); - for (Type type = (Type) 0; type < TotalTimeCounterCount; type - = (Type) (type + 1)) { - if (sTotalTimeUsed[type] == sLastTimeUsed[type]) - continue; - char scratch[256]; - int index = sprintf(scratch, "*-* Diff %s time: %d ms", - timeCounterNames[type], sTotalTimeUsed[type] - sLastTimeUsed[type]); - if (sCounter[type] > sLastCounter[type]) - sprintf(&scratch[index], " called %d times", sCounter[type] - - sLastCounter[type]); - LOGD("%s", scratch); - } - memcpy(sLastTimeUsed, sTotalTimeUsed, sizeof(sTotalTimeUsed)); - memcpy(sLastCounter, sCounter, sizeof(sCounter)); - sLastTotalTime = current; - sLastThreadTime = currentThread; - sRecordWebCoreTime = true; -} - -void TimeCounter::reset() { - bzero(sTotalTimeUsed, sizeof(sTotalTimeUsed)); - bzero(sCounter, sizeof(sCounter)); - LOGD("*-* Start browser instrument\n"); - sStartTotalTime = currentTime(); - sStartThreadTime = getThreadMsec(); -} - -void TimeCounter::start(enum Type type) -{ - uint32_t time = getThreadMsec(); - if (sRecordWebCoreTime) { - sStartWebCoreThreadTime = time; - sRecordWebCoreTime = false; - } - sStartTime[type] = time; -} - -#endif // ANDROID_INSTRUMENT - -} diff --git a/Source/WebKit/android/TimeCounter.h b/Source/WebKit/android/TimeCounter.h deleted file mode 100644 index ecede27..0000000 --- a/Source/WebKit/android/TimeCounter.h +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright 2009, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TimeCounter_h -#define TimeCounter_h - -#include "hardware_legacy/qemu_tracing.h" - -namespace WebCore { - -class KURL; - -} - -namespace android { - -uint32_t getThreadMsec(); - -#ifdef ANDROID_INSTRUMENT - -class TimeCounter { -public: - enum Type { - // function base counters - CSSParseTimeCounter, - JavaScriptTimeCounter, - JavaScriptInitTimeCounter, - JavaScriptParseTimeCounter, - JavaScriptExecuteTimeCounter, - CalculateStyleTimeCounter, - JavaCallbackTimeCounter, - ParsingTimeCounter, - LayoutTimeCounter, - // file base counters - NativeCallbackTimeCounter, // WebCoreFrameBridge.cpp - ResourceTimeCounter, // WebCoreResourceLoader.cpp - SharedTimerTimeCounter, // JavaBridge.cpp - WebViewCoreBuildNavTimeCounter, - WebViewCoreRecordTimeCounter, - WebViewCoreTimeCounter, // WebViewCore.cpp - WebViewUIDrawTimeCounter, - TotalTimeCounterCount - }; - - static void record(enum Type type, const char* functionName); - static void recordNoCounter(enum Type type, const char* functionName); - static void report(const WebCore::KURL& , int live, int dead, size_t arenaSize); - static void reportNow(); - static void reset(); - static void start(enum Type type); -private: - static uint32_t sStartWebCoreThreadTime; - static uint32_t sEndWebCoreThreadTime; - static bool sRecordWebCoreTime; - static uint32_t sTotalTimeUsed[TotalTimeCounterCount]; - static uint32_t sLastTimeUsed[TotalTimeCounterCount]; - static uint32_t sCounter[TotalTimeCounterCount]; - static uint32_t sLastCounter[TotalTimeCounterCount]; - static uint32_t sStartTime[TotalTimeCounterCount]; - friend class TimeCounterAuto; -}; - -class TimeCounterAuto { -public: - TimeCounterAuto(TimeCounter::Type type) : - m_type(type), m_startTime(getThreadMsec()) {} - ~TimeCounterAuto() { - uint32_t time = getThreadMsec(); - TimeCounter::sEndWebCoreThreadTime = time; - TimeCounter::sTotalTimeUsed[m_type] += time - m_startTime; - TimeCounter::sCounter[m_type]++; - } -private: - TimeCounter::Type m_type; - uint32_t m_startTime; -}; - -class QemuTracerAuto { -public: - QemuTracerAuto() { - if (!reentry_count) - qemu_start_tracing(); - reentry_count++; - } - - ~QemuTracerAuto() { - reentry_count--; - if (!reentry_count) - qemu_stop_tracing(); - } -private: - static int reentry_count; -}; -#endif // ANDROID_INSTRUMENT - -} - -#endif diff --git a/Source/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp b/Source/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp index ab5fcb0..1328675 100644 --- a/Source/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp +++ b/Source/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp @@ -298,7 +298,7 @@ bool ChromeClientAndroid::shouldInterruptJavaScript() { KeyboardUIMode ChromeClientAndroid::keyboardUIMode() { - return KeyboardAccessDefault; + return KeyboardAccessTabsToLinks; } IntRect ChromeClientAndroid::windowResizerRect() const { return IntRect(0, 0, 0, 0); } @@ -638,6 +638,11 @@ void ChromeClientAndroid::enterFullscreenForNode(Node* node) void ChromeClientAndroid::exitFullscreenForNode(Node* node) { + FrameView* frameView = m_webFrame->page()->mainFrame()->view(); + android::WebViewCore* core = android::WebViewCore::getWebViewCore(frameView); + if (core) + core->exitFullscreenVideo(); + return; } #endif diff --git a/Source/WebKit/android/WebCoreSupport/ChromiumIncludes.h b/Source/WebKit/android/WebCoreSupport/ChromiumIncludes.h index 022511a..1c898a0 100644 --- a/Source/WebKit/android/WebCoreSupport/ChromiumIncludes.h +++ b/Source/WebKit/android/WebCoreSupport/ChromiumIncludes.h @@ -23,31 +23,46 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +// All source files wishing to include Chromium headers must include this file +// and must not incude Chromium headers directly. + #ifndef ChromiumIncludes_h #define ChromiumIncludes_h #include "config.h" -// Include all external/chromium files in this file so the problems with the LOG -// and LOG_ASSERT defines can be handled in one place. - -// Undefine LOG and LOG_ASSERT before including chrome code, and if they were -// defined attempt to set the macros to the Android logging macros (which are -// the only ones that actually log). - +// Both WebKit and Chromium define LOG. In AOSP, the framework also defines +// LOG. To avoid conflicts, we undefine LOG before including Chromium code, +// then define it back to the WebKit macro. #ifdef LOG -#define LOG_WAS_DEFINED LOG +#define LOG_WAS_DEFINED #undef LOG #endif -#ifdef LOG_ASSERT -#define LOG_ASSERT_WAS_DEFINED LOG_ASSERT +// In AOSP, the framework still uses LOG_ASSERT (as well as ALOG_ASSERT), which +// conflicts with Chromium's LOG_ASSERT. So we undefine LOG_ASSERT to allow the +// Chromium implementation to be picked up. We also redefine ALOG_ASSERT to the +// underlying framework implementation without using LOG_ASSERT. +// TODO: Remove this once LOG_ASSERT is removed from the framework in AOSP. #undef LOG_ASSERT +#undef ALOG_ASSERT +// Copied from log.h. +#define ALOG_ASSERT(cond, ...) LOG_FATAL_IF(!(cond), ## __VA_ARGS__) + +// Chromium won't build without NDEBUG set, so we set it for all source files +// that use Chromium code. This means that if NDEBUG was previously unset, we +// have to redefine ASSERT() to a no-op, as this is enabled in debug builds. +// Unfortunately, ASSERT() is defined from config.h, so we can't get in first. +#ifndef NDEBUG +#define NDEBUG 1 +#undef ASSERT +#define ASSERT(assertion) (void(0)) #endif #include <android/net/android_network_library_impl.h> #include <android/jni/jni_utils.h> #include <base/callback.h> +#include <base/lazy_instance.h> #include <base/memory/ref_counted.h> #include <base/message_loop_proxy.h> #include <base/openssl_util.h> @@ -100,13 +115,15 @@ #endif #undef LOG -#if defined(LOG_WAS_DEFINED) && defined(LOG_PRI) -#define LOG(priority, tag, ...) LOG_PRI(ANDROID_##priority, tag, __VA_ARGS__) +// If LOG was defined, restore it to the WebKit macro. +#ifdef LOG_WAS_DEFINED +// If LOG was defined, JOIN_LOG_CHANNEL_WITH_PREFIX must be too. +// Copied from Assertions.h. +#if LOG_DISABLED +#define LOG(channel, ...) ((void)0) +#else +#define LOG(channel, ...) WTFLog(&JOIN_LOG_CHANNEL_WITH_PREFIX(LOG_CHANNEL_PREFIX, channel), __VA_ARGS__) #endif - -#undef LOG_ASSERT -#if defined(LOG_ASSERT_WAS_DEFINED) && defined(LOG_FATAL_IF) -#define LOG_ASSERT(cond, ...) LOG_FATAL_IF(!(cond), ## __VA_ARGS__) #endif #endif diff --git a/Source/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp b/Source/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp index 0be31eb..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" @@ -79,7 +78,7 @@ #include "autofill/WebAutofill.h" #include "android_graphics.h" -#include <utils/AssetManager.h> +#include <androidfw/AssetManager.h> #include <wtf/text/CString.h> #define verifiedOk() // Verified that we don't need to implement this. @@ -267,11 +266,11 @@ void FrameLoaderClientAndroid::dispatchDidReceiveIcon() { // There is a bug in webkit where cancelling an icon load is treated as a // failure. When this is fixed, we can ASSERT again that we have an icon. if (icon) { - LOGV("Received icon (%p) for %s", icon, + ALOGV("Received icon (%p) for %s", icon, url.utf8().data()); m_webFrame->didReceiveIcon(icon); } else { - LOGV("Icon data for %s unavailable, registering for notification...", + ALOGV("Icon data for %s unavailable, registering for notification...", url.utf8().data()); registerForIconNotification(); } @@ -1016,7 +1015,7 @@ WTF::PassRefPtr<WebCore::Frame> FrameLoaderClientAndroid::createFrame(const KURL newFrame->setView(frameView); newFrame->init(); newFrame->selection()->setFocused(true); - LOGV("::WebCore:: createSubFrame returning %p", newFrame); + ALOGV("::WebCore:: createSubFrame returning %p", newFrame); // The creation of the frame may have run arbitrary JavaScript that removed it from the page already. if (!pFrame->page()) @@ -1331,8 +1330,8 @@ void FrameLoaderClientAndroid::dispatchDidClearWindowObjectInWorld(DOMWrapperWor return; ASSERT(m_frame); - LOGV("::WebCore:: windowObjectCleared called on frame %p for %s\n", - m_frame, m_frame->loader()->url().string().ascii().data()); + ALOGV("::WebCore:: windowObjectCleared called on frame %p for %s\n", + m_frame, m_frame->document()->url().string().ascii().data()); m_webFrame->windowObjectCleared(m_frame); } diff --git a/Source/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.h b/Source/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.h index 2464c58..6eb4745 100644 --- a/Source/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.h +++ b/Source/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.h @@ -26,7 +26,6 @@ #ifndef FrameLoaderClientAndroid_h #define FrameLoaderClientAndroid_h -#include "CacheBuilder.h" #include "FrameLoaderClient.h" #include "ResourceResponse.h" #include "WebIconDatabase.h" @@ -200,14 +199,12 @@ namespace android { virtual void documentElementAvailable(); virtual void didPerformFirstNavigation() const; -#if USE(V8) - // TODO(benm): Implement + // TODO: Implement virtual void didCreateScriptContextForFrame() { } virtual void didDestroyScriptContextForFrame() { } virtual void didCreateIsolatedScriptContext() { } - virtual bool allowScriptExtension(const String& extensionName, int extensionGroup) { return false; } -#endif + virtual bool allowScriptExtension(const String& extensionName, int extensionGroup) { return false; } virtual void registerForIconNotification(bool listen = true); @@ -218,9 +215,6 @@ namespace android { // WebIconDatabaseClient api virtual void didAddIconForPageUrl(const String& pageUrl); - // FIXME: this doesn't really go here, but it's better than Frame - CacheBuilder& getCacheBuilder() { return m_cacheBuilder; } - void enableOnDemandPlugins() { m_onDemandPluginsEnabled = true; } void dispatchDidChangeIcons(); @@ -229,7 +223,6 @@ namespace android { virtual void didSaveToPageCache() { } virtual void didRestoreFromPageCache() { } private: - CacheBuilder m_cacheBuilder; Frame* m_frame; WebFrame* m_webFrame; PluginManualLoader* m_manualLoader; @@ -265,7 +258,6 @@ namespace android { ErrorFileNotFound = -14, ErrorTooManyRequests = -15 }; - friend class CacheBuilder; }; } diff --git a/Source/WebKit/android/WebCoreSupport/MediaPlayerPrivateAndroid.cpp b/Source/WebKit/android/WebCoreSupport/MediaPlayerPrivateAndroid.cpp index 339e91b..fea45de 100644 --- a/Source/WebKit/android/WebCoreSupport/MediaPlayerPrivateAndroid.cpp +++ b/Source/WebKit/android/WebCoreSupport/MediaPlayerPrivateAndroid.cpp @@ -168,6 +168,14 @@ void MediaPlayerPrivate::onEnded() m_networkState = MediaPlayer::Idle; } +void MediaPlayerPrivate::onRestoreState() +{ + if (!m_paused) { + //Kick off a JNI call to start the video. + play(); + } +} + void MediaPlayerPrivate::onPaused() { m_paused = true; @@ -293,7 +301,8 @@ public: m_player->durationChanged(); m_player->sizeChanged(); TilesManager::instance()->videoLayerManager()->updateVideoLayerSize( - m_player->platformLayer()->uniqueId(), width*height); + m_player->platformLayer()->uniqueId(), width * height, + width / (float)height); } virtual bool hasAudio() const { return false; } // do not display the audio UI @@ -570,6 +579,15 @@ static void OnTimeupdate(JNIEnv* env, jobject obj, int position, int pointer) } } +static void OnRestoreState(JNIEnv* env, jobject obj, int pointer) +{ + if (pointer) { + WebCore::MediaPlayerPrivate* player = reinterpret_cast<WebCore::MediaPlayerPrivate*>(pointer); + player->onRestoreState(); + } +} + + // This is called on the UI thread only. // The video layers are composited on the webkit thread and then copied over // to the UI thread with the same ID. For rendering, we are only using the @@ -632,6 +650,8 @@ static JNINativeMethod g_MediaPlayerMethods[] = { (void*) OnPaused }, { "nativeOnPosterFetched", "(Landroid/graphics/Bitmap;I)V", (void*) OnPosterFetched }, + { "nativeOnRestoreState", "(I)V", + (void*) OnRestoreState }, { "nativeSendSurfaceTexture", "(Landroid/graphics/SurfaceTexture;IIII)Z", (void*) SendSurfaceTexture }, { "nativeOnTimeupdate", "(II)V", diff --git a/Source/WebKit/android/WebCoreSupport/MemoryUsage.cpp b/Source/WebKit/android/WebCoreSupport/MemoryUsage.cpp index 32cdebf..592fad3 100644 --- a/Source/WebKit/android/WebCoreSupport/MemoryUsage.cpp +++ b/Source/WebKit/android/WebCoreSupport/MemoryUsage.cpp @@ -29,9 +29,7 @@ #include <malloc.h> #include <wtf/CurrentTime.h> -#if USE(V8) #include <v8.h> -#endif // USE(V8) using namespace WTF; @@ -59,12 +57,10 @@ int MemoryUsageCache::getCachedMemoryUsage(bool forceFresh) struct mallinfo minfo = mallinfo(); m_cachedMemoryUsage = (minfo.hblkhd + minfo.arena) >> 20; -#if USE(V8) v8::HeapStatistics stat; v8::V8::GetHeapStatistics(&stat); unsigned v8Usage = stat.total_heap_size() >> 20; m_cachedMemoryUsage += v8Usage; -#endif // USE(V8) m_cacheTime = currentTimeMS(); return m_cachedMemoryUsage; diff --git a/Source/WebKit/android/WebCoreSupport/PlatformBridge.cpp b/Source/WebKit/android/WebCoreSupport/PlatformBridge.cpp index 27fe208..b684a1a 100644 --- a/Source/WebKit/android/WebCoreSupport/PlatformBridge.cpp +++ b/Source/WebKit/android/WebCoreSupport/PlatformBridge.cpp @@ -35,13 +35,15 @@ #include "KeyGeneratorClient.h" #include "MemoryUsage.h" #include "PluginView.h" +#include "RenderLayer.h" +#include "RenderView.h" #include "Settings.h" #include "WebCookieJar.h" #include "WebRequestContext.h" #include "WebViewCore.h" #include "npruntime.h" -#include <surfaceflinger/SurfaceComposerClient.h> +#include <gui/SurfaceComposerClient.h> #include <ui/DisplayInfo.h> #include <ui/PixelFormat.h> #include <wtf/android/AndroidThreading.h> @@ -71,62 +73,34 @@ 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) { -#if USE(V8) if (!widget->isPluginView()) return 0; PluginView* pluginView = static_cast<PluginView*>(widget); return pluginView->getNPObject(); -#else - return 0; -#endif } bool PlatformBridge::isWebViewPaused(const WebCore::FrameView* frameView) @@ -175,15 +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) @@ -203,6 +173,16 @@ void PlatformBridge::setScrollPosition(ScrollView* scrollView, int x, int y) { android::WebViewCore *webViewCore = android::WebViewCore::getWebViewCore(scrollView); if (webViewCore->mainFrame()->view() == scrollView) webViewCore->scrollTo(x, y); + else { + FrameView* frameView = scrollView->frameView(); + if (frameView) { + RenderView* renderer = frameView->frame()->contentRenderer(); + if (renderer) { + RenderLayer* layer = renderer->layer(); + layer->scrollToOffset(x, y); + } + } + } } int PlatformBridge::lowMemoryUsageMB() diff --git a/Source/WebKit/android/WebCoreSupport/ResourceLoaderAndroid.cpp b/Source/WebKit/android/WebCoreSupport/ResourceLoaderAndroid.cpp index 7f54810..92c39b8 100644 --- a/Source/WebKit/android/WebCoreSupport/ResourceLoaderAndroid.cpp +++ b/Source/WebKit/android/WebCoreSupport/ResourceLoaderAndroid.cpp @@ -29,7 +29,6 @@ #include "Frame.h" #include "FrameLoaderClientAndroid.h" #include "WebCoreFrameBridge.h" -#include "WebCoreResourceLoader.h" #include "WebUrlLoader.h" #include "WebViewCore.h" @@ -42,18 +41,13 @@ PassRefPtr<ResourceLoaderAndroid> ResourceLoaderAndroid::start( { // Called on main thread FrameLoaderClientAndroid* clientAndroid = static_cast<FrameLoaderClientAndroid*>(client); -#if USE(CHROME_NETWORK_STACK) WebViewCore* webViewCore = WebViewCore::getWebViewCore(clientAndroid->getFrame()->view()); bool isMainFrame = !(clientAndroid->getFrame()->tree() && clientAndroid->getFrame()->tree()->parent()); return WebUrlLoader::start(client, handle, request, isMainResource, isMainFrame, isSync, webViewCore->webRequestContext()); -#else - return clientAndroid->webFrame()->startLoadingResource(handle, request, isMainResource, isSync); -#endif } bool ResourceLoaderAndroid::willLoadFromCache(const WebCore::KURL& url, int64_t identifier) { -#if USE(CHROME_NETWORK_STACK) // This method is used to determine if a POST request can be repeated from // cache, but you cannot really know until you actually try to read from the // cache. Even if we checked now, something else could come along and wipe @@ -63,9 +57,6 @@ bool ResourceLoaderAndroid::willLoadFromCache(const WebCore::KURL& url, int64_t // reload. Then in FrameLoaderClientImpl::dispatchWillSendRequest, we // fix-up the cache policy of the request to force a load from the cache. return true; -#else - return WebCoreResourceLoader::willLoadFromCache(url, identifier); -#endif } } diff --git a/Source/WebKit/android/WebCoreSupport/V8Counters.cpp b/Source/WebKit/android/WebCoreSupport/V8Counters.cpp deleted file mode 100644 index d164f9a..0000000 --- a/Source/WebKit/android/WebCoreSupport/V8Counters.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright 2010, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - -#ifdef ANDROID_INSTRUMENT - -#define LOG_TAG "WebCore" - -#include "config.h" -#include "V8Counters.h" - -#include "NotImplemented.h" -#include <utils/Log.h> -#include <wtf/text/CString.h> -#include <wtf/text/StringHash.h> - -#if USE(V8) - -namespace WebCore { - -V8Counters::Counter::Counter(bool isHistogram) - : m_count(0), m_sampleTotal(0), m_isHistogram(isHistogram) { } - -void V8Counters::Counter::addSample(int sample) -{ - m_count++; - m_sampleTotal += sample; -} - -HashMap<String, V8Counters::Counter*> V8Counters::m_counters; - -// static -int* V8Counters::counterForName(const char* name) -{ - Counter* counter = m_counters.get(name); - if (!counter) { - counter = new Counter(false); - m_counters.add(name, counter); - } - return *counter; -} - -// static -void* V8Counters::createHistogram(const char* name, int min, int max, - size_t buckets) -{ - Counter* counter = new Counter(true); - m_counters.add(name, counter); - return counter; -} - -// static -void V8Counters::addHistogramSample(void* histogram, int sample) -{ - Counter* counter = reinterpret_cast<Counter*>(histogram); - counter->addSample(sample); -} - -// static -void V8Counters::initCounters() -{ - static bool isInitialized = false; - if (!isInitialized) { - v8::V8::SetCounterFunction(counterForName); - v8::V8::SetCreateHistogramFunction(createHistogram); - v8::V8::SetAddHistogramSampleFunction(addHistogramSample); - isInitialized = true; - } -} - -// static -void V8Counters::dumpCounters() -{ - LOGD("+----------------------------------------+-------------+\n"); - LOGD("| Name | Value |\n"); - LOGD("+----------------------------------------+-------------+\n"); - typedef HashMap<String, V8Counters::Counter*>::iterator CounterIterator; - for (CounterIterator iter = m_counters.begin(); iter != m_counters.end(); ++iter) { - Counter* counter = iter->second; - if (counter->isHistogram()) { - LOGD("| c:%-36s | %11i |\n", iter->first.latin1().data(), counter->count()); - LOGD("| t:%-36s | %11i |\n", iter->first.latin1().data(), counter->sampleTotal()); - } else { - LOGD("| %-38s | %11i |\n", iter->first.latin1().data(), counter->count()); - } - } - LOGD("+----------------------------------------+-------------+\n"); -} - -} - -#endif // ANDROID_INSTRUMENT - -#endif // USE(V8) diff --git a/Source/WebKit/android/WebCoreSupport/V8Counters.h b/Source/WebKit/android/WebCoreSupport/V8Counters.h deleted file mode 100644 index 499b856..0000000 --- a/Source/WebKit/android/WebCoreSupport/V8Counters.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2010, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef V8Counters_h -#define V8Counters_h - -#if USE(V8) - -#ifdef ANDROID_INSTRUMENT - -#include <PlatformString.h> -#include <v8.h> -#include <wtf/HashMap.h> - -namespace WebCore { - -class V8Counters { -public: - // Counter callbacks, see v8.h - static int* counterForName(const char* name); - - static void* createHistogram(const char* name, - int min, - int max, - size_t buckets); - - static void addHistogramSample(void* histogram, int sample); - - static void initCounters(); - static void dumpCounters(); -private: - class Counter { - public: - Counter(bool isHistogram); - - int count() { return m_count; } - int sampleTotal() { return m_sampleTotal; } - bool isHistogram() { return m_isHistogram; } - void addSample(int32_t sample); - - operator int*() { return &m_count; } - private: - int m_count; - int m_sampleTotal; - bool m_isHistogram; - }; - - static HashMap<String, Counter*> m_counters; -}; - -} - -#endif // ANDROID_INSTRUMENT -#endif // USE(V8) -#endif // V8Counters_h diff --git a/Source/WebKit/android/WebCoreSupport/WebCache.cpp b/Source/WebKit/android/WebCoreSupport/WebCache.cpp index 9b505ee..82e3b27 100644 --- a/Source/WebKit/android/WebCoreSupport/WebCache.cpp +++ b/Source/WebKit/android/WebCoreSupport/WebCache.cpp @@ -30,7 +30,7 @@ #include "WebCoreJni.h" #include "WebRequestContext.h" #include "WebUrlLoaderClient.h" - +#include "net/http/http_network_session.h" #include <wtf/text/CString.h> using namespace WTF; @@ -131,6 +131,21 @@ void WebCache::clear() thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this, &WebCache::clearImpl)); } +void WebCache::certTrustChanged() +{ + base::Thread* thread = WebUrlLoaderClient::ioThread(); + if (thread) + thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this, &WebCache::certTrustChangedImpl)); +} + +void WebCache::certTrustChangedImpl() +{ + net::HttpNetworkSession* session = m_cache->GetSession(); + if (session) + session->cert_verifier()->ClearCache(); + m_cache->CloseAllConnections(); +} + void WebCache::closeIdleConnections() { base::Thread* thread = WebUrlLoaderClient::ioThread(); diff --git a/Source/WebKit/android/WebCoreSupport/WebCache.h b/Source/WebKit/android/WebCoreSupport/WebCache.h index c3b623d..ad57d88 100644 --- a/Source/WebKit/android/WebCoreSupport/WebCache.h +++ b/Source/WebKit/android/WebCoreSupport/WebCache.h @@ -48,7 +48,7 @@ public: net::HttpCache* cache() { return m_cache.get(); } net::ProxyConfigServiceAndroid* proxy() { return m_proxyConfigService; } void closeIdleConnections(); - + void certTrustChanged(); private: WebCache(bool isPrivateBrowsing); @@ -60,6 +60,7 @@ private: // For closeIdleConnections void closeIdleImpl(); + void certTrustChangedImpl(); // For getEntry() void getEntryImpl(); diff --git a/Source/WebKit/android/WebCoreSupport/WebCookieJar.cpp b/Source/WebKit/android/WebCoreSupport/WebCookieJar.cpp index 1dc4637..0af3cc2 100644 --- a/Source/WebKit/android/WebCoreSupport/WebCookieJar.cpp +++ b/Source/WebKit/android/WebCoreSupport/WebCookieJar.cpp @@ -98,7 +98,7 @@ static std::string databaseDirectory(bool isPrivateBrowsing) return databaseFilePath; } -scoped_refptr<WebCookieJar>* instance(bool isPrivateBrowsing) +static scoped_refptr<WebCookieJar>* instance(bool isPrivateBrowsing) { static scoped_refptr<WebCookieJar> regularInstance; static scoped_refptr<WebCookieJar> privateInstance; @@ -127,10 +127,16 @@ void WebCookieJar::cleanup(bool isPrivateBrowsing) } WebCookieJar::WebCookieJar(const std::string& databaseFilePath) - : m_allowCookies(true) -{ + : m_cookieStoreInitialized(false) + , m_databaseFilePath(databaseFilePath) + , m_allowCookies(true) {} + +void WebCookieJar::initCookieStore() { + MutexLocker lock(m_cookieStoreInitializeMutex); + if (m_cookieStoreInitialized) + return; // Setup the permissions for the file - const char* cDatabasePath = databaseFilePath.c_str(); + const char* cDatabasePath = m_databaseFilePath.c_str(); mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP; if (access(cDatabasePath, F_OK) == 0) chmod(cDatabasePath, mode); @@ -140,9 +146,10 @@ WebCookieJar::WebCookieJar(const std::string& databaseFilePath) close(fd); } - FilePath cookiePath(databaseFilePath.c_str()); + FilePath cookiePath(cDatabasePath); m_cookieDb = new SQLitePersistentCookieStore(cookiePath); m_cookieStore = new net::CookieMonster(m_cookieDb.get(), 0); + m_cookieStoreInitialized = true; } bool WebCookieJar::allowCookies() @@ -157,13 +164,6 @@ void WebCookieJar::setAllowCookies(bool allow) m_allowCookies = allow; } -int WebCookieJar::getNumCookiesInDatabase() -{ - if (!m_cookieStore) - return 0; - return m_cookieStore->GetCookieMonster()->GetAllCookies().size(); -} - // From CookiePolicy in chromium int WebCookieJar::CanGetCookies(const GURL&, const GURL&) const { @@ -178,6 +178,17 @@ int WebCookieJar::CanSetCookie(const GURL&, const GURL&, const std::string&) con return m_allowCookies ? net::OK : net::ERR_ACCESS_DENIED; } +net::CookieStore* WebCookieJar::cookieStore() +{ + initCookieStore(); + return m_cookieStore.get(); +} + +int WebCookieJar::getNumCookiesInDatabase() +{ + return cookieStore()->GetCookieMonster()->GetAllCookies().size(); +} + class FlushSemaphore : public base::RefCounted<FlushSemaphore> { public: diff --git a/Source/WebKit/android/WebCoreSupport/WebCookieJar.h b/Source/WebKit/android/WebCoreSupport/WebCookieJar.h index b6490af..7ade9d0 100644 --- a/Source/WebKit/android/WebCoreSupport/WebCookieJar.h +++ b/Source/WebKit/android/WebCoreSupport/WebCookieJar.h @@ -55,9 +55,10 @@ public: static bool acceptFileSchemeCookies(); static void setAcceptFileSchemeCookies(bool); + // TODO // Instead of this it would probably be better to add the cookie methods // here so the rest of WebKit doesn't have to know about Chromium classes - net::CookieStore* cookieStore() { return m_cookieStore.get(); } + net::CookieStore* cookieStore(); net::CookiePolicy* cookiePolicy() { return this; } // Get the number of cookies that have actually been saved to flash. @@ -66,7 +67,13 @@ public: private: WebCookieJar(const std::string& databaseFilePath); + void initCookieStore(); +private: + bool m_cookieStoreInitialized; + WTF::Mutex m_cookieStoreInitializeMutex; + + const std::string m_databaseFilePath; scoped_refptr<SQLitePersistentCookieStore> m_cookieDb; scoped_refptr<net::CookieStore> m_cookieStore; bool m_allowCookies; diff --git a/Source/WebKit/android/WebCoreSupport/WebRequest.cpp b/Source/WebKit/android/WebCoreSupport/WebRequest.cpp index 90b0939..fea7afa 100644 --- a/Source/WebKit/android/WebCoreSupport/WebRequest.cpp +++ b/Source/WebKit/android/WebCoreSupport/WebRequest.cpp @@ -30,6 +30,7 @@ #include "MainThread.h" #include "UrlInterceptResponse.h" #include "WebCoreFrameBridge.h" +#include "WebCoreJni.h" #include "WebRequestContext.h" #include "WebResourceRequest.h" #include "WebUrlLoaderClient.h" @@ -38,7 +39,7 @@ #include <cutils/log.h> #include <openssl/x509.h> #include <string> -#include <utils/AssetManager.h> +#include <androidfw/AssetManager.h> extern android::AssetManager* globalAssetManager(); @@ -58,7 +59,24 @@ while (0) namespace android { namespace { - const int kInitialReadBufSize = 32768; +const int kInitialReadBufSize = 32768; +const char* kXRequestedWithHeader = "X-Requested-With"; + +struct RequestPackageName { + std::string value; + RequestPackageName(); +}; + +RequestPackageName::RequestPackageName() { + JNIEnv* env = JSC::Bindings::getJNIEnv(); + jclass bridgeClass = env->FindClass("android/webkit/JniUtil"); + jmethodID method = env->GetStaticMethodID(bridgeClass, "getPackageName", "()Ljava/lang/String;"); + value = jstringToStdString(env, static_cast<jstring>(env->CallStaticObjectMethod(bridgeClass, method))); + env->DeleteLocalRef(bridgeClass); +} + +base::LazyInstance<RequestPackageName> s_packageName(base::LINKER_INITIALIZED); + } WebRequest::WebRequest(WebUrlLoaderClient* loader, const WebResourceRequest& webResourceRequest) @@ -79,6 +97,7 @@ WebRequest::WebRequest(WebUrlLoaderClient* loader, const WebResourceRequest& web m_request = new net::URLRequest(gurl, this); m_request->SetExtraRequestHeaders(webResourceRequest.requestHeaders()); + m_request->SetExtraRequestHeaderByName(kXRequestedWithHeader, s_packageName.Get().value, true); m_request->set_referrer(webResourceRequest.referrer()); m_request->set_method(webResourceRequest.method()); m_request->set_load_flags(webResourceRequest.loadFlags()); diff --git a/Source/WebKit/android/WebCoreSupport/WebUrlLoaderClient.cpp b/Source/WebKit/android/WebCoreSupport/WebUrlLoaderClient.cpp index 43037ab..5df0ed2 100644 --- a/Source/WebKit/android/WebCoreSupport/WebUrlLoaderClient.cpp +++ b/Source/WebKit/android/WebCoreSupport/WebUrlLoaderClient.cpp @@ -37,6 +37,7 @@ #include "WebRequest.h" #include "WebResourceRequest.h" +#include <utils/Log.h> #include <wtf/text/CString.h> using base::Lock; @@ -156,11 +157,11 @@ WebUrlLoaderClient::WebUrlLoaderClient(WebFrame* webFrame, WebCore::ResourceHand break; #if ENABLE(BLOB) case FormDataElement::encodedBlob: - LOG_ASSERT(false, "Unexpected use of FormDataElement::encodedBlob"); + ALOG_ASSERT(false, "Unexpected use of FormDataElement::encodedBlob"); break; #endif // ENABLE(BLOB) default: - LOG_ASSERT(false, "Unexpected default case in WebUrlLoaderClient.cpp"); + ALOG_ASSERT(false, "Unexpected default case in WebUrlLoaderClient.cpp"); break; } } @@ -199,7 +200,7 @@ bool WebUrlLoaderClient::start(bool isMainResource, bool isMainFrame, bool sync, syncCondition()->TimedWait(base::TimeDelta::FromSeconds(kCallbackWaitingTime)); if (m_queue.empty()) { - LOGE("Synchronous request timed out after %d seconds for the %dth try, URL: %s", + ALOGE("Synchronous request timed out after %d seconds for the %dth try, URL: %s", kCallbackWaitingTime, num_timeout, m_request->getUrl().c_str()); num_timeout++; if (num_timeout >= kMaxNumTimeout) { @@ -253,7 +254,7 @@ void WebUrlLoaderClient::downloadFile() if (!m_isCertMimeType) cancel(); } else { - LOGE("Unexpected call to downloadFile() before didReceiveResponse(). URL: %s", m_request->getUrl().c_str()); + ALOGE("Unexpected call to downloadFile() before didReceiveResponse(). URL: %s", m_request->getUrl().c_str()); // TODO: Turn off asserts crashing before release // http://b/issue?id=2951985 CRASH(); diff --git a/Source/WebKit/android/WebCoreSupport/WebViewClientError.cpp b/Source/WebKit/android/WebCoreSupport/WebViewClientError.cpp index 260c76e..1857e9c 100644 --- a/Source/WebKit/android/WebCoreSupport/WebViewClientError.cpp +++ b/Source/WebKit/android/WebCoreSupport/WebViewClientError.cpp @@ -79,6 +79,7 @@ WebViewClientError ToWebViewClientError(net::Error error) { case ERR_CONNECTION_ABORTED: case ERR_CONNECTION_FAILED: case ERR_SOCKET_NOT_CONNECTED: + case ERR_CACHE_MISS: return ERROR_CONNECT; case ERR_ADDRESS_INVALID: diff --git a/Source/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.cpp b/Source/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.cpp index e837244..2969252 100644 --- a/Source/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.cpp +++ b/Source/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.cpp @@ -562,7 +562,7 @@ void FormManager::ExtractForms(Frame* frame) { ResetFrame(frame); - WTF::PassRefPtr<HTMLCollection> web_forms = frame->document()->forms(); + WTF::RefPtr<HTMLCollection> web_forms = frame->document()->forms(); for (size_t i = 0; i < web_forms->length(); ++i) { // Owned by |form_elements|. diff --git a/Source/WebKit/android/benchmark/Android.mk b/Source/WebKit/android/benchmark/Android.mk deleted file mode 100644 index 5b189e1..0000000 --- a/Source/WebKit/android/benchmark/Android.mk +++ /dev/null @@ -1,41 +0,0 @@ -## -## -## Copyright 2009, The Android Open Source Project -## -## Redistribution and use in source and binary forms, with or without -## modification, are permitted provided that the following conditions -## are met: -## * Redistributions of source code must retain the above copyright -## notice, this list of conditions and the following disclaimer. -## * Redistributions in binary form must reproduce the above copyright -## notice, this list of conditions and the following disclaimer in the -## documentation and/or other materials provided with the distribution. -## -## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY -## EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -## IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR -## CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -## EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -## PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -## PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY -## OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -## - -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - main.cpp - -# Pull the webkit definitions from the base webkit makefile. -LOCAL_SHARED_LIBRARIES := libwebcore $(WEBKIT_SHARED_LIBRARIES) -LOCAL_LDLIBS := $(WEBKIT_LDLIBS) - -LOCAL_MODULE := webcore_test - -LOCAL_MODULE_TAGS := optional - -include $(BUILD_EXECUTABLE) diff --git a/Source/WebKit/android/benchmark/Intercept.cpp b/Source/WebKit/android/benchmark/Intercept.cpp deleted file mode 100644 index deffac2..0000000 --- a/Source/WebKit/android/benchmark/Intercept.cpp +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright 2009, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#define LOG_TAG "webcore_test" -#include "config.h" - -#include "Base64.h" -#include "HTTPParsers.h" -#include "Intercept.h" -#include "ResourceHandle.h" -#include "ResourceHandleClient.h" -#include "ResourceRequest.h" -#include "ResourceResponse.h" -#include "TextEncoding.h" - -#include <utils/Log.h> -#include <wtf/HashMap.h> -#include <wtf/text/CString.h> -#include <wtf/text/StringHash.h> - -PassRefPtr<WebCore::ResourceLoaderAndroid> MyResourceLoader::create( - ResourceHandle* handle, String url) -{ - return adoptRef<WebCore::ResourceLoaderAndroid>( - new MyResourceLoader(handle, url)); -} - -void MyResourceLoader::handleRequest() -{ - if (protocolIs(m_url, "data")) - loadData(m_url.substring(5)); // 5 for data: - else if (protocolIs(m_url, "file")) - loadFile(m_url.substring(7)); // 7 for file:// -} - -void MyResourceLoader::loadData(const String& data) -{ - LOGD("Loading data (%s) ...", data.latin1().data()); - ResourceHandleClient* client = m_handle->client(); - int index = data.find(','); - if (index == -1) { - client->cannotShowURL(m_handle); - return; - } - - String mediaType = data.substring(0, index); - String base64 = data.substring(index + 1); - - bool decode = mediaType.endsWith(";base64", false); - if (decode) - mediaType = mediaType.left(mediaType.length() - 7); // 7 for base64; - - if (mediaType.isEmpty()) - mediaType = "text/plain;charset=US-ASCII"; - - String mimeType = extractMIMETypeFromMediaType(mediaType); - String charset = extractCharsetFromMediaType(mediaType); - - ResourceResponse response; - response.setMimeType(mimeType); - - if (decode) { - base64 = decodeURLEscapeSequences(base64); - response.setTextEncodingName(charset); - client->didReceiveResponse(m_handle, response); - - // FIXME: This is annoying. WebCore's Base64 decoder chokes on spaces. - // That is correct with strict decoding but html authors (particularly - // the acid3 authors) put spaces in the data which should be ignored. - // Remove them here before sending to the decoder. - Vector<char> in; - CString str = base64.latin1(); - const char* chars = str.data(); - unsigned i = 0; - while (i < str.length()) { - char c = chars[i]; - // Don't send spaces or control characters. - if (c != ' ' && c != '\n' && c != '\t' && c != '\b' - && c != '\f' && c != '\r') - in.append(chars[i]); - i++; - } - Vector<char> out; - if (base64Decode(in, out) && out.size() > 0) - client->didReceiveData(m_handle, out.data(), out.size(), 0); - } else { - base64 = decodeURLEscapeSequences(base64, TextEncoding(charset)); - response.setTextEncodingName("UTF-16"); - client->didReceiveResponse(m_handle, response); - if (base64.length() > 0) - client->didReceiveData(m_handle, (const char*)base64.characters(), - base64.length() * sizeof(UChar), 0); - } - client->didFinishLoading(m_handle, 0); -} -static String mimeTypeForExtension(const String& file) -{ - static HashMap<String, String, CaseFoldingHash> extensionToMime; - if (extensionToMime.isEmpty()) { - extensionToMime.set("txt", "text/plain"); - extensionToMime.set("html", "text/html"); - extensionToMime.set("htm", "text/html"); - extensionToMime.set("png", "image/png"); - extensionToMime.set("jpeg", "image/jpeg"); - extensionToMime.set("jpg", "image/jpeg"); - extensionToMime.set("gif", "image/gif"); - extensionToMime.set("ico", "image/x-icon"); - extensionToMime.set("js", "text/javascript"); - } - int dot = file.reverseFind('.'); - String mime("text/plain"); - if (dot != -1) { - String ext = file.substring(dot + 1); - if (extensionToMime.contains(ext)) - mime = extensionToMime.get(ext); - } - return mime; -} - -void MyResourceLoader::loadFile(const String& file) -{ - LOGD("Loading file (%s) ...", file.latin1().data()); - FILE* f = fopen(file.latin1().data(), "r"); - ResourceHandleClient* client = m_handle->client(); - if (!f) { - client->didFail(m_handle, - ResourceError("", -14, file, "Could not open file")); - } else { - ResourceResponse response; - response.setTextEncodingName("utf-8"); - response.setMimeType(mimeTypeForExtension(file)); - client->didReceiveResponse(m_handle, response); - char buf[512]; - while (true) { - int res = fread(buf, 1, sizeof(buf), f); - if (res <= 0) - break; - client->didReceiveData(m_handle, buf, res, 0); - } - fclose(f); - client->didFinishLoading(m_handle, 0); - } -} - -PassRefPtr<WebCore::ResourceLoaderAndroid> MyWebFrame::startLoadingResource( - ResourceHandle* handle, const ResourceRequest& req, bool ignore, - bool ignore2) -{ - RefPtr<WebCore::ResourceLoaderAndroid> loader = - MyResourceLoader::create(handle, req.url().string()); - m_requests.append(loader); - if (!m_timer.isActive()) - m_timer.startOneShot(0); - return loader.release(); -} - -void MyWebFrame::timerFired(Timer<MyWebFrame>*) -{ - LOGD("Handling requests..."); - Vector<RefPtr<WebCore::ResourceLoaderAndroid> > reqs; - reqs.swap(m_requests); - Vector<RefPtr<WebCore::ResourceLoaderAndroid> >::iterator i = reqs.begin(); - Vector<RefPtr<WebCore::ResourceLoaderAndroid> >::iterator end = reqs.end(); - for (; i != end; i++) - static_cast<MyResourceLoader*>((*i).get())->handleRequest(); - - LOGD("...done"); -} diff --git a/Source/WebKit/android/benchmark/Intercept.h b/Source/WebKit/android/benchmark/Intercept.h deleted file mode 100644 index 6694dba..0000000 --- a/Source/WebKit/android/benchmark/Intercept.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2009, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef Intercept_h -#define Intercept_h - -#include "MyJavaVM.h" -#include "PlatformString.h" -#include "Timer.h" -#include "WebCoreFrameBridge.h" -#include "WebCoreResourceLoader.h" -#include <JNIUtility.h> -#include <wtf/Vector.h> - -namespace WebCore { - class Page; - class ResourceHandle; - class ResourceRequest; -} - -using namespace android; -using namespace WebCore; -using namespace WTF; - -class MyResourceLoader : public WebCoreResourceLoader { -public: - static PassRefPtr<WebCore::ResourceLoaderAndroid> create( - ResourceHandle* handle, String url); - void handleRequest(); - -private: - MyResourceLoader(ResourceHandle* handle, String url) - : WebCoreResourceLoader(JSC::Bindings::getJNIEnv(), MY_JOBJECT) - , m_handle(handle) - , m_url(url) {} - - void loadData(const String&); - void loadFile(const String&); - ResourceHandle* m_handle; - String m_url; -}; - -class MyWebFrame : public WebFrame { -public: - MyWebFrame(Page* page) - : WebFrame(JSC::Bindings::getJNIEnv(), MY_JOBJECT, MY_JOBJECT, page) - , m_timer(this, &MyWebFrame::timerFired) {} - - virtual PassRefPtr<WebCore::ResourceLoaderAndroid> startLoadingResource( - ResourceHandle* handle, const ResourceRequest& req, bool, bool); - - virtual bool canHandleRequest(const ResourceRequest&) { return true; } - -private: - void timerFired(Timer<MyWebFrame>*); - Vector<RefPtr<WebCore::ResourceLoaderAndroid> > m_requests; - Timer<MyWebFrame> m_timer; -}; - -#endif diff --git a/Source/WebKit/android/benchmark/MyJavaVM.cpp b/Source/WebKit/android/benchmark/MyJavaVM.cpp deleted file mode 100644 index 574c745..0000000 --- a/Source/WebKit/android/benchmark/MyJavaVM.cpp +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright 2009, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "MyJavaVM.h" - -#include <JNIUtility.h> -#include <jni.h> - -static JNIEnv* s_env; -static JavaVM* s_jvm; - -// JavaVM functions -jint vm_attachCurrentThread(JavaVM*, JNIEnv** env, void*) { - *env = s_env; - return JNI_OK; -} - -// JNIEnv functions -jobject env_callObjectMethodV(JNIEnv*, jobject, jmethodID, va_list) { - return MY_JOBJECT; -} -void env_callVoidMethodV(JNIEnv*, jobject, jmethodID, va_list) {} -void env_deleteRef(JNIEnv*, jobject) {} -jboolean env_exceptionCheck(JNIEnv*) { - return false; -} -jclass env_findClass(JNIEnv*, const char*) { - return (jclass) 1; -} -jbyte* env_getByteArrayElements(JNIEnv*, jbyteArray, jboolean*) { - return NULL; -} -jmethodID env_getMethodID(JNIEnv*, jclass, const char*, const char*) { - return (jmethodID) 1; -} -jclass env_getObjectClass(JNIEnv*, jobject) { - return (jclass) 1; -} -static const char* s_fakeString = "Fake Java String"; -const jchar* env_getStringChars(JNIEnv*, jstring, jboolean* isCopy) { - if (isCopy) - *isCopy = false; - return (const jchar*)s_fakeString; -} -jsize env_getStringLength(JNIEnv*, jstring) { - return sizeof(s_fakeString) - 1; -} -jbyteArray env_newByteArray(JNIEnv*, jsize) { - return (jbyteArray) 1; -} -jobject env_newRef(JNIEnv*, jobject obj) { - return obj; -} -jobject env_newObjectV(JNIEnv*, jclass, jmethodID, va_list) { - return MY_JOBJECT; -} -jstring env_newString(JNIEnv*, const jchar*, jsize) { - return (jstring) 1; -} -void env_releaseByteArrayElements(JNIEnv*, jbyteArray, jbyte*, jint) {} -void env_releaseStringChars(JNIEnv*, jstring, const jchar*) {} -void env_setByteArrayRegion(JNIEnv*, jbyteArray, jsize, jsize, const jbyte*) {} -void env_setIntField(JNIEnv*, jobject, jfieldID, jint) {} - -void InitializeJavaVM() { - // First, create the fake vm - s_jvm = new JavaVM; - JNIInvokeInterface* i = new JNIInvokeInterface; - memset(i, 0, sizeof(JNIInvokeInterface)); - s_jvm->functions = i; - - // Now, assign the functions of the vm to our fake ones. - i->AttachCurrentThread = vm_attachCurrentThread; - - // Create the fake env next - s_env = new JNIEnv; - JNINativeInterface* n = new JNINativeInterface; - memset(n, 0, sizeof(JNINativeInterface)); - s_env->functions = n; - - // Point the functions we care about to out fake ones. - n->CallObjectMethodV = env_callObjectMethodV; - n->CallVoidMethodV = env_callVoidMethodV; - n->DeleteLocalRef = env_deleteRef; - n->DeleteGlobalRef = env_deleteRef; - n->DeleteWeakGlobalRef = env_deleteRef; - n->ExceptionCheck = env_exceptionCheck; - n->FindClass = env_findClass; - n->GetByteArrayElements = env_getByteArrayElements; - n->GetMethodID = env_getMethodID; - n->GetObjectClass = env_getObjectClass; - n->GetStringChars = env_getStringChars; - n->GetStringLength = env_getStringLength; - n->NewByteArray = env_newByteArray; - n->NewLocalRef = env_newRef; - n->NewGlobalRef = env_newRef; - n->NewWeakGlobalRef = env_newRef; - n->NewObjectV = env_newObjectV; - n->NewString = env_newString; - n->ReleaseByteArrayElements = env_releaseByteArrayElements; - n->ReleaseStringChars = env_releaseStringChars; - n->SetByteArrayRegion = env_setByteArrayRegion; - n->SetIntField = env_setIntField; - - // Tell WebCore about the vm - JSC::Bindings::setJavaVM(s_jvm); -} diff --git a/Source/WebKit/android/benchmark/main.cpp b/Source/WebKit/android/benchmark/main.cpp deleted file mode 100644 index fcb797d..0000000 --- a/Source/WebKit/android/benchmark/main.cpp +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2009, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#define LOG_TAG "webcore_test" - -#include <stdlib.h> -#include <string.h> -#include <getopt.h> -#include <utils/Log.h> - -namespace android { -extern void benchmark(const char*, int, int ,int); -} - -int main(int argc, char** argv) { - int width = 800; - int height = 600; - int reloadCount = 0; - while (true) { - int c = getopt(argc, argv, "d:r:"); - if (c == -1) - break; - else if (c == 'd') { - char* x = strchr(optarg, 'x'); - if (x) { - width = atoi(optarg); - height = atoi(x + 1); - LOGD("Rendering page at %dx%d", width, height); - } - } else if (c == 'r') { - reloadCount = atoi(optarg); - if (reloadCount < 0) - reloadCount = 0; - LOGD("Reloading %d times", reloadCount); - } - } - if (optind >= argc) { - LOGE("Please supply a file to read\n"); - return 1; - } - - android::benchmark(argv[optind], reloadCount, width, height); -} diff --git a/Source/WebKit/android/content/PhoneEmailDetector.cpp b/Source/WebKit/android/content/PhoneEmailDetector.cpp new file mode 100644 index 0000000..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 new file mode 100644 index 0000000..16dd809 --- /dev/null +++ b/Source/WebKit/android/jni/AndroidHitTestResult.cpp @@ -0,0 +1,264 @@ +/* + * Copyright 2012, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define LOG_TAG "AndroidHitTestResult" + +#include "config.h" +#include "AndroidHitTestResult.h" + +#include "content/address_detector.h" +#include "content/PhoneEmailDetector.h" +#include "android/WebHitTestInfo.h" +#include "Document.h" +#include "Element.h" +#include "Frame.h" +#include "HitTestResult.h" +#include "KURL.h" +#include "LayerAndroid.h" +#include "PlatformString.h" +#include "Range.h" +#include "RenderLayer.h" +#include "RenderLayerBacking.h" +#include "RenderObject.h" +#include "WebCoreJni.h" +#include "WebViewCore.h" + +#include <cutils/log.h> +#include <JNIHelp.h> +#include <JNIUtility.h> + +namespace android { + +using namespace WebCore; + +static bool gJniInitialized = false; +static struct { + jmethodID m_Init; + jfieldID m_LinkUrl; + jfieldID m_AnchorText; + jfieldID m_ImageUrl; + jfieldID m_AltDisplayString; + jfieldID m_Title; + jfieldID m_Editable; + jfieldID m_TouchRects; + jfieldID m_TapHighlightColor; + jfieldID m_EnclosingParentRects; + jfieldID m_HasFocus; + jfieldID m_IntentUrl; +} gHitTestGlue; + +struct field { + jclass m_class; + const char *m_fieldName; + const char *m_fieldType; + jfieldID *m_jfield; +}; + +static void InitJni(JNIEnv* env) +{ + if (gJniInitialized) + return; + + jclass rectClass = env->FindClass("android/graphics/Rect"); + ALOG_ASSERT(rectClass, "Could not find android/graphics/Rect"); + jclass hitTestClass = env->FindClass("android/webkit/WebViewCore$WebKitHitTest"); + ALOG_ASSERT(hitTestClass, "Could not find android/webkit/WebViewCore$WebKitHitTest"); + + gHitTestGlue.m_Init = env->GetMethodID(hitTestClass, "<init>", "()V"); + ALOG_ASSERT(gHitTestGlue.m_Init, "Could not find init method on android/webkit/WebViewCore$WebKitHitTest"); + + field fields[] = { + { hitTestClass, "mTouchRects", "[Landroid/graphics/Rect;", &gHitTestGlue.m_TouchRects }, + { hitTestClass, "mEditable", "Z", &gHitTestGlue.m_Editable }, + { hitTestClass, "mLinkUrl", "Ljava/lang/String;", &gHitTestGlue.m_LinkUrl }, + { hitTestClass, "mIntentUrl", "Ljava/lang/String;", &gHitTestGlue.m_IntentUrl }, + { hitTestClass, "mAnchorText", "Ljava/lang/String;", &gHitTestGlue.m_AnchorText }, + { hitTestClass, "mImageUrl", "Ljava/lang/String;", &gHitTestGlue.m_ImageUrl }, + { hitTestClass, "mAltDisplayString", "Ljava/lang/String;", &gHitTestGlue.m_AltDisplayString }, + { hitTestClass, "mTitle", "Ljava/lang/String;", &gHitTestGlue.m_Title }, + { hitTestClass, "mTapHighlightColor", "I", &gHitTestGlue.m_TapHighlightColor }, + { hitTestClass, "mEnclosingParentRects", "[Landroid/graphics/Rect;", &gHitTestGlue.m_EnclosingParentRects }, + { hitTestClass, "mHasFocus", "Z", &gHitTestGlue.m_HasFocus }, + {0, 0, 0, 0}, + }; + + for (int i = 0; fields[i].m_jfield; i++) { + field *f = &fields[i]; + jfieldID field = env->GetFieldID(f->m_class, f->m_fieldName, f->m_fieldType); + ALOG_ASSERT(field, "Can't find %s", f->m_fieldName); + *(f->m_jfield) = field; + } + + gJniInitialized = true; +} + +AndroidHitTestResult::AndroidHitTestResult(WebViewCore* webViewCore, WebCore::HitTestResult& hitTestResult) + : m_webViewCore(webViewCore) + , m_hitTestResult(hitTestResult) +{ + buildHighlightRects(); +} + +void AndroidHitTestResult::setURLElement(Element* element) +{ + m_hitTestResult.setURLElement(element); + buildHighlightRects(); +} + +void AndroidHitTestResult::buildHighlightRects() +{ + m_highlightRects.clear(); + Node* node = m_hitTestResult.URLElement(); + if (!node || !node->renderer()) + node = m_hitTestResult.innerNode(); + if (!node || !node->renderer()) + return; + Frame* frame = node->document()->frame(); + IntPoint frameOffset = m_webViewCore->convertGlobalContentToFrameContent(IntPoint(), frame); + RenderObject* renderer = node->renderer(); + Vector<FloatQuad> quads; + renderer->absoluteFocusRingQuads(quads); + for (size_t i = 0; i < quads.size(); i++) { + IntRect boundingBox = quads[i].enclosingBoundingBox(); + boundingBox.move(-frameOffset.x(), -frameOffset.y()); + m_highlightRects.append(boundingBox); + } +} + +void AndroidHitTestResult::searchContentDetectors() +{ + AddressDetector address; + PhoneEmailDetector phoneEmail; + Node* node = m_hitTestResult.innerNode(); + if (!node || !node->isTextNode()) + return; + if (!m_hitTestResult.absoluteLinkURL().isEmpty()) + return; + WebKit::WebHitTestInfo webHitTest(m_hitTestResult); + m_searchResult = address.FindTappedContent(webHitTest); + if (!m_searchResult.valid) { + m_searchResult = phoneEmail.FindTappedContent(webHitTest); + } + if (m_searchResult.valid) { + m_highlightRects.clear(); + RefPtr<Range> range = (PassRefPtr<Range>) m_searchResult.range; + range->textRects(m_highlightRects, true); + } +} + +void setStringField(JNIEnv* env, jobject obj, jfieldID field, const String& str) +{ + jstring jstr = wtfStringToJstring(env, str, false); + env->SetObjectField(obj, field, jstr); + env->DeleteLocalRef(jstr); +} + +void setStringField(JNIEnv* env, jobject obj, jfieldID field, const GURL& url) +{ + jstring jstr = stdStringToJstring(env, url.spec(), false); + env->SetObjectField(obj, field, jstr); + env->DeleteLocalRef(jstr); +} + +void setRectArray(JNIEnv* env, jobject obj, jfieldID field, Vector<IntRect> &rects) +{ + jobjectArray array = intRectVectorToRectArray(env, rects); + env->SetObjectField(obj, field, array); + env->DeleteLocalRef(array); +} + +// Some helper macros specific to setting hitTest fields +#define _SET(jtype, jfield, value) env->Set ## jtype ## Field(hitTest, gHitTestGlue.m_ ## jfield, value) +#define SET_BOOL(jfield, value) _SET(Boolean, jfield, value) +#define SET_STRING(jfield, value) setStringField(env, hitTest, gHitTestGlue.m_ ## jfield, value) +#define SET_INT(jfield, value) _SET(Int, jfield, value) + +jobject AndroidHitTestResult::createJavaObject(JNIEnv* env) +{ + InitJni(env); + jclass hitTestClass = env->FindClass("android/webkit/WebViewCore$WebKitHitTest"); + ALOG_ASSERT(hitTestClass, "Could not find android/webkit/WebViewCore$WebKitHitTest"); + + jobject hitTest = env->NewObject(hitTestClass, gHitTestGlue.m_Init); + setRectArray(env, hitTest, gHitTestGlue.m_TouchRects, m_highlightRects); + + Vector<IntRect> rects = enclosingParentRects(m_hitTestResult.innerNode()); + setRectArray(env, hitTest, gHitTestGlue.m_EnclosingParentRects, rects); + + SET_BOOL(Editable, m_hitTestResult.isContentEditable()); + SET_STRING(LinkUrl, m_hitTestResult.absoluteLinkURL().string()); + if (m_searchResult.valid) + SET_STRING(IntentUrl, m_searchResult.intent_url); + SET_STRING(ImageUrl, m_hitTestResult.absoluteImageURL().string()); + SET_STRING(AltDisplayString, m_hitTestResult.altDisplayString()); + TextDirection titleTextDirection; + SET_STRING(Title, m_hitTestResult.title(titleTextDirection)); + if (m_hitTestResult.URLElement()) { + Element* urlElement = m_hitTestResult.URLElement(); + SET_STRING(AnchorText, urlElement->innerText()); + if (urlElement->renderer()) { + SET_INT(TapHighlightColor, + urlElement->renderer()->style()->tapHighlightColor().rgb()); + } + } + Node* focusedNode = m_webViewCore->focusedFrame()->document()->focusedNode(); + SET_BOOL(HasFocus, + focusedNode == m_hitTestResult.URLElement() + || focusedNode == m_hitTestResult.innerNode() + || focusedNode == m_hitTestResult.innerNonSharedNode()); + + env->DeleteLocalRef(hitTestClass); + + return hitTest; +} + +Vector<IntRect> AndroidHitTestResult::enclosingParentRects(Node* node) +{ + int count = 0; + int lastX = 0; + Vector<IntRect> rects; + + while (node && count < 5) { + RenderObject* render = node->renderer(); + if (!render || render->isBody()) + break; + + IntPoint frameOffset = m_webViewCore->convertGlobalContentToFrameContent(IntPoint(), + node->document()->frame()); + IntRect rect = render->absoluteBoundingBoxRect(); + rect.move(-frameOffset.x(), -frameOffset.y()); + if (count == 0 || rect.x() != lastX) { + rects.append(rect); + lastX = rect.x(); + count++; + } + + node = node->parentNode(); + } + + return rects; +} + +} /* namespace android */ diff --git a/Source/WebKit/android/RenderSkinRadio.h b/Source/WebKit/android/jni/AndroidHitTestResult.h index 34101cf..5bbfc6b 100644 --- a/Source/WebKit/android/RenderSkinRadio.h +++ b/Source/WebKit/android/jni/AndroidHitTestResult.h @@ -1,5 +1,5 @@ /* - * Copyright 2006, The Android Open Source Project + * Copyright 2012, The Android Open Source Project * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,39 +23,45 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef RenderSkinRadio_h -#define RenderSkinRadio_h +#ifndef AndroidHitTestResult_h +#define AndroidHitTestResult_h -#include "PlatformString.h" +#include "content/content_detector.h" +#include "Element.h" +#include "HitTestResult.h" +#include "IntRect.h" +#include "wtf/Vector.h" -class SkCanvas; +#include <jni.h> namespace android { - class AssetManager; -} -namespace WebCore { +class WebViewCore; -class Node; -class IntRect; - -/* RenderSkin for a radio button or a checkbox - */ -class RenderSkinRadio +class AndroidHitTestResult { public: - static void SetDrawableDirectory(String drawableDirectory); + AndroidHitTestResult(WebViewCore*, WebCore::HitTestResult&); + ~AndroidHitTestResult() {} + + WebCore::HitTestResult& hitTestResult() { return m_hitTestResult; } + Vector<WebCore::IntRect>& highlightRects() { return m_highlightRects; } - // Perform lazy decoding the first time this a radio/checkbox is needed. - static void Decode(); + void setURLElement(WebCore::Element* element); + void buildHighlightRects(); + void searchContentDetectors(); - /** - * Draw the element to the canvas at the specified size and location. - * param isCheckBox If true, draws a checkbox. Else, draw a radio button. - */ - static void Draw(SkCanvas* canvas, Node* element, const IntRect&, - bool isCheckBox); + jobject createJavaObject(JNIEnv*); + +private: + Vector<WebCore::IntRect> enclosingParentRects(WebCore::Node* node); + + WebViewCore* m_webViewCore; + WebCore::HitTestResult m_hitTestResult; + Vector<WebCore::IntRect> m_highlightRects; + ContentDetector::Result m_searchResult; }; -} // WebCore -#endif +} // namespace android + +#endif // AndroidHitTestResult_h diff --git a/Source/WebKit/android/jni/CacheManager.cpp b/Source/WebKit/android/jni/CacheManager.cpp index f600d00..b34776d 100644 --- a/Source/WebKit/android/jni/CacheManager.cpp +++ b/Source/WebKit/android/jni/CacheManager.cpp @@ -25,8 +25,6 @@ #include "config.h" -#if USE(CHROME_NETWORK_STACK) - #include "ChromiumIncludes.h" #include "WebCache.h" #include "WebCoreJni.h" @@ -133,12 +131,10 @@ int registerCacheManager(JNIEnv* env) { #ifndef NDEBUG jclass cacheManager = env->FindClass(javaCacheManagerClass); - LOG_ASSERT(cacheManager, "Unable to find class"); + ALOG_ASSERT(cacheManager, "Unable to find class"); env->DeleteLocalRef(cacheManager); #endif return jniRegisterNativeMethods(env, javaCacheManagerClass, gCacheManagerMethods, NELEM(gCacheManagerMethods)); } } // namespace android - -#endif // USE(CHROME_NETWORK_STACK) diff --git a/Source/WebKit/android/jni/CookieManager.cpp b/Source/WebKit/android/jni/CookieManager.cpp index f8c2dee..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[] = { @@ -192,7 +151,7 @@ int registerCookieManager(JNIEnv* env) { #ifndef NDEBUG jclass cookieManager = env->FindClass(javaCookieManagerClass); - LOG_ASSERT(cookieManager, "Unable to find class"); + ALOG_ASSERT(cookieManager, "Unable to find class"); env->DeleteLocalRef(cookieManager); #endif return jniRegisterNativeMethods(env, javaCookieManagerClass, gCookieManagerMethods, NELEM(gCookieManagerMethods)); diff --git a/Source/WebKit/android/jni/DeviceMotionAndOrientationManager.cpp b/Source/WebKit/android/jni/DeviceMotionAndOrientationManager.cpp index 8beb372..bd63f59 100644 --- a/Source/WebKit/android/jni/DeviceMotionAndOrientationManager.cpp +++ b/Source/WebKit/android/jni/DeviceMotionAndOrientationManager.cpp @@ -161,7 +161,7 @@ int registerDeviceMotionAndOrientationManager(JNIEnv* env) { #ifndef NDEBUG jclass deviceMotionAndOrientationManager = env->FindClass(javaDeviceMotionAndOrientationManagerClass); - LOG_ASSERT(deviceMotionAndOrientationManager, "Unable to find class"); + ALOG_ASSERT(deviceMotionAndOrientationManager, "Unable to find class"); env->DeleteLocalRef(deviceMotionAndOrientationManager); #endif diff --git a/Source/WebKit/android/jni/GeolocationPermissionsBridge.cpp b/Source/WebKit/android/jni/GeolocationPermissionsBridge.cpp index a366601..2c1db3f 100755 --- a/Source/WebKit/android/jni/GeolocationPermissionsBridge.cpp +++ b/Source/WebKit/android/jni/GeolocationPermissionsBridge.cpp @@ -102,7 +102,7 @@ int registerGeolocationPermissions(JNIEnv* env) const char* kGeolocationPermissionsClass = "android/webkit/GeolocationPermissions"; #ifndef NDEBUG jclass geolocationPermissions = env->FindClass(kGeolocationPermissionsClass); - LOG_ASSERT(geolocationPermissions, "Unable to find class"); + ALOG_ASSERT(geolocationPermissions, "Unable to find class"); env->DeleteLocalRef(geolocationPermissions); #endif diff --git a/Source/WebKit/android/jni/JavaBridge.cpp b/Source/WebKit/android/jni/JavaBridge.cpp index 68eb367..4c8234b 100644 --- a/Source/WebKit/android/jni/JavaBridge.cpp +++ b/Source/WebKit/android/jni/JavaBridge.cpp @@ -41,9 +41,6 @@ #include "PluginDatabase.h" #include "Timer.h" #include "TimerClient.h" -#ifdef ANDROID_INSTRUMENT -#include "TimeCounter.h" -#endif #include "WebCache.h" #include "WebCoreJni.h" @@ -148,15 +145,15 @@ JavaBridge::JavaBridge(JNIEnv* env, jobject obj) mResolveFilePathForContentUri = env->GetMethodID(clazz, "resolveFilePathForContentUri", "(Ljava/lang/String;)Ljava/lang/String;"); env->DeleteLocalRef(clazz); - LOG_ASSERT(mSetSharedTimer, "Could not find method setSharedTimer"); - LOG_ASSERT(mStopSharedTimer, "Could not find method stopSharedTimer"); - LOG_ASSERT(mSetCookies, "Could not find method setCookies"); - LOG_ASSERT(mCookies, "Could not find method cookies"); - LOG_ASSERT(mCookiesEnabled, "Could not find method cookiesEnabled"); - LOG_ASSERT(mGetPluginDirectories, "Could not find method getPluginDirectories"); - LOG_ASSERT(mGetPluginSharedDataDirectory, "Could not find method getPluginSharedDataDirectory"); - LOG_ASSERT(mGetKeyStrengthList, "Could not find method getKeyStrengthList"); - LOG_ASSERT(mGetSignedPublicKey, "Could not find method getSignedPublicKey"); + ALOG_ASSERT(mSetSharedTimer, "Could not find method setSharedTimer"); + ALOG_ASSERT(mStopSharedTimer, "Could not find method stopSharedTimer"); + ALOG_ASSERT(mSetCookies, "Could not find method setCookies"); + ALOG_ASSERT(mCookies, "Could not find method cookies"); + ALOG_ASSERT(mCookiesEnabled, "Could not find method cookiesEnabled"); + ALOG_ASSERT(mGetPluginDirectories, "Could not find method getPluginDirectories"); + ALOG_ASSERT(mGetPluginSharedDataDirectory, "Could not find method getPluginSharedDataDirectory"); + ALOG_ASSERT(mGetKeyStrengthList, "Could not find method getKeyStrengthList"); + ALOG_ASSERT(mGetSignedPublicKey, "Could not find method getSignedPublicKey"); JavaSharedClient::SetTimerClient(this); JavaSharedClient::SetCookieClient(this); @@ -283,7 +280,7 @@ JavaBridge::getPluginSharedDataDirectory() void JavaBridge::setSharedTimerCallback(void (*f)()) { - LOG_ASSERT(!sSharedTimerFiredCallback || sSharedTimerFiredCallback==f, + ALOG_ASSERT(!sSharedTimerFiredCallback || sSharedTimerFiredCallback==f, "Shared timer callback may already be set or null!"); sSharedTimerFiredCallback = f; @@ -363,8 +360,8 @@ void JavaBridge::Finalize(JNIEnv* env, jobject obj) { JavaBridge* javaBridge = (JavaBridge*) (env->GetIntField(obj, gJavaBridge_ObjectID)); - LOG_ASSERT(javaBridge, "Finalize should not be called twice for the same java bridge!"); - LOGV("webcore_javabridge::nativeFinalize(%p)\n", javaBridge); + ALOG_ASSERT(javaBridge, "Finalize should not be called twice for the same java bridge!"); + ALOGV("webcore_javabridge::nativeFinalize(%p)\n", javaBridge); delete javaBridge; env->SetIntField(obj, gJavaBridge_ObjectID, 0); } @@ -374,14 +371,8 @@ void JavaBridge::SharedTimerFired(JNIEnv* env, jobject) { if (sSharedTimerFiredCallback) { -#ifdef ANDROID_INSTRUMENT - TimeCounter::start(TimeCounter::SharedTimerTimeCounter); -#endif SkAutoMemoryUsageProbe mup("JavaBridge::sharedTimerFired"); sSharedTimerFiredCallback(); -#ifdef ANDROID_INSTRUMENT - TimeCounter::record(TimeCounter::SharedTimerTimeCounter, __FUNCTION__); -#endif } } @@ -481,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/JavaSharedClient.cpp b/Source/WebKit/android/jni/JavaSharedClient.cpp index 4f40355..4d073c2 100644 --- a/Source/WebKit/android/jni/JavaSharedClient.cpp +++ b/Source/WebKit/android/jni/JavaSharedClient.cpp @@ -88,12 +88,12 @@ namespace android { FileSystemClient* JavaSharedClient::gFileSystemClient = NULL; /////////////////////////////////////////////////////////////////////////// - + struct FuncPtrRec { void (*fProc)(void* payload); void* fPayload; }; - + static SkMutex gFuncPtrQMutex; static SkDeque gFuncPtrQ(sizeof(FuncPtrRec)); @@ -105,33 +105,34 @@ namespace android { FuncPtrRec* rec = (FuncPtrRec*)gFuncPtrQ.push_back(); rec->fProc = proc; rec->fPayload = payload; - + gFuncPtrQMutex.release(); - + gTimerClient->signalServiceFuncPtrQueue(); } void JavaSharedClient::ServiceFunctionPtrQueue() { - for (;;) { - void (*proc)(void*) = 0; - void* payload = 0; - const FuncPtrRec* rec; - - // we have to copy the proc/payload (if present). we do this so we - // don't call the proc inside the mutex (possible deadlock!) - gFuncPtrQMutex.acquire(); - rec = (const FuncPtrRec*)gFuncPtrQ.front(); - if (rec) { - proc = rec->fProc; - payload = rec->fPayload; - gFuncPtrQ.pop_front(); - } - gFuncPtrQMutex.release(); - - if (!rec) - break; - proc(payload); + // Don't let execution block the WebViewCore thread for too long. + void (*proc)(void*) = 0; + void* payload = 0; + const FuncPtrRec* rec; + + // we have to copy the proc/payload (if present). we do this so we + // don't call the proc inside the mutex (possible deadlock!) + gFuncPtrQMutex.acquire(); + rec = (const FuncPtrRec*)gFuncPtrQ.front(); + if (rec) { + proc = rec->fProc; + payload = rec->fPayload; + gFuncPtrQ.pop_front(); } + bool scheduleAdditionalCall = (gFuncPtrQ.count() > 0); + gFuncPtrQMutex.release(); + + if (rec) + proc(payload); + if (scheduleAdditionalCall) + gTimerClient->signalServiceFuncPtrQueue(); } } diff --git a/Source/WebKit/android/jni/JniUtil.cpp b/Source/WebKit/android/jni/JniUtil.cpp deleted file mode 100644 index ee1e3f9..0000000 --- a/Source/WebKit/android/jni/JniUtil.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2010, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" - -#include "ChromiumIncludes.h" -#include <JNIHelp.h> - -namespace android { - -static const char* javaJniUtilClass = "android/webkit/JniUtil"; - -static bool useChromiumHttpStack(JNIEnv*, jobject) -{ -#if USE(CHROME_NETWORK_STACK) - return true; -#else - return false; -#endif -} - -static JNINativeMethod gJniUtilMethods[] = { - { "nativeUseChromiumHttpStack", "()Z", (void*) useChromiumHttpStack }, -}; - -int registerJniUtil(JNIEnv* env) -{ -#ifndef NDEBUG - jclass jniUtil = env->FindClass(javaJniUtilClass); - LOG_ASSERT(jniUtil, "Unable to find class"); - env->DeleteLocalRef(jniUtil); -#endif - return jniRegisterNativeMethods(env, javaJniUtilClass, gJniUtilMethods, NELEM(gJniUtilMethods)); -} - -} // namespace android diff --git a/Source/WebKit/android/jni/MIMETypeRegistry.cpp b/Source/WebKit/android/jni/MIMETypeRegistry.cpp index cbfef6c..2734aeb 100644 --- a/Source/WebKit/android/jni/MIMETypeRegistry.cpp +++ b/Source/WebKit/android/jni/MIMETypeRegistry.cpp @@ -44,11 +44,11 @@ String MIMETypeRegistry::getMIMETypeForExtension(const String& ext) ASSERT(isMainThread()); JNIEnv* env = JSC::Bindings::getJNIEnv(); jclass mimeClass = env->FindClass("android/webkit/MimeTypeMap"); - LOG_ASSERT(mimeClass, "Could not find class MimeTypeMap"); + ALOG_ASSERT(mimeClass, "Could not find class MimeTypeMap"); jmethodID mimeTypeFromExtension = env->GetStaticMethodID(mimeClass, "mimeTypeFromExtension", "(Ljava/lang/String;)Ljava/lang/String;"); - LOG_ASSERT(mimeTypeFromExtension, + ALOG_ASSERT(mimeTypeFromExtension, "Could not find method mimeTypeFromExtension"); jstring extString = wtfStringToJstring(env, ext); jobject mimeType = env->CallStaticObjectMethod(mimeClass, diff --git a/Source/WebKit/android/jni/MockGeolocation.cpp b/Source/WebKit/android/jni/MockGeolocation.cpp index 1370715..250953f 100755 --- a/Source/WebKit/android/jni/MockGeolocation.cpp +++ b/Source/WebKit/android/jni/MockGeolocation.cpp @@ -74,7 +74,7 @@ int registerMockGeolocation(JNIEnv* env) { #ifndef NDEBUG jclass mockGeolocation = env->FindClass(javaMockGeolocationClass); - LOG_ASSERT(mockGeolocation, "Unable to find class"); + ALOG_ASSERT(mockGeolocation, "Unable to find class"); env->DeleteLocalRef(mockGeolocation); #endif diff --git a/Source/WebKit/android/jni/PictureSet.cpp b/Source/WebKit/android/jni/PictureSet.cpp index 4d9d16c..89b16dc 100644 --- a/Source/WebKit/android/jni/PictureSet.cpp +++ b/Source/WebKit/android/jni/PictureSet.cpp @@ -26,17 +26,16 @@ #define LOG_NDEBUG 0 #define LOG_TAG "pictureset" -//#include <config.h> -#include "CachedPrefix.h" -#include "android_graphics.h" +#include "config.h" #include "PictureSet.h" + +#include "android_graphics.h" #include "SkBounder.h" #include "SkCanvas.h" #include "SkPicture.h" #include "SkRect.h" #include "SkRegion.h" #include "SkStream.h" -#include "TimeCounter.h" #define MAX_DRAW_TIME 100 #define MIN_SPLITTABLE 400 @@ -693,6 +692,22 @@ void PictureSet::clear() mWidth = mHeight = 0; } +uint32_t getThreadMsec() +{ +#if defined(HAVE_POSIX_CLOCKS) + struct timespec tm; + + clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tm); + return tm.tv_sec * 1000LL + tm.tv_nsec / 1000000; +#else + struct timeval now; + struct timezone zone; + + gettimeofday(&now, &zone); + return now.tv_sec * 1000LL + now.tv_usec / 1000; +#endif +} + bool PictureSet::draw(SkCanvas* canvas) { #ifdef FAST_PICTURESET @@ -835,7 +850,7 @@ void PictureSet::dump(const char* label) const MeasureStream measure; if (working->mPicture != NULL) working->mPicture->serialize(&measure); - LOGD(" [%d]" + ALOGD(" [%d]" " mArea.bounds={%d,%d,r=%d,b=%d}" " mPicture=%p" " mUnsplit={%d,%d,r=%d,b=%d}" @@ -1184,24 +1199,24 @@ bool PictureSet::validate(const char* funct) const const SkIRect& bounds = area.getBounds(); bool localValid = false; if (working->mUnsplit.isEmpty()) - LOGD("%s working->mUnsplit.isEmpty()", funct); + ALOGD("%s working->mUnsplit.isEmpty()", funct); else if (working->mUnsplit.contains(bounds) == false) - LOGD("%s working->mUnsplit.contains(bounds) == false", funct); + ALOGD("%s working->mUnsplit.contains(bounds) == false", funct); else if (working->mElapsed >= 1000) - LOGD("%s working->mElapsed >= 1000", funct); + ALOGD("%s working->mElapsed >= 1000", funct); else if ((working->mSplit & 0xfe) != 0) - LOGD("%s (working->mSplit & 0xfe) != 0", funct); + ALOGD("%s (working->mSplit & 0xfe) != 0", funct); else if ((working->mWroteElapsed & 0xfe) != 0) - LOGD("%s (working->mWroteElapsed & 0xfe) != 0", funct); + ALOGD("%s (working->mWroteElapsed & 0xfe) != 0", funct); else if (pict != NULL) { int pictWidth = pict->width(); int pictHeight = pict->height(); if (pictWidth < bounds.width()) - LOGD("%s pictWidth=%d < bounds.width()=%d", funct, pictWidth, bounds.width()); + ALOGD("%s pictWidth=%d < bounds.width()=%d", funct, pictWidth, bounds.width()); else if (pictHeight < bounds.height()) - LOGD("%s pictHeight=%d < bounds.height()=%d", funct, pictHeight, bounds.height()); + ALOGD("%s pictHeight=%d < bounds.height()=%d", funct, pictHeight, bounds.height()); else if (working->mArea.isEmpty()) - LOGD("%s working->mArea.isEmpty()", funct); + ALOGD("%s working->mArea.isEmpty()", funct); else localValid = true; } else @@ -1209,7 +1224,7 @@ bool PictureSet::validate(const char* funct) const working->mArea.validate(); if (localValid == false) { if (all.contains(area) == true) - LOGD("%s all.contains(area) == true", funct); + ALOGD("%s all.contains(area) == true", funct); else localValid = true; } @@ -1220,9 +1235,9 @@ bool PictureSet::validate(const char* funct) const if (valid) { valid = false; if (allBounds.width() != mWidth) - LOGD("%s allBounds.width()=%d != mWidth=%d", funct, allBounds.width(), mWidth); + ALOGD("%s allBounds.width()=%d != mWidth=%d", funct, allBounds.width(), mWidth); else if (allBounds.height() != mHeight) - LOGD("%s allBounds.height()=%d != mHeight=%d", funct, allBounds.height(), mHeight); + ALOGD("%s allBounds.height()=%d != mHeight=%d", funct, allBounds.height(), mHeight); else valid = true; } diff --git a/Source/WebKit/android/jni/PictureSet.h b/Source/WebKit/android/jni/PictureSet.h index fe47361..97d91e0 100644 --- a/Source/WebKit/android/jni/PictureSet.h +++ b/Source/WebKit/android/jni/PictureSet.h @@ -31,9 +31,9 @@ #define PICTURE_SET_VALIDATE 0 #if PICTURE_SET_DEBUG -#define DBG_SET_LOG(message) LOGD("%s %s", __FUNCTION__, message) -#define DBG_SET_LOGD(format, ...) LOGD("%s " format, __FUNCTION__, __VA_ARGS__) -#define DEBUG_SET_UI_LOGD(...) LOGD(__VA_ARGS__) +#define DBG_SET_LOG(message) ALOGD("%s %s", __FUNCTION__, message) +#define DBG_SET_LOGD(format, ...) ALOGD("%s " format, __FUNCTION__, __VA_ARGS__) +#define DEBUG_SET_UI_LOGD(...) ALOGD(__VA_ARGS__) #else #define DBG_SET_LOG(message) ((void)0) #define DBG_SET_LOGD(format, ...) ((void)0) diff --git a/Source/WebKit/android/jni/WebCoreFrameBridge.cpp b/Source/WebKit/android/jni/WebCoreFrameBridge.cpp index d53ddb6..d0f3830 100644 --- a/Source/WebKit/android/jni/WebCoreFrameBridge.cpp +++ b/Source/WebKit/android/jni/WebCoreFrameBridge.cpp @@ -60,6 +60,8 @@ #include "IconDatabase.h" #include "Image.h" #include "InspectorClientAndroid.h" +#include "JavaNPObjectV8.h" +#include "JavaInstanceJobjectV8.h" #include "KURL.h" #include "Page.h" #include "PageCache.h" @@ -81,7 +83,6 @@ #include "WebArchiveAndroid.h" #include "WebCache.h" #include "WebCoreJni.h" -#include "WebCoreResourceLoader.h" #include "WebHistory.h" #include "WebIconDatabase.h" #include "WebFrameView.h" @@ -99,30 +100,13 @@ #include <android_runtime/android_util_AssetManager.h> #include <openssl/x509.h> #include <utils/misc.h> -#include <utils/AssetManager.h> +#include <androidfw/AssetManager.h> #include <wtf/CurrentTime.h> #include <wtf/Platform.h> #include <wtf/text/AtomicString.h> #include <wtf/text/CString.h> #include <wtf/text/StringBuilder.h> -#if USE(JSC) -#include "GCController.h" -#include "JSDOMWindow.h" -#include "JavaInstanceJSC.h" -#include <runtime_object.h> -#include <runtime_root.h> -#include <runtime/JSLock.h> -#elif USE(V8) -#include "JavaNPObjectV8.h" -#include "JavaInstanceJobjectV8.h" -#include "V8Counters.h" -#endif // USE(JSC) - -#ifdef ANDROID_INSTRUMENT -#include "TimeCounter.h" -#endif - #if ENABLE(WEB_AUTOFILL) #include "autofill/WebAutofill.h" #endif @@ -244,8 +228,6 @@ WebFrame::WebFrame(JNIEnv* env, jobject obj, jobject historyList, WebCore::Page* mJavaFrame = new JavaBrowserFrame; mJavaFrame->mObj = env->NewWeakGlobalRef(obj); mJavaFrame->mHistoryList = env->NewWeakGlobalRef(historyList); - mJavaFrame->mStartLoadingResource = env->GetMethodID(clazz, "startLoadingResource", - "(ILjava/lang/String;Ljava/lang/String;Ljava/util/HashMap;[BJIZZZLjava/lang/String;Ljava/lang/String;)Landroid/webkit/LoadListener;"); mJavaFrame->mMaybeSavePassword = env->GetMethodID(clazz, "maybeSavePassword", "([BLjava/lang/String;Ljava/lang/String;)V"); mJavaFrame->mShouldInterceptRequest = @@ -301,38 +283,37 @@ WebFrame::WebFrame(JNIEnv* env, jobject obj, jobject historyList, WebCore::Page* "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); env->DeleteLocalRef(clazz); - LOG_ASSERT(mJavaFrame->mStartLoadingResource, "Could not find method startLoadingResource"); - LOG_ASSERT(mJavaFrame->mMaybeSavePassword, "Could not find method maybeSavePassword"); - LOG_ASSERT(mJavaFrame->mShouldInterceptRequest, "Could not find method shouldInterceptRequest"); - LOG_ASSERT(mJavaFrame->mLoadStarted, "Could not find method loadStarted"); - LOG_ASSERT(mJavaFrame->mTransitionToCommitted, "Could not find method transitionToCommitted"); - LOG_ASSERT(mJavaFrame->mLoadFinished, "Could not find method loadFinished"); - LOG_ASSERT(mJavaFrame->mReportError, "Could not find method reportError"); - LOG_ASSERT(mJavaFrame->mSetTitle, "Could not find method setTitle"); - LOG_ASSERT(mJavaFrame->mWindowObjectCleared, "Could not find method windowObjectCleared"); - LOG_ASSERT(mJavaFrame->mSetProgress, "Could not find method setProgress"); - LOG_ASSERT(mJavaFrame->mDidReceiveIcon, "Could not find method didReceiveIcon"); - LOG_ASSERT(mJavaFrame->mDidReceiveTouchIconUrl, "Could not find method didReceiveTouchIconUrl"); - LOG_ASSERT(mJavaFrame->mUpdateVisitedHistory, "Could not find method updateVisitedHistory"); - LOG_ASSERT(mJavaFrame->mHandleUrl, "Could not find method handleUrl"); - LOG_ASSERT(mJavaFrame->mCreateWindow, "Could not find method createWindow"); - LOG_ASSERT(mJavaFrame->mCloseWindow, "Could not find method closeWindow"); - LOG_ASSERT(mJavaFrame->mDecidePolicyForFormResubmission, "Could not find method decidePolicyForFormResubmission"); - LOG_ASSERT(mJavaFrame->mRequestFocus, "Could not find method requestFocus"); - LOG_ASSERT(mJavaFrame->mGetRawResFilename, "Could not find method getRawResFilename"); - LOG_ASSERT(mJavaFrame->mDensity, "Could not find method density"); - LOG_ASSERT(mJavaFrame->mGetFileSize, "Could not find method getFileSize"); - LOG_ASSERT(mJavaFrame->mGetFile, "Could not find method getFile"); - LOG_ASSERT(mJavaFrame->mDidReceiveAuthenticationChallenge, "Could not find method didReceiveAuthenticationChallenge"); - LOG_ASSERT(mJavaFrame->mReportSslCertError, "Could not find method reportSslCertError"); - LOG_ASSERT(mJavaFrame->mRequestClientCert, "Could not find method requestClientCert"); - LOG_ASSERT(mJavaFrame->mDownloadStart, "Could not find method downloadStart"); - LOG_ASSERT(mJavaFrame->mDidReceiveData, "Could not find method didReceiveData"); - LOG_ASSERT(mJavaFrame->mDidFinishLoading, "Could not find method didFinishLoading"); - LOG_ASSERT(mJavaFrame->mSetCertificate, "Could not find method setCertificate"); - LOG_ASSERT(mJavaFrame->mShouldSaveFormData, "Could not find method shouldSaveFormData"); - LOG_ASSERT(mJavaFrame->mSaveFormData, "Could not find method saveFormData"); - LOG_ASSERT(mJavaFrame->mAutoLogin, "Could not find method autoLogin"); + ALOG_ASSERT(mJavaFrame->mMaybeSavePassword, "Could not find method maybeSavePassword"); + ALOG_ASSERT(mJavaFrame->mShouldInterceptRequest, "Could not find method shouldInterceptRequest"); + ALOG_ASSERT(mJavaFrame->mLoadStarted, "Could not find method loadStarted"); + ALOG_ASSERT(mJavaFrame->mTransitionToCommitted, "Could not find method transitionToCommitted"); + ALOG_ASSERT(mJavaFrame->mLoadFinished, "Could not find method loadFinished"); + ALOG_ASSERT(mJavaFrame->mReportError, "Could not find method reportError"); + ALOG_ASSERT(mJavaFrame->mSetTitle, "Could not find method setTitle"); + ALOG_ASSERT(mJavaFrame->mWindowObjectCleared, "Could not find method windowObjectCleared"); + ALOG_ASSERT(mJavaFrame->mSetProgress, "Could not find method setProgress"); + ALOG_ASSERT(mJavaFrame->mDidReceiveIcon, "Could not find method didReceiveIcon"); + ALOG_ASSERT(mJavaFrame->mDidReceiveTouchIconUrl, "Could not find method didReceiveTouchIconUrl"); + ALOG_ASSERT(mJavaFrame->mUpdateVisitedHistory, "Could not find method updateVisitedHistory"); + ALOG_ASSERT(mJavaFrame->mHandleUrl, "Could not find method handleUrl"); + ALOG_ASSERT(mJavaFrame->mCreateWindow, "Could not find method createWindow"); + ALOG_ASSERT(mJavaFrame->mCloseWindow, "Could not find method closeWindow"); + ALOG_ASSERT(mJavaFrame->mDecidePolicyForFormResubmission, "Could not find method decidePolicyForFormResubmission"); + ALOG_ASSERT(mJavaFrame->mRequestFocus, "Could not find method requestFocus"); + ALOG_ASSERT(mJavaFrame->mGetRawResFilename, "Could not find method getRawResFilename"); + ALOG_ASSERT(mJavaFrame->mDensity, "Could not find method density"); + ALOG_ASSERT(mJavaFrame->mGetFileSize, "Could not find method getFileSize"); + ALOG_ASSERT(mJavaFrame->mGetFile, "Could not find method getFile"); + ALOG_ASSERT(mJavaFrame->mDidReceiveAuthenticationChallenge, "Could not find method didReceiveAuthenticationChallenge"); + ALOG_ASSERT(mJavaFrame->mReportSslCertError, "Could not find method reportSslCertError"); + ALOG_ASSERT(mJavaFrame->mRequestClientCert, "Could not find method requestClientCert"); + ALOG_ASSERT(mJavaFrame->mDownloadStart, "Could not find method downloadStart"); + ALOG_ASSERT(mJavaFrame->mDidReceiveData, "Could not find method didReceiveData"); + ALOG_ASSERT(mJavaFrame->mDidFinishLoading, "Could not find method didFinishLoading"); + ALOG_ASSERT(mJavaFrame->mSetCertificate, "Could not find method setCertificate"); + ALOG_ASSERT(mJavaFrame->mShouldSaveFormData, "Could not find method shouldSaveFormData"); + ALOG_ASSERT(mJavaFrame->mSaveFormData, "Could not find method saveFormData"); + ALOG_ASSERT(mJavaFrame->mAutoLogin, "Could not find method autoLogin"); mUserAgent = WTF::String(); mUserInitiatedAction = false; @@ -362,14 +343,14 @@ WebFrame* WebFrame::getWebFrame(const WebCore::Frame* frame) static jobject createJavaMapFromHTTPHeaders(JNIEnv* env, const WebCore::HTTPHeaderMap& map) { jclass mapClass = env->FindClass("java/util/HashMap"); - LOG_ASSERT(mapClass, "Could not find HashMap class!"); + ALOG_ASSERT(mapClass, "Could not find HashMap class!"); jmethodID init = env->GetMethodID(mapClass, "<init>", "(I)V"); - LOG_ASSERT(init, "Could not find constructor for HashMap"); + ALOG_ASSERT(init, "Could not find constructor for HashMap"); jobject hashMap = env->NewObject(mapClass, init, map.size()); - LOG_ASSERT(hashMap, "Could not create a new HashMap"); + ALOG_ASSERT(hashMap, "Could not create a new HashMap"); jmethodID put = env->GetMethodID(mapClass, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); - LOG_ASSERT(put, "Could not find put method on HashMap"); + ALOG_ASSERT(put, "Could not find put method on HashMap"); WebCore::HTTPHeaderMap::const_iterator end = map.end(); for (WebCore::HTTPHeaderMap::const_iterator i = map.begin(); i != end; ++i) { @@ -416,104 +397,10 @@ private: int m_size; }; -PassRefPtr<WebCore::ResourceLoaderAndroid> -WebFrame::startLoadingResource(WebCore::ResourceHandle* loader, - const WebCore::ResourceRequest& request, - bool mainResource, - bool synchronous) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); -#endif - LOGV("::WebCore:: startLoadingResource(%p, %s)", - loader, request.url().string().latin1().data()); - - JNIEnv* env = getJNIEnv(); - AutoJObject javaFrame = mJavaFrame->frame(env); - if (!javaFrame.get()) - return 0; - - WTF::String method = request.httpMethod(); - WebCore::HTTPHeaderMap headers = request.httpHeaderFields(); - - WTF::String urlStr = request.url().string(); - int colon = urlStr.find(':'); - bool allLower = true; - for (int index = 0; index < colon; index++) { - UChar ch = urlStr[index]; - if (!WTF::isASCIIAlpha(ch)) - break; - allLower &= WTF::isASCIILower(ch); - if (index == colon - 1 && !allLower) { - urlStr = urlStr.substring(0, colon).lower() - + urlStr.substring(colon); - } - } - LOGV("%s lower=%s", __FUNCTION__, urlStr.latin1().data()); - jstring jUrlStr = wtfStringToJstring(env, urlStr); - jstring jMethodStr = NULL; - if (!method.isEmpty()) - jMethodStr = wtfStringToJstring(env, method); - WebCore::FormData* formdata = request.httpBody(); - jbyteArray jPostDataStr = getPostData(request); - jobject jHeaderMap = createJavaMapFromHTTPHeaders(env, headers); - - // Convert the WebCore Cache Policy to a WebView Cache Policy. - int cacheMode = 0; // WebSettings.LOAD_NORMAL - switch (request.cachePolicy()) { - case WebCore::ReloadIgnoringCacheData: - cacheMode = 2; // WebSettings.LOAD_NO_CACHE - break; - case WebCore::ReturnCacheDataDontLoad: - cacheMode = 3; // WebSettings.LOAD_CACHE_ONLY - break; - case WebCore::ReturnCacheDataElseLoad: - cacheMode = 1; // WebSettings.LOAD_CACHE_ELSE_NETWORK - break; - case WebCore::UseProtocolCachePolicy: - default: - break; - } - - LOGV("::WebCore:: startLoadingResource %s with cacheMode %d", urlStr.ascii().data(), cacheMode); - - ResourceHandleInternal* loaderInternal = loader->getInternal(); - jstring jUsernameString = loaderInternal->m_user.isEmpty() ? - NULL : wtfStringToJstring(env, loaderInternal->m_user); - jstring jPasswordString = loaderInternal->m_pass.isEmpty() ? - NULL : wtfStringToJstring(env, loaderInternal->m_pass); - - bool isUserGesture = UserGestureIndicator::processingUserGesture(); - jobject jLoadListener = - env->CallObjectMethod(javaFrame.get(), mJavaFrame->mStartLoadingResource, - (int)loader, jUrlStr, jMethodStr, jHeaderMap, - jPostDataStr, formdata ? formdata->identifier(): 0, - cacheMode, mainResource, isUserGesture, - synchronous, jUsernameString, jPasswordString); - - env->DeleteLocalRef(jUrlStr); - env->DeleteLocalRef(jMethodStr); - env->DeleteLocalRef(jPostDataStr); - env->DeleteLocalRef(jHeaderMap); - env->DeleteLocalRef(jUsernameString); - env->DeleteLocalRef(jPasswordString); - if (checkException(env)) - return 0; - - PassRefPtr<WebCore::ResourceLoaderAndroid> h; - if (jLoadListener) - h = WebCoreResourceLoader::create(env, jLoadListener); - env->DeleteLocalRef(jLoadListener); - return h; -} - UrlInterceptResponse* WebFrame::shouldInterceptRequest(const WTF::String& url) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); -#endif - LOGV("::WebCore:: shouldInterceptRequest(%s)", url.latin1().data()); + ALOGV("::WebCore:: shouldInterceptRequest(%s)", url.latin1().data()); JNIEnv* env = getJNIEnv(); AutoJObject javaFrame = mJavaFrame->frame(env); @@ -534,10 +421,7 @@ void WebFrame::reportError(int errorCode, const WTF::String& description, const WTF::String& failingUrl) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); -#endif - LOGV("::WebCore:: reportError(%d, %s)", errorCode, description.ascii().data()); + ALOGV("::WebCore:: reportError(%d, %s)", errorCode, description.ascii().data()); JNIEnv* env = getJNIEnv(); AutoJObject javaFrame = mJavaFrame->frame(env); if (!javaFrame.get()) @@ -553,7 +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; @@ -566,16 +449,12 @@ WebFrame::convertIDNToUnicode(const WebCore::KURL& url) { newUrl.setHost(convertedHost); converted = newUrl.string(); } -#endif return converted; } void WebFrame::loadStarted(WebCore::Frame* frame) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); -#endif JNIEnv* env = getJNIEnv(); AutoJObject javaFrame = mJavaFrame->frame(env); if (!javaFrame.get()) @@ -589,7 +468,7 @@ WebFrame::loadStarted(WebCore::Frame* frame) const WebCore::KURL& url = documentLoader->url(); if (url.isEmpty()) return; - LOGV("::WebCore:: loadStarted %s", url.string().ascii().data()); + ALOGV("::WebCore:: loadStarted %s", url.string().ascii().data()); bool isMainFrame = (!frame->tree() || !frame->tree()->parent()); WebCore::FrameLoadType loadType = frame->loader()->loadType(); @@ -609,7 +488,7 @@ WebFrame::loadStarted(WebCore::Frame* frame) WebCore::Image* icon = WebCore::iconDatabase().synchronousIconForPageURL(urlString, WebCore::IntSize(16, 16)); if (icon) favicon = webcoreImageToJavaBitmap(env, icon); - LOGV("favicons", "Starting load with icon %p for %s", icon, url.string().utf8().data()); + ALOGV("favicons", "Starting load with icon %p for %s", icon, url.string().utf8().data()); } jstring urlStr = wtfStringToJstring(env, urlString); @@ -633,9 +512,6 @@ WebFrame::loadStarted(WebCore::Frame* frame) void WebFrame::transitionToCommitted(WebCore::Frame* frame) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); -#endif JNIEnv* env = getJNIEnv(); AutoJObject javaFrame = mJavaFrame->frame(env); if (!javaFrame.get()) @@ -650,9 +526,6 @@ WebFrame::transitionToCommitted(WebCore::Frame* frame) void WebFrame::didFinishLoad(WebCore::Frame* frame) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); -#endif JNIEnv* env = getJNIEnv(); AutoJObject javaFrame = mJavaFrame->frame(env); if (!javaFrame.get()) @@ -667,7 +540,7 @@ WebFrame::didFinishLoad(WebCore::Frame* frame) const WebCore::KURL& url = documentLoader->url(); if (url.isEmpty()) return; - LOGV("::WebCore:: didFinishLoad %s", url.string().ascii().data()); + ALOGV("::WebCore:: didFinishLoad %s", url.string().ascii().data()); bool isMainFrame = (!frame->tree() || !frame->tree()->parent()); WebCore::FrameLoadType loadType = loader->loadType(); @@ -681,10 +554,7 @@ WebFrame::didFinishLoad(WebCore::Frame* frame) void WebFrame::addHistoryItem(WebCore::HistoryItem* item) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); -#endif - LOGV("::WebCore:: addHistoryItem"); + ALOGV("::WebCore:: addHistoryItem"); JNIEnv* env = getJNIEnv(); WebHistory::AddItem(mJavaFrame->history(env), item); } @@ -692,10 +562,7 @@ WebFrame::addHistoryItem(WebCore::HistoryItem* item) void WebFrame::removeHistoryItem(int index) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); -#endif - LOGV("::WebCore:: removeHistoryItem at %d", index); + ALOGV("::WebCore:: removeHistoryItem at %d", index); JNIEnv* env = getJNIEnv(); WebHistory::RemoveItem(mJavaFrame->history(env), index); } @@ -703,10 +570,7 @@ WebFrame::removeHistoryItem(int index) void WebFrame::updateHistoryIndex(int newIndex) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); -#endif - LOGV("::WebCore:: updateHistoryIndex to %d", newIndex); + ALOGV("::WebCore:: updateHistoryIndex to %d", newIndex); JNIEnv* env = getJNIEnv(); WebHistory::UpdateHistoryIndex(mJavaFrame->history(env), newIndex); } @@ -714,11 +578,8 @@ WebFrame::updateHistoryIndex(int newIndex) void WebFrame::setTitle(const WTF::String& title) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); -#endif #ifndef NDEBUG - LOGV("setTitle(%s)", title.ascii().data()); + ALOGV("setTitle(%s)", title.ascii().data()); #endif JNIEnv* env = getJNIEnv(); AutoJObject javaFrame = mJavaFrame->frame(env); @@ -735,10 +596,7 @@ WebFrame::setTitle(const WTF::String& title) void WebFrame::windowObjectCleared(WebCore::Frame* frame) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); -#endif - LOGV("::WebCore:: windowObjectCleared"); + ALOGV("::WebCore:: windowObjectCleared"); JNIEnv* env = getJNIEnv(); AutoJObject javaFrame = mJavaFrame->frame(env); if (!javaFrame.get()) @@ -751,9 +609,6 @@ WebFrame::windowObjectCleared(WebCore::Frame* frame) void WebFrame::setProgress(float newProgress) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); -#endif JNIEnv* env = getJNIEnv(); AutoJObject javaFrame = mJavaFrame->frame(env); if (!javaFrame.get()) @@ -773,10 +628,7 @@ WebFrame::userAgentForURL(const WebCore::KURL* url) void WebFrame::didReceiveIcon(WebCore::Image* icon) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); -#endif - LOG_ASSERT(icon, "DidReceiveIcon called without an image!"); + ALOG_ASSERT(icon, "DidReceiveIcon called without an image!"); JNIEnv* env = getJNIEnv(); AutoJObject javaFrame = mJavaFrame->frame(env); if (!javaFrame.get()) @@ -794,9 +646,6 @@ WebFrame::didReceiveIcon(WebCore::Image* icon) void WebFrame::didReceiveTouchIconURL(const WTF::String& url, bool precomposed) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); -#endif JNIEnv* env = getJNIEnv(); AutoJObject javaFrame = mJavaFrame->frame(env); if (!javaFrame.get()) @@ -812,9 +661,6 @@ WebFrame::didReceiveTouchIconURL(const WTF::String& url, bool precomposed) void WebFrame::updateVisitedHistory(const WebCore::KURL& url, bool reload) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); -#endif JNIEnv* env = getJNIEnv(); AutoJObject javaFrame = mJavaFrame->frame(env); if (!javaFrame.get()) @@ -831,9 +677,6 @@ WebFrame::updateVisitedHistory(const WebCore::KURL& url, bool reload) bool WebFrame::canHandleRequest(const WebCore::ResourceRequest& request) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); -#endif JNIEnv* env = getJNIEnv(); AutoJObject javaFrame = mJavaFrame->frame(env); if (!javaFrame.get()) @@ -874,9 +717,6 @@ WebFrame::shouldSaveFormData() WebCore::Frame* WebFrame::createWindow(bool dialog, bool userGesture) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); -#endif JNIEnv* env = getJNIEnv(); AutoJObject javaFrame = mJavaFrame->frame(env); if (!javaFrame.get()) @@ -890,9 +730,6 @@ WebFrame::createWindow(bool dialog, bool userGesture) void WebFrame::requestFocus() const { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); -#endif JNIEnv* env = getJNIEnv(); AutoJObject javaFrame = mJavaFrame->frame(env); if (!javaFrame.get()) @@ -904,9 +741,6 @@ WebFrame::requestFocus() const void WebFrame::closeWindow(WebViewCore* webViewCore) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); -#endif assert(webViewCore); JNIEnv* env = getJNIEnv(); AutoJObject javaFrame = mJavaFrame->frame(env); @@ -925,9 +759,6 @@ struct PolicyFunctionWrapper { void WebFrame::decidePolicyForFormResubmission(WebCore::FramePolicyFunction func) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); -#endif JNIEnv* env = getJNIEnv(); AutoJObject javaFrame = mJavaFrame->frame(env); if (!javaFrame.get()) @@ -961,13 +792,9 @@ WebFrame::density() const return dpi; } -#if USE(CHROME_NETWORK_STACK) void WebFrame::didReceiveAuthenticationChallenge(WebUrlLoaderClient* client, const std::string& host, const std::string& realm, bool useCachedCredentials, bool suppressDialog) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); -#endif JNIEnv* env = getJNIEnv(); AutoJObject javaFrame = mJavaFrame->frame(env); if (!javaFrame.get()) @@ -985,9 +812,6 @@ WebFrame::didReceiveAuthenticationChallenge(WebUrlLoaderClient* client, const st void WebFrame::reportSslCertError(WebUrlLoaderClient* client, int error, const std::string& cert, const std::string& url) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); -#endif JNIEnv* env = getJNIEnv(); AutoJObject javaFrame = mJavaFrame->frame(env); if (!javaFrame.get()) @@ -1008,9 +832,6 @@ WebFrame::reportSslCertError(WebUrlLoaderClient* client, int error, const std::s void WebFrame::requestClientCert(WebUrlLoaderClient* client, const std::string& hostAndPort) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); -#endif JNIEnv* env = getJNIEnv(); int jHandle = reinterpret_cast<int>(client); @@ -1024,9 +845,6 @@ WebFrame::requestClientCert(WebUrlLoaderClient* client, const std::string& hostA void WebFrame::downloadStart(const std::string& url, const std::string& userAgent, const std::string& contentDisposition, const std::string& mimetype, long long contentLength) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); -#endif JNIEnv* env = getJNIEnv(); AutoJObject javaFrame = mJavaFrame->frame(env); if (!javaFrame.get()) @@ -1047,9 +865,6 @@ WebFrame::downloadStart(const std::string& url, const std::string& userAgent, co void WebFrame::didReceiveData(const char* data, int size) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); -#endif JNIEnv* env = getJNIEnv(); AutoJObject javaFrame = mJavaFrame->frame(env); if (!javaFrame.get()) @@ -1064,9 +879,6 @@ WebFrame::didReceiveData(const char* data, int size) { void WebFrame::didFinishLoading() { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); -#endif JNIEnv* env = getJNIEnv(); AutoJObject javaFrame = mJavaFrame->frame(env); if (!javaFrame.get()) @@ -1078,9 +890,6 @@ WebFrame::didFinishLoading() { void WebFrame::setCertificate(const std::string& cert) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); -#endif JNIEnv* env = getJNIEnv(); AutoJObject javaFrame = mJavaFrame->frame(env); if (!javaFrame.get()) @@ -1094,13 +903,9 @@ void WebFrame::setCertificate(const std::string& cert) checkException(env); } -#endif // USE(CHROME_NETWORK_STACK) void WebFrame::autoLogin(const std::string& loginHeader) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimerCoutner::JavaCallbackTimeCounter); -#endif JNIEnv* env = getJNIEnv(); AutoJObject javaFrame = mJavaFrame->frame(env); if (!javaFrame.get()) @@ -1174,7 +979,7 @@ void WebFrame::maybeSavePassword(WebCore::Frame* frame, const WebCore::ResourceR bool WebFrame::getUsernamePasswordFromDom(WebCore::Frame* frame, WTF::String& username, WTF::String& password) { bool found = false; - WTF::PassRefPtr<WebCore::HTMLCollection> form = frame->document()->forms(); + WTF::RefPtr<WebCore::HTMLCollection> form = frame->document()->forms(); WebCore::Node* node = form->firstItem(); while (node && !found && !node->namespaceURI().isNull() && !node->namespaceURI().isEmpty()) { @@ -1271,13 +1076,10 @@ jbyteArray WebFrame::getPostData(const WebCore::ResourceRequest& request) static void CallPolicyFunction(JNIEnv* env, jobject obj, jint func, jint decision) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter); -#endif WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj); - LOG_ASSERT(pFrame, "nativeCallPolicyFunction must take a valid frame pointer!"); + ALOG_ASSERT(pFrame, "nativeCallPolicyFunction must take a valid frame pointer!"); PolicyFunctionWrapper* pFunc = (PolicyFunctionWrapper*)func; - LOG_ASSERT(pFunc, "nativeCallPolicyFunction must take a valid function pointer!"); + ALOG_ASSERT(pFunc, "nativeCallPolicyFunction must take a valid function pointer!"); // If we are resending the form then we should reset the multiple submission protection. if (decision == WebCore::PolicyUse) @@ -1290,17 +1092,9 @@ static void CreateFrame(JNIEnv* env, jobject obj, jobject javaview, jobject jAss { ScriptController::initializeThreading(); -#if USE(CHROME_NETWORK_STACK) // needs to be called before any other chromium code initChromium(); -#endif -#ifdef ANDROID_INSTRUMENT -#if USE(V8) - V8Counters::initCounters(); -#endif - TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter); -#endif // Create a new page ChromeClientAndroid* chromeC = new ChromeClientAndroid; EditorClientAndroid* editorC = new EditorClientAndroid; @@ -1362,7 +1156,7 @@ static void CreateFrame(JNIEnv* env, jobject obj, jobject javaview, jobject jAss WebCore::SecurityOrigin::setLocalLoadPolicy( WebCore::SecurityOrigin::AllowLocalLoadsForLocalAndSubstituteData); - LOGV("::WebCore:: createFrame %p", frame); + ALOGV("::WebCore:: createFrame %p", frame); // Set the mNativeFrame field in Frame SET_NATIVE_FRAME(env, obj, (int)frame); @@ -1370,7 +1164,7 @@ static void CreateFrame(JNIEnv* env, jobject obj, jobject javaview, jobject jAss String directory = webFrame->getRawResourceFilename( WebCore::PlatformBridge::DrawableDir); if (directory.isEmpty()) - LOGE("Can't find the drawable directory"); + ALOGE("Can't find the drawable directory"); else { // Initialize our skinning classes webFrame->setRenderSkins(new WebCore::RenderSkinAndroid(directory)); @@ -1384,13 +1178,10 @@ static void CreateFrame(JNIEnv* env, jobject obj, jobject javaview, jobject jAss static void DestroyFrame(JNIEnv* env, jobject obj) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter); -#endif WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj); - LOG_ASSERT(pFrame, "nativeDestroyFrame must take a valid frame pointer!"); + ALOG_ASSERT(pFrame, "nativeDestroyFrame must take a valid frame pointer!"); - LOGV("::WebCore:: deleting frame %p", pFrame); + ALOGV("::WebCore:: deleting frame %p", pFrame); WebCore::FrameView* view = pFrame->view(); view->ref(); @@ -1415,11 +1206,8 @@ static void DestroyFrame(JNIEnv* env, jobject obj) static void LoadUrl(JNIEnv *env, jobject obj, jstring url, jobject headers) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter); -#endif WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj); - LOG_ASSERT(pFrame, "nativeLoadUrl must take a valid frame pointer!"); + ALOG_ASSERT(pFrame, "nativeLoadUrl must take a valid frame pointer!"); WTF::String webcoreUrl = jstringToWtfString(env, url); WebCore::KURL kurl(WebCore::KURL(), webcoreUrl); @@ -1463,17 +1251,14 @@ static void LoadUrl(JNIEnv *env, jobject obj, jstring url, jobject headers) env->DeleteLocalRef(set); env->DeleteLocalRef(mapClass); } - LOGV("LoadUrl %s", kurl.string().latin1().data()); + ALOGV("LoadUrl %s", kurl.string().latin1().data()); pFrame->loader()->load(request, false); } static void PostUrl(JNIEnv *env, jobject obj, jstring url, jbyteArray postData) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter); -#endif WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj); - LOG_ASSERT(pFrame, "nativePostUrl must take a valid frame pointer!"); + ALOG_ASSERT(pFrame, "nativePostUrl must take a valid frame pointer!"); WebCore::KURL kurl(WebCore::KURL(), jstringToWtfString(env, url)); WebCore::ResourceRequest request(kurl); @@ -1491,7 +1276,7 @@ static void PostUrl(JNIEnv *env, jobject obj, jstring url, jbyteArray postData) env->ReleaseByteArrayElements(postData, bytes, 0); } - LOGV("PostUrl %s", kurl.string().latin1().data()); + ALOGV("PostUrl %s", kurl.string().latin1().data()); WebCore::FrameLoadRequest frameRequest(pFrame->document()->securityOrigin(), request); pFrame->loader()->loadFrameRequest(frameRequest, false, false, 0, 0, WebCore::SendReferrer); } @@ -1499,20 +1284,17 @@ static void PostUrl(JNIEnv *env, jobject obj, jstring url, jbyteArray postData) static void LoadData(JNIEnv *env, jobject obj, jstring baseUrl, jstring data, jstring mimeType, jstring encoding, jstring failUrl) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter); -#endif WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj); - LOG_ASSERT(pFrame, "nativeLoadData must take a valid frame pointer!"); + ALOG_ASSERT(pFrame, "nativeLoadData must take a valid frame pointer!"); // Setup the resource request WebCore::ResourceRequest request(jstringToWtfString(env, baseUrl)); // Setup the substituteData const char* dataStr = env->GetStringUTFChars(data, NULL); - WTF::PassRefPtr<WebCore::SharedBuffer> sharedBuffer = + WTF::RefPtr<WebCore::SharedBuffer> sharedBuffer = WebCore::SharedBuffer::create(); - LOG_ASSERT(dataStr, "nativeLoadData has a null data string."); + ALOG_ASSERT(dataStr, "nativeLoadData has a null data string."); sharedBuffer->append(dataStr, strlen(dataStr)); env->ReleaseStringUTFChars(data, dataStr); @@ -1526,12 +1308,9 @@ static void LoadData(JNIEnv *env, jobject obj, jstring baseUrl, jstring data, static void StopLoading(JNIEnv *env, jobject obj) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter); -#endif WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj); - LOG_ASSERT(pFrame, "nativeStopLoading must take a valid frame pointer!"); - LOGV("::WebCore:: stopLoading %p", pFrame); + ALOG_ASSERT(pFrame, "nativeStopLoading must take a valid frame pointer!"); + ALOGV("::WebCore:: stopLoading %p", pFrame); // Stop loading the page and do not send an unload event pFrame->loader()->stopForUserCancel(); @@ -1579,7 +1358,7 @@ static jstring SaveWebArchive(JNIEnv *env, jobject obj, jstring basename, jboole { #if ENABLE(WEB_ARCHIVE) WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj); - LOG_ASSERT(pFrame, "nativeSaveWebArchive must take a valid frame pointer!"); + ALOG_ASSERT(pFrame, "nativeSaveWebArchive must take a valid frame pointer!"); String mimeType = pFrame->loader()->documentLoader()->mainResource()->mimeType(); if ((mimeType != "text/html") && (mimeType != "application/xhtml+xml")) return NULL; @@ -1597,7 +1376,7 @@ static jstring SaveWebArchive(JNIEnv *env, jobject obj, jstring basename, jboole } if (filename.isNull() || filename.isEmpty()) { - LOGD("saveWebArchive: Failed to select a filename to save."); + ALOGD("saveWebArchive: Failed to select a filename to save."); releaseCharactersForJStringInEnv(env, basename, basenameNative); return NULL; } @@ -1605,7 +1384,7 @@ static jstring SaveWebArchive(JNIEnv *env, jobject obj, jstring basename, jboole const int noCompression = 0; xmlTextWriterPtr writer = xmlNewTextWriterFilename(filename.utf8().data(), noCompression); if (writer == NULL) { - LOGD("saveWebArchive: Failed to initialize xml writer."); + ALOGD("saveWebArchive: Failed to initialize xml writer."); releaseCharactersForJStringInEnv(env, basename, basenameNative); return NULL; } @@ -1626,11 +1405,8 @@ static jstring SaveWebArchive(JNIEnv *env, jobject obj, jstring basename, jboole static jstring ExternalRepresentation(JNIEnv *env, jobject obj) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter); -#endif WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj); - LOG_ASSERT(pFrame, "android_webcore_nativeExternalRepresentation must take a valid frame pointer!"); + ALOG_ASSERT(pFrame, "android_webcore_nativeExternalRepresentation must take a valid frame pointer!"); // Request external representation of the render tree WTF::String renderDump = WebCore::externalRepresentation(pFrame); @@ -1661,11 +1437,8 @@ static StringBuilder FrameAsText(WebCore::Frame *pFrame, jboolean dumpChildFrame static jstring DocumentAsText(JNIEnv *env, jobject obj) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter); -#endif WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj); - LOG_ASSERT(pFrame, "android_webcore_nativeDocumentAsText must take a valid frame pointer!"); + ALOG_ASSERT(pFrame, "android_webcore_nativeDocumentAsText must take a valid frame pointer!"); WTF::String renderDump = FrameAsText(pFrame, false /* dumpChildFrames */).toString(); return wtfStringToJstring(env, renderDump); @@ -1673,11 +1446,8 @@ static jstring DocumentAsText(JNIEnv *env, jobject obj) static jstring ChildFramesAsText(JNIEnv *env, jobject obj) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter); -#endif WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj); - LOG_ASSERT(pFrame, "android_webcore_nativeDocumentAsText must take a valid frame pointer!"); + ALOG_ASSERT(pFrame, "android_webcore_nativeDocumentAsText must take a valid frame pointer!"); StringBuilder renderDumpBuilder; for (unsigned i = 0; i < pFrame->tree()->childCount(); ++i) { @@ -1689,11 +1459,8 @@ static jstring ChildFramesAsText(JNIEnv *env, jobject obj) static void Reload(JNIEnv *env, jobject obj, jboolean allowStale) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter); -#endif WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj); - LOG_ASSERT(pFrame, "nativeReload must take a valid frame pointer!"); + ALOG_ASSERT(pFrame, "nativeReload must take a valid frame pointer!"); WebCore::FrameLoader* loader = pFrame->loader(); if (allowStale) { @@ -1709,11 +1476,8 @@ static void Reload(JNIEnv *env, jobject obj, jboolean allowStale) static void GoBackOrForward(JNIEnv *env, jobject obj, jint pos) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter); -#endif WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj); - LOG_ASSERT(pFrame, "nativeGoBackOrForward must take a valid frame pointer!"); + ALOG_ASSERT(pFrame, "nativeGoBackOrForward must take a valid frame pointer!"); if (pos == 1) pFrame->page()->goForward(); @@ -1725,11 +1489,8 @@ static void GoBackOrForward(JNIEnv *env, jobject obj, jint pos) static jobject StringByEvaluatingJavaScriptFromString(JNIEnv *env, jobject obj, jstring script) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter); -#endif WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj); - LOG_ASSERT(pFrame, "stringByEvaluatingJavaScriptFromString must take a valid frame pointer!"); + ALOG_ASSERT(pFrame, "stringByEvaluatingJavaScriptFromString must take a valid frame pointer!"); WebCore::ScriptValue value = pFrame->script()->executeScript(jstringToWtfString(env, script), true); @@ -1743,32 +1504,16 @@ static jobject StringByEvaluatingJavaScriptFromString(JNIEnv *env, jobject obj, // Wrap the JavaInstance used when binding custom javascript interfaces. Use a // weak reference so that the gc can collect the WebView. Override virtualBegin // and virtualEnd and swap the weak reference for the real object. -#if USE(JSC) -class WeakJavaInstance : public JavaInstance { -#elif USE(V8) class WeakJavaInstance : public JavaInstanceJobject { -#endif public: -#if USE(JSC) - static PassRefPtr<WeakJavaInstance> create(jobject obj, PassRefPtr<RootObject> root) - { - return adoptRef(new WeakJavaInstance(obj, root)); - } -#elif USE(V8) static PassRefPtr<WeakJavaInstance> create(jobject obj) { return adoptRef(new WeakJavaInstance(obj)); } -#endif private: -#if USE(JSC) - WeakJavaInstance(jobject instance, PassRefPtr<RootObject> rootObject) - : JavaInstance(instance, rootObject) -#elif USE(V8) WeakJavaInstance(jobject instance) : JavaInstanceJobject(instance) -#endif , m_beginEndDepth(0) { JNIEnv* env = getJNIEnv(); @@ -1780,7 +1525,7 @@ private: } ~WeakJavaInstance() { - LOG_ASSERT(!m_beginEndDepth, "Unbalanced calls to WeakJavaInstance::begin() / end()"); + ALOG_ASSERT(!m_beginEndDepth, "Unbalanced calls to WeakJavaInstance::begin() / end()"); JNIEnv* env = getJNIEnv(); // The JavaInstance destructor attempts to delete the global ref stored // in m_instance. Since we replaced it in our constructor with a weak @@ -1818,11 +1563,7 @@ private: } private: -#if USE(JSC) - typedef JavaInstance INHERITED; -#elif USE(V8) typedef JavaInstanceJobject INHERITED; -#endif jweak m_weakRef; // The current depth of nested calls to virtualBegin and virtualEnd. int m_beginEndDepth; @@ -1831,42 +1572,17 @@ private: static void AddJavascriptInterface(JNIEnv *env, jobject obj, jint nativeFramePointer, jobject javascriptObj, jstring interfaceName) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter); -#endif WebCore::Frame* pFrame = 0; if (nativeFramePointer == 0) pFrame = GET_NATIVE_FRAME(env, obj); else pFrame = (WebCore::Frame*)nativeFramePointer; - LOG_ASSERT(pFrame, "nativeAddJavascriptInterface must take a valid frame pointer!"); + ALOG_ASSERT(pFrame, "nativeAddJavascriptInterface must take a valid frame pointer!"); JavaVM* vm; env->GetJavaVM(&vm); - LOGV("::WebCore:: addJSInterface: %p", pFrame); - -#if USE(JSC) - // Copied from qwebframe.cpp - JSC::JSLock lock(JSC::SilenceAssertionsOnly); - WebCore::JSDOMWindow *window = WebCore::toJSDOMWindow(pFrame, mainThreadNormalWorld()); - if (window) { - RootObject *root = pFrame->script()->bindingRootObject(); - setJavaVM(vm); - // Add the binding to JS environment - JSC::ExecState* exec = window->globalExec(); - JSC::JSObject* addedObject = WeakJavaInstance::create(javascriptObj, - root)->createRuntimeObject(exec); - const jchar* s = env->GetStringChars(interfaceName, NULL); - if (s) { - // Add the binding name to the window's table of child objects. - JSC::PutPropertySlot slot; - window->put(exec, JSC::Identifier(exec, (const UChar *)s, - env->GetStringLength(interfaceName)), addedObject, slot); - env->ReleaseStringChars(interfaceName, s); - checkException(env); - } - } -#elif USE(V8) + ALOGV("::WebCore:: addJSInterface: %p", pFrame); + if (pFrame) { RefPtr<JavaInstance> addedObject = WeakJavaInstance::create(javascriptObj); const char* name = getCharactersFromJStringInEnv(env, interfaceName); @@ -1887,24 +1603,6 @@ static void AddJavascriptInterface(JNIEnv *env, jobject obj, jint nativeFramePoi NPN_ReleaseObject(npObject); releaseCharactersForJString(interfaceName, name); } -#endif - -} - -static void SetCacheDisabled(JNIEnv *env, jobject obj, jboolean disabled) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter); -#endif - WebCore::memoryCache()->setDisabled(disabled); -} - -static jboolean CacheDisabled(JNIEnv *env, jobject obj) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter); -#endif - return WebCore::memoryCache()->disabled(); } static void ClearWebCoreCache() @@ -1926,59 +1624,32 @@ static void ClearWebCoreCache() static void ClearWebViewCache() { -#if USE(CHROME_NETWORK_STACK) WebCache::get(false /*privateBrowsing*/)->clear(); -#else - // The Android network stack provides a WebView cache in CacheManager.java. - // Clearing this is handled entirely Java-side. -#endif } static void ClearCache(JNIEnv *env, jobject obj) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter); -#if USE(JSC) - JSC::JSLock lock(false); - JSC::Heap::Statistics jsHeapStatistics = WebCore::JSDOMWindow::commonJSGlobalData()->heap.statistics(); - LOGD("About to gc and JavaScript heap size is %d and has %d bytes free", - jsHeapStatistics.size, jsHeapStatistics.free); -#endif // USE(JSC) - LOGD("About to clear cache and current cache has %d bytes live and %d bytes dead", - memoryCache()->getLiveSize(), memoryCache()->getDeadSize()); -#endif // ANDROID_INSTRUMENT ClearWebCoreCache(); ClearWebViewCache(); -#if USE(JSC) - // force JavaScript to GC when clear cache - WebCore::gcController().garbageCollectSoon(); -#elif USE(V8) WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj); pFrame->script()->lowMemoryNotification(); -#endif // USE(JSC) } static jboolean DocumentHasImages(JNIEnv *env, jobject obj) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter); -#endif WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj); - LOG_ASSERT(pFrame, "DocumentHasImages must take a valid frame pointer!"); + ALOG_ASSERT(pFrame, "DocumentHasImages must take a valid frame pointer!"); return pFrame->document()->images()->length() > 0; } static jboolean HasPasswordField(JNIEnv *env, jobject obj) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter); -#endif WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj); - LOG_ASSERT(pFrame, "HasPasswordField must take a valid frame pointer!"); + ALOG_ASSERT(pFrame, "HasPasswordField must take a valid frame pointer!"); bool found = false; - WTF::PassRefPtr<WebCore::HTMLCollection> form = pFrame->document()->forms(); + WTF::RefPtr<WebCore::HTMLCollection> form = pFrame->document()->forms(); WebCore::Node* node = form->firstItem(); // Null/Empty namespace means that node is not created in HTMLFormElement // class, but just normal Element class. @@ -2001,11 +1672,8 @@ static jboolean HasPasswordField(JNIEnv *env, jobject obj) static jobjectArray GetUsernamePassword(JNIEnv *env, jobject obj) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter); -#endif WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj); - LOG_ASSERT(pFrame, "GetUsernamePassword must take a valid frame pointer!"); + ALOG_ASSERT(pFrame, "GetUsernamePassword must take a valid frame pointer!"); jobjectArray strArray = NULL; WTF::String username; WTF::String password; @@ -2022,16 +1690,13 @@ static jobjectArray GetUsernamePassword(JNIEnv *env, jobject obj) static void SetUsernamePassword(JNIEnv *env, jobject obj, jstring username, jstring password) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter); -#endif WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj); - LOG_ASSERT(pFrame, "SetUsernamePassword must take a valid frame pointer!"); + ALOG_ASSERT(pFrame, "SetUsernamePassword must take a valid frame pointer!"); WebCore::HTMLInputElement* usernameEle = NULL; WebCore::HTMLInputElement* passwordEle = NULL; bool found = false; - WTF::PassRefPtr<WebCore::HTMLCollection> form = pFrame->document()->forms(); + WTF::RefPtr<WebCore::HTMLCollection> form = pFrame->document()->forms(); WebCore::Node* node = form->firstItem(); while (node && !found && !node->namespaceURI().isNull() && !node->namespaceURI().isEmpty()) { @@ -2071,14 +1736,14 @@ WebFrame::saveFormData(HTMLFormElement* form) if (form->autoComplete()) { JNIEnv* env = getJNIEnv(); jclass mapClass = env->FindClass("java/util/HashMap"); - LOG_ASSERT(mapClass, "Could not find HashMap class!"); + ALOG_ASSERT(mapClass, "Could not find HashMap class!"); jmethodID init = env->GetMethodID(mapClass, "<init>", "(I)V"); - LOG_ASSERT(init, "Could not find constructor for HashMap"); + ALOG_ASSERT(init, "Could not find constructor for HashMap"); jobject hashMap = env->NewObject(mapClass, init, 1); - LOG_ASSERT(hashMap, "Could not create a new HashMap"); + ALOG_ASSERT(hashMap, "Could not create a new HashMap"); jmethodID put = env->GetMethodID(mapClass, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); - LOG_ASSERT(put, "Could not find put method on HashMap"); + ALOG_ASSERT(put, "Could not find put method on HashMap"); WTF::Vector<WebCore::FormAssociatedElement*> elements = form->associatedElements(); size_t size = elements.size(); for (size_t i = 0; i < size; i++) { @@ -2093,7 +1758,7 @@ WebFrame::saveFormData(HTMLFormElement* form) const WTF::AtomicString& name = input->name(); jstring key = wtfStringToJstring(env, name); jstring val = wtfStringToJstring(env, value); - LOG_ASSERT(key && val, "name or value not set"); + ALOG_ASSERT(key && val, "name or value not set"); env->CallObjectMethod(hashMap, put, key, val); env->DeleteLocalRef(key); env->DeleteLocalRef(val); @@ -2109,11 +1774,8 @@ WebFrame::saveFormData(HTMLFormElement* form) static void OrientationChanged(JNIEnv *env, jobject obj, int orientation) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter); -#endif WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj); - LOGV("Sending orientation: %d", orientation); + ALOGV("Sending orientation: %d", orientation); pFrame->sendOrientationChangeEvent(orientation); } @@ -2126,8 +1788,9 @@ static jboolean GetShouldStartScrolledRight(JNIEnv *env, jobject obj, if (document) { RenderStyle* style = document->renderer()->style(); WritingMode writingMode = style->writingMode(); - LOG_ASSERT(writingMode != WebCore::BottomToTopWritingMode, - "BottomToTopWritingMode isn't supported"); + ALOG_ASSERT(writingMode != WebCore::BottomToTopWritingMode, + "BottomToTopWritingMode isn't possible in any " + "language and cannot be specified in w3c writing-mode."); if (writingMode == WebCore::RightToLeftWritingMode) startScrolledRight = true; // vertical-rl pages start scrolled right else if (writingMode == WebCore::TopToBottomWritingMode) @@ -2136,8 +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); @@ -2242,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) -{ - LOGW("Chromium authentication API called, but libchromium is not available"); -} - -static void AuthenticationCancel(JNIEnv *env, jobject obj, int handle) -{ - LOGW("Chromium authentication API called, but libchromium is not available"); -} - -static void SslCertErrorProceed(JNIEnv *env, jobject obj, int handle) -{ - LOGW("Chromium SSL API called, but libchromium is not available"); -} - -static void SslCertErrorCancel(JNIEnv *env, jobject obj, int handle, int cert_error) -{ - LOGW("Chromium SSL API called, but libchromium is not available"); -} - -static void SslClientCert(JNIEnv *env, jobject obj, int handle, jbyteArray privateKey, jobjectArray chain) -{ - LOGW("Chromium SSL API called, but libchromium is not available"); -} -#endif // USE(CHROME_NETWORK_STACK) - // ---------------------------------------------------------------------------- /* @@ -2308,10 +1941,6 @@ static JNINativeMethod gBrowserFrameNativeMethods[] = { { "stringByEvaluatingJavaScriptFromString", "(Ljava/lang/String;)Ljava/lang/String;", (void*) StringByEvaluatingJavaScriptFromString }, - { "setCacheDisabled", "(Z)V", - (void*) SetCacheDisabled }, - { "cacheDisabled", "()Z", - (void*) CacheDisabled }, { "clearCache", "()V", (void*) ClearCache }, { "documentHasImages", "()Z", @@ -2341,9 +1970,9 @@ static JNINativeMethod gBrowserFrameNativeMethods[] = { int registerWebFrame(JNIEnv* env) { jclass clazz = env->FindClass("android/webkit/BrowserFrame"); - LOG_ASSERT(clazz, "Cannot find BrowserFrame"); + ALOG_ASSERT(clazz, "Cannot find BrowserFrame"); gFrameField = env->GetFieldID(clazz, "mNativeFrame", "I"); - LOG_ASSERT(gFrameField, "Cannot find mNativeFrame on BrowserFrame"); + ALOG_ASSERT(gFrameField, "Cannot find mNativeFrame on BrowserFrame"); env->DeleteLocalRef(clazz); return jniRegisterNativeMethods(env, "android/webkit/BrowserFrame", diff --git a/Source/WebKit/android/jni/WebCoreFrameBridge.h b/Source/WebKit/android/jni/WebCoreFrameBridge.h index eaee63c..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 2a07999..5a142c8 100644 --- a/Source/WebKit/android/jni/WebCoreJni.cpp +++ b/Source/WebKit/android/jni/WebCoreJni.cpp @@ -26,7 +26,9 @@ #define LOG_TAG "webcoreglue" #include "config.h" +#include "IntRect.h" #include "WebCoreJni.h" +#include "wtf/Vector.h" #include "NotImplemented.h" #include <JNIUtility.h> @@ -38,7 +40,7 @@ namespace android { AutoJObject getRealObject(JNIEnv* env, jobject obj) { jobject real = env->NewLocalRef(obj); - LOG_ASSERT(real, "The real object has been deleted!"); + ALOG_ASSERT(real, "The real object has been deleted!"); return AutoJObject(env, real); } @@ -50,7 +52,7 @@ bool checkException(JNIEnv* env) { if (env->ExceptionCheck() != 0) { - LOGE("*** Uncaught exception returned from Java call!\n"); + ALOGE("*** Uncaught exception returned from Java call!\n"); env->ExceptionDescribe(); return true; } @@ -77,8 +79,6 @@ jstring wtfStringToJstring(JNIEnv* env, const WTF::String& str, bool validOnZero return length || validOnZeroLength ? env->NewString(str.characters(), length) : 0; } - -#if USE(CHROME_NETWORK_STACK) string16 jstringToString16(JNIEnv* env, jstring jstr) { if (!jstr || !env) @@ -112,6 +112,25 @@ 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"); + ALOG_ASSERT(rectClass, "Could not find android/graphics/Rect"); + jmethodID rectInit = env->GetMethodID(rectClass, "<init>", "(IIII)V"); + ALOG_ASSERT(rectInit, "Could not find init method on Rect"); + jobjectArray array = env->NewObjectArray(rects.size(), rectClass, 0); + ALOG_ASSERT(array, "Could not create a Rect array"); + for (size_t i = 0; i < rects.size(); i++) { + jobject rect = env->NewObject(rectClass, rectInit, + rects[i].x(), rects[i].y(), + rects[i].maxX(), rects[i].maxY()); + if (rect) { + env->SetObjectArrayElement(array, i, rect); + env->DeleteLocalRef(rect); + } + } + env->DeleteLocalRef(rectClass); + return array; +} } diff --git a/Source/WebKit/android/jni/WebCoreJni.h b/Source/WebKit/android/jni/WebCoreJni.h index 0f77cc6..25aa986 100644 --- a/Source/WebKit/android/jni/WebCoreJni.h +++ b/Source/WebKit/android/jni/WebCoreJni.h @@ -27,6 +27,7 @@ #define WebCoreJni_h #include "ChromiumIncludes.h" +#include "IntRect.h" #include "PlatformString.h" #include <jni.h> @@ -81,7 +82,6 @@ WTF::String jstringToWtfString(JNIEnv*, jstring); // an empty WTF String returns 0. jstring wtfStringToJstring(JNIEnv*, const WTF::String&, bool validOnZeroLength = false); -#if USE(CHROME_NETWORK_STACK) string16 jstringToString16(JNIEnv*, jstring); std::string jstringToStdString(JNIEnv*, jstring); @@ -89,7 +89,8 @@ 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 bb71bf5..2644dab 100644 --- a/Source/WebKit/android/jni/WebCoreJniOnLoad.cpp +++ b/Source/WebKit/android/jni/WebCoreJniOnLoad.cpp @@ -62,8 +62,6 @@ #include "WebCoreViewBridge.h" #include "WebFrameView.h" #include "WebViewCore.h" -#include "benchmark/Intercept.h" -#include "benchmark/MyJavaVM.h" #include <JNIUtility.h> #include <jni.h> @@ -75,7 +73,6 @@ namespace android { extern int registerWebFrame(JNIEnv*); extern int registerJavaBridge(JNIEnv*); -extern int registerJniUtil(JNIEnv*); extern int registerResourceLoader(JNIEnv*); extern int registerWebViewCore(JNIEnv*); extern int registerWebHistory(JNIEnv*); @@ -94,9 +91,7 @@ extern int registerMediaPlayerVideo(JNIEnv*); #endif extern int registerDeviceMotionAndOrientationManager(JNIEnv*); extern int registerCookieManager(JNIEnv*); -#if USE(CHROME_NETWORK_STACK) extern int registerCacheManager(JNIEnv*); -#endif } @@ -107,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 }, @@ -127,9 +120,7 @@ static RegistrationMethod gWebCoreRegMethods[] = { #endif { "DeviceMotionAndOrientationManager", android::registerDeviceMotionAndOrientationManager }, { "CookieManager", android::registerCookieManager }, -#if USE(CHROME_NETWORK_STACK) { "CacheManager", android::registerCacheManager }, -#endif }; EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) @@ -141,16 +132,16 @@ EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) jint result = -1; if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { - LOGE("GetEnv failed!"); + ALOGE("GetEnv failed!"); return result; } - LOG_ASSERT(env, "Could not retrieve the env!"); + ALOG_ASSERT(env, "Could not retrieve the env!"); const RegistrationMethod* method = gWebCoreRegMethods; const RegistrationMethod* end = method + sizeof(gWebCoreRegMethods)/sizeof(RegistrationMethod); while (method != end) { if (method->func(env) < 0) { - LOGE("%s registration failed!", method->name); + ALOGE("%s registration failed!", method->name); return result; } method++; @@ -162,160 +153,3 @@ EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) return JNI_VERSION_1_4; } - -class MyJavaSharedClient : public TimerClient, public CookieClient { -public: - MyJavaSharedClient() : m_hasTimer(false) {} - virtual void setSharedTimer(long long timemillis) { m_hasTimer = true; } - virtual void stopSharedTimer() { m_hasTimer = false; } - virtual void setSharedTimerCallback(void (*f)()) { m_func = f; } - virtual void signalServiceFuncPtrQueue() {} - - // Cookie methods that do nothing. - virtual void setCookies(const KURL&, const String&) {} - virtual String cookies(const KURL&) { return ""; } - virtual bool cookiesEnabled() { return false; } - - bool m_hasTimer; - void (*m_func)(); -}; - -static void historyItemChanged(HistoryItem* i) { - if (i->bridge()) - i->bridge()->updateHistoryItem(i); -} - -namespace android { - -EXPORT void benchmark(const char* url, int reloadCount, int width, int height) { - ScriptController::initializeThreading(); - - // Setting this allows data: urls to load from a local file. - SecurityOrigin::setLocalLoadPolicy(SecurityOrigin::AllowLocalLoadsForAll); - - // Create the fake JNIEnv and JavaVM - InitializeJavaVM(); - - // The real function is private to libwebcore but we know what it does. - notifyHistoryItemChanged = historyItemChanged; - - // Implement the shared timer callback - MyJavaSharedClient client; - JavaSharedClient::SetTimerClient(&client); - JavaSharedClient::SetCookieClient(&client); - - // Create the page with all the various clients - ChromeClientAndroid* chrome = new ChromeClientAndroid; - EditorClientAndroid* editor = new EditorClientAndroid; - DeviceMotionClientAndroid* deviceMotion = new DeviceMotionClientAndroid; - DeviceOrientationClientAndroid* deviceOrientation = new DeviceOrientationClientAndroid; - WebCore::Page::PageClients pageClients; - pageClients.chromeClient = chrome; - pageClients.contextMenuClient = new ContextMenuClientAndroid; - pageClients.editorClient = editor; - pageClients.dragClient = new DragClientAndroid; - pageClients.inspectorClient = new InspectorClientAndroid; - pageClients.deviceMotionClient = deviceMotion; - pageClients.deviceOrientationClient = deviceOrientation; - WebCore::Page* page = new WebCore::Page(pageClients); - editor->setPage(page); - - // Create MyWebFrame that intercepts network requests - MyWebFrame* webFrame = new MyWebFrame(page); - webFrame->setUserAgent("Performance testing"); // needs to be non-empty - chrome->setWebFrame(webFrame); - // ChromeClientAndroid maintains the reference. - Release(webFrame); - - // Create the Frame and the FrameLoaderClient - FrameLoaderClientAndroid* loader = new FrameLoaderClientAndroid(webFrame); - RefPtr<Frame> frame = Frame::create(page, NULL, loader); - loader->setFrame(frame.get()); - - // Build our View system, resize it to the given dimensions and release our - // references. Note: We keep a referenec to frameView so we can layout and - // draw later without risk of it being deleted. - WebViewCore* webViewCore = new WebViewCore(JSC::Bindings::getJNIEnv(), - MY_JOBJECT, frame.get()); - RefPtr<FrameView> frameView = FrameView::create(frame.get()); - WebFrameView* webFrameView = new WebFrameView(frameView.get(), webViewCore); - frame->setView(frameView); - frameView->resize(width, height); - Release(webViewCore); - Release(webFrameView); - - // Initialize the frame and turn of low-bandwidth display (it fails an - // assertion in the Cache code) - frame->init(); - frame->selection()->setFocused(true); - frame->page()->focusController()->setFocused(true); - - deviceMotion->setWebViewCore(webViewCore); - deviceOrientation->setWebViewCore(webViewCore); - - // Set all the default settings the Browser normally uses. - Settings* s = frame->settings(); -#ifdef ANDROID_LAYOUT - s->setLayoutAlgorithm(Settings::kLayoutNormal); // Normal layout for now -#endif - s->setStandardFontFamily("sans-serif"); - s->setFixedFontFamily("monospace"); - s->setSansSerifFontFamily("sans-serif"); - s->setSerifFontFamily("serif"); - s->setCursiveFontFamily("cursive"); - s->setFantasyFontFamily("fantasy"); - s->setMinimumFontSize(8); - s->setMinimumLogicalFontSize(8); - s->setDefaultFontSize(16); - s->setDefaultFixedFontSize(13); - s->setLoadsImagesAutomatically(true); - s->setJavaScriptEnabled(true); - s->setDefaultTextEncodingName("latin1"); - s->setPluginsEnabled(false); - s->setShrinksStandaloneImagesToFit(false); -#ifdef ANDROID_LAYOUT - s->setUseWideViewport(false); -#endif - - // Finally, load the actual data - ResourceRequest req(url); - frame->loader()->load(req, false); - - do { - // Layout the page and service the timer - frame->view()->layout(); - while (client.m_hasTimer) { - client.m_func(); - JavaSharedClient::ServiceFunctionPtrQueue(); - } - JavaSharedClient::ServiceFunctionPtrQueue(); - - // Layout more if needed. - while (frame->view()->needsLayout()) - frame->view()->layout(); - JavaSharedClient::ServiceFunctionPtrQueue(); - - if (reloadCount) - frame->loader()->reload(true); - } while (reloadCount--); - - // Draw into an offscreen bitmap - SkBitmap bmp; - bmp.setConfig(SkBitmap::kARGB_8888_Config, width, height); - bmp.allocPixels(); - SkCanvas canvas(bmp); - PlatformGraphicsContext ctx(&canvas); - GraphicsContext gc(&ctx); - frame->view()->paintContents(&gc, IntRect(0, 0, width, height)); - - // Write the bitmap to the sdcard - SkImageEncoder* enc = SkImageEncoder::Create(SkImageEncoder::kPNG_Type); - enc->encodeFile("/sdcard/webcore_test.png", bmp, 100); - delete enc; - - // Tear down the world. - frame->loader()->detachFromParent(); - delete page; -} - -} // namespace android diff --git a/Source/WebKit/android/jni/WebCoreResourceLoader.cpp b/Source/WebKit/android/jni/WebCoreResourceLoader.cpp deleted file mode 100644 index f9acc97..0000000 --- a/Source/WebKit/android/jni/WebCoreResourceLoader.cpp +++ /dev/null @@ -1,352 +0,0 @@ -/* - * Copyright 2006, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#define LOG_TAG "webcoreglue" - -#include "config.h" -#include "WebCoreResourceLoader.h" - -#include "ResourceError.h" -#include "ResourceHandle.h" -#include "ResourceHandleClient.h" -#include "ResourceHandleInternal.h" -#include "ResourceResponse.h" -#include "SkUtils.h" -#ifdef ANDROID_INSTRUMENT -#include "TimeCounter.h" -#endif -#include "WebCoreJni.h" - -#include <JNIHelp.h> -#include <JNIUtility.h> -#include <SkTypes.h> -#include <stdlib.h> -#include <utils/misc.h> -#include <wtf/Platform.h> -#include <wtf/text/CString.h> - -namespace android { - -// ---------------------------------------------------------------------------- - -static struct resourceloader_t { - jfieldID mObject; - jmethodID mCancelMethodID; - jmethodID mDownloadFileMethodID; - jmethodID mWillLoadFromCacheMethodID; - jmethodID mPauseLoadMethodID; -} gResourceLoader; - -// ---------------------------------------------------------------------------- - -#define GET_NATIVE_HANDLE(env, obj) ((WebCore::ResourceHandle*)env->GetIntField(obj, gResourceLoader.mObject)) -#define SET_NATIVE_HANDLE(env, obj, handle) (env->SetIntField(obj, gResourceLoader.mObject, handle)) - -//----------------------------------------------------------------------------- -// ResourceLoadHandler - -PassRefPtr<WebCore::ResourceLoaderAndroid> WebCoreResourceLoader::create(JNIEnv *env, jobject jLoadListener) -{ - return adoptRef<WebCore::ResourceLoaderAndroid>(new WebCoreResourceLoader(env, jLoadListener)); -} - -WebCoreResourceLoader::WebCoreResourceLoader(JNIEnv *env, jobject jLoadListener) - : mPausedLoad(false) -{ - mJLoader = env->NewGlobalRef(jLoadListener); -} - -WebCoreResourceLoader::~WebCoreResourceLoader() -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - SET_NATIVE_HANDLE(env, mJLoader, 0); - env->DeleteGlobalRef(mJLoader); - mJLoader = 0; -} - -void WebCoreResourceLoader::cancel() -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(mJLoader, gResourceLoader.mCancelMethodID); - checkException(env); -} - -void WebCoreResourceLoader::downloadFile() -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(mJLoader, gResourceLoader.mDownloadFileMethodID); - checkException(env); -} - -void WebCoreResourceLoader::pauseLoad(bool pause) -{ - if (mPausedLoad == pause) - return; - - mPausedLoad = pause; - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(mJLoader, gResourceLoader.mPauseLoadMethodID, pause); - checkException(env); -} - -/* -* This static method is called to check to see if a POST response is in -* the cache. This may be slow, but is only used during a navigation to -* a POST response. -*/ -bool WebCoreResourceLoader::willLoadFromCache(const WebCore::KURL& url, int64_t identifier) -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - WTF::String urlStr = url.string(); - jstring jUrlStr = wtfStringToJstring(env, urlStr); - jclass resourceLoader = env->FindClass("android/webkit/LoadListener"); - bool val = env->CallStaticBooleanMethod(resourceLoader, gResourceLoader.mWillLoadFromCacheMethodID, jUrlStr, identifier); - checkException(env); - env->DeleteLocalRef(resourceLoader); - env->DeleteLocalRef(jUrlStr); - - return val; -} - -// ---------------------------------------------------------------------------- -void WebCoreResourceLoader::SetResponseHeader(JNIEnv* env, jobject obj, jint nativeResponse, jstring key, jstring val) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::ResourceTimeCounter); -#endif - - WebCore::ResourceResponse* response = (WebCore::ResourceResponse*)nativeResponse; - LOG_ASSERT(response, "nativeSetResponseHeader must take a valid response pointer!"); - - LOG_ASSERT(key, "How did a null value become a key?"); - if (val) - response->setHTTPHeaderField(jstringToWtfString(env, key), jstringToWtfString(env, val)); -} - -jint WebCoreResourceLoader::CreateResponse(JNIEnv* env, jobject obj, jstring url, jint statusCode, - jstring statusText, jstring mimeType, jlong expectedLength, - jstring encoding) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::ResourceTimeCounter); -#endif - LOG_ASSERT(url, "Must have a url in the response!"); - WebCore::KURL kurl(WebCore::ParsedURLString, jstringToWtfString(env, url)); - WTF::String encodingStr; - WTF::String mimeTypeStr; - if (mimeType) { - mimeTypeStr = jstringToWtfString(env, mimeType); - LOGV("Response setMIMEType: %s", mimeTypeStr.latin1().data()); - } - if (encoding) { - encodingStr = jstringToWtfString(env, encoding); - LOGV("Response setTextEncodingName: %s", encodingStr.latin1().data()); - } - WebCore::ResourceResponse* response = new WebCore::ResourceResponse( - kurl, mimeTypeStr, (long long)expectedLength, - encodingStr, WTF::String()); - response->setHTTPStatusCode(statusCode); - if (statusText) { - WTF::String status = jstringToWtfString(env, statusText); - response->setHTTPStatusText(status); - LOGV("Response setStatusText: %s", status.latin1().data()); - } - return (int)response; -} - -void WebCoreResourceLoader::ReceivedResponse(JNIEnv* env, jobject obj, jint nativeResponse) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::ResourceTimeCounter); -#endif - WebCore::ResourceHandle* handle = GET_NATIVE_HANDLE(env, obj); - LOG_ASSERT(handle, "nativeReceivedResponse must take a valid handle!"); - // ResourceLoader::didFail() can set handle to be NULL, we need to check - if (!handle) - return; - - WebCore::ResourceResponse* response = (WebCore::ResourceResponse*)nativeResponse; - LOG_ASSERT(response, "nativeReceivedResponse must take a valid resource pointer!"); - handle->client()->didReceiveResponse(handle, *response); - // As the client makes a copy of the response, delete it here. - delete response; -} - -void WebCoreResourceLoader::AddData(JNIEnv* env, jobject obj, jbyteArray dataArray, jint length) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::ResourceTimeCounter); -#endif - LOGV("webcore_resourceloader data(%d)", length); - - WebCore::ResourceHandle* handle = GET_NATIVE_HANDLE(env, obj); - LOG_ASSERT(handle, "nativeAddData must take a valid handle!"); - // ResourceLoader::didFail() can set handle to be NULL, we need to check - if (!handle) - return; - - SkAutoMemoryUsageProbe mup("android_webcore_resourceloader_nativeAddData"); - - bool result = false; - jbyte * data = env->GetByteArrayElements(dataArray, NULL); - - LOG_ASSERT(handle->client(), "Why do we not have a client?"); - handle->client()->didReceiveData(handle, (const char *)data, length, length); - env->ReleaseByteArrayElements(dataArray, data, JNI_ABORT); -} - -void WebCoreResourceLoader::Finished(JNIEnv* env, jobject obj) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::ResourceTimeCounter); -#endif - LOGV("webcore_resourceloader finished"); - WebCore::ResourceHandle* handle = GET_NATIVE_HANDLE(env, obj); - LOG_ASSERT(handle, "nativeFinished must take a valid handle!"); - // ResourceLoader::didFail() can set handle to be NULL, we need to check - if (!handle) - return; - - LOG_ASSERT(handle->client(), "Why do we not have a client?"); - handle->client()->didFinishLoading(handle, 0); -} - -jstring WebCoreResourceLoader::RedirectedToUrl(JNIEnv* env, jobject obj, - jstring baseUrl, jstring redirectTo, jint nativeResponse) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::ResourceTimeCounter); -#endif - LOGV("webcore_resourceloader redirectedToUrl"); - WebCore::ResourceHandle* handle = GET_NATIVE_HANDLE(env, obj); - LOG_ASSERT(handle, "nativeRedirectedToUrl must take a valid handle!"); - // ResourceLoader::didFail() can set handle to be NULL, we need to check - if (!handle) - return NULL; - - LOG_ASSERT(handle->client(), "Why do we not have a client?"); - WebCore::ResourceRequest r = handle->firstRequest(); - WebCore::KURL url(WebCore::KURL(WebCore::ParsedURLString, jstringToWtfString(env, baseUrl)), - jstringToWtfString(env, redirectTo)); - WebCore::ResourceResponse* response = (WebCore::ResourceResponse*)nativeResponse; - // If the url fails to resolve the relative path, return null. - if (url.protocol().isEmpty()) { - delete response; - return NULL; - } else { - // Ensure the protocol is lowercase. - url.setProtocol(url.protocol().lower()); - } - // Set the url after updating the protocol. - r.setURL(url); - if (r.httpMethod() == "POST") { - r.setHTTPMethod("GET"); - r.clearHTTPReferrer(); - r.setHTTPBody(0); - r.setHTTPContentType(""); - } - handle->client()->willSendRequest(handle, r, *response); - delete response; - return wtfStringToJstring(env, url.string()); -} - -void WebCoreResourceLoader::Error(JNIEnv* env, jobject obj, jint id, jstring description, - jstring failingUrl) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::ResourceTimeCounter); -#endif - LOGV("webcore_resourceloader error"); - WebCore::ResourceHandle* handle = GET_NATIVE_HANDLE(env, obj); - LOG_ASSERT(handle, "nativeError must take a valid handle!"); - // ResourceLoader::didFail() can set handle to be NULL, we need to check - if (!handle) - return; - - handle->client()->didFail(handle, WebCore::ResourceError("", id, - jstringToWtfString(env, failingUrl), jstringToWtfString(env, description))); -} - -// ---------------------------------------------------------------------------- - -/* - * JNI registration. - */ -static JNINativeMethod gResourceloaderMethods[] = { - /* name, signature, funcPtr */ - { "nativeSetResponseHeader", "(ILjava/lang/String;Ljava/lang/String;)V", - (void*) WebCoreResourceLoader::SetResponseHeader }, - { "nativeCreateResponse", "(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;JLjava/lang/String;)I", - (void*) WebCoreResourceLoader::CreateResponse }, - { "nativeReceivedResponse", "(I)V", - (void*) WebCoreResourceLoader::ReceivedResponse }, - { "nativeAddData", "([BI)V", - (void*) WebCoreResourceLoader::AddData }, - { "nativeFinished", "()V", - (void*) WebCoreResourceLoader::Finished }, - { "nativeRedirectedToUrl", "(Ljava/lang/String;Ljava/lang/String;I)Ljava/lang/String;", - (void*) WebCoreResourceLoader::RedirectedToUrl }, - { "nativeError", "(ILjava/lang/String;Ljava/lang/String;)V", - (void*) WebCoreResourceLoader::Error } -}; - -int registerResourceLoader(JNIEnv* env) -{ - jclass resourceLoader = env->FindClass("android/webkit/LoadListener"); - LOG_FATAL_IF(resourceLoader == NULL, - "Unable to find class android/webkit/LoadListener"); - - gResourceLoader.mObject = - env->GetFieldID(resourceLoader, "mNativeLoader", "I"); - LOG_FATAL_IF(gResourceLoader.mObject == NULL, - "Unable to find android/webkit/LoadListener.mNativeLoader"); - - gResourceLoader.mCancelMethodID = - env->GetMethodID(resourceLoader, "cancel", "()V"); - LOG_FATAL_IF(gResourceLoader.mCancelMethodID == NULL, - "Could not find method cancel on LoadListener"); - - gResourceLoader.mDownloadFileMethodID = - env->GetMethodID(resourceLoader, "downloadFile", "()V"); - LOG_FATAL_IF(gResourceLoader.mDownloadFileMethodID == NULL, - "Could not find method downloadFile on LoadListener"); - - gResourceLoader.mPauseLoadMethodID = - env->GetMethodID(resourceLoader, "pauseLoad", "(Z)V"); - LOG_FATAL_IF(gResourceLoader.mPauseLoadMethodID == NULL, - "Could not find method pauseLoad on LoadListener"); - - gResourceLoader.mWillLoadFromCacheMethodID = - env->GetStaticMethodID(resourceLoader, "willLoadFromCache", "(Ljava/lang/String;J)Z"); - LOG_FATAL_IF(gResourceLoader.mWillLoadFromCacheMethodID == NULL, - "Could not find static method willLoadFromCache on LoadListener"); - - env->DeleteLocalRef(resourceLoader); - - return jniRegisterNativeMethods(env, "android/webkit/LoadListener", - gResourceloaderMethods, NELEM(gResourceloaderMethods)); -} - -} /* namespace android */ diff --git a/Source/WebKit/android/jni/WebCoreResourceLoader.h b/Source/WebKit/android/jni/WebCoreResourceLoader.h deleted file mode 100644 index 0e34a5b..0000000 --- a/Source/WebKit/android/jni/WebCoreResourceLoader.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2006, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WebCoreResourceLoader_h -#define WebCoreResourceLoader_h - -#include <KURL.h> -#include <ResourceLoaderAndroid.h> -#include <jni.h> - -namespace android { - -class WebCoreResourceLoader : public WebCore::ResourceLoaderAndroid -{ -public: - static PassRefPtr<WebCore::ResourceLoaderAndroid> create(JNIEnv *env, jobject jLoadListener); - virtual ~WebCoreResourceLoader(); - - /** - * Call to java to cancel the current load. - */ - virtual void cancel(); - - /** - * Call to java to download the current load rather than feed it - * back to WebCore - */ - virtual void downloadFile(); - - virtual void pauseLoad(bool); - - /** - * Call to java to find out if this URL is in the cache - */ - static bool willLoadFromCache(const WebCore::KURL& url, int64_t identifier); - - // Native jni functions - static void SetResponseHeader(JNIEnv*, jobject, jint, jstring, jstring); - static jint CreateResponse(JNIEnv*, jobject, jstring, jint, jstring, - jstring, jlong, jstring); - static void ReceivedResponse(JNIEnv*, jobject, jint); - static void AddData(JNIEnv*, jobject, jbyteArray, jint); - static void Finished(JNIEnv*, jobject); - static jstring RedirectedToUrl(JNIEnv*, jobject, jstring, jstring, jint); - static void Error(JNIEnv*, jobject, jint, jstring, jstring); - -protected: - WebCoreResourceLoader(JNIEnv *env, jobject jLoadListener); -private: - jobject mJLoader; - bool mPausedLoad; -}; - -} // end namespace android - -#endif diff --git a/Source/WebKit/android/jni/WebHistory.cpp b/Source/WebKit/android/jni/WebHistory.cpp index aa74b81..1ab8f37 100644 --- a/Source/WebKit/android/jni/WebHistory.cpp +++ b/Source/WebKit/android/jni/WebHistory.cpp @@ -54,9 +54,9 @@ namespace android { // Forward declarations -static void write_item(WTF::Vector<char>& v, WebCore::HistoryItem* item); -static void write_children_recursive(WTF::Vector<char>& v, WebCore::HistoryItem* parent); -static bool read_item_recursive(WebCore::HistoryItem* child, const char** pData, int length); +static void writeItem(WTF::Vector<char>& vector, WebCore::HistoryItem* item); +static void writeChildrenRecursive(WTF::Vector<char>& vector, WebCore::HistoryItem* parent); +static bool readItemRecursive(WebCore::HistoryItem* child, const char** pData, int length); // Field ids for WebHistoryItems struct WebHistoryItemFields { @@ -78,7 +78,7 @@ struct WebBackForwardListFields { static void WebHistoryClose(JNIEnv* env, jobject obj, jint frame) { - LOG_ASSERT(frame, "Close needs a valid Frame pointer!"); + ALOG_ASSERT(frame, "Close needs a valid Frame pointer!"); WebCore::Frame* pFrame = (WebCore::Frame*)frame; WebCore::BackForwardListImpl* list = static_cast<WebCore::BackForwardListImpl*>(pFrame->page()->backForwardList()); @@ -145,7 +145,7 @@ static void WebHistoryClose(JNIEnv* env, jobject obj, jint frame) static void WebHistoryRestoreIndex(JNIEnv* env, jobject obj, jint frame, jint index) { - LOG_ASSERT(frame, "RestoreState needs a valid Frame pointer!"); + ALOG_ASSERT(frame, "RestoreState needs a valid Frame pointer!"); WebCore::Frame* pFrame = (WebCore::Frame*)frame; WebCore::Page* page = pFrame->page(); WebCore::HistoryItem* currentItem = @@ -158,8 +158,8 @@ static void WebHistoryRestoreIndex(JNIEnv* env, jobject obj, jint frame, jint in static void WebHistoryInflate(JNIEnv* env, jobject obj, jint frame, jbyteArray data) { - LOG_ASSERT(frame, "Inflate needs a valid frame pointer!"); - LOG_ASSERT(data, "Inflate needs a valid data pointer!"); + ALOG_ASSERT(frame, "Inflate needs a valid frame pointer!"); + ALOG_ASSERT(data, "Inflate needs a valid data pointer!"); // Get the actual bytes and the length from the java array. const jbyte* bytes = env->GetByteArrayElements(data, NULL); @@ -178,7 +178,7 @@ static void WebHistoryInflate(JNIEnv* env, jobject obj, jint frame, jbyteArray d // ptr's value. We can't pass &bytes since we have to send bytes to // ReleaseByteArrayElements unchanged. const char* ptr = reinterpret_cast<const char*>(bytes); - read_item_recursive(newItem.get(), &ptr, (int)size); + readItemRecursive(newItem.get(), &ptr, (int)size); env->ReleaseByteArrayElements(data, const_cast<jbyte*>(bytes), JNI_ABORT); bridge->setActive(); @@ -194,27 +194,27 @@ static void WebHistoryInflate(JNIEnv* env, jobject obj, jint frame, jbyteArray d // 1 char for isTargetItem. #define HISTORY_MIN_SIZE ((int)(sizeof(unsigned) * 10 + sizeof(char))) -jbyteArray WebHistory::Flatten(JNIEnv* env, WTF::Vector<char>& v, WebCore::HistoryItem* item) +jbyteArray WebHistory::Flatten(JNIEnv* env, WTF::Vector<char>& vector, WebCore::HistoryItem* item) { if (!item) return NULL; // Reserve a vector of chars with an initial size of HISTORY_MIN_SIZE. - v.reserveCapacity(HISTORY_MIN_SIZE); + vector.reserveCapacity(HISTORY_MIN_SIZE); // Write the top-level history item and then write all the children // recursively. - LOG_ASSERT(item->bridge(), "Why don't we have a bridge object here?"); - write_item(v, item); - write_children_recursive(v, item); + ALOG_ASSERT(item->bridge(), "Why don't we have a bridge object here?"); + writeItem(vector, item); + writeChildrenRecursive(vector, item); // Try to create a new java byte array. - jbyteArray b = env->NewByteArray(v.size()); + jbyteArray b = env->NewByteArray(vector.size()); if (!b) return NULL; // Write our flattened data to the java array. - env->SetByteArrayRegion(b, 0, v.size(), (const jbyte*)v.data()); + env->SetByteArrayRegion(b, 0, vector.size(), (const jbyte*)vector.data()); return b; } @@ -246,7 +246,7 @@ void WebHistoryItem::updateHistoryItem(WebCore::HistoryItem* item) { // if the parent only has one ref, it is from this WebHistoryItem. // This means that the matching WebCore::HistoryItem has been freed. // This can happen during clear(). - LOGW("Can't updateHistoryItem as the top HistoryItem is gone"); + ALOGW("Can't updateHistoryItem as the top HistoryItem is gone"); return; } while (webItem->parent()) @@ -256,7 +256,7 @@ void WebHistoryItem::updateHistoryItem(WebCore::HistoryItem* item) { // If a HistoryItem only exists for page cache, it is possible that // the parent HistoryItem destroyed before the child HistoryItem. If // it happens, skip updating. - LOGW("Can't updateHistoryItem as the top HistoryItem is gone"); + ALOGW("Can't updateHistoryItem as the top HistoryItem is gone"); return; } } @@ -311,7 +311,7 @@ void WebHistoryItem::updateHistoryItem(WebCore::HistoryItem* item) { } static void historyItemChanged(WebCore::HistoryItem* item) { - LOG_ASSERT(item, "historyItemChanged called with a null item"); + ALOG_ASSERT(item, "historyItemChanged called with a null item"); if (item->bridge()) item->bridge()->updateHistoryItem(item); @@ -319,7 +319,7 @@ static void historyItemChanged(WebCore::HistoryItem* item) { void WebHistory::AddItem(const AutoJObject& list, WebCore::HistoryItem* item) { - LOG_ASSERT(item, "newItem must take a valid HistoryItem!"); + ALOG_ASSERT(item, "newItem must take a valid HistoryItem!"); // Item already added. Should only happen when we are inflating the list. if (item->bridge() || !list.get()) return; @@ -358,7 +358,7 @@ void WebHistory::UpdateHistoryIndex(const AutoJObject& list, int newIndex) list.env()->CallVoidMethod(list.get(), gWebBackForwardList.mSetCurrentIndex, newIndex); } -static void write_string(WTF::Vector<char>& v, const WTF::String& str) +static void writeString(WTF::Vector<char>& vector, const WTF::String& str) { unsigned strLen = str.length(); // Only do work if the string has data. @@ -366,96 +366,96 @@ static void write_string(WTF::Vector<char>& v, const WTF::String& str) // Determine how much to grow the vector. Use the worst case for utf8 to // avoid reading the string twice. Add sizeof(unsigned) to hold the // string length in utf8. - unsigned vectorLen = v.size() + sizeof(unsigned); + unsigned vectorLen = vector.size() + sizeof(unsigned); unsigned length = (strLen << 2) + vectorLen; // Grow the vector. This will change the value of v.size() but we // remember the original size above. - v.grow(length); + vector.grow(length); // Grab the position to write to. - char* data = v.begin() + vectorLen; + char* data = vector.begin() + vectorLen; // Write the actual string int l = SkUTF16_ToUTF8(str.characters(), strLen, data); - LOGV("Writing string %d %.*s", l, l, data); + ALOGV("Writing string %d %.*s", l, l, data); // Go back and write the utf8 length. Subtract sizeof(unsigned) from // data to get the position to write the length. memcpy(data - sizeof(unsigned), (char*)&l, sizeof(unsigned)); // Shrink the internal state of the vector so we match what was // actually written. - v.shrink(vectorLen + l); + vector.shrink(vectorLen + l); } else - v.append((char*)&strLen, sizeof(unsigned)); + vector.append((char*)&strLen, sizeof(unsigned)); } -static void write_item(WTF::Vector<char>& v, WebCore::HistoryItem* item) +static void writeItem(WTF::Vector<char>& vector, WebCore::HistoryItem* item) { // Original url - write_string(v, item->originalURLString()); + writeString(vector, item->originalURLString()); // Url - write_string(v, item->urlString()); + writeString(vector, item->urlString()); // Title - write_string(v, item->title()); + writeString(vector, item->title()); // Form content type - write_string(v, item->formContentType()); + writeString(vector, item->formContentType()); // Form data const WebCore::FormData* formData = item->formData(); if (formData) { - write_string(v, formData->flattenToString()); + writeString(vector, formData->flattenToString()); // save the identifier as it is not included in the flatten data int64_t id = formData->identifier(); - v.append((char*)&id, sizeof(int64_t)); + vector.append((char*)&id, sizeof(int64_t)); } else - write_string(v, WTF::String()); // Empty constructor does not allocate a buffer. + writeString(vector, WTF::String()); // Empty constructor does not allocate a buffer. // Target - write_string(v, item->target()); + writeString(vector, item->target()); AndroidWebHistoryBridge* bridge = item->bridge(); - LOG_ASSERT(bridge, "We should have a bridge here!"); + ALOG_ASSERT(bridge, "We should have a bridge here!"); // Screen scale const float scale = bridge->scale(); - LOGV("Writing scale %f", scale); - v.append((char*)&scale, sizeof(float)); + ALOGV("Writing scale %f", scale); + vector.append((char*)&scale, sizeof(float)); const float textWrapScale = bridge->textWrapScale(); - LOGV("Writing text wrap scale %f", textWrapScale); - v.append((char*)&textWrapScale, sizeof(float)); + ALOGV("Writing text wrap scale %f", textWrapScale); + vector.append((char*)&textWrapScale, sizeof(float)); // Scroll position. const int scrollX = item->scrollPoint().x(); - v.append((char*)&scrollX, sizeof(int)); + vector.append((char*)&scrollX, sizeof(int)); const int scrollY = item->scrollPoint().y(); - v.append((char*)&scrollY, sizeof(int)); + vector.append((char*)&scrollY, sizeof(int)); // Document state const WTF::Vector<WTF::String>& docState = item->documentState(); WTF::Vector<WTF::String>::const_iterator end = docState.end(); unsigned stateSize = docState.size(); - LOGV("Writing docState %d", stateSize); - v.append((char*)&stateSize, sizeof(unsigned)); + ALOGV("Writing docState %d", stateSize); + vector.append((char*)&stateSize, sizeof(unsigned)); for (WTF::Vector<WTF::String>::const_iterator i = docState.begin(); i != end; ++i) { - write_string(v, *i); + writeString(vector, *i); } // Is target item - LOGV("Writing isTargetItem %d", item->isTargetItem()); - v.append((char)item->isTargetItem()); + ALOGV("Writing isTargetItem %d", item->isTargetItem()); + vector.append((char)item->isTargetItem()); // Children count unsigned childCount = item->children().size(); - LOGV("Writing childCount %d", childCount); - v.append((char*)&childCount, sizeof(unsigned)); + ALOGV("Writing childCount %d", childCount); + vector.append((char*)&childCount, sizeof(unsigned)); } -static void write_children_recursive(WTF::Vector<char>& v, WebCore::HistoryItem* parent) +static void writeChildrenRecursive(WTF::Vector<char>& vector, WebCore::HistoryItem* parent) { const WebCore::HistoryItemVector& children = parent->children(); WebCore::HistoryItemVector::const_iterator end = children.end(); for (WebCore::HistoryItemVector::const_iterator i = children.begin(); i != end; ++i) { WebCore::HistoryItem* item = (*i).get(); - LOG_ASSERT(parent->bridge(), + ALOG_ASSERT(parent->bridge(), "The parent item should have a bridge object!"); if (!item->bridge()) { WebHistoryItem* bridge = new WebHistoryItem(static_cast<WebHistoryItem*>(parent->bridge())); @@ -467,116 +467,223 @@ static void write_children_recursive(WTF::Vector<char>& v, WebCore::HistoryItem* // parent must not have a parent bridge. WebHistoryItem* bridge = static_cast<WebHistoryItem*>(item->bridge()); WebHistoryItem* parentBridge = static_cast<WebHistoryItem*>(parent->bridge()); - LOG_ASSERT(parentBridge->parent() == 0 || + ALOG_ASSERT(parentBridge->parent() == 0 || bridge->parent() == parentBridge, "Somehow this item has an incorrect parent"); bridge->setParent(parentBridge); } - write_item(v, item); - write_children_recursive(v, item); + writeItem(vector, item); + writeChildrenRecursive(vector, item); } } -static bool read_item_recursive(WebCore::HistoryItem* newItem, +bool readUnsigned(const char*& data, const char* end, unsigned& result, const char* dbgLabel = 0); +bool readInt(const char*& data, const char* end, int& result, const char* dbgLabel = 0); +bool readInt64(const char*& data, const char* end, int64_t& result, const char* dbgLabel = 0); +bool readFloat(const char*& data, const char* end, float& result, const char* dbgLabel = 0); +bool readBool(const char*& data, const char* end, bool& result, const char* dbgLabel = 0); +bool readString(const char*& data, const char* end, String& result, const char* dbgLabel = 0); + +bool readUnsigned(const char*& data, const char* end, unsigned& result, const char* dbgLabel) +{ + // Check if we have enough data left to continue. + if ((end < data) || (static_cast<size_t>(end - data) < sizeof(unsigned))) { + ALOGW("\tNot enough data to read unsigned; tag=\"%s\" end=%p data=%p", + dbgLabel ? dbgLabel : "<no tag>", end, data); + return false; + } + + memcpy(&result, data, sizeof(unsigned)); + data += sizeof(unsigned); + if (dbgLabel) + ALOGV("Reading %-16s %u", dbgLabel, result); + return true; +} + +bool readInt(const char*& data, const char* end, int& result, const char* dbgLabel) +{ + // Check if we have enough data left to continue. + if ((end < data) || (static_cast<size_t>(end - data) < sizeof(int))) { + ALOGW("Not enough data to read int; tag=\"%s\" end=%p data=%p", + dbgLabel ? dbgLabel : "<no tag>", end, data); + return false; + } + + memcpy(&result, data, sizeof(int)); + data += sizeof(int); + if (dbgLabel) + ALOGV("Reading %-16s %d", dbgLabel, result); + return true; +} + +bool readInt64(const char*& data, const char* end, int64_t& result, const char* dbgLabel) +{ + // Check if we have enough data left to continue. + if ((end < data) || (static_cast<size_t>(end - data) < sizeof(int64_t))) { + ALOGW("Not enough data to read int64_t; tag=\"%s\" end=%p data=%p", + dbgLabel ? dbgLabel : "<no tag>", end, data); + return false; + } + + memcpy(&result, data, sizeof(int64_t)); + data += sizeof(int64_t); + if (dbgLabel) + ALOGV("Reading %-16s %ll", dbgLabel, result); + return true; +} + +bool readFloat(const char*& data, const char* end, float& result, const char* dbgLabel) +{ + // Check if we have enough data left to continue. + if ((end < data) || (static_cast<size_t>(end - data) < sizeof(float))) { + ALOGW("Not enough data to read float; tag=\"%s\" end=%p data=%p", + dbgLabel ? dbgLabel : "<no tag>", end, data); + return false; + } + + memcpy(&result, data, sizeof(float)); + data += sizeof(float); + if (dbgLabel) + ALOGV("Reading %-16s %f", dbgLabel, result); + return true; +} + +// Note that the return value indicates success or failure, while the result +// parameter indicates the read value of the bool +bool readBool(const char*& data, const char* end, bool& result, const char* dbgLabel) +{ + // Check if we have enough data left to continue. + if ((end < data) || (static_cast<size_t>(end - data) < sizeof(char))) { + ALOGW("Not enough data to read bool; tag=\"%s\" end=%p data=%p", + dbgLabel ? dbgLabel : "<no tag>", end, data); + return false; + } + + char c; + memcpy(&c, data, sizeof(char)); + data += sizeof(char); + if (dbgLabel) + ALOGV("Reading %-16s %d", dbgLabel, c); + result = c; + + // Valid bool results are 0 or 1 + if ((c != 0) && (c != 1)) { + ALOGW("Invalid value for bool; tag=\"%s\" end=%p data=%p c=%u", + dbgLabel ? dbgLabel : "<no tag>", end, data, c); + return false; + } + + return true; +} + +bool readString(const char*& data, const char* end, String& result, const char* dbgLabel) +{ + unsigned stringLength; + if (!readUnsigned(data, end, stringLength)) { + ALOGW("Not enough data to read string length; tag=\"%s\" end=%p data=%p", + dbgLabel ? dbgLabel : "<no tag>", end, data); + return false; + } + + if (dbgLabel) + ALOGV("Reading %-16s %d %.*s", dbgLabel, stringLength, stringLength, data); + + // If length was 0, there will be no string content, but still return true + if (!stringLength) { + result = String(); + return true; + } + + if ((end < data) || ((unsigned)(end - data) < stringLength)) { + ALOGW("Not enough data to read content; tag=\"%s\" end=%p data=%p stringLength=%u", + dbgLabel ? dbgLabel : "<no tag>", end, data, stringLength); + return false; + } + + const unsigned MAX_REASONABLE_STRING_LENGTH = 10000; + if (stringLength > MAX_REASONABLE_STRING_LENGTH) { + ALOGW("String length is suspiciously large (>%d); tag=\"%s\" end=%p data=%p stringLength=%u", + MAX_REASONABLE_STRING_LENGTH, dbgLabel ? dbgLabel : "<no tag>", + end, data, stringLength); + } + + bool decodeFailed = false; + static const WebCore::TextEncoding& encoding = WebCore::UTF8Encoding(); + result = encoding.decode(data, stringLength, true, decodeFailed); + if (decodeFailed) { + ALOGW("Decode failed, tag=\"%s\" end=%p data=%p stringLength=%u content=\"%s\"", + dbgLabel ? dbgLabel : "<no tag>", end, data, stringLength, + result.utf8().data()); + return false; + } + + if (stringLength > MAX_REASONABLE_STRING_LENGTH) { + ALOGW("\tdecodeFailed=%d (flag is ignored) content=\"%s\"", + decodeFailed, result.utf8().data()); + } + + data += stringLength; + return true; +} + +static bool readItemRecursive(WebCore::HistoryItem* newItem, const char** pData, int length) { - if (!pData || length < HISTORY_MIN_SIZE) + if (!pData || length < HISTORY_MIN_SIZE) { + ALOGW("readItemRecursive() bad params; pData=%p length=%d", pData, length); return false; + } - const WebCore::TextEncoding& e = WebCore::UTF8Encoding(); const char* data = *pData; const char* end = data + length; - int sizeofUnsigned = (int)sizeof(unsigned); + String content; // Read the original url - // Read the expected length of the string. - unsigned l; - memcpy(&l, data, sizeofUnsigned); - // Increment data pointer by the size of an unsigned int. - data += sizeofUnsigned; - if (l) { - LOGV("Original url %d %.*s", l, l, data); - // If we have a length, check if that length exceeds the data length - // and return null if there is not enough data. - if (data + l < end) - newItem->setOriginalURLString(e.decode(data, l)); - else - return false; - // Increment the data pointer by the length of the string. - data += l; - } - // Check if we have enough data left to continue. - if (end - data < sizeofUnsigned) + if (readString(data, end, content, "Original url")) + newItem->setOriginalURLString(content); + else return false; // Read the url - memcpy(&l, data, sizeofUnsigned); - data += sizeofUnsigned; - if (l) { - LOGV("Url %d %.*s", l, l, data); - if (data + l < end) - newItem->setURLString(e.decode(data, l)); - else - return false; - data += l; - } - if (end - data < sizeofUnsigned) + if (readString(data, end, content, "Url")) + newItem->setURLString(content); + else return false; // Read the title - memcpy(&l, data, sizeofUnsigned); - data += sizeofUnsigned; - if (l) { - LOGV("Title %d %.*s", l, l, data); - if (data + l < end) - newItem->setTitle(e.decode(data, l)); - else - return false; - data += l; - } - if (end - data < sizeofUnsigned) + if (readString(data, end, content, "Title")) + newItem->setTitle(content); + else return false; // Generate a new ResourceRequest object for populating form information. + // Read the form content type WTF::String formContentType; - WTF::PassRefPtr<WebCore::FormData> formData = NULL; + if (!readString(data, end, formContentType, "Content type")) + return false; - // Read the form content type - memcpy(&l, data, sizeofUnsigned); - data += sizeofUnsigned; - if (l) { - LOGV("Content type %d %.*s", l, l, data); - if (data + l < end) - formContentType = e.decode(data, l); - else - return false; - data += l; - } - if (end - data < sizeofUnsigned) + // Read the form data size + unsigned formDataSize; + if (!readUnsigned(data, end, formDataSize, "Form data size")) return false; // Read the form data - memcpy(&l, data, sizeofUnsigned); - data += sizeofUnsigned; - if (l) { - LOGV("Form data %d %.*s", l, l, data); - if (data + l < end) - formData = WebCore::FormData::create(data, l); - else + WTF::RefPtr<WebCore::FormData> formData; + if (formDataSize) { + ALOGV("Reading Form data %d %.*s", formDataSize, formDataSize, data); + if ((end < data) || ((size_t)(end - data) < formDataSize)) { + ALOGW("\tNot enough data to read form data; returning"); return false; - data += l; - // Read the identifier - { - int64_t id; - int size = (int)sizeof(int64_t); - memcpy(&id, data, size); - data += size; - if (id) - formData->setIdentifier(id); } + formData = WebCore::FormData::create(data, formDataSize); + data += formDataSize; + // Read the identifier + int64_t id; + if (!readInt64(data, end, id, "Form id")) + return false; + if (id) + formData->setIdentifier(id); } - if (end - data < sizeofUnsigned) - return false; // Set up the form info if (formData != NULL) { @@ -588,112 +695,76 @@ static bool read_item_recursive(WebCore::HistoryItem* newItem, } // Read the target - memcpy(&l, data, sizeofUnsigned); - data += sizeofUnsigned; - if (l) { - LOGV("Target %d %.*s", l, l, data); - if (data + l < end) - newItem->setTarget(e.decode(data, l)); - else - return false; - data += l; - } - if (end - data < sizeofUnsigned) + if (readString(data, end, content, "Target")) + newItem->setTarget(content); + else return false; AndroidWebHistoryBridge* bridge = newItem->bridge(); - LOG_ASSERT(bridge, "There should be a bridge object during inflate"); - float fValue; + ALOG_ASSERT(bridge, "There should be a bridge object during inflate"); + // Read the screen scale - memcpy(&fValue, data, sizeof(float)); - LOGV("Screen scale %f", fValue); - bridge->setScale(fValue); - data += sizeof(float); - memcpy(&fValue, data, sizeofUnsigned); - LOGV("Text wrap scale %f", fValue); - bridge->setTextWrapScale(fValue); - data += sizeof(float); + float fValue; + if (readFloat(data, end, fValue, "Screen scale")) + bridge->setScale(fValue); + else + return false; - if (end - data < sizeofUnsigned) + // Read the text wrap scale + if (readFloat(data, end, fValue, "Text wrap scale")) + bridge->setTextWrapScale(fValue); + else return false; // Read scroll position. - int scrollX = 0; - memcpy(&scrollX, data, sizeofUnsigned); - data += sizeofUnsigned; - int scrollY = 0; - memcpy(&scrollY, data, sizeofUnsigned); - data += sizeofUnsigned; - newItem->setScrollPoint(IntPoint(scrollX, scrollY)); - - if (end - data < sizeofUnsigned) + int scrollX; + if (!readInt(data, end, scrollX, "Scroll pos x")) + return false; + int scrollY; + if (!readInt(data, end, scrollY, "Scroll pos y")) return false; + newItem->setScrollPoint(IntPoint(scrollX, scrollY)); // Read the document state - memcpy(&l, data, sizeofUnsigned); - LOGV("Document state %d", l); - data += sizeofUnsigned; - if (l) { - // Check if we have enough data to at least parse the sizes of each - // document state string. - if (data + l * sizeofUnsigned >= end) - return false; + unsigned docStateCount; + if (!readUnsigned(data, end, docStateCount, "Doc state count")) + return false; + if (docStateCount) { // Create a new vector and reserve enough space for the document state. WTF::Vector<WTF::String> docState; - docState.reserveCapacity(l); - while (l--) { - // Check each time if we have enough to parse the length of the next - // string. - if (end - data < sizeofUnsigned) - return false; - int strLen; - memcpy(&strLen, data, sizeofUnsigned); - data += sizeofUnsigned; - if (data + strLen < end) - docState.append(e.decode(data, strLen)); + docState.reserveCapacity(docStateCount); + while (docStateCount--) { + // Read a document state string + if (readString(data, end, content, "Document state")) + docState.append(content); else return false; - LOGV("\t\t%d %.*s", strLen, strLen, data); - data += strLen; } newItem->setDocumentState(docState); } - // Check if we have enough to read the next byte - if (data >= end) - return false; // Read is target item - // Cast the value to unsigned char in order to make a negative value larger - // than 1. A value that is not 0 or 1 is a failure. - unsigned char c = (unsigned char)data[0]; - if (c > 1) - return false; - LOGV("Target item %d", c); - newItem->setIsTargetItem((bool)c); - data++; - if (end - data < sizeofUnsigned) + bool c; + if (readBool(data, end, c, "Target item")) + newItem->setIsTargetItem(c); + else return false; // Read the child count - memcpy(&l, data, sizeofUnsigned); - LOGV("Child count %d", l); - data += sizeofUnsigned; + unsigned count; + if (!readUnsigned(data, end, count, "Child count")) + return false; *pData = data; - if (l) { - // Check if we have the minimum amount need to parse l children. - if (data + l * HISTORY_MIN_SIZE >= end) - return false; - while (l--) { + if (count) { + while (count--) { // No need to check the length each time because read_item_recursive // will return null if there isn't enough data left to parse. - WTF::PassRefPtr<WebCore::HistoryItem> child = WebCore::HistoryItem::create(); + WTF::RefPtr<WebCore::HistoryItem> child = WebCore::HistoryItem::create(); // Set a bridge that will not call into java. child->setBridge(new WebHistoryItem(static_cast<WebHistoryItem*>(bridge))); // Read the child item. - if (!read_item_recursive(child.get(), pData, end - data)) { - child.clear(); + if (!readItemRecursive(child.get(), pData, end - data)) return false; - } child->bridge()->setActive(); newItem->addChildItem(child); } @@ -709,83 +780,86 @@ static bool read_item_recursive(WebCore::HistoryItem* newItem, // main thread will be incorrect and an assert will fire later. // In conclusion, define UNIT_TEST only if you know what you are doing. #ifdef UNIT_TEST -static void unit_test() +static void unitTest() { - LOGD("Entering history unit test!"); + ALOGD("Entering history unit test!"); const char* test1 = new char[0]; WTF::RefPtr<WebCore::HistoryItem> item = WebCore::HistoryItem::create(); WebCore::HistoryItem* testItem = item.get(); testItem->setBridge(new WebHistoryItem(0)); - LOG_ASSERT(!read_item_recursive(testItem, &test1, 0), "0 length array should fail!"); + ALOG_ASSERT(!readItemRecursive(testItem, &test1, 0), "0 length array should fail!"); delete[] test1; const char* test2 = new char[2]; - LOG_ASSERT(!read_item_recursive(testItem, &test2, 2), "Small array should fail!"); + ALOG_ASSERT(!readItemRecursive(testItem, &test2, 2), "Small array should fail!"); delete[] test2; - LOG_ASSERT(!read_item_recursive(testItem, NULL, HISTORY_MIN_SIZE), "Null data should fail!"); + ALOG_ASSERT(!readItemRecursive(testItem, NULL, HISTORY_MIN_SIZE), "Null data should fail!"); // Original Url char* test3 = new char[HISTORY_MIN_SIZE]; const char* ptr = (const char*)test3; memset(test3, 0, HISTORY_MIN_SIZE); *(int*)test3 = 4000; - LOG_ASSERT(!read_item_recursive(testItem, &ptr, HISTORY_MIN_SIZE), "4000 length originalUrl should fail!"); + ALOG_ASSERT(!readItemRecursive(testItem, &ptr, HISTORY_MIN_SIZE), "4000 length originalUrl should fail!"); // Url int offset = 4; memset(test3, 0, HISTORY_MIN_SIZE); ptr = (const char*)test3; *(int*)(test3 + offset) = 4000; - LOG_ASSERT(!read_item_recursive(testItem, &ptr, HISTORY_MIN_SIZE), "4000 length url should fail!"); + ALOG_ASSERT(!readItemRecursive(testItem, &ptr, HISTORY_MIN_SIZE), "4000 length url should fail!"); // Title offset += 4; memset(test3, 0, HISTORY_MIN_SIZE); ptr = (const char*)test3; *(int*)(test3 + offset) = 4000; - LOG_ASSERT(!read_item_recursive(testItem, &ptr, HISTORY_MIN_SIZE), "4000 length title should fail!"); + ALOG_ASSERT(!readItemRecursive(testItem, &ptr, HISTORY_MIN_SIZE), "4000 length title should fail!"); // Form content type offset += 4; memset(test3, 0, HISTORY_MIN_SIZE); ptr = (const char*)test3; *(int*)(test3 + offset) = 4000; - LOG_ASSERT(!read_item_recursive(testItem, &ptr, HISTORY_MIN_SIZE), "4000 length contentType should fail!"); + ALOG_ASSERT(!readItemRecursive(testItem, &ptr, HISTORY_MIN_SIZE), "4000 length contentType should fail!"); // Form data offset += 4; memset(test3, 0, HISTORY_MIN_SIZE); ptr = (const char*)test3; *(int*)(test3 + offset) = 4000; - LOG_ASSERT(!read_item_recursive(testItem, &ptr, HISTORY_MIN_SIZE), "4000 length form data should fail!"); + ALOG_ASSERT(!readItemRecursive(testItem, &ptr, HISTORY_MIN_SIZE), "4000 length form data should fail!"); // Target offset += 4; memset(test3, 0, HISTORY_MIN_SIZE); ptr = (const char*)test3; *(int*)(test3 + offset) = 4000; - LOG_ASSERT(!read_item_recursive(testItem, &ptr, HISTORY_MIN_SIZE), "4000 length target should fail!"); - offset += 4; // Scale + ALOG_ASSERT(!readItemRecursive(testItem, &ptr, HISTORY_MIN_SIZE), "4000 length target should fail!"); + offset += 4; // Screen scale + offset += 4; // Text wrap scale + offset += 4; // Scroll pos x + offset += 4; // Scroll pos y // Document state offset += 4; memset(test3, 0, HISTORY_MIN_SIZE); ptr = (const char*)test3; *(int*)(test3 + offset) = 4000; - LOG_ASSERT(!read_item_recursive(testItem, &ptr, HISTORY_MIN_SIZE), "4000 length document state should fail!"); + ALOG_ASSERT(!readItemRecursive(testItem, &ptr, HISTORY_MIN_SIZE), "4000 length document state should fail!"); // Is target item offset += 1; memset(test3, 0, HISTORY_MIN_SIZE); ptr = (const char*)test3; *(char*)(test3 + offset) = '!'; - LOG_ASSERT(!read_item_recursive(testItem, &ptr, HISTORY_MIN_SIZE), "IsTargetItem should fail with ! as the value!"); + ALOG_ASSERT(!readItemRecursive(testItem, &ptr, HISTORY_MIN_SIZE), "IsTargetItem should fail with ! as the value!"); // Child count offset += 4; memset(test3, 0, HISTORY_MIN_SIZE); ptr = (const char*)test3; *(int*)(test3 + offset) = 4000; - LOG_ASSERT(!read_item_recursive(testItem, &ptr, HISTORY_MIN_SIZE), "4000 kids should fail!"); - offset = 36; + ALOG_ASSERT(!readItemRecursive(testItem, &ptr, HISTORY_MIN_SIZE), "4000 kids should fail!"); // Test document state + offset = 40; delete[] test3; test3 = new char[HISTORY_MIN_SIZE + sizeof(unsigned)]; memset(test3, 0, HISTORY_MIN_SIZE + sizeof(unsigned)); ptr = (const char*)test3; *(int*)(test3 + offset) = 1; *(int*)(test3 + offset + 4) = 20; - LOG_ASSERT(!read_item_recursive(testItem, &ptr, HISTORY_MIN_SIZE + sizeof(unsigned)), "1 20 length document state string should fail!"); + ALOG_ASSERT(!readItemRecursive(testItem, &ptr, HISTORY_MIN_SIZE + sizeof(unsigned)), "1 20 length document state string should fail!"); delete[] test3; test3 = new char[HISTORY_MIN_SIZE + 2 * sizeof(unsigned)]; memset(test3, 0, HISTORY_MIN_SIZE + 2 * sizeof(unsigned)); @@ -793,8 +867,9 @@ static void unit_test() *(int*)(test3 + offset) = 2; *(int*)(test3 + offset + 4) = 0; *(int*)(test3 + offset + 8) = 20; - LOG_ASSERT(!read_item_recursive(testItem, &ptr, HISTORY_MIN_SIZE + 2 * sizeof(unsigned) ), "2 20 length document state string should fail!"); + ALOG_ASSERT(!readItemRecursive(testItem, &ptr, HISTORY_MIN_SIZE + 2 * sizeof(unsigned) ), "2 20 length document state string should fail!"); delete[] test3; + ALOGD("Leaving history unit test!"); } #endif @@ -818,35 +893,35 @@ int registerWebHistory(JNIEnv* env) // Get notified of all changes to history items. WebCore::notifyHistoryItemChanged = historyItemChanged; #ifdef UNIT_TEST - unit_test(); + unitTest(); #endif // Find WebHistoryItem, its constructor, and the update method. jclass clazz = env->FindClass("android/webkit/WebHistoryItem"); - LOG_ASSERT(clazz, "Unable to find class android/webkit/WebHistoryItem"); + ALOG_ASSERT(clazz, "Unable to find class android/webkit/WebHistoryItem"); gWebHistoryItem.mInit = env->GetMethodID(clazz, "<init>", "()V"); - LOG_ASSERT(gWebHistoryItem.mInit, "Could not find WebHistoryItem constructor"); + ALOG_ASSERT(gWebHistoryItem.mInit, "Could not find WebHistoryItem constructor"); gWebHistoryItem.mUpdate = env->GetMethodID(clazz, "update", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Landroid/graphics/Bitmap;[B)V"); - LOG_ASSERT(gWebHistoryItem.mUpdate, "Could not find method update in WebHistoryItem"); + ALOG_ASSERT(gWebHistoryItem.mUpdate, "Could not find method update in WebHistoryItem"); // Find the field ids for mTitle and mUrl. gWebHistoryItem.mTitle = env->GetFieldID(clazz, "mTitle", "Ljava/lang/String;"); - LOG_ASSERT(gWebHistoryItem.mTitle, "Could not find field mTitle in WebHistoryItem"); + ALOG_ASSERT(gWebHistoryItem.mTitle, "Could not find field mTitle in WebHistoryItem"); gWebHistoryItem.mUrl = env->GetFieldID(clazz, "mUrl", "Ljava/lang/String;"); - LOG_ASSERT(gWebHistoryItem.mUrl, "Could not find field mUrl in WebHistoryItem"); + ALOG_ASSERT(gWebHistoryItem.mUrl, "Could not find field mUrl in WebHistoryItem"); env->DeleteLocalRef(clazz); // Find the WebBackForwardList object and method. clazz = env->FindClass("android/webkit/WebBackForwardList"); - LOG_ASSERT(clazz, "Unable to find class android/webkit/WebBackForwardList"); + ALOG_ASSERT(clazz, "Unable to find class android/webkit/WebBackForwardList"); gWebBackForwardList.mAddHistoryItem = env->GetMethodID(clazz, "addHistoryItem", "(Landroid/webkit/WebHistoryItem;)V"); - LOG_ASSERT(gWebBackForwardList.mAddHistoryItem, "Could not find method addHistoryItem"); + ALOG_ASSERT(gWebBackForwardList.mAddHistoryItem, "Could not find method addHistoryItem"); gWebBackForwardList.mRemoveHistoryItem = env->GetMethodID(clazz, "removeHistoryItem", "(I)V"); - LOG_ASSERT(gWebBackForwardList.mRemoveHistoryItem, "Could not find method removeHistoryItem"); + ALOG_ASSERT(gWebBackForwardList.mRemoveHistoryItem, "Could not find method removeHistoryItem"); gWebBackForwardList.mSetCurrentIndex = env->GetMethodID(clazz, "setCurrentIndex", "(I)V"); - LOG_ASSERT(gWebBackForwardList.mSetCurrentIndex, "Could not find method setCurrentIndex"); + ALOG_ASSERT(gWebBackForwardList.mSetCurrentIndex, "Could not find method setCurrentIndex"); env->DeleteLocalRef(clazz); int result = jniRegisterNativeMethods(env, "android/webkit/WebBackForwardList", diff --git a/Source/WebKit/android/jni/WebIconDatabase.cpp b/Source/WebKit/android/jni/WebIconDatabase.cpp index d5f8947..3d988e9 100644 --- a/Source/WebKit/android/jni/WebIconDatabase.cpp +++ b/Source/WebKit/android/jni/WebIconDatabase.cpp @@ -168,7 +168,7 @@ static void Open(JNIEnv* env, jobject obj, jstring path) return; iconDb.setEnabled(true); iconDb.setClient(gIconDatabaseClient); - LOG_ASSERT(path, "No path given to nativeOpen"); + ALOG_ASSERT(path, "No path given to nativeOpen"); WTF::String pathStr = jstringToWtfString(env, path); WTF::CString fullPath = WebCore::pathByAppendingComponent(pathStr, WebCore::IconDatabase::defaultDatabaseFilename()).utf8(); @@ -185,12 +185,12 @@ static void Open(JNIEnv* env, jobject obj, jstring path) } } if (didSetPermissions) { - LOGV("Opening WebIconDatabase file '%s'", pathStr.latin1().data()); + ALOGV("Opening WebIconDatabase file '%s'", pathStr.latin1().data()); bool res = iconDb.open(pathStr, WebCore::IconDatabase::defaultDatabaseFilename()); if (!res) - LOGE("Open failed!"); + ALOGE("Open failed!"); } else - LOGE("Failed to set permissions on '%s'", fullPath.data()); + ALOGE("Failed to set permissions on '%s'", fullPath.data()); } static void Close(JNIEnv* env, jobject obj) @@ -200,37 +200,37 @@ static void Close(JNIEnv* env, jobject obj) static void RemoveAllIcons(JNIEnv* env, jobject obj) { - LOGV("Removing all icons"); + ALOGV("Removing all icons"); WebCore::iconDatabase().removeAllIcons(); } static jobject IconForPageUrl(JNIEnv* env, jobject obj, jstring url) { - LOG_ASSERT(url, "No url given to iconForPageUrl"); + ALOG_ASSERT(url, "No url given to iconForPageUrl"); WTF::String urlStr = jstringToWtfString(env, url); // FIXME: This method should not be used from outside WebCore and will be removed. // http://trac.webkit.org/changeset/81484 WebCore::Image* icon = WebCore::iconDatabase().synchronousIconForPageURL(urlStr, WebCore::IntSize(16, 16)); - LOGV("Retrieving icon for '%s' %p", urlStr.latin1().data(), icon); + ALOGV("Retrieving icon for '%s' %p", urlStr.latin1().data(), icon); return webcoreImageToJavaBitmap(env, icon); } static void RetainIconForPageUrl(JNIEnv* env, jobject obj, jstring url) { - LOG_ASSERT(url, "No url given to retainIconForPageUrl"); + ALOG_ASSERT(url, "No url given to retainIconForPageUrl"); WTF::String urlStr = jstringToWtfString(env, url); - LOGV("Retaining icon for '%s'", urlStr.latin1().data()); + ALOGV("Retaining icon for '%s'", urlStr.latin1().data()); WebCore::iconDatabase().retainIconForPageURL(urlStr); } static void ReleaseIconForPageUrl(JNIEnv* env, jobject obj, jstring url) { - LOG_ASSERT(url, "No url given to releaseIconForPageUrl"); + ALOG_ASSERT(url, "No url given to releaseIconForPageUrl"); WTF::String urlStr = jstringToWtfString(env, url); - LOGV("Releasing icon for '%s'", urlStr.latin1().data()); + ALOGV("Releasing icon for '%s'", urlStr.latin1().data()); WebCore::iconDatabase().releaseIconForPageURL(urlStr); } @@ -256,7 +256,7 @@ int registerWebIconDatabase(JNIEnv* env) { #ifndef NDEBUG jclass webIconDatabase = env->FindClass("android/webkit/WebIconDatabase"); - LOG_ASSERT(webIconDatabase, "Unable to find class android.webkit.WebIconDatabase"); + ALOG_ASSERT(webIconDatabase, "Unable to find class android.webkit.WebIconDatabase"); env->DeleteLocalRef(webIconDatabase); #endif diff --git a/Source/WebKit/android/jni/WebSettings.cpp b/Source/WebKit/android/jni/WebSettings.cpp index 589615d..59ade52 100644 --- a/Source/WebKit/android/jni/WebSettings.cpp +++ b/Source/WebKit/android/jni/WebSettings.cpp @@ -49,9 +49,7 @@ #include "Settings.h" #include "WebCoreFrameBridge.h" #include "WebCoreJni.h" -#if USE(V8) #include "WorkerContextExecutionProxy.h" -#endif #include "WebRequestContext.h" #include "WebViewCore.h" @@ -146,53 +144,51 @@ struct FieldIds { mAutoFillProfilePhoneNumber = env->GetFieldID(autoFillProfileClass, "mPhoneNumber", "Ljava/lang/String;"); env->DeleteLocalRef(autoFillProfileClass); #endif -#if USE(CHROME_NETWORK_STACK) mOverrideCacheMode = env->GetFieldID(clazz, "mOverrideCacheMode", "I"); -#endif - LOG_ASSERT(mLayoutAlgorithm, "Could not find field mLayoutAlgorithm"); - LOG_ASSERT(mTextSize, "Could not find field mTextSize"); - LOG_ASSERT(mStandardFontFamily, "Could not find field mStandardFontFamily"); - LOG_ASSERT(mFixedFontFamily, "Could not find field mFixedFontFamily"); - LOG_ASSERT(mSansSerifFontFamily, "Could not find field mSansSerifFontFamily"); - LOG_ASSERT(mSerifFontFamily, "Could not find field mSerifFontFamily"); - LOG_ASSERT(mCursiveFontFamily, "Could not find field mCursiveFontFamily"); - LOG_ASSERT(mFantasyFontFamily, "Could not find field mFantasyFontFamily"); - LOG_ASSERT(mDefaultTextEncoding, "Could not find field mDefaultTextEncoding"); - LOG_ASSERT(mUserAgent, "Could not find field mUserAgent"); - LOG_ASSERT(mAcceptLanguage, "Could not find field mAcceptLanguage"); - LOG_ASSERT(mMinimumFontSize, "Could not find field mMinimumFontSize"); - LOG_ASSERT(mMinimumLogicalFontSize, "Could not find field mMinimumLogicalFontSize"); - LOG_ASSERT(mDefaultFontSize, "Could not find field mDefaultFontSize"); - LOG_ASSERT(mDefaultFixedFontSize, "Could not find field mDefaultFixedFontSize"); - LOG_ASSERT(mLoadsImagesAutomatically, "Could not find field mLoadsImagesAutomatically"); + ALOG_ASSERT(mLayoutAlgorithm, "Could not find field mLayoutAlgorithm"); + ALOG_ASSERT(mTextSize, "Could not find field mTextSize"); + ALOG_ASSERT(mStandardFontFamily, "Could not find field mStandardFontFamily"); + ALOG_ASSERT(mFixedFontFamily, "Could not find field mFixedFontFamily"); + ALOG_ASSERT(mSansSerifFontFamily, "Could not find field mSansSerifFontFamily"); + ALOG_ASSERT(mSerifFontFamily, "Could not find field mSerifFontFamily"); + ALOG_ASSERT(mCursiveFontFamily, "Could not find field mCursiveFontFamily"); + ALOG_ASSERT(mFantasyFontFamily, "Could not find field mFantasyFontFamily"); + ALOG_ASSERT(mDefaultTextEncoding, "Could not find field mDefaultTextEncoding"); + ALOG_ASSERT(mUserAgent, "Could not find field mUserAgent"); + ALOG_ASSERT(mAcceptLanguage, "Could not find field mAcceptLanguage"); + ALOG_ASSERT(mMinimumFontSize, "Could not find field mMinimumFontSize"); + ALOG_ASSERT(mMinimumLogicalFontSize, "Could not find field mMinimumLogicalFontSize"); + ALOG_ASSERT(mDefaultFontSize, "Could not find field mDefaultFontSize"); + ALOG_ASSERT(mDefaultFixedFontSize, "Could not find field mDefaultFixedFontSize"); + ALOG_ASSERT(mLoadsImagesAutomatically, "Could not find field mLoadsImagesAutomatically"); #ifdef ANDROID_BLOCK_NETWORK_IMAGE - LOG_ASSERT(mBlockNetworkImage, "Could not find field mBlockNetworkImage"); + ALOG_ASSERT(mBlockNetworkImage, "Could not find field mBlockNetworkImage"); #endif - LOG_ASSERT(mBlockNetworkLoads, "Could not find field mBlockNetworkLoads"); - LOG_ASSERT(mJavaScriptEnabled, "Could not find field mJavaScriptEnabled"); - LOG_ASSERT(mPluginState, "Could not find field mPluginState"); + ALOG_ASSERT(mBlockNetworkLoads, "Could not find field mBlockNetworkLoads"); + ALOG_ASSERT(mJavaScriptEnabled, "Could not find field mJavaScriptEnabled"); + ALOG_ASSERT(mPluginState, "Could not find field mPluginState"); #if ENABLE(OFFLINE_WEB_APPLICATIONS) - LOG_ASSERT(mAppCacheEnabled, "Could not find field mAppCacheEnabled"); - LOG_ASSERT(mAppCachePath, "Could not find field mAppCachePath"); - LOG_ASSERT(mAppCacheMaxSize, "Could not find field mAppCacheMaxSize"); + ALOG_ASSERT(mAppCacheEnabled, "Could not find field mAppCacheEnabled"); + ALOG_ASSERT(mAppCachePath, "Could not find field mAppCachePath"); + ALOG_ASSERT(mAppCacheMaxSize, "Could not find field mAppCacheMaxSize"); #endif #if ENABLE(WORKERS) - LOG_ASSERT(mWorkersEnabled, "Could not find field mWorkersEnabled"); + ALOG_ASSERT(mWorkersEnabled, "Could not find field mWorkersEnabled"); #endif - LOG_ASSERT(mJavaScriptCanOpenWindowsAutomatically, + ALOG_ASSERT(mJavaScriptCanOpenWindowsAutomatically, "Could not find field mJavaScriptCanOpenWindowsAutomatically"); - LOG_ASSERT(mUseWideViewport, "Could not find field mUseWideViewport"); - LOG_ASSERT(mSupportMultipleWindows, "Could not find field mSupportMultipleWindows"); - LOG_ASSERT(mShrinksStandaloneImagesToFit, "Could not find field mShrinksStandaloneImagesToFit"); - LOG_ASSERT(mMaximumDecodedImageSize, "Could not find field mMaximumDecodedImageSize"); - LOG_ASSERT(mUseDoubleTree, "Could not find field mUseDoubleTree"); - LOG_ASSERT(mPageCacheCapacity, "Could not find field mPageCacheCapacity"); + ALOG_ASSERT(mUseWideViewport, "Could not find field mUseWideViewport"); + ALOG_ASSERT(mSupportMultipleWindows, "Could not find field mSupportMultipleWindows"); + ALOG_ASSERT(mShrinksStandaloneImagesToFit, "Could not find field mShrinksStandaloneImagesToFit"); + ALOG_ASSERT(mMaximumDecodedImageSize, "Could not find field mMaximumDecodedImageSize"); + ALOG_ASSERT(mUseDoubleTree, "Could not find field mUseDoubleTree"); + ALOG_ASSERT(mPageCacheCapacity, "Could not find field mPageCacheCapacity"); jclass enumClass = env->FindClass("java/lang/Enum"); - LOG_ASSERT(enumClass, "Could not find Enum class!"); + ALOG_ASSERT(enumClass, "Could not find Enum class!"); mOrdinal = env->GetMethodID(enumClass, "ordinal", "()I"); - LOG_ASSERT(mOrdinal, "Could not find method ordinal"); + ALOG_ASSERT(mOrdinal, "Could not find method ordinal"); env->DeleteLocalRef(enumClass); } @@ -267,9 +263,7 @@ struct FieldIds { jfieldID mAutoFillProfileCountry; jfieldID mAutoFillProfilePhoneNumber; #endif -#if USE(CHROME_NETWORK_STACK) jfieldID mOverrideCacheMode; -#endif }; static struct FieldIds* gFieldIds; @@ -315,7 +309,7 @@ public: static void Sync(JNIEnv* env, jobject obj, jint frame) { WebCore::Frame* pFrame = (WebCore::Frame*)frame; - LOG_ASSERT(pFrame, "%s must take a valid frame pointer!", __FUNCTION__); + ALOG_ASSERT(pFrame, "%s must take a valid frame pointer!", __FUNCTION__); WebCore::Settings* s = pFrame->settings(); if (!s) return; @@ -331,7 +325,7 @@ public: pFrame->document()->styleSelectorChanged(WebCore::RecalcStyleImmediately); if (pFrame->document()->renderer()) { recursiveCleanupForFullLayout(pFrame->document()->renderer()); - LOG_ASSERT(pFrame->view(), "No view for this frame when trying to relayout"); + ALOG_ASSERT(pFrame->view(), "No view for this frame when trying to relayout"); pFrame->view()->layout(); // FIXME: This call used to scroll the page to put the focus into view. // It worked on the WebViewCore, but now scrolling is done outside of the @@ -369,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); @@ -377,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); @@ -408,6 +400,10 @@ public: flag = env->GetBooleanField(obj, gFieldIds->mJavaScriptEnabled); s->setJavaScriptEnabled(flag); + // Hyperlink auditing (the ping attribute) has similar privacy + // considerations as does the running of JavaScript, so to keep the UI + // simpler, we leverage the same setting. + s->setHyperlinkAuditingEnabled(flag); // ON = 0 // ON_DEMAND = 1 @@ -420,22 +416,38 @@ public: #endif #if ENABLE(OFFLINE_WEB_APPLICATIONS) - flag = env->GetBooleanField(obj, gFieldIds->mAppCacheEnabled); - s->setOfflineWebApplicationCacheEnabled(flag); - str = (jstring)env->GetObjectField(obj, gFieldIds->mAppCachePath); - if (str) { - String path = jstringToWtfString(env, str); - if (path.length() && cacheStorage().cacheDirectory().isNull()) { - cacheStorage().setCacheDirectory(path); + // We only enable AppCache if it's been enabled with a call to + // setAppCacheEnabled() and if a valid path has been supplied to + // setAppCachePath(). Note that the path is applied to all WebViews + // whereas enabling is applied per WebView. + + // WebCore asserts that the path is only set once. Since the path is + // shared between WebViews, we can't do the required checks to guard + // against this in the Java WebSettings. + bool isPathValid = false; + if (cacheStorage().cacheDirectory().isNull()) { + str = static_cast<jstring>(env->GetObjectField(obj, gFieldIds->mAppCachePath)); + // Check for non-null string as an optimization, as this is the common case. + if (str) { + String path = jstringToWtfString(env, str); + ALOG_ASSERT(!path.empty(), "Java side should never send empty string for AppCache path"); // This database is created on the first load. If the file // doesn't exist, we create it and set its permissions. The // filename must match that in ApplicationCacheStorage.cpp. String filename = pathByAppendingComponent(path, "ApplicationCache.db"); - int fd = open(filename.utf8().data(), O_CREAT | O_EXCL, permissionFlags660); - if (fd >= 0) + int fd = open(filename.utf8().data(), O_CREAT, permissionFlags660); + if (fd >= 0) { close(fd); + cacheStorage().setCacheDirectory(path); + isPathValid = true; + } } - } + } else + isPathValid = true; + + flag = env->GetBooleanField(obj, gFieldIds->mAppCacheEnabled); + s->setOfflineWebApplicationCacheEnabled(flag && isPathValid); + jlong maxsize = env->GetLongField(obj, gFieldIds->mAppCacheMaxSize); cacheStorage().setMaximumSize(maxsize); #endif @@ -571,6 +583,9 @@ public: // This is required to enable the XMLTreeViewer when loading an XML document that // has no style attached to it. http://trac.webkit.org/changeset/79799 s->setDeveloperExtrasEnabled(true); + s->setSpatialNavigationEnabled(true); + + s->setPasswordEchoEnabled(true); } }; @@ -587,7 +602,7 @@ static JNINativeMethod gWebSettingsMethods[] = { int registerWebSettings(JNIEnv* env) { jclass clazz = env->FindClass("android/webkit/WebSettings"); - LOG_ASSERT(clazz, "Unable to find class WebSettings!"); + ALOG_ASSERT(clazz, "Unable to find class WebSettings!"); gFieldIds = new FieldIds(env, clazz); env->DeleteLocalRef(clazz); return jniRegisterNativeMethods(env, "android/webkit/WebSettings", diff --git a/Source/WebKit/android/jni/WebStorage.cpp b/Source/WebKit/android/jni/WebStorage.cpp index 9ce207d..9e9774d 100644 --- a/Source/WebKit/android/jni/WebStorage.cpp +++ b/Source/WebKit/android/jni/WebStorage.cpp @@ -175,7 +175,7 @@ int registerWebStorage(JNIEnv* env) { #ifndef NDEBUG jclass webStorage = env->FindClass("android/webkit/WebStorage"); - LOG_ASSERT(webStorage, "Unable to find class android.webkit.WebStorage"); + ALOG_ASSERT(webStorage, "Unable to find class android.webkit.WebStorage"); env->DeleteLocalRef(webStorage); #endif diff --git a/Source/WebKit/android/jni/WebViewCore.cpp b/Source/WebKit/android/jni/WebViewCore.cpp index 1e406b1..32befc7 100644 --- a/Source/WebKit/android/jni/WebViewCore.cpp +++ b/Source/WebKit/android/jni/WebViewCore.cpp @@ -29,10 +29,10 @@ #include "WebViewCore.h" #include "AccessibilityObject.h" +#include "AndroidHitTestResult.h" #include "Attribute.h" #include "BaseLayerAndroid.h" -#include "CachedNode.h" -#include "CachedRoot.h" +#include "content/address_detector.h" #include "Chrome.h" #include "ChromeClientAndroid.h" #include "ChromiumIncludes.h" @@ -43,6 +43,7 @@ #include "CSSValueKeywords.h" #include "DatabaseTracker.h" #include "Document.h" +#include "DocumentMarkerController.h" #include "DOMWindow.h" #include "DOMSelection.h" #include "Element.h" @@ -78,6 +79,7 @@ #include "HitTestRequest.h" #include "HitTestResult.h" #include "InlineTextBox.h" +#include "KeyboardEvent.h" #include "MemoryUsage.h" #include "NamedNodeMap.h" #include "Navigator.h" @@ -93,6 +95,7 @@ #include "ProgressTracker.h" #include "Range.h" #include "RenderBox.h" +#include "RenderImage.h" #include "RenderInline.h" #include "RenderLayer.h" #include "RenderPart.h" @@ -103,7 +106,9 @@ #include "ResourceRequest.h" #include "RuntimeEnabledFeatures.h" #include "SchemeRegistry.h" +#include "ScriptController.h" #include "SelectionController.h" +#include "SelectText.h" #include "Settings.h" #include "SkANP.h" #include "SkTemplates.h" @@ -113,6 +118,7 @@ #include "SkPicture.h" #include "SkUtils.h" #include "Text.h" +#include "TextIterator.h" #include "TypingCommand.h" #include "WebCache.h" #include "WebCoreFrameBridge.h" @@ -122,19 +128,16 @@ #include "autofill/WebAutofill.h" #include "htmlediting.h" #include "markup.h" +#include "visible_units.h" #include <JNIHelp.h> #include <JNIUtility.h> -#include <ui/KeycodeLabels.h> +#include <androidfw/KeycodeLabels.h> +#include <v8.h> #include <wtf/CurrentTime.h> #include <wtf/text/AtomicString.h> -#include <wtf/text/StringImpl.h> - -#if USE(V8) -#include "ScriptController.h" -#include "V8Counters.h" #include <wtf/text/CString.h> -#endif +#include <wtf/text/StringImpl.h> #if DEBUG_NAV_UI #include "SkTime.h" @@ -153,19 +156,11 @@ FILE* gDomTreeFile = 0; FILE* gRenderTreeFile = 0; #endif -#ifdef ANDROID_INSTRUMENT -#include "TimeCounter.h" -#endif - #if USE(ACCELERATED_COMPOSITING) #include "GraphicsLayerAndroid.h" #include "RenderLayerCompositor.h" #endif -#if USE(V8) -#include <v8.h> -#endif - // In some cases, too many invalidations passed to the UI will slow us down. // Limit ourselves to 32 rectangles, past this just send the area bounds to the UI. // see WebViewCore::recordPictureSet(). @@ -181,6 +176,64 @@ 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(); + } + return false; + } + Frame* child = startFrame->tree()->firstChild(); + while (child) { + bool result = validNode(child, matchFrame, matchNode); + if (result) + return result; + child = child->tree()->nextSibling(); + } + return false; +} + static SkTDArray<WebViewCore*> gInstanceList; void WebViewCore::addInstance(WebViewCore* inst) { @@ -189,7 +242,7 @@ void WebViewCore::addInstance(WebViewCore* inst) { void WebViewCore::removeInstance(WebViewCore* inst) { int index = gInstanceList.find(inst); - LOG_ASSERT(index >= 0, "RemoveInstance inst not found"); + ALOG_ASSERT(index >= 0, "RemoveInstance inst not found"); if (index >= 0) { gInstanceList.removeShuffle(index); } @@ -242,8 +295,6 @@ bool WebViewCore::isSupportedMediaMimeType(const WTF::String& mimeType) { // ---------------------------------------------------------------------------- -#define GET_NATIVE_VIEW(env, obj) ((WebViewCore*)env->GetIntField(obj, gWebViewCoreFields.m_nativeClass)) - // Field ids for WebViewCore struct WebViewCoreFields { jfieldID m_nativeClass; @@ -286,7 +337,6 @@ struct WebViewCore::JavaGlue { jmethodID m_restoreScale; jmethodID m_needTouchEvents; jmethodID m_requestKeyboard; - jmethodID m_requestKeyboardWithSelection; jmethodID m_exceededDatabaseQuota; jmethodID m_reachedMaxAppCacheSize; jmethodID m_populateVisitedLinks; @@ -296,6 +346,7 @@ struct WebViewCore::JavaGlue { jmethodID m_getDeviceOrientationService; jmethodID m_addMessageToConsole; jmethodID m_formDidBlur; + jmethodID m_focusNodeChanged; jmethodID m_getPluginClass; jmethodID m_showFullScreenPlugin; jmethodID m_hideFullScreenPlugin; @@ -305,14 +356,16 @@ struct WebViewCore::JavaGlue { jmethodID m_destroySurface; jmethodID m_getContext; jmethodID m_keepScreenOn; - jmethodID m_sendFindAgain; jmethodID m_showRect; jmethodID m_centerFitRect; jmethodID m_setScrollbarModes; jmethodID m_setInstallableWebApp; jmethodID m_enterFullscreenForVideoLayer; + jmethodID m_exitFullscreenVideo; jmethodID m_setWebTextViewAutoFillable; jmethodID m_selectAt; + jmethodID m_initEditField; + jmethodID m_updateMatchCount; AutoJObject object(JNIEnv* env) { // We hold a weak reference to the Java WebViewCore to avoid memeory // leaks due to circular references when WebView.destroy() is not @@ -332,27 +385,15 @@ struct WebViewCore::JavaGlue { static jmethodID GetJMethod(JNIEnv* env, jclass clazz, const char name[], const char signature[]) { jmethodID m = env->GetMethodID(clazz, name, signature); - LOG_ASSERT(m, "Could not find method %s", name); + ALOG_ASSERT(m, "Could not find method %s", name); return m; } -Mutex WebViewCore::gFrameCacheMutex; -Mutex WebViewCore::gCursorBoundsMutex; - WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* mainframe) - : m_frameCacheKit(0) - , m_navPictureKit(0) - , m_moveGeneration(0) + : m_moveGeneration(0) , m_touchGeneration(0) , m_lastGeneration(0) - , m_updatedFrameCache(true) , m_findIsUp(false) - , m_hasCursorBounds(false) - , m_cursorBounds(WebCore::IntRect(0, 0, 0, 0)) - , m_cursorHitBounds(WebCore::IntRect(0, 0, 0, 0)) - , m_cursorFrame(0) - , m_cursorLocation(WebCore::IntPoint(0, 0)) - , m_cursorNode(0) , m_javaGlue(new JavaGlue) , m_mainFrame(mainframe) , m_popupReply(0) @@ -365,8 +406,6 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m , m_focusBoundsChanged(false) , m_skipContentDraw(false) , m_textGeneration(0) - , m_temp(0) - , m_tempPict(0) , m_maxXScroll(320/4) , m_maxYScroll(240/4) , m_scrollOffsetX(0) @@ -383,7 +422,10 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m , m_groupForVisitedLinks(0) , m_isPaused(false) , m_cacheMode(0) - , m_shouldPaintCaret(true) + , m_fullscreenVideoMode(false) + , m_matchCount(0) + , m_activeMatchIndex(0) + , m_activeMatch(0) , m_pluginInvalTimer(this, &WebViewCore::pluginInvalTimerFired) , m_screenOnCounter(0) , m_currentNodeDomNavigationAxis(0) @@ -391,11 +433,9 @@ 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 { - LOG_ASSERT(m_mainFrame, "Uh oh, somehow a frameview was made without an initial frame!"); + ALOG_ASSERT(m_mainFrame, "Uh oh, somehow a frameview was made without an initial frame!"); jclass clazz = env->GetObjectClass(javaWebViewCore); m_javaGlue->m_obj = env->NewWeakGlobalRef(javaWebViewCore); @@ -415,12 +455,11 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m m_javaGlue->m_sendNotifyProgressFinished = GetJMethod(env, clazz, "sendNotifyProgressFinished", "()V"); m_javaGlue->m_sendViewInvalidate = GetJMethod(env, clazz, "sendViewInvalidate", "(IIII)V"); m_javaGlue->m_updateTextfield = GetJMethod(env, clazz, "updateTextfield", "(IZLjava/lang/String;I)V"); - m_javaGlue->m_updateTextSelection = GetJMethod(env, clazz, "updateTextSelection", "(IIII)V"); + m_javaGlue->m_updateTextSelection = GetJMethod(env, clazz, "updateTextSelection", "(IIIII)V"); m_javaGlue->m_clearTextEntry = GetJMethod(env, clazz, "clearTextEntry", "()V"); m_javaGlue->m_restoreScale = GetJMethod(env, clazz, "restoreScale", "(FF)V"); m_javaGlue->m_needTouchEvents = GetJMethod(env, clazz, "needTouchEvents", "(Z)V"); m_javaGlue->m_requestKeyboard = GetJMethod(env, clazz, "requestKeyboard", "(Z)V"); - m_javaGlue->m_requestKeyboardWithSelection = GetJMethod(env, clazz, "requestKeyboardWithSelection", "(IIII)V"); m_javaGlue->m_exceededDatabaseQuota = GetJMethod(env, clazz, "exceededDatabaseQuota", "(Ljava/lang/String;Ljava/lang/String;JJ)V"); m_javaGlue->m_reachedMaxAppCacheSize = GetJMethod(env, clazz, "reachedMaxAppCacheSize", "(J)V"); m_javaGlue->m_populateVisitedLinks = GetJMethod(env, clazz, "populateVisitedLinks", "()V"); @@ -430,6 +469,7 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m m_javaGlue->m_getDeviceOrientationService = GetJMethod(env, clazz, "getDeviceOrientationService", "()Landroid/webkit/DeviceOrientationService;"); m_javaGlue->m_addMessageToConsole = GetJMethod(env, clazz, "addMessageToConsole", "(Ljava/lang/String;ILjava/lang/String;I)V"); m_javaGlue->m_formDidBlur = GetJMethod(env, clazz, "formDidBlur", "(I)V"); + m_javaGlue->m_focusNodeChanged = GetJMethod(env, clazz, "focusNodeChanged", "(Landroid/webkit/WebViewCore$WebKitHitTest;)V"); m_javaGlue->m_getPluginClass = GetJMethod(env, clazz, "getPluginClass", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Class;"); m_javaGlue->m_showFullScreenPlugin = GetJMethod(env, clazz, "showFullScreenPlugin", "(Landroid/webkit/ViewManager$ChildView;II)V"); m_javaGlue->m_hideFullScreenPlugin = GetJMethod(env, clazz, "hideFullScreenPlugin", "()V"); @@ -439,16 +479,18 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m m_javaGlue->m_destroySurface = GetJMethod(env, clazz, "destroySurface", "(Landroid/webkit/ViewManager$ChildView;)V"); m_javaGlue->m_getContext = GetJMethod(env, clazz, "getContext", "()Landroid/content/Context;"); m_javaGlue->m_keepScreenOn = GetJMethod(env, clazz, "keepScreenOn", "(Z)V"); - m_javaGlue->m_sendFindAgain = GetJMethod(env, clazz, "sendFindAgain", "()V"); m_javaGlue->m_showRect = GetJMethod(env, clazz, "showRect", "(IIIIIIFFFF)V"); m_javaGlue->m_centerFitRect = GetJMethod(env, clazz, "centerFitRect", "(IIII)V"); m_javaGlue->m_setScrollbarModes = GetJMethod(env, clazz, "setScrollbarModes", "(II)V"); m_javaGlue->m_setInstallableWebApp = GetJMethod(env, clazz, "setInstallableWebApp", "()V"); #if ENABLE(VIDEO) m_javaGlue->m_enterFullscreenForVideoLayer = GetJMethod(env, clazz, "enterFullscreenForVideoLayer", "(ILjava/lang/String;)V"); + m_javaGlue->m_exitFullscreenVideo = GetJMethod(env, clazz, "exitFullscreenVideo", "()V"); #endif m_javaGlue->m_setWebTextViewAutoFillable = GetJMethod(env, clazz, "setWebTextViewAutoFillable", "(ILjava/lang/String;)V"); m_javaGlue->m_selectAt = GetJMethod(env, clazz, "selectAt", "(II)V"); + m_javaGlue->m_initEditField = GetJMethod(env, clazz, "initEditField", "(ILjava/lang/String;IZZLjava/lang/String;III)V"); + m_javaGlue->m_updateMatchCount = GetJMethod(env, clazz, "updateMatchCount", "(IILjava/lang/String;)V"); env->DeleteLocalRef(clazz); env->SetIntField(javaWebViewCore, gWebViewCoreFields.m_nativeClass, (jint)this); @@ -463,16 +505,12 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m WebViewCore::addInstance(this); -#if USE(CHROME_NETWORK_STACK) AndroidNetworkLibraryImpl::InitWithApplicationContext(env, 0); -#endif -#if USE(V8) // Static initialisation of certain important V8 static data gets performed at system startup when // libwebcore gets loaded. We now need to associate the WebCore thread with V8 to complete // initialisation. v8::V8::Initialize(); -#endif // Configure any RuntimeEnabled features that we need to change from their default now. // See WebCore/bindings/generic/RuntimeEnabledFeatures.h @@ -494,8 +532,6 @@ WebViewCore::~WebViewCore() m_javaGlue->m_obj = 0; } delete m_javaGlue; - delete m_frameCacheKit; - delete m_navPictureKit; } WebViewCore* WebViewCore::getWebViewCore(const WebCore::FrameView* view) @@ -536,32 +572,21 @@ static bool layoutIfNeededRecursive(WebCore::Frame* f) return success && !v->needsLayout(); } -CacheBuilder& WebViewCore::cacheBuilder() -{ - return FrameLoaderClientAndroid::get(m_mainFrame)->getCacheBuilder(); -} - WebCore::Node* WebViewCore::currentFocus() { - return cacheBuilder().currentFocus(); + return focusedFrame()->document()->focusedNode(); } void WebViewCore::recordPicture(SkPicture* picture) { // if there is no document yet, just return - if (!m_mainFrame->document()) { - DBG_NAV_LOG("no document"); + if (!m_mainFrame->document()) return; - } // Call layout to ensure that the contentWidth and contentHeight are correct - if (!layoutIfNeededRecursive(m_mainFrame)) { - DBG_NAV_LOG("layout failed"); + if (!layoutIfNeededRecursive(m_mainFrame)) return; - } // draw into the picture's recording canvas WebCore::FrameView* view = m_mainFrame->view(); - DBG_NAV_LOGD("view=(w=%d,h=%d)", view->contentsWidth(), - view->contentsHeight()); SkAutoPictureRecord arp(picture, view->contentsWidth(), view->contentsHeight(), PICT_RECORD_FLAGS); SkAutoMemoryUsageProbe mup(__FUNCTION__); @@ -595,11 +620,6 @@ void WebViewCore::recordPictureSet(PictureSet* content) if (!success) return; - { // collect WebViewCoreRecordTimeCounter after layoutIfNeededRecursive -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreRecordTimeCounter); -#endif - // if the webkit page dimensions changed, discard the pictureset and redraw. WebCore::FrameView* view = m_mainFrame->view(); int width = view->contentsWidth(); @@ -669,9 +689,6 @@ void WebViewCore::recordPictureSet(PictureSet* content) height = view->contentsHeight(); } - if (cacheBuilder().pictureSetDisabled()) - content->clear(); - #if USE(ACCELERATED_COMPOSITING) // The invals are not always correct when the content size has changed. For // now, let's just reset the inval so that it invalidates the entire content @@ -710,99 +727,6 @@ void WebViewCore::recordPictureSet(PictureSet* content) // Rebuild the pictureset (webkit repaint) rebuildPictureSet(content); - } // WebViewCoreRecordTimeCounter - - WebCore::Node* oldFocusNode = currentFocus(); - m_frameCacheOutOfDate = true; - WebCore::IntRect oldBounds; - int oldSelStart = 0; - int oldSelEnd = 0; - if (oldFocusNode) { - oldBounds = oldFocusNode->getRect(); - RenderObject* renderer = oldFocusNode->renderer(); - if (renderer && (renderer->isTextArea() || renderer->isTextField())) { - WebCore::RenderTextControl* rtc = - static_cast<WebCore::RenderTextControl*>(renderer); - oldSelStart = rtc->selectionStart(); - oldSelEnd = rtc->selectionEnd(); - } - } else - oldBounds = WebCore::IntRect(0,0,0,0); - unsigned latestVersion = 0; - if (m_check_domtree_version) { - // as domTreeVersion only increment, we can just check the sum to see - // whether we need to update the frame cache - for (Frame* frame = m_mainFrame; frame; frame = frame->tree()->traverseNext()) { - const Document* doc = frame->document(); - latestVersion += doc->domTreeVersion() + doc->styleVersion(); - } - } - DBG_NAV_LOGD("m_lastFocused=%p oldFocusNode=%p" - " m_lastFocusedBounds={%d,%d,%d,%d} oldBounds={%d,%d,%d,%d}" - " m_lastFocusedSelection={%d,%d} oldSelection={%d,%d}" - " m_check_domtree_version=%s latestVersion=%d m_domtree_version=%d", - m_lastFocused, oldFocusNode, - m_lastFocusedBounds.x(), m_lastFocusedBounds.y(), - m_lastFocusedBounds.width(), m_lastFocusedBounds.height(), - oldBounds.x(), oldBounds.y(), oldBounds.width(), oldBounds.height(), - m_lastFocusedSelStart, m_lastFocusedSelEnd, oldSelStart, oldSelEnd, - m_check_domtree_version ? "true" : "false", - latestVersion, m_domtree_version); - if (m_lastFocused == oldFocusNode && m_lastFocusedBounds == oldBounds - && m_lastFocusedSelStart == oldSelStart - && m_lastFocusedSelEnd == oldSelEnd - && !m_findIsUp - && (!m_check_domtree_version || latestVersion == m_domtree_version)) - { - return; - } - m_focusBoundsChanged |= m_lastFocused == oldFocusNode - && m_lastFocusedBounds != oldBounds; - m_lastFocused = oldFocusNode; - m_lastFocusedBounds = oldBounds; - m_lastFocusedSelStart = oldSelStart; - m_lastFocusedSelEnd = oldSelEnd; - m_domtree_version = latestVersion; - DBG_NAV_LOG("call updateFrameCache"); - updateFrameCache(); - if (m_findIsUp) { - LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); - JNIEnv* env = JSC::Bindings::getJNIEnv(); - AutoJObject javaObject = m_javaGlue->object(env); - if (javaObject.get()) { - env->CallVoidMethod(javaObject.get(), m_javaGlue->m_sendFindAgain); - checkException(env); - } - } -} - -// note: updateCursorBounds is called directly by the WebView thread -// This needs to be called each time we call CachedRoot::setCursor() with -// non-null CachedNode/CachedFrame, since otherwise the WebViewCore's data -// about the cursor is incorrect. When we call setCursor(0,0), we need -// to set hasCursorBounds to false. -void WebViewCore::updateCursorBounds(const CachedRoot* root, - const CachedFrame* cachedFrame, const CachedNode* cachedNode) -{ - LOG_ASSERT(root, "updateCursorBounds: root cannot be null"); - LOG_ASSERT(cachedNode, "updateCursorBounds: cachedNode cannot be null"); - LOG_ASSERT(cachedFrame, "updateCursorBounds: cachedFrame cannot be null"); - gCursorBoundsMutex.lock(); - m_hasCursorBounds = !cachedNode->isHidden(); - // If m_hasCursorBounds is false, we never look at the other - // values, so do not bother setting them. - if (m_hasCursorBounds) { - WebCore::IntRect bounds = cachedNode->bounds(cachedFrame); - if (m_cursorBounds != bounds) - DBG_NAV_LOGD("new cursor bounds=(%d,%d,w=%d,h=%d)", - bounds.x(), bounds.y(), bounds.width(), bounds.height()); - m_cursorBounds = bounds; - m_cursorHitBounds = cachedNode->hitBounds(cachedFrame); - m_cursorFrame = cachedFrame->framePointer(); - root->getSimulatedMousePosition(&m_cursorLocation); - m_cursorNode = cachedNode->nodePointer(); - } - gCursorBoundsMutex.unlock(); } void WebViewCore::clearContent() @@ -848,8 +772,6 @@ SkPicture* WebViewCore::rebuildPicture(const SkIRect& inval) void WebViewCore::rebuildPictureSet(PictureSet* pictureSet) { - WebCore::FrameView* view = m_mainFrame->view(); - #ifdef FAST_PICTURESET WTF::Vector<Bucket*>* buckets = pictureSet->bucketsToUpdate(); @@ -911,7 +833,7 @@ BaseLayerAndroid* WebViewCore::createBaseLayer(SkRegion* region) bool layoutSucceeded = layoutIfNeededRecursive(m_mainFrame); m_skipContentDraw = false; // Layout only fails if called during a layout. - LOG_ASSERT(layoutSucceeded, "Can never be called recursively"); + ALOG_ASSERT(layoutSucceeded, "Can never be called recursively"); #if USE(ACCELERATED_COMPOSITING) // We set the background color @@ -945,7 +867,7 @@ BaseLayerAndroid* WebViewCore::recordContent(SkRegion* region, SkIPoint* point) DBG_SET_LOG("start"); // If there is a pending style recalculation, just return. if (m_mainFrame->document()->isPendingStyleRecalc()) { - DBG_SET_LOGD("recordContent: pending style recalc, ignoring."); + DBG_SET_LOG("recordContent: pending style recalc, ignoring."); return 0; } float progress = (float) m_mainFrame->page()->progress()->estimatedProgress(); @@ -977,7 +899,7 @@ void WebViewCore::splitContent(PictureSet* content) #ifdef FAST_PICTURESET #else bool layoutSucceeded = layoutIfNeededRecursive(m_mainFrame); - LOG_ASSERT(layoutSucceeded, "Can never be called recursively"); + ALOG_ASSERT(layoutSucceeded, "Can never be called recursively"); content->split(&m_content); rebuildPictureSet(&m_content); content->set(m_content); @@ -986,9 +908,9 @@ void WebViewCore::splitContent(PictureSet* content) void WebViewCore::scrollTo(int x, int y, bool animate) { - LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); + ALOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); -// LOGD("WebViewCore::scrollTo(%d %d)\n", x, y); +// ALOGD("WebViewCore::scrollTo(%d %d)\n", x, y); JNIEnv* env = JSC::Bindings::getJNIEnv(); AutoJObject javaObject = m_javaGlue->object(env); @@ -1001,7 +923,7 @@ void WebViewCore::scrollTo(int x, int y, bool animate) void WebViewCore::sendNotifyProgressFinished() { - LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); + ALOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); JNIEnv* env = JSC::Bindings::getJNIEnv(); AutoJObject javaObject = m_javaGlue->object(env); if (!javaObject.get()) @@ -1012,7 +934,7 @@ void WebViewCore::sendNotifyProgressFinished() void WebViewCore::viewInvalidate(const WebCore::IntRect& rect) { - LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); + ALOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); JNIEnv* env = JSC::Bindings::getJNIEnv(); AutoJObject javaObject = m_javaGlue->object(env); if (!javaObject.get()) @@ -1072,19 +994,9 @@ void WebViewCore::offInvalidate(const WebCore::IntRect &r) contentInvalidate(r); } -static int pin_pos(int x, int width, int targetWidth) -{ - if (x + width > targetWidth) - x = targetWidth - width; - if (x < 0) - x = 0; - return x; -} - void WebViewCore::didFirstLayout() { - DEBUG_NAV_UI_LOGD("%s", __FUNCTION__); - LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); + ALOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); JNIEnv* env = JSC::Bindings::getJNIEnv(); AutoJObject javaObject = m_javaGlue->object(env); @@ -1094,7 +1006,7 @@ void WebViewCore::didFirstLayout() const WebCore::KURL& url = m_mainFrame->document()->url(); if (url.isEmpty()) return; - LOGV("::WebCore:: didFirstLayout %s", url.string().ascii().data()); + ALOGV("::WebCore:: didFirstLayout %s", url.string().ascii().data()); WebCore::FrameLoadType loadType = m_mainFrame->loader()->loadType(); @@ -1108,17 +1020,11 @@ void WebViewCore::didFirstLayout() // a newly-loaded page. || loadType == WebCore::FrameLoadTypeSame); checkException(env); - - DBG_NAV_LOG("call updateFrameCache"); - m_check_domtree_version = false; - updateFrameCache(); - m_history.setDidFirstLayout(true); } void WebViewCore::updateViewport() { - DEBUG_NAV_UI_LOGD("%s", __FUNCTION__); - LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); + ALOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); JNIEnv* env = JSC::Bindings::getJNIEnv(); AutoJObject javaObject = m_javaGlue->object(env); @@ -1130,8 +1036,7 @@ void WebViewCore::updateViewport() void WebViewCore::restoreScale(float scale, float textWrapScale) { - DEBUG_NAV_UI_LOGD("%s", __FUNCTION__); - LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); + ALOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); JNIEnv* env = JSC::Bindings::getJNIEnv(); AutoJObject javaObject = m_javaGlue->object(env); @@ -1143,8 +1048,7 @@ void WebViewCore::restoreScale(float scale, float textWrapScale) void WebViewCore::needTouchEvents(bool need) { - DEBUG_NAV_UI_LOGD("%s", __FUNCTION__); - LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); + ALOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); #if ENABLE(TOUCH_EVENTS) JNIEnv* env = JSC::Bindings::getJNIEnv(); @@ -1162,26 +1066,9 @@ void WebViewCore::needTouchEvents(bool need) #endif } -void WebViewCore::requestKeyboardWithSelection(const WebCore::Node* node, - int selStart, int selEnd) -{ - DEBUG_NAV_UI_LOGD("%s", __FUNCTION__); - LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); - - JNIEnv* env = JSC::Bindings::getJNIEnv(); - AutoJObject javaObject = m_javaGlue->object(env); - if (!javaObject.get()) - return; - env->CallVoidMethod(javaObject.get(), - m_javaGlue->m_requestKeyboardWithSelection, - reinterpret_cast<int>(node), selStart, selEnd, m_textGeneration); - checkException(env); -} - void WebViewCore::requestKeyboard(bool showKeyboard) { - DEBUG_NAV_UI_LOGD("%s", __FUNCTION__); - LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); + ALOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); JNIEnv* env = JSC::Bindings::getJNIEnv(); AutoJObject javaObject = m_javaGlue->object(env); @@ -1197,35 +1084,8 @@ void WebViewCore::notifyProgressFinished() sendNotifyProgressFinished(); } -void WebViewCore::doMaxScroll(CacheBuilder::Direction dir) -{ - int dx = 0, dy = 0; - - switch (dir) { - case CacheBuilder::LEFT: - dx = -m_maxXScroll; - break; - case CacheBuilder::UP: - dy = -m_maxYScroll; - break; - case CacheBuilder::RIGHT: - dx = m_maxXScroll; - break; - case CacheBuilder::DOWN: - dy = m_maxYScroll; - break; - case CacheBuilder::UNINITIALIZED: - default: - LOG_ASSERT(0, "unexpected focus selector"); - } - WebCore::FrameView* view = m_mainFrame->view(); - this->scrollTo(view->scrollX() + dx, view->scrollY() + dy, true); -} - void WebViewCore::setScrollOffset(int moveGeneration, bool sendScrollEvent, int dx, int dy) { - DBG_NAV_LOGD("{%d,%d} m_scrollOffset=(%d,%d), sendScrollEvent=%d", dx, dy, - m_scrollOffsetX, m_scrollOffsetY, sendScrollEvent); if (m_scrollOffsetX != dx || m_scrollOffsetY != dy) { m_scrollOffsetX = dx; m_scrollOffsetY = dy; @@ -1259,19 +1119,10 @@ void WebViewCore::setScrollOffset(int moveGeneration, bool sendScrollEvent, int // update the currently visible screen sendPluginVisibleScreen(); } - gCursorBoundsMutex.lock(); - bool hasCursorBounds = m_hasCursorBounds; - Frame* frame = (Frame*) m_cursorFrame; - IntPoint location = m_cursorLocation; - gCursorBoundsMutex.unlock(); - if (!hasCursorBounds) - return; - moveMouseIfLatest(moveGeneration, frame, location.x(), location.y()); } void WebViewCore::setGlobalBounds(int x, int y, int h, int v) { - DBG_NAV_LOGD("{%d,%d}", x, y); m_mainFrame->view()->platformWidget()->setWindowBounds(x, y, h, v); } @@ -1290,9 +1141,6 @@ void WebViewCore::setSizeScreenWidthAndScale(int width, int height, int osw = m_screenWidth; int osh = m_screenHeight; int otw = m_textWrapWidth; - float oldScale = m_scale; - DBG_NAV_LOGD("old:(w=%d,h=%d,sw=%d,scale=%g) new:(w=%d,h=%d,sw=%d,scale=%g)", - ow, oh, osw, m_scale, width, height, screenWidth, scale); m_screenWidth = screenWidth; m_screenHeight = screenHeight; m_textWrapWidth = textWrapWidth; @@ -1311,11 +1159,8 @@ void WebViewCore::setSizeScreenWidthAndScale(int width, int height, if (ow != width || (!ignoreHeight && oh != height) || reflow) { WebCore::RenderObject *r = m_mainFrame->contentRenderer(); - DBG_NAV_LOGD("renderer=%p view=(w=%d,h=%d)", r, - screenWidth, screenHeight); if (r) { WebCore::IntPoint anchorPoint = WebCore::IntPoint(anchorX, anchorY); - DBG_NAV_LOGD("anchorX=%d anchorY=%d", anchorX, anchorY); RefPtr<WebCore::Node> node; WebCore::IntRect bounds; WebCore::IntPoint offset; @@ -1330,8 +1175,6 @@ void WebViewCore::setSizeScreenWidthAndScale(int width, int height, } if (node) { bounds = node->getRect(); - DBG_NAV_LOGD("ob:(x=%d,y=%d,w=%d,h=%d)", - bounds.x(), bounds.y(), bounds.width(), bounds.height()); // sites like nytimes.com insert a non-standard tag <nyt_text> // in the html. If it is the HitTestResult, it may have zero // width and height. In this case, use its parent node. @@ -1339,8 +1182,6 @@ void WebViewCore::setSizeScreenWidthAndScale(int width, int height, node = node->parentOrHostNode(); if (node) { bounds = node->getRect(); - DBG_NAV_LOGD("found a zero width node and use its parent, whose ob:(x=%d,y=%d,w=%d,h=%d)", - bounds.x(), bounds.y(), bounds.width(), bounds.height()); } } } @@ -1361,9 +1202,6 @@ void WebViewCore::setSizeScreenWidthAndScale(int width, int height, // scroll to restore current screen center if (node) { const WebCore::IntRect& newBounds = node->getRect(); - DBG_NAV_LOGD("nb:(x=%d,y=%d,w=%d," - "h=%d)", newBounds.x(), newBounds.y(), - newBounds.width(), newBounds.height()); if ((osw && osh && bounds.width() && bounds.height()) && (bounds != newBounds)) { WebCore::FrameView* view = m_mainFrame->view(); @@ -1440,13 +1278,6 @@ void WebViewCore::dumpRenderTree(bool useFile) #endif } -void WebViewCore::dumpNavTree() -{ -#if DUMP_NAV_CACHE - cacheBuilder().mDebug.print(); -#endif -} - HTMLElement* WebViewCore::retrieveElement(int x, int y, const QualifiedName& tagName) { @@ -1455,12 +1286,12 @@ HTMLElement* WebViewCore::retrieveElement(int x, int y, DontHitTestScrollbars, HitTestRequest::Active | HitTestRequest::ReadOnly, IntSize(1, 1)); if (!hitTestResult.innerNode() || !hitTestResult.innerNode()->inDocument()) { - LOGE("Should not happen: no in document Node found"); + ALOGE("Should not happen: no in document Node found"); return 0; } const ListHashSet<RefPtr<Node> >& list = hitTestResult.rectBasedTestResult(); if (list.isEmpty()) { - LOGE("Should not happen: no rect-based-test nodes found"); + ALOGE("Should not happen: no rect-based-test nodes found"); return 0; } Node* node = hitTestResult.innerNode(); @@ -1469,9 +1300,6 @@ HTMLElement* WebViewCore::retrieveElement(int x, int y, || !element->hasTagName(tagName))) { element = element->parentNode(); } - DBG_NAV_LOGD("node=%p element=%p x=%d y=%d nodeName=%s tagName=%s", node, - element, x, y, node->nodeName().utf8().data(), - element ? ((Element*) element)->tagName().utf8().data() : "<none>"); return static_cast<WebCore::HTMLElement*>(element); } @@ -1489,8 +1317,10 @@ HTMLImageElement* WebViewCore::retrieveImageElement(int x, int y) WTF::String WebViewCore::retrieveHref(int x, int y) { - WebCore::HTMLAnchorElement* anchor = retrieveAnchorElement(x, y); - return anchor ? anchor->href() : WTF::String(); + // TODO: This is expensive, cache + HitTestResult result = m_mainFrame->eventHandler()->hitTestResultAtPoint(IntPoint(x, y), + false, false, DontHitTestScrollbars, HitTestRequest::Active | HitTestRequest::ReadOnly, IntSize(1, 1)); + return result.absoluteLinkURL(); } WTF::String WebViewCore::retrieveAnchorText(int x, int y) @@ -1501,14 +1331,16 @@ WTF::String WebViewCore::retrieveAnchorText(int x, int y) WTF::String WebViewCore::retrieveImageSource(int x, int y) { - HTMLImageElement* image = retrieveImageElement(x, y); - return image ? image->src().string() : WTF::String(); + // TODO: This is expensive, cache + HitTestResult result = m_mainFrame->eventHandler()->hitTestResultAtPoint(IntPoint(x, y), + false, false, DontHitTestScrollbars, HitTestRequest::Active | HitTestRequest::ReadOnly, IntSize(1, 1)); + return result.absoluteImageURL(); } WTF::String WebViewCore::requestLabel(WebCore::Frame* frame, WebCore::Node* node) { - if (node && CacheBuilder::validNode(m_mainFrame, frame, node)) { + if (node && validNode(m_mainFrame, frame, node)) { RefPtr<WebCore::NodeList> list = node->document()->getElementsByTagName("label"); unsigned length = list->length(); for (unsigned i = 0; i < length; i++) { @@ -1532,8 +1364,12 @@ WTF::String WebViewCore::requestLabel(WebCore::Frame* frame, static bool isContentEditable(const WebCore::Node* node) { - if (!node) return false; - return node->document()->frame()->selection()->isContentEditable(); + if (!node) + return false; + Frame* frame = node->document()->frame(); + if (!frame) + return false; + return frame->selection()->isContentEditable(); } // Returns true if the node is a textfield, textarea, or contentEditable @@ -1560,107 +1396,9 @@ void WebViewCore::revealSelection() focusedFrame->selection()->revealSelection(ScrollAlignment::alignToEdgeIfNeeded); } -void WebViewCore::updateCacheOnNodeChange() -{ - gCursorBoundsMutex.lock(); - bool hasCursorBounds = m_hasCursorBounds; - Frame* frame = (Frame*) m_cursorFrame; - Node* node = (Node*) m_cursorNode; - IntRect bounds = m_cursorHitBounds; - gCursorBoundsMutex.unlock(); - if (!hasCursorBounds || !node) - return; - if (CacheBuilder::validNode(m_mainFrame, frame, node)) { - RenderObject* renderer = node->renderer(); - if (renderer && renderer->style()->visibility() != HIDDEN) { - IntRect absBox = renderer->absoluteBoundingBoxRect(); - int globalX, globalY; - CacheBuilder::GetGlobalOffset(frame, &globalX, &globalY); - absBox.move(globalX, globalY); - if (absBox == bounds) - return; - DBG_NAV_LOGD("absBox=(%d,%d,%d,%d) bounds=(%d,%d,%d,%d)", - absBox.x(), absBox.y(), absBox.width(), absBox.height(), - bounds.x(), bounds.y(), bounds.width(), bounds.height()); - } - } - DBG_NAV_LOGD("updateFrameCache node=%p", node); - updateFrameCache(); -} - -void WebViewCore::updateFrameCache() -{ - if (!m_frameCacheOutOfDate) { - DBG_NAV_LOG("!m_frameCacheOutOfDate"); - return; - } - - // If there is a pending style recalculation, do not update the frame cache. - // Until the recalculation is complete, there may be internal objects that - // are in an inconsistent state (such as font pointers). - // In any event, there's not much point to updating the cache while a style - // recalculation is pending, since it will simply have to be updated again - // once the recalculation is complete. - // TODO: Do we need to reschedule an update for after the style is recalculated? - if (m_mainFrame && m_mainFrame->document() && m_mainFrame->document()->isPendingStyleRecalc()) { - LOGW("updateFrameCache: pending style recalc, ignoring."); - return; - } -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreBuildNavTimeCounter); -#endif - m_frameCacheOutOfDate = false; - m_temp = new CachedRoot(); - m_temp->init(m_mainFrame, &m_history); -#if USE(ACCELERATED_COMPOSITING) - GraphicsLayerAndroid* graphicsLayer = graphicsRootLayer(); - if (graphicsLayer) - m_temp->setRootLayer(graphicsLayer->contentLayer()); -#endif - CacheBuilder& builder = cacheBuilder(); - WebCore::Settings* settings = m_mainFrame->page()->settings(); - builder.allowAllTextDetection(); -#ifdef ANDROID_META_SUPPORT - if (settings) { - if (!settings->formatDetectionAddress()) - builder.disallowAddressDetection(); - if (!settings->formatDetectionEmail()) - builder.disallowEmailDetection(); - if (!settings->formatDetectionTelephone()) - builder.disallowPhoneDetection(); - } -#endif - builder.buildCache(m_temp); - m_tempPict = new SkPicture(); - recordPicture(m_tempPict); - m_temp->setPicture(m_tempPict); - m_temp->setTextGeneration(m_textGeneration); - WebCoreViewBridge* window = m_mainFrame->view()->platformWidget(); - m_temp->setVisibleRect(WebCore::IntRect(m_scrollOffsetX, - m_scrollOffsetY, window->width(), window->height())); - gFrameCacheMutex.lock(); - delete m_frameCacheKit; - delete m_navPictureKit; - m_frameCacheKit = m_temp; - m_navPictureKit = m_tempPict; - m_updatedFrameCache = true; -#if DEBUG_NAV_UI - const CachedNode* cachedFocusNode = m_frameCacheKit->currentFocus(); - DBG_NAV_LOGD("cachedFocusNode=%d (nodePointer=%p)", - cachedFocusNode ? cachedFocusNode->index() : 0, - cachedFocusNode ? cachedFocusNode->nodePointer() : 0); -#endif - gFrameCacheMutex.unlock(); -} - -void WebViewCore::updateFrameCacheIfLoading() -{ - if (!m_check_domtree_version) - updateFrameCache(); -} - struct TouchNodeData { - Node* mNode; + Node* mUrlNode; + Node* mInnerNode; IntRect mBounds; }; @@ -1668,6 +1406,8 @@ struct TouchNodeData { static IntRect getAbsoluteBoundingBox(Node* node) { IntRect rect; RenderObject* render = node->renderer(); + if (!render) + return rect; if (render->isRenderInline()) rect = toRenderInline(render)->linesVisualOverflowBoundingBox(); else if (render->isBox()) @@ -1675,30 +1415,301 @@ static IntRect getAbsoluteBoundingBox(Node* node) { else if (render->isText()) rect = toRenderText(render)->linesBoundingBox(); else - LOGE("getAbsoluteBoundingBox failed for node %p, name %s", node, render->renderName()); - FloatPoint absPos = render->localToAbsolute(); + ALOGE("getAbsoluteBoundingBox failed for node %p, name %s", node, render->renderName()); + FloatPoint absPos = render->localToAbsolute(FloatPoint(), false, true); rect.move(absPos.x(), absPos.y()); return rect; } +WebCore::Frame* WebViewCore::focusedFrame() const +{ + return m_mainFrame->page()->focusController()->focusedOrMainFrame(); +} + +VisiblePosition WebViewCore::visiblePositionForContentPoint(int x, int y) +{ + return visiblePositionForContentPoint(IntPoint(x, y)); +} + +VisiblePosition WebViewCore::visiblePositionForContentPoint(const IntPoint& point) +{ + // Hit test of this kind required for this to work inside input fields + HitTestRequest request(HitTestRequest::Active + | HitTestRequest::MouseMove + | HitTestRequest::ReadOnly + | HitTestRequest::IgnoreClipping); + HitTestResult result(point); + focusedFrame()->document()->renderView()->layer()->hitTest(request, result); + + // Matching the logic in MouseEventWithHitTestResults::targetNode() + Node* node = result.innerNode(); + if (!node) + return VisiblePosition(); + Element* element = node->parentElement(); + if (!node->inDocument() && element && element->inDocument()) + node = element; + + return node->renderer()->positionForPoint(result.localPoint()); +} + +void WebViewCore::selectWordAt(int x, int y) +{ + HitTestResult hoverResult; + moveMouse(m_mainFrame, x, y, &hoverResult); + if (hoverResult.innerNode()) { + Node* node = hoverResult.innerNode(); + Frame* frame = node->document()->frame(); + Page* page = m_mainFrame->document()->page(); + page->focusController()->setFocusedFrame(frame); + } + + IntPoint point = convertGlobalContentToFrameContent(IntPoint(x, y)); + + // Hit test of this kind required for this to work inside input fields + HitTestRequest request(HitTestRequest::Active); + HitTestResult result(point); + + focusedFrame()->document()->renderView()->layer()->hitTest(request, result); + + // Matching the logic in MouseEventWithHitTestResults::targetNode() + Node* node = result.innerNode(); + if (!node) + return; + Element* element = node->parentElement(); + if (!node->inDocument() && element && element->inDocument()) + node = element; + + SelectionController* sc = focusedFrame()->selection(); + if (!sc->contains(point) && (node->isContentEditable() || node->isTextNode()) && !result.isLiveLink() + && node->dispatchEvent(Event::create(eventNames().selectstartEvent, true, true))) { + VisiblePosition pos(node->renderer()->positionForPoint(result.localPoint())); + selectWordAroundPosition(node->document()->frame(), pos); + } +} + +void WebViewCore::selectWordAroundPosition(Frame* frame, VisiblePosition pos) +{ + VisibleSelection selection(pos); + selection.expandUsingGranularity(WordGranularity); + + if (frame->selection()->shouldChangeSelection(selection)) { + bool allWhitespaces = true; + RefPtr<Range> firstRange = selection.firstRange(); + String text = firstRange.get() ? firstRange->text() : ""; + for (size_t i = 0; i < text.length(); ++i) { + if (!isSpaceOrNewline(text[i])) { + allWhitespaces = false; + break; + } + } + + if (allWhitespaces) { + VisibleSelection emptySelection(selection.visibleStart(), selection.visibleStart()); + frame->selection()->setSelection(emptySelection); + } + frame->selection()->setSelection(selection); + } +} + +int WebViewCore::platformLayerIdFromNode(Node* node, LayerAndroid** outLayer) +{ + if (!node || !node->renderer()) + return -1; + RenderLayer* renderLayer = node->renderer()->enclosingLayer(); + if (!renderLayer || !renderLayer->isComposited()) + return -1; + GraphicsLayer* graphicsLayer = renderLayer->backing()->graphicsLayer(); + if (!graphicsLayer) + return -1; + GraphicsLayerAndroid* agl = static_cast<GraphicsLayerAndroid*>(graphicsLayer); + LayerAndroid* layer = agl->foregroundLayer(); + if (!layer) + layer = agl->contentLayer(); + if (!layer) + return -1; + if (outLayer) + *outLayer = layer; + return layer->uniqueId(); +} + +void WebViewCore::layerToAbsoluteOffset(const LayerAndroid* layer, IntPoint& offset) +{ + while (layer) { + const SkPoint& pos = layer->getPosition(); + offset.move(pos.fX, pos.fY); + const IntPoint& scroll = layer->scrollOffset(); + offset.move(-scroll.x(), -scroll.y()); + layer = static_cast<LayerAndroid*>(layer->getParent()); + } +} + +SelectText* WebViewCore::createSelectText(const VisibleSelection& selection) +{ + // We need to agressively check to see if this is an empty selection to prevent + // accidentally entering text selection mode + bool isCaret = selection.isCaret(); + if (selection.isNone() || (!selection.isContentEditable() && isCaret)) + return 0; + + RefPtr<Range> range = selection.firstRange(); + Node* startContainer = range->startContainer(); + Node* endContainer = range->endContainer(); + + if (!startContainer || !endContainer) + return 0; + if (!isCaret && startContainer == endContainer + && range->startOffset() == range->endOffset()) + return 0; + + SelectText* selectTextContainer = new SelectText(); + IntPoint frameOffset = convertGlobalContentToFrameContent(IntPoint()); + + IntRect startHandle; + IntRect endHandle; + if (isCaret) { + // Caret selection + Position start = selection.start(); + Node* node = start.anchorNode(); + LayerAndroid* layer = 0; + int layerId = platformLayerIdFromNode(node, &layer); + selectTextContainer->setCaretLayerId(SelectText::EndHandle, layerId); + selectTextContainer->setCaretLayerId(SelectText::StartHandle, layerId); + IntPoint layerOffset; + layerToAbsoluteOffset(layer, layerOffset); + RenderObject* r = node->renderer(); + RenderText* renderText = toRenderText(r); + int caretOffset; + InlineBox* inlineBox; + start.getInlineBoxAndOffset(DOWNSTREAM, inlineBox, caretOffset); + startHandle = renderText->localCaretRect(inlineBox, caretOffset); + FloatPoint absoluteOffset = renderText->localToAbsolute(startHandle.location()); + startHandle.setX(absoluteOffset.x() - layerOffset.x()); + startHandle.setY(absoluteOffset.y() - layerOffset.y()); + endHandle = startHandle; + } else { + // Selected range + Node* stopNode = range->pastLastNode(); + for (Node* node = range->firstNode(); node != stopNode; node = node->traverseNextNode()) { + RenderObject* r = node->renderer(); + if (!r || !r->isText() || r->style()->visibility() != VISIBLE) + continue; + RenderText* renderText = toRenderText(r); + int startOffset = node == startContainer ? range->startOffset() : 0; + int endOffset = node == endContainer ? range->endOffset() : numeric_limits<int>::max(); + LayerAndroid* layer = 0; + int layerId = platformLayerIdFromNode(node, &layer); + Vector<IntRect> rects; + renderText->absoluteRectsForRange(rects, startOffset, endOffset, true); + if (rects.size()) { + IntPoint offset; + layerToAbsoluteOffset(layer, offset); + endHandle = rects[rects.size() - 1]; + endHandle.move(-offset.x(), -offset.y()); + selectTextContainer->setCaretLayerId(SelectText::EndHandle, layerId); + if (startHandle.isEmpty()) { + startHandle = rects[0]; + startHandle.move(-offset.x(), -offset.y()); + selectTextContainer->setCaretLayerId(SelectText::StartHandle, layerId); + } + } + selectTextContainer->addHighlightRegion(layer, rects, frameOffset); + } + } + + selectTextContainer->setBaseFirst(selection.isBaseFirst()); + + // Squish the handle rects + startHandle.setWidth(1); + endHandle.move(endHandle.width() - 1, 0); + endHandle.setWidth(1); + startHandle.move(-frameOffset.x(), -frameOffset.y()); + selectTextContainer->setCaretRect(SelectText::StartHandle, startHandle); + endHandle.move(-frameOffset.x(), -frameOffset.y()); + selectTextContainer->setCaretRect(SelectText::EndHandle, endHandle); + + selectTextContainer->setText(range->text()); + + return selectTextContainer; +} + +IntPoint WebViewCore::convertGlobalContentToFrameContent(const IntPoint& point, WebCore::Frame* frame) +{ + if (!frame) frame = focusedFrame(); + IntPoint frameOffset(-m_scrollOffsetX, -m_scrollOffsetY); + frameOffset = frame->view()->windowToContents(frameOffset); + return IntPoint(point.x() + frameOffset.x(), point.y() + frameOffset.y()); +} + +void WebViewCore::selectText(int startX, int startY, int endX, int endY) +{ + SelectionController* sc = focusedFrame()->selection(); + IntPoint startPoint = convertGlobalContentToFrameContent(IntPoint(startX, startY)); + VisiblePosition startPosition(visiblePositionForContentPoint(startPoint)); + IntPoint endPoint = convertGlobalContentToFrameContent(IntPoint(endX, endY)); + VisiblePosition endPosition(visiblePositionForContentPoint(endPoint)); + + if (startPosition.isNull() || endPosition.isNull()) + return; + + // Ensure startPosition is before endPosition + if (comparePositions(startPosition, endPosition) > 0) + swap(startPosition, endPosition); + + if (sc->isContentEditable()) { + startPosition = sc->selection().visibleStart().honorEditableBoundaryAtOrAfter(startPosition); + endPosition = sc->selection().visibleEnd().honorEditableBoundaryAtOrBefore(endPosition); + if (startPosition.isNull() || endPosition.isNull()) { + return; + } + } + + // Ensure startPosition is not at end of block + if (startPosition != endPosition && isEndOfBlock(startPosition)) { + VisiblePosition nextStartPosition(startPosition.next()); + if (!nextStartPosition.isNull()) + startPosition = nextStartPosition; + } + // Ensure endPosition is not at start of block + if (startPosition != endPosition && isStartOfBlock(endPosition)) { + VisiblePosition prevEndPosition(endPosition.previous()); + if (!prevEndPosition.isNull()) + endPosition = prevEndPosition; + } + + VisibleSelection selection(startPosition, endPosition); + // Only allow changes between caret positions or to text selection. + bool selectChangeAllowed = (!selection.isCaret() || sc->isCaret()); + if (selectChangeAllowed && sc->shouldChangeSelection(selection)) + sc->setSelection(selection); +} + // get the highlight rectangles for the touch point (x, y) with the slop -Vector<IntRect> WebViewCore::getTouchHighlightRects(int x, int y, int slop) +AndroidHitTestResult WebViewCore::hitTestAtPoint(int x, int y, int slop, bool doMoveMouse) { - Vector<IntRect> rects; - m_mousePos = IntPoint(x - m_scrollOffsetX, y - m_scrollOffsetY); + if (doMoveMouse) + moveMouse(m_mainFrame, x, y); HitTestResult hitTestResult = m_mainFrame->eventHandler()->hitTestResultAtPoint(IntPoint(x, y), false, false, DontHitTestScrollbars, HitTestRequest::Active | HitTestRequest::ReadOnly, IntSize(slop, slop)); + AndroidHitTestResult androidHitResult(this, hitTestResult); if (!hitTestResult.innerNode() || !hitTestResult.innerNode()->inDocument()) { - LOGE("Should not happen: no in document Node found"); - return rects; + ALOGE("Should not happen: no in document Node found"); + return androidHitResult; } const ListHashSet<RefPtr<Node> >& list = hitTestResult.rectBasedTestResult(); if (list.isEmpty()) { - LOGE("Should not happen: no rect-based-test nodes found"); - return rects; + ALOGE("Should not happen: no rect-based-test nodes found"); + return androidHitResult; } Frame* frame = hitTestResult.innerNode()->document()->frame(); Vector<TouchNodeData> nodeDataList; + if (hitTestResult.innerNode() != hitTestResult.innerNonSharedNode() + && hitTestResult.innerNode()->hasTagName(WebCore::HTMLNames::areaTag)) { + HTMLAreaElement* area = static_cast<HTMLAreaElement*>(hitTestResult.innerNode()); + androidHitResult.hitTestResult().setURLElement(area); + androidHitResult.highlightRects().append(area->computeRect( + hitTestResult.innerNonSharedNode()->renderer())); + return androidHitResult; + } ListHashSet<RefPtr<Node> >::const_iterator last = list.end(); for (ListHashSet<RefPtr<Node> >::const_iterator it = list.begin(); it != last; ++it) { // TODO: it seems reasonable to not search across the frame. Isn't it? @@ -1708,6 +1719,7 @@ Vector<IntRect> WebViewCore::getTouchHighlightRects(int x, int y, int slop) // traverse up the tree to find the first node that needs highlight bool found = false; Node* eventNode = it->get(); + Node* innerNode = eventNode; while (eventNode) { RenderObject* render = eventNode->renderer(); if (render && (render->isBody() || render->isRenderView())) @@ -1715,7 +1727,8 @@ Vector<IntRect> WebViewCore::getTouchHighlightRects(int x, int y, int slop) if (eventNode->supportsFocus() || eventNode->hasEventListeners(eventNames().clickEvent) || eventNode->hasEventListeners(eventNames().mousedownEvent) - || eventNode->hasEventListeners(eventNames().mouseupEvent)) { + || eventNode->hasEventListeners(eventNames().mouseupEvent) + || eventNode->hasEventListeners(eventNames().mouseoverEvent)) { found = true; break; } @@ -1747,7 +1760,7 @@ Vector<IntRect> WebViewCore::getTouchHighlightRects(int x, int y, int slop) Vector<TouchNodeData>::const_iterator nlast = nodeDataList.end(); for (Vector<TouchNodeData>::const_iterator n = nodeDataList.begin(); n != nlast; ++n) { // found the same node, skip it - if (eventNode == n->mNode) { + if (eventNode == n->mUrlNode) { found = false; break; } @@ -1788,16 +1801,19 @@ Vector<IntRect> WebViewCore::getTouchHighlightRects(int x, int y, int slop) } if (!found) { TouchNodeData newNode; - newNode.mNode = eventNode; + newNode.mUrlNode = eventNode; newNode.mBounds = rect; + newNode.mInnerNode = innerNode; nodeDataList.append(newNode); } } - if (!nodeDataList.size()) - return rects; + if (!nodeDataList.size()) { + androidHitResult.searchContentDetectors(); + return androidHitResult; + } // finally select the node with the largest overlap with the fat point TouchNodeData final; - final.mNode = 0; + final.mUrlNode = 0; IntPoint docPos = frame->view()->windowToContents(m_mousePos); IntRect testRect(docPos.x() - slop, docPos.y() - slop, 2 * slop + 1, 2 * slop + 1); int area = 0; @@ -1806,101 +1822,40 @@ Vector<IntRect> WebViewCore::getTouchHighlightRects(int x, int y, int slop) IntRect rect = n->mBounds; rect.intersect(testRect); int a = rect.width() * rect.height(); - if (a > area) { + if (a > area || !final.mUrlNode) { final = *n; area = a; } } // now get the node's highlight rectangles in the page coordinate system - if (final.mNode) { + if (final.mUrlNode) { + if (final.mUrlNode->isElementNode()) { + // We found a URL element. Update the hitTestResult + androidHitResult.setURLElement(static_cast<Element*>(final.mUrlNode)); + } else { + androidHitResult.setURLElement(0); + } + // Update innerNode and innerNonSharedNode + androidHitResult.hitTestResult().setInnerNode(final.mInnerNode); + androidHitResult.hitTestResult().setInnerNonSharedNode(final.mInnerNode); IntPoint frameAdjust; if (frame != m_mainFrame) { frameAdjust = frame->view()->contentsToWindow(IntPoint()); frameAdjust.move(m_scrollOffsetX, m_scrollOffsetY); } - if (final.mNode->isLink()) { - // most of the links are inline instead of box style. So the bounding box is not - // a good representation for the highlights. Get the list of rectangles instead. - RenderObject* render = final.mNode->renderer(); - IntPoint offset = roundedIntPoint(render->localToAbsolute()); - render->absoluteRects(rects, offset.x() + frameAdjust.x(), offset.y() + frameAdjust.y()); - bool inside = false; - int distance = INT_MAX; - int newx = x, newy = y; - int i = rects.size(); - while (i--) { - if (rects[i].isEmpty()) { - rects.remove(i); - continue; - } - // check whether the point (x, y) is inside one of the rectangles. - if (inside) - continue; - if (rects[i].contains(x, y)) { - inside = true; - continue; - } - if (x >= rects[i].x() && x < rects[i].maxX()) { - if (y < rects[i].y()) { - if (rects[i].y() - y < distance) { - newx = x; - newy = rects[i].y(); - distance = rects[i].y() - y; - } - } else if (y >= rects[i].maxY()) { - if (y - rects[i].maxY() + 1 < distance) { - newx = x; - newy = rects[i].maxY() - 1; - distance = y - rects[i].maxY() + 1; - } - } - } else if (y >= rects[i].y() && y < rects[i].maxY()) { - if (x < rects[i].x()) { - if (rects[i].x() - x < distance) { - newx = rects[i].x(); - newy = y; - distance = rects[i].x() - x; - } - } else if (x >= rects[i].maxX()) { - if (x - rects[i].maxX() + 1 < distance) { - newx = rects[i].maxX() - 1; - newy = y; - distance = x - rects[i].maxX() + 1; - } - } - } - } - if (!rects.isEmpty()) { - if (!inside) { - // if neither x nor y has overlap, just pick the top/left of the first rectangle - if (newx == x && newy == y) { - newx = rects[0].x(); - newy = rects[0].y(); - } - m_mousePos.setX(newx - m_scrollOffsetX); - m_mousePos.setY(newy - m_scrollOffsetY); - DBG_NAV_LOGD("Move x/y from (%d, %d) to (%d, %d) scrollOffset is (%d, %d)", - x, y, m_mousePos.x() + m_scrollOffsetX, m_mousePos.y() + m_scrollOffsetY, - m_scrollOffsetX, m_scrollOffsetY); - } - return rects; - } - } IntRect rect = final.mBounds; rect.move(frameAdjust.x(), frameAdjust.y()); - rects.append(rect); - // adjust m_mousePos if it is not inside the returned highlight rectangle - testRect.move(frameAdjust.x(), frameAdjust.y()); - testRect.intersect(rect); - if (!testRect.contains(x, y)) { - m_mousePos = testRect.center(); - m_mousePos.move(-m_scrollOffsetX, -m_scrollOffsetY); - DBG_NAV_LOGD("Move x/y from (%d, %d) to (%d, %d) scrollOffset is (%d, %d)", - x, y, m_mousePos.x() + m_scrollOffsetX, m_mousePos.y() + m_scrollOffsetY, - m_scrollOffsetX, m_scrollOffsetY); + if (doMoveMouse) { + // adjust m_mousePos if it is not inside the returned highlight rectangle + testRect.move(frameAdjust.x(), frameAdjust.y()); + testRect.intersect(rect); + if (!testRect.contains(x, y)) + moveMouse(m_mainFrame, testRect.center().x(), testRect.center().y()); } + } else { + androidHitResult.searchContentDetectors(); } - return rects; + return androidHitResult; } /////////////////////////////////////////////////////////////////////////////// @@ -2071,29 +2026,11 @@ static PluginView* nodeIsPlugin(Node* node) { return 0; } -Node* WebViewCore::cursorNodeIsPlugin() { - gCursorBoundsMutex.lock(); - bool hasCursorBounds = m_hasCursorBounds; - Frame* frame = (Frame*) m_cursorFrame; - Node* node = (Node*) m_cursorNode; - gCursorBoundsMutex.unlock(); - if (hasCursorBounds && CacheBuilder::validNode(m_mainFrame, frame, node) - && nodeIsPlugin(node)) { - return node; - } - return 0; -} - /////////////////////////////////////////////////////////////////////////////// void WebViewCore::moveMouseIfLatest(int moveGeneration, WebCore::Frame* frame, int x, int y) { - DBG_NAV_LOGD("m_moveGeneration=%d moveGeneration=%d" - " frame=%p x=%d y=%d", - m_moveGeneration, moveGeneration, frame, x, y); if (m_moveGeneration > moveGeneration) { - DBG_NAV_LOGD("m_moveGeneration=%d > moveGeneration=%d", - m_moveGeneration, moveGeneration); return; // short-circuit if a newer move has already been generated } m_lastGeneration = moveGeneration; @@ -2102,8 +2039,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 @@ -2120,11 +2056,9 @@ void WebViewCore::moveFocus(WebCore::Frame* frame, WebCore::Node* node) } // Update mouse position -void WebViewCore::moveMouse(WebCore::Frame* frame, int x, int y) +void WebViewCore::moveMouse(WebCore::Frame* frame, int x, int y, HitTestResult* hoveredNode) { - 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); @@ -2133,8 +2067,32 @@ void WebViewCore::moveMouse(WebCore::Frame* frame, int x, int y) WebCore::PlatformMouseEvent mouseEvent(m_mousePos, m_mousePos, WebCore::NoButton, WebCore::MouseEventMoved, 1, false, false, false, false, WTF::currentTime()); - frame->eventHandler()->handleMouseMoveEvent(mouseEvent); - updateCacheOnNodeChange(); + frame->eventHandler()->handleMouseMoveEvent(mouseEvent, hoveredNode); +} + +Position WebViewCore::getPositionForOffset(Node* node, int offset) +{ + Position start = firstPositionInNode(node); + Position end = lastPositionInNode(node); + Document* document = node->document(); + PassRefPtr<Range> range = Range::create(document, start, end); + WebCore::CharacterIterator iterator(range.get()); + iterator.advance(offset); + return iterator.range()->startPosition(); +} + +void WebViewCore::setSelection(Node* node, int start, int end) +{ + RenderTextControl* control = toRenderTextControl(node); + if (control) + setSelectionRange(node, start, end); + else { + Position startPosition = getPositionForOffset(node, start); + Position endPosition = getPositionForOffset(node, end); + VisibleSelection selection(startPosition, endPosition); + SelectionController* selector = node->document()->frame()->selection(); + selector->setSelection(selection); + } } void WebViewCore::setSelection(int start, int end) @@ -2142,28 +2100,22 @@ void WebViewCore::setSelection(int start, int end) WebCore::Node* focus = currentFocus(); if (!focus) return; - WebCore::RenderObject* renderer = focus->renderer(); - if (!renderer || (!renderer->isTextField() && !renderer->isTextArea())) - return; - if (start > end) { - int temp = start; - start = end; - end = temp; - } + if (start > end) + swap(start, end); + // Tell our EditorClient that this change was generated from the UI, so it // does not need to echo it to the UI. EditorClientAndroid* client = static_cast<EditorClientAndroid*>( m_mainFrame->editor()->client()); client->setUiGeneratedSelectionChange(true); - setSelectionRange(focus, start, end); - if (start != end) { + setSelection(focus, start, end); + RenderTextControl* control = toRenderTextControl(focus); + if (start != end && control) { // Fire a select event. No event is sent when the selection reduces to // an insertion point - RenderTextControl* control = toRenderTextControl(renderer); control->selectionChanged(true); } client->setUiGeneratedSelectionChange(false); - WebCore::Frame* focusedFrame = focus->document()->frame(); bool isPasswordField = false; if (focus->isElementNode()) { WebCore::Element* element = static_cast<WebCore::Element*>(focus); @@ -2172,7 +2124,7 @@ void WebViewCore::setSelection(int start, int end) } // For password fields, this is done in the UI side via // bringPointIntoView, since the UI does the drawing. - if (renderer->isTextArea() || !isPasswordField) + if ((control && control->isTextArea()) || !isPasswordField) revealSelection(); } @@ -2197,7 +2149,7 @@ String WebViewCore::modifySelection(const int direction, const int axis) case AXIS_DOCUMENT: return modifySelectionDomNavigationAxis(selection, direction, axis); default: - LOGE("Invalid navigation axis: %d", axis); + ALOGE("Invalid navigation axis: %d", axis); return String(); } } @@ -2238,9 +2190,9 @@ String WebViewCore::modifySelectionTextNavigationAxis(DOMSelection* selection, i // initialize the selection if necessary if (selection->rangeCount() == 0) { if (m_currentNodeDomNavigationAxis - && CacheBuilder::validNode(m_mainFrame, + && validNode(m_mainFrame, m_mainFrame, m_currentNodeDomNavigationAxis)) { - PassRefPtr<Range> rangeRef = + RefPtr<Range> rangeRef = selection->frame()->document()->createRange(); rangeRef->selectNode(m_currentNodeDomNavigationAxis, ec); m_currentNodeDomNavigationAxis = 0; @@ -2249,15 +2201,6 @@ String WebViewCore::modifySelectionTextNavigationAxis(DOMSelection* selection, i selection->addRange(rangeRef.get()); } else if (currentFocus()) { selection->setPosition(currentFocus(), 0, ec); - } else if (m_cursorNode - && CacheBuilder::validNode(m_mainFrame, - m_mainFrame, m_cursorNode)) { - PassRefPtr<Range> rangeRef = - selection->frame()->document()->createRange(); - rangeRef->selectNode(reinterpret_cast<Node*>(m_cursorNode), ec); - if (ec) - return String(); - selection->addRange(rangeRef.get()); } else { selection->setPosition(body, 0, ec); } @@ -2456,13 +2399,13 @@ String WebViewCore::modifySelectionTextNavigationAxis(DOMSelection* selection, i scrollNodeIntoView(m_mainFrame, selection->anchorNode()); // format markup for the visible content - PassRefPtr<Range> range = selection->getRangeAt(0, ec); + RefPtr<Range> range = selection->getRangeAt(0, ec); if (ec) return String(); IntRect bounds = range->boundingBox(); selectAt(bounds.center().x(), bounds.center().y()); markup = formatMarkup(selection); - LOGV("Selection markup: %s", markup.utf8().data()); + ALOGV("Selection markup: %s", markup.utf8().data()); return markup; } @@ -2670,7 +2613,7 @@ String WebViewCore::modifySelectionDomNavigationAxis(DOMSelection* selection, in if (!m_currentNodeDomNavigationAxis) m_currentNodeDomNavigationAxis = currentFocus(); if (!m_currentNodeDomNavigationAxis - || !CacheBuilder::validNode(m_mainFrame, m_mainFrame, + || !validNode(m_mainFrame, m_mainFrame, m_currentNodeDomNavigationAxis)) m_currentNodeDomNavigationAxis = body; Node* currentNode = m_currentNodeDomNavigationAxis; @@ -2714,14 +2657,14 @@ String WebViewCore::modifySelectionDomNavigationAxis(DOMSelection* selection, in if (direction == DIRECTION_FORWARD) currentNode = currentNode->lastDescendant(); } else { - LOGE("Invalid axis: %d", axis); + ALOGE("Invalid axis: %d", axis); return String(); } if (currentNode) { m_currentNodeDomNavigationAxis = currentNode; scrollNodeIntoView(m_mainFrame, currentNode); String selectionString = createMarkup(currentNode); - LOGV("Selection markup: %s", selectionString.utf8().data()); + ALOGV("Selection markup: %s", selectionString.utf8().data()); return selectionString; } return String(); @@ -2771,7 +2714,7 @@ bool WebViewCore::isVisible(Node* node) while (currentNode && currentNode != body) { RenderStyle* style = currentNode->computedStyle(); if (style && - (style->display() == NONE || style->visibility() == HIDDEN)) { + (style->display() == WebCore::NONE || style->visibility() == WebCore::HIDDEN)) { return false; } currentNode = currentNode->parentNode(); @@ -2783,7 +2726,7 @@ String WebViewCore::formatMarkup(DOMSelection* selection) { ExceptionCode ec = 0; String markup = String(); - PassRefPtr<Range> wholeRange = selection->getRangeAt(0, ec); + RefPtr<Range> wholeRange = selection->getRangeAt(0, ec); if (ec) return String(); if (!wholeRange->startContainer() || !wholeRange->startContainer()) @@ -2793,7 +2736,7 @@ String WebViewCore::formatMarkup(DOMSelection* selection) Node* firstNode = wholeRange->firstNode(); Node* pastLastNode = wholeRange->pastLastNode(); Node* currentNode = firstNode; - PassRefPtr<Range> currentRange; + RefPtr<Range> currentRange; while (currentNode != pastLastNode) { Node* nextNode = currentNode->traverseNextNode(); @@ -2870,7 +2813,6 @@ void WebViewCore::deleteSelection(int start, int end, int textGeneration) key(up); client->setUiGeneratedSelectionChange(false); m_textGeneration = textGeneration; - m_shouldPaintCaret = true; } void WebViewCore::replaceTextfieldText(int oldStart, @@ -2886,13 +2828,15 @@ void WebViewCore::replaceTextfieldText(int oldStart, EditorClientAndroid* client = static_cast<EditorClientAndroid*>( m_mainFrame->editor()->client()); client->setUiGeneratedSelectionChange(true); - WebCore::TypingCommand::insertText(focus->document(), replace, - false); + if (replace.length()) + WebCore::TypingCommand::insertText(focus->document(), replace, + false); + else + WebCore::TypingCommand::deleteSelection(focus->document()); client->setUiGeneratedSelectionChange(false); // setSelection calls revealSelection, so there is no need to do it here. setSelection(start, end); m_textGeneration = textGeneration; - m_shouldPaintCaret = true; } void WebViewCore::passToJs(int generation, const WTF::String& current, @@ -2900,13 +2844,6 @@ void WebViewCore::passToJs(int generation, const WTF::String& current, { WebCore::Node* focus = currentFocus(); if (!focus) { - DBG_NAV_LOG("!focus"); - clearTextEntry(); - return; - } - WebCore::RenderObject* renderer = focus->renderer(); - if (!renderer || (!renderer->isTextField() && !renderer->isTextArea())) { - DBG_NAV_LOGD("renderer==%p || not text", renderer); clearTextEntry(); return; } @@ -2921,40 +2858,30 @@ void WebViewCore::passToJs(int generation, const WTF::String& current, client->setUiGeneratedSelectionChange(false); m_blockTextfieldUpdates = false; m_textGeneration = generation; - WebCore::RenderTextControl* renderText = - static_cast<WebCore::RenderTextControl*>(renderer); - WTF::String test = renderText->text(); + WTF::String test = getInputText(focus); if (test != current) { // If the text changed during the key event, update the UI text field. updateTextfield(focus, false, test); - } else { - DBG_NAV_LOG("test == current"); } // Now that the selection has settled down, send it. updateTextSelection(); - m_shouldPaintCaret = true; } void WebViewCore::scrollFocusedTextInput(float xPercent, int y) { WebCore::Node* focus = currentFocus(); if (!focus) { - DBG_NAV_LOG("!focus"); clearTextEntry(); return; } - WebCore::RenderObject* renderer = focus->renderer(); - if (!renderer || (!renderer->isTextField() && !renderer->isTextArea())) { - DBG_NAV_LOGD("renderer==%p || not text", renderer); + WebCore::RenderTextControl* renderText = toRenderTextControl(focus); + if (!renderText) { clearTextEntry(); return; } - WebCore::RenderTextControl* renderText = - static_cast<WebCore::RenderTextControl*>(renderer); + int x = (int) (xPercent * (renderText->scrollWidth() - renderText->clientWidth())); - DBG_NAV_LOGD("x=%d y=%d xPercent=%g scrollW=%d clientW=%d", x, y, - xPercent, renderText->scrollWidth(), renderText->clientWidth()); renderText->setScrollLeft(x); renderText->setScrollTop(y); } @@ -2966,7 +2893,7 @@ void WebViewCore::setFocusControllerActive(bool active) void WebViewCore::saveDocumentState(WebCore::Frame* frame) { - if (!CacheBuilder::validNode(m_mainFrame, frame, 0)) + if (!validNode(m_mainFrame, frame, 0)) frame = m_mainFrame; WebCore::HistoryItem *item = frame->loader()->history()->currentItem(); @@ -2982,9 +2909,9 @@ void WebViewCore::saveDocumentState(WebCore::Frame* frame) static jobjectArray makeLabelArray(JNIEnv* env, const uint16_t** labels, size_t count) { jclass stringClass = env->FindClass("java/lang/String"); - LOG_ASSERT(stringClass, "Could not find java/lang/String"); + ALOG_ASSERT(stringClass, "Could not find java/lang/String"); jobjectArray array = env->NewObjectArray(count, stringClass, 0); - LOG_ASSERT(array, "Could not create new string array"); + ALOG_ASSERT(array, "Could not create new string array"); for (size_t i = 0; i < count; i++) { jobject newString = env->NewString(&labels[i][1], labels[i][0]); @@ -3023,7 +2950,7 @@ void WebViewCore::openFileChooser(PassRefPtr<WebCore::FileChooser> chooser) void WebViewCore::listBoxRequest(WebCoreReply* reply, const uint16_t** labels, size_t count, const int enabled[], size_t enabledCount, bool multiple, const int selected[], size_t selectedCountOrSelection) { - LOG_ASSERT(m_javaGlue->m_obj, "No java widget associated with this view!"); + ALOG_ASSERT(m_javaGlue->m_obj, "No java widget associated with this view!"); JNIEnv* env = JSC::Bindings::getJNIEnv(); AutoJObject javaObject = m_javaGlue->object(env); @@ -3082,14 +3009,15 @@ bool WebViewCore::key(const PlatformKeyboardEvent& event) { WebCore::EventHandler* eventHandler; WebCore::Node* focusNode = currentFocus(); - DBG_NAV_LOGD("keyCode=%s unichar=%d focusNode=%p", - event.keyIdentifier().utf8().data(), event.unichar(), focusNode); if (focusNode) { WebCore::Frame* frame = focusNode->document()->frame(); - WebFrame* webFrame = WebFrame::getWebFrame(frame); eventHandler = frame->eventHandler(); VisibleSelection old = frame->selection()->selection(); + EditorClientAndroid* client = static_cast<EditorClientAndroid*>( + m_mainFrame->editor()->client()); + client->setUiGeneratedSelectionChange(true); bool handled = eventHandler->keyEvent(event); + client->setUiGeneratedSelectionChange(false); if (isContentEditable(focusNode)) { // keyEvent will return true even if the contentEditable did not // change its selection. In the case that it does not, we want to @@ -3099,7 +3027,7 @@ bool WebViewCore::key(const PlatformKeyboardEvent& event) } return handled; } else { - eventHandler = m_mainFrame->eventHandler(); + eventHandler = focusedFrame()->eventHandler(); } return eventHandler->keyEvent(event); } @@ -3114,9 +3042,6 @@ void WebViewCore::click(WebCore::Frame* frame, WebCore::Node* node, bool fake) { hitTestResultAtPoint(pt, false); node = hitTestResult.innerNode(); frame = node->document()->frame(); - DBG_NAV_LOGD("m_mousePos=(%d,%d) m_scrollOffset=(%d,%d) pt=(%d,%d)" - " node=%p", m_mousePos.x(), m_mousePos.y(), - m_scrollOffsetX, m_scrollOffsetY, pt.x(), pt.y(), node); } if (node) { EditorClientAndroid* client @@ -3193,7 +3118,7 @@ bool WebViewCore::handleTouchEvent(int action, Vector<int>& ids, Vector<IntPoint default: // We do not support other kinds of touch event inside WebCore // at the moment. - LOGW("Java passed a touch event type that we do not support in WebCore: %d", action); + ALOGW("Java passed a touch event type that we do not support in WebCore: %d", action); return 0; } @@ -3234,23 +3159,17 @@ void WebViewCore::touchUp(int touchGeneration, frame = node->document()->frame(); else frame = 0; - DBG_NAV_LOGD("touch up on (%d, %d), scrollOffset is (%d, %d), node:%p, frame:%p", m_mousePos.x() + m_scrollOffsetX, m_mousePos.y() + m_scrollOffsetY, m_scrollOffsetX, m_scrollOffsetY, node, frame); } else { - if (m_touchGeneration > touchGeneration) { - DBG_NAV_LOGD("m_touchGeneration=%d > touchGeneration=%d" - " x=%d y=%d", m_touchGeneration, touchGeneration, x, y); + if (m_touchGeneration > touchGeneration) return; // short circuit if a newer touch has been generated - } // This moves m_mousePos to the correct place, and handleMouseClick uses // m_mousePos to determine where the click happens. moveMouse(frame, x, y); m_lastGeneration = touchGeneration; } - if (frame && CacheBuilder::validNode(m_mainFrame, frame, 0)) { + if (frame && validNode(m_mainFrame, frame, 0)) { frame->loader()->resetMultipleFormSubmissionProtection(); } - DBG_NAV_LOGD("touchGeneration=%d handleMouseClick frame=%p node=%p" - " x=%d y=%d", touchGeneration, frame, node, x, y); handleMouseClick(frame, node, false); } @@ -3258,7 +3177,7 @@ void WebViewCore::touchUp(int touchGeneration, // set to hidden, do not show the soft keyboard. Node passed as a parameter // must not be null. static bool shouldSuppressKeyboard(const WebCore::Node* node) { - LOG_ASSERT(node, "node passed to shouldSuppressKeyboard cannot be null"); + ALOG_ASSERT(node, "node passed to shouldSuppressKeyboard cannot be null"); const NamedNodeMap* attributes = node->attributes(); if (!attributes) return false; size_t length = attributes->length(); @@ -3275,7 +3194,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 @@ -3284,7 +3203,6 @@ bool WebViewCore::handleMouseClick(WebCore::Frame* framePtr, WebCore::Node* node webFrame->setUserInitiatedAction(true); nodePtr->dispatchSimulatedClick(0, true, true); webFrame->setUserInitiatedAction(false); - DBG_NAV_LOG("area"); return true; } } @@ -3305,31 +3223,21 @@ bool WebViewCore::handleMouseClick(WebCore::Frame* framePtr, WebCore::Node* node // If the user clicked on a textfield, make the focusController active // so we show the blinking cursor. WebCore::Node* focusNode = currentFocus(); - DBG_NAV_LOGD("m_mousePos={%d,%d} focusNode=%p handled=%s", m_mousePos.x(), - m_mousePos.y(), focusNode, handled ? "true" : "false"); if (focusNode) { - WebCore::RenderObject* renderer = focusNode->renderer(); - if (renderer && (renderer->isTextField() || renderer->isTextArea())) { + WebCore::RenderTextControl* rtc = toRenderTextControl(focusNode); + if (rtc) { bool ime = !shouldSuppressKeyboard(focusNode) && !(static_cast<WebCore::HTMLInputElement*>(focusNode))->readOnly(); if (ime) { #if ENABLE(WEB_AUTOFILL) - if (renderer->isTextField()) { + if (rtc->isTextField()) { EditorClientAndroid* editorC = static_cast<EditorClientAndroid*>(framePtr->page()->editorClient()); WebAutofill* autoFill = editorC->getAutofill(); autoFill->formFieldFocused(static_cast<HTMLFormControlElement*>(focusNode)); } #endif - if (!fake) { - RenderTextControl* rtc - = static_cast<RenderTextControl*> (renderer); - // Force an update of the navcache as this will fire off a - // message to WebView that *must* have an updated focus. - m_frameCacheOutOfDate = true; - updateFrameCache(); - requestKeyboardWithSelection(focusNode, rtc->selectionStart(), - rtc->selectionEnd()); - } + if (!fake) + initEditField(focusNode); } else if (!fake) { requestKeyboard(false); } @@ -3338,7 +3246,7 @@ bool WebViewCore::handleMouseClick(WebCore::Frame* framePtr, WebCore::Node* node // user can type. Otherwise hide the keyboard because no text // input is needed. if (isContentEditable(focusNode)) { - requestKeyboard(true); + initEditField(focusNode); } else if (!nodeIsPlugin(focusNode)) { clearTextEntry(); } @@ -3350,6 +3258,76 @@ bool WebViewCore::handleMouseClick(WebCore::Frame* framePtr, WebCore::Node* node return handled; } +WebViewCore::InputType WebViewCore::getInputType(Node* node) +{ + WebCore::RenderObject* renderer = node->renderer(); + if (!renderer) + return WebViewCore::NONE; + if (renderer->isTextArea()) + return WebViewCore::TEXT_AREA; + + if (node->hasTagName(WebCore::HTMLNames::inputTag)) { + HTMLInputElement* htmlInput = static_cast<HTMLInputElement*>(node); + if (htmlInput->isPasswordField()) + return WebViewCore::PASSWORD; + if (htmlInput->isSearchField()) + return WebViewCore::SEARCH; + if (htmlInput->isEmailField()) + return WebViewCore::EMAIL; + if (htmlInput->isNumberField()) + return WebViewCore::NUMBER; + if (htmlInput->isTelephoneField()) + return WebViewCore::TELEPHONE; + if (htmlInput->isTextField()) + return WebViewCore::NORMAL_TEXT_FIELD; + } + + if (node->isContentEditable()) + return WebViewCore::TEXT_AREA; + + return WebViewCore::NONE; +} + +bool WebViewCore::isSpellCheckEnabled(Node* node) +{ + bool isEnabled = true; + if (node->isElementNode()) { + WebCore::Element* element = static_cast<WebCore::Element*>(node); + isEnabled = element->isSpellCheckingEnabled(); + } + return isEnabled; +} + +void WebViewCore::initEditField(Node* node) +{ + String text = getInputText(node); + int start = 0; + int end = 0; + getSelectionOffsets(node, start, end); + JNIEnv* env = JSC::Bindings::getJNIEnv(); + AutoJObject javaObject = m_javaGlue->object(env); + if (!javaObject.get()) + return; + m_textGeneration = 0; + InputType inputType = getInputType(node); + Document* document = node->document(); + PlatformKeyboardEvent tab(AKEYCODE_TAB, 0, 0, false, false, false, false); + PassRefPtr<KeyboardEvent> tabEvent = + KeyboardEvent::create(tab, document->defaultView()); + Node* nextFocus = document->nextFocusableNode(node, tabEvent.get()); + bool isNextText = isTextInput(nextFocus); + bool spellCheckEnabled = isSpellCheckEnabled(node); + String label = requestLabel(document->frame(), node); + jstring fieldText = wtfStringToJstring(env, text, true); + jstring labelText = wtfStringToJstring(env, text, false); + SelectText* selectText = createSelectText(focusedFrame()->selection()->selection()); + env->CallVoidMethod(javaObject.get(), m_javaGlue->m_initEditField, + reinterpret_cast<int>(node), fieldText, inputType, + spellCheckEnabled, isNextText, labelText, start, end, + reinterpret_cast<int>(selectText)); + checkException(env); +} + void WebViewCore::popupReply(int index) { if (m_popupReply) { @@ -3377,19 +3355,65 @@ void WebViewCore::formDidBlur(const WebCore::Node* node) m_blurringNodePointer = reinterpret_cast<int>(node); } -void WebViewCore::focusNodeChanged(const WebCore::Node* newFocus) +// This is a slightly modified Node::nextNodeConsideringAtomicNodes() with the +// extra constraint of limiting the search to inside a containing parent +WebCore::Node* nextNodeWithinParent(WebCore::Node* parent, WebCore::Node* start) { - if (isTextInput(newFocus)) - m_shouldPaintCaret = true; - else if (m_blurringNodePointer) { - JNIEnv* env = JSC::Bindings::getJNIEnv(); - AutoJObject javaObject = m_javaGlue->object(env); - if (!javaObject.get()) - return; + if (!isAtomicNode(start) && start->firstChild()) + return start->firstChild(); + if (start->nextSibling()) + return start->nextSibling(); + const Node *n = start; + while (n && !n->nextSibling()) { + n = n->parentNode(); + if (n == parent) + return 0; + } + if (n) + return n->nextSibling(); + return 0; +} + +void WebViewCore::focusNodeChanged(WebCore::Node* newFocus) +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + AutoJObject javaObject = m_javaGlue->object(env); + if (!javaObject.get()) + return; + if (!isTextInput(newFocus) && m_blurringNodePointer) { env->CallVoidMethod(javaObject.get(), m_javaGlue->m_formDidBlur, m_blurringNodePointer); checkException(env); m_blurringNodePointer = 0; } + HitTestResult focusHitResult; + focusHitResult.setInnerNode(newFocus); + focusHitResult.setInnerNonSharedNode(newFocus); + if (newFocus && newFocus->isLink() && newFocus->isElementNode()) { + focusHitResult.setURLElement(static_cast<Element*>(newFocus)); + if (newFocus->hasChildNodes() && !newFocus->hasTagName(HTMLNames::imgTag)) { + // Check to see if any of the children are images, and if so + // set them as the innerNode and innerNonSharedNode + // This will stop when it hits the first image. I'm not sure what + // should be done in the case of multiple images inside one anchor... + Node* nextNode = newFocus->firstChild(); + bool found = false; + while (nextNode) { + if (nextNode->hasTagName(HTMLNames::imgTag)) { + found = true; + break; + } + nextNode = nextNodeWithinParent(newFocus, nextNode); + } + if (found) { + focusHitResult.setInnerNode(nextNode); + focusHitResult.setInnerNonSharedNode(nextNode); + } + } + } + AndroidHitTestResult androidHitTest(this, focusHitResult); + jobject jHitTestObj = androidHitTest.createJavaObject(env); + env->CallVoidMethod(javaObject.get(), m_javaGlue->m_focusNodeChanged, jHitTestObj); + env->DeleteLocalRef(jHitTestObj); } void WebViewCore::addMessageToConsole(const WTF::String& message, unsigned int lineNumber, const WTF::String& sourceID, int msgLevel) { @@ -3591,22 +3615,71 @@ WebViewCore::getWebViewJavaObject() return env->GetObjectField(javaObject.get(), gWebViewCoreFields.m_webView); } +RenderTextControl* WebViewCore::toRenderTextControl(Node* node) +{ + RenderTextControl* rtc = 0; + RenderObject* renderer = node->renderer(); + if (renderer && renderer->isTextControl()) { + rtc = WebCore::toRenderTextControl(renderer); + } + return rtc; +} + +void WebViewCore::getSelectionOffsets(Node* node, int& start, int& end) +{ + RenderTextControl* rtc = toRenderTextControl(node); + if (rtc) { + start = rtc->selectionStart(); + end = rtc->selectionEnd(); + } else { + // It must be content editable field. + Document* document = node->document(); + Frame* frame = document->frame(); + SelectionController* selector = frame->selection(); + Position selectionStart = selector->start(); + Position selectionEnd = selector->end(); + Position startOfNode = firstPositionInNode(node); + RefPtr<Range> startRange = Range::create(document, startOfNode, + selectionStart); + start = TextIterator::rangeLength(startRange.get(), true); + RefPtr<Range> endRange = Range::create(document, startOfNode, + selectionEnd); + end = TextIterator::rangeLength(endRange.get(), true); + } +} + +String WebViewCore::getInputText(Node* node) +{ + String text; + WebCore::RenderTextControl* renderText = toRenderTextControl(node); + if (renderText) + text = renderText->text(); + else { + // It must be content editable field. + Position inNode(node, 0); + Position start = firstPositionInNode(node); + Position end = lastPositionInNode(node); + VisibleSelection allEditableText(start, end); + text = allEditableText.firstRange()->text(); + } + return text; +} + void WebViewCore::updateTextSelection() { JNIEnv* env = JSC::Bindings::getJNIEnv(); AutoJObject javaObject = m_javaGlue->object(env); if (!javaObject.get()) return; - WebCore::Node* focusNode = currentFocus(); - if (!focusNode) - return; - RenderObject* renderer = focusNode->renderer(); - if (!renderer || (!renderer->isTextArea() && !renderer->isTextField())) - return; - RenderTextControl* rtc = static_cast<RenderTextControl*>(renderer); + VisibleSelection selection = focusedFrame()->selection()->selection(); + int start = 0; + int end = 0; + if (selection.isCaretOrRange()) + getSelectionOffsets(selection.start().anchorNode(), start, end); + SelectText* selectText = createSelectText(selection); env->CallVoidMethod(javaObject.get(), - m_javaGlue->m_updateTextSelection, reinterpret_cast<int>(focusNode), - rtc->selectionStart(), rtc->selectionEnd(), m_textGeneration); + m_javaGlue->m_updateTextSelection, reinterpret_cast<int>(currentFocus()), + start, end, m_textGeneration, reinterpret_cast<int>(selectText)); checkException(env); } @@ -3783,14 +3856,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; } @@ -3848,6 +3921,20 @@ void WebViewCore::enterFullscreenForVideoLayer(int layerId, const WTF::String& u return; jstring jUrlStr = wtfStringToJstring(env, url); env->CallVoidMethod(javaObject.get(), m_javaGlue->m_enterFullscreenForVideoLayer, layerId, jUrlStr); + m_fullscreenVideoMode = true; + checkException(env); +} + +void WebViewCore::exitFullscreenVideo() +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + AutoJObject javaObject = m_javaGlue->object(env); + if (!javaObject.get()) + return; + if (m_fullscreenVideoMode) { + env->CallVoidMethod(javaObject.get(), m_javaGlue->m_exitFullscreenVideo); + m_fullscreenVideoMode = false; + } checkException(env); } #endif @@ -3873,7 +3960,6 @@ bool WebViewCore::drawIsPaused() const return false; } -#if USE(CHROME_NETWORK_STACK) void WebViewCore::setWebRequestContextUserAgent() { // We cannot create a WebRequestContext, because we might not know it this is a private tab or not yet @@ -3901,7 +3987,6 @@ WebRequestContext* WebViewCore::webRequestContext() } return m_webRequestContext.get(); } -#endif void WebViewCore::scrollRenderLayer(int layer, const SkRect& rect) { @@ -3922,188 +4007,347 @@ void WebViewCore::scrollRenderLayer(int layer, const SkRect& rect) if (!owner) return; - if (owner->stackingContext()) - owner->scrollToOffset(rect.fLeft, rect.fTop); + owner->scrollToOffset(rect.fLeft, rect.fTop); #endif } +Vector<VisibleSelection> WebViewCore::getTextRanges( + int startX, int startY, int endX, int endY) +{ + // These are the positions of the selection handles, + // which reside below the line that they are selecting. + // Use the vertical position higher, which will include + // the selected text. + startY--; + endY--; + VisiblePosition startSelect = visiblePositionForContentPoint(startX, startY); + VisiblePosition endSelect = visiblePositionForContentPoint(endX, endY); + Position start = startSelect.deepEquivalent(); + Position end = endSelect.deepEquivalent(); + Vector<VisibleSelection> ranges; + if (!start.isNull() && !end.isNull()) { + if (comparePositions(start, end) > 0) { + swap(start, end); // RTL start/end positions may be swapped + } + Position nextRangeStart = start; + Position previousRangeEnd; + do { + VisibleSelection selection(nextRangeStart, end); + ranges.append(selection); + previousRangeEnd = selection.end(); + nextRangeStart = nextCandidate(previousRangeEnd); + } while (comparePositions(previousRangeEnd, end) < 0); + } + return ranges; +} + +void WebViewCore::deleteText(int startX, int startY, int endX, int endY) +{ + Vector<VisibleSelection> ranges = + getTextRanges(startX, startY, endX, endY); + + EditorClientAndroid* client = static_cast<EditorClientAndroid*>( + m_mainFrame->editor()->client()); + client->setUiGeneratedSelectionChange(true); + + SelectionController* selector = m_mainFrame->selection(); + for (size_t i = 0; i < ranges.size(); i++) { + const VisibleSelection& selection = ranges[i]; + if (selection.isContentEditable()) { + selector->setSelection(selection, CharacterGranularity); + Document* document = selection.start().anchorNode()->document(); + WebCore::TypingCommand::deleteSelection(document, 0); + } + } + client->setUiGeneratedSelectionChange(false); +} + +void WebViewCore::insertText(const WTF::String &text) +{ + WebCore::Node* focus = currentFocus(); + if (!focus || !isTextInput(focus)) + return; + + Document* document = focus->document(); + + EditorClientAndroid* client = static_cast<EditorClientAndroid*>( + m_mainFrame->editor()->client()); + if (!client) + return; + client->setUiGeneratedSelectionChange(true); + WebCore::TypingCommand::insertText(document, text, + TypingCommand::PreventSpellChecking); + client->setUiGeneratedSelectionChange(false); +} + +void WebViewCore::resetFindOnPage() +{ + m_searchText.truncate(0); + m_matchCount = 0; + m_activeMatchIndex = 0; + m_activeMatch = 0; +} + +int WebViewCore::findTextOnPage(const WTF::String &text) +{ + resetFindOnPage(); // reset even if parameters are bad + + WebCore::Frame* frame = m_mainFrame; + if (!frame) + return 0; + + m_searchText = text; + FindOptions findOptions = WebCore::CaseInsensitive; + + do { + frame->document()->markers()->removeMarkers(DocumentMarker::TextMatch); + m_matchCount += frame->editor()->countMatchesForText(text, findOptions, + 0, true); + updateMatchCount(); + frame->editor()->setMarkedTextMatchesAreHighlighted(true); + frame = frame->tree()->traverseNextWithWrap(false); + } while (frame); + + m_activeMatchIndex = m_matchCount - 1; // prime first findNext + findNextOnPage(true); + return m_matchCount; +} + +void WebViewCore::findNextOnPage(bool forward) +{ + if (!m_mainFrame) + return; + if (!m_matchCount) + return; + + EditorClientAndroid* client = static_cast<EditorClientAndroid*>( + m_mainFrame->editor()->client()); + client->setUiGeneratedSelectionChange(true); + + // Clear previous active match. + if (m_activeMatch) { + m_mainFrame->document()->markers()->setMarkersActive( + m_activeMatch.get(), false); + } + + FindOptions findOptions = WebCore::CaseInsensitive + | WebCore::StartInSelection | WebCore::WrapAround; + if (!forward) + findOptions |= WebCore::Backwards; + + // Start from the previous active match. + if (m_activeMatch) { + m_mainFrame->selection()->setSelection(m_activeMatch.get()); + } + + bool found = m_mainFrame->editor()->findString(m_searchText, findOptions); + if (found) { + VisibleSelection selection(m_mainFrame->selection()->selection()); + if (selection.isNone() || selection.start() == selection.end()) { + // Temporary workaround for findString() refusing to select text + // marked "-webkit-user-select: none". + m_activeMatchIndex = 0; + m_activeMatch = 0; + } else { + // Mark current match "active". + if (forward) { + ++m_activeMatchIndex; + if (m_activeMatchIndex == m_matchCount) + m_activeMatchIndex = 0; + } else { + if (m_activeMatchIndex == 0) + m_activeMatchIndex = m_matchCount; + --m_activeMatchIndex; + } + m_activeMatch = selection.firstRange(); + m_mainFrame->document()->markers()->setMarkersActive( + m_activeMatch.get(), true); + m_mainFrame->selection()->revealSelection( + ScrollAlignment::alignCenterIfNeeded, true); + } + updateMatchCount(); + } + + // Clear selection so it doesn't display. + m_mainFrame->selection()->clear(); + client->setUiGeneratedSelectionChange(false); +} + +void WebViewCore::updateMatchCount() const +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + AutoJObject javaObject = m_javaGlue->object(env); + if (!javaObject.get()) + return; + jstring javaText = wtfStringToJstring(env, m_searchText, true); + env->CallVoidMethod(javaObject.get(), m_javaGlue->m_updateMatchCount, + m_activeMatchIndex, m_matchCount, javaText); + checkException(env); +} + +String WebViewCore::getText(int startX, int startY, int endX, int endY) +{ + String text; + + Vector<VisibleSelection> ranges = + getTextRanges(startX, startY, endX, endY); + + for (size_t i = 0; i < ranges.size(); i++) { + const VisibleSelection& selection = ranges[i]; + PassRefPtr<Range> range = selection.firstRange(); + String textInRange = range->text(); + if (textInRange.length() > 0) { + if (text.length() > 0) + text.append('\n'); + text.append(textInRange); + } + } + + return text; +} + //---------------------------------------------------------------------- // Native JNI methods //---------------------------------------------------------------------- -static void RevealSelection(JNIEnv *env, jobject obj) +static void RevealSelection(JNIEnv* env, jobject obj, jint nativeClass) { - GET_NATIVE_VIEW(env, obj)->revealSelection(); + reinterpret_cast<WebViewCore*>(nativeClass)->revealSelection(); } -static jstring RequestLabel(JNIEnv *env, jobject obj, int framePointer, - int nodePointer) +static jstring RequestLabel(JNIEnv* env, jobject obj, jint nativeClass, + int framePointer, int nodePointer) { - return wtfStringToJstring(env, GET_NATIVE_VIEW(env, obj)->requestLabel( + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + return wtfStringToJstring(env, viewImpl->requestLabel( (WebCore::Frame*) framePointer, (WebCore::Node*) nodePointer)); } -static void ClearContent(JNIEnv *env, jobject obj) +static void ClearContent(JNIEnv* env, jobject obj, jint nativeClass) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); viewImpl->clearContent(); } -static void UpdateFrameCacheIfLoading(JNIEnv *env, jobject obj) +static void UpdateFrameCacheIfLoading(JNIEnv* env, jobject obj, jint nativeClass) { - GET_NATIVE_VIEW(env, obj)->updateFrameCacheIfLoading(); } -static void SetSize(JNIEnv *env, jobject obj, jint width, jint height, - jint textWrapWidth, jfloat scale, jint screenWidth, jint screenHeight, - jint anchorX, jint anchorY, jboolean ignoreHeight) +static void SetSize(JNIEnv* env, jobject obj, jint nativeClass, jint width, + jint height, jint textWrapWidth, jfloat scale, jint screenWidth, + jint screenHeight, jint anchorX, jint anchorY, jboolean ignoreHeight) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOGV("webviewcore::nativeSetSize(%u %u)\n viewImpl: %p", (unsigned)width, (unsigned)height, viewImpl); - LOG_ASSERT(viewImpl, "viewImpl not set in nativeSetSize"); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + ALOGV("webviewcore::nativeSetSize(%u %u)\n viewImpl: %p", (unsigned)width, (unsigned)height, viewImpl); + ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSetSize"); viewImpl->setSizeScreenWidthAndScale(width, height, textWrapWidth, scale, screenWidth, screenHeight, anchorX, anchorY, ignoreHeight); } -static void SetScrollOffset(JNIEnv *env, jobject obj, jint gen, jboolean sendScrollEvent, jint x, jint y) +static void SetScrollOffset(JNIEnv* env, jobject obj, jint nativeClass, + jint gen, jboolean sendScrollEvent, jint x, jint y) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "need viewImpl"); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + ALOG_ASSERT(viewImpl, "need viewImpl"); viewImpl->setScrollOffset(gen, sendScrollEvent, x, y); } -static void SetGlobalBounds(JNIEnv *env, jobject obj, jint x, jint y, jint h, - jint v) +static void SetGlobalBounds(JNIEnv* env, jobject obj, jint nativeClass, + jint x, jint y, jint h, jint v) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "need viewImpl"); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + ALOG_ASSERT(viewImpl, "need viewImpl"); viewImpl->setGlobalBounds(x, y, h, v); } -static jboolean Key(JNIEnv *env, jobject obj, jint keyCode, jint unichar, - jint repeatCount, jboolean isShift, jboolean isAlt, jboolean isSym, - jboolean isDown) +static jboolean Key(JNIEnv* env, jobject obj, jint nativeClass, jint keyCode, + jint unichar, jint repeatCount, jboolean isShift, jboolean isAlt, + jboolean isSym, jboolean isDown) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - return GET_NATIVE_VIEW(env, obj)->key(PlatformKeyboardEvent(keyCode, + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + return viewImpl->key(PlatformKeyboardEvent(keyCode, unichar, repeatCount, isDown, isShift, isAlt, isSym)); } -static void Click(JNIEnv *env, jobject obj, int framePtr, int nodePtr, jboolean fake) +static void Click(JNIEnv* env, jobject obj, jint nativeClass, int framePtr, + int nodePtr, jboolean fake) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in Click"); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + ALOG_ASSERT(viewImpl, "viewImpl not set in Click"); viewImpl->click(reinterpret_cast<WebCore::Frame*>(framePtr), reinterpret_cast<WebCore::Node*>(nodePtr), fake); } -static void ContentInvalidateAll(JNIEnv *env, jobject obj) +static void ContentInvalidateAll(JNIEnv* env, jobject obj, jint nativeClass) { - GET_NATIVE_VIEW(env, obj)->contentInvalidateAll(); + reinterpret_cast<WebViewCore*>(nativeClass)->contentInvalidateAll(); } -static void DeleteSelection(JNIEnv *env, jobject obj, jint start, jint end, - jint textGeneration) +static void DeleteSelection(JNIEnv* env, jobject obj, jint nativeClass, + jint start, jint end, jint textGeneration) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); viewImpl->deleteSelection(start, end, textGeneration); } -static void SetSelection(JNIEnv *env, jobject obj, jint start, jint end) +static void SetSelection(JNIEnv* env, jobject obj, jint nativeClass, + jint start, jint end) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); viewImpl->setSelection(start, end); } -static jstring ModifySelection(JNIEnv *env, jobject obj, jint direction, jint granularity) +static jstring ModifySelection(JNIEnv* env, jobject obj, jint nativeClass, + jint direction, jint granularity) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); String selectionString = viewImpl->modifySelection(direction, granularity); return wtfStringToJstring(env, selectionString); } -static void ReplaceTextfieldText(JNIEnv *env, jobject obj, +static void ReplaceTextfieldText(JNIEnv* env, jobject obj, jint nativeClass, jint oldStart, jint oldEnd, jstring replace, jint start, jint end, jint textGeneration) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); WTF::String webcoreString = jstringToWtfString(env, replace); viewImpl->replaceTextfieldText(oldStart, oldEnd, webcoreString, start, end, textGeneration); } -static void PassToJs(JNIEnv *env, jobject obj, +static void PassToJs(JNIEnv* env, jobject obj, jint nativeClass, jint generation, jstring currentText, jint keyCode, jint keyValue, jboolean down, jboolean cap, jboolean fn, jboolean sym) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif WTF::String current = jstringToWtfString(env, currentText); - GET_NATIVE_VIEW(env, obj)->passToJs(generation, current, + reinterpret_cast<WebViewCore*>(nativeClass)->passToJs(generation, current, PlatformKeyboardEvent(keyCode, keyValue, 0, down, cap, fn, sym)); } -static void ScrollFocusedTextInput(JNIEnv *env, jobject obj, jfloat xPercent, - jint y) +static void ScrollFocusedTextInput(JNIEnv* env, jobject obj, jint nativeClass, + jfloat xPercent, jint y) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); viewImpl->scrollFocusedTextInput(xPercent, y); } -static void SetFocusControllerActive(JNIEnv *env, jobject obj, jboolean active) +static void SetFocusControllerActive(JNIEnv* env, jobject obj, jint nativeClass, + jboolean active) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - LOGV("webviewcore::nativeSetFocusControllerActive()\n"); - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in nativeSetFocusControllerActive"); + ALOGV("webviewcore::nativeSetFocusControllerActive()\n"); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSetFocusControllerActive"); viewImpl->setFocusControllerActive(active); } -static void SaveDocumentState(JNIEnv *env, jobject obj, jint frame) +static void SaveDocumentState(JNIEnv* env, jobject obj, jint nativeClass, + jint frame) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - LOGV("webviewcore::nativeSaveDocumentState()\n"); - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in nativeSaveDocumentState"); + ALOGV("webviewcore::nativeSaveDocumentState()\n"); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSaveDocumentState"); viewImpl->saveDocumentState((WebCore::Frame*) frame); } @@ -4113,7 +4357,8 @@ void WebViewCore::addVisitedLink(const UChar* string, int length) m_groupForVisitedLinks->addVisitedLink(string, length); } -static bool UpdateLayers(JNIEnv *env, jobject obj, jint nativeClass, jint jbaseLayer) +static bool UpdateLayers(JNIEnv* env, jobject obj, jint nativeClass, + jint jbaseLayer) { WebViewCore* viewImpl = (WebViewCore*) nativeClass; BaseLayerAndroid* baseLayer = (BaseLayerAndroid*) jbaseLayer; @@ -4125,18 +4370,16 @@ static bool UpdateLayers(JNIEnv *env, jobject obj, jint nativeClass, jint jbaseL return true; } -static void NotifyAnimationStarted(JNIEnv *env, jobject obj, jint nativeClass) +static void NotifyAnimationStarted(JNIEnv* env, jobject obj, jint nativeClass) { WebViewCore* viewImpl = (WebViewCore*) nativeClass; viewImpl->notifyAnimationStarted(); } -static jint RecordContent(JNIEnv *env, jobject obj, jobject region, jobject pt) +static jint RecordContent(JNIEnv* env, jobject obj, jint nativeClass, + jobject region, jobject pt) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); SkRegion* nativeRegion = GraphicsJNI::getNativeRegion(env, region); SkIPoint nativePt; BaseLayerAndroid* result = viewImpl->recordContent(nativeRegion, &nativePt); @@ -4144,22 +4387,18 @@ static jint RecordContent(JNIEnv *env, jobject obj, jobject region, jobject pt) return reinterpret_cast<jint>(result); } -static void SplitContent(JNIEnv *env, jobject obj, jint content) +static void SplitContent(JNIEnv* env, jobject obj, jint nativeClass, + jint content) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); viewImpl->splitContent(reinterpret_cast<PictureSet*>(content)); } -static void SendListBoxChoice(JNIEnv* env, jobject obj, jint choice) +static void SendListBoxChoice(JNIEnv* env, jobject obj, jint nativeClass, + jint choice) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoice"); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoice"); viewImpl->popupReply(choice); } @@ -4169,14 +4408,11 @@ static void SendListBoxChoice(JNIEnv* env, jobject obj, jint choice) // number of items in the average multiple-select listbox. #define PREPARED_LISTBOX_STORAGE 10 -static void SendListBoxChoices(JNIEnv* env, jobject obj, jbooleanArray jArray, - jint size) +static void SendListBoxChoices(JNIEnv* env, jobject obj, jint nativeClass, + jbooleanArray jArray, jint size) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoices"); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoices"); jboolean* ptrArray = env->GetBooleanArrayElements(jArray, 0); SkAutoSTMalloc<PREPARED_LISTBOX_STORAGE, int> storage(size); int* array = storage.get(); @@ -4190,21 +4426,19 @@ static void SendListBoxChoices(JNIEnv* env, jobject obj, jbooleanArray jArray, viewImpl->popupReply(array, count); } -static jstring FindAddress(JNIEnv *env, jobject obj, jstring addr, - jboolean caseInsensitive) +// TODO: Move this to WebView.cpp since it is only needed there +static jstring FindAddress(JNIEnv* env, jobject obj, jstring addr, + jboolean caseInsensitive) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif if (!addr) return 0; int length = env->GetStringLength(addr); if (!length) return 0; const jchar* addrChars = env->GetStringChars(addr, 0); - int start, end; - bool success = CacheBuilder::FindAddress(addrChars, length, - &start, &end, caseInsensitive) == CacheBuilder::FOUND_COMPLETE; + size_t start, end; + AddressDetector detector; + bool success = detector.FindContent(addrChars, addrChars + length, &start, &end); jstring ret = 0; if (success) ret = env->NewString(addrChars + start, end - start); @@ -4212,15 +4446,12 @@ static jstring FindAddress(JNIEnv *env, jobject obj, jstring addr, return ret; } -static jboolean HandleTouchEvent(JNIEnv *env, jobject obj, jint action, jintArray idArray, - jintArray xArray, jintArray yArray, - jint count, jint actionIndex, jint metaState) +static jboolean HandleTouchEvent(JNIEnv* env, jobject obj, jint nativeClass, + jint action, jintArray idArray, jintArray xArray, jintArray yArray, + jint count, jint actionIndex, jint metaState) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); jint* ptrIdArray = env->GetIntArrayElements(idArray, 0); jint* ptrXArray = env->GetIntArrayElements(xArray, 0); jint* ptrYArray = env->GetIntArrayElements(yArray, 0); @@ -4238,105 +4469,78 @@ static jboolean HandleTouchEvent(JNIEnv *env, jobject obj, jint action, jintArra return viewImpl->handleTouchEvent(action, ids, points, actionIndex, metaState); } -static void TouchUp(JNIEnv *env, jobject obj, jint touchGeneration, - jint frame, jint node, jint x, jint y) +static void TouchUp(JNIEnv* env, jobject obj, jint nativeClass, + jint touchGeneration, jint frame, jint node, jint x, jint y) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); viewImpl->touchUp(touchGeneration, (WebCore::Frame*) frame, (WebCore::Node*) node, x, y); } -static jstring RetrieveHref(JNIEnv *env, jobject obj, jint x, jint y) +static jstring RetrieveHref(JNIEnv* env, jobject obj, jint nativeClass, + jint x, jint y) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); WTF::String result = viewImpl->retrieveHref(x, y); if (!result.isEmpty()) return wtfStringToJstring(env, result); return 0; } -static jstring RetrieveAnchorText(JNIEnv *env, jobject obj, jint x, jint y) +static jstring RetrieveAnchorText(JNIEnv* env, jobject obj, jint nativeClass, + jint x, jint y) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); WTF::String result = viewImpl->retrieveAnchorText(x, y); if (!result.isEmpty()) return wtfStringToJstring(env, result); return 0; } -static jstring RetrieveImageSource(JNIEnv *env, jobject obj, jint x, jint y) +static jstring RetrieveImageSource(JNIEnv* env, jobject obj, jint nativeClass, + jint x, jint y) { - WTF::String result = GET_NATIVE_VIEW(env, obj)->retrieveImageSource(x, y); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + WTF::String result = viewImpl->retrieveImageSource(x, y); return !result.isEmpty() ? wtfStringToJstring(env, result) : 0; } -static void StopPaintingCaret(JNIEnv *env, jobject obj) +static void MoveFocus(JNIEnv* env, jobject obj, jint nativeClass, jint framePtr, + jint nodePtr) { - GET_NATIVE_VIEW(env, obj)->setShouldPaintCaret(false); -} - -static void MoveFocus(JNIEnv *env, jobject obj, jint framePtr, jint nodePtr) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); viewImpl->moveFocus((WebCore::Frame*) framePtr, (WebCore::Node*) nodePtr); } -static void MoveMouse(JNIEnv *env, jobject obj, jint frame, +static void MoveMouse(JNIEnv* env, jobject obj, jint nativeClass, jint frame, jint x, jint y) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); viewImpl->moveMouse((WebCore::Frame*) frame, x, y); } -static void MoveMouseIfLatest(JNIEnv *env, jobject obj, jint moveGeneration, - jint frame, jint x, jint y) +static void MoveMouseIfLatest(JNIEnv* env, jobject obj, jint nativeClass, + jint moveGeneration, jint frame, jint x, jint y) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); viewImpl->moveMouseIfLatest(moveGeneration, (WebCore::Frame*) frame, x, y); } -static void UpdateFrameCache(JNIEnv *env, jobject obj) +static void UpdateFrameCache(JNIEnv* env, jobject obj, jint nativeClass) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); - viewImpl->updateFrameCache(); } -static jint GetContentMinPrefWidth(JNIEnv *env, jobject obj) +static jint GetContentMinPrefWidth(JNIEnv* env, jobject obj, jint nativeClass) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); WebCore::Frame* frame = viewImpl->mainFrame(); if (frame) { @@ -4351,13 +4555,11 @@ static jint GetContentMinPrefWidth(JNIEnv *env, jobject obj) return 0; } -static void SetViewportSettingsFromNative(JNIEnv *env, jobject obj) +static void SetViewportSettingsFromNative(JNIEnv* env, jobject obj, + jint nativeClass) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); WebCore::Settings* s = viewImpl->mainFrame()->page()->settings(); if (!s) @@ -4374,66 +4576,53 @@ static void SetViewportSettingsFromNative(JNIEnv *env, jobject obj) #endif } -static void SetBackgroundColor(JNIEnv *env, jobject obj, jint color) +static void SetBackgroundColor(JNIEnv* env, jobject obj, jint nativeClass, + jint color) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); viewImpl->setBackgroundColor((SkColor) color); } -static void DumpDomTree(JNIEnv *env, jobject obj, jboolean useFile) +static void DumpDomTree(JNIEnv* env, jobject obj, jint nativeClass, + jboolean useFile) { - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); viewImpl->dumpDomTree(useFile); } -static void DumpRenderTree(JNIEnv *env, jobject obj, jboolean useFile) +static void DumpRenderTree(JNIEnv* env, jobject obj, jint nativeClass, + jboolean useFile) { - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); viewImpl->dumpRenderTree(useFile); } -static void DumpNavTree(JNIEnv *env, jobject obj) +static void DumpNavTree(JNIEnv* env, jobject obj, jint nativeClass) { - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); - - viewImpl->dumpNavTree(); -} - -static void DumpV8Counters(JNIEnv*, jobject) -{ -#if USE(V8) -#ifdef ANDROID_INSTRUMENT - V8Counters::dumpCounters(); -#endif -#endif } -static void SetJsFlags(JNIEnv *env, jobject obj, jstring flags) +static void SetJsFlags(JNIEnv* env, jobject obj, jint nativeClass, jstring flags) { -#if USE(V8) WTF::String flagsString = jstringToWtfString(env, flags); WTF::CString utf8String = flagsString.utf8(); WebCore::ScriptController::setFlags(utf8String.data(), utf8String.length()); -#endif } // Called from the Java side to set a new quota for the origin or new appcache // max size in response to a notification that the original quota was exceeded or // that the appcache has reached its maximum size. -static void SetNewStorageLimit(JNIEnv* env, jobject obj, jlong quota) { +static void SetNewStorageLimit(JNIEnv* env, jobject obj, jint nativeClass, + jlong quota) +{ #if ENABLE(DATABASE) || ENABLE(OFFLINE_WEB_APPLICATIONS) - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); Frame* frame = viewImpl->mainFrame(); // The main thread is blocked awaiting this response, so now we can wake it @@ -4444,93 +4633,98 @@ static void SetNewStorageLimit(JNIEnv* env, jobject obj, jlong quota) { } // Called from Java to provide a Geolocation permission state for the specified origin. -static void GeolocationPermissionsProvide(JNIEnv* env, jobject obj, jstring origin, jboolean allow, jboolean remember) { - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); +static void GeolocationPermissionsProvide(JNIEnv* env, jobject obj, + jint nativeClass, jstring origin, jboolean allow, jboolean remember) +{ + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); Frame* frame = viewImpl->mainFrame(); ChromeClientAndroid* chromeClient = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client()); chromeClient->provideGeolocationPermissions(jstringToWtfString(env, origin), allow, remember); } -static void RegisterURLSchemeAsLocal(JNIEnv* env, jobject obj, jstring scheme) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif +static void RegisterURLSchemeAsLocal(JNIEnv* env, jobject obj, jint nativeClass, + jstring scheme) +{ WebCore::SchemeRegistry::registerURLSchemeAsLocal(jstringToWtfString(env, scheme)); } -static bool FocusBoundsChanged(JNIEnv* env, jobject obj) +static bool FocusBoundsChanged(JNIEnv* env, jobject obj, jint nativeClass) { - return GET_NATIVE_VIEW(env, obj)->focusBoundsChanged(); + return reinterpret_cast<WebViewCore*>(nativeClass)->focusBoundsChanged(); } -static void SetIsPaused(JNIEnv* env, jobject obj, jboolean isPaused) +static void SetIsPaused(JNIEnv* env, jobject obj, jint nativeClass, + jboolean isPaused) { // tell the webcore thread to stop thinking while we do other work // (selection and scrolling). This has nothing to do with the lifecycle // pause and resume. - GET_NATIVE_VIEW(env, obj)->setIsPaused(isPaused); + reinterpret_cast<WebViewCore*>(nativeClass)->setIsPaused(isPaused); } -static void Pause(JNIEnv* env, jobject obj) +static void Pause(JNIEnv* env, jobject obj, jint nativeClass) { // This is called for the foreground tab when the browser is put to the // background (and also for any tab when it is put to the background of the // browser). The browser can only be killed by the system when it is in the // background, so saving the Geolocation permission state now ensures that // is maintained when the browser is killed. - ChromeClient* chromeClient = GET_NATIVE_VIEW(env, obj)->mainFrame()->page()->chrome()->client(); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + ChromeClient* chromeClient = viewImpl->mainFrame()->page()->chrome()->client(); ChromeClientAndroid* chromeClientAndroid = static_cast<ChromeClientAndroid*>(chromeClient); chromeClientAndroid->storeGeolocationPermissions(); - Frame* mainFrame = GET_NATIVE_VIEW(env, obj)->mainFrame(); + Frame* mainFrame = viewImpl->mainFrame(); for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) { Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation(); if (geolocation) geolocation->suspend(); } - GET_NATIVE_VIEW(env, obj)->deviceMotionAndOrientationManager()->maybeSuspendClients(); + viewImpl->deviceMotionAndOrientationManager()->maybeSuspendClients(); ANPEvent event; SkANP::InitEvent(&event, kLifecycle_ANPEventType); event.data.lifecycle.action = kPause_ANPLifecycleAction; - GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event); + viewImpl->sendPluginEvent(event); - GET_NATIVE_VIEW(env, obj)->setIsPaused(true); + viewImpl->setIsPaused(true); } -static void Resume(JNIEnv* env, jobject obj) +static void Resume(JNIEnv* env, jobject obj, jint nativeClass) { - Frame* mainFrame = GET_NATIVE_VIEW(env, obj)->mainFrame(); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + Frame* mainFrame = viewImpl->mainFrame(); for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) { Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation(); if (geolocation) geolocation->resume(); } - GET_NATIVE_VIEW(env, obj)->deviceMotionAndOrientationManager()->maybeResumeClients(); + viewImpl->deviceMotionAndOrientationManager()->maybeResumeClients(); ANPEvent event; SkANP::InitEvent(&event, kLifecycle_ANPEventType); event.data.lifecycle.action = kResume_ANPLifecycleAction; - GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event); + viewImpl->sendPluginEvent(event); - GET_NATIVE_VIEW(env, obj)->setIsPaused(false); + viewImpl->setIsPaused(false); } -static void FreeMemory(JNIEnv* env, jobject obj) +static void FreeMemory(JNIEnv* env, jobject obj, jint nativeClass) { ANPEvent event; SkANP::InitEvent(&event, kLifecycle_ANPEventType); event.data.lifecycle.action = kFreeMemory_ANPLifecycleAction; - GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event); + reinterpret_cast<WebViewCore*>(nativeClass)->sendPluginEvent(event); } -static void ProvideVisitedHistory(JNIEnv *env, jobject obj, jobject hist) +static void ProvideVisitedHistory(JNIEnv* env, jobject obj, jint nativeClass, + jobject hist) { - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); jobjectArray array = static_cast<jobjectArray>(hist); @@ -4545,17 +4739,18 @@ static void ProvideVisitedHistory(JNIEnv *env, jobject obj, jobject hist) } } -static void PluginSurfaceReady(JNIEnv* env, jobject obj) +static void PluginSurfaceReady(JNIEnv* env, jobject obj, jint nativeClass) { - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); if (viewImpl) viewImpl->sendPluginSurfaceReady(); } // Notification from the UI thread that the plugin's full-screen surface has been discarded -static void FullScreenPluginHidden(JNIEnv* env, jobject obj, jint npp) +static void FullScreenPluginHidden(JNIEnv* env, jobject obj, jint nativeClass, + jint npp) { - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); PluginWidgetAndroid* plugin = viewImpl->getPluginWidget((NPP)npp); if (plugin) plugin->exitFullScreen(false); @@ -4568,55 +4763,31 @@ static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj) return WebCore::IntRect(L, T, R - L, B - T); } -static bool ValidNodeAndBounds(JNIEnv *env, jobject obj, int frame, int node, - jobject rect) +static bool ValidNodeAndBounds(JNIEnv* env, jobject obj, jint nativeClass, + int frame, int node, jobject rect) { IntRect nativeRect = jrect_to_webrect(env, rect); - return GET_NATIVE_VIEW(env, obj)->validNodeAndBounds( + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + return viewImpl->validNodeAndBounds( reinterpret_cast<Frame*>(frame), reinterpret_cast<Node*>(node), nativeRect); } -static jobject GetTouchHighlightRects(JNIEnv* env, jobject obj, jint x, jint y, jint slop) +static jobject HitTest(JNIEnv* env, jobject obj, jint nativeClass, jint x, + jint y, jint slop, jboolean doMoveMouse) { - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); if (!viewImpl) return 0; - Vector<IntRect> rects = viewImpl->getTouchHighlightRects(x, y, slop); - if (rects.isEmpty()) - return 0; - - jclass arrayClass = env->FindClass("java/util/ArrayList"); - LOG_ASSERT(arrayClass, "Could not find java/util/ArrayList"); - jmethodID init = env->GetMethodID(arrayClass, "<init>", "(I)V"); - LOG_ASSERT(init, "Could not find constructor for ArrayList"); - jobject array = env->NewObject(arrayClass, init, rects.size()); - LOG_ASSERT(array, "Could not create a new ArrayList"); - jmethodID add = env->GetMethodID(arrayClass, "add", "(Ljava/lang/Object;)Z"); - LOG_ASSERT(add, "Could not find add method on ArrayList"); - jclass rectClass = env->FindClass("android/graphics/Rect"); - LOG_ASSERT(rectClass, "Could not find android/graphics/Rect"); - jmethodID rectinit = env->GetMethodID(rectClass, "<init>", "(IIII)V"); - LOG_ASSERT(rectinit, "Could not find init method on Rect"); - - for (size_t i = 0; i < rects.size(); i++) { - jobject rect = env->NewObject(rectClass, rectinit, rects[i].x(), - rects[i].y(), rects[i].maxX(), rects[i].maxY()); - if (rect) { - env->CallBooleanMethod(array, add, rect); - env->DeleteLocalRef(rect); - } - } - - env->DeleteLocalRef(rectClass); - env->DeleteLocalRef(arrayClass); - return array; + AndroidHitTestResult result = viewImpl->hitTestAtPoint(x, y, slop, doMoveMouse); + return result.createJavaObject(env); } -static void AutoFillForm(JNIEnv* env, jobject obj, jint queryId) +static void AutoFillForm(JNIEnv* env, jobject obj, jint nativeClass, + jint queryId) { #if ENABLE(WEB_AUTOFILL) - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); if (!viewImpl) return; @@ -4629,19 +4800,89 @@ static void AutoFillForm(JNIEnv* env, jobject obj, jint queryId) #endif } -static void CloseIdleConnections(JNIEnv* env, jobject obj) +static void CloseIdleConnections(JNIEnv* env, jobject obj, jint nativeClass) { -#if USE(CHROME_NETWORK_STACK) WebCache::get(true)->closeIdleConnections(); WebCache::get(false)->closeIdleConnections(); +} + +static void nativeCertTrustChanged(JNIEnv *env, jobject obj) +{ +#if USE(CHROME_NETWORK_STACK) + WebCache::get(true)->certTrustChanged(); + WebCache::get(false)->certTrustChanged(); #endif } -static void ScrollRenderLayer(JNIEnv* env, jobject obj, jint layer, jobject jRect) +static void ScrollRenderLayer(JNIEnv* env, jobject obj, jint nativeClass, + jint layer, jobject jRect) { SkRect rect; GraphicsJNI::jrect_to_rect(env, jRect, &rect); - GET_NATIVE_VIEW(env, obj)->scrollRenderLayer(layer, rect); + reinterpret_cast<WebViewCore*>(nativeClass)->scrollRenderLayer(layer, rect); +} + +static void DeleteText(JNIEnv* env, jobject obj, jint nativeClass, + jint startX, jint startY, jint endX, jint endY) +{ + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + viewImpl->deleteText(startX, startY, endX, endY); +} + +static void InsertText(JNIEnv* env, jobject obj, jint nativeClass, + jstring text) +{ + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + WTF::String wtfText = jstringToWtfString(env, text); + viewImpl->insertText(wtfText); +} + +static jobject GetText(JNIEnv* env, jobject obj, jint nativeClass, + jint startX, jint startY, jint endX, jint endY) +{ + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + WTF::String text = viewImpl->getText(startX, startY, endX, endY); + return text.isEmpty() ? 0 : wtfStringToJstring(env, text); +} + +static void SelectText(JNIEnv* env, jobject obj, jint nativeClass, + jint startX, jint startY, jint endX, jint endY) +{ + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + viewImpl->selectText(startX, startY, endX, endY); +} + +static void ClearSelection(JNIEnv* env, jobject obj, jint nativeClass) +{ + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + viewImpl->focusedFrame()->selection()->clear(); +} + +static void SelectWordAt(JNIEnv* env, jobject obj, jint nativeClass, jint x, jint y) +{ + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + viewImpl->selectWordAt(x, y); +} + +static void SelectAll(JNIEnv* env, jobject obj, jint nativeClass) +{ + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + viewImpl->focusedFrame()->selection()->selectAll(); +} + +static int FindAll(JNIEnv* env, jobject obj, jint nativeClass, + jstring text) +{ + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + WTF::String wtfText = jstringToWtfString(env, text); + return viewImpl->findTextOnPage(wtfText); +} + +static void FindNext(JNIEnv* env, jobject obj, jint nativeClass, + jboolean forward) +{ + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + viewImpl->findNextOnPage(forward); } // ---------------------------------------------------------------------------- @@ -4650,164 +4891,180 @@ static void ScrollRenderLayer(JNIEnv* env, jobject obj, jint layer, jobject jRec * JNI registration. */ static JNINativeMethod gJavaWebViewCoreMethods[] = { - { "nativeClearContent", "()V", + { "nativeClearContent", "(I)V", (void*) ClearContent }, - { "nativeFocusBoundsChanged", "()Z", + { "nativeFocusBoundsChanged", "(I)Z", (void*) FocusBoundsChanged } , - { "nativeKey", "(IIIZZZZ)Z", + { "nativeKey", "(IIIIZZZZ)Z", (void*) Key }, - { "nativeClick", "(IIZ)V", + { "nativeClick", "(IIIZ)V", (void*) Click }, - { "nativeContentInvalidateAll", "()V", + { "nativeContentInvalidateAll", "(I)V", (void*) ContentInvalidateAll }, - { "nativeSendListBoxChoices", "([ZI)V", + { "nativeSendListBoxChoices", "(I[ZI)V", (void*) SendListBoxChoices }, - { "nativeSendListBoxChoice", "(I)V", + { "nativeSendListBoxChoice", "(II)V", (void*) SendListBoxChoice }, - { "nativeSetSize", "(IIIFIIIIZ)V", + { "nativeSetSize", "(IIIIFIIIIZ)V", (void*) SetSize }, - { "nativeSetScrollOffset", "(IZII)V", + { "nativeSetScrollOffset", "(IIZII)V", (void*) SetScrollOffset }, - { "nativeSetGlobalBounds", "(IIII)V", + { "nativeSetGlobalBounds", "(IIIII)V", (void*) SetGlobalBounds }, - { "nativeSetSelection", "(II)V", + { "nativeSetSelection", "(III)V", (void*) SetSelection } , - { "nativeModifySelection", "(II)Ljava/lang/String;", + { "nativeModifySelection", "(III)Ljava/lang/String;", (void*) ModifySelection }, - { "nativeDeleteSelection", "(III)V", + { "nativeDeleteSelection", "(IIII)V", (void*) DeleteSelection } , - { "nativeReplaceTextfieldText", "(IILjava/lang/String;III)V", + { "nativeReplaceTextfieldText", "(IIILjava/lang/String;III)V", (void*) ReplaceTextfieldText } , - { "nativeMoveFocus", "(II)V", + { "nativeMoveFocus", "(III)V", (void*) MoveFocus }, - { "nativeMoveMouse", "(III)V", + { "nativeMoveMouse", "(IIII)V", (void*) MoveMouse }, - { "nativeMoveMouseIfLatest", "(IIII)V", + { "nativeMoveMouseIfLatest", "(IIIII)V", (void*) MoveMouseIfLatest }, - { "passToJs", "(ILjava/lang/String;IIZZZZ)V", + { "passToJs", "(IILjava/lang/String;IIZZZZ)V", (void*) PassToJs }, - { "nativeScrollFocusedTextInput", "(FI)V", + { "nativeScrollFocusedTextInput", "(IFI)V", (void*) ScrollFocusedTextInput }, - { "nativeSetFocusControllerActive", "(Z)V", + { "nativeSetFocusControllerActive", "(IZ)V", (void*) SetFocusControllerActive }, - { "nativeSaveDocumentState", "(I)V", + { "nativeSaveDocumentState", "(II)V", (void*) SaveDocumentState }, { "nativeFindAddress", "(Ljava/lang/String;Z)Ljava/lang/String;", (void*) FindAddress }, - { "nativeHandleTouchEvent", "(I[I[I[IIII)Z", + { "nativeHandleTouchEvent", "(II[I[I[IIII)Z", (void*) HandleTouchEvent }, - { "nativeTouchUp", "(IIIII)V", + { "nativeTouchUp", "(IIIIII)V", (void*) TouchUp }, - { "nativeRetrieveHref", "(II)Ljava/lang/String;", + { "nativeRetrieveHref", "(III)Ljava/lang/String;", (void*) RetrieveHref }, - { "nativeRetrieveAnchorText", "(II)Ljava/lang/String;", + { "nativeRetrieveAnchorText", "(III)Ljava/lang/String;", (void*) RetrieveAnchorText }, - { "nativeRetrieveImageSource", "(II)Ljava/lang/String;", + { "nativeRetrieveImageSource", "(III)Ljava/lang/String;", (void*) RetrieveImageSource }, - { "nativeStopPaintingCaret", "()V", - (void*) StopPaintingCaret }, - { "nativeUpdateFrameCache", "()V", + { "nativeUpdateFrameCache", "(I)V", (void*) UpdateFrameCache }, - { "nativeGetContentMinPrefWidth", "()I", + { "nativeGetContentMinPrefWidth", "(I)I", (void*) GetContentMinPrefWidth }, { "nativeUpdateLayers", "(II)Z", (void*) UpdateLayers }, { "nativeNotifyAnimationStarted", "(I)V", (void*) NotifyAnimationStarted }, - { "nativeRecordContent", "(Landroid/graphics/Region;Landroid/graphics/Point;)I", + { "nativeRecordContent", "(ILandroid/graphics/Region;Landroid/graphics/Point;)I", (void*) RecordContent }, - { "setViewportSettingsFromNative", "()V", + { "setViewportSettingsFromNative", "(I)V", (void*) SetViewportSettingsFromNative }, - { "nativeSplitContent", "(I)V", + { "nativeSplitContent", "(II)V", (void*) SplitContent }, - { "nativeSetBackgroundColor", "(I)V", + { "nativeSetBackgroundColor", "(II)V", (void*) SetBackgroundColor }, - { "nativeRegisterURLSchemeAsLocal", "(Ljava/lang/String;)V", + { "nativeRegisterURLSchemeAsLocal", "(ILjava/lang/String;)V", (void*) RegisterURLSchemeAsLocal }, - { "nativeDumpDomTree", "(Z)V", + { "nativeDumpDomTree", "(IZ)V", (void*) DumpDomTree }, - { "nativeDumpRenderTree", "(Z)V", + { "nativeDumpRenderTree", "(IZ)V", (void*) DumpRenderTree }, - { "nativeDumpNavTree", "()V", + { "nativeDumpNavTree", "(I)V", (void*) DumpNavTree }, - { "nativeDumpV8Counters", "()V", - (void*) DumpV8Counters }, - { "nativeSetNewStorageLimit", "(J)V", + { "nativeSetNewStorageLimit", "(IJ)V", (void*) SetNewStorageLimit }, - { "nativeGeolocationPermissionsProvide", "(Ljava/lang/String;ZZ)V", + { "nativeGeolocationPermissionsProvide", "(ILjava/lang/String;ZZ)V", (void*) GeolocationPermissionsProvide }, - { "nativeSetIsPaused", "(Z)V", (void*) SetIsPaused }, - { "nativePause", "()V", (void*) Pause }, - { "nativeResume", "()V", (void*) Resume }, - { "nativeFreeMemory", "()V", (void*) FreeMemory }, - { "nativeSetJsFlags", "(Ljava/lang/String;)V", (void*) SetJsFlags }, - { "nativeRequestLabel", "(II)Ljava/lang/String;", + { "nativeSetIsPaused", "(IZ)V", (void*) SetIsPaused }, + { "nativePause", "(I)V", (void*) Pause }, + { "nativeResume", "(I)V", (void*) Resume }, + { "nativeFreeMemory", "(I)V", (void*) FreeMemory }, + { "nativeSetJsFlags", "(ILjava/lang/String;)V", (void*) SetJsFlags }, + { "nativeRequestLabel", "(III)Ljava/lang/String;", (void*) RequestLabel }, - { "nativeRevealSelection", "()V", (void*) RevealSelection }, - { "nativeUpdateFrameCacheIfLoading", "()V", + { "nativeRevealSelection", "(I)V", (void*) RevealSelection }, + { "nativeUpdateFrameCacheIfLoading", "(I)V", (void*) UpdateFrameCacheIfLoading }, - { "nativeProvideVisitedHistory", "([Ljava/lang/String;)V", + { "nativeProvideVisitedHistory", "(I[Ljava/lang/String;)V", (void*) ProvideVisitedHistory }, - { "nativeFullScreenPluginHidden", "(I)V", + { "nativeFullScreenPluginHidden", "(II)V", (void*) FullScreenPluginHidden }, - { "nativePluginSurfaceReady", "()V", + { "nativePluginSurfaceReady", "(I)V", (void*) PluginSurfaceReady }, - { "nativeValidNodeAndBounds", "(IILandroid/graphics/Rect;)Z", + { "nativeValidNodeAndBounds", "(IIILandroid/graphics/Rect;)Z", (void*) ValidNodeAndBounds }, - { "nativeGetTouchHighlightRects", "(III)Ljava/util/ArrayList;", - (void*) GetTouchHighlightRects }, - { "nativeAutoFillForm", "(I)V", + { "nativeHitTest", "(IIIIZ)Landroid/webkit/WebViewCore$WebKitHitTest;", + (void*) HitTest }, + { "nativeAutoFillForm", "(II)V", (void*) AutoFillForm }, - { "nativeScrollLayer", "(ILandroid/graphics/Rect;)V", + { "nativeScrollLayer", "(IILandroid/graphics/Rect;)V", (void*) ScrollRenderLayer }, - { "nativeCloseIdleConnections", "()V", + { "nativeCloseIdleConnections", "(I)V", (void*) CloseIdleConnections }, + { "nativeDeleteText", "(IIIII)V", + (void*) DeleteText }, + { "nativeInsertText", "(ILjava/lang/String;)V", + (void*) InsertText }, + { "nativeGetText", "(IIIII)Ljava/lang/String;", + (void*) GetText }, + { "nativeSelectText", "(IIIII)V", + (void*) SelectText }, + { "nativeClearTextSelection", "(I)V", + (void*) ClearSelection }, + { "nativeSelectWordAt", "(III)V", + (void*) SelectWordAt }, + { "nativeSelectAll", "(I)V", + (void*) SelectAll }, + { "nativeCertTrustChanged","()V", + (void*) nativeCertTrustChanged }, + { "nativeFindAll", "(ILjava/lang/String;)I", + (void*) FindAll }, + { "nativeFindNext", "(IZ)V", + (void*) FindNext }, }; int registerWebViewCore(JNIEnv* env) { jclass widget = env->FindClass("android/webkit/WebViewCore"); - LOG_ASSERT(widget, + ALOG_ASSERT(widget, "Unable to find class android/webkit/WebViewCore"); gWebViewCoreFields.m_nativeClass = env->GetFieldID(widget, "mNativeClass", "I"); - LOG_ASSERT(gWebViewCoreFields.m_nativeClass, + ALOG_ASSERT(gWebViewCoreFields.m_nativeClass, "Unable to find android/webkit/WebViewCore.mNativeClass"); gWebViewCoreFields.m_viewportWidth = env->GetFieldID(widget, "mViewportWidth", "I"); - LOG_ASSERT(gWebViewCoreFields.m_viewportWidth, + ALOG_ASSERT(gWebViewCoreFields.m_viewportWidth, "Unable to find android/webkit/WebViewCore.mViewportWidth"); gWebViewCoreFields.m_viewportHeight = env->GetFieldID(widget, "mViewportHeight", "I"); - LOG_ASSERT(gWebViewCoreFields.m_viewportHeight, + ALOG_ASSERT(gWebViewCoreFields.m_viewportHeight, "Unable to find android/webkit/WebViewCore.mViewportHeight"); gWebViewCoreFields.m_viewportInitialScale = env->GetFieldID(widget, "mViewportInitialScale", "I"); - LOG_ASSERT(gWebViewCoreFields.m_viewportInitialScale, + ALOG_ASSERT(gWebViewCoreFields.m_viewportInitialScale, "Unable to find android/webkit/WebViewCore.mViewportInitialScale"); gWebViewCoreFields.m_viewportMinimumScale = env->GetFieldID(widget, "mViewportMinimumScale", "I"); - LOG_ASSERT(gWebViewCoreFields.m_viewportMinimumScale, + ALOG_ASSERT(gWebViewCoreFields.m_viewportMinimumScale, "Unable to find android/webkit/WebViewCore.mViewportMinimumScale"); gWebViewCoreFields.m_viewportMaximumScale = env->GetFieldID(widget, "mViewportMaximumScale", "I"); - LOG_ASSERT(gWebViewCoreFields.m_viewportMaximumScale, + ALOG_ASSERT(gWebViewCoreFields.m_viewportMaximumScale, "Unable to find android/webkit/WebViewCore.mViewportMaximumScale"); gWebViewCoreFields.m_viewportUserScalable = env->GetFieldID(widget, "mViewportUserScalable", "Z"); - LOG_ASSERT(gWebViewCoreFields.m_viewportUserScalable, + ALOG_ASSERT(gWebViewCoreFields.m_viewportUserScalable, "Unable to find android/webkit/WebViewCore.mViewportUserScalable"); gWebViewCoreFields.m_viewportDensityDpi = env->GetFieldID(widget, "mViewportDensityDpi", "I"); - LOG_ASSERT(gWebViewCoreFields.m_viewportDensityDpi, + ALOG_ASSERT(gWebViewCoreFields.m_viewportDensityDpi, "Unable to find android/webkit/WebViewCore.mViewportDensityDpi"); gWebViewCoreFields.m_webView = env->GetFieldID(widget, "mWebView", "Landroid/webkit/WebView;"); - LOG_ASSERT(gWebViewCoreFields.m_webView, + ALOG_ASSERT(gWebViewCoreFields.m_webView, "Unable to find android/webkit/WebViewCore.mWebView"); gWebViewCoreFields.m_drawIsPaused = env->GetFieldID(widget, "mDrawIsPaused", "Z"); - LOG_ASSERT(gWebViewCoreFields.m_drawIsPaused, + ALOG_ASSERT(gWebViewCoreFields.m_drawIsPaused, "Unable to find android/webkit/WebViewCore.mDrawIsPaused"); gWebViewCoreFields.m_lowMemoryUsageMb = env->GetFieldID(widget, "mLowMemoryUsageThresholdMb", "I"); gWebViewCoreFields.m_highMemoryUsageMb = env->GetFieldID(widget, "mHighMemoryUsageThresholdMb", "I"); diff --git a/Source/WebKit/android/jni/WebViewCore.h b/Source/WebKit/android/jni/WebViewCore.h index a05c3ea..c5bb63f 100644 --- a/Source/WebKit/android/jni/WebViewCore.h +++ b/Source/WebKit/android/jni/WebViewCore.h @@ -26,24 +26,27 @@ #ifndef WebViewCore_h #define WebViewCore_h -#include "CacheBuilder.h" -#include "CachedHistory.h" #include "DeviceMotionAndOrientationManager.h" #include "DOMSelection.h" #include "FileChooser.h" +#include "HitTestResult.h" #include "PictureSet.h" #include "PlatformGraphicsContext.h" +#include "Position.h" +#include "ScrollTypes.h" #include "SkColor.h" #include "SkTDArray.h" #include "SkRegion.h" +#include "Text.h" #include "Timer.h" #include "WebCoreRefObject.h" #include "WebCoreJni.h" #include "WebRequestContext.h" #include "android_npapi.h" +#include "VisiblePosition.h" #include <jni.h> -#include <ui/KeycodeLabels.h> +#include <androidfw/KeycodeLabels.h> #include <ui/PixelFormat.h> namespace WebCore { @@ -67,6 +70,7 @@ namespace WebCore { #if USE(ACCELERATED_COMPOSITING) namespace WebCore { class GraphicsLayerAndroid; + class LayerAndroid; } #endif @@ -79,6 +83,9 @@ class SkPicture; class SkIRect; namespace android { + // TODO: This file hasn't been good about namespace. Remove this temporary + // workaround to build + using namespace WebCore; enum Direction { DIRECTION_BACKWARD = 0, @@ -95,10 +102,9 @@ namespace android { AXIS_DOCUMENT = 6 }; - class CachedFrame; - class CachedNode; - class CachedRoot; class ListBoxReply; + class AndroidHitTestResult; + class SelectText; class WebCoreReply : public WebCoreRefObject { public: @@ -136,7 +142,7 @@ namespace android { * @param Node The Node that blurred. */ void formDidBlur(const WebCore::Node*); - void focusNodeChanged(const WebCore::Node*); + void focusNodeChanged(WebCore::Node*); /** * Scroll to an absolute position. @@ -146,7 +152,7 @@ namespace android { * * This method calls Java to trigger a gradual scroll event. */ - void scrollTo(int x, int y, bool animate = false); + void scrollTo(int x, int y, bool animate = true); /** * Record the invalid rectangle @@ -299,7 +305,7 @@ namespace android { void recordPicture(SkPicture* picture); void moveFocus(WebCore::Frame* frame, WebCore::Node* node); - void moveMouse(WebCore::Frame* frame, int x, int y); + void moveMouse(WebCore::Frame* frame, int x, int y, HitTestResult* hoveredNode = 0); void moveMouseIfLatest(int moveGeneration, WebCore::Frame* frame, int x, int y); @@ -424,11 +430,9 @@ namespace android { jobject getWebViewJavaObject(); void setBackgroundColor(SkColor c); - void updateFrameCache(); - void updateCacheOnNodeChange(); + void dumpDomTree(bool); void dumpRenderTree(bool); - void dumpNavTree(); /* We maintain a list of active plugins. The list is edited by the pluginview itself. The list is used to service invals to the plugin @@ -459,9 +463,6 @@ namespace android { // lookup the plugin widget struct given an NPP PluginWidgetAndroid* getPluginWidget(NPP npp); - // return the cursorNode if it is a plugin - Node* cursorNodeIsPlugin(); - // Notify the Java side whether it needs to pass down the touch events void needTouchEvents(bool); @@ -511,7 +512,10 @@ namespace android { void centerFitRect(int x, int y, int width, int height); // return a list of rects matching the touch point (x, y) with the slop - Vector<IntRect> getTouchHighlightRects(int x, int y, int slop); + Vector<IntRect> getTouchHighlightRects(int x, int y, int slop, + Node** node, HitTestResult* hitTestResult); + // This does a sloppy hit test + AndroidHitTestResult hitTestAtPoint(int x, int y, int slop, bool doMoveMouse = false); // Open a file chooser for selecting a file to upload void openFileChooser(PassRefPtr<WebCore::FileChooser> ); @@ -535,17 +539,26 @@ namespace android { float scale() const { return m_scale; } float textWrapScale() const { return m_screenWidth * m_scale / m_textWrapWidth; } WebCore::Frame* mainFrame() const { return m_mainFrame; } - void updateCursorBounds(const CachedRoot* root, - const CachedFrame* cachedFrame, const CachedNode* cachedNode); - void updateFrameCacheIfLoading(); + WebCore::Frame* focusedFrame() const; // utility to split slow parts of the picture set void splitContent(PictureSet*); void notifyWebAppCanBeInstalled(); + void deleteText(int startX, int startY, int endX, int endY); + WTF::String getText(int startX, int startY, int endX, int endY); + void insertText(const WTF::String &text); + + // find on page + void resetFindOnPage(); + int findTextOnPage(const WTF::String &text); + void findNextOnPage(bool forward); + void updateMatchCount() const; + #if ENABLE(VIDEO) void enterFullscreenForVideoLayer(int layerId, const WTF::String& url); + void exitFullscreenVideo(); #endif void setWebTextViewAutoFillable(int queryId, const string16& previewSummary); @@ -555,19 +568,15 @@ namespace android { void listBoxRequest(WebCoreReply* reply, const uint16_t** labels, size_t count, const int enabled[], size_t enabledCount, bool multiple, const int selected[], size_t selectedCountOrSelection); - bool shouldPaintCaret() { return m_shouldPaintCaret; } - void setShouldPaintCaret(bool should) { m_shouldPaintCaret = should; } bool isPaused() const { return m_isPaused; } void setIsPaused(bool isPaused) { m_isPaused = isPaused; } bool drawIsPaused() const; // The actual content (without title bar) size in doc coordinate int screenWidth() const { return m_screenWidth; } int screenHeight() const { return m_screenHeight; } -#if USE(CHROME_NETWORK_STACK) void setWebRequestContextUserAgent(); void setWebRequestContextCacheMode(int mode); WebRequestContext* webRequestContext(); -#endif // Attempts to scroll the layer to the x,y coordinates of rect. The // layer is the id of the LayerAndroid. void scrollRenderLayer(int layer, const SkRect& rect); @@ -580,33 +589,53 @@ namespace android { // Check whether a media mimeType is supported in Android media framework. static bool isSupportedMediaMimeType(const WTF::String& mimeType); + /** + * Returns all text ranges consumed by the cursor points referred + * to by startX, startY, endX, and endY. The vector will be empty + * if no text is in the given area or if the positions are invalid. + */ + Vector<WebCore::VisibleSelection> getTextRanges( + int startX, int startY, int endX, int endY); + static int platformLayerIdFromNode(Node* node, LayerAndroid** outLayer = 0); + void selectText(int startX, int startY, int endX, int endY); + void selectWordAt(int x, int y); + + // Converts from the global content coordinates that WebView sends + // to frame-local content coordinates using the focused frame + IntPoint convertGlobalContentToFrameContent(const IntPoint& point, WebCore::Frame* frame = 0); + static void layerToAbsoluteOffset(const LayerAndroid* layer, IntPoint& offset); + + /** + * Returns a text position at a given coordinate. + */ + WebCore::VisiblePosition visiblePositionForWindowPoint(int x, int y); + // these members are shared with webview.cpp - static Mutex gFrameCacheMutex; - CachedRoot* m_frameCacheKit; // nav data being built by webcore - SkPicture* m_navPictureKit; int m_moveGeneration; // copy of state in WebViewNative triggered by move int m_touchGeneration; // copy of state in WebViewNative triggered by touch int m_lastGeneration; // last action using up to date cache - bool m_updatedFrameCache; bool m_findIsUp; - bool m_hasCursorBounds; - WebCore::IntRect m_cursorBounds; - WebCore::IntRect m_cursorHitBounds; - void* m_cursorFrame; - IntPoint m_cursorLocation; - void* m_cursorNode; - static Mutex gCursorBoundsMutex; // end of shared members // internal functions private: - CacheBuilder& cacheBuilder(); + enum InputType { + NONE = -1, + NORMAL_TEXT_FIELD = 0, + TEXT_AREA = 1, + PASSWORD = 2, + SEARCH = 3, + EMAIL = 4, + NUMBER = 5, + TELEPHONE = 6, + URL = 7, + }; + WebCore::Node* currentFocus(); // Create a set of pictures to represent the drawn DOM, driven by // the invalidated region and the time required to draw (used to draw) void recordPictureSet(PictureSet* master); - void doMaxScroll(CacheBuilder::Direction dir); SkPicture* rebuildPicture(const SkIRect& inval); void rebuildPictureSet(PictureSet* ); void sendNotifyProgressFinished(); @@ -639,6 +668,55 @@ namespace android { void advanceAnchorNode(DOMSelection* selection, int direction, String& markup, bool ignoreFirstNode, ExceptionCode& ec); Node* getNextAnchorNode(Node* anchorNode, bool skipFirstHack, int direction); Node* getImplicitBoundaryNode(Node* node, unsigned offset, int direction); + /** + * Calls into java to reset the text edit field with the + * current contents and selection. + */ + void initEditField(Node* node); + + /** + * Gets the input type a Node. NONE is returned if it isn't an + * input field. + */ + InputType getInputType(Node* node); + + /** + * If node is an input field, the spellcheck value for the + * field is returned. Otherwise true is returned. + */ + static bool isSpellCheckEnabled(Node* node); + + /** + * Returns the offsets of the selection area for both normal text + * fields and content editable fields. start and end are modified + * by this method. + */ + static void getSelectionOffsets(Node* node, int& start, int& end); + /** + * Gets the plain text of the specified editable text field. node + * may be content-editable or a plain text fields. + */ + static String getInputText(Node* node); + /** + * Gets the RenderTextControl for the given node if it has one. + * If its renderer isn't a RenderTextControl, then NULL is returned. + */ + static RenderTextControl* toRenderTextControl(Node *node); + /** + * Sets the selection for node's editable field to the offsets + * between start (inclusive) and end (exclusive). + */ + static void setSelection(Node* node, int start, int end); + /** + * Returns the Position for the given offset for an editable + * field. The offset is relative to the node start. + */ + static WebCore::Position getPositionForOffset(Node* node, int offset); + + VisiblePosition visiblePositionForContentPoint(int x, int y); + VisiblePosition visiblePositionForContentPoint(const IntPoint& point); + void selectWordAroundPosition(Frame* frame, VisiblePosition pos); + SelectText* createSelectText(const VisibleSelection&); // called from constructor, to add this to a global list static void addInstance(WebViewCore*); @@ -666,8 +744,6 @@ namespace android { // Passed in with key events to know when they were generated. Store it // with the cache so that we can ignore stale text changes. int m_textGeneration; - CachedRoot* m_temp; - SkPicture* m_tempPict; int m_maxXScroll; int m_maxYScroll; int m_scrollOffsetX; // webview.java's current scroll in X @@ -675,7 +751,6 @@ namespace android { WebCore::IntPoint m_mousePos; bool m_frameCacheOutOfDate; bool m_progressDone; - CachedHistory m_history; int m_screenWidth; // width of the visible rect in document coordinates int m_screenHeight;// height of the visible rect in document coordinates int m_textWrapWidth; @@ -685,7 +760,13 @@ namespace android { PageGroup* m_groupForVisitedLinks; bool m_isPaused; int m_cacheMode; - bool m_shouldPaintCaret; + bool m_fullscreenVideoMode; + + // find on page data + WTF::String m_searchText; + int m_matchCount; + int m_activeMatchIndex; + RefPtr<WebCore::Range> m_activeMatch; SkTDArray<PluginWidgetAndroid*> m_plugins; WebCore::Timer<WebViewCore> m_pluginInvalTimer; @@ -701,10 +782,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 940991f..0000000 --- a/Source/WebKit/android/nav/CacheBuilder.cpp +++ /dev/null @@ -1,3194 +0,0 @@ -/* - * Copyright 2006, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "CachedPrefix.h" -#include "CachedNode.h" -#include "CachedRoot.h" -#include "ColumnInfo.h" -#include "Document.h" -#include "EventListener.h" -#include "EventNames.h" -#include "Frame.h" -#include "FrameLoader.h" -#include "FrameLoaderClientAndroid.h" -#include "FrameTree.h" -#include "FrameView.h" -//#include "GraphicsContext.h" -#include "HTMLAreaElement.h" -#include "HTMLImageElement.h" -#include "HTMLInputElement.h" -#include "HTMLMapElement.h" -#include "HTMLNames.h" -#include "HTMLOptionElement.h" -#include "HTMLSelectElement.h" -#include "HTMLTextAreaElement.h" -#include "InlineTextBox.h" -#include "KURL.h" -#include "LayerAndroid.h" -#include "PluginView.h" -#include "RegisteredEventListener.h" -#include "RenderImage.h" -#include "RenderInline.h" -#include "RenderLayerBacking.h" -#include "RenderListBox.h" -#include "RenderSkinCombo.h" -#include "RenderTextControl.h" -#include "RenderView.h" -#include "RenderWidget.h" -#include "SkCanvas.h" -#include "SkPoint.h" -#include "Text.h" -#include "WebCoreFrameBridge.h" -#include "WebCoreViewBridge.h" -#include "Widget.h" -#include <wtf/unicode/Unicode.h> - -#ifdef DUMP_NAV_CACHE_USING_PRINTF - FILE* gNavCacheLogFile = NULL; - android::Mutex gWriteLogMutex; -#endif - -#include "CacheBuilder.h" - -#define MINIMUM_FOCUSABLE_WIDTH 3 -#define MINIMUM_FOCUSABLE_HEIGHT 3 -#define MAXIMUM_FOCUS_RING_COUNT 32 - -namespace android { - -CacheBuilder* CacheBuilder::Builder(Frame* frame) { - return &((FrameLoaderClientAndroid*) frame->loader()->client())->getCacheBuilder(); -} - -Frame* CacheBuilder::FrameAnd(CacheBuilder* cacheBuilder) { - FrameLoaderClientAndroid* loader = (FrameLoaderClientAndroid*) - ((char*) cacheBuilder - OFFSETOF(FrameLoaderClientAndroid, m_cacheBuilder)); - return loader->getFrame(); -} - -Frame* CacheBuilder::FrameAnd(const CacheBuilder* cacheBuilder) { - FrameLoaderClientAndroid* loader = (FrameLoaderClientAndroid*) - ((char*) cacheBuilder - OFFSETOF(FrameLoaderClientAndroid, m_cacheBuilder)); - return loader->getFrame(); -} - -CacheBuilder::LayerTracker::~LayerTracker() { - // Check for a stacking context to prevent a crash in layers without a - // parent. - if (mRenderLayer && mRenderLayer->stackingContext()) - // Restore the scroll position of the layer. Does not affect layers - // without overflow scroll as the layer will not be scrolled. - mRenderLayer->scrollToOffset(mScroll.x(), mScroll.y()); -} - -#if DUMP_NAV_CACHE - -static bool hasEventListener(Node* node, const AtomicString& eventType) { - if (!node->isElementNode()) - return false; - Element* element = static_cast<Element*>(node); - EventListener* listener = element->getAttributeEventListener(eventType); - return 0 != listener; -} - -#define DEBUG_BUFFER_SIZE 256 -#define DEBUG_WRAP_SIZE 150 -#define DEBUG_WRAP_MAX 170 - -Frame* CacheBuilder::Debug::frameAnd() const { - CacheBuilder* nav = (CacheBuilder*) ((char*) this - OFFSETOF(CacheBuilder, mDebug)); - return CacheBuilder::FrameAnd(nav); -} - -void CacheBuilder::Debug::attr(const AtomicString& name, const AtomicString& value) { - if (name.isNull() || name.isEmpty() || value.isNull() || value.isEmpty()) - return; - uChar(name.characters(), name.length(), false); - print("="); - wideString(value.characters(), value.length(), false); - print(" "); -} - -void CacheBuilder::Debug::comma(const char* str) { - print(str); - print(", "); -} - -void CacheBuilder::Debug::flush() { - int len; - do { - int limit = mIndex; - if (limit < DEBUG_WRAP_SIZE) - return; - if (limit < DEBUG_WRAP_MAX) - len = limit; - else { - limit = DEBUG_WRAP_MAX; - len = DEBUG_WRAP_SIZE; - while (len < limit) { - char test = mBuffer[len]; - if (test < '/' || (test > '9' && test < 'A') || (test > 'Z' && test < 'a') || test > 'z') - break; - len++; - } - while (len > 0 && mBuffer[len - 1] == '\\') - len--; - while (mBuffer[len] == '"') - len++; - } - const char* prefix = mPrefix; - if (prefix[0] == '\"') { - // see if we're inside a quote - int quoteCount = 0; - for (int index = 0; index < len; index++) { - if (mBuffer[index] == '\\') { - index++; - continue; - } - if (mBuffer[index] == '\n') { - quoteCount = 0; - continue; - } - if (mBuffer[index] == '"') - quoteCount++; - } - if ((quoteCount & 1) == 0) - prefix = "\n"; - } - DUMP_NAV_LOGD("%.*s", len, mBuffer); - int copy = mIndex - len; - strcpy(mBuffer, prefix); - memcpy(&mBuffer[strlen(prefix)], &mBuffer[len], copy); - mIndex = strlen(prefix) + copy; - } while (true); -} - -void CacheBuilder::Debug::frameName(char*& namePtr, const char* max) const { - if (namePtr >= max) - return; - Frame* frame = frameAnd(); - Frame* parent = frame->tree()->parent(); - if (parent) - Builder(parent)->mDebug.frameName(namePtr, max); - const AtomicString& name = frame->tree()->name(); - if (name.length() == 0) - return; - unsigned index = 0; - if (name.startsWith(AtomicString("opener"))) - index = 6; - for (; index < name.length(); index++) { - char ch = name[index]; - if (ch <= ' ') - ch = '_'; - if (WTF::isASCIIAlphanumeric(ch) || ch == '_') - *namePtr++ = ch; - } -} - -void CacheBuilder::Debug::frames() { - Frame* frame = frameAnd(); - Document* doc = frame->document(); - if (doc == NULL) - return; - bool top = frame->tree()->parent() == NULL; - if (top) { -#ifdef DUMP_NAV_CACHE_USING_PRINTF - gWriteLogMutex.lock(); - ASSERT(gNavCacheLogFile == NULL); - gNavCacheLogFile = fopen(NAV_CACHE_LOG_FILE, "a"); -#endif - groups(); - } - Frame* child = frame->tree()->firstChild(); - bool hasChild = child != NULL; - if (top && hasChild) - DUMP_NAV_LOGD("\nnamespace TEST_SPACE {\n\n"); - while (child) { - Builder(child)->mDebug.frames(); - child = child->tree()->nextSibling(); - } - if (hasChild) { - child = frame->tree()->firstChild(); - while (child) { - char childName[256]; - char* childNamePtr = childName; - Builder(child)->mDebug.frameName(childNamePtr, childNamePtr + sizeof(childName) - 1); - *childNamePtr = '\0'; - if (child == frame->tree()->firstChild()) - DUMP_NAV_LOGD("DebugTestFrameGroup TEST%s_GROUP[] = {\n", childName); - Frame* next = child->tree()->nextSibling(); - Document* doc = child->document(); - if (doc != NULL) { - RenderObject* renderer = doc->renderer(); - if (renderer != NULL) { - RenderLayer* layer = renderer->enclosingLayer(); - if (layer != NULL) { - DUMP_NAV_LOGD("{ "); - DUMP_NAV_LOGD("TEST%s_RECTS, ", childName); - DUMP_NAV_LOGD("TEST%s_RECT_COUNT, ", childName); - DUMP_NAV_LOGD("TEST%s_RECTPARTS, ", childName); - DUMP_NAV_LOGD("TEST%s_BOUNDS,\n", childName); - DUMP_NAV_LOGD("TEST%s_WIDTH, ", childName); - DUMP_NAV_LOGD("TEST%s_HEIGHT,\n", childName); - DUMP_NAV_LOGD("0, 0, 0, 0,\n"); - DUMP_NAV_LOGD("TEST%s_FOCUS, ", childName); - Frame* grandChild = child->tree()->firstChild(); - if (grandChild) { - char grandChildName[256]; - char* grandChildNamePtr = grandChildName; - Builder(grandChild)->mDebug.frameName(grandChildNamePtr, - grandChildNamePtr + sizeof(grandChildName) - 1); - *grandChildNamePtr = '\0'; - DUMP_NAV_LOGD("TEST%s_GROUP, ", grandChildName); - DUMP_NAV_LOGD("sizeof(TEST%s_GROUP) / sizeof(DebugTestFrameGroup), ", grandChildName); - } else - DUMP_NAV_LOGD("NULL, 0, "); - DUMP_NAV_LOGD("\"%s\"\n", childName); - DUMP_NAV_LOGD("}%c\n", next ? ',' : ' '); - } - } - } - child = next; - } - DUMP_NAV_LOGD("};\n"); - } - if (top) { - if (hasChild) - DUMP_NAV_LOGD("\n} // end of namespace\n\n"); - char name[256]; - char* frameNamePtr = name; - frameName(frameNamePtr, frameNamePtr + sizeof(name) - 1); - *frameNamePtr = '\0'; - DUMP_NAV_LOGD("DebugTestFrameGroup TEST%s_GROUP = {\n", name); - DUMP_NAV_LOGD("TEST%s_RECTS, ", name); - DUMP_NAV_LOGD("TEST%s_RECT_COUNT, ", name); - DUMP_NAV_LOGD("TEST%s_RECTPARTS, ", name); - DUMP_NAV_LOGD("TEST%s_BOUNDS,\n", name); - DUMP_NAV_LOGD("TEST%s_WIDTH, ", name); - DUMP_NAV_LOGD("TEST%s_HEIGHT,\n", name); - DUMP_NAV_LOGD("TEST%s_MAX_H, ", name); - DUMP_NAV_LOGD("TEST%s_MIN_H, ", name); - DUMP_NAV_LOGD("TEST%s_MAX_V, ", name); - DUMP_NAV_LOGD("TEST%s_MIN_V,\n", name); - DUMP_NAV_LOGD("TEST%s_FOCUS, ", name); - if (hasChild) { - child = frame->tree()->firstChild(); - char childName[256]; - char* childNamePtr = childName; - Builder(child)->mDebug.frameName(childNamePtr, childNamePtr + sizeof(childName) - 1); - *childNamePtr = '\0'; - DUMP_NAV_LOGD("TEST_SPACE::TEST%s_GROUP, ", childName); - DUMP_NAV_LOGD("sizeof(TEST_SPACE::TEST%s_GROUP) / sizeof(DebugTestFrameGroup), \n" ,childName); - } else - DUMP_NAV_LOGD("NULL, 0, "); - DUMP_NAV_LOGD("\"%s\"\n", name); - DUMP_NAV_LOGD("};\n"); -#ifdef DUMP_NAV_CACHE_USING_PRINTF - if (gNavCacheLogFile) - fclose(gNavCacheLogFile); - gNavCacheLogFile = NULL; - gWriteLogMutex.unlock(); -#endif - } -} - -void CacheBuilder::Debug::init(char* buffer, size_t size) { - mBuffer = buffer; - mBufferSize = size; - mIndex = 0; - mPrefix = ""; -} - -void CacheBuilder::Debug::groups() { - Frame* frame = frameAnd(); - Frame* child = frame->tree()->firstChild(); - bool hasChild = child != NULL; - if (frame->tree()->parent() == NULL && hasChild) - DUMP_NAV_LOGD("namespace TEST_SPACE {\n\n"); - while (child) { - Builder(child)->mDebug.groups(); - child = child->tree()->nextSibling(); - } - if (frame->tree()->parent() == NULL && hasChild) - DUMP_NAV_LOGD("\n} // end of namespace\n\n"); - Document* doc = frame->document(); - char name[256]; - char* frameNamePtr = name; - frameName(frameNamePtr, frameNamePtr + sizeof(name) - 1); - *frameNamePtr = '\0'; - if (doc == NULL) { - DUMP_NAV_LOGD("// %s has no document\n", name); - return; - } - RenderObject* renderer = doc->renderer(); - if (renderer == NULL) { - DUMP_NAV_LOGD("// %s has no renderer\n", name); - return; - } - RenderLayer* layer = renderer->enclosingLayer(); - if (layer == NULL) { - DUMP_NAV_LOGD("// %s has no enclosingLayer\n", name); - return; - } - Node* node = doc; - Node* focus = doc->focusedNode(); - bool atLeastOne = false; - do { - if ((atLeastOne |= isFocusable(node)) != false) - break; - } while ((node = node->traverseNextNode()) != NULL); - int focusIndex = -1; - if (atLeastOne == false) { - DUMP_NAV_LOGD("static DebugTestNode TEST%s_RECTS[] = {\n" - "{{0, 0, 0, 0}, \"\", 0, -1, \"\", {0, 0, 0, 0}, false, 0}\n" - "};\n\n", name); - DUMP_NAV_LOGD("static int TEST%s_RECT_COUNT = 1;" - " // no focusable nodes\n", name); - DUMP_NAV_LOGD("#define TEST%s_RECTPARTS NULL\n", name); - } else { - node = doc; - int count = 1; - DUMP_NAV_LOGD("static DebugTestNode TEST%s_RECTS[] = {\n", name); - do { - String properties; - if (hasEventListener(node, eventNames().clickEvent)) - properties.append("ONCLICK | "); - if (hasEventListener(node, eventNames().mousedownEvent)) - properties.append("MOUSEDOWN | "); - if (hasEventListener(node, eventNames().mouseupEvent)) - properties.append("MOUSEUP | "); - if (hasEventListener(node, eventNames().mouseoverEvent)) - properties.append("MOUSEOVER | "); - if (hasEventListener(node, eventNames().mouseoutEvent)) - properties.append("MOUSEOUT | "); - if (hasEventListener(node, eventNames().keydownEvent)) - properties.append("KEYDOWN | "); - if (hasEventListener(node, eventNames().keyupEvent)) - properties.append("KEYUP | "); - if (CacheBuilder::HasFrame(node)) - properties.append("FRAME | "); - if (focus == node) { - properties.append("FOCUS | "); - focusIndex = count; - } - if (node->isKeyboardFocusable(NULL)) - properties.append("KEYBOARD_FOCUSABLE | "); - if (node->isMouseFocusable()) - properties.append("MOUSE_FOCUSABLE | "); - if (node->isFocusable()) - properties.append("SIMPLE_FOCUSABLE | "); - if (properties.isEmpty()) - properties.append("0"); - else - properties.truncate(properties.length() - 3); - IntRect rect = node->getRect(); - if (node->hasTagName(HTMLNames::areaTag)) - rect = getAreaRect(static_cast<HTMLAreaElement*>(node)); - char buffer[DEBUG_BUFFER_SIZE]; - memset(buffer, 0, sizeof(buffer)); - mBuffer = buffer; - mBufferSize = sizeof(buffer); - mPrefix = "\"\n\""; - mIndex = snprintf(buffer, sizeof(buffer), "{{%d, %d, %d, %d}, ", rect.x(), rect.y(), - rect.width(), rect.height()); - localName(node); - uChar(properties.characters(), properties.length(), false); - print(", "); - int parentIndex = ParentIndex(node, count, node->parentNode()); - char scratch[256]; - snprintf(scratch, sizeof(scratch), "%d", parentIndex); - comma(scratch); - Element* element = static_cast<Element*>(node); - if (node->isElementNode() && element->hasID()) - wideString(element->getIdAttribute()); - else if (node->isTextNode()) { - #if 01 // set to one to abbreviate text that can be omitted from the address detection code - if (rect.isEmpty() && node->textContent().length() > 100) { - wideString(node->textContent().characters(), 100, false); - snprintf(scratch, sizeof(scratch), "/* + %d bytes */", - node->textContent().length() - 100); - print(scratch); - } else - #endif - wideString(node->textContent().characters(), node->textContent().length(), true); - } else if (node->hasTagName(HTMLNames::aTag) || - node->hasTagName(HTMLNames::areaTag)) - { - HTMLAnchorElement* anchor = static_cast<HTMLAnchorElement*>(node); - wideString(anchor->href()); - } else if (node->hasTagName(HTMLNames::imgTag)) { - HTMLImageElement* image = static_cast<HTMLImageElement*>(node); - wideString(image->src()); - } else - print("\"\""); - RenderObject* renderer = node->renderer(); - int tabindex = node->isElementNode() ? node->tabIndex() : 0; - RenderLayer* layer = 0; - if (renderer) { - const IntRect& absB = renderer->absoluteBoundingBoxRect(); - bool hasLayer = renderer->hasLayer(); - layer = hasLayer ? toRenderBoxModelObject(renderer)->layer() : 0; - snprintf(scratch, sizeof(scratch), ", {%d, %d, %d, %d}, %s" - ", %d, %s, %s},", - absB.x(), absB.y(), absB.width(), absB.height(), - renderer->hasOverflowClip() ? "true" : "false", tabindex, - hasLayer ? "true" : "false", - hasLayer && layer->isComposited() ? "true" : "false"); - // TODO: add renderer->style()->visibility() - print(scratch); - } else - print(", {0, 0, 0, 0}, false, 0},"); - - flush(); - snprintf(scratch, sizeof(scratch), "// %d: ", count); - mPrefix = "\n// "; - print(scratch); - //print(renderer ? renderer->information().ascii() : "NO_RENDER_INFO"); - if (node->isElementNode()) { - Element* element = static_cast<Element*>(node); - NamedNodeMap* attrs = element->attributes(); - unsigned length = attrs->length(); - if (length > 0) { - newLine(); - print("// attr: "); - for (unsigned i = 0; i < length; i++) { - Attribute* a = attrs->attributeItem(i); - attr(a->localName(), a->value()); - } - } - } - if (renderer) { - RenderStyle* style = renderer->style(); - snprintf(scratch, sizeof(scratch), "// renderStyle:" - " visibility=%s hasBackGround=%d" - " tapHighlightColor().alpha()=0x%02x" - " isTransparent()=%s", - style->visibility() == HIDDEN ? "HIDDEN" : "VISIBLE", - renderer->hasBackground(), style->tapHighlightColor().alpha(), - renderer->isTransparent() ? "true" : "false"); - newLine(); - print(scratch); - RenderBlock* renderBlock = static_cast<RenderBlock*>(renderer); - if (renderer->isRenderBlock() && renderBlock->hasColumns()) { - const RenderBox* box = static_cast<RenderBox*>(renderer); - const IntRect& oRect = box->visibleOverflowRect(); - snprintf(scratch, sizeof(scratch), "// renderBlock:" - " columnCount=%d columnGap=%d direction=%d" - " hasOverflowClip=%d overflow=(%d,%d,w=%d,h=%d)", - renderBlock->columnInfo()->columnCount(), renderBlock->columnGap(), - renderBlock->style()->direction(), renderer->hasOverflowClip(), - oRect.x(), oRect.y(), oRect.width(), oRect.height()); - newLine(); - print(scratch); - } - } - #if USE(ACCELERATED_COMPOSITING) - if (renderer && renderer->hasLayer()) { - RenderLayer* layer = toRenderBoxModelObject(renderer)->layer(); - RenderLayerBacking* back = layer->backing(); - GraphicsLayer* grLayer = back ? back->graphicsLayer() : 0; - LayerAndroid* aLayer = grLayer ? grLayer->platformLayer() : 0; - const SkPicture* pict = aLayer ? aLayer->picture() : 0; - const IntRect& r = renderer->absoluteBoundingBoxRect(); - snprintf(scratch, sizeof(scratch), "// layer:%p back:%p" - " gLayer:%p aLayer:%p pict:%p r:(%d,%d,w=%d,h=%d)", - layer, back, grLayer, aLayer, pict, r.x(), r.y(), - r.width(), r.height()); - newLine(); - print(scratch); - } - #endif - count++; - newLine(); - } while ((node = node->traverseNextNode()) != NULL); - DUMP_NAV_LOGD("}; // focusables = %d\n", count - 1); - DUMP_NAV_LOGD("\n"); - DUMP_NAV_LOGD("static int TEST%s_RECT_COUNT = %d;\n\n", name, count - 1); - // look for rects with multiple parts - node = doc; - count = 1; - bool hasRectParts = false; - int globalOffsetX, globalOffsetY; - GetGlobalOffset(frame, &globalOffsetX, &globalOffsetY); - do { - IntRect rect; - bool _isFocusable = isFocusable(node) || (node->isTextNode() - && node->getRect().isEmpty() == false - ); - int nodeIndex = count++; - if (_isFocusable == false) - continue; - RenderObject* renderer = node->renderer(); - if (renderer == NULL) - continue; - WTF::Vector<IntRect> rects; - IntRect clipBounds = IntRect(0, 0, INT_MAX, INT_MAX); - IntRect focusBounds = IntRect(0, 0, INT_MAX, INT_MAX); - IntRect* rectPtr = &focusBounds; - int imageCount = 0; - if (node->isTextNode()) { - Text* textNode = (Text*) node; - if (CacheBuilder::ConstructTextRects(textNode, 0, textNode, - INT_MAX, globalOffsetX, globalOffsetY, rectPtr, - clipBounds, &rects) == false) - continue; - } else { - IntRect nodeBounds = node->getRect(); - if (CacheBuilder::ConstructPartRects(node, nodeBounds, rectPtr, - globalOffsetX, globalOffsetY, &rects, &imageCount) == false) - continue; - } - unsigned arraySize = rects.size(); - if (arraySize > 1 || (arraySize == 1 && (rectPtr->width() != rect.width())) || - rectPtr->height() != rect.height()) { - if (hasRectParts == false) { - DUMP_NAV_LOGD("static DebugTestRectPart TEST%s_RECTPARTS[] = {\n", name); - hasRectParts = true; - } - if (node->isTextNode() == false) { - unsigned rectIndex = 0; - for (; rectIndex < arraySize; rectIndex++) { - rectPtr = &rects.at(rectIndex); - DUMP_NAV_LOGD("{ %d, %d, %d, %d, %d }, // %d\n", nodeIndex, - rectPtr->x(), rectPtr->y(), rectPtr->width(), - rectPtr->height(), rectIndex + 1); - } - } else { - RenderText* renderText = (RenderText*) node->renderer(); - InlineTextBox* textBox = renderText->firstTextBox(); - unsigned rectIndex = 0; - while (textBox) { - FloatPoint pt = renderText->localToAbsolute(); - IntRect rect = textBox->selectionRect((int) pt.x(), (int) pt.y(), 0, INT_MAX); - mIndex = 0; - mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex, "{ %d, %d, %d, %d, %d", - nodeIndex, rect.x(), rect.y(), rect.width(), rect.height()); - mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex, ", %d, %d, %d", - textBox->len(), 0 /*textBox->selectionHeight()*/, - 0 /*textBox->selectionTop()*/); - mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex, ", %d, %d, %d", - 0 /*textBox->spaceAdd()*/, textBox->start(), 0 /*textBox->textPos()*/); - mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex, ", %d, %d, %d, %d", - textBox->x(), textBox->y(), textBox->logicalWidth(), textBox->logicalHeight()); - int baseline = textBox->renderer()->style(textBox->isFirstLineStyle())->font().ascent(); - mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex, ", %d, %d }, // %d ", - baseline, imageCount, ++rectIndex); - wideString(node->textContent().characters() + textBox->start(), textBox->len(), true); - DUMP_NAV_LOGD("%.*s\n", mIndex, mBuffer); - textBox = textBox->nextTextBox(); - } - } - } - } while ((node = node->traverseNextNode()) != NULL); - if (hasRectParts) - DUMP_NAV_LOGD("{0}\n};\n\n"); - else - DUMP_NAV_LOGD("static DebugTestRectPart* TEST%s_RECTPARTS = NULL;\n", name); - } - int contentsWidth = layer->width(); - int contentsHeight = layer->height(); - DUMP_NAV_LOGD("static int TEST%s_FOCUS = %d;\n", name, focusIndex); - DUMP_NAV_LOGD("static int TEST%s_WIDTH = %d;\n", name, contentsWidth); - DUMP_NAV_LOGD("static int TEST%s_HEIGHT = %d;\n\n", name, contentsHeight); -} - -bool CacheBuilder::Debug::isFocusable(Node* node) { - if (node->hasTagName(HTMLNames::areaTag)) - return true; - if (node->renderer() == false) - return false; - if (node->isKeyboardFocusable(NULL)) - return true; - if (node->isMouseFocusable()) - return true; - if (node->isFocusable()) - return true; - if (CacheBuilder::AnyIsClick(node)) - return false; - if (CacheBuilder::HasTriggerEvent(node)) - return true; - return false; -} - -void CacheBuilder::Debug::localName(Node* node) { - const AtomicString& local = node->localName(); - if (node->isTextNode()) - print("\"#text\""); - else - wideString(local.characters(), local.length(), false); - print(", "); -} - -void CacheBuilder::Debug::newLine(int indent) { - if (mPrefix[0] != '\n') - print(&mPrefix[0], 1); - flush(); - int lastnewline = mIndex - 1; - while (lastnewline >= 0 && mBuffer[lastnewline] != '\n') - lastnewline--; - lastnewline++; - char* buffer = mBuffer; - if (lastnewline > 0) { - DUMP_NAV_LOGD("%.*s", lastnewline, buffer); - mIndex -= lastnewline; - buffer += lastnewline; - } - size_t prefixLen = strlen(mPrefix); - int minPrefix = prefixLen - 1; - while (minPrefix >= 0 && mPrefix[minPrefix] != '\n') - minPrefix--; - minPrefix = prefixLen - minPrefix - 1; - if (mIndex > minPrefix) - DUMP_NAV_LOGD("%.*s\n", mIndex, buffer); - mIndex = 0; - setIndent(indent); -} - -int CacheBuilder::Debug::ParentIndex(Node* node, int count, Node* parent) -{ - if (parent == NULL) - return -1; - ASSERT(node != parent); - int result = count; - Node* previous = node; - do { - result--; - previous = previous->traversePreviousNode(); - } while (previous && previous != parent); - if (previous != NULL) - return result; - result = count; - do { - result++; - } while ((node = node->traverseNextNode()) != NULL && node != parent); - if (node != NULL) - return result; - ASSERT(0); - return -1; -} - -void CacheBuilder::Debug::print(const char* name) { - print(name, strlen(name)); -} - -void CacheBuilder::Debug::print(const char* name, unsigned len) { - do { - if (mIndex + len >= DEBUG_BUFFER_SIZE) - flush(); - int copyLen = mIndex + len < DEBUG_BUFFER_SIZE ? - len : DEBUG_BUFFER_SIZE - mIndex; - memcpy(&mBuffer[mIndex], name, copyLen); - mIndex += copyLen; - name += copyLen; - len -= copyLen; - } while (len > 0); - mBuffer[mIndex] = '\0'; -} - -void CacheBuilder::Debug::setIndent(int indent) -{ - char scratch[64]; - snprintf(scratch, sizeof(scratch), "%.*s", indent, - " "); - print(scratch); -} - -void CacheBuilder::Debug::uChar(const UChar* name, unsigned len, bool hex) { - const UChar* end = name + len; - bool wroteHex = false; - while (name < end) { - unsigned ch = *name++; - if (ch == '\t' || ch == '\n' || ch == '\r' || ch == 0xa0) - ch = ' '; - if (ch < ' ' || ch == 0x7f) { - if (hex) { - mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex, "\\x%02x", ch); - wroteHex = true; - } else - mBuffer[mIndex++] = '?'; - } else if (ch >= 0x80) { - if (hex) { - if (ch < 0x800) - mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex, - "\\x%02x\\x%02x", ch >> 6 | 0xc0, (ch & 0x3f) | 0x80); - else - mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex, - "\\x%02x\\x%02x\\x%02x", ch >> 12 | 0xe0, - (ch >> 6 & 0x3f) | 0x80, (ch & 0x3f) | 0x80); - wroteHex = true; - } else - mBuffer[mIndex++] = '?'; - } else { - if (wroteHex && WTF::isASCIIHexDigit((UChar) ch)) - mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex, - "\" \""); - else if (ch == '"' || ch == '\\') - mBuffer[mIndex++] = '\\'; - mBuffer[mIndex++] = ch; - wroteHex = false; - } - if (mIndex + 1 >= DEBUG_BUFFER_SIZE) - flush(); - } - flush(); -} - -void CacheBuilder::Debug::validateFrame() { - Frame* frame = frameAnd(); - Page* page = frame->page(); - ASSERT(page); - ASSERT((int) page > 0x10000); - Frame* child = frame->tree()->firstChild(); - while (child) { - Builder(child)->mDebug.validateFrame(); - child = child->tree()->nextSibling(); - } -} - -void CacheBuilder::Debug::wideString(const UChar* chars, int length, bool hex) { - if (length == 0) - print("\"\""); - else { - print("\""); - uChar(chars, length, hex); - print("\""); - } -} - -void CacheBuilder::Debug::wideString(const String& str) { - wideString(str.characters(), str.length(), false); -} - -#endif // DUMP_NAV_CACHE - -CacheBuilder::CacheBuilder() -{ - mAllowableTypes = ALL_CACHEDNODE_BITS; -#ifdef DUMP_NAV_CACHE_USING_PRINTF - gNavCacheLogFile = NULL; -#endif -} - -void CacheBuilder::adjustForColumns(const ClipColumnTracker& track, - CachedNode* node, IntRect* bounds, RenderBlock* renderer) -{ - if (!renderer->hasColumns()) - return; - int x = 0; - int y = 0; - int tx = track.mBounds.x(); - int ty = track.mBounds.y(); - int columnGap = track.mColumnGap; - size_t limit = track.mColumnInfo->columnCount(); - for (size_t index = 0; index < limit; index++) { - IntRect column = renderer->columnRectAt(track.mColumnInfo, index); - column.move(tx, ty); - IntRect test = *bounds; - test.move(x, y); - if (column.contains(test)) { - if ((x | y) == 0) - return; - *bounds = test; - node->move(x, y); - return; - } - int xOffset = column.width() + columnGap; - x += track.mDirection == LTR ? xOffset : -xOffset; - y -= column.height(); - } -} - -// Checks if a node has one of event listener types. -bool CacheBuilder::NodeHasEventListeners(Node* node, AtomicString* eventTypes, int length) { - for (int i = 0; i < length; ++i) { - if (!node->getEventListeners(eventTypes[i]).isEmpty()) - return true; - } - return false; -} - -bool CacheBuilder::AnyChildIsClick(Node* node) -{ - AtomicString eventTypes[5] = { - eventNames().clickEvent, - eventNames().mousedownEvent, - eventNames().mouseupEvent, - eventNames().keydownEvent, - eventNames().keyupEvent - }; - - Node* child = node->firstChild(); - while (child != NULL) { - if (child->isFocusable() || - NodeHasEventListeners(child, eventTypes, 5)) - return true; - if (AnyChildIsClick(child)) - return true; - child = child->nextSibling(); - } - return false; -} - -bool CacheBuilder::AnyIsClick(Node* node) -{ - if (node->hasTagName(HTMLNames::bodyTag)) - return AnyChildIsClick(node); - - AtomicString eventTypeSetOne[4] = { - eventNames().mouseoverEvent, - eventNames().mouseoutEvent, - eventNames().keydownEvent, - eventNames().keyupEvent - }; - - if (!NodeHasEventListeners(node, eventTypeSetOne, 4)) - return false; - - AtomicString eventTypeSetTwo[3] = { - eventNames().clickEvent, - eventNames().mousedownEvent, - eventNames().mouseupEvent - }; - - if (NodeHasEventListeners(node, eventTypeSetTwo, 3)) - return false; - - return AnyChildIsClick(node); -} - -void CacheBuilder::buildCache(CachedRoot* root) -{ - Frame* frame = FrameAnd(this); - mPictureSetDisabled = false; - BuildFrame(frame, frame, root, (CachedFrame*) root); - root->finishInit(); // set up frame parent pointers, child pointers - setData((CachedFrame*) root); -} - -static Node* ParentWithChildren(Node* node) -{ - Node* parent = node; - while ((parent = parent->parentNode())) { - if (parent->childNodeCount() > 1) - return parent; - } - return 0; -} - -// FIXME -// Probably this should check for null instead of the caller. If the -// Tracker object is the last thing in the dom, checking for null in the -// caller in some cases fails to set up Tracker state which may be useful -// to the nodes parsed immediately after the tracked noe. -static Node* OneAfter(Node* node) -{ - Node* parent = node; - Node* sibling = NULL; - while ((parent = parent->parentNode()) != NULL) { - sibling = parent->nextSibling(); - if (sibling != NULL) - break; - } - return sibling; -} - -// return true if this renderer is really a pluinview, and it wants -// key-events (i.e. focus) -static bool checkForPluginViewThatWantsFocus(RenderObject* renderer) { - if (renderer->isWidget()) { - Widget* widget = static_cast<RenderWidget*>(renderer)->widget(); - if (widget && (widget->isPluginView() || widget->isPluginViewBase())) { - // check if this plugin really wants key events (TODO) - return true; - } - } - return false; -} - -#if USE(ACCELERATED_COMPOSITING) -static void AddLayer(CachedFrame* frame, size_t index, const IntPoint& location, int id) -{ - DBG_NAV_LOGD("frame=%p index=%d loc=(%d,%d) id=%d", frame, index, - location.x(), location.y(), id); - CachedLayer cachedLayer; - cachedLayer.setCachedNodeIndex(index); - cachedLayer.setOffset(location); - cachedLayer.setUniqueId(id); - frame->add(cachedLayer); -} -#endif - -static int FindColorIndex(WTF::Vector<CachedColor>& colorTracker, - const CachedColor& cachedColor) -{ - CachedColor* work = colorTracker.begin() - 1; - CachedColor* end = colorTracker.end(); - while (++work < end) { - if (*work == cachedColor) - return work - colorTracker.begin(); - } - int result = colorTracker.size(); - colorTracker.grow(result + 1); - CachedColor& newColor = colorTracker.last(); - newColor = cachedColor; - return result; -} - -static void InitColor(CachedColor* color) -{ - color->setFillColor(RenderStyle::initialRingFillColor()); - color->setInnerWidth(RenderStyle::initialRingInnerWidth()); - color->setOuterWidth(RenderStyle::initialRingOuterWidth()); - color->setOutset(RenderStyle::initialRingOutset()); - color->setPressedInnerColor(RenderStyle::initialRingPressedInnerColor()); - color->setPressedOuterColor(RenderStyle::initialRingPressedOuterColor()); - color->setRadius(RenderStyle::initialRingRadius()); - color->setSelectedInnerColor(RenderStyle::initialRingSelectedInnerColor()); - color->setSelectedOuterColor(RenderStyle::initialRingSelectedOuterColor()); -} - -// when new focus is found, push it's parent on a stack - // as long as more focii are found with the same (grand) parent, note it - // (which only requires retrieving the last parent on the stack) -// when the parent's last child is found, pop the stack -// different from Tracker in that Tracker only pushes focii with children - -// making this work with focus - child focus - grandchild focus is tricky -// if I keep the generation number, I may be able to more quickly determine that -// a node is a grandchild of the focus's parent -// this additionally requires being able to find the grandchild's parent - -// keep nodes that are focusable -void CacheBuilder::BuildFrame(Frame* root, Frame* frame, - CachedRoot* cachedRoot, CachedFrame* cachedFrame) -{ - WTF::Vector<FocusTracker> tracker(1); // sentinel - { - FocusTracker* baseTracker = tracker.data(); - bzero(baseTracker, sizeof(FocusTracker)); - baseTracker->mCachedNodeIndex = -1; - } - WTF::Vector<LayerTracker> layerTracker(1); // sentinel - bzero(layerTracker.data(), sizeof(LayerTracker)); - WTF::Vector<ClipColumnTracker> clipTracker(1); // sentinel - bzero(clipTracker.data(), sizeof(ClipColumnTracker)); - WTF::Vector<TabIndexTracker> tabIndexTracker(1); // sentinel - bzero(tabIndexTracker.data(), sizeof(TabIndexTracker)); - WTF::Vector<CachedColor> colorTracker(1); - InitColor(colorTracker.data()); -#if DUMP_NAV_CACHE - char* frameNamePtr = cachedFrame->mDebug.mFrameName; - Builder(frame)->mDebug.frameName(frameNamePtr, frameNamePtr + - sizeof(cachedFrame->mDebug.mFrameName) - 1); - *frameNamePtr = '\0'; - int nodeIndex = 1; -#endif - NodeWalk walk; - Document* doc = frame->document(); - Node* parent = doc; - CachedNode cachedParentNode; - cachedParentNode.init(parent); -#if DUMP_NAV_CACHE - cachedParentNode.mDebug.mNodeIndex = nodeIndex; -#endif - cachedFrame->add(colorTracker[0]); - cachedFrame->add(cachedParentNode); - Node* node = parent; - int cacheIndex = 1; - int colorIndex = 0; // assume no special css ring colors - const void* lastStyleDataPtr = 0; - int textInputIndex = 0; - Node* focused = doc->focusedNode(); - if (focused) - cachedRoot->setFocusBounds(focused->getRect()); - int globalOffsetX, globalOffsetY; - GetGlobalOffset(frame, &globalOffsetX, &globalOffsetY); -#if USE(ACCELERATED_COMPOSITING) - // The frame itself might be composited so we need to track the layer. Do - // not track the base frame's layer as the main content is draw as part of - // BaseLayerAndroid's picture. - if (frame != root && frame->contentRenderer() - && frame->contentRenderer()->usesCompositing() && node->lastChild()) - TrackLayer(layerTracker, frame->contentRenderer(), node->lastChild(), - globalOffsetX, globalOffsetY); -#endif - while (walk.mMore || (node = node->traverseNextNode()) != NULL) { -#if DUMP_NAV_CACHE - nodeIndex++; -#endif - FocusTracker* last = &tracker.last(); - int lastChildIndex = cachedFrame->size() - 1; - while (node == last->mLastChild) { - if (CleanUpContainedNodes(cachedRoot, cachedFrame, last, lastChildIndex)) - cacheIndex--; - tracker.removeLast(); - lastChildIndex = last->mCachedNodeIndex; - last = &tracker.last(); - } - do { - const ClipColumnTracker* lastClip = &clipTracker.last(); - if (node != lastClip->mLastChild) - break; - clipTracker.removeLast(); - } while (true); - do { - const LayerTracker* lastLayer = &layerTracker.last(); - if (node != lastLayer->mLastChild) - break; - layerTracker.removeLast(); - } while (true); - do { - const TabIndexTracker* lastTabIndex = &tabIndexTracker.last(); - if (node != lastTabIndex->mLastChild) - break; - tabIndexTracker.removeLast(); - } while (true); - Frame* child = HasFrame(node); - CachedNode cachedNode; - if (child != NULL) { - if (child->document() == NULL) - continue; - RenderObject* nodeRenderer = node->renderer(); - if (nodeRenderer != NULL && nodeRenderer->style()->visibility() == HIDDEN) - continue; - CachedFrame cachedChild; - cachedChild.init(cachedRoot, cacheIndex, child); - int childFrameIndex = cachedFrame->childCount(); - cachedFrame->addFrame(cachedChild); - cachedNode.init(node); - cachedNode.setIndex(cacheIndex++); - cachedNode.setDataIndex(childFrameIndex); - cachedNode.setType(FRAME_CACHEDNODETYPE); -#if DUMP_NAV_CACHE - cachedNode.mDebug.mNodeIndex = nodeIndex; - cachedNode.mDebug.mParentGroupIndex = Debug::ParentIndex( - node, nodeIndex, NULL); -#endif - cachedFrame->add(cachedNode); - CachedFrame* childPtr = cachedFrame->lastChild(); - BuildFrame(root, child, cachedRoot, childPtr); - continue; - } - int tabIndex = node->tabIndex(); - Node* lastChild = node->lastChild(); - if (tabIndex <= 0) - tabIndex = tabIndexTracker.last().mTabIndex; - else if (tabIndex > 0 && lastChild) { - DBG_NAV_LOGD("tabIndex=%d node=%p", tabIndex, node); - tabIndexTracker.grow(tabIndexTracker.size() + 1); - TabIndexTracker& indexTracker = tabIndexTracker.last(); - indexTracker.mTabIndex = tabIndex; - indexTracker.mLastChild = OneAfter(lastChild); - } - RenderObject* nodeRenderer = node->renderer(); - bool isTransparent = false; - bool hasCursorRing = true; - if (nodeRenderer != NULL) { - RenderStyle* style = nodeRenderer->style(); - if (style->visibility() == HIDDEN) - continue; - isTransparent = nodeRenderer->hasBackground() == false; -#ifdef ANDROID_CSS_TAP_HIGHLIGHT_COLOR - hasCursorRing = style->tapHighlightColor().alpha() > 0; -#endif -#if USE(ACCELERATED_COMPOSITING) - // If this renderer has its own layer and the layer is composited, - // start tracking it. - if (lastChild && nodeRenderer->hasLayer() && toRenderBoxModelObject(nodeRenderer)->layer()->backing()) - TrackLayer(layerTracker, nodeRenderer, lastChild, globalOffsetX, globalOffsetY); -#endif - } - bool more = walk.mMore; - walk.reset(); - // GetGlobalBounds(node, &bounds, false); - bool computeCursorRings = false; - bool hasClip = false; - bool hasMouseOver = false; - bool isUnclipped = false; - bool isFocus = node == focused; - bool takesFocus = false; - int columnGap = 0; - int imageCount = 0; - TextDirection direction = LTR; - String exported; - CachedNodeType type = NORMAL_CACHEDNODETYPE; - CachedColor cachedColor; - CachedInput cachedInput; - IntRect bounds; - IntRect absBounds; - IntRect originalAbsBounds; - ColumnInfo* columnInfo = NULL; - if (node->hasTagName(HTMLNames::areaTag)) { - type = AREA_CACHEDNODETYPE; - HTMLAreaElement* area = static_cast<HTMLAreaElement*>(node); - bounds = getAreaRect(area); - originalAbsBounds = bounds; - bounds.move(globalOffsetX, globalOffsetY); - absBounds = bounds; - isUnclipped = true; // FIXME: areamaps require more effort to detect - // assume areamaps are always visible for now - takesFocus = true; - goto keepNode; - } - if (nodeRenderer == NULL) - continue; - - // some common setup - absBounds = nodeRenderer->absoluteBoundingBoxRect(); - originalAbsBounds = absBounds; - absBounds.move(globalOffsetX, globalOffsetY); - hasClip = nodeRenderer->hasOverflowClip(); - - if (checkForPluginViewThatWantsFocus(nodeRenderer)) { - bounds = absBounds; - isUnclipped = true; - takesFocus = true; - type = PLUGIN_CACHEDNODETYPE; - goto keepNode; - } - // Only use the root contentEditable element - if (node->rendererIsEditable() && !node->parentOrHostNode()->rendererIsEditable()) { - bounds = absBounds; - takesFocus = true; - type = CONTENT_EDITABLE_CACHEDNODETYPE; - goto keepNode; - } - if (nodeRenderer->isRenderBlock()) { - RenderBlock* renderBlock = (RenderBlock*) nodeRenderer; - if (renderBlock->hasColumns()) { - columnInfo = renderBlock->columnInfo(); - columnGap = renderBlock->columnGap(); - direction = renderBlock->style()->direction(); - } - } - if ((hasClip != false || columnInfo != NULL) && lastChild) { - clipTracker.grow(clipTracker.size() + 1); - ClipColumnTracker& clip = clipTracker.last(); - clip.mBounds = absBounds; - clip.mLastChild = OneAfter(lastChild); - clip.mNode = node; - clip.mColumnInfo = columnInfo; - clip.mColumnGap = columnGap; - clip.mHasClip = hasClip; - clip.mDirection = direction; - if (columnInfo != NULL) { - const IntRect& oRect = ((RenderBox*)nodeRenderer)->visualOverflowRect(); - clip.mBounds.move(oRect.x(), oRect.y()); - } - } - if (node->isTextNode() && mAllowableTypes != NORMAL_CACHEDNODE_BITS) { - if (last->mSomeParentTakesFocus) // don't look at text inside focusable node - continue; - CachedNodeType checkType; - if (isFocusableText(&walk, more, node, &checkType, - &exported) == false) - continue; - #if DUMP_NAV_CACHE - { - char buffer[DEBUG_BUFFER_SIZE]; - mDebug.init(buffer, sizeof(buffer)); - mDebug.print("text link found: "); - mDebug.wideString(exported); - DUMP_NAV_LOGD("%s\n", buffer); - } - #endif - type = checkType; - // !!! test ! is the following line correctly needed for frames to work? - cachedNode.init(node); - const ClipColumnTracker& clipTrack = clipTracker.last(); - const IntRect& clip = clipTrack.mHasClip ? clipTrack.mBounds : - IntRect(0, 0, INT_MAX, INT_MAX); - if (ConstructTextRects((WebCore::Text*) node, walk.mStart, - (WebCore::Text*) walk.mFinalNode, walk.mEnd, globalOffsetX, - globalOffsetY, &bounds, clip, &cachedNode.mCursorRing) == false) - continue; - absBounds = bounds; - cachedNode.setBounds(bounds); - if (bounds.width() < MINIMUM_FOCUSABLE_WIDTH) - continue; - if (bounds.height() < MINIMUM_FOCUSABLE_HEIGHT) - continue; - computeCursorRings = true; - isUnclipped = true; // FIXME: to hide or partially occlude synthesized links, each - // focus ring will also need the offset and length of characters - // used to produce it - goto keepTextNode; - } - if (node->hasTagName(WebCore::HTMLNames::inputTag)) { - HTMLInputElement* input = static_cast<HTMLInputElement*>(node); - if (input->isTextField()) { - if (input->readOnly()) - continue; - type = TEXT_INPUT_CACHEDNODETYPE; - cachedInput.init(); - cachedInput.setAutoComplete(input->autoComplete()); - cachedInput.setSpellcheck(input->spellcheck()); - cachedInput.setFormPointer(input->form()); - cachedInput.setIsTextField(true); - exported = input->value().threadsafeCopy(); - cachedInput.setMaxLength(input->maxLength()); - cachedInput.setTypeFromElement(input); - // If this does not need to be threadsafe, we can use crossThreadString(). - // See http://trac.webkit.org/changeset/49160. - cachedInput.setName(input->name().string().threadsafeCopy()); - // can't detect if this is drawn on top (example: deviant.com login parts) - isUnclipped = isTransparent; - } else if (input->isInputTypeHidden()) - continue; - else if (input->isRadioButton() || input->isCheckbox()) - isTransparent = false; - } else if (node->hasTagName(HTMLNames::textareaTag)) { - HTMLTextAreaElement* area = static_cast<HTMLTextAreaElement*>(node); - if (area->readOnly()) - continue; - cachedInput.init(); - type = TEXT_INPUT_CACHEDNODETYPE; - cachedInput.setFormPointer(area->form()); - cachedInput.setIsTextArea(true); - cachedInput.setSpellcheck(area->spellcheck()); - exported = area->value().threadsafeCopy(); - } else if (node->hasTagName(HTMLNames::aTag)) { - const HTMLAnchorElement* anchorNode = - (const HTMLAnchorElement*) node; - if (!anchorNode->isFocusable() && !HasTriggerEvent(node)) - continue; - if (node->disabled()) - continue; - hasMouseOver = NodeHasEventListeners(node, &eventNames().mouseoverEvent, 1); - type = ANCHOR_CACHEDNODETYPE; - KURL href = anchorNode->href(); - if (!href.isEmpty() && !WebCore::protocolIsJavaScript(href.string())) - // Set the exported string for all non-javascript anchors. - exported = href.string().threadsafeCopy(); - } else if (node->hasTagName(HTMLNames::selectTag)) { - type = SELECT_CACHEDNODETYPE; - } - if (type == TEXT_INPUT_CACHEDNODETYPE) { - RenderTextControl* renderText = - static_cast<RenderTextControl*>(nodeRenderer); - if (isFocus) - cachedRoot->setSelection(renderText->selectionStart(), renderText->selectionEnd()); - // FIXME: Are we sure there will always be a style and font, and it's correct? - RenderStyle* style = nodeRenderer->style(); - if (style) { - isUnclipped |= !style->hasAppearance(); - int lineHeight = -1; - Length lineHeightLength = style->lineHeight(); - // If the lineHeight is negative, WebTextView will calculate it - // based on the text size, using the Paint. - // See RenderStyle.computedLineHeight. - if (lineHeightLength.isPositive()) - lineHeight = style->computedLineHeight(); - cachedInput.setLineHeight(lineHeight); - cachedInput.setTextSize(style->font().size()); - cachedInput.setIsRtlText(style->direction() == RTL - || style->textAlign() == WebCore::RIGHT - || style->textAlign() == WebCore::WEBKIT_RIGHT); - } - cachedInput.setPaddingLeft(renderText->paddingLeft() + renderText->borderLeft()); - cachedInput.setPaddingTop(renderText->paddingTop() + renderText->borderTop()); - cachedInput.setPaddingRight(renderText->paddingRight() + renderText->borderRight()); - cachedInput.setPaddingBottom(renderText->paddingBottom() + renderText->borderBottom()); - } - takesFocus = true; - bounds = absBounds; - if (type != ANCHOR_CACHEDNODETYPE) { - bool isFocusable = node->isKeyboardFocusable(NULL) || - node->isMouseFocusable() || node->isFocusable(); - if (isFocusable == false) { - if (node->disabled()) - continue; - bool overOrOut = HasOverOrOut(node); - bool hasTrigger = HasTriggerEvent(node); - if (overOrOut == false && hasTrigger == false) - continue; - takesFocus = hasTrigger; - } - } - computeCursorRings = true; - keepNode: - cachedNode.init(node); - if (computeCursorRings == false) { - cachedNode.setBounds(bounds); - cachedNode.mCursorRing.append(bounds); - } else if (ConstructPartRects(node, bounds, &cachedNode.mBounds, - globalOffsetX, globalOffsetY, &cachedNode.mCursorRing, - &imageCount) == false) - continue; - keepTextNode: - if (nodeRenderer) { // area tags' node->renderer() == 0 - RenderStyle* style = nodeRenderer->style(); - const void* styleDataPtr = style->ringData(); - // to save time, see if we're pointing to the same style data as before - if (lastStyleDataPtr != styleDataPtr) { - lastStyleDataPtr = styleDataPtr; - cachedColor.setFillColor(style->ringFillColor()); - cachedColor.setInnerWidth(style->ringInnerWidth()); - cachedColor.setOuterWidth(style->ringOuterWidth()); - cachedColor.setOutset(style->ringOutset()); - cachedColor.setPressedInnerColor(style->ringPressedInnerColor()); - cachedColor.setPressedOuterColor(style->ringPressedOuterColor()); - cachedColor.setRadius(style->ringRadius()); - cachedColor.setSelectedInnerColor(style->ringSelectedInnerColor()); - cachedColor.setSelectedOuterColor(style->ringSelectedOuterColor()); - int oldSize = colorTracker.size(); - colorIndex = FindColorIndex(colorTracker, cachedColor); - if (colorIndex == oldSize) - cachedFrame->add(cachedColor); - } - } else - colorIndex = 0; - IntRect clip = hasClip ? bounds : absBounds; - size_t clipIndex = clipTracker.size(); - if (clipTracker.last().mNode == node) - clipIndex -= 1; - while (--clipIndex > 0) { - const ClipColumnTracker& clipTrack = clipTracker.at(clipIndex); - if (clipTrack.mHasClip == false) { - adjustForColumns(clipTrack, &cachedNode, &absBounds, static_cast<RenderBlock*>(nodeRenderer)); - continue; - } - const IntRect& parentClip = clipTrack.mBounds; - if (hasClip == false && type == ANCHOR_CACHEDNODETYPE) - clip = parentClip; - else - clip.intersect(parentClip); - hasClip = true; - } - bool isInLayer = false; -#if USE(ACCELERATED_COMPOSITING) - // If this renderer has a composited parent layer (including itself), - // add the node to the cached layer. - // FIXME: does not work for area rects - RenderLayer* enclosingLayer = nodeRenderer->enclosingLayer(); - if (enclosingLayer && enclosingLayer->enclosingCompositingLayer()) { - LayerAndroid* layer = layerTracker.last().mLayer; - if (layer) { - const IntRect& layerClip = layerTracker.last().mBounds; - if (!layerClip.isEmpty() && !cachedNode.clip(layerClip)) { - DBG_NAV_LOGD("skipped on layer clip %d", cacheIndex); - continue; // skip this node if outside of the clip - } - isInLayer = true; - isUnclipped = true; // assume that layers do not have occluded nodes - hasClip = false; - AddLayer(cachedFrame, cachedFrame->size(), layerClip.location(), - layer->uniqueId()); - } - } -#endif - if (hasClip) { - if (clip.isEmpty()) - continue; // skip this node if clip prevents all drawing - else if (cachedNode.clip(clip) == false) - continue; // skip this node if outside of the clip - } - cachedNode.setColorIndex(colorIndex); - cachedNode.setExport(exported); - cachedNode.setHasCursorRing(hasCursorRing); - cachedNode.setHasMouseOver(hasMouseOver); - cachedNode.setHitBounds(absBounds); - cachedNode.setIndex(cacheIndex); - cachedNode.setIsFocus(isFocus); - cachedNode.setIsInLayer(isInLayer); - cachedNode.setIsTransparent(isTransparent); - cachedNode.setIsUnclipped(isUnclipped); - cachedNode.setOriginalAbsoluteBounds(originalAbsBounds); - cachedNode.setParentIndex(last->mCachedNodeIndex); - cachedNode.setParentGroup(ParentWithChildren(node)); - cachedNode.setSingleImage(imageCount == 1); - cachedNode.setTabIndex(tabIndex); - cachedNode.setType(type); - if (type == TEXT_INPUT_CACHEDNODETYPE) { - cachedFrame->add(cachedInput); - cachedNode.setDataIndex(textInputIndex); - textInputIndex++; - } else - cachedNode.setDataIndex(-1); -#if DUMP_NAV_CACHE - cachedNode.mDebug.mNodeIndex = nodeIndex; - cachedNode.mDebug.mParentGroupIndex = Debug::ParentIndex( - node, nodeIndex, (Node*) cachedNode.parentGroup()); -#endif - cachedFrame->add(cachedNode); - { - int lastIndex = cachedFrame->size() - 1; - if (node == focused) { - CachedNode* cachedNodePtr = cachedFrame->getIndex(lastIndex); - cachedRoot->setCachedFocus(cachedFrame, cachedNodePtr); - } - if (lastChild != NULL) { - tracker.grow(tracker.size() + 1); - FocusTracker& working = tracker.last(); - working.mCachedNodeIndex = lastIndex; - working.mLastChild = OneAfter(lastChild); - last = &tracker.at(tracker.size() - 2); - working.mSomeParentTakesFocus = last->mSomeParentTakesFocus | takesFocus; - } - } - cacheIndex++; - } - while (tracker.size() > 1) { - FocusTracker* last = &tracker.last(); - int lastChildIndex = cachedFrame->size() - 1; - if (CleanUpContainedNodes(cachedRoot, cachedFrame, last, lastChildIndex)) - cacheIndex--; - tracker.removeLast(); - } -} - -bool CacheBuilder::CleanUpContainedNodes(CachedRoot* cachedRoot, - CachedFrame* cachedFrame, const FocusTracker* last, int lastChildIndex) -{ - // if outer is body, disable outer - // or if there's more than one inner, disable outer - // or if inner is keyboard focusable, disable outer - // else disable inner by removing it - int childCount = lastChildIndex - last->mCachedNodeIndex; - if (childCount == 0) - return false; - CachedNode* lastCached = cachedFrame->getIndex(last->mCachedNodeIndex); - Node* lastNode = (Node*) lastCached->nodePointer(); - if ((childCount > 1 && lastNode->hasTagName(HTMLNames::selectTag) == false) || - lastNode->hasTagName(HTMLNames::bodyTag) || - lastNode->hasTagName(HTMLNames::formTag)) { - lastCached->setBounds(IntRect(0, 0, 0, 0)); - lastCached->mCursorRing.clear(); - return false; - } - CachedNode* onlyChildCached = cachedFrame->lastNode(); - Node* onlyChild = (Node*) onlyChildCached->nodePointer(); - bool outerIsMouseMoveOnly = - lastNode->isKeyboardFocusable(NULL) == false && - lastNode->isMouseFocusable() == false && - lastNode->isFocusable() == false && - HasOverOrOut(lastNode) == true && - HasTriggerEvent(lastNode) == false; - if (onlyChildCached->parent() == lastCached) - onlyChildCached->setParentIndex(lastCached->parentIndex()); - bool hasFocus = lastCached->isFocus() || onlyChildCached->isFocus(); - if (outerIsMouseMoveOnly || onlyChild->isKeyboardFocusable(NULL) - || onlyChildCached->isPlugin()) { - int index = lastCached->index(); - *lastCached = *onlyChildCached; - lastCached->setIndex(index); - CachedFrame* frame = cachedFrame->hasFrame(lastCached); - if (frame) - frame->setIndexInParent(index); - } - cachedFrame->removeLast(); - if (hasFocus) - cachedRoot->setCachedFocus(cachedFrame, cachedFrame->lastNode()); - return true; -} - -Node* CacheBuilder::currentFocus() const -{ - Frame* frame = FrameAnd(this); - Document* doc = frame->document(); - if (doc != NULL) { - Node* focus = doc->focusedNode(); - if (focus != NULL) - return focus; - } - Frame* child = frame->tree()->firstChild(); - while (child) { - CacheBuilder* cacheBuilder = Builder(child); - Node* focus = cacheBuilder->currentFocus(); - if (focus) - return focus; - child = child->tree()->nextSibling(); - } - return NULL; -} - -static bool strCharCmp(const char* matches, const UChar* test, int wordLength, - int wordCount) -{ - for (int index = 0; index < wordCount; index++) { - for (int inner = 0; inner < wordLength; inner++) { - if (matches[inner] != test[inner]) { - matches += wordLength; - goto next; - } - } - return true; -next: - ; - } - return false; -} - -static const int stateTwoLetter[] = { - 0x02060c00, // A followed by: [KLRSZ] - 0x00000000, // B - 0x00084001, // C followed by: [AOT] - 0x00000014, // D followed by: [CE] - 0x00000000, // E - 0x00001800, // F followed by: [LM] - 0x00100001, // G followed by: [AU] - 0x00000100, // H followed by: [I] - 0x00002809, // I followed by: [ADLN] - 0x00000000, // J - 0x01040000, // K followed by: [SY] - 0x00000001, // L followed by: [A] - 0x000ce199, // M followed by: [ADEHINOPST] - 0x0120129c, // N followed by: [CDEHJMVY] - 0x00020480, // O followed by: [HKR] - 0x00420001, // P followed by: [ARW] - 0x00000000, // Q - 0x00000100, // R followed by: [I] - 0x0000000c, // S followed by: [CD] - 0x00802000, // T followed by: [NX] - 0x00080000, // U followed by: [T] - 0x00080101, // V followed by: [AIT] - 0x01200101 // W followed by: [AIVY] -}; - -static const char firstIndex[] = { - 0, 5, 5, 8, 10, 10, 12, 14, - 15, 19, 19, 21, 22, 32, 40, 43, - 46, 46, 47, 49, 51, 52, 55, 59 -}; - -// from http://infolab.stanford.edu/~manku/bitcount/bitcount.html -#define TWO(c) (0x1u << (c)) -#define MASK(c) (((unsigned int)(-1)) / (TWO(TWO(c)) + 1u)) -#define COUNT(x,c) ((x) & MASK(c)) + (((x) >> (TWO(c))) & MASK(c)) - -int bitcount (unsigned int n) -{ - n = COUNT(n, 0); - n = COUNT(n, 1); - n = COUNT(n, 2); - n = COUNT(n, 3); - return COUNT(n, 4); -} - -#undef TWO -#undef MASK -#undef COUNT - -static bool isUnicodeSpace(UChar ch) -{ - return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' || ch == 0xa0; -} - -static bool validZip(int stateIndex, const UChar* zipPtr) -{ - static const struct { - char mLow; - char mHigh; - char mException1; - char mException2; - } zipRange[] = { - { 99, 99, -1, -1 }, // AK Alaska - { 35, 36, -1, -1 }, // AL Alabama - { 71, 72, -1, -1 }, // AR Arkansas - { 96, 96, -1, -1 }, // AS American Samoa - { 85, 86, -1, -1 }, // AZ Arizona - { 90, 96, -1, -1 }, // CA California - { 80, 81, -1, -1 }, // CO Colorado - { 6, 6, -1, -1 }, // CT Connecticut - { 20, 20, -1, -1 }, // DC District of Columbia - { 19, 19, -1, -1 }, // DE Delaware - { 32, 34, -1, -1 }, // FL Florida - { 96, 96, -1, -1 }, // FM Federated States of Micronesia - { 30, 31, -1, -1 }, // GA Georgia - { 96, 96, -1, -1 }, // GU Guam - { 96, 96, -1, -1 }, // HI Hawaii - { 50, 52, -1, -1 }, // IA Iowa - { 83, 83, -1, -1 }, // ID Idaho - { 60, 62, -1, -1 }, // IL Illinois - { 46, 47, -1, -1 }, // IN Indiana - { 66, 67, 73, -1 }, // KS Kansas - { 40, 42, -1, -1 }, // KY Kentucky - { 70, 71, -1, -1 }, // LA Louisiana - { 1, 2, -1, -1 }, // MA Massachusetts - { 20, 21, -1, -1 }, // MD Maryland - { 3, 4, -1, -1 }, // ME Maine - { 96, 96, -1, -1 }, // MH Marshall Islands - { 48, 49, -1, -1 }, // MI Michigan - { 55, 56, -1, -1 }, // MN Minnesota - { 63, 65, -1, -1 }, // MO Missouri - { 96, 96, -1, -1 }, // MP Northern Mariana Islands - { 38, 39, -1, -1 }, // MS Mississippi - { 55, 56, -1, -1 }, // MT Montana - { 27, 28, -1, -1 }, // NC North Carolina - { 58, 58, -1, -1 }, // ND North Dakota - { 68, 69, -1, -1 }, // NE Nebraska - { 3, 4, -1, -1 }, // NH New Hampshire - { 7, 8, -1, -1 }, // NJ New Jersey - { 87, 88, 86, -1 }, // NM New Mexico - { 88, 89, 96, -1 }, // NV Nevada - { 10, 14, 0, 6 }, // NY New York - { 43, 45, -1, -1 }, // OH Ohio - { 73, 74, -1, -1 }, // OK Oklahoma - { 97, 97, -1, -1 }, // OR Oregon - { 15, 19, -1, -1 }, // PA Pennsylvania - { 6, 6, 0, 9 }, // PR Puerto Rico - { 96, 96, -1, -1 }, // PW Palau - { 2, 2, -1, -1 }, // RI Rhode Island - { 29, 29, -1, -1 }, // SC South Carolina - { 57, 57, -1, -1 }, // SD South Dakota - { 37, 38, -1, -1 }, // TN Tennessee - { 75, 79, 87, 88 }, // TX Texas - { 84, 84, -1, -1 }, // UT Utah - { 22, 24, 20, -1 }, // VA Virginia - { 6, 9, -1, -1 }, // VI Virgin Islands - { 5, 5, -1, -1 }, // VT Vermont - { 98, 99, -1, -1 }, // WA Washington - { 53, 54, -1, -1 }, // WI Wisconsin - { 24, 26, -1, -1 }, // WV West Virginia - { 82, 83, -1, -1 } // WY Wyoming - }; - - int zip = zipPtr[0] - '0'; - zip *= 10; - zip += zipPtr[1] - '0'; - int low = zipRange[stateIndex].mLow; - int high = zipRange[stateIndex].mHigh; - if (zip >= low && zip <= high) - return true; - if (zip == zipRange[stateIndex].mException1) - return true; - if (zip == zipRange[stateIndex].mException2) - return true; - return false; -} - -#define MAX_PLACE_NAME_LENGTH 25 // the longest allowable one word place name - -CacheBuilder::FoundState CacheBuilder::FindAddress(const UChar* chars, - unsigned length, int* start, int* end, bool caseInsensitive) -{ - FindState addressState; - FindReset(&addressState); - addressState.mWords[0] = addressState.mStarts[0] = chars; - addressState.mCaseInsensitive = caseInsensitive; - FoundState state = FindPartialAddress(chars, chars, length, &addressState); - if (state == FOUND_PARTIAL && addressState.mProgress == ZIP_CODE && - addressState.mNumberCount == 0) { - addressState.mProgress = FIND_STREET; - state = FindPartialAddress(NULL, NULL, 0, &addressState); - } - *start = addressState.mStartResult; - *end = addressState.mEndResult; - return state; -} - -CacheBuilder::FoundState CacheBuilder::FindPartialAddress(const UChar* baseChars, - const UChar* chars, unsigned length, FindState* s) -{ - // lower case letters are optional; trailing asterisk is optional 's' - static char const* const longStreetNames[] = { - "\x04" "LleY" "\x04" "NneX" "\x05" "RCade" "\x05" "VEnue" "\x06" "LAMEDA", // A - "\x04" "aYoU" "\x04" "eaCH" "\x03" "eND" "\x05" "LuFf*" "\x05" "oTtoM" - "\x08" "ouLeVarD" "\x05" "Ranch" "\x05" "RidGe" "\x05" "RooK*" - "\x04" "urG*" "\x05" "YPass" "\x07" "roadWAY", // B - "\x05" "AMINO" - "\x03" "amP" "\x05" "anYoN" "\x03" "aPE" "\x07" "auSeWaY" "\x06" "enTeR*" - "\x06" "IRcle*" "\x05" "LiFf*" "\x03" "LuB" "\x05" "oMmoN" "\x06" "ORner*" - "\x05" "ouRSE" "\x05" "ourT*" "\x04" "oVe*" "\x04" "ReeK" "\x07" "REScent" - "\x04" "ReST" "\x07" "ROSSING" "\x08" "ROSSROAD" "\x04" "URVe" - "\x05" "AMINO" "\x06" "IRCULO" "\x07" "REScent", // C - "\x03" "aLe" "\x02" "aM" "\x05" "iVide" "\x05" "Rive*", // D - "\x06" "STate*" "\x09" "XPresswaY" "\x09" "XTension*", // E - "\x04" "ALL*" "\x04" "eRrY" "\x05" "ieLD*" "\x04" "LaT*" "\x04" "oRD*" - "\x05" "oReST" "\x05" "oRGe*" "\x04" "oRK*" "\x03" "orT" "\x06" "reeWaY", // F - "\x06" "arDeN*" "\x06" "aTeWaY" "\x04" "LeN*" "\x05" "ReeN*" "\x05" "RoVe*", // G - "\x06" "arBoR*" "\x04" "aVeN" "\x06" "eighTS" "\x06" "ighWaY" "\x04" "iLl*" - "\x05" "OLloW", // H - "\x04" "NLeT" "\x06" "Sland*" "\x03" "SLE", // I - "\x08" "unCTion*", // J - "\x03" "eY*" "\x05" "NoLl*", // K - "\x04" "aKe*" "\x03" "AND" "\x06" "aNDinG" "\x03" "aNe" "\x05" "iGhT*" - "\x03" "oaF" "\x04" "oCK*" "\x04" "oDGe" "\x03" "OOP", // L - "\x03" "ALL" "\x05" "aNoR*" "\x06" "eaDoW*" "\x03" "EWS" "\x04" "iLl*" - "\x06" "iSsioN" "\x07" "oTorWaY" "\x04" "ounT" "\x08" "ounTaiN*", // M - "\x03" "eCK", // N - "\x06" "RCHard" "\x03" "VAL" "\x07" "verPASs", // O - "\x04" "ARK*" "\x07" "arKWaY*" "\x03" "ASS" "\x06" "aSsaGE" "\x03" "ATH" - "\x03" "IKE" "\x04" "iNE*" "\x04" "Lace" "\x05" "LaiN*" "\x04" "LaZa" - "\x05" "oinT*" "\x04" "oRT*" "\x06" "Rairie" "\x06" "RIVADA", // P - NULL, - "\x05" "ADiaL" "\x03" "AMP" "\x04" "aNCH" "\x05" "aPiD*" - "\x03" "eST" - "\x05" "iDGe*" "\x04" "IVer" "\x04" "oaD*" "\x04" "ouTE" "\x02" "OW" - "\x02" "UE" "\x02" "UN", // R - "\x05" "HoaL*" "\x05" "HoRe*" "\x05" "KyWaY" "\x06" "PrinG*" "\x04" "PUR*" - "\x06" "Quare*" "\x06" "TAtion" "\x08" "TRAvenue" "\x05" "TReaM" - "\x06" "Treet*" "\x05" "uMmiT" "\x07" "PeeDWaY", // S - "\x06" "ERrace" "\x09" "hRoughWaY" "\x04" "RaCE" "\x04" "RAcK" "\x09" "RaFficwaY" - "\x04" "RaiL" "\x05" "UNneL" "\x07" "urnPiKE", // T - "\x08" "nderPASs" "\x05" "Nion*", // U - "\x06" "aLleY*" "\x06" "IAduct" "\x04" "ieW*" "\x07" "iLlaGe*" "\x04" "iLle" - "\x04" "ISta", // V - "\x04" "ALK*" "\x03" "ALL" "\x03" "AY*" "\x04" "eLl*", // W - "\x03" "ING" "\x02" "RD", // X - }; - - static char const* const longStateNames[] = { - "\x8e" "la" "\x85" "bama" "\x02" "\x84" "ska" "\x01" "\x8f" "merican Samoa" "\x04" - "\x91" "r" "\x86" "izona" "\x05" "\x87" "kansas" "\x03", - NULL, - "\x8b" "alifornia" "\x06" "\x95" "o" "\x87" "lorado" "\x07" "\x8a" "nnecticut" "\x08", - "\x89" "elaware" "\x0a" "\x95" "istrict of Columbia" "\x09", - NULL, - "\x9f" "ederated States of Micronesia" "\x0c" "\x88" "lorida" "\x0b", - "\x85" "uam" "\x0e" "\x88" "eorgia" "\x0d", - "\x87" "awaii" "\x0f", - "\x86" "daho" "\x11" "\x89" "llinois" "\x12" "\x88" "ndiana" "\x13" "\x85" - "owa" "\x10", - NULL, - "\x87" "ansas" "\x14" "\x89" "entucky" "\x15", - "\x8a" "ouisiana" "\x16", - "\x86" "aine" "\x19" "\x99" "ar" "\x8e" "shall Islands" "\x1a" "\x86" "yland" "\x18" - "\x8e" "assachusetts" "\x17" "\x93" "i" "\x87" "chigan" "\x1b" - "\x88" "nnesota" "\x1c" "\x93" "iss" "\x88" "issippi" "\x1f" "\x85" - "ouri" "\x1d" "\x88" "ontana" "\x20", - "\x90" "e" "\x87" "braska" "\x23" "\x85" "vada" "\x27" "\xa5" "ew " "\x8a" - "Hampshire" "\x24" "\x87" "Jersey" "\x25" "\x87" "Mexico" "\x26" - "\x85" "York" "\x28" "\x98" "orth " "\x89" "Carolina" "\x21" "\x87" - "Dakota" "\x22" "\x99" "orthern Mariana Islands" "\x1e", - "\x85" "hio" "\x29" "\x89" "klahoma" "\x2a" "\x87" "regon" "\x2b", - "\x86" "alau" "\x2e" "\x8d" "ennsylvania" "\x2c" "\x8c" "uerto Rico" "\x2d", - NULL, - "\x8d" "hode Island" "\x2f", - "\x98" "outh " "\x89" "Carolina" "\x30" "\x87" "Dakota" "\x31", - "\x90" "e" "\x88" "nnessee" "\x32" "\x84" "xas" "\x33", - "\x85" "tah" "\x34", - "\x88" "ermont" "\x37" "\x94" "irgin" "\x89" " Islands" "\x36" "\x83" "ia" "\x35", - "\x8b" "ashington" "\x38" "\x8e" "est Virginia" "\x3a" "\x8a" "isconsin" "\x39" - "\x88" "yoming" "\x3b" - }; - -#if 0 // DEBUG_NAV_UI - static char const* const progressNames[] = { - "NO_ADDRESS", - "SKIP_TO_SPACE", - "HOUSE_NUMBER", - "NUMBER_TRAILING_SPACE", - "ADDRESS_LINE", - "STATE_NAME", - "SECOND_HALF", - "ZIP_CODE", - "PLUS_4", - "FIND_STREET" - }; -#endif - // strategy: US only support at first - // look for a 1 - 5 digit number for a street number (no support for 'One Microsoft Way') - // ignore if preceded by '#', Suite, Ste, Rm - // look for two or more words (up to 5? North Frank Lloyd Wright Blvd) - // note: "The Circle at North Hills St." has six words, and a lower 'at' -- allow at, by, of, in, the, and, ... ? - // if a word starts with a lowercase letter, no match - // allow: , . - # / (for 1/2) ' " - // don't look for street name type yet - // look for one or two delimiters to represent possible 2nd addr line and city name - // look for either full state name, or state two letters, and/or zip code (5 or 9 digits) - // now look for street suffix, either in full or abbreviated form, with optional 's' if there's an asterisk - - s->mCurrentStart = chars; - s->mEnd = chars + length; - int candIndex = 0; - bool retryState; - bool mustBeAllUpper = false; - bool secondHalf = false; - chars -= 1; - UChar ch = s->mCurrent; - while (++chars <= s->mEnd) { - UChar prior = ch; - ch = chars < s->mEnd ? *chars : ' '; - switch (s->mProgress) { - case NO_ADDRESS: - if (WTF::isASCIIDigit(ch) == false) { - if (ch != 'O') // letter 'O', not zero - continue; - if (s->mEnd - chars < 3) - continue; - prior = *++chars; - ch = *++chars; - if ((prior != 'n' || ch != 'e') && (prior != 'N' || ch != 'E')) - continue; - if (isUnicodeSpace(*++chars) == false) - continue; - s->mProgress = ADDRESS_LINE; - s->mStartResult = chars - 3 - s->mCurrentStart; - continue; - } - if (isUnicodeSpace(prior) == false) { - s->mProgress = SKIP_TO_SPACE; - continue; - } - s->mNumberCount = 1; - s->mProgress = HOUSE_NUMBER; - s->mStartResult = chars - s->mCurrentStart; - continue; - case SKIP_TO_SPACE: - if (isUnicodeSpace(ch) == false) - continue; - break; - case HOUSE_NUMBER: - if (WTF::isASCIIDigit(ch)) { - if (++s->mNumberCount >= 6) - s->mProgress = SKIP_TO_SPACE; - continue; - } - if (WTF::isASCIIUpper(ch)) { // allow one letter after house number, e.g. 12A SKOLFIELD PL, HARPSWELL, ME 04079 - if (WTF::isASCIIDigit(prior) == false) - s->mProgress = SKIP_TO_SPACE; - continue; - } - if (ch == '-') { - if (s->mNumberCount > 0) { // permit 21-23 ELM ST - ++s->mNumberCount; - continue; - } - } - s->mNumberCount = 0; - s->mProgress = NUMBER_TRAILING_SPACE; - case NUMBER_TRAILING_SPACE: - if (isUnicodeSpace(ch)) - continue; - if (0 && WTF::isASCIIDigit(ch)) { - s->mNumberCount = 1; - s->mProgress = HOUSE_NUMBER; - s->mStartResult = chars - s->mCurrentStart; - continue; - } - if (WTF::isASCIIDigit(ch) == false && WTF::isASCIIUpper(ch) == false) - break; - s->mProgress = ADDRESS_LINE; - case ADDRESS_LINE: - if (WTF::isASCIIAlpha(ch) || ch == '\'' || ch == '-' || ch == '&' || ch == '(' || ch == ')') { - if (++s->mLetterCount > 1) { - s->mNumberWords &= ~(1 << s->mWordCount); - continue; - } - if (s->mNumberCount >= 5) - break; -// FIXME: the test below was added to give up on a non-address, but it -// incorrectly discards addresses where the house number is in one node -// and the street name is in the next; I don't recall what the failing case -// is that suggested this fix. -// if (s->mWordCount == 0 && s->mContinuationNode) -// return FOUND_NONE; - s->newWord(baseChars, chars); - if (WTF::isASCIILower(ch) && s->mNumberCount == 0) - s->mFirstLower = chars; - s->mNumberCount = 0; - if (WTF::isASCIILower(ch) || (WTF::isASCIIAlpha(ch) == false && ch != '-')) - s->mNumberWords &= ~(1 << s->mWordCount); - s->mUnparsed = true; - continue; - } else if (s->mLetterCount >= MAX_PLACE_NAME_LENGTH) { - break; - } else if (s->mFirstLower != NULL) { - if (s->mCaseInsensitive) - goto resetWord; - size_t length = chars - s->mFirstLower; - if (length > 3) - break; - if (length == 3 && strCharCmp("and" "the", s->mFirstLower, 3, 2) == false) - break; - if (length == 2 && strCharCmp("at" "by" "el" "in" "of", s->mFirstLower, 2, 5) == false) - break; - goto resetWord; - } - if (ch == ',' || ch == '*') { // delimits lines - // asterisk as delimiter: http://www.sa.sc.edu/wellness/members.html - if (++s->mLineCount > 5) - break; - goto lookForState; - } - if (isUnicodeSpace(ch) || prior == '-') { - lookForState: - if (s->mUnparsed == false) - continue; - const UChar* candidate = s->mWords[s->mWordCount]; - UChar firstLetter = candidate[0]; - if (WTF::isASCIIUpper(firstLetter) == false && WTF::isASCIIDigit(firstLetter) == false) - goto resetWord; - s->mWordCount++; - if ((s->mWordCount == 2 && s->mNumberWords == 3 && WTF::isASCIIDigit(s->mWords[1][1])) || // choose second of 8888 333 Main - (s->mWordCount >= sizeof(s->mWords) / sizeof(s->mWords[0]) - 1)) { // subtract 1 since state names may have two parts - // search for simple number already stored since first potential house # didn't pan out - if (s->mNumberWords == 0) - break; - int shift = 0; - while ((s->mNumberWords & (1 << shift)) == 0) - shift++; - s->mNumberWords >>= ++shift; - if (s->mBases[0] != s->mBases[shift]) // if we're past the original node, bail - break; - s->shiftWords(shift); - s->mStartResult = s->mWords[0] - s->mStarts[0]; - s->mWordCount -= shift; - // FIXME: need to adjust lineCount to account for discarded delimiters - } - if (s->mWordCount < 4) - goto resetWord; - firstLetter -= 'A'; - if (firstLetter > 'W' - 'A') - goto resetWord; - UChar secondLetter = candidate[1]; - if (prior == '-') - s->mLetterCount--; // trim trailing dashes, to accept CA-94043 - if (s->mLetterCount == 2) { - secondLetter -= 'A'; - if (secondLetter > 'Z' - 'A') - goto resetWord; - if ((stateTwoLetter[firstLetter] & 1 << secondLetter) != 0) { - // special case to ignore 'et al' - if (strCharCmp("ET", s->mWords[s->mWordCount - 2], 2, 1) == false) { - s->mStateWord = s->mWordCount - 1; - s->mZipHint = firstIndex[firstLetter] + - bitcount(stateTwoLetter[firstLetter] & ((1 << secondLetter) - 1)); - goto foundStateName; - } - } - goto resetWord; - } - s->mStates = longStateNames[firstLetter]; - if (s->mStates == NULL) - goto resetWord; - mustBeAllUpper = false; - s->mProgress = STATE_NAME; - unsigned char section = s->mStates[0]; - ASSERT(section > 0x80); - s->mSectionLength = section & 0x7f; - candIndex = 1; - secondHalf = false; - s->mStateWord = s->mWordCount - 1; - goto stateName; - } - if (WTF::isASCIIDigit(ch)) { - if (s->mLetterCount == 0) { - if (++s->mNumberCount > 1) - continue; - if (s->mWordCount == 0 && s->mContinuationNode) - return FOUND_NONE; - s->newWord(baseChars, chars); - s->mNumberWords |= 1 << s->mWordCount; - s->mUnparsed = true; - } - continue; - } - if (ch == '.') { // optionally can follow letters - if (s->mLetterCount == 0) - break; - if (s->mNumberCount > 0) - break; - continue; - } - if (ch == '/') // between numbers (1/2) between words (12 Main / Ste 4d) - goto resetWord; - if (ch == '#') // can precede numbers, allow it to appear randomly - goto resetWord; - if (ch == '"') // sometimes parts of addresses are quoted (FIXME: cite an example here) - continue; - break; - case SECOND_HALF: - if (WTF::isASCIIAlpha(ch)) { - if (s->mLetterCount == 0) { - s->newWord(baseChars, chars); - s->mWordCount++; - } - s->mLetterCount++; - continue; - } - if (WTF::isASCIIDigit(ch) == false) { - if (s->mLetterCount > 0) { - s->mProgress = STATE_NAME; - candIndex = 0; - secondHalf = true; - goto stateName; - } - continue; - } - s->mProgress = ADDRESS_LINE; - goto resetState; - case STATE_NAME: - stateName: - // pick up length of first section - do { - int stateIndex = 1; - int skip = 0; - int prefix = 0; - bool subStr = false; - do { - unsigned char match = s->mStates[stateIndex]; - if (match >= 0x80) { - if (stateIndex == s->mSectionLength) - break; - subStr = true; - // if (skip > 0) - // goto foundStateName; - prefix = candIndex; - skip = match & 0x7f; - match = s->mStates[++stateIndex]; - } - UChar candChar = s->mWords[s->mWordCount - 1][candIndex]; - if (mustBeAllUpper && WTF::isASCIILower(candChar)) - goto skipToNext; - if (match != candChar) { - if (match != WTF::toASCIILower(candChar)) { - skipToNext: - if (subStr == false) - break; - if (stateIndex == s->mSectionLength) { - if (secondHalf) { - s->mProgress = ADDRESS_LINE; - goto resetState; - } - break; - } - stateIndex += skip; - skip = 0; - candIndex = prefix; - continue; // try next substring - } - mustBeAllUpper = true; - } - int nextindex = stateIndex + 1; - if (++candIndex >= s->mLetterCount && s->mStates[nextindex] == ' ') { - s->mProgress = SECOND_HALF; - s->mStates += nextindex; - s->mSectionLength -= nextindex; - goto resetWord; - } - if (nextindex + 1 == s->mSectionLength || skip == 2) { - s->mZipHint = s->mStates[nextindex] - 1; - goto foundStateName; - } - stateIndex += 1; - skip -= 1; - } while (true); - s->mStates += s->mSectionLength; - ASSERT(s->mStates[0] == 0 || (unsigned) s->mStates[0] > 0x80); - s->mSectionLength = s->mStates[0] & 0x7f; - candIndex = 1; - subStr = false; - } while (s->mSectionLength != 0); - s->mProgress = ADDRESS_LINE; - goto resetState; - foundStateName: - s->mEndResult = chars - s->mCurrentStart; - s->mEndWord = s->mWordCount - 1; - s->mProgress = ZIP_CODE; - // a couple of delimiters is an indication that the state name is good - // or, a non-space / non-alpha-digit is also good - s->mZipDelimiter = s->mLineCount > 2 - || isUnicodeSpace(ch) == false - || chars == s->mEnd; - if (WTF::isASCIIDigit(ch)) - s->mZipStart = chars; - goto resetState; - case ZIP_CODE: - if (WTF::isASCIIDigit(ch)) { - int count = ++s->mNumberCount; - if (count == 1) { - if (WTF::isASCIIDigit(prior)) - ++s->mNumberCount; - else - s->mZipStart = chars; - } - if (count <= 9) - continue; - } else if (isUnicodeSpace(ch)) { - if (s->mNumberCount == 0) { - s->mZipDelimiter = true; // two spaces delimit state name - continue; - } - } else if (ch == '-') { - if (s->mNumberCount == 5 && validZip(s->mZipHint, s->mZipStart)) { - s->mNumberCount = 0; - s->mProgress = PLUS_4; - continue; - } - if (s->mNumberCount == 0) - s->mZipDelimiter = true; - } else if (WTF::isASCIIAlpha(ch) == false) - s->mZipDelimiter = true; - else { - if (s->mLetterCount == 0) { - s->newWord(baseChars, chars); - s->mUnparsed = true; - } - ++s->mLetterCount; - } - if (s->mNumberCount == 5 || s->mNumberCount == 9) { - if (validZip(s->mZipHint, s->mZipStart) == false) - goto noZipMatch; - s->mEndResult = chars - s->mCurrentStart; - s->mEndWord = s->mWordCount - 1; - } else if (s->mZipDelimiter == false) { - noZipMatch: - --chars; - s->mProgress = ADDRESS_LINE; - continue; - } - s->mProgress = FIND_STREET; - goto findStreet; - case PLUS_4: - if (WTF::isASCIIDigit(ch)) { - if (++s->mNumberCount <= 4) - continue; - } - if (isUnicodeSpace(ch)) { - if (s->mNumberCount == 0) - continue; - } - if (s->mNumberCount == 4) { - if (WTF::isASCIIAlpha(ch) == false) { - s->mEndResult = chars - s->mCurrentStart; - s->mEndWord = s->mWordCount - 1; - } - } else if (s->mNumberCount != 0) - break; - s->mProgress = FIND_STREET; - case FIND_STREET: - findStreet: - retryState = false; - for (int wordsIndex = s->mStateWord - 1; wordsIndex >= 0; --wordsIndex) { - const UChar* test = s->mWords[wordsIndex]; - UChar letter = test[0]; - letter -= 'A'; - if (letter > 'X' - 'A') - continue; - const char* names = longStreetNames[letter]; - if (names == NULL) - continue; - int offset; - while ((offset = *names++) != 0) { - int testIndex = 1; - bool abbr = false; - for (int idx = 0; idx < offset; idx++) { - char nameLetter = names[idx]; - char testUpper = WTF::toASCIIUpper(test[testIndex]); - if (nameLetter == '*') { - if (testUpper == 'S') - testIndex++; - break; - } - bool fullOnly = WTF::isASCIILower(nameLetter); - nameLetter = WTF::toASCIIUpper(nameLetter); - if (testUpper == nameLetter) { - if (abbr && fullOnly) - goto nextTest; - testIndex++; - continue; - } - if (fullOnly == false) - goto nextTest; - abbr = true; - } - letter = &test[testIndex] < s->mEnds[wordsIndex] ? - test[testIndex] : ' '; - if (WTF::isASCIIAlpha(letter) == false && WTF::isASCIIDigit(letter) == false) { - if (s->mNumberWords != 0) { - int shift = 0; - int wordReduction = -1; - do { - while ((s->mNumberWords & (1 << shift)) == 0) - shift++; - if (shift > wordsIndex) - break; - wordReduction = shift; - } while (s->mNumberWords >> ++shift != 0); - if (wordReduction >= 0) { - if (s->mContinuationNode) { - if (retryState) - break; - return FOUND_NONE; - } - s->mStartResult = s->mWords[wordReduction] - s->mStarts[wordReduction]; - } - } - if (wordsIndex != s->mStateWord - 1) - return FOUND_COMPLETE; - retryState = true; - } - nextTest: - names += offset; - } - } - if (retryState) { - s->mProgress = ADDRESS_LINE; - s->mStates = NULL; - continue; - } - if (s->mNumberWords != 0) { - unsigned shift = 0; - while ((s->mNumberWords & (1 << shift)) == 0) - shift++; - s->mNumberWords >>= ++shift; - if (s->mBases[0] != s->mBases[shift]) - return FOUND_NONE; - s->shiftWords(shift); - s->mStartResult = s->mWords[0] - s->mStarts[0]; - s->mWordCount -= shift; - s->mProgress = ADDRESS_LINE; - --chars; - continue; - } - break; - } - if (s->mContinuationNode) - return FOUND_NONE; - s->mProgress = NO_ADDRESS; - s->mWordCount = s->mLineCount = 0; - s->mNumberWords = 0; - resetState: - s->mStates = NULL; - resetWord: - s->mNumberCount = s->mLetterCount = 0; - s->mFirstLower = NULL; - s->mUnparsed = false; - } - s->mCurrent = ch; - return s->mProgress == NO_ADDRESS ? FOUND_NONE : FOUND_PARTIAL; -} - -// Recogize common email patterns only. Currently has lots of state, walks text forwards and backwards -- will be -// a real challenge to adapt to walk text across multiple nodes, I imagine -// FIXME: it's too hard for the caller to call these incrementally -- it's probably best for this to -// either walk the node tree directly or make a callout to get the next or previous node, if there is one -// walking directly will avoid adding logic in caller to track the multiple partial or full nodes that compose this -// text pattern. -CacheBuilder::FoundState CacheBuilder::FindPartialEMail(const UChar* chars, unsigned length, - FindState* s) -{ - // the following tables were generated by tests/browser/focusNavigation/BrowserDebug.cpp - // hand-edit at your own risk - static const int domainTwoLetter[] = { - 0x02df797c, // a followed by: [cdefgilmnoqrstuwxz] - 0x036e73fb, // b followed by: [abdefghijmnorstvwyz] - 0x03b67ded, // c followed by: [acdfghiklmnorsuvxyz] - 0x02005610, // d followed by: [ejkmoz] - 0x001e00d4, // e followed by: [ceghrstu] - 0x00025700, // f followed by: [ijkmor] - 0x015fb9fb, // g followed by: [abdefghilmnpqrstuwy] - 0x001a3400, // h followed by: [kmnrtu] - 0x000f7818, // i followed by: [delmnoqrst] - 0x0000d010, // j followed by: [emop] - 0x0342b1d0, // k followed by: [eghimnprwyz] - 0x013e0507, // l followed by: [abcikrstuvy] - 0x03fffccd, // m followed by: [acdghklmnopqrstuvwxyz] - 0x0212c975, // n followed by: [acefgilopruz] - 0x00001000, // o followed by: [m] - 0x014e3cf1, // p followed by: [aefghklmnrstwy] - 0x00000001, // q followed by: [a] - 0x00504010, // r followed by: [eouw] - 0x032a7fdf, // s followed by: [abcdeghijklmnortvyz] - 0x026afeec, // t followed by: [cdfghjklmnoprtvwz] - 0x03041441, // u followed by: [agkmsyz] - 0x00102155, // v followed by: [aceginu] - 0x00040020, // w followed by: [fs] - 0x00000000, // x - 0x00180010, // y followed by: [etu] - 0x00401001, // z followed by: [amw] - }; - - static char const* const longDomainNames[] = { - "\x03" "ero" "\x03" "rpa", // aero, arpa - "\x02" "iz", // biz - "\x02" "at" "\x02" "om" "\x03" "oop", // cat, com, coop - NULL, // d - "\x02" "du", // edu - NULL, // f - "\x02" "ov", // gov - NULL, // h - "\x03" "nfo" "\x02" "nt", // info, int - "\x03" "obs", // jobs - NULL, // k - NULL, // l - "\x02" "il" "\x03" "obi" "\x05" "useum", // mil, mobi, museum - "\x03" "ame" "\x02" "et", // name, net - "\x02" "rg", // , org - "\x02" "ro", // pro - NULL, // q - NULL, // r - NULL, // s - "\x05" "ravel", // travel - NULL, // u - NULL, // v - NULL, // w - NULL, // x - NULL, // y - NULL, // z - }; - - const UChar* start = chars; - const UChar* end = chars + length; - while (chars < end) { - UChar ch = *chars++; - if (ch != '@') - continue; - const UChar* atLocation = chars - 1; - // search for domain - ch = *chars++ | 0x20; // convert uppercase to lower - if (ch < 'a' || ch > 'z') - continue; - while (chars < end) { - ch = *chars++; - if (IsDomainChar(ch) == false) - goto nextAt; - if (ch != '.') - continue; - UChar firstLetter = *chars++ | 0x20; // first letter of the domain - if (chars >= end) - return FOUND_NONE; // only one letter; must be at least two - firstLetter -= 'a'; - if (firstLetter > 'z' - 'a') - continue; // non-letter followed '.' - int secondLetterMask = domainTwoLetter[firstLetter]; - ch = *chars | 0x20; // second letter of the domain - ch -= 'a'; - if (ch >= 'z' - 'a') - continue; - bool secondMatch = (secondLetterMask & 1 << ch) != 0; - const char* wordMatch = longDomainNames[firstLetter]; - int wordIndex = 0; - while (wordMatch != NULL) { - int len = *wordMatch++; - char match; - do { - match = wordMatch[wordIndex]; - if (match < 0x20) - goto foundDomainStart; - if (chars[wordIndex] != match) - break; - wordIndex++; - } while (true); - wordMatch += len; - if (*wordMatch == '\0') - break; - wordIndex = 0; - } - if (secondMatch) { - wordIndex = 1; - foundDomainStart: - chars += wordIndex; - if (chars < end) { - ch = *chars; - if (ch != '.') { - if (IsDomainChar(ch)) - goto nextDot; - } else if (chars + 1 < end && IsDomainChar(chars[1])) - goto nextDot; - } - // found domain. Search backwards from '@' for beginning of email address - s->mEndResult = chars - start; - chars = atLocation; - if (chars <= start) - goto nextAt; - ch = *--chars; - if (ch == '.') - goto nextAt; // mailbox can't end in period - do { - if (IsMailboxChar(ch) == false) { - chars++; - break; - } - if (chars == start) - break; - ch = *--chars; - } while (true); - UChar firstChar = *chars; - if (firstChar == '.' || firstChar == '@') // mailbox can't start with period or be empty - goto nextAt; - s->mStartResult = chars - start; - return FOUND_COMPLETE; - } - nextDot: - ; - } -nextAt: - chars = atLocation + 1; - } - return FOUND_NONE; -} - -#define PHONE_PATTERN "(200) /-.\\ 100 -. 0000" // poor man's regex: parens optional, any one of punct, digit smallest allowed - -CacheBuilder::FoundState CacheBuilder::FindPartialNumber(const UChar* chars, unsigned length, - FindState* s) -{ - char* pattern = s->mPattern; - UChar* store = s->mStorePtr; - const UChar* start = chars; - const UChar* end = chars + length; - const UChar* lastDigit = NULL; - do { - bool initialized = s->mInitialized; - while (chars < end) { - if (initialized == false) { - s->mBackTwo = s->mBackOne; - s->mBackOne = s->mCurrent; - } - UChar ch = s->mCurrent = *chars; - do { - char patternChar = *pattern; - switch (patternChar) { - case '2': - if (initialized == false) { - s->mStartResult = chars - start; - initialized = true; - } - case '0': - case '1': - if (ch < patternChar || ch > '9') - goto resetPattern; - *store++ = ch; - pattern++; - lastDigit = chars; - goto nextChar; - case '\0': - if (WTF::isASCIIDigit(ch) == false) { - *store = '\0'; - goto checkMatch; - } - goto resetPattern; - case ' ': - if (ch == patternChar) - goto nextChar; - break; - case '(': - if (ch == patternChar) { - s->mStartResult = chars - start; - initialized = true; - s->mOpenParen = true; - } - goto commonPunctuation; - case ')': - if ((ch == patternChar) ^ s->mOpenParen) - goto resetPattern; - default: - commonPunctuation: - if (ch == patternChar) { - pattern++; - goto nextChar; - } - } - } while (++pattern); // never false - nextChar: - chars++; - } - break; -resetPattern: - if (s->mContinuationNode) - return FOUND_NONE; - FindResetNumber(s); - pattern = s->mPattern; - store = s->mStorePtr; - } while (++chars < end); -checkMatch: - if (WTF::isASCIIDigit(s->mBackOne != '1' ? s->mBackOne : s->mBackTwo)) - return FOUND_NONE; - *store = '\0'; - s->mStorePtr = store; - s->mPattern = pattern; - s->mEndResult = lastDigit - start + 1; - char pState = pattern[0]; - return pState == '\0' ? FOUND_COMPLETE : pState == '(' || (WTF::isASCIIDigit(pState) && WTF::isASCIIDigit(pattern[-1])) ? - FOUND_NONE : FOUND_PARTIAL; -} - -CacheBuilder::FoundState CacheBuilder::FindPhoneNumber(const UChar* chars, unsigned length, - int* start, int* end) -{ - FindState state; - FindReset(&state); - FoundState result = FindPartialNumber(chars, length, &state); - *start = state.mStartResult; - *end = state.mEndResult; - return result; -} - -void CacheBuilder::FindReset(FindState* state) -{ - memset(state, 0, sizeof(FindState)); - state->mCurrent = ' '; - FindResetNumber(state); -} - -void CacheBuilder::FindResetNumber(FindState* state) -{ - state->mOpenParen = false; - state->mPattern = (char*) PHONE_PATTERN; - state->mStorePtr = state->mStore; -} - -IntRect CacheBuilder::getAreaRect(const HTMLAreaElement* area) -{ - Node* node = area->document(); - while ((node = node->traverseNextNode()) != NULL) { - RenderObject* renderer = node->renderer(); - if (renderer && renderer->isRenderImage()) { - RenderImage* image = static_cast<RenderImage*>(renderer); - HTMLMapElement* map = image->imageMap(); - if (map) { - Node* n; - for (n = map->firstChild(); n; - n = n->traverseNextNode(map)) { - if (n == area) { - if (area->isDefault()) - return image->absoluteBoundingBoxRect(); - return area->computeRect(image); - } - } - } - } - } - return IntRect(); -} - -void CacheBuilder::GetGlobalOffset(Node* node, int* x, int * y) -{ - GetGlobalOffset(node->document()->frame(), x, y); -} - -void CacheBuilder::GetGlobalOffset(Frame* frame, int* x, int* y) -{ -// TIMER_PROBE(__FUNCTION__); - ASSERT(x); - ASSERT(y); - *x = 0; - *y = 0; - if (!frame->view()) - return; - Frame* parent; - while ((parent = frame->tree()->parent()) != NULL) { - const WebCore::IntRect& rect = frame->view()->platformWidget()->getBounds(); - *x += rect.x(); - *y += rect.y(); - frame = parent; - } - // TIMER_PROBE_END(); -} - -Frame* CacheBuilder::HasFrame(Node* node) -{ - RenderObject* renderer = node->renderer(); - if (renderer == NULL) - return NULL; - if (renderer->isWidget() == false) - return NULL; - Widget* widget = static_cast<RenderWidget*>(renderer)->widget(); - if (widget == NULL) - return NULL; - if (widget->isFrameView() == false) - return NULL; - return static_cast<FrameView*>(widget)->frame(); -} - -bool CacheBuilder::HasOverOrOut(Node* node) -{ - // eventNames are thread-local data, I avoid using 'static' variable here. - AtomicString eventTypes[2] = { - eventNames().mouseoverEvent, - eventNames().mouseoutEvent - }; - - return NodeHasEventListeners(node, eventTypes, 2); -} - -bool CacheBuilder::HasTriggerEvent(Node* node) -{ - AtomicString eventTypes[5] = { - eventNames().clickEvent, - eventNames().mousedownEvent, - eventNames().mouseupEvent, - eventNames().keydownEvent, - eventNames().keyupEvent - }; - - return NodeHasEventListeners(node, eventTypes, 5); -} - -// #define EMAIL_PATTERN "x@y.d" // where 'x' is letters, numbers, and '-', '.', '_' ; 'y' is 'x' without the underscore, and 'd' is a valid domain -// - 0x2D . 0x2E 0-9 0x30-39 A-Z 0x41-5A _ 0x5F a-z 0x61-7A - -bool CacheBuilder::IsDomainChar(UChar ch) -{ - static const unsigned body[] = {0x03ff6000, 0x07fffffe, 0x07fffffe}; // 0-9 . - A-Z a-z - ch -= 0x20; - if (ch > 'z' - 0x20) - return false; - return (body[ch >> 5] & 1 << (ch & 0x1f)) != 0; -} - -bool CacheBuilder::isFocusableText(NodeWalk* walk, bool more, Node* node, - CachedNodeType* type, String* exported) const -{ - Text* textNode = static_cast<Text*>(node); - StringImpl* string = textNode->dataImpl(); - const UChar* baseChars = string->characters(); -// const UChar* originalBase = baseChars; - int length = string->length(); - int index = 0; - while (index < length && isUnicodeSpace(baseChars[index])) - index++; - if (index >= length) - return false; - if (more == false) { - walk->mStart = 0; - walk->mEnd = 0; - walk->mFinalNode = node; - walk->mLastInline = NULL; - } - // starting with this node, search forward for email, phone number, and address - // if any of the three is found, track it so that the remaining can be looked for later - FoundState state = FOUND_NONE; - RenderText* renderer = (RenderText*) node->renderer(); - bool foundBetter = false; - InlineTextBox* baseInline = walk->mLastInline != NULL ? walk->mLastInline : - renderer->firstTextBox(); - if (baseInline == NULL) - return false; - int start = walk->mEnd; - InlineTextBox* saveInline; - int baseStart, firstStart = start; - saveInline = baseInline; - baseStart = start; - for (CachedNodeType checkType = ADDRESS_CACHEDNODETYPE; - checkType <= PHONE_CACHEDNODETYPE; - checkType = static_cast<CachedNodeType>(checkType + 1)) - { - if ((1 << (checkType - 1) & mAllowableTypes) == 0) - continue; - InlineTextBox* inlineTextBox = baseInline; - FindState findState; - FindReset(&findState); - start = baseStart; - if (checkType == ADDRESS_CACHEDNODETYPE) { - findState.mBases[0] = baseChars; - findState.mWords[0] = baseChars + start; - findState.mStarts[0] = baseChars + start; - } - Node* lastPartialNode = NULL; - int lastPartialEnd = -1; - bool lastPartialMore = false; - bool firstPartial = true; - InlineTextBox* lastPartialInline = NULL; - do { - do { - const UChar* chars = baseChars + start; - length = inlineTextBox == NULL ? 0 : - inlineTextBox->end() - start + 1; - bool wasInitialized = findState.mInitialized; - switch (checkType) { - case ADDRESS_CACHEDNODETYPE: - state = FindPartialAddress(baseChars, chars, length, &findState); - break; - case EMAIL_CACHEDNODETYPE: - state = FindPartialEMail(chars, length, &findState); - break; - case PHONE_CACHEDNODETYPE: - state = FindPartialNumber(chars, length, &findState); - break; - default: - ASSERT(0); - } - findState.mInitialized = state != FOUND_NONE; - if (wasInitialized != findState.mInitialized) - firstStart = start; - if (state == FOUND_PARTIAL) { - lastPartialNode = node; - lastPartialEnd = findState.mEndResult + start; - lastPartialMore = firstPartial && - lastPartialEnd < (int) string->length(); - firstPartial = false; - lastPartialInline = inlineTextBox; - findState.mContinuationNode = true; - } else if (state == FOUND_COMPLETE) { - if (foundBetter == false || walk->mStart > findState.mStartResult) { - walk->mStart = findState.mStartResult + firstStart; - if (findState.mEndResult > 0) { - walk->mFinalNode = node; - walk->mEnd = findState.mEndResult + start; - walk->mMore = node == textNode && - walk->mEnd < (int) string->length(); - walk->mLastInline = inlineTextBox; - } else { - walk->mFinalNode = lastPartialNode; - walk->mEnd = lastPartialEnd; - walk->mMore = lastPartialMore; - walk->mLastInline = lastPartialInline; - } - *type = checkType; - if (checkType == PHONE_CACHEDNODETYPE) { - const UChar* store = findState.mStore; - *exported = String(store); - } else { - Node* temp = textNode; - length = 1; - start = walk->mStart; - exported->truncate(0); - do { - Text* tempText = static_cast<Text*>(temp); - StringImpl* string = tempText->dataImpl(); - int end = tempText == walk->mFinalNode ? - walk->mEnd : string->length(); - exported->append(String(string->substring( - start, end - start))); - ASSERT(end > start); - length += end - start + 1; - if (temp == walk->mFinalNode) - break; - start = 0; - do { - temp = temp->traverseNextNode(); - ASSERT(temp); - } while (temp->isTextNode() == false); - // add a space in between text nodes to avoid - // words collapsing together - exported->append(" "); - } while (true); - } - foundBetter = true; - } - goto tryNextCheckType; - } else if (findState.mContinuationNode) - break; - if (inlineTextBox == NULL) - break; - inlineTextBox = inlineTextBox->nextTextBox(); - if (inlineTextBox == NULL) - break; - start = inlineTextBox->start(); - if (state == FOUND_PARTIAL && node == textNode) - findState.mContinuationNode = false; - } while (true); - if (state == FOUND_NONE) - break; - // search for next text node, if any - Text* nextNode; - do { - do { - do { - if (node) - node = node->traverseNextNode(); - if (node == NULL || node->hasTagName(HTMLNames::aTag) - || node->hasTagName(HTMLNames::inputTag) - || node->hasTagName(HTMLNames::textareaTag)) { - if (state == FOUND_PARTIAL && - checkType == ADDRESS_CACHEDNODETYPE && - findState.mProgress == ZIP_CODE && - findState.mNumberCount == 0) { - baseChars = NULL; - inlineTextBox = NULL; - start = 0; - findState.mProgress = FIND_STREET; - goto finalNode; - } - goto tryNextCheckType; - } - } while (node->isTextNode() == false); - nextNode = static_cast<Text*>(node); - renderer = (RenderText*) nextNode->renderer(); - } while (renderer == NULL); - baseInline = renderer->firstTextBox(); - } while (baseInline == NULL); - string = nextNode->dataImpl(); - baseChars = string->characters(); - inlineTextBox = baseInline; - start = inlineTextBox->start(); - finalNode: - findState.mEndResult = 0; - } while (true); -tryNextCheckType: - node = textNode; - baseInline = saveInline; - string = textNode->dataImpl(); - baseChars = string->characters(); - } - if (foundBetter) { - CachedNodeType temp = *type; - switch (temp) { - case ADDRESS_CACHEDNODETYPE: { - static const char geoString[] = "geo:0,0?q="; - exported->insert(String(geoString), 0); - int index = sizeof(geoString) - 1; - String escapedComma("%2C"); - while ((index = exported->find(',', index)) >= 0) - exported->replace(index, 1, escapedComma); - } break; - case EMAIL_CACHEDNODETYPE: { - String encoded = WebCore::encodeWithURLEscapeSequences(*exported); - exported->swap(encoded); - exported->insert(WTF::String("mailto:"), 0); - } break; - case PHONE_CACHEDNODETYPE: - exported->insert(WTF::String("tel:"), 0); - break; - default: - break; - } - return true; - } -noTextMatch: - walk->reset(); - return false; -} - -bool CacheBuilder::IsMailboxChar(UChar ch) -{ - // According to http://en.wikipedia.org/wiki/Email_address - // ! # $ % & ' * + - . / 0-9 = ? - // A-Z ^ _ - // ` a-z { | } ~ - static const unsigned body[] = {0xa3ffecfa, 0xc7fffffe, 0x7fffffff}; - ch -= 0x20; - if (ch > '~' - 0x20) - return false; - return (body[ch >> 5] & 1 << (ch & 0x1f)) != 0; -} - -bool CacheBuilder::setData(CachedFrame* cachedFrame) -{ - Frame* frame = FrameAnd(this); - Document* doc = frame->document(); - if (doc == NULL) - return false; - RenderObject* renderer = doc->renderer(); - if (renderer == NULL) - return false; - RenderLayer* layer = renderer->enclosingLayer(); - if (layer == NULL) - return false; - if (!frame->view()) - return false; - int x, y; - GetGlobalOffset(frame, &x, &y); - WebCore::IntRect viewBounds = frame->view()->platformWidget()->getBounds(); - if ((x | y) != 0) - viewBounds.setLocation(WebCore::IntPoint(x, y)); - cachedFrame->setLocalViewBounds(viewBounds); - cachedFrame->setContentsSize(layer->scrollWidth(), layer->scrollHeight()); - if (cachedFrame->childCount() == 0) - return true; - CachedFrame* lastCachedFrame = cachedFrame->lastChild(); - cachedFrame = cachedFrame->firstChild(); - do { - CacheBuilder* cacheBuilder = Builder((Frame* )cachedFrame->framePointer()); - cacheBuilder->setData(cachedFrame); - } while (cachedFrame++ != lastCachedFrame); - return true; -} - -#if USE(ACCELERATED_COMPOSITING) -void CacheBuilder::TrackLayer(WTF::Vector<LayerTracker>& layerTracker, - RenderObject* nodeRenderer, Node* lastChild, int offsetX, int offsetY) -{ - RenderLayer* layer = nodeRenderer->enclosingLayer(); - RenderLayerBacking* back = layer->backing(); - if (!back) - return; - GraphicsLayer* grLayer = back->graphicsLayer(); - if (back->hasContentsLayer()) - grLayer = back->foregroundLayer(); - if (!grLayer) - return; - LayerAndroid* aLayer = grLayer->platformLayer(); - if (!aLayer) - return; - IntPoint scroll(layer->scrollXOffset(), layer->scrollYOffset()); -#if ENABLE(ANDROID_OVERFLOW_SCROLL) - // If this is an overflow element, track the content layer. - if (layer->hasOverflowScroll() && aLayer->getChild(0)) - aLayer = aLayer->getChild(0)->getChild(0); - if (!aLayer) - return; - // Prevent a crash when scrolling a layer that does not have a parent. - if (layer->stackingContext()) - layer->scrollToOffset(0, 0); -#endif - layerTracker.grow(layerTracker.size() + 1); - LayerTracker& indexTracker = layerTracker.last(); - indexTracker.mLayer = aLayer; - indexTracker.mRenderLayer = layer; - indexTracker.mBounds = enclosingIntRect(aLayer->bounds()); - // Use the absolute location of the layer as the bounds location. This - // provides the original offset of nodes in the layer so that we can - // translate nodes between their original location and the layer's new - // location. - indexTracker.mBounds.setLocation(layer->absoluteBoundingBox().location()); - indexTracker.mBounds.move(offsetX, offsetY); - indexTracker.mScroll = scroll; - indexTracker.mLastChild = OneAfter(lastChild); - DBG_NAV_LOGD("layer=%p [%d] bounds=(%d,%d,w=%d,h=%d)", aLayer, - aLayer->uniqueId(), indexTracker.mBounds.x(), indexTracker.mBounds.y(), - indexTracker.mBounds.width(), indexTracker.mBounds.height()); -} -#endif - -bool CacheBuilder::validNode(Frame* startFrame, void* matchFrame, - void* matchNode) -{ - if (matchFrame == startFrame) { - if (matchNode == NULL) - return true; - Node* node = startFrame->document(); - while (node != NULL) { - if (node == matchNode) { - const IntRect& rect = node->hasTagName(HTMLNames::areaTag) ? - getAreaRect(static_cast<HTMLAreaElement*>(node)) : node->getRect(); - // Consider nodes with empty rects that are not at the origin - // to be valid, since news.google.com has valid nodes like this - if (rect.x() == 0 && rect.y() == 0 && rect.isEmpty()) - return false; - return true; - } - node = node->traverseNextNode(); - } - DBG_NAV_LOGD("frame=%p valid node=%p invalid\n", matchFrame, matchNode); - return false; - } - Frame* child = startFrame->tree()->firstChild(); - while (child) { - bool result = validNode(child, matchFrame, matchNode); - if (result) - return result; - child = child->tree()->nextSibling(); - } -#if DEBUG_NAV_UI - if (startFrame->tree()->parent() == NULL) - DBG_NAV_LOGD("frame=%p node=%p false\n", matchFrame, matchNode); -#endif - return false; -} - -static int Area(const IntRect& rect) -{ - return rect.width() * rect.height(); -} - -bool CacheBuilder::AddPartRect(IntRect& bounds, int x, int y, - WTF::Vector<IntRect>* result, IntRect* focusBounds) -{ - if (bounds.isEmpty()) - return true; - bounds.move(x, y); - if (bounds.maxX() <= 0 || bounds.maxY() <= 0) - return true; - IntRect* work = result->begin() - 1; - IntRect* end = result->end(); - while (++work < end) { - if (work->contains(bounds)) - return true; - if (bounds.contains(*work)) { - *work = bounds; - focusBounds->unite(bounds); - return true; - } - if ((bounds.x() != work->x() || bounds.width() != work->width()) && - (bounds.y() != work->y() || bounds.height() != work->height())) - continue; - IntRect test = *work; - test.unite(bounds); - if (Area(test) > Area(*work) + Area(bounds)) - continue; - *work = test; - focusBounds->unite(bounds); - return true; - } - if (result->size() >= MAXIMUM_FOCUS_RING_COUNT) - return false; - result->append(bounds); - if (focusBounds->isEmpty()) - *focusBounds = bounds; - else - focusBounds->unite(bounds); - return true; -} - -bool CacheBuilder::ConstructPartRects(Node* node, const IntRect& bounds, - IntRect* focusBounds, int x, int y, WTF::Vector<IntRect>* result, - int* imageCountPtr) -{ - WTF::Vector<ClipColumnTracker> clipTracker(1); - ClipColumnTracker* baseTracker = clipTracker.data(); // sentinel - bzero(baseTracker, sizeof(ClipColumnTracker)); - if (node->hasChildNodes() && node->hasTagName(HTMLNames::buttonTag) == false - && node->hasTagName(HTMLNames::selectTag) == false) { - // collect all text rects from first to last child - Node* test = node->firstChild(); - Node* last = NULL; - Node* prior = node; - while ((prior = prior->lastChild()) != NULL) - last = prior; - ASSERT(last != NULL); - bool nodeIsAnchor = node->hasTagName(HTMLNames::aTag); - do { - do { - const ClipColumnTracker* lastClip = &clipTracker.last(); - if (test != lastClip->mLastChild) - break; - clipTracker.removeLast(); - } while (true); - RenderObject* renderer = test->renderer(); - if (renderer == NULL) - continue; - EVisibility vis = renderer->style()->visibility(); - if (vis == HIDDEN) - continue; - bool hasClip = renderer->hasOverflowClip(); - size_t clipIndex = clipTracker.size(); - IntRect clipBounds = IntRect(0, 0, INT_MAX, INT_MAX); - if (hasClip || --clipIndex > 0) { - clipBounds = hasClip ? renderer->absoluteBoundingBoxRect() : - clipTracker.at(clipIndex).mBounds; // x, y fixup done by ConstructTextRect - } - if (test->isTextNode()) { - RenderText* renderText = (RenderText*) renderer; - InlineTextBox *textBox = renderText->firstTextBox(); - if (textBox == NULL) - continue; - if (ConstructTextRect((Text*) test, textBox, 0, INT_MAX, - x, y, focusBounds, clipBounds, result) == false) { - return false; - } - continue; - } - if (test->hasTagName(HTMLNames::imgTag)) { - IntRect bounds = test->getRect(); - bounds.intersect(clipBounds); - if (AddPartRect(bounds, x, y, result, focusBounds) == false) - return false; - *imageCountPtr += 1; - continue; - } - if (hasClip == false) { - if (nodeIsAnchor && test->hasTagName(HTMLNames::divTag)) { - IntRect bounds = renderer->absoluteBoundingBoxRect(); // x, y fixup done by AddPartRect - RenderBox* renderBox = static_cast<RenderBox*>(renderer); - int left = bounds.x() + renderBox->paddingLeft() + renderBox->borderLeft(); - int top = bounds.y() + renderBox->paddingTop() + renderBox->borderTop(); - int right = bounds.maxX() - renderBox->paddingRight() - renderBox->borderRight(); - int bottom = bounds.maxY() - renderBox->paddingBottom() - renderBox->borderBottom(); - if (left >= right || top >= bottom) - continue; - bounds = IntRect(left, top, right - left, bottom - top); - if (AddPartRect(bounds, x, y, result, focusBounds) == false) - return false; - } - continue; - } - Node* lastChild = test->lastChild(); - if (lastChild == NULL) - continue; - clipTracker.grow(clipTracker.size() + 1); - ClipColumnTracker& clip = clipTracker.last(); - clip.mBounds = renderer->absoluteBoundingBoxRect(); // x, y fixup done by ConstructTextRect - clip.mLastChild = OneAfter(lastChild); - clip.mNode = test; - } while (test != last && (test = test->traverseNextNode()) != NULL); - } - if (result->size() == 0 || focusBounds->width() < MINIMUM_FOCUSABLE_WIDTH - || focusBounds->height() < MINIMUM_FOCUSABLE_HEIGHT) { - if (bounds.width() < MINIMUM_FOCUSABLE_WIDTH) - return false; - if (bounds.height() < MINIMUM_FOCUSABLE_HEIGHT) - return false; - result->append(bounds); - *focusBounds = bounds; - } - return true; -} - -static inline bool isNotSpace(UChar c) -{ - return c <= 0xA0 ? isUnicodeSpace(c) == false : - WTF::Unicode::direction(c) != WTF::Unicode::WhiteSpaceNeutral; -} - -bool CacheBuilder::ConstructTextRect(Text* textNode, - InlineTextBox* textBox, int start, int relEnd, int x, int y, - IntRect* focusBounds, const IntRect& clipBounds, WTF::Vector<IntRect>* result) -{ - RenderText* renderText = (RenderText*) textNode->renderer(); - EVisibility vis = renderText->style()->visibility(); - StringImpl* string = textNode->dataImpl(); - const UChar* chars = string->characters(); - FloatPoint pt = renderText->localToAbsolute(); - do { - int textBoxStart = textBox->start(); - int textBoxEnd = textBoxStart + textBox->len(); - if (textBoxEnd <= start) - continue; - if (textBoxEnd > relEnd) - textBoxEnd = relEnd; - IntRect bounds = textBox->selectionRect((int) pt.x(), (int) pt.y(), - start, textBoxEnd); - bounds.intersect(clipBounds); - if (bounds.isEmpty()) - continue; - bool drawable = false; - for (int index = start; index < textBoxEnd; index++) - if ((drawable |= isNotSpace(chars[index])) != false) - break; - if (drawable && vis != HIDDEN) { - if (AddPartRect(bounds, x, y, result, focusBounds) == false) - return false; - } - if (textBoxEnd == relEnd) - break; - } while ((textBox = textBox->nextTextBox()) != NULL); - return true; -} - -bool CacheBuilder::ConstructTextRects(Text* node, int start, - Text* last, int end, int x, int y, IntRect* focusBounds, - const IntRect& clipBounds, WTF::Vector<IntRect>* result) -{ - result->clear(); - *focusBounds = IntRect(0, 0, 0, 0); - do { - RenderText* renderText = (RenderText*) node->renderer(); - int relEnd = node == last ? end : renderText->textLength(); - InlineTextBox *textBox = renderText->firstTextBox(); - if (textBox != NULL) { - do { - if ((int) textBox->end() >= start) - break; - } while ((textBox = textBox->nextTextBox()) != NULL); - if (textBox && ConstructTextRect(node, textBox, start, relEnd, - x, y, focusBounds, clipBounds, result) == false) - return false; - } - start = 0; - do { - if (node == last) - return true; - node = (Text*) node->traverseNextNode(); - ASSERT(node != NULL); - } while (node->isTextNode() == false || node->renderer() == NULL); - } while (true); -} - -} diff --git a/Source/WebKit/android/nav/CacheBuilder.h b/Source/WebKit/android/nav/CacheBuilder.h deleted file mode 100644 index 8f1cc72..0000000 --- a/Source/WebKit/android/nav/CacheBuilder.h +++ /dev/null @@ -1,297 +0,0 @@ -/* - * Copyright 2006, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef CacheBuilder_h -#define CacheBuilder_h - -#include "CachedDebug.h" -#include "CachedNodeType.h" -#include "IntRect.h" -#include "PlatformString.h" -#include "TextDirection.h" -#include <wtf/Forward.h> -#include <wtf/Vector.h> - -#define NAVIGATION_MAX_PHONE_LENGTH 14 - -using namespace WebCore; - -namespace WebCore { - -class ColumnInfo; -class Document; -class Frame; -class HTMLAreaElement; -class InlineTextBox; -class LayerAndroid; -class Node; -class PlatformGraphicsContext; -class RenderBlock; -class RenderFlow; -class RenderLayer; -class RenderObject; -class Text; - -} - -namespace android { - -class CachedFrame; -class CachedNode; -class CachedRoot; - -class CacheBuilder { -public: - enum Direction { - UNINITIALIZED = -1, - LEFT, - RIGHT, - UP, - DOWN, - DIRECTION_COUNT, - UP_DOWN = UP & DOWN, // mask and result - RIGHT_DOWN = RIGHT & DOWN, // mask and result - }; - enum FoundState { - FOUND_NONE, - FOUND_PARTIAL, - FOUND_COMPLETE - }; - CacheBuilder(); - void allowAllTextDetection() { mAllowableTypes = ALL_CACHEDNODE_BITS; } - void buildCache(CachedRoot* root); - static bool ConstructPartRects(Node* node, const IntRect& bounds, - IntRect* focusBounds, int x, int y, WTF::Vector<IntRect>* result, - int* imageCountPtr); - Node* currentFocus() const; - void disallowAddressDetection() { mAllowableTypes = (CachedNodeBits) ( - mAllowableTypes & ~ADDRESS_CACHEDNODE_BIT); } - void disallowEmailDetection() { mAllowableTypes = (CachedNodeBits) ( - mAllowableTypes & ~EMAIL_CACHEDNODE_BIT); } - void disallowPhoneDetection() { mAllowableTypes = (CachedNodeBits) ( - mAllowableTypes & ~PHONE_CACHEDNODE_BIT); } - static FoundState FindAddress(const UChar* , unsigned length, int* start, - int* end, bool caseInsensitive); - static IntRect getAreaRect(const HTMLAreaElement* area); - static void GetGlobalOffset(Frame* , int* x, int * y); - static void GetGlobalOffset(Node* , int* x, int * y); - bool pictureSetDisabled() { return mPictureSetDisabled; } - static bool validNode(Frame* startFrame, void* framePtr, void* nodePtr); -private: - enum AddressProgress { - NO_ADDRESS, - SKIP_TO_SPACE, - HOUSE_NUMBER, - NUMBER_TRAILING_SPACE, - ADDRESS_LINE, - STATE_NAME, - SECOND_HALF, - ZIP_CODE, - PLUS_4, - FIND_STREET - }; - struct NodeWalk { - NodeWalk() { reset(); } - int mStart; - int mEnd; - Node* mFinalNode; - InlineTextBox* mLastInline; - bool mMore; - void reset() { mMore = false; } - }; - struct BoundsPart { - IntRect mRect; - int mStart; - int mEnd; - }; - struct Bounds { - typedef bool (*FindText)(BoundsPart* result, InlineTextBox* , const String& match); - IntRect mNodeBounds; - BoundsPart mPart; - WTF::Vector<BoundsPart> mParts; - char mStore[NAVIGATION_MAX_PHONE_LENGTH + 1]; - int mPartIndex; - Node* mNode; - Node* mFinalNode; - void reset() { mNode = NULL; } - }; - struct FindState { - int mStartResult; - int mEndResult; - const UChar* mCurrentStart; - const UChar* mEnd; - AddressProgress mProgress; - int mNumberCount; - int mLetterCount; - unsigned mWordCount; - int mLineCount; - const UChar* mFirstLower; - const UChar* mZipStart; - const UChar* mBases[16]; // FIXME: random guess, maybe too small, maybe too big - const UChar* mWords[16]; - const UChar* mEnds[16]; - const UChar* mStarts[16]; // text is not necessarily contiguous - const char* mStates; - int mEndWord; - int mStateWord; - int mZipHint; - int mSectionLength; - unsigned mNumberWords; // must contain as many bits as mWords contains elements - char* mPattern; - UChar mStore[NAVIGATION_MAX_PHONE_LENGTH + 1]; - UChar* mStorePtr; - UChar mBackOne; - UChar mBackTwo; - UChar mCurrent; - bool mUnparsed; - bool mZipDelimiter; - bool mOpenParen; - bool mInitialized; - bool mContinuationNode; - bool mCaseInsensitive; - void shiftWords(int shift) { - memmove(mBases, &mBases[shift], (sizeof(mBases) / - sizeof(mBases[0]) - shift) * sizeof(mBases[0])); - memmove(mWords, &mWords[shift], (sizeof(mWords) / - sizeof(mWords[0]) - shift) * sizeof(mWords[0])); - memmove(mEnds, &mEnds[shift], (sizeof(mEnds) / - sizeof(mEnds[0]) - shift) * sizeof(mEnds[0])); - memmove(mStarts, &mStarts[shift], (sizeof(mStarts) / - sizeof(mStarts[0]) - shift) * sizeof(mStarts[0])); - } - void newWord(const UChar* baseChars, const UChar* chars) { - mBases[mWordCount] = baseChars; - mWords[mWordCount] = chars; - mEnds[mWordCount] = mEnd; - mStarts[mWordCount] = mCurrentStart; - } - }; - struct Tracker { - Node* mLastChild; - }; - struct ClipColumnTracker : Tracker { - Node* mNode; - IntRect mBounds; - ColumnInfo* mColumnInfo; - int mColumnGap; - TextDirection mDirection; - bool mHasClip; - }; - struct LayerTracker : Tracker { - LayerAndroid* mLayer; - RenderLayer* mRenderLayer; - IntRect mBounds; - IntPoint mScroll; - ~LayerTracker(); - }; - struct TabIndexTracker : Tracker { - int mTabIndex; - }; - struct FocusTracker : TabIndexTracker { - int mCachedNodeIndex; - bool mSomeParentTakesFocus; - }; - void adjustForColumns(const ClipColumnTracker& track, - CachedNode* node, IntRect* bounds, RenderBlock*); - static bool AddPartRect(IntRect& bounds, int x, int y, - WTF::Vector<IntRect>* result, IntRect* focusBounds); - static bool AnyIsClick(Node* node); - static bool AnyChildIsClick(Node* node); - static bool NodeHasEventListeners(Node* node, AtomicString* eventTypes, int length); - void BuildFrame(Frame* root, Frame* frame, - CachedRoot* cachedRoot, CachedFrame* cachedFrame); - bool CleanUpContainedNodes(CachedRoot* cachedRoot, CachedFrame* cachedFrame, - const FocusTracker* last, int lastChildIndex); - static bool ConstructTextRect(Text* textNode, - InlineTextBox* textBox, int start, int relEnd, int x, int y, - IntRect* focusBounds, const IntRect& clip, WTF::Vector<IntRect>* result); - static bool ConstructTextRects(Text* node, int start, - Text* last, int end, int x, int y, IntRect* focusBounds, - const IntRect& clip, WTF::Vector<IntRect>* result); - static FoundState FindPartialAddress(const UChar* , const UChar* , unsigned length, FindState* ); - static FoundState FindPartialEMail(const UChar* , unsigned length, FindState* ); - static FoundState FindPartialNumber(const UChar* , unsigned length, FindState* ); - static FoundState FindPhoneNumber(const UChar* chars, unsigned length, int* start, int* end); - static void FindReset(FindState* ); - static void FindResetNumber(FindState* ); - static Frame* FrameAnd(CacheBuilder* focusNav); - static Frame* FrameAnd(const CacheBuilder* focusNav); - static CacheBuilder* Builder(Frame* ); - static Frame* HasFrame(Node* ); - static bool HasOverOrOut(Node* ); - static bool HasTriggerEvent(Node* ); - static bool IsDomainChar(UChar ch); - bool isFocusableText(NodeWalk* , bool oldMore, Node* , CachedNodeType* type, - String* exported) const; //returns true if it is focusable - static bool IsMailboxChar(UChar ch); - static bool IsRealNode(Frame* , Node* ); - int overlap(int left, int right); // returns distance scale factor as 16.16 scalar - bool setData(CachedFrame* ); -#if USE(ACCELERATED_COMPOSITING) - void TrackLayer(WTF::Vector<LayerTracker>& layerTracker, - RenderObject* nodeRenderer, Node* lastChild, int offsetX, int offsetY); -#endif - Node* tryFocus(Direction direction); - Node* trySegment(Direction direction, int mainStart, int mainEnd); - CachedNodeBits mAllowableTypes; - bool mPictureSetDisabled; -#if DUMP_NAV_CACHE -public: - class Debug { -public: - void frameName(char*& namePtr, const char* max) const; - void init(char* buffer, size_t size); - static int ParentIndex(Node* node, int count, Node* parent); - void print() { frames(); } - void print(const char* name); - void wideString(const String& str); -private: - void attr(const AtomicString& name, const AtomicString& value); - void comma(const char* str); - void flush(); - Frame* frameAnd() const; - void frames(); - void groups(); - bool isFocusable(Node* node); - void localName(Node* node); - void newLine(int indent = 0); - void print(const char* name, unsigned len); - void setIndent(int ); - void uChar(const UChar* name, unsigned len, bool hex); - void validateFrame(); - void validateStringData(); - void wideString(const UChar* chars, int length, bool hex); - char* mBuffer; - size_t mBufferSize; - int mIndex; - const char* mPrefix; - int mMinPrefix; - } mDebug; -#endif -}; - -} - -#endif diff --git a/Source/WebKit/android/nav/CachedColor.cpp b/Source/WebKit/android/nav/CachedColor.cpp deleted file mode 100644 index c610022..0000000 --- a/Source/WebKit/android/nav/CachedColor.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2010, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "CachedPrefix.h" -#include "CachedColor.h" - -namespace android { - -#if DUMP_NAV_CACHE - -#define DEBUG_PRINT_COLOR(field) \ - DUMP_NAV_LOGD("// SkColor " #field "=0x%08x;\n", b->field) - -CachedColor* CachedColor::Debug::base() const { - CachedColor* nav = (CachedColor*) ((char*) this - OFFSETOF(CachedColor, mDebug)); - return nav; -} - -void CachedColor::Debug::print() const -{ - CachedColor* b = base(); - DEBUG_PRINT_COLOR(mFillColor); - DUMP_NAV_LOGD("// int mInnerWidth=%d;\n", b->mInnerWidth); - DUMP_NAV_LOGD("// int mOuterWidth=%d;\n", b->mOuterWidth); - DUMP_NAV_LOGD("// int mOutset=%d;\n", b->mOutset); - DEBUG_PRINT_COLOR(mPressedInnerColor); - DEBUG_PRINT_COLOR(mPressedOuterColor); - DUMP_NAV_LOGD("// int mRadius=%d;\n", b->mRadius); - DEBUG_PRINT_COLOR(mSelectedInnerColor); - DEBUG_PRINT_COLOR(mSelectedOuterColor); -} - -#endif - -} - diff --git a/Source/WebKit/android/nav/CachedColor.h b/Source/WebKit/android/nav/CachedColor.h deleted file mode 100644 index 2ba9b18..0000000 --- a/Source/WebKit/android/nav/CachedColor.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2010, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef CachedColor_h -#define CachedColor_h - -#include "CachedDebug.h" -#include "Color.h" -#include "Length.h" -#include "SkColor.h" - -using namespace WebCore; - -namespace android { - -class CachedColor { -public: - CachedColor() { - // Initiaized to 0 in its array, so nothing to do in the - // constructor - } - bool operator==(const CachedColor& o) const { - return memcmp(&o, this, sizeof(this)) == 0; } - SkColor fillColor() const { return mFillColor; } - void init(); - int innerWidth() const { return mInnerWidth; } - int outerWidth() const { return mOuterWidth; } - int outset() const { return mOutset; } - SkColor pressedInnerColor() const { return mPressedInnerColor; } - SkColor pressedOuterColor() const { return mPressedOuterColor; } - int radius() const { return mRadius; } - SkColor selectedInnerColor() const { return mSelectedInnerColor; } - SkColor selectedOuterColor() const { return mSelectedOuterColor; } - void setFillColor(const Color& c) { mFillColor = c.rgb(); } - void setInnerWidth(Length l) { mInnerWidth = l.value(); } - void setOuterWidth(Length l) { mOuterWidth = l.value(); } - void setOutset(Length l) { mOutset = l.value(); } - void setPressedInnerColor(const Color& c) { mPressedInnerColor = c.rgb(); } - void setPressedOuterColor(const Color& c) { mPressedOuterColor = c.rgb(); } - void setRadius(Length l) { mRadius = l.value(); } - void setSelectedInnerColor(const Color& c) { mSelectedInnerColor = c.rgb(); } - void setSelectedOuterColor(const Color& c) { mSelectedOuterColor = c.rgb(); } -private: - SkColor mFillColor; - int mInnerWidth; - int mOuterWidth; - int mOutset; - SkColor mPressedInnerColor; - SkColor mPressedOuterColor; - int mRadius; - SkColor mSelectedInnerColor; - SkColor mSelectedOuterColor; -#if DUMP_NAV_CACHE -public: - class Debug { -public: - CachedColor* base() const; - void print() const; - } mDebug; -#endif -}; - -} - -#endif diff --git a/Source/WebKit/android/nav/CachedDebug.h b/Source/WebKit/android/nav/CachedDebug.h deleted file mode 100644 index f77c07a..0000000 --- a/Source/WebKit/android/nav/CachedDebug.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2007, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef CachedDebug_h -#define CachedDebug_h - -#define DUMP_NAV_CACHE 0 -#define DEBUG_NAV_UI 0 -#define DEBUG_NAV_UI_VERBOSE 0 - -#if DEBUG_NAV_UI -#define DBG_NAV_LOG(message) LOGD("%s %s", __FUNCTION__, message) -#define DBG_NAV_LOGD(format, ...) LOGD("%s " format, __FUNCTION__, __VA_ARGS__) -#define DEBUG_NAV_UI_LOGD(...) LOGD(__VA_ARGS__) -#else -#define DBG_NAV_LOG(message) ((void)0) -#define DBG_NAV_LOGD(format, ...) ((void)0) -#define DEBUG_NAV_UI_LOGD(...) ((void)0) -#endif - -#if DEBUG_NAV_UI_VERBOSE -#define DBG_NAV_LOGV(format, ...) LOGD("%s " format, __FUNCTION__, __VA_ARGS__) -#else -#define DBG_NAV_LOGV(format, ...) ((void)0) -#endif - -#if DUMP_NAV_CACHE != 0 && !defined DUMP_NAV_CACHE_USING_PRINTF && defined NDEBUG -#define DUMP_NAV_CACHE_USING_PRINTF -#endif - -#if DUMP_NAV_CACHE -#ifdef DUMP_NAV_CACHE_USING_PRINTF -#include <stdio.h> -extern FILE* gNavCacheLogFile; -#define NAV_CACHE_LOG_FILE "/data/data/com.android.browser/navlog" -#define DUMP_NAV_LOGD(...) do { if (gNavCacheLogFile) \ - fprintf(gNavCacheLogFile, __VA_ARGS__); else LOGD(__VA_ARGS__); } while (false) -#define DUMP_NAV_LOGX(format, ...) do { if (gNavCacheLogFile) \ - fprintf(gNavCacheLogFile, format, __VA_ARGS__); \ - else LOGD("%s " format, __FUNCTION__, __VA_ARGS__); } while (false) -#else -#define DUMP_NAV_LOGD(...) LOGD(__VA_ARGS__) -#define DUMP_NAV_LOGX(format, ...) LOGD("%s " format, __FUNCTION__, __VA_ARGS__) -#endif -#else -#define DUMP_NAV_LOGD(...) ((void)0) -#define DUMP_NAV_LOGX(...) ((void)0) -#endif - -#endif diff --git a/Source/WebKit/android/nav/CachedFrame.cpp b/Source/WebKit/android/nav/CachedFrame.cpp deleted file mode 100644 index c51944e..0000000 --- a/Source/WebKit/android/nav/CachedFrame.cpp +++ /dev/null @@ -1,1511 +0,0 @@ -/* - * Copyright 2007, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "CachedPrefix.h" -#include "CachedHistory.h" -#include "CachedNode.h" -#include "CachedRoot.h" -#include "LayerAndroid.h" - -#include "CachedFrame.h" - -#define OFFSETOF(type, field) ((char*)&(((type*)1)->field) - (char*)1) // avoids gnu warning - -#define MIN_OVERLAP 3 // if rects overlap by 2 pixels or fewer, treat them as non-intersecting - -namespace android { - -WebCore::IntRect CachedFrame::adjustBounds(const CachedNode* node, - const WebCore::IntRect& rect) const -{ - DBG_NAV_LOGV("node=%p [%d] rect=(%d,%d,w=%d,h=%d) view=(%d,%d,w=%d,h=%d)" - " local=(%d,%d,w=%d,h=%d) root=(%d,%d,w=%d,h=%d)", - node, node->index(), rect.x(), rect.y(), rect.width(), rect.height(), - mViewBounds.x(), mViewBounds.y(), - mViewBounds.width(), mViewBounds.height(), - mLocalViewBounds.x(), mLocalViewBounds.y(), - mLocalViewBounds.width(), mLocalViewBounds.height(), - mRoot->mViewBounds.x(), mRoot->mViewBounds.y(), - mRoot->mViewBounds.width(), mRoot->mViewBounds.height()); -#if USE(ACCELERATED_COMPOSITING) - if (!mRoot) - return rect; - - const CachedLayer* cachedLayer = layer(node); - if (!cachedLayer) - return rect; - - const WebCore::LayerAndroid* rootLayer = mRoot->rootLayer(); - const LayerAndroid* aLayer = cachedLayer->layer(rootLayer); - if (aLayer) - return cachedLayer->adjustBounds(rootLayer, rect); -#endif - return rect; -} - -bool CachedFrame::CheckBetween(Direction direction, const WebCore::IntRect& bestRect, - const WebCore::IntRect& prior, WebCore::IntRect* result) -{ - int left, top, width, height; - if (direction & UP_DOWN) { - top = direction == UP ? bestRect.maxY() : prior.maxY(); - int bottom = direction == UP ? prior.y() : bestRect.y(); - height = bottom - top; - if (height < 0) - return false; - left = prior.x(); - int testLeft = bestRect.x(); - if (left > testLeft) - left = testLeft; - int right = prior.maxX(); - int testRight = bestRect.maxX(); - if (right < testRight) - right = testRight; - width = right - left; - } else { - left = direction == LEFT ? bestRect.maxX() : prior.maxX(); - int right = direction == LEFT ? prior.x() : bestRect.x(); - width = right - left; - if (width < 0) - return false; - top = prior.y(); - int testTop = bestRect.y(); - if (top > testTop) - top = testTop; - int bottom = prior.maxY(); - int testBottom = bestRect.maxY(); - if (bottom < testBottom) - bottom = testBottom; - height = bottom - top; - } - *result = WebCore::IntRect(left, top, width, height); - return true; -} - -bool CachedFrame::checkBetween(BestData* best, Direction direction) -{ - const WebCore::IntRect& bestRect = best->bounds(); - BestData test; - test.mDistance = INT_MAX; - test.mNode = NULL; - int index = direction; - int limit = index + DIRECTION_COUNT; - do { - WebCore::IntRect edges; - Direction check = (Direction) (index & DIRECTION_MASK); - if (CheckBetween(check, bestRect, - history()->priorBounds(), &edges) == false) - continue; - WebCore::IntRect clip = mRoot->scrolledBounds(); - clip.intersect(edges); - if (clip.isEmpty()) - continue; - findClosest(&test, direction, check, &clip); - if (test.mNode == NULL) - continue; - if (direction == check) - break; - } while (++index < limit); - if (test.mNode == NULL) - return false; - *best = test; - return true; -} - -bool CachedFrame::checkRings(const CachedNode* node, - const WebCore::IntRect& testBounds) const -{ - return mRoot->checkRings(picture(node), node, testBounds); -} - -bool CachedFrame::checkVisited(const CachedNode* node, Direction direction) const -{ - return history()->checkVisited(node, direction); -} - -void CachedFrame::clearCursor() -{ - DBG_NAV_LOGD("mCursorIndex=%d", mCursorIndex); - if (mCursorIndex < CURSOR_SET) - return; - CachedNode& cursor = mCachedNodes[mCursorIndex]; - cursor.clearCursor(this); - mCursorIndex = CURSOR_CLEARED; // initialized and explicitly cleared -} - -// returns 0 if test is preferable to best, 1 if not preferable, or -1 if unknown -int CachedFrame::compare(BestData& testData, const BestData& bestData) const -{ - if (testData.mNode->tabIndex() != bestData.mNode->tabIndex()) { - if (testData.mNode->tabIndex() < bestData.mNode->tabIndex() - || (mRoot->mCursor && mRoot->mCursor->tabIndex() < bestData.mNode->tabIndex())) { - testData.mNode->setCondition(CachedNode::HIGHER_TAB_INDEX); - return REJECT_TEST; - } - return TEST_IS_BEST; - } - // if the test minor axis line intersects the line segment between cursor - // center and best center, choose it - // give more weight to exact major axis alignment (rows, columns) - if (testData.mInNav != bestData.mInNav) { - if (bestData.mInNav) { - testData.mNode->setCondition(CachedNode::IN_CURSOR); - return REJECT_TEST; - } - return TEST_IS_BEST; - } - if (testData.mInNav) { - if (bestData.mMajorDelta < testData.mMajorDelta) { - testData.mNode->setCondition(CachedNode::CLOSER_IN_CURSOR); - return REJECT_TEST; - } - if (testData.mMajorDelta < bestData.mMajorDelta) - return TEST_IS_BEST; - } - if (testData.mMajorDelta < 0 && bestData.mMajorDelta >= 0) { - testData.mNode->setCondition(CachedNode::FURTHER); - return REJECT_TEST; - } - if ((testData.mMajorDelta ^ bestData.mMajorDelta) < 0) // one above, one below (or one left, one right) - return TEST_IS_BEST; - bool bestInWorking = bestData.inOrSubsumesWorking(); - bool testInWorking = testData.inOrSubsumesWorking(); - if (bestInWorking && testData.mWorkingOutside && testData.mNavOutside) { - testData.mNode->setCondition(CachedNode::IN_WORKING); - return REJECT_TEST; - } - if (testInWorking && bestData.mWorkingOutside && bestData.mNavOutside) - return TEST_IS_BEST; - bool bestInNav = directionChange() && bestData.inOrSubsumesNav(); - bool testInNav = directionChange() && testData.inOrSubsumesNav(); - if (bestInWorking == false && testInWorking == false) { - if (bestInNav && testData.mNavOutside) { - testData.mNode->setCondition(CachedNode::IN_UMBRA); - return REJECT_TEST; - } - if (testInNav && bestData.mNavOutside) - return TEST_IS_BEST; - } -#if 01 // hopefully butt test will remove need for this - if (testData.mCursorChild != bestData.mCursorChild) { - if (bestData.mCursorChild) { - testData.mNode->setCondition(CachedNode::IN_CURSOR_CHILDREN); - return REJECT_TEST; - } - return TEST_IS_BEST; - } -#endif - bool bestTestIn = (bestInWorking || bestInNav) && (testInWorking || testInNav); - bool testOverlap = bestTestIn || (testData.mWorkingOverlap != 0 && bestData.mWorkingOverlap == 0); - bool bestOverlap = bestTestIn || (testData.mWorkingOverlap == 0 && bestData.mWorkingOverlap != 0); -#if 01 // this isn't working? - if (testOverlap == bestOverlap) { - if (bestData.mMajorButt < 10 && testData.mMajorButt >= 40) { - testData.mNode->setCondition(CachedNode::BUTTED_UP); - return REJECT_TEST; - } - if (testData.mMajorButt < 10 && bestData.mMajorButt >= 40) - return TEST_IS_BEST; - } -#endif - if (bestOverlap && bestData.mMajorDelta < testData.mMajorDelta) { // choose closest major axis center - testData.mNode->setCondition(CachedNode::CLOSER); - return REJECT_TEST; - } - if (testOverlap && testData.mMajorDelta < bestData.mMajorDelta) - return TEST_IS_BEST; - if (bestOverlap && bestData.mMajorDelta2 < testData.mMajorDelta2) { - testData.mNode->setCondition(CachedNode::CLOSER_TOP); - return REJECT_TEST; - } - if (testOverlap && testData.mMajorDelta2 < bestData.mMajorDelta2) - return TEST_IS_BEST; -#if 01 - if (bestOverlap && ((bestData.mSideDistance <= 0 && testData.mSideDistance > 0) || - abs(bestData.mSideDistance) < abs(testData.mSideDistance))) { - testData.mNode->setCondition(CachedNode::LEFTMOST); - return REJECT_TEST; - } - if (testOverlap && ((testData.mSideDistance <= 0 && bestData.mSideDistance > 0) || - abs(testData.mSideDistance) < abs(bestData.mSideDistance))) - return TEST_IS_BEST; -// fix me : the following ASSERT fires -- not sure if this case should be handled or not -// ASSERT(bestOverlap == false && testOverlap == false); -#endif - SkFixed testMultiplier = testData.mWorkingOverlap > testData.mNavOverlap ? - testData.mWorkingOverlap : testData.mNavOverlap; - SkFixed bestMultiplier = bestData.mWorkingOverlap > bestData.mNavOverlap ? - bestData.mWorkingOverlap : bestData.mNavOverlap; - int testDistance = testData.mDistance; - int bestDistance = bestData.mDistance; -// start here; - // this fails if they're off by 1 - // try once again to implement sliding scale so that off by 1 is nearly like zero, - // and off by a lot causes sideDistance to have little or no effect - // try elliptical distance -- lengthen side contribution - // these ASSERTs should not fire, but do fire on mail.google.com - // can't debug yet, won't reproduce - ASSERT(testDistance >= 0); - ASSERT(bestDistance >= 0); - testDistance += testDistance; // multiply by 2 - testDistance *= testDistance; - bestDistance += bestDistance; // multiply by 2 - bestDistance *= bestDistance; - int side = testData.mSideDistance; - int negative = side < 0 && bestData.mSideDistance > 0; - side *= side; - if (negative) - side = -side; - testDistance += side; - side = bestData.mSideDistance; - negative = side < 0 && testData.mSideDistance > 0; - side *= side; - if (negative) - side = -side; - bestDistance += side; - if (testMultiplier > (SK_Fixed1 >> 1) || bestMultiplier > (SK_Fixed1 >> 1)) { // considerable working overlap? - testDistance = SkFixedMul(testDistance, bestMultiplier); - bestDistance = SkFixedMul(bestDistance, testMultiplier); - } - if (bestDistance < testDistance) { - testData.mNode->setCondition(CachedNode::CLOSER_OVERLAP); - return REJECT_TEST; - } - if (testDistance < bestDistance) - return TEST_IS_BEST; -#if 0 - int distance = testData.mDistance + testData.mSideDistance; - int best = bestData.mDistance + bestData.mSideDistance; - if (distance > best) { - testData.mNode->setCondition(CachedNode::CLOSER_RAW_DISTANCE); - return REJECT_TEST; - } - else if (distance < best) - return TEST_IS_BEST; - best = bestData.mSideDistance; - if (testData.mSideDistance > best) { - testData.mNode->setCondition(CachedNode::SIDE_DISTANCE); - return REJECT_TEST; - } - if (testData.mSideDistance < best) - return TEST_IS_BEST; -#endif - if (testData.mPreferred < bestData.mPreferred) { - testData.mNode->setCondition(CachedNode::PREFERRED); - return REJECT_TEST; - } - if (testData.mPreferred > bestData.mPreferred) - return TEST_IS_BEST; - return UNDECIDED; -} - -const CachedNode* CachedFrame::currentCursor(const CachedFrame** framePtr) const -{ - if (framePtr) - *framePtr = this; - if (mCursorIndex < CURSOR_SET) - return NULL; - const CachedNode* result = &mCachedNodes[mCursorIndex]; - const CachedFrame* frame = hasFrame(result); - if (frame != NULL) - return frame->currentCursor(framePtr); - (const_cast<CachedNode*>(result))->fixUpCursorRects(this); - return result; -} - -const CachedNode* CachedFrame::currentFocus(const CachedFrame** framePtr) const -{ - if (framePtr) - *framePtr = this; - if (mFocusIndex < 0) - return NULL; - const CachedNode* result = &mCachedNodes[mFocusIndex]; - const CachedFrame* frame = hasFrame(result); - if (frame != NULL) - return frame->currentFocus(framePtr); - return result; -} - -bool CachedFrame::directionChange() const -{ - return history()->directionChange(); -} - -#ifdef BROWSER_DEBUG -CachedNode* CachedFrame::find(WebCore::Node* node) // !!! probably debugging only -{ - for (CachedNode* test = mCachedNodes.begin(); test != mCachedNodes.end(); test++) - if (node == test->webCoreNode()) - return test; - for (CachedFrame* frame = mCachedFrames.begin(); frame != mCachedFrames.end(); - frame++) { - CachedNode* result = frame->find(node); - if (result != NULL) - return result; - } - return NULL; -} -#endif - -const CachedNode* CachedFrame::findBestAt(const WebCore::IntRect& rect, - int* best, bool* inside, const CachedNode** directHit, - const CachedFrame** directHitFramePtr, - const CachedFrame** framePtr, int* x, int* y, - bool checkForHiddenStart) const -{ - const CachedNode* result = NULL; - int rectWidth = rect.width(); - WebCore::IntPoint center = WebCore::IntPoint(rect.x() + (rectWidth >> 1), - rect.y() + (rect.height() >> 1)); - mRoot->setupScrolledBounds(); - for (const CachedNode* test = mCachedNodes.begin(); test != mCachedNodes.end(); test++) { - if (test->disabled()) - continue; - size_t parts = test->navableRects(); - BestData testData; - testData.mNode = test; - testData.mFrame = this; - WebCore::IntRect bounds = test->bounds(this); - testData.setMouseBounds(bounds); - testData.setNodeBounds(bounds); - bool checkForHidden = checkForHiddenStart; - for (size_t part = 0; part < parts; part++) { - WebCore::IntRect testRect = test->ring(this, part); - if (testRect.intersects(rect)) { -#if DEBUG_NAV_UI - if (test->isInLayer()) { - DBG_NAV_LOGD("[%d] intersects=%s testRect=(%d,%d,w=%d,h=%d)" - " rect=(%d,%d,w=%d,h=%d)", test->index(), - testRect.intersects(rect) ? "true" : "false", - testRect.x(), testRect.y(), - testRect.width(), testRect.height(), - rect.x(), rect.y(), rect.width(), rect.height()); - } -#endif - if (checkForHidden && mRoot->maskIfHidden(&testData) == true) { - DBG_NAV_LOGD("hidden [%d]", test->index()); - break; - } - checkForHidden = false; - testRect.intersect(testData.mouseBounds()); - if (testRect.contains(center)) { - // We have a direct hit. - if (*directHit == NULL) { - DBG_NAV_LOGD("direct hit 1 [%d]", test->index()); - *directHit = test; - *directHitFramePtr = this; - IntRect r(center, IntSize(0, 0)); - *x = r.x(); - *y = r.y(); - } else { - DBG_NAV_LOGD("direct hit 2 [%d]", test->index()); - // We have hit another one before - const CachedNode* d = *directHit; - if (d->bounds(this).contains(testRect)) { - // This rectangle is inside the other one, so it is - // the best one. - *directHit = test; - *directHitFramePtr = this; - } - } - } - if (NULL != *directHit) { - // If we have a direct hit already, there is no need to - // calculate the distances, or check the other parts - break; - } - DBG_NAV_LOGD("indirect hit [%d]", test->index()); - WebCore::IntRect both = rect; - int smaller = testRect.width() < testRect.height() ? - testRect.width() : testRect.height(); - smaller -= rectWidth; - int inset = smaller < rectWidth ? smaller : rectWidth; - inset >>= 1; // inflate doubles the width decrease - if (inset > 1) - both.inflate(1 - inset); - both.intersect(testRect); - if (both.isEmpty()) - continue; - bool testInside = testRect.contains(center); - if (*inside && !testInside) - continue; - WebCore::IntPoint testCenter = WebCore::IntPoint(testRect.x() + - (testRect.width() >> 1), testRect.y() + (testRect.height() >> 1)); - int dx = testCenter.x() - center.x(); - int dy = testCenter.y() - center.y(); - int distance = dx * dx + dy * dy; - if ((!*inside && testInside) || *best >= distance) { - *best = distance; - *inside = testInside; - result = test; - *framePtr = this; - *x = both.x() + (both.width() >> 1); - *y = both.y() + (both.height() >> 1); - } - } - } - } - for (const CachedFrame* frame = mCachedFrames.begin(); - frame != mCachedFrames.end(); frame++) { - const CachedNode* frameResult = frame->findBestAt(rect, best, inside, - directHit, directHitFramePtr, framePtr, x, y, checkForHiddenStart); - if (NULL != frameResult) - result = frameResult; - } - if (NULL != *directHit) { - result = *directHit; - *framePtr = *directHitFramePtr; - } - return result; -} - -const CachedFrame* CachedFrame::findBestFrameAt(int x, int y) const -{ - if (mLocalViewBounds.contains(x, y) == false) - return NULL; - const CachedFrame* result = this; - for (const CachedFrame* frame = mCachedFrames.begin(); - frame != mCachedFrames.end(); frame++) { - const CachedFrame* frameResult = frame->findBestFrameAt(x, y); - if (NULL != frameResult) - result = frameResult; - } - return result; -} - -const CachedNode* CachedFrame::findBestHitAt(const WebCore::IntRect& rect, - const CachedFrame** framePtr, int* x, int* y) const -{ - mRoot->setupScrolledBounds(); - for (const CachedFrame* frame = mCachedFrames.end() - 1; - frame != mCachedFrames.begin() - 1; frame--) { - const CachedNode* frameResult = frame->findBestHitAt(rect, - framePtr, x, y); - if (NULL != frameResult) - return frameResult; - } - for (const CachedNode* test = mCachedNodes.end() - 1; - test != mCachedNodes.begin() - 1; test--) { - if (test->disabled()) - continue; - WebCore::IntRect testRect = test->hitBounds(this); - if (testRect.intersects(rect) == false) - continue; - BestData testData; - testData.mNode = test; - testData.mFrame = this; - testData.setMouseBounds(testRect); - testData.setNodeBounds(testRect); - if (mRoot->maskIfHidden(&testData) == true) - continue; - DBG_NAV_LOGD("candidate %d rect=(%d,%d,r=%d,b=%d)" - " testRect=(%d,%d,r=%d,b=%d)", - test->index(), rect.x(), rect.y(), rect.maxX(), rect.maxY(), - testRect.x(), testRect.y(), testRect.maxX(), testRect.maxY()); - for (int i = 0; i < test->navableRects(); i++) { - WebCore::IntRect cursorRect = test->ring(this, i); - DBG_NAV_LOGD("candidate %d cursorRect=(%d,%d,r=%d,b=%d)", - i, cursorRect.x(), cursorRect.y(), cursorRect.maxX(), - cursorRect.maxY()); - if (cursorRect.intersects(rect)) { - WebCore::IntRect intersection(cursorRect); - intersection.intersect(rect); - *x = intersection.x() + (intersection.width() >> 1); - *y = intersection.y() + (intersection.height() >> 1); - *framePtr = this; - return test; - } - } - testRect.intersect(rect); - *x = testRect.x() + (testRect.width() >> 1); - *y = testRect.y() + (testRect.height() >> 1); - *framePtr = this; - return test; - } - return NULL; -} - -void CachedFrame::findClosest(BestData* bestData, Direction originalDirection, - Direction direction, WebCore::IntRect* clip) const -{ - const CachedNode* test = mCachedNodes.begin(); - while ((test = test->traverseNextNode()) != NULL) { - const CachedFrame* child = hasFrame(test); - if (child != NULL) { - const CachedNode* childDoc = child->validDocument(); - if (childDoc == NULL) - continue; - child->findClosest(bestData, originalDirection, direction, clip); - } - if (test->noSecondChance()) - continue; - if (test->isNavable(this, *clip) == false) - continue; - if (checkVisited(test, originalDirection) == false) - continue; - size_t partMax = test->navableRects(); - for (size_t part = 0; part < partMax; part++) { - WebCore::IntRect testBounds = test->ring(this, part); - if (clip->intersects(testBounds) == false) - continue; - if (clip->contains(testBounds) == false) { - if (direction & UP_DOWN) { -// if (testBounds.x() > clip->x() || testBounds.right() < clip->right()) -// continue; - testBounds.setX(clip->x()); - testBounds.setWidth(clip->width()); - } else { -// if (testBounds.y() > clip->y() || testBounds.bottom() < clip->bottom()) -// continue; - testBounds.setY(clip->y()); - testBounds.setHeight(clip->height()); - } - if (clip->contains(testBounds) == false) - continue; - } - int distance; - // seems like distance for UP for instance needs to be 'test top closest to - // clip bottom' -- keep the old code but try this instead - switch (direction) { -#if 0 - case LEFT: - distance = testBounds.x() - clip->x(); - break; - case RIGHT: - distance = clip->right() - testBounds.right(); - break; - case UP: - distance = testBounds.y() - clip->y(); - break; - case DOWN: - distance = clip->bottom() - testBounds.bottom(); - break; -#else - case LEFT: - distance = clip->maxX() - testBounds.x(); - break; - case RIGHT: - distance = testBounds.maxX() - clip->x(); - break; - case UP: - distance = clip->maxY() - testBounds.y(); - break; - case DOWN: - distance = testBounds.maxY() - clip->y(); - break; -#endif - default: - distance = 0; - ASSERT(false); - } - if (distance < bestData->mDistance) { - bestData->mNode = test; - bestData->mFrame = this; - bestData->mDistance = distance; - WebCore::IntRect rect = test->ring(this, part); - bestData->setMouseBounds(rect); - bestData->setNodeBounds(rect); - CachedHistory* cachedHistory = history(); - switch (direction) { - case LEFT: - bestData->setLeftDirection(cachedHistory); - break; - case RIGHT: - bestData->setRightDirection(cachedHistory); - break; - case UP: - bestData->setUpDirection(cachedHistory); - break; - case DOWN: - bestData->setDownDirection(cachedHistory); - break; - default: - ASSERT(0); - } - } - } - } -} - -void CachedFrame::finishInit() -{ - CachedNode* lastCached = lastNode(); - lastCached->setLast(); - CachedFrame* child = mCachedFrames.begin(); - while (child != mCachedFrames.end()) { - child->mParent = this; - child->finishInit(); - child++; - } - CachedFrame* frameParent; - if (mFocusIndex >= 0 && (frameParent = parent())) - frameParent->setFocusIndex(indexInParent()); -} - -const CachedNode* CachedFrame::frameDown(const CachedNode* test, - const CachedNode* limit, BestData* bestData) const -{ - BestData originalData = *bestData; - do { - if (moveInFrame(&CachedFrame::frameDown, test, bestData)) - continue; - BestData testData; - if (frameNodeCommon(testData, test, bestData, &originalData) == REJECT_TEST) - continue; - if (checkVisited(test, DOWN) == false) - continue; - size_t parts = test->navableRects(); - for (size_t part = 0; part < parts; part++) { - testData.setNodeBounds(test->ring(this, part)); - if (testData.setDownDirection(history())) - continue; - int result = framePartCommon(testData, test, bestData); - if (result == REJECT_TEST) - continue; - if (result == 0 && limit == NULL) { // retry all data up to this point, since smaller may have replaced node preferable to larger - BestData innerData = testData; - frameDown(document(), test, &innerData); - if (checkVisited(innerData.mNode, DOWN)) { - *bestData = innerData; - continue; - } - } - if (checkVisited(test, DOWN)) - *bestData = testData; - } - } while ((test = test->traverseNextNode()) != limit); - ASSERT(mRoot->mCursor == NULL || bestData->mNode != mRoot->mCursor); - // does the best contain something (or, is it contained by an area which is not the cursor?) - // if so, is the conainer/containee should have been chosen, but wasn't -- so there's a better choice - // in the doc list prior to this choice - // - return bestData->mNode; -} - -const CachedNode* CachedFrame::frameLeft(const CachedNode* test, - const CachedNode* limit, BestData* bestData) const -{ - BestData originalData = *bestData; - do { - if (moveInFrame(&CachedFrame::frameLeft, test, bestData)) - continue; - BestData testData; - if (frameNodeCommon(testData, test, bestData, &originalData) == REJECT_TEST) - continue; - if (checkVisited(test, LEFT) == false) - continue; - size_t parts = test->navableRects(); - for (size_t part = 0; part < parts; part++) { - testData.setNodeBounds(test->ring(this, part)); - if (testData.setLeftDirection(history())) - continue; - int result = framePartCommon(testData, test, bestData); - if (result == REJECT_TEST) - continue; - if (result == 0 && limit == NULL) { // retry all data up to this point, since smaller may have replaced node preferable to larger - BestData innerData = testData; - frameLeft(document(), test, &innerData); - if (checkVisited(innerData.mNode, LEFT)) { - *bestData = innerData; - continue; - } - } - if (checkVisited(test, LEFT)) - *bestData = testData; - } - } while ((test = test->traverseNextNode()) != limit); // FIXME ??? left and up should use traversePreviousNode to choose reverse document order - ASSERT(mRoot->mCursor == NULL || bestData->mNode != mRoot->mCursor); - return bestData->mNode; -} - -int CachedFrame::frameNodeCommon(BestData& testData, const CachedNode* test, - BestData* bestData, BestData* originalData) const -{ - testData.mFrame = this; - testData.mNode = test; - test->clearCondition(); - if (test->disabled()) { - testData.mNode->setCondition(CachedNode::DISABLED); - return REJECT_TEST; - } - WebCore::IntRect bounds = test->bounds(this); - if (bounds.isEmpty()) { - testData.mNode->setCondition(CachedNode::NAVABLE); - return REJECT_TEST; - } - if (mRoot->scrolledBounds().intersects(bounds) == false) { - testData.mNode->setCondition(CachedNode::NAVABLE); - return REJECT_TEST; - } - if (mRoot->rootLayer() && !test->isInLayer() - && !mRoot->baseUncovered().intersects(bounds)) { - testData.mNode->setCondition(CachedNode::UNDER_LAYER); - return REJECT_TEST; - } -// if (isNavable(test, &testData.mNodeBounds, walk) == false) { -// testData.mNode->setCondition(CachedNode::NAVABLE); -// return REJECT_TEST; -// } -// - if (test == mRoot->mCursor) { - testData.mNode->setCondition(CachedNode::NOT_CURSOR_NODE); - return REJECT_TEST; - } -// if (test->bounds().contains(mRoot->mCursorBounds)) { -// testData.mNode->setCondition(CachedNode::NOT_ENCLOSING_CURSOR); -// return REJECT_TEST; -// } - void* par = mRoot->mCursor ? mRoot->mCursor->parentGroup() : NULL; - testData.mCursorChild = par ? test->parentGroup() == par : false; - if (bestData->mNode == NULL) - return TEST_IS_BEST; - if (mRoot->mCursor && testData.mNode->parentIndex() != bestData->mNode->parentIndex()) { - int cursorParentIndex = mRoot->mCursor->parentIndex(); - if (cursorParentIndex >= 0) { - if (bestData->mNode->parentIndex() == cursorParentIndex) - return REJECT_TEST; - if (testData.mNode->parentIndex() == cursorParentIndex) - return TEST_IS_BEST; - } - } - if (testData.mNode->parent() == bestData->mNode) { - testData.mNode->setCondition(CachedNode::CHILD); - return REJECT_TEST; - } - if (testData.mNode == bestData->mNode->parent()) - return TEST_IS_BEST; - int testInBest = testData.isContainer(bestData); /* -1 pick best over test, 0 no containership, 1 pick test over best */ - if (testInBest == 1) { - if (test->isArea() || bestData->mNode->isArea()) - return UNDECIDED; - bestData->mNode = NULL; // force part tests to be ignored, yet still set up remaining test data for later comparisons - return TEST_IS_BEST; - } - if (testInBest == -1) { - testData.mNode->setCondition(CachedNode::OUTSIDE_OF_BEST); - return REJECT_TEST; - } - if (originalData->mNode != NULL) { // test is best case - testInBest = testData.isContainer(originalData); - if (testInBest == -1) { /* test is inside best */ - testData.mNode->setCondition(CachedNode::OUTSIDE_OF_ORIGINAL); - return REJECT_TEST; - } - } - return UNDECIDED; -} - -int CachedFrame::framePartCommon(BestData& testData, - const CachedNode* test, BestData* bestData) const -{ - if (mRoot->mCursor - && testData.bounds().contains(mRoot->mCursorBounds) - && !test->wantsKeyEvents()) { - testData.mNode->setCondition(CachedNode::NOT_ENCLOSING_CURSOR); - return REJECT_TEST; - } - testData.setDistances(); - if (bestData->mNode != NULL) { - int compared = compare(testData, *bestData); - if (compared == 0 && test->isArea() == false && bestData->mNode->isArea() == false) - goto pickTest; - if (compared >= 0) - return compared; - } -pickTest: - return -1; // pick test -} - -const CachedNode* CachedFrame::frameRight(const CachedNode* test, - const CachedNode* limit, BestData* bestData) const -{ - BestData originalData = *bestData; - do { - if (moveInFrame(&CachedFrame::frameRight, test, bestData)) - continue; - BestData testData; - if (frameNodeCommon(testData, test, bestData, &originalData) == REJECT_TEST) - continue; - if (checkVisited(test, RIGHT) == false) - continue; - size_t parts = test->navableRects(); - for (size_t part = 0; part < parts; part++) { - testData.setNodeBounds(test->ring(this, part)); - if (testData.setRightDirection(history())) - continue; - int result = framePartCommon(testData, test, bestData); - if (result == REJECT_TEST) - continue; - if (result == 0 && limit == NULL) { // retry all data up to this point, since smaller may have replaced node preferable to larger - BestData innerData = testData; - frameRight(document(), test, &innerData); - if (checkVisited(innerData.mNode, RIGHT)) { - *bestData = innerData; - continue; - } - } - if (checkVisited(test, RIGHT)) - *bestData = testData; - } - } while ((test = test->traverseNextNode()) != limit); - ASSERT(mRoot->mCursor == NULL || bestData->mNode != mRoot->mCursor); - return bestData->mNode; -} - -const CachedNode* CachedFrame::frameUp(const CachedNode* test, - const CachedNode* limit, BestData* bestData) const -{ - BestData originalData = *bestData; - do { - if (moveInFrame(&CachedFrame::frameUp, test, bestData)) - continue; - BestData testData; - if (frameNodeCommon(testData, test, bestData, &originalData) == REJECT_TEST) - continue; - if (checkVisited(test, UP) == false) - continue; - size_t parts = test->navableRects(); - for (size_t part = 0; part < parts; part++) { - testData.setNodeBounds(test->ring(this, part)); - if (testData.setUpDirection(history())) - continue; - int result = framePartCommon(testData, test, bestData); - if (result == REJECT_TEST) - continue; - if (result == 0 && limit == NULL) { // retry all data up to this point, since smaller may have replaced node preferable to larger - BestData innerData = testData; - frameUp(document(), test, &innerData); - if (checkVisited(innerData.mNode, UP)) { - *bestData = innerData; - continue; - } - } - if (checkVisited(test, UP)) - *bestData = testData; - } - } while ((test = test->traverseNextNode()) != limit); // FIXME ??? left and up should use traversePreviousNode to choose reverse document order - ASSERT(mRoot->mCursor == NULL || bestData->mNode != mRoot->mCursor); - return bestData->mNode; -} - -CachedFrame* CachedFrame::hasFrame(const CachedNode* node) -{ - return node->isFrame() ? &mCachedFrames[node->childFrameIndex()] : NULL; -} - -void CachedFrame::hideCursor() -{ - DBG_NAV_LOGD("mCursorIndex=%d", mCursorIndex); - if (mCursorIndex < CURSOR_SET) - return; - CachedNode& cursor = mCachedNodes[mCursorIndex]; - cursor.hideCursor(this); -} - -CachedHistory* CachedFrame::history() const -{ - return mRoot->rootHistory(); -} - -void CachedFrame::init(const CachedRoot* root, int childFrameIndex, - WebCore::Frame* frame) -{ - mContents = WebCore::IntRect(0, 0, 0, 0); // fixed up for real in setData() - mLocalViewBounds = WebCore::IntRect(0, 0, 0, 0); - mViewBounds = WebCore::IntRect(0, 0, 0, 0); - mRoot = root; - mCursorIndex = CURSOR_UNINITIALIZED; // not explicitly cleared - mFocusIndex = -1; - mFrame = frame; - mParent = NULL; // set up parents after stretchy arrays are set up - mIndexInParent = childFrameIndex; -} - -#if USE(ACCELERATED_COMPOSITING) -const CachedLayer* CachedFrame::layer(const CachedNode* node) const -{ - if (!node->isInLayer()) - return 0; - CachedLayer test; - test.setCachedNodeIndex(node->index()); - return std::lower_bound(mCachedLayers.begin(), mCachedLayers.end(), test); -} -#endif - -WebCore::IntRect CachedFrame::localBounds(const CachedNode* node, - const WebCore::IntRect& rect) const -{ - DBG_NAV_LOGD("node=%p [%d] rect=(%d,%d,w=%d,h=%d)", - node, node->index(), rect.x(), rect.y(), rect.width(), rect.height()); -#if USE(ACCELERATED_COMPOSITING) - return layer(node)->localBounds(mRoot->rootLayer(), rect); -#else - return rect; -#endif -} - -int CachedFrame::minWorkingHorizontal() const -{ - return history()->minWorkingHorizontal(); -} - -int CachedFrame::minWorkingVertical() const -{ - return history()->minWorkingVertical(); -} - -int CachedFrame::maxWorkingHorizontal() const -{ - return history()->maxWorkingHorizontal(); -} - -int CachedFrame::maxWorkingVertical() const -{ - return history()->maxWorkingVertical(); -} - -const CachedNode* CachedFrame::nextTextField(const CachedNode* start, - const CachedFrame** framePtr, bool* startFound) const -{ - const CachedNode* test = mCachedNodes.begin(); - while ((test = test->traverseNextNode())) { - const CachedFrame* frame = hasFrame(test); - if (frame) { - if (!frame->validDocument()) - continue; - const CachedNode* node - = frame->nextTextField(start, framePtr, startFound); - if (node) - return node; - } else if (test->isTextInput()) { - if (test == start) - *startFound = true; - else if (*startFound) { - if (framePtr) - *framePtr = this; - return test; - } - } - } - return 0; -} - -bool CachedFrame::moveInFrame(MoveInDirection moveInDirection, - const CachedNode* test, BestData* bestData) const -{ - const CachedFrame* frame = hasFrame(test); - if (frame == NULL) - return false; // if it's not a frame, let the caller have another swing at it - const CachedNode* childDoc = frame->validDocument(); - if (childDoc == NULL) - return true; - (frame->*moveInDirection)(childDoc, NULL, bestData); - return true; -} - -const WebCore::IntRect& CachedFrame::_navBounds() const -{ - return history()->navBounds(); -} - -SkPicture* CachedFrame::picture(const CachedNode* node) const -{ -#if USE(ACCELERATED_COMPOSITING) - if (node->isInLayer()) - return layer(node)->picture(mRoot->rootLayer()); -#endif - return mRoot->mPicture; -} - -SkPicture* CachedFrame::picture(const CachedNode* node, int* xPtr, int* yPtr) const -{ -#if USE(ACCELERATED_COMPOSITING) - if (node->isInLayer()) { - const CachedLayer* cachedLayer = layer(node); - const LayerAndroid* rootLayer = mRoot->rootLayer(); - cachedLayer->toLocal(rootLayer, xPtr, yPtr); - return cachedLayer->picture(rootLayer); - } -#endif - return mRoot->mPicture; -} - -void CachedFrame::resetClippedOut() -{ - for (CachedNode* test = mCachedNodes.begin(); test != mCachedNodes.end(); test++) - { - if (test->clippedOut()) { - test->setDisabled(false); - test->setClippedOut(false); - } - } - for (CachedFrame* frame = mCachedFrames.begin(); frame != mCachedFrames.end(); - frame++) { - frame->resetClippedOut(); - } -} - -void CachedFrame::resetLayers() -{ -#if USE(ACCELERATED_COMPOSITING) - for (CachedFrame* frame = mCachedFrames.begin(); frame != mCachedFrames.end(); - frame++) { - frame->resetLayers(); - } -#endif -} - -bool CachedFrame::sameFrame(const CachedFrame* test) const -{ - ASSERT(test); - if (mIndexInParent != test->mIndexInParent) - return false; - if (mIndexInParent == -1) // index within parent's array of children, or -1 if root - return true; - return mParent->sameFrame(test->mParent); -} - -void CachedFrame::setData() -{ - if (this != mRoot) { - mViewBounds = mLocalViewBounds; - mViewBounds.intersect(mRoot->mViewBounds); - } - int x, y; - if (parent() == NULL) - x = y = 0; - else { - x = mLocalViewBounds.x(); - y = mLocalViewBounds.y(); - } - mContents.setX(x); - mContents.setY(y); - CachedFrame* child = mCachedFrames.begin(); - while (child != mCachedFrames.end()) { - child->setData(); - child++; - } -} - -bool CachedFrame::setCursor(WebCore::Frame* frame, WebCore::Node* node, - int x, int y) -{ - if (NULL == node) { - const_cast<CachedRoot*>(mRoot)->setCursor(NULL, NULL); - return true; - } - if (mFrame != frame) { - for (CachedFrame* testF = mCachedFrames.begin(); testF != mCachedFrames.end(); - testF++) { - if (testF->setCursor(frame, node, x, y)) - return true; - } - DBG_NAV_LOGD("no frame frame=%p node=%p", frame, node); - return false; - } - bool first = true; - CachedNode const * const end = mCachedNodes.end(); - do { - for (CachedNode* test = mCachedNodes.begin(); test != end; test++) { - if (test->nodePointer() != node && first) - continue; - size_t partMax = test->navableRects(); - for (size_t part = 0; part < partMax; part++) { - WebCore::IntRect testBounds = test->ring(this, part); - if (testBounds.contains(x, y) == false) - continue; - if (test->isCursor()) { - DBG_NAV_LOGD("already set? test=%d frame=%p node=%p x=%d y=%d", - test->index(), frame, node, x, y); - return false; - } - const_cast<CachedRoot*>(mRoot)->setCursor(this, test); - return true; - } - } - DBG_NAV_LOGD("moved? frame=%p node=%p x=%d y=%d", frame, node, x, y); - } while ((first ^= true) == false); -failed: - DBG_NAV_LOGD("no match frame=%p node=%p", frame, node); - return false; -} - -const CachedNode* CachedFrame::validDocument() const -{ - const CachedNode* doc = document(); - return doc != NULL && mViewBounds.isEmpty() == false ? doc : NULL; -} - -bool CachedFrame::BestData::canBeReachedByAnotherDirection() -{ - if (mMajorButt > -MIN_OVERLAP) - return false; - mMajorButt = -mMajorButt; - return mNavOutside; -} - -int CachedFrame::BestData::isContainer(CachedFrame::BestData* other) -{ - int _x = x(); - int otherRight = other->right(); - if (_x >= otherRight) - return 0; // does not intersect - int _y = y(); - int otherBottom = other->bottom(); - if (_y >= otherBottom) - return 0; // does not intersect - int _right = right(); - int otherX = other->x(); - if (otherX >= _right) - return 0; // does not intersect - int _bottom = bottom(); - int otherY = other->y(); - if (otherY >= _bottom) - return 0; // does not intersect - int intoX = otherX - _x; - int intoY = otherY - _y; - int intoRight = otherRight - _right; - int intoBottom = otherBottom - _bottom; - bool contains = intoX >= 0 && intoY >= 0 && intoRight <= 0 && intoBottom <= 0; - if (contains && mNode->partRectsContains(other->mNode)) { -// if (mIsArea == false && hasMouseOver()) -// other->mMouseOver = mNode; - return mNode->isArea() ? 1 : -1; - } - bool containedBy = intoX <= 0 && intoY <= 0 && intoRight >= 0 && intoBottom >= 0; - if (containedBy && other->mNode->partRectsContains(mNode)) { -// if (other->mIsArea == false && other->hasMouseOver()) -// mMouseOver = other->mNode; - return other->mNode->isArea() ? -1 : 1; - } - return 0; -} - -// distance scale factor factor as a 16.16 scalar -SkFixed CachedFrame::BestData::Overlap(int span, int left, int right) -{ - unsigned result; - if (left > 0 && left < span && right > span) - result = (unsigned) left; - else if (right > 0 && right < span && left > span) - result = (unsigned) right; - else if (left > 0 && right > 0) - return SK_Fixed1; - else - return 0; - result = (result << 16) / (unsigned) span; // linear proportion, always less than fixed 1 - return (SkFixed) result; -// !!! experiment with weight -- enable if overlaps are preferred too much -// or reverse weighting if overlaps are preferred to little -// return (SkFixed) (result * result >> 16); // but fall off with square -} - -void CachedFrame::BestData::setDistances() -{ - mDistance = abs(mMajorDelta); - int sideDistance = mWorkingDelta; - if (mWorkingOverlap < SK_Fixed1) { - if (mPreferred > 0) - sideDistance = mWorkingDelta2; - } else if (sideDistance >= 0 && mWorkingDelta2 >=- 0) - sideDistance = 0; - else { - ASSERT(sideDistance <= 0 && mWorkingDelta2 <= 0); - if (sideDistance < mWorkingDelta2) - sideDistance = mWorkingDelta2; - } - // if overlap, smaller abs mWorkingDelta is better, smaller abs majorDelta is better - // if not overlap, positive mWorkingDelta is better - mSideDistance = sideDistance; -} - -bool CachedFrame::BestData::setDownDirection(const CachedHistory* history) -{ - const WebCore::IntRect& navBounds = history->navBounds(); - mMajorButt = mNodeBounds.y() - navBounds.maxY(); - int testX = mNodeBounds.x(); - int testRight = mNodeBounds.maxX(); - setNavOverlap(navBounds.width(), navBounds.maxX() - testX, - testRight - navBounds.x()); - if (canBeReachedByAnotherDirection()) { - mNode->setCondition(CachedNode::BEST_DIRECTION); - return REJECT_TEST; - } - int inNavTop = mNodeBounds.y() - navBounds.y(); - mMajorDelta2 = inNavTop; - mMajorDelta = mMajorDelta2 + ((mNodeBounds.height() - - navBounds.height()) >> 1); - if (mMajorDelta2 <= 1 && mMajorDelta <= 1) { - mNode->setCondition(CachedNode::CENTER_FURTHER); // never move up or sideways - return REJECT_TEST; - } - int inNavBottom = navBounds.maxY() - mNodeBounds.maxY(); - setNavInclusion(testRight - navBounds.maxX(), navBounds.x() - testX); - bool subsumes = navBounds.height() > 0 && inOrSubsumesNav(); - if (inNavTop <= 0 && inNavBottom <= 0 && subsumes && !mNode->wantsKeyEvents()) { - mNode->setCondition(CachedNode::NOT_ENCLOSING_CURSOR); - return REJECT_TEST; - } - int maxV = history->maxWorkingVertical(); - int minV = history->minWorkingVertical(); - setWorkingOverlap(testRight - testX, maxV - testX, testRight - minV); - setWorkingInclusion(testRight - maxV, minV - testX); - if (mWorkingOverlap == 0 && mNavOverlap == 0 && inNavBottom >= 0) { - mNode->setCondition(CachedNode::OVERLAP_OR_EDGE_FURTHER); - return REJECT_TEST; - } - mInNav = history->directionChange() && inNavTop >= 0 && - inNavBottom > 0 && subsumes; - return false; -} - -bool CachedFrame::BestData::setLeftDirection(const CachedHistory* history) -{ - const WebCore::IntRect& navBounds = history->navBounds(); - mMajorButt = navBounds.x() - mNodeBounds.maxX(); - int testY = mNodeBounds.y(); - int testBottom = mNodeBounds.maxY(); - setNavOverlap(navBounds.height(), navBounds.maxY() - testY, - testBottom - navBounds.y()); - if (canBeReachedByAnotherDirection()) { - mNode->setCondition(CachedNode::BEST_DIRECTION); - return REJECT_TEST; - } - int inNavRight = navBounds.maxX() - mNodeBounds.maxX(); - mMajorDelta2 = inNavRight; - mMajorDelta = mMajorDelta2 - ((navBounds.width() - - mNodeBounds.width()) >> 1); - if (mMajorDelta2 <= 1 && mMajorDelta <= 1) { - mNode->setCondition(CachedNode::CENTER_FURTHER); // never move right or sideways - return REJECT_TEST; - } - int inNavLeft = mNodeBounds.x() - navBounds.x(); - setNavInclusion(navBounds.y() - testY, testBottom - navBounds.maxY()); - bool subsumes = navBounds.width() > 0 && inOrSubsumesNav(); - if (inNavLeft <= 0 && inNavRight <= 0 && subsumes && !mNode->wantsKeyEvents()) { - mNode->setCondition(CachedNode::NOT_ENCLOSING_CURSOR); - return REJECT_TEST; - } - int maxH = history->maxWorkingHorizontal(); - int minH = history->minWorkingHorizontal(); - setWorkingOverlap(testBottom - testY, maxH - testY, testBottom - minH); - setWorkingInclusion(minH - testY, testBottom - maxH); - if (mWorkingOverlap == 0 && mNavOverlap == 0 && inNavLeft >= 0) { - mNode->setCondition(CachedNode::OVERLAP_OR_EDGE_FURTHER); - return REJECT_TEST; - } - mInNav = history->directionChange() && inNavLeft >= 0 && - inNavRight > 0 && subsumes; /* both L/R in or out */ - return false; -} - -bool CachedFrame::BestData::setRightDirection(const CachedHistory* history) -{ - const WebCore::IntRect& navBounds = history->navBounds(); - mMajorButt = mNodeBounds.x() - navBounds.maxX(); - int testY = mNodeBounds.y(); - int testBottom = mNodeBounds.maxY(); - setNavOverlap(navBounds.height(), navBounds.maxY() - testY, - testBottom - navBounds.y()); - if (canBeReachedByAnotherDirection()) { - mNode->setCondition(CachedNode::BEST_DIRECTION); - return REJECT_TEST; - } - int inNavLeft = mNodeBounds.x() - navBounds.x(); - mMajorDelta2 = inNavLeft; - mMajorDelta = mMajorDelta2 + ((mNodeBounds.width() - - navBounds.width()) >> 1); - if (mMajorDelta2 <= 1 && mMajorDelta <= 1) { - mNode->setCondition(CachedNode::CENTER_FURTHER); // never move left or sideways - return REJECT_TEST; - } - int inNavRight = navBounds.maxX() - mNodeBounds.maxX(); - setNavInclusion(testBottom - navBounds.maxY(), navBounds.y() - testY); - bool subsumes = navBounds.width() > 0 && inOrSubsumesNav(); - if (inNavLeft <= 0 && inNavRight <= 0 && subsumes && !mNode->wantsKeyEvents()) { - mNode->setCondition(CachedNode::NOT_ENCLOSING_CURSOR); - return REJECT_TEST; - } - int maxH = history->maxWorkingHorizontal(); - int minH = history->minWorkingHorizontal(); - setWorkingOverlap(testBottom - testY, testBottom - minH, maxH - testY); - setWorkingInclusion(testBottom - maxH, minH - testY); - if (mWorkingOverlap == 0 && mNavOverlap == 0 && inNavRight >= 0) { - mNode->setCondition(CachedNode::OVERLAP_OR_EDGE_FURTHER); - return REJECT_TEST; - } - mInNav = history->directionChange() && inNavLeft >= 0 && - inNavRight > 0 && subsumes; /* both L/R in or out */ - return false; -} - -bool CachedFrame::BestData::setUpDirection(const CachedHistory* history) -{ - const WebCore::IntRect& navBounds = history->navBounds(); - mMajorButt = navBounds.y() - mNodeBounds.maxY(); - int testX = mNodeBounds.x(); - int testRight = mNodeBounds.maxX(); - setNavOverlap(navBounds.width(), navBounds.maxX() - testX, - testRight - navBounds.x()); - if (canBeReachedByAnotherDirection()) { - mNode->setCondition(CachedNode::BEST_DIRECTION); - return REJECT_TEST; - } - int inNavBottom = navBounds.maxY() - mNodeBounds.maxY(); - mMajorDelta2 = inNavBottom; - mMajorDelta = mMajorDelta2 - ((navBounds.height() - - mNodeBounds.height()) >> 1); - if (mMajorDelta2 <= 1 && mMajorDelta <= 1) { - mNode->setCondition(CachedNode::CENTER_FURTHER); // never move down or sideways - return REJECT_TEST; - } - int inNavTop = mNodeBounds.y() - navBounds.y(); - setNavInclusion(navBounds.x() - testX, testRight - navBounds.maxX()); - bool subsumes = navBounds.height() > 0 && inOrSubsumesNav(); - if (inNavTop <= 0 && inNavBottom <= 0 && subsumes && !mNode->wantsKeyEvents()) { - mNode->setCondition(CachedNode::NOT_ENCLOSING_CURSOR); - return REJECT_TEST; - } - int maxV = history->maxWorkingVertical(); - int minV = history->minWorkingVertical(); - setWorkingOverlap(testRight - testX, testRight - minV, maxV - testX); - setWorkingInclusion(minV - testX, testRight - maxV); - if (mWorkingOverlap == 0 && mNavOverlap == 0 && inNavTop >= 0) { - mNode->setCondition(CachedNode::OVERLAP_OR_EDGE_FURTHER); - return REJECT_TEST; - } - mInNav = history->directionChange() && inNavTop >= 0 && - inNavBottom > 0 && subsumes; /* both L/R in or out */ - return false; -} - -void CachedFrame::BestData::setNavInclusion(int left, int right) -{ - // if left and right <= 0, test node is completely in umbra of cursor - // prefer leftmost center - // if left and right > 0, test node subsumes cursor - mNavDelta = left; - mNavDelta2 = right; -} - -void CachedFrame::BestData::setNavOverlap(int span, int left, int right) -{ - // if left or right < 0, test node is not in umbra of cursor - mNavOutside = left < MIN_OVERLAP || right < MIN_OVERLAP; - mNavOverlap = Overlap(span, left, right); // prefer smallest negative left -} - -void CachedFrame::BestData::setWorkingInclusion(int left, int right) -{ - mWorkingDelta = left; - mWorkingDelta2 = right; -} - -// distance scale factor factor as a 16.16 scalar -void CachedFrame::BestData::setWorkingOverlap(int span, int left, int right) -{ - // if left or right < 0, test node is not in umbra of cursor - mWorkingOutside = left < MIN_OVERLAP || right < MIN_OVERLAP; - mWorkingOverlap = Overlap(span, left, right); - mPreferred = left <= 0 ? 0 : left; -} - -#if DUMP_NAV_CACHE - -#define DEBUG_PRINT_RECT(prefix, debugName, field) \ - { const WebCore::IntRect& r = b->field; \ - DUMP_NAV_LOGD("%s DebugTestRect TEST%s_" #debugName "={%d, %d, %d, %d}; //" #field "\n", \ - prefix, mFrameName, r.x(), r.y(), r.width(), r.height()); } - -CachedFrame* CachedFrame::Debug::base() const { - CachedFrame* nav = (CachedFrame*) ((char*) this - OFFSETOF(CachedFrame, mDebug)); - return nav; -} - -void CachedFrame::Debug::print() const -{ - CachedFrame* b = base(); - DEBUG_PRINT_RECT("//", CONTENTS, mContents); - DEBUG_PRINT_RECT("", BOUNDS, mLocalViewBounds); - DEBUG_PRINT_RECT("//", VIEW, mViewBounds); - - DUMP_NAV_LOGD("// CachedNode mCachedNodes={ // count=%d\n", b->mCachedNodes.size()); - for (CachedNode* node = b->mCachedNodes.begin(); - node != b->mCachedNodes.end(); node++) { - node->mDebug.print(); - const CachedInput* input = b->textInput(node); - if (input) - input->mDebug.print(); - DUMP_NAV_LOGD("\n"); - } - DUMP_NAV_LOGD("// }; // end of nodes\n"); -#if USE(ACCELERATED_COMPOSITING) - DUMP_NAV_LOGD("// CachedLayer mCachedLayers={ // count=%d\n", b->mCachedLayers.size()); - for (CachedLayer* layer = b->mCachedLayers.begin(); - layer != b->mCachedLayers.end(); layer++) { - layer->mDebug.print(); - } - DUMP_NAV_LOGD("// }; // end of layers\n"); -#endif // USE(ACCELERATED_COMPOSITING) - DUMP_NAV_LOGD("// CachedColor mCachedColors={ // count=%d\n", b->mCachedColors.size()); - for (CachedColor* color = b->mCachedColors.begin(); - color != b->mCachedColors.end(); color++) { - color->mDebug.print(); - } - DUMP_NAV_LOGD("// }; // end of colors\n"); - DUMP_NAV_LOGD("// CachedFrame mCachedFrames={ // count=%d\n", b->mCachedFrames.size()); - for (CachedFrame* child = b->mCachedFrames.begin(); - child != b->mCachedFrames.end(); child++) - { - child->mDebug.print(); - } - DUMP_NAV_LOGD("// }; // end of child frames\n"); - DUMP_NAV_LOGD("// void* mFrame=(void*) %p;\n", b->mFrame); - DUMP_NAV_LOGD("// CachedFrame* mParent=%p;\n", b->mParent); - DUMP_NAV_LOGD("// int mIndexInParent=%d;\n", b->mIndexInParent); - DUMP_NAV_LOGD("// const CachedRoot* mRoot=%p;\n", b->mRoot); - DUMP_NAV_LOGD("// int mCursorIndex=%d;\n", b->mCursorIndex); - DUMP_NAV_LOGD("// int mFocusIndex=%d;\n", b->mFocusIndex); -} - -bool CachedFrame::Debug::validate(const CachedNode* node) const -{ - const CachedFrame* b = base(); - if (b->mCachedNodes.size() == 0) - return false; - if (node >= b->mCachedNodes.begin() && node < b->mCachedNodes.end()) - return true; - for (const CachedFrame* child = b->mCachedFrames.begin(); - child != b->mCachedFrames.end(); child++) - if (child->mDebug.validate(node)) - return true; - return false; -} - -#undef DEBUG_PRINT_RECT - -#endif - -} diff --git a/Source/WebKit/android/nav/CachedFrame.h b/Source/WebKit/android/nav/CachedFrame.h deleted file mode 100644 index da86521..0000000 --- a/Source/WebKit/android/nav/CachedFrame.h +++ /dev/null @@ -1,287 +0,0 @@ -/* - * Copyright 2007, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -// FIXME: A file of this name already exists in WebCore/history. -// This file should be renamed. -#ifndef AndroidCachedFrame_h -#define AndroidCachedFrame_h - -#include "CachedColor.h" -#include "CachedInput.h" -#include "CachedLayer.h" -#include "CachedNode.h" -#include "IntRect.h" -#include "SkFixed.h" -#include "wtf/Vector.h" - -class SkPicture; - -namespace WebCore { - class Frame; - class Node; -} - -namespace android { - -class CachedHistory; -class CachedRoot; - - // first node referenced by cache is always document -class CachedFrame { -public: - enum Direction { - UNINITIALIZED = -1, - LEFT, - RIGHT, - UP, - DOWN, - DIRECTION_COUNT, - DIRECTION_MASK = DIRECTION_COUNT - 1, - UP_DOWN = UP & DOWN, // mask and result - RIGHT_DOWN = RIGHT & DOWN, // mask and result - }; - enum Compare { - UNDECIDED = -1, - TEST_IS_BEST, - REJECT_TEST - }; - enum CursorInit { - CURSOR_UNINITIALIZED = -2, - CURSOR_CLEARED = -1, - CURSOR_SET = 0 - }; - CachedFrame() {} - void add(CachedColor& color) { mCachedColors.append(color); } - void add(CachedInput& input) { mCachedTextInputs.append(input); } -#if USE(ACCELERATED_COMPOSITING) - void add(CachedLayer& layer) { mCachedLayers.append(layer); } -#endif - void add(CachedNode& node) { mCachedNodes.append(node); } - void addFrame(CachedFrame& child) { mCachedFrames.append(child); } - WebCore::IntRect adjustBounds(const CachedNode* , - const WebCore::IntRect& ) const; - bool checkRings(const CachedNode* node, - const WebCore::IntRect& testBounds) const; - bool checkVisited(const CachedNode* , CachedFrame::Direction ) const; - size_t childCount() { return mCachedFrames.size(); } - void clearCursor(); - const CachedColor& color(const CachedNode* node) const { - return mCachedColors[node->colorIndex()]; - } - const CachedNode* currentCursor() const { return currentCursor(NULL); } - const CachedNode* currentCursor(const CachedFrame** ) const; - const CachedNode* currentFocus() const { return currentFocus(NULL); } - const CachedNode* currentFocus(const CachedFrame** ) const; - bool directionChange() const; - const CachedNode* document() const { return mCachedNodes.begin(); } - bool empty() const { return mCachedNodes.size() < 2; } // must have 1 past doc - const CachedNode* findBestAt(const WebCore::IntRect& , int* best, - bool* inside, const CachedNode** , const CachedFrame** directFrame, - const CachedFrame** resultFrame, int* x, - int* y, bool checkForHidden) const; - const CachedFrame* findBestFrameAt(int x, int y) const; - const CachedNode* findBestHitAt(const WebCore::IntRect& , - const CachedFrame** , int* x, int* y) const; - void finishInit(); - CachedFrame* firstChild() { return mCachedFrames.begin(); } - const CachedFrame* firstChild() const { return mCachedFrames.begin(); } - void* framePointer() const { return mFrame; } - CachedNode* getIndex(int index) { return index >= 0 ? - &mCachedNodes[index] : NULL; } - const CachedFrame* hasFrame(const CachedNode* node) const { - return const_cast<CachedFrame*>(this)->hasFrame(node); - } - CachedFrame* hasFrame(const CachedNode* node); - void hideCursor(); - int indexInParent() const { return mIndexInParent; } - void init(const CachedRoot* root, int index, WebCore::Frame* frame); - const CachedFrame* lastChild() const { return &mCachedFrames.last(); } -#if USE(ACCELERATED_COMPOSITING) - const CachedLayer* lastLayer() const { return &mCachedLayers.last(); } -#endif - CachedNode* lastNode() { return &mCachedNodes.last(); } - CachedFrame* lastChild() { return &mCachedFrames.last(); } -#if USE(ACCELERATED_COMPOSITING) - const CachedLayer* layer(const CachedNode* ) const; - size_t layerCount() const { return mCachedLayers.size(); } -#endif - WebCore::IntRect localBounds(const CachedNode* , - const WebCore::IntRect& ) const; - const CachedFrame* parent() const { return mParent; } - CachedFrame* parent() { return mParent; } - SkPicture* picture(const CachedNode* ) const; - SkPicture* picture(const CachedNode* , int* xPtr, int* yPtr) const; - void resetLayers(); - bool sameFrame(const CachedFrame* ) const; - void removeLast() { mCachedNodes.removeLast(); } - void resetClippedOut(); - void setContentsSize(int width, int height) { mContents.setWidth(width); - mContents.setHeight(height); } - bool setCursor(WebCore::Frame* , WebCore::Node* , int x, int y); - void setCursorIndex(int index) { mCursorIndex = index; } - void setData(); - bool setFocus(WebCore::Frame* , WebCore::Node* , int x, int y); - void setFocusIndex(int index) { mFocusIndex = index; } - void setIndexInParent(int index) { mIndexInParent = index; } - void setLocalViewBounds(const WebCore::IntRect& bounds) { mLocalViewBounds = bounds; } - int size() { return mCachedNodes.size(); } - const CachedInput* textInput(const CachedNode* node) const { - return node->isTextInput() ? &mCachedTextInputs[node->textInputIndex()] - : 0; - } - const CachedNode* validDocument() const; -protected: - const CachedNode* nextTextField(const CachedNode* start, - const CachedFrame** framePtr, bool* found) const; - struct BestData { - int mDistance; - int mSideDistance; - int mMajorDelta; // difference of center of object - // used only when leading and trailing edges contain another set of edges - int mMajorDelta2; // difference of leading edge (only used when center is same) - int mMajorButt; // checks for next cell butting up against or close to previous one - int mWorkingDelta; - int mWorkingDelta2; - int mNavDelta; - int mNavDelta2; - const CachedFrame* mFrame; - const CachedNode* mNode; - SkFixed mWorkingOverlap; // this and below are fuzzy answers instead of bools - SkFixed mNavOverlap; - SkFixed mPreferred; - bool mCursorChild; - bool mInNav; - bool mNavOutside; - bool mWorkingOutside; - int bottom() const { return bounds().maxY(); } - const WebCore::IntRect& bounds() const { return mNodeBounds; } - bool canBeReachedByAnotherDirection(); - int height() const { return bounds().height(); } - bool inOrSubsumesNav() const { return (mNavDelta ^ mNavDelta2) >= 0; } - bool inOrSubsumesWorking() const { return (mWorkingDelta ^ mWorkingDelta2) >= 0; } - int isContainer(BestData* ); - const WebCore::IntRect& mouseBounds() const { return mMouseBounds; } - static SkFixed Overlap(int span, int left, int right); - void reset() { mNode = NULL; } - int right() const { return bounds().maxX(); } - void setMouseBounds(const WebCore::IntRect& b) { mMouseBounds = b; } - void setNodeBounds(const WebCore::IntRect& b) { mNodeBounds = b; } - void setDistances(); - bool setDownDirection(const CachedHistory* ); - bool setLeftDirection(const CachedHistory* ); - bool setRightDirection(const CachedHistory* ); - bool setUpDirection(const CachedHistory* ); - void setNavInclusion(int left, int right); - void setNavOverlap(int span, int left, int right); - void setWorkingInclusion(int left, int right); - void setWorkingOverlap(int span, int left, int right); - int width() const { return bounds().width(); } - int x() const { return bounds().x(); } - int y() const { return bounds().y(); } -private: // since computing these is complicated, protect them so that the - // are only written by appropriate helpers - WebCore::IntRect mMouseBounds; - WebCore::IntRect mNodeBounds; - }; - typedef const CachedNode* (CachedFrame::*MoveInDirection)( - const CachedNode* test, const CachedNode* limit, BestData* ) const; - void adjustToTextColumn(int* delta) const; - static bool CheckBetween(Direction , const WebCore::IntRect& bestRect, - const WebCore::IntRect& prior, WebCore::IntRect* result); - bool checkBetween(BestData* , Direction ); - int compare(BestData& testData, const BestData& bestData) const; - void findClosest(BestData* , Direction original, Direction test, - WebCore::IntRect* clip) const; - int frameNodeCommon(BestData& testData, const CachedNode* test, - BestData* bestData, BestData* originalData) const; - int framePartCommon(BestData& testData, const CachedNode* test, - BestData* ) const; - const CachedNode* frameDown(const CachedNode* test, const CachedNode* limit, - BestData* ) const; - const CachedNode* frameLeft(const CachedNode* test, const CachedNode* limit, - BestData* ) const; - const CachedNode* frameRight(const CachedNode* test, const CachedNode* limit, - BestData* ) const; - const CachedNode* frameUp(const CachedNode* test, const CachedNode* limit, - BestData* ) const; - int minWorkingHorizontal() const; - int minWorkingVertical() const; - int maxWorkingHorizontal() const; - int maxWorkingVertical() const; - bool moveInFrame(MoveInDirection , const CachedNode* test, BestData* ) const; - const WebCore::IntRect& _navBounds() const; - WebCore::IntRect mContents; - WebCore::IntRect mLocalViewBounds; - WebCore::IntRect mViewBounds; - WTF::Vector<CachedColor> mCachedColors; - WTF::Vector<CachedNode> mCachedNodes; - WTF::Vector<CachedFrame> mCachedFrames; - WTF::Vector<CachedInput> mCachedTextInputs; -#if USE(ACCELERATED_COMPOSITING) - WTF::Vector<CachedLayer> mCachedLayers; -#endif - void* mFrame; // WebCore::Frame*, used only to compare pointers - CachedFrame* mParent; - int mCursorIndex; - int mFocusIndex; - int mIndexInParent; // index within parent's array of children, or -1 if root - const CachedRoot* mRoot; -private: - CachedHistory* history() const; -#ifdef BROWSER_DEBUG -public: - CachedNode* find(WebCore::Node* ); // !!! probably debugging only - int mDebugIndex; - int mDebugLoopbackOffset; -#endif -#if !defined NDEBUG || DUMP_NAV_CACHE -public: - class Debug { -public: - Debug() { -#if DUMP_NAV_CACHE - mFrameName[0] = '\0'; -#endif -#if !defined NDEBUG - mInUse = true; -#endif - } -#if !defined NDEBUG - ~Debug() { mInUse = false; } - bool mInUse; -#endif -#if DUMP_NAV_CACHE - CachedFrame* base() const; - void print() const; - bool validate(const CachedNode* ) const; - char mFrameName[256]; -#endif - } mDebug; -#endif -}; - -} - -#endif // AndroidCachedFrame_h diff --git a/Source/WebKit/android/nav/CachedHistory.cpp b/Source/WebKit/android/nav/CachedHistory.cpp deleted file mode 100644 index d132cc3..0000000 --- a/Source/WebKit/android/nav/CachedHistory.cpp +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright 2007, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "CachedPrefix.h" -#include "CachedFrame.h" -#include "CachedNode.h" -#if DUMP_NAV_CACHE -#include "CachedRoot.h" -#endif - -#include "CachedHistory.h" - -namespace android { - -CachedHistory::CachedHistory() { - memset(this, 0, sizeof(CachedHistory)); // this assume the class has no virtuals - mLastMove = CachedFrame::UNINITIALIZED; - mPriorMove = CachedFrame::UNINITIALIZED; -} - - -void CachedHistory::addToVisited(const CachedNode* node, CachedFrame::Direction direction) -{ - memmove(&mVisited[1], &mVisited[0], sizeof(mVisited) - sizeof(mVisited[0])); - mVisited[0].mNode = node; - mVisited[0].mDirection = direction; -} - -bool CachedHistory::checkVisited(const CachedNode* node, CachedFrame::Direction direction) const -{ - // if the direction is unchanged and we've already visited this node, don't visit it again - int index = 0; - while (index < NAVIGATION_VISIT_DEPTH - 1) { - if (direction != mVisited[index].mDirection) - break; - index++; // compare with last direction, previous to last node (where the arrow took us from) - if (node == mVisited[index].mNode) - return false; - } - return true; -} - -void CachedHistory::pinMaxMin(const WebCore::IntRect& viewBounds) -{ - if (mMinWorkingHorizontal < viewBounds.y() || mMinWorkingHorizontal >= viewBounds.maxY()) - mMinWorkingHorizontal = viewBounds.y(); - if (mMaxWorkingHorizontal > viewBounds.maxY() || mMaxWorkingHorizontal <= viewBounds.y()) - mMaxWorkingHorizontal = viewBounds.maxY(); - if (mMinWorkingVertical < viewBounds.x() || mMinWorkingVertical >= viewBounds.maxX()) - mMinWorkingVertical = viewBounds.x(); - if (mMaxWorkingVertical > viewBounds.maxX() || mMaxWorkingVertical <= viewBounds.x()) - mMaxWorkingVertical = viewBounds.maxX(); -} - -void CachedHistory::reset() -{ - memset(mVisited, 0, sizeof(mVisited)); -// mLastScroll = 0; - mPriorBounds = WebCore::IntRect(0, 0, 0, 0); - mDirectionChange = false; - mDidFirstLayout = false; - mPriorMove = mLastMove = CachedFrame::UNINITIALIZED; - mMinWorkingHorizontal = mMinWorkingVertical = INT_MIN; - mMaxWorkingHorizontal = mMaxWorkingVertical = INT_MAX; -} - -void CachedHistory::setWorking(CachedFrame::Direction newMove, - const CachedFrame* cursorFrame, const CachedNode* cursor, - const WebCore::IntRect& viewBounds) -{ - CachedFrame::Direction lastAxis = (CachedFrame::Direction) (mLastMove & ~CachedFrame::RIGHT_DOWN); // up, left or uninitialized - CachedFrame::Direction newAxis = (CachedFrame::Direction) (newMove & ~CachedFrame::RIGHT_DOWN); - bool change = newAxis != lastAxis; - mDirectionChange = change && mLastMove != CachedFrame::UNINITIALIZED; - if (cursor != NULL || mLastMove != CachedFrame::UNINITIALIZED) { - mPriorMove = mLastMove; - mLastMove = newMove; - } - const WebCore::IntRect* navBounds = &mNavBounds; - if (cursor != NULL) { - WebCore::IntRect cursorBounds = cursor->bounds(cursorFrame); - if (cursorBounds.isEmpty() == false) - mNavBounds = cursorBounds; - } - if (change) { // uninitialized or change in direction - if (lastAxis != CachedFrame::LEFT && navBounds->height() > 0) { - mMinWorkingHorizontal = navBounds->y(); - mMaxWorkingHorizontal = navBounds->maxY(); - } - if (lastAxis != CachedFrame::UP && navBounds->width() > 0) { - mMinWorkingVertical = navBounds->x(); - mMaxWorkingVertical = navBounds->maxX(); - } - } - pinMaxMin(viewBounds); -} - -#if DUMP_NAV_CACHE - -#define DEBUG_PRINT_BOOL(field) \ - DUMP_NAV_LOGD("// bool " #field "=%s;\n", b->field ? "true" : "false") - -#define DEBUG_PRINT_RECT(field) \ - { const WebCore::IntRect& r = b->field; \ - DUMP_NAV_LOGD("// IntRect " #field "={%d, %d, %d, %d};\n", \ - r.x(), r.y(), r.width(), r.height()); } - -CachedHistory* CachedHistory::Debug::base() const { - CachedHistory* nav = (CachedHistory*) ((char*) this - OFFSETOF(CachedHistory, mDebug)); - return nav; -} - -const char* CachedHistory::Debug::direction(CachedFrame::Direction d) const -{ - switch (d) { - case CachedFrame::LEFT: return "LEFT"; break; - case CachedFrame::RIGHT: return "RIGHT"; break; - case CachedFrame::UP: return "UP"; break; - case CachedFrame::DOWN: return "DOWN"; break; - default: return "UNINITIALIZED"; - } -} - -void CachedHistory::Debug::print(CachedRoot* root) const -{ - CachedHistory* b = base(); - DUMP_NAV_LOGD("// Visited mVisited[]={\n"); - for (size_t i = 0; i < NAVIGATION_VISIT_DEPTH; i++) { - const Visited& visit = b->mVisited[i]; - const CachedNode* node = visit.mNode; - int index = root != NULL && root->CachedFrame::mDebug.validate(node) ? - node->index() : -1; - DUMP_NAV_LOGD(" // { 0x%p (%d), %s },\n", node, index, direction(visit.mDirection)); - } - DUMP_NAV_LOGD("// };\n"); -// DUMP_NAV_LOGD("// int mLastScroll=%d;\n", b->mLastScroll); - DEBUG_PRINT_RECT(mMouseBounds); - DEBUG_PRINT_RECT(mNavBounds); - DEBUG_PRINT_RECT(mPriorBounds); - DEBUG_PRINT_BOOL(mDirectionChange); - DEBUG_PRINT_BOOL(mDidFirstLayout); - DUMP_NAV_LOGD("// CachedFrame::Direction mLastMove=%s, mPriorMove=%s;\n", - direction(b->mLastMove), direction(b->mPriorMove)); - int max = b->mMaxWorkingHorizontal; - DUMP_NAV_LOGD("static int TEST_MAX_H = %d;\n", max); - int min = b->mMinWorkingHorizontal; - if (min == INT_MIN) - min++; - DUMP_NAV_LOGD("static int TEST_MIN_H = %d;\n", min); - max = b->mMaxWorkingVertical; - DUMP_NAV_LOGD("static int TEST_MAX_V = %d;\n", max); - min = b->mMinWorkingVertical; - if (min == INT_MIN) - min++; - DUMP_NAV_LOGD("static int TEST_MIN_V = %d;\n", min); - DUMP_NAV_LOGD("\n"); -} - -#endif - -} diff --git a/Source/WebKit/android/nav/CachedHistory.h b/Source/WebKit/android/nav/CachedHistory.h deleted file mode 100644 index 96975ca..0000000 --- a/Source/WebKit/android/nav/CachedHistory.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2007, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef CachedHistory_h -#define CachedHistory_h - -#include "CachedFrame.h" - -#define NAVIGATION_VISIT_DEPTH 8 // the number of nodes last visited -- used to detect ping-ponging (number should be tuned) - -namespace android { - -class CachedRoot; - -// CachedHistory is maintained even if DOM is rebuilt by running script. -// It uses blind pointers for comparison in the previously visited nodes. -class CachedHistory { -public: - CachedHistory(); - void addToVisited(const CachedNode* , CachedFrame::Direction ); - bool checkVisited(const CachedNode* , CachedFrame::Direction ) const; - bool didFirstLayout() const { return mDidFirstLayout; } - bool directionChange() const { return mDirectionChange; } - int minWorkingHorizontal() const { return mMinWorkingHorizontal; } - int minWorkingVertical() const { return mMinWorkingVertical; } - int maxWorkingHorizontal() const { return mMaxWorkingHorizontal; } - int maxWorkingVertical() const { return mMaxWorkingVertical; } - const WebCore::IntRect& navBounds() const { return mNavBounds; } - const WebCore::IntRect& priorBounds() const { return mPriorBounds; } - void setDidFirstLayout(bool did) { mDidFirstLayout = did; } - void setMouseBounds(const WebCore::IntRect& loc) { mMouseBounds = loc; } - void setNavBounds(const WebCore::IntRect& loc) { mNavBounds = loc; } - void setWorking(CachedFrame::Direction , const CachedFrame* , - const CachedNode* , const WebCore::IntRect& viewBounds); - void reset(); -private: - void pinMaxMin(const WebCore::IntRect& viewBounds); - struct Visited { - const CachedNode* mNode; - CachedFrame::Direction mDirection; - } mVisited[NAVIGATION_VISIT_DEPTH]; - WebCore::IntRect mMouseBounds; // constricted bounds, if cursor ring is partially visible - WebCore::IntRect mNavBounds; // cursor ring bounds plus optional keystroke movement - WebCore::IntRect mPriorBounds; // prior chosen cursor ring (for reversing narrowing) - bool mDirectionChange; - bool mDidFirstLayout; // set true when page is newly laid out - CachedFrame::Direction mLastMove; - CachedFrame::Direction mPriorMove; - int mMinWorkingHorizontal; - int mMaxWorkingHorizontal; - int mMinWorkingVertical; - int mMaxWorkingVertical; - friend class CachedRoot; -#if DUMP_NAV_CACHE -public: - class Debug { -public: - CachedHistory* base() const; - const char* direction(CachedFrame::Direction d) const; - void print(CachedRoot* ) const; - } mDebug; -#endif -}; - -} - -#endif diff --git a/Source/WebKit/android/nav/CachedInput.cpp b/Source/WebKit/android/nav/CachedInput.cpp deleted file mode 100644 index a6a57ef..0000000 --- a/Source/WebKit/android/nav/CachedInput.cpp +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2009, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "CachedPrefix.h" -#include "CachedInput.h" - -namespace android { - -void CachedInput::init() { - bzero(this, sizeof(CachedInput)); - mName = WTF::String(); -} - -void CachedInput::setTypeFromElement(WebCore::HTMLInputElement* element) -{ - ASSERT(element); - - if (element->isPasswordField()) - mType = PASSWORD; - else if (element->isSearchField()) - mType = SEARCH; - else if (element->isEmailField()) - mType = EMAIL; - else if (element->isNumberField()) - mType = NUMBER; - else if (element->isTelephoneField()) - mType = TELEPHONE; - else if (element->isURLField()) - mType = URL; - else - mType = NORMAL_TEXT_FIELD; -} - -#if DUMP_NAV_CACHE - -#define DEBUG_PRINT_BOOL(field) \ - DUMP_NAV_LOGD("// bool " #field "=%s;\n", b->field ? "true" : "false") - -CachedInput* CachedInput::Debug::base() const { - CachedInput* nav = (CachedInput*) ((char*) this - OFFSETOF(CachedInput, mDebug)); - return nav; -} - -static void printWebCoreString(const char* label, - const WTF::String& string) { - char scratch[256]; - size_t index = snprintf(scratch, sizeof(scratch), label); - const UChar* ch = string.characters(); - while (ch && *ch && index < sizeof(scratch)) { - UChar c = *ch++; - if (c < ' ' || c >= 0x7f) c = ' '; - scratch[index++] = c; - } - DUMP_NAV_LOGD("%.*s\"\n", index, scratch); -} - -void CachedInput::Debug::print() const -{ - CachedInput* b = base(); - DEBUG_PRINT_BOOL(mAutoComplete); - DUMP_NAV_LOGD("// void* mForm=%p;\n", b->mForm); - printWebCoreString("// char* mName=\"", b->mName); - DUMP_NAV_LOGD("// int mMaxLength=%d;\n", b->mMaxLength); - DUMP_NAV_LOGD("// int mPaddingLeft=%d;\n", b->mPaddingLeft); - DUMP_NAV_LOGD("// int mPaddingTop=%d;\n", b->mPaddingTop); - DUMP_NAV_LOGD("// int mPaddingRight=%d;\n", b->mPaddingRight); - DUMP_NAV_LOGD("// int mPaddingBottom=%d;\n", b->mPaddingBottom); - DUMP_NAV_LOGD("// float mTextSize=%f;\n", b->mTextSize); - DUMP_NAV_LOGD("// int mLineHeight=%d;\n", b->mLineHeight); - DUMP_NAV_LOGD("// Type mType=%d;\n", b->mType); - DEBUG_PRINT_BOOL(mIsRtlText); - DEBUG_PRINT_BOOL(mIsTextField); - DEBUG_PRINT_BOOL(mIsTextArea); -} - -#endif - -} diff --git a/Source/WebKit/android/nav/CachedInput.h b/Source/WebKit/android/nav/CachedInput.h deleted file mode 100644 index 77ae57b..0000000 --- a/Source/WebKit/android/nav/CachedInput.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright 2009, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef CachedInput_h -#define CachedInput_h - -#include "CachedDebug.h" -#include "HTMLInputElement.h" -#include "PlatformString.h" - -namespace android { - -class CachedInput { -public: - CachedInput() { - // Initiaized to 0 in its array, so nothing to do in the - // constructor - } - - enum Type { - NONE = -1, - NORMAL_TEXT_FIELD = 0, - TEXT_AREA = 1, - PASSWORD = 2, - SEARCH = 3, - EMAIL = 4, - NUMBER = 5, - TELEPHONE = 6, - URL = 7 - }; - - bool autoComplete() const { return mAutoComplete; } - void* formPointer() const { return mForm; } - void init(); - void setTypeFromElement(WebCore::HTMLInputElement*); - Type getType() const { return mType; } - bool isRtlText() const { return mIsRtlText; } - bool isTextField() const { return mIsTextField; } - bool isTextArea() const { return mIsTextArea; } - int lineHeight() const { return mLineHeight; } - int maxLength() const { return mMaxLength; }; - const WTF::String& name() const { return mName; } - int paddingBottom() const { return mPaddingBottom; } - int paddingLeft() const { return mPaddingLeft; } - int paddingRight() const { return mPaddingRight; } - int paddingTop() const { return mPaddingTop; } - void setAutoComplete(bool autoComplete) { mAutoComplete = autoComplete; } - void setFormPointer(void* form) { mForm = form; } - void setIsRtlText(bool isRtlText) { mIsRtlText = isRtlText; } - void setIsTextField(bool isTextField) { mIsTextField = isTextField; } - void setIsTextArea(bool isTextArea) { mIsTextArea = isTextArea; } - void setLineHeight(int height) { mLineHeight = height; } - void setMaxLength(int maxLength) { mMaxLength = maxLength; } - void setName(const WTF::String& name) { mName = name; } - void setPaddingBottom(int bottom) { mPaddingBottom = bottom; } - void setPaddingLeft(int left) { mPaddingLeft = left; } - void setPaddingRight(int right) { mPaddingRight = right; } - void setPaddingTop(int top) { mPaddingTop = top; } - void setSpellcheck(bool spellcheck) { mSpellcheck = spellcheck; } - void setTextSize(float textSize) { mTextSize = textSize; } - bool spellcheck() const { return mSpellcheck; } - float textSize() const { return mTextSize; } - -private: - - void* mForm; - int mLineHeight; - int mMaxLength; - WTF::String mName; - int mPaddingBottom; - int mPaddingLeft; - int mPaddingRight; - int mPaddingTop; - float mTextSize; - Type mType; - bool mAutoComplete : 1; - bool mSpellcheck : 1; - bool mIsRtlText : 1; - bool mIsTextField : 1; - bool mIsTextArea : 1; -#if DUMP_NAV_CACHE -public: - class Debug { -public: - CachedInput* base() const; - void print() const; - } mDebug; -#endif -}; - -} - -#endif diff --git a/Source/WebKit/android/nav/CachedLayer.cpp b/Source/WebKit/android/nav/CachedLayer.cpp deleted file mode 100644 index f6dfb88..0000000 --- a/Source/WebKit/android/nav/CachedLayer.cpp +++ /dev/null @@ -1,221 +0,0 @@ -/* - * Copyright 2010, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "CachedPrefix.h" - -#include "CachedLayer.h" -#include "FloatRect.h" -#include "LayerAndroid.h" - -namespace android { - -#if USE(ACCELERATED_COMPOSITING) - -IntRect CachedLayer::adjustBounds(const LayerAndroid* root, - const IntRect& bounds) const -{ - const LayerAndroid* aLayer = layer(root); - if (!aLayer) { - DBG_NAV_LOGD("no layer in root=%p uniqueId=%d", root, mUniqueId); -#if DUMP_NAV_CACHE - if (root) - mDebug.printRootLayerAndroid(root); -#endif - return bounds; - } - FloatRect temp = bounds; - // First, remove the original offset from the bounds. - temp.move(-mOffset.x(), -mOffset.y()); - - // Next, add in the new position of the layer (could be different due to a - // fixed position layer). - FloatPoint position = getGlobalPosition(aLayer); - temp.move(position.x(), position.y()); - - // Add in any layer translation. - // FIXME: Should use bounds() and apply the entire transformation matrix. - const FloatPoint& translation = aLayer->translation(); - temp.move(translation.x(), translation.y()); - - SkRect clip; - aLayer->bounds(&clip); - - // Do not try to traverse the parent chain if this is the root as the parent - // will not be a LayerAndroid. - if (aLayer != root) { - LayerAndroid* parent = static_cast<LayerAndroid*>(aLayer->getParent()); - while (parent) { - SkRect pClip; - parent->bounds(&pClip); - - // Move our position into our parent's coordinate space. - clip.offset(pClip.fLeft, pClip.fTop); - // Clip our visible rectangle to the parent. - clip.intersect(pClip); - - // Stop at the root. - if (parent == root) - break; - parent = static_cast<LayerAndroid*>(parent->getParent()); - } - } - - // Intersect the result with the visible clip. - temp.intersect(clip); - - IntRect result = enclosingIntRect(temp); - - DBG_NAV_LOGV("root=%p aLayer=%p [%d]" - " bounds=(%d,%d,w=%d,h=%d) trans=(%g,%g) pos=(%f,%f)" - " offset=(%d,%d)" - " result=(%d,%d,w=%d,h=%d)", - root, aLayer, aLayer->uniqueId(), - bounds.x(), bounds.y(), bounds.width(), bounds.height(), - translation.x(), translation.y(), position.x(), position.y(), - mOffset.x(), mOffset.y(), - result.x(), result.y(), result.width(), result.height()); - return result; -} - -FloatPoint CachedLayer::getGlobalPosition(const LayerAndroid* aLayer) const -{ - SkPoint result = aLayer->getPosition(); - const Layer* parent = aLayer->getParent(); - while (parent) { - result += parent->getPosition(); - DBG_NAV_LOGV("result=(%g,%g) parent=%p [%d]", result.fX, result.fY, - parent, ((LayerAndroid*) parent)->uniqueId()); - parent = parent->getParent(); - } - return result; -} - -const LayerAndroid* CachedLayer::layer(const LayerAndroid* root) const -{ - if (!root) - return 0; - return root->findById(mUniqueId); -} - -// return bounds relative to the layer as recorded when walking the dom -IntRect CachedLayer::localBounds(const LayerAndroid* root, - const IntRect& bounds) const -{ - IntRect temp = bounds; - // Remove the original offset from the bounds. - temp.move(-mOffset.x(), -mOffset.y()); - -#if DEBUG_NAV_UI - const LayerAndroid* aLayer = layer(root); - DBG_NAV_LOGD("aLayer=%p [%d] bounds=(%d,%d,w=%d,h=%d) offset=(%d,%d)" - " result=(%d,%d,w=%d,h=%d)", - aLayer, aLayer ? aLayer->uniqueId() : 0, - bounds.x(), bounds.y(), bounds.width(), bounds.height(), - mOffset.x(), mOffset.y(), - temp.x(), temp.y(), temp.width(), temp.height()); -#endif - - return temp; -} - -SkPicture* CachedLayer::picture(const LayerAndroid* root) const -{ - const LayerAndroid* aLayer = layer(root); - if (!aLayer) - return 0; - DBG_NAV_LOGD("root=%p aLayer=%p [%d] picture=%p", - root, aLayer, aLayer->uniqueId(), aLayer->picture()); - return aLayer->picture(); -} - -void CachedLayer::toLocal(const LayerAndroid* root, int* xPtr, int* yPtr) const -{ - const LayerAndroid* aLayer = layer(root); - if (!aLayer) - return; - DBG_NAV_LOGD("root=%p aLayer=%p [%d]", root, aLayer, aLayer->uniqueId()); - SkRect localBounds; - aLayer->bounds(&localBounds); - *xPtr -= localBounds.fLeft; - *yPtr -= localBounds.fTop; -} - -#if DUMP_NAV_CACHE - -CachedLayer* CachedLayer::Debug::base() const { - return (CachedLayer*) ((char*) this - OFFSETOF(CachedLayer, mDebug)); -} - -void CachedLayer::Debug::print() const -{ - CachedLayer* b = base(); - DUMP_NAV_LOGD(" // int mCachedNodeIndex=%d;\n", b->mCachedNodeIndex); - DUMP_NAV_LOGD(" // int mOffset=(%d, %d);\n", - b->mOffset.x(), b->mOffset.y()); - DUMP_NAV_LOGD(" // int mUniqueId=%p;\n", b->mUniqueId); - DUMP_NAV_LOGD("%s\n", ""); -} - -#endif - -#if DUMP_NAV_CACHE - -int CachedLayer::Debug::spaces; - -void CachedLayer::Debug::printLayerAndroid(const LayerAndroid* layer) -{ - ++spaces; - SkRect bounds; - layer->bounds(&bounds); - DBG_NAV_LOGD("%.*s layer=%p [%d] (%g,%g,%g,%g)" - " position=(%g,%g) translation=(%g,%g) anchor=(%g,%g)" - " matrix=(%g,%g) childMatrix=(%g,%g) picture=%p clipped=%s" - " scrollable=%s\n", - spaces, " ", layer, layer->uniqueId(), - bounds.fLeft, bounds.fTop, bounds.width(), bounds.height(), - layer->getPosition().fX, layer->getPosition().fY, - layer->translation().x(), layer->translation().y(), - layer->getAnchorPoint().fX, layer->getAnchorPoint().fY, - layer->getMatrix().getTranslateX(), layer->getMatrix().getTranslateY(), - layer->getChildrenMatrix().getTranslateX(), - layer->getChildrenMatrix().getTranslateY(), - layer->picture(), layer->m_haveClip ? "true" : "false", - layer->contentIsScrollable() ? "true" : "false"); - for (int i = 0; i < layer->countChildren(); i++) - printLayerAndroid(layer->getChild(i)); - --spaces; -} - -void CachedLayer::Debug::printRootLayerAndroid(const LayerAndroid* layer) -{ - spaces = 0; - printLayerAndroid(layer); -} -#endif - -#endif // USE(ACCELERATED_COMPOSITING) - -} - diff --git a/Source/WebKit/android/nav/CachedLayer.h b/Source/WebKit/android/nav/CachedLayer.h deleted file mode 100644 index fa427d2..0000000 --- a/Source/WebKit/android/nav/CachedLayer.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2010, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef CachedLayer_h -#define CachedLayer_h - -#include "CachedDebug.h" -#include "IntRect.h" - -class SkPicture; - -namespace WebCore { - class FloatPoint; - class LayerAndroid; -} - -using namespace WebCore; - -namespace android { - -class CachedLayer { -public: -#if USE(ACCELERATED_COMPOSITING) - bool operator<(const CachedLayer& l) const { - return mCachedNodeIndex < l.mCachedNodeIndex; - } - // FIXME: adjustBounds should be renamed globalBounds or toGlobal - IntRect adjustBounds(const LayerAndroid* root, const IntRect& bounds) const; - int cachedNodeIndex() const { return mCachedNodeIndex; } - FloatPoint getGlobalPosition(const LayerAndroid* ) const; - const LayerAndroid* layer(const LayerAndroid* root) const; - IntRect localBounds(const LayerAndroid* root, const IntRect& bounds) const; - SkPicture* picture(const LayerAndroid* root) const; - void toLocal(const LayerAndroid* root, int* xPtr, int* yPtr) const; - void setCachedNodeIndex(int index) { mCachedNodeIndex = index; } - // Set the global position of the layer. This is recorded by the nav cache - // and corresponds to RenderLayer::absoluteBoundingBox() which is in - // document coordinates. This can be different from the global position of - // the layer if the layer is fixed positioned or scrollable. - void setOffset(const IntPoint& offset) { mOffset = offset; } - void setUniqueId(int uniqueId) { mUniqueId = uniqueId; } - int uniqueId() const { return mUniqueId; } -private: - int mCachedNodeIndex; - IntPoint mOffset; - int mUniqueId; - -#if DUMP_NAV_CACHE -public: - class Debug { -public: - CachedLayer* base() const; - void print() const; - static void printLayerAndroid(const LayerAndroid* ); - static void printRootLayerAndroid(const LayerAndroid* ); - static int spaces; - } mDebug; -#endif -#endif // USE(ACCELERATED_COMPOSITING) -}; - -} - -#endif diff --git a/Source/WebKit/android/nav/CachedNode.cpp b/Source/WebKit/android/nav/CachedNode.cpp deleted file mode 100644 index e500875..0000000 --- a/Source/WebKit/android/nav/CachedNode.cpp +++ /dev/null @@ -1,431 +0,0 @@ -/* - * Copyright 2007, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "CachedPrefix.h" -#include "android_graphics.h" -#include "CachedFrame.h" -#include "CachedHistory.h" -#include "Node.h" -#include "PlatformString.h" - -#include "CachedNode.h" - -namespace android { - -WebCore::IntRect CachedNode::bounds(const CachedFrame* frame) const -{ - return mIsInLayer ? frame->adjustBounds(this, mBounds) : mBounds; -} - -void CachedNode::clearCursor(CachedFrame* parent) -{ - if (isFrame()) { - CachedFrame* child = const_cast<CachedFrame*>(parent->hasFrame(this)); - child->clearCursor(); - } - mIsCursor = false; -} - -bool CachedNode::Clip(const WebCore::IntRect& outer, WebCore::IntRect* inner, - WTF::Vector<WebCore::IntRect>* rings) -{ - if (outer.contains(*inner)) - return true; -// DBG_NAV_LOGD("outer:{%d,%d,%d,%d} does not contain inner:{%d,%d,%d,%d}", -// outer.x(), outer.y(), outer.width(), outer.height(), -// inner->x(), inner->y(), inner->width(), inner->height()); - bool intersects = outer.intersects(*inner); - size_t size = intersects ? rings->size() : 0; - *inner = WebCore::IntRect(0, 0, 0, 0); - if (intersects) { - WebCore::IntRect * const start = rings->begin(); - WebCore::IntRect* ring = start + size - 1; - do { - ring->intersect(outer); - if (ring->isEmpty()) { - if ((size_t) (ring - start) != --size) - *ring = start[size]; - } else - inner->unite(*ring); - } while (ring-- != start); - } - rings->shrink(size); -// DBG_NAV_LOGD("size:%d", size); - return size != 0; -} - -bool CachedNode::clip(const WebCore::IntRect& bounds) -{ - return Clip(bounds, &mBounds, &mCursorRing); -} - - -void CachedNode::cursorRings(const CachedFrame* frame, - WTF::Vector<WebCore::IntRect>* rings) const -{ - rings->clear(); - for (unsigned index = 0; index < mCursorRing.size(); index++) - rings->append(ring(frame, index)); -} - -WebCore::IntRect CachedNode::cursorRingBounds(const CachedFrame* frame) const -{ - int partMax = navableRects(); - WebCore::IntRect bounds; - for (int partIndex = 0; partIndex < partMax; partIndex++) - bounds.unite(mCursorRing[partIndex]); - bounds.inflate(CURSOR_RING_HIT_TEST_RADIUS); - return mIsInLayer ? frame->adjustBounds(this, bounds) : bounds; -} - -#define OVERLAP 3 - -void CachedNode::fixUpCursorRects(const CachedFrame* frame) -{ - if (mFixedUpCursorRects) - return; - mFixedUpCursorRects = true; - // if the hit-test rect doesn't intersect any other rect, use it - if (mHitBounds != mBounds && mHitBounds.contains(mBounds) && - frame->checkRings(this, mHitBounds)) { - DBG_NAV_LOGD("use mHitBounds (%d,%d,%d,%d)", mHitBounds.x(), - mHitBounds.y(), mHitBounds.width(), mHitBounds.height()); - mUseHitBounds = true; - return; - } - if (navableRects() <= 1) - return; - // if there is more than 1 rect, and the bounds doesn't intersect - // any other cursor ring bounds, use it - IntRect sloppyBounds = mBounds; - sloppyBounds.inflate(2); // give it a couple of extra pixels - if (frame->checkRings(this, sloppyBounds)) { - DBG_NAV_LOGD("use mBounds (%d,%d,%d,%d)", mBounds.x(), - mBounds.y(), mBounds.width(), mBounds.height()); - mUseBounds = true; - return; - } -#if DEBUG_NAV_UI - { - WebCore::IntRect* boundsPtr = mCursorRing.begin() - 1; - const WebCore::IntRect* const boundsEnd = mCursorRing.begin() + mCursorRing.size(); - while (++boundsPtr < boundsEnd) - LOGD("%s %d:(%d, %d, %d, %d)\n", __FUNCTION__, boundsPtr - mCursorRing.begin(), - boundsPtr->x(), boundsPtr->y(), boundsPtr->width(), boundsPtr->height()); - } -#endif - // q: need to know when rects are for drawing and hit-testing, but not mouse down calcs? - bool again; - do { - again = false; - size_t size = mCursorRing.size(); - WebCore::IntRect* unitBoundsPtr = mCursorRing.begin() - 1; - const WebCore::IntRect* const unitBoundsEnd = mCursorRing.begin() + size; - while (++unitBoundsPtr < unitBoundsEnd) { - // any other unitBounds to the left or right of this one? - int unitTop = unitBoundsPtr->y(); - int unitBottom = unitBoundsPtr->maxY(); - int unitLeft = unitBoundsPtr->x(); - int unitRight = unitBoundsPtr->maxX(); - WebCore::IntRect* testBoundsPtr = mCursorRing.begin() - 1; - while (++testBoundsPtr < unitBoundsEnd) { - if (unitBoundsPtr == testBoundsPtr) - continue; - int testTop = testBoundsPtr->y(); - int testBottom = testBoundsPtr->maxY(); - int testLeft = testBoundsPtr->x(); - int testRight = testBoundsPtr->maxX(); - int candidateTop = unitTop > testTop ? unitTop : testTop; - int candidateBottom = unitBottom < testBottom ? unitBottom : testBottom; - int candidateLeft = unitRight < testLeft ? unitRight : testRight; - int candidateRight = unitRight > testLeft ? unitLeft : testLeft; - bool leftRight = true; - if (candidateTop + OVERLAP >= candidateBottom || - candidateLeft + OVERLAP >= candidateRight) { - candidateTop = unitBottom < testTop ? unitBottom : testBottom; - candidateBottom = unitBottom > testTop ? unitTop : testTop; - candidateLeft = unitLeft > testLeft ? unitLeft : testLeft; - candidateRight = unitRight < testRight ? unitRight : testRight; - if (candidateTop + OVERLAP >= candidateBottom || - candidateLeft + OVERLAP >= candidateRight) - continue; - leftRight = false; - } - // construct candidate to add - WebCore::IntRect candidate = WebCore::IntRect(candidateLeft, candidateTop, - candidateRight - candidateLeft, candidateBottom - candidateTop); - // does a different unit bounds intersect the candidate? if so, don't add - WebCore::IntRect* checkBoundsPtr = mCursorRing.begin() - 1; - while (++checkBoundsPtr < unitBoundsEnd) { - if (checkBoundsPtr->intersects(candidate) == false) - continue; - if (leftRight) { - if (candidateTop >= checkBoundsPtr->y() && - candidateBottom > checkBoundsPtr->maxY()) - candidateTop = checkBoundsPtr->maxY(); - else if (candidateTop < checkBoundsPtr->y() && - candidateBottom <= checkBoundsPtr->maxY()) - candidateBottom = checkBoundsPtr->y(); - else - goto nextCheck; - } else { - if (candidateLeft >= checkBoundsPtr->x() && - candidateRight > checkBoundsPtr->maxX()) - candidateLeft = checkBoundsPtr->maxX(); - else if (candidateLeft < checkBoundsPtr->x() && - candidateRight <= checkBoundsPtr->maxX()) - candidateRight = checkBoundsPtr->x(); - else - goto nextCheck; - } - } - candidate = WebCore::IntRect(candidateLeft, candidateTop, - candidateRight - candidateLeft, candidateBottom - candidateTop); - ASSERT(candidate.isEmpty() == false); -#if DEBUG_NAV_UI - LOGD("%s %d:(%d, %d, %d, %d)\n", __FUNCTION__, mCursorRing.size(), - candidate.x(), candidate.y(), candidate.width(), candidate.height()); -#endif - mCursorRing.append(candidate); - again = true; - goto tryAgain; - nextCheck: - continue; - } - } -tryAgain: - ; - } while (again); -} - - -void CachedNode::hideCursor(CachedFrame* parent) -{ - if (isFrame()) { - CachedFrame* child = const_cast<CachedFrame*>(parent->hasFrame(this)); - child->hideCursor(); - } - mIsHidden = true; -} - -WebCore::IntRect CachedNode::hitBounds(const CachedFrame* frame) const -{ - return mIsInLayer ? frame->adjustBounds(this, mHitBounds) : mHitBounds; -} - -void CachedNode::init(WebCore::Node* node) -{ - bzero(this, sizeof(CachedNode)); - mExport = WTF::String(); - mNode = node; - mParentIndex = mDataIndex = -1; - mType = android::NORMAL_CACHEDNODETYPE; -} - -bool CachedNode::isTextField(const CachedFrame* frame) const -{ - const CachedInput* input = frame->textInput(this); - return input ? input->isTextField() : false; -} - -void CachedNode::localCursorRings(const CachedFrame* frame, - WTF::Vector<WebCore::IntRect>* rings) const -{ - rings->clear(); - for (unsigned index = 0; index < mCursorRing.size(); index++) - rings->append(localRing(frame, index)); -} - -WebCore::IntRect CachedNode::localBounds(const CachedFrame* frame) const -{ - return mIsInLayer ? frame->localBounds(this, mBounds) : mBounds; -} - -WebCore::IntRect CachedNode::localHitBounds(const CachedFrame* frame) const -{ - return mIsInLayer ? frame->localBounds(this, mHitBounds) : mHitBounds; -} - -WebCore::IntRect CachedNode::localRing(const CachedFrame* frame, - size_t part) const -{ - const WebCore::IntRect& rect = mCursorRing.at(part); - return mIsInLayer ? frame->localBounds(this, rect) : rect; -} - -void CachedNode::move(int x, int y) -{ - mBounds.move(x, y); - // mHitTestBounds will be moved by caller - WebCore::IntRect* first = mCursorRing.begin(); - WebCore::IntRect* last = first + mCursorRing.size(); - --first; - while (++first != last) - first->move(x, y); -} - -bool CachedNode::partRectsContains(const CachedNode* other) const -{ - int outerIndex = 0; - int outerMax = navableRects(); - int innerMax = other->navableRects(); - do { - const WebCore::IntRect& outerBounds = mCursorRing[outerIndex]; - int innerIndex = 0; - do { - const WebCore::IntRect& innerBounds = other->mCursorRing[innerIndex]; - if (innerBounds.contains(outerBounds)) - return true; - } while (++innerIndex < innerMax); - } while (++outerIndex < outerMax); - return false; -} - -WebCore::IntRect CachedNode::ring(const CachedFrame* frame, size_t part) const -{ - const WebCore::IntRect& rect = mCursorRing.at(part); - return mIsInLayer ? frame->adjustBounds(this, rect) : rect; -} - -#if DUMP_NAV_CACHE - -#define DEBUG_PRINT_BOOL(field) \ - DUMP_NAV_LOGD("// bool " #field "=%s;\n", b->field ? "true" : "false") - -#define DEBUG_PRINT_RECT(field) \ - { const WebCore::IntRect& r = b->field; \ - DUMP_NAV_LOGD("// IntRect " #field "={%d, %d, %d, %d};\n", \ - r.x(), r.y(), r.width(), r.height()); } - -CachedNode* CachedNode::Debug::base() const { - CachedNode* nav = (CachedNode*) ((char*) this - OFFSETOF(CachedNode, mDebug)); - return nav; -} - -const char* CachedNode::Debug::condition(Condition t) const -{ - switch (t) { - case NOT_REJECTED: return "NOT_REJECTED"; break; - case BUTTED_UP: return "BUTTED_UP"; break; - case CENTER_FURTHER: return "CENTER_FURTHER"; break; - case CLOSER: return "CLOSER"; break; - case CLOSER_IN_CURSOR: return "CLOSER_IN_CURSOR"; break; - case CLOSER_OVERLAP: return "CLOSER_OVERLAP"; break; - case CLOSER_TOP: return "CLOSER_TOP"; break; - case NAVABLE: return "NAVABLE"; break; - case FURTHER: return "FURTHER"; break; - case IN_UMBRA: return "IN_UMBRA"; break; - case IN_WORKING: return "IN_WORKING"; break; - case LEFTMOST: return "LEFTMOST"; break; - case OVERLAP_OR_EDGE_FURTHER: return "OVERLAP_OR_EDGE_FURTHER"; break; - case PREFERRED: return "PREFERRED"; break; - case ANCHOR_IN_ANCHOR: return "ANCHOR_IN_ANCHOR"; break; - case BEST_DIRECTION: return "BEST_DIRECTION"; break; - case CHILD: return "CHILD"; break; - case DISABLED: return "DISABLED"; break; - case HIGHER_TAB_INDEX: return "HIGHER_TAB_INDEX"; break; - case IN_CURSOR: return "IN_CURSOR"; break; - case IN_CURSOR_CHILDREN: return "IN_CURSOR_CHILDREN"; break; - case NOT_ENCLOSING_CURSOR: return "NOT_ENCLOSING_CURSOR"; break; - case NOT_CURSOR_NODE: return "NOT_CURSOR_NODE"; break; - case OUTSIDE_OF_BEST: return "OUTSIDE_OF_BEST"; break; - case OUTSIDE_OF_ORIGINAL: return "OUTSIDE_OF_ORIGINAL"; break; - default: return "???"; - } -} - -const char* CachedNode::Debug::type(android::CachedNodeType t) const -{ - switch (t) { - case NORMAL_CACHEDNODETYPE: return "NORMAL"; break; - case ADDRESS_CACHEDNODETYPE: return "ADDRESS"; break; - case EMAIL_CACHEDNODETYPE: return "EMAIL"; break; - case PHONE_CACHEDNODETYPE: return "PHONE"; break; - case ANCHOR_CACHEDNODETYPE: return "ANCHOR"; break; - case AREA_CACHEDNODETYPE: return "AREA"; break; - case FRAME_CACHEDNODETYPE: return "FRAME"; break; - case PLUGIN_CACHEDNODETYPE: return "PLUGIN"; break; - case TEXT_INPUT_CACHEDNODETYPE: return "INPUT"; break; - case SELECT_CACHEDNODETYPE: return "SELECT"; break; - case CONTENT_EDITABLE_CACHEDNODETYPE: return "CONTENT_EDITABLE"; break; - default: return "???"; - } -} - -void CachedNode::Debug::print() const -{ - CachedNode* b = base(); - char scratch[256]; - size_t index = snprintf(scratch, sizeof(scratch), "// char* mExport=\""); - const UChar* ch = b->mExport.characters(); - while (ch && *ch && index < sizeof(scratch)) { - UChar c = *ch++; - if (c < ' ' || c >= 0x7f) c = ' '; - scratch[index++] = c; - } - DUMP_NAV_LOGD("%.*s\"\n", index, scratch); - DEBUG_PRINT_RECT(mBounds); - DEBUG_PRINT_RECT(mHitBounds); - DEBUG_PRINT_RECT(mOriginalAbsoluteBounds); - const WTF::Vector<WebCore::IntRect>* rects = &b->mCursorRing; - size_t size = rects->size(); - DUMP_NAV_LOGD("// IntRect cursorRings={ // size=%d\n", size); - for (size_t i = 0; i < size; i++) { - const WebCore::IntRect& rect = (*rects)[i]; - DUMP_NAV_LOGD(" // {%d, %d, %d, %d}, // %d\n", rect.x(), rect.y(), - rect.width(), rect.height(), i); - } - DUMP_NAV_LOGD("// };\n"); - DUMP_NAV_LOGD("// void* mNode=%p; // (%d) \n", b->mNode, mNodeIndex); - DUMP_NAV_LOGD("// void* mParentGroup=%p; // (%d) \n", b->mParentGroup, mParentGroupIndex); - DUMP_NAV_LOGD("// int mDataIndex=%d;\n", b->mDataIndex); - DUMP_NAV_LOGD("// int mIndex=%d;\n", b->mIndex); - DUMP_NAV_LOGD("// int navableRects()=%d;\n", b->navableRects()); - DUMP_NAV_LOGD("// int mParentIndex=%d;\n", b->mParentIndex); - DUMP_NAV_LOGD("// int mTabIndex=%d;\n", b->mTabIndex); - DUMP_NAV_LOGD("// int mColorIndex=%d;\n", b->mColorIndex); - DUMP_NAV_LOGD("// Condition mCondition=%s;\n", condition(b->mCondition)); - DUMP_NAV_LOGD("// Type mType=%s;\n", type(b->mType)); - DEBUG_PRINT_BOOL(mClippedOut); - DEBUG_PRINT_BOOL(mDisabled); - DEBUG_PRINT_BOOL(mFixedUpCursorRects); - DEBUG_PRINT_BOOL(mHasCursorRing); - DEBUG_PRINT_BOOL(mHasMouseOver); - DEBUG_PRINT_BOOL(mIsCursor); - DEBUG_PRINT_BOOL(mIsFocus); - DEBUG_PRINT_BOOL(mIsHidden); - DEBUG_PRINT_BOOL(mIsInLayer); - DEBUG_PRINT_BOOL(mIsParentAnchor); - DEBUG_PRINT_BOOL(mIsTransparent); - DEBUG_PRINT_BOOL(mIsUnclipped); - DEBUG_PRINT_BOOL(mLast); - DEBUG_PRINT_BOOL(mUseBounds); - DEBUG_PRINT_BOOL(mUseHitBounds); - DEBUG_PRINT_BOOL(mSingleImage); -} - -#endif - -} diff --git a/Source/WebKit/android/nav/CachedNode.h b/Source/WebKit/android/nav/CachedNode.h deleted file mode 100644 index 321b7fd..0000000 --- a/Source/WebKit/android/nav/CachedNode.h +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Copyright 2007, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef CachedNode_h -#define CachedNode_h - -#include "CachedDebug.h" -#include "CachedNodeType.h" -#include "IntRect.h" -#include "PlatformString.h" - -#include <wtf/Vector.h> -#include <wtf/text/AtomicString.h> - -class SkPicture; - -namespace WebCore { - class Node; -} - -namespace android { - -class CachedFrame; -class CachedRoot; - -class CachedNode { -public: -// Nodes are rejected because either they are spacially not the best (first set) -// or because they have the wrong DOM attribute (in focus, a focused child, etc) -// findClosest() gives only spacially rejected nodes a second chance - enum Condition { // if bigger than 32, increase bitfield size below - // rejections that get a second chance - NOT_REJECTED = 0, - SECOND_CHANCE_START = NOT_REJECTED, // must be first in list - BUTTED_UP, - CENTER_FURTHER, - CLOSER, - CLOSER_IN_CURSOR, - CLOSER_OVERLAP, - CLOSER_TOP, - NAVABLE, - FURTHER, - IN_UMBRA, - IN_WORKING, - LEFTMOST, - NOT_ENCLOSING_CURSOR, - OVERLAP_OR_EDGE_FURTHER, - PREFERRED, // better overlap measure - SECOND_CHANCE_END = PREFERRED, // must be last in list - // rejections that don't get a second chance - ANCHOR_IN_ANCHOR, - BEST_DIRECTION, // can be reached by another direction - CHILD, - DISABLED, - HIGHER_TAB_INDEX, - IN_CURSOR, - IN_CURSOR_CHILDREN, - NOT_CURSOR_NODE, - OUTSIDE_OF_BEST, // containership - OUTSIDE_OF_ORIGINAL, // containership - UNDER_LAYER, - CONDITION_SIZE // FIXME: test that CONDITION_SIZE fits in mCondition - }; - CachedNode() { - // The node is initiaized to 0 in its array, so nothing to do in the - // constructor - } - - WebCore::IntRect bounds(const CachedFrame* ) const; - int childFrameIndex() const { return isFrame() ? mDataIndex : -1; } - void clearCondition() const { mCondition = NOT_REJECTED; } - void clearCursor(CachedFrame* ); - static bool Clip(const WebCore::IntRect& outer, WebCore::IntRect* inner, - WTF::Vector<WebCore::IntRect>* rings); - bool clip(const WebCore::IntRect& ); - bool clippedOut() { return mClippedOut; } - int colorIndex() const { return mColorIndex; } - WebCore::IntRect cursorRingBounds(const CachedFrame* ) const; - void cursorRings(const CachedFrame* , WTF::Vector<WebCore::IntRect>* ) const; - bool disabled() const { return mDisabled; } - const CachedNode* document() const { return &this[-mIndex]; } - void fixUpCursorRects(const CachedFrame* frame); - const WTF::String& getExport() const { return mExport; } - bool hasCursorRing() const { return mHasCursorRing; } - bool hasMouseOver() const { return mHasMouseOver; } - void hideCursor(CachedFrame* ); - WebCore::IntRect hitBounds(const CachedFrame* ) const; - int index() const { return mIndex; } - void init(WebCore::Node* node); - bool isAnchor() const { return mType == ANCHOR_CACHEDNODETYPE; } - bool isContentEditable() const { return mType == CONTENT_EDITABLE_CACHEDNODETYPE; } - bool isCursor() const { return mIsCursor; } - bool isArea() const { return mType == AREA_CACHEDNODETYPE; } - bool isFocus() const { return mIsFocus; } - bool isFrame() const { return mType == FRAME_CACHEDNODETYPE; } - bool isHidden() const { return mIsHidden; } - bool isInLayer() const { return mIsInLayer; } - bool isNavable(const CachedFrame* frame, const WebCore::IntRect& clip) const { - return clip.intersects(bounds(frame)); - } - bool isPlugin() const { return mType == PLUGIN_CACHEDNODETYPE; } - bool isSelect() const { return mType == SELECT_CACHEDNODETYPE; } - bool isSyntheticLink() const { - return mType >= ADDRESS_CACHEDNODETYPE && mType <= PHONE_CACHEDNODETYPE; - } - bool isTextField(const CachedFrame*) const; - bool isTextInput() const { return mType == TEXT_INPUT_CACHEDNODETYPE; } - bool isTransparent() const { return mIsTransparent; } - bool isUnclipped() const { return mIsUnclipped; } - // localXXX functions are used only for drawing cursor rings - WebCore::IntRect localBounds(const CachedFrame* ) const; - void localCursorRings(const CachedFrame* , - WTF::Vector<WebCore::IntRect>* ) const; - WebCore::IntRect localHitBounds(const CachedFrame* ) const; - WebCore::IntRect localRing(const CachedFrame* , size_t part) const; - void move(int x, int y); - int navableRects() const { return mCursorRing.size(); } - void* nodePointer() const { return mNode; } - bool noSecondChance() const { return mCondition > SECOND_CHANCE_END; } - const WebCore::IntRect& originalAbsoluteBounds() const { - return mOriginalAbsoluteBounds; } - const CachedNode* parent() const { return document() + mParentIndex; } - void* parentGroup() const { return mParentGroup; } - int parentIndex() const { return mParentIndex; } - bool partRectsContains(const CachedNode* other) const; - const WebCore::IntRect& rawBounds() const { return mBounds; } - void reset(); - WebCore::IntRect ring(const CachedFrame* , size_t part) const; - const WTF::Vector<WebCore::IntRect>& rings() const { return mCursorRing; } - void setBounds(const WebCore::IntRect& bounds) { mBounds = bounds; } - void setClippedOut(bool clipped) { mClippedOut = clipped; } - void setColorIndex(int index) { mColorIndex = index; } - void setCondition(Condition condition) const { mCondition = condition; } - void setDataIndex(int index) { mDataIndex = index; } - void setDisabled(bool disabled) { mDisabled = disabled; } - void setExport(const WTF::String& exported) { mExport = exported; } - void setHasCursorRing(bool hasRing) { mHasCursorRing = hasRing; } - void setHasMouseOver(bool hasMouseOver) { mHasMouseOver = hasMouseOver; } - void setHitBounds(const WebCore::IntRect& bounds) { mHitBounds = bounds; } - void setOriginalAbsoluteBounds(const WebCore::IntRect& bounds) { - mOriginalAbsoluteBounds = bounds; } - void setIndex(int index) { mIndex = index; } - void setIsCursor(bool isCursor) { mIsCursor = isCursor; } - void setIsFocus(bool isFocus) { mIsFocus = isFocus; } - void setIsInLayer(bool isInLayer) { mIsInLayer = isInLayer; } - void setIsParentAnchor(bool isAnchor) { mIsParentAnchor = isAnchor; } - void setIsTransparent(bool isTransparent) { mIsTransparent = isTransparent; } - void setIsUnclipped(bool unclipped) { mIsUnclipped = unclipped; } - void setLast() { mLast = true; } - void setParentGroup(void* group) { mParentGroup = group; } - void setParentIndex(int parent) { mParentIndex = parent; } - void setSingleImage(bool single) { mSingleImage = single; } - void setTabIndex(int index) { mTabIndex = index; } - void setType(CachedNodeType type) { mType = type; } - void show() { mIsHidden = false; } - bool singleImage() const { return mSingleImage; } - int tabIndex() const { return mTabIndex; } - int textInputIndex() const { return isTextInput() ? mDataIndex : -1; } - const CachedNode* traverseNextNode() const { return mLast ? NULL : &this[1]; } - bool useBounds() const { return mUseBounds; } - bool useHitBounds() const { return mUseHitBounds; } - bool wantsKeyEvents() const { return isTextInput() || isPlugin() - || isContentEditable() || isFrame(); } -private: - friend class CacheBuilder; - WTF::String mExport; - WebCore::IntRect mBounds; - WebCore::IntRect mHitBounds; - WebCore::IntRect mOriginalAbsoluteBounds; - WTF::Vector<WebCore::IntRect> mCursorRing; - void* mNode; // WebCore::Node*, only used to match pointers - void* mParentGroup; // WebCore::Node*, only used to match pointers - int mDataIndex; // child frame if a frame; input data index; or -1 - int mIndex; // index of itself, to find first in array (document) - int mParentIndex; - int mTabIndex; - int mColorIndex; // index to ring color and other stylable properties - mutable Condition mCondition : 5; // why the node was not chosen on the first pass - CachedNodeType mType : 4; - bool mClippedOut : 1; - bool mDisabled : 1; - bool mFixedUpCursorRects : 1; - bool mHasCursorRing : 1; - bool mHasMouseOver : 1; - bool mIsCursor : 1; - bool mIsFocus : 1; - bool mIsHidden : 1; - bool mIsInLayer : 1; - bool mIsParentAnchor : 1; - bool mIsTransparent : 1; - bool mIsUnclipped : 1; - bool mLast : 1; // true if this is the last node in a group - bool mSingleImage : 1; - bool mUseBounds : 1; - bool mUseHitBounds : 1; -#ifdef BROWSER_DEBUG -public: - WebCore::Node* webCoreNode() const { return (WebCore::Node*) mNode; } - bool mDisplayMeasure; - mutable bool mInCompare; - int mSideDistance; - int mSecondSide; -#endif -#if DEBUG_NAV_UI || DUMP_NAV_CACHE -public: - class Debug { -public: - CachedNode* base() const; - const char* condition(Condition t) const; - void print() const; - const char* type(CachedNodeType t) const; -#if DUMP_NAV_CACHE - int mNodeIndex; - int mParentGroupIndex; -#endif - } mDebug; - friend class CachedNode::Debug; -#endif -}; - -} - -#endif diff --git a/Source/WebKit/android/nav/CachedNodeType.h b/Source/WebKit/android/nav/CachedNodeType.h deleted file mode 100644 index f922946..0000000 --- a/Source/WebKit/android/nav/CachedNodeType.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2007, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef CachedNodeType_h -#define CachedNodeType_h - -namespace android { - -enum CachedNodeType { - NORMAL_CACHEDNODETYPE, - ADDRESS_CACHEDNODETYPE, - EMAIL_CACHEDNODETYPE, - PHONE_CACHEDNODETYPE, - ANCHOR_CACHEDNODETYPE, - AREA_CACHEDNODETYPE, - FRAME_CACHEDNODETYPE, - PLUGIN_CACHEDNODETYPE, - TEXT_INPUT_CACHEDNODETYPE, - SELECT_CACHEDNODETYPE, - CONTENT_EDITABLE_CACHEDNODETYPE -}; - -enum CachedNodeBits { - NORMAL_CACHEDNODE_BITS = 0, - ADDRESS_CACHEDNODE_BIT = 1 << (ADDRESS_CACHEDNODETYPE - 1), - EMAIL_CACHEDNODE_BIT = 1 << (EMAIL_CACHEDNODETYPE - 1), - PHONE_CACHEDNODE_BIT = 1 << (PHONE_CACHEDNODETYPE - 1), - ALL_CACHEDNODE_BITS = ADDRESS_CACHEDNODE_BIT | EMAIL_CACHEDNODE_BIT - | PHONE_CACHEDNODE_BIT -}; - -} - -#endif diff --git a/Source/WebKit/android/nav/CachedPrefix.h b/Source/WebKit/android/nav/CachedPrefix.h deleted file mode 100644 index 576aa4a..0000000 --- a/Source/WebKit/android/nav/CachedPrefix.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2007, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef CachedPrefix_h -#define CachedPrefix_h - -#ifndef LOG_TAG -#define LOG_TAG "navcache" -#endif - -#include "config.h" -#include "CachedDebug.h" - -#ifndef _LIBS_CUTILS_LOG_H - #ifdef LOG - #undef LOG - #endif - - #include <utils/Log.h> -#endif - -#define OFFSETOF(type, field) ((char*)&(((type*)1)->field) - (char*)1) // avoids gnu warning - -#ifndef BZERO_DEFINED -#define BZERO_DEFINED -// http://www.opengroup.org/onlinepubs/000095399/functions/bzero.html -// For maximum portability, it is recommended to replace the function call to bzero() as follows: -#define bzero(b,len) (memset((b), '\0', (len)), (void) 0) -#endif - -#endif diff --git a/Source/WebKit/android/nav/CachedRoot.cpp b/Source/WebKit/android/nav/CachedRoot.cpp deleted file mode 100644 index 2371c4f..0000000 --- a/Source/WebKit/android/nav/CachedRoot.cpp +++ /dev/null @@ -1,1815 +0,0 @@ -/* - * Copyright 2007, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "CachedPrefix.h" -#include "android_graphics.h" -#include "CachedHistory.h" -#include "CachedInput.h" -#include "CachedLayer.h" -#include "CachedNode.h" -#include "FindCanvas.h" -#include "FloatRect.h" -#include "LayerAndroid.h" -#include "ParseCanvas.h" -#include "SkBitmap.h" -#include "SkBounder.h" -#include "SkPixelRef.h" -#include "SkRegion.h" - -#include "CachedRoot.h" - -#if DEBUG_NAV_UI -#include "wtf/text/CString.h" -#endif - -#define DONT_CENTER_IF_ALREADY_VISIBLE - -using std::min; -using std::max; - -#ifdef DUMP_NAV_CACHE_USING_PRINTF - extern android::Mutex gWriteLogMutex; -#endif - -namespace android { - -class CommonCheck : public SkBounder { -public: - enum Type { - kNo_Type, - kDrawBitmap_Type, - kDrawGlyph_Type, - kDrawPaint_Type, - kDrawPath_Type, - kDrawPicture_Type, - kDrawPoints_Type, - kDrawPosText_Type, - kDrawPosTextH_Type, - kDrawRect_Type, - kDrawSprite_Type, - kDrawText_Type, - kDrawTextOnPath_Type, - kPopLayer_Type, - kPushLayer_Type, - kPushSave_Type - }; - - static bool isTextType(Type t) { - return t == kDrawPosTextH_Type || t == kDrawText_Type; - } - - CommonCheck() : mType(kNo_Type), mAllOpaque(true), mIsOpaque(true) { - setEmpty(); - } - - bool doRect(Type type) { - mType = type; - return doIRect(mUnion); - } - - bool isEmpty() { return mUnion.isEmpty(); } - - bool joinGlyphs(const SkIRect& rect) { - bool isGlyph = mType == kDrawGlyph_Type; - if (isGlyph) - mUnion.join(rect); - return isGlyph; - } - - void setAllOpaque(bool opaque) { mAllOpaque = opaque; } - void setEmpty() { mUnion.setEmpty(); } - void setIsOpaque(bool opaque) { mIsOpaque = opaque; } - void setType(Type type) { mType = type; } - - Type mType; - SkIRect mUnion; - bool mAllOpaque; - bool mIsOpaque; -}; - -#if DEBUG_NAV_UI - static const char* TypeNames[] = { - "kNo_Type", - "kDrawBitmap_Type", - "kDrawGlyph_Type", - "kDrawPaint_Type", - "kDrawPath_Type", - "kDrawPicture_Type", - "kDrawPoints_Type", - "kDrawPosText_Type", - "kDrawPosTextH_Type", - "kDrawRect_Type", - "kDrawSprite_Type", - "kDrawText_Type", - "kDrawTextOnPath_Type", - "kPopLayer_Type", - "kPushLayer_Type", - "kPushSave_Type" - }; -#endif - -#define kMargin 16 -#define kSlop 2 - -class BoundsCanvas : public ParseCanvas { -public: - - BoundsCanvas(CommonCheck* bounder) : mBounder(*bounder) { - mTransparentLayer = 0; - setBounder(bounder); - } - - virtual void drawPaint(const SkPaint& paint) { - mBounder.setType(CommonCheck::kDrawPaint_Type); - INHERITED::drawPaint(paint); - } - - virtual void drawPoints(PointMode mode, size_t count, const SkPoint pts[], - const SkPaint& paint) { - mBounder.setType(CommonCheck::kDrawPoints_Type); - INHERITED::drawPoints(mode, count, pts, paint); - } - - virtual void drawRect(const SkRect& rect, const SkPaint& paint) { - mBounder.setType(CommonCheck::kDrawRect_Type); - INHERITED::drawRect(rect, paint); - } - - virtual void drawPath(const SkPath& path, const SkPaint& paint) { - mBounder.setType(CommonCheck::kDrawPath_Type); - INHERITED::drawPath(path, paint); - } - - virtual void commonDrawBitmap(const SkBitmap& bitmap, const SkIRect* rect, - const SkMatrix& matrix, const SkPaint& paint) { - mBounder.setType(CommonCheck::kDrawBitmap_Type); - mBounder.setIsOpaque(bitmap.isOpaque()); - INHERITED::commonDrawBitmap(bitmap, rect, matrix, paint); - } - - virtual void drawSprite(const SkBitmap& bitmap, int left, int top, - const SkPaint* paint) { - mBounder.setType(CommonCheck::kDrawSprite_Type); - mBounder.setIsOpaque(bitmap.isOpaque() && - (!paint || paint->getAlpha() == 255)); - INHERITED::drawSprite(bitmap, left, top, paint); - } - - virtual void drawText(const void* text, size_t byteLength, SkScalar x, - SkScalar y, const SkPaint& paint) { - mBounder.setEmpty(); - mBounder.setType(CommonCheck::kDrawGlyph_Type); - INHERITED::drawText(text, byteLength, x, y, paint); - mBounder.doRect(CommonCheck::kDrawText_Type); - } - - virtual void drawPosText(const void* text, size_t byteLength, - const SkPoint pos[], const SkPaint& paint) { - mBounder.setEmpty(); - mBounder.setType(CommonCheck::kDrawGlyph_Type); - INHERITED::drawPosText(text, byteLength, pos, paint); - if (!mBounder.isEmpty()) - mBounder.doRect(CommonCheck::kDrawPosText_Type); - } - - virtual void drawPosTextH(const void* text, size_t byteLength, - const SkScalar xpos[], SkScalar constY, - const SkPaint& paint) { - mBounder.setEmpty(); - mBounder.setType(CommonCheck::kDrawGlyph_Type); - INHERITED::drawPosTextH(text, byteLength, xpos, constY, paint); - if (mBounder.mUnion.isEmpty()) { - DBG_NAV_LOGD("empty constY=%g", SkScalarToFloat(constY)); - return; - } - SkPaint::FontMetrics metrics; - paint.getFontMetrics(&metrics); - SkPoint upDown[2] = { {xpos[0], constY + metrics.fAscent}, - {xpos[0], constY + metrics.fDescent} }; - const SkMatrix& matrix = getTotalMatrix(); - matrix.mapPoints(upDown, 2); - if (upDown[0].fX == upDown[1].fX) { - mBounder.mUnion.fTop = SkScalarFloor(upDown[0].fY); - mBounder.mUnion.fBottom = SkScalarFloor(upDown[1].fY); - } - mBounder.doRect(CommonCheck::kDrawPosTextH_Type); - } - - virtual void drawTextOnPath(const void* text, size_t byteLength, - const SkPath& path, const SkMatrix* matrix, - const SkPaint& paint) { - mBounder.setEmpty(); - mBounder.setType(CommonCheck::kDrawGlyph_Type); - INHERITED::drawTextOnPath(text, byteLength, path, matrix, paint); - mBounder.doRect(CommonCheck::kDrawTextOnPath_Type); - } - - virtual void drawPicture(SkPicture& picture) { - mBounder.setType(CommonCheck::kDrawPicture_Type); - INHERITED::drawPicture(picture); - } - - virtual int saveLayer(const SkRect* bounds, const SkPaint* paint, - SaveFlags flags) { - int depth = INHERITED::saveLayer(bounds, paint, flags); - if (mTransparentLayer == 0 && paint && paint->getAlpha() < 255) { - mTransparentLayer = depth; - mBounder.setAllOpaque(false); - } - return depth; - } - - virtual void restore() { - mBounder.setType(CommonCheck::kDrawSprite_Type); // for layer draws - int depth = getSaveCount(); - if (depth == mTransparentLayer) { - mTransparentLayer = 0; - mBounder.setAllOpaque(true); - } - INHERITED::restore(); - } - - int mTransparentLayer; - CommonCheck& mBounder; -private: - typedef ParseCanvas INHERITED; -}; - -/* -LeftCheck examines the text in a picture, within a viewable rectangle, -and returns via left() the position of the left edge of the paragraph. -It first looks at the left edge of the test point, then looks above and below -it for more lines of text to determine the div's left edge. -*/ -class LeftCheck : public CommonCheck { -public: - LeftCheck(int x, int y) : mX(x), mY(y), mHitLeft(INT_MAX), - mMostLeft(INT_MAX) { - mHit.set(x - (HIT_SLOP << 1), y - HIT_SLOP, x, y + HIT_SLOP); - mPartial.setEmpty(); - mBounds.setEmpty(); - mPartialType = kNo_Type; - } - - int left() { - if (isTextType(mType)) - doRect(); // process the final line of text - return mMostLeft != INT_MAX ? mMostLeft : mX >> 1; - } - - // FIXME: this is identical to CenterCheck::onIRect() - // refactor so that LeftCheck and CenterCheck inherit common functions - virtual bool onIRect(const SkIRect& rect) { - bool opaqueBitmap = mType == kDrawBitmap_Type && mIsOpaque; - if (opaqueBitmap && rect.contains(mX, mY)) { - mMostLeft = rect.fLeft; - return false; - } - if (joinGlyphs(rect)) // assembles glyphs into a text string - return false; - if (!isTextType(mType) && !opaqueBitmap) - return false; - /* Text on one line may be broken into several parts. Reassemble - the text into a rectangle before considering it. */ - if (rect.fTop < mPartial.fBottom - && rect.fBottom > mPartial.fTop - && mPartial.fRight + JOIN_SLOP_X >= rect.fLeft - && (mPartialType != kDrawBitmap_Type - || mPartial.height() <= rect.height() + JOIN_SLOP_Y)) { - DBG_NAV_LOGD("LeftCheck join mPartial=(%d, %d, %d, %d)" - " rect=(%d, %d, %d, %d)", - mPartial.fLeft, mPartial.fTop, mPartial.fRight, mPartial.fBottom, - rect.fLeft, rect.fTop, rect.fRight, rect.fBottom); - mPartial.join(rect); - return false; - } - if (mPartial.isEmpty() == false) { - doRect(); // process the previous line of text -#if DEBUG_NAV_UI - if (mHitLeft == INT_MAX) - DBG_NAV_LOGD("LeftCheck disabled rect=(%d, %d, %d, %d)", - rect.fLeft, rect.fTop, rect.fRight, rect.fBottom); -#endif - } - mPartial = rect; - mPartialType = mType; - return false; - } - - void doRect() - { - /* Record the outer bounds of the lines of text that intersect the - touch coordinates, given some slop */ - if (SkIRect::Intersects(mPartial, mHit)) { - if (mHitLeft > mPartial.fLeft) - mHitLeft = mPartial.fLeft; - DBG_NAV_LOGD("LeftCheck mHitLeft=%d", mHitLeft); - } else if (mHitLeft == INT_MAX) - return; // wait for intersect success - /* If text is too far away vertically, don't consider it */ - if (!mBounds.isEmpty() && (mPartial.fTop > mBounds.fBottom + HIT_SLOP - || mPartial.fBottom < mBounds.fTop - HIT_SLOP)) { - DBG_NAV_LOGD("LeftCheck stop mPartial=(%d, %d, %d, %d)" - " mBounds=(%d, %d, %d, %d)", - mPartial.fLeft, mPartial.fTop, mPartial.fRight, mPartial.fBottom, - mBounds.fLeft, mBounds.fTop, mBounds.fRight, mBounds.fBottom); - mHitLeft = INT_MAX; // and disable future comparisons - return; - } - /* If the considered text is completely to the left or right of the - touch coordinates, skip it, turn off further detection */ - if (mPartial.fLeft > mX || mPartial.fRight < mX) { - DBG_NAV_LOGD("LeftCheck stop mX=%d mPartial=(%d, %d, %d, %d)", mX, - mPartial.fLeft, mPartial.fTop, mPartial.fRight, mPartial.fBottom); - mHitLeft = INT_MAX; - return; - } - /* record the smallest margins on the left and right */ - if (mMostLeft > mPartial.fLeft) { - DBG_NAV_LOGD("LeftCheck new mMostLeft=%d (old=%d)", mPartial.fLeft, - mMostLeft); - mMostLeft = mPartial.fLeft; - } - if (mBounds.isEmpty()) - mBounds = mPartial; - else if (mPartial.fBottom > mBounds.fBottom) { - DBG_NAV_LOGD("LeftCheck new bottom=%d (old=%d)", mPartial.fBottom, - mBounds.fBottom); - mBounds.fBottom = mPartial.fBottom; - } - } - - static const int JOIN_SLOP_X = 30; // horizontal space between text parts - static const int JOIN_SLOP_Y = 5; // vertical space between text lines - static const int HIT_SLOP = 30; // diameter allowing for tap size - /* const */ SkIRect mHit; // sloppy hit rectangle - SkIRect mBounds; // reference bounds - SkIRect mPartial; // accumulated text bounds, per line - const int mX; // touch location - const int mY; - int mHitLeft; // touched text extremes - int mMostLeft; // paragraph extremes - Type mPartialType; -}; - -/* -CenterCheck examines the text in a picture, within a viewable rectangle, -and returns via center() the optimal amount to scroll in x to display the -paragraph of text. - -The caller of CenterCheck has configured (but not allocated) a bitmap -the height and three times the width of the view. The picture is drawn centered -in the bitmap, so text that would be revealed, if the view was scrolled up to -a view-width to the left or right, is considered. -*/ -class CenterCheck : public CommonCheck { -public: - CenterCheck(int x, int y, int width) : mX(x), mY(y), - mHitLeft(x), mHitRight(x), mMostLeft(INT_MAX), mMostRight(-INT_MAX), - mViewLeft(width), mViewRight(width << 1) { - mHit.set(x - CENTER_SLOP, y - CENTER_SLOP, - x + CENTER_SLOP, y + CENTER_SLOP); - mPartial.setEmpty(); - } - - int center() { - doRect(); // process the final line of text - /* If the touch coordinates aren't near any text, return 0 */ - if (mHitLeft == mHitRight) { - DBG_NAV_LOGD("abort: mHitLeft=%d ==mHitRight", mHitLeft); - return 0; - } - int leftOver = mHitLeft - mViewLeft; - int rightOver = mHitRight - mViewRight; - int center; - /* If the touched text is too large to entirely fit on the screen, - center it. */ - if (leftOver < 0 && rightOver > 0) { - center = (leftOver + rightOver) >> 1; - DBG_NAV_LOGD("overlap: leftOver=%d rightOver=%d center=%d", - leftOver, rightOver, center); - return center; - } - center = (mMostLeft + mMostRight) >> 1; // the paragraph center - if (leftOver > 0 && rightOver >= 0) { // off to the right - if (center > mMostLeft) // move to center loses left-most text? - center = mMostLeft; - } else if (rightOver < 0 && leftOver <= 0) { // off to the left - if (center < mMostRight) // move to center loses right-most text? - center = mMostRight; - } else { -#ifdef DONT_CENTER_IF_ALREADY_VISIBLE - center = 0; // paragraph is already fully visible -#endif - } - DBG_NAV_LOGD("scroll: leftOver=%d rightOver=%d center=%d", - leftOver, rightOver, center); - return center; - } - -protected: - virtual bool onIRect(const SkIRect& rect) { - if (joinGlyphs(rect)) // assembles glyphs into a text string - return false; - if (!isTextType(mType)) - return false; - /* Text on one line may be broken into several parts. Reassemble - the text into a rectangle before considering it. */ - if (rect.fTop < mPartial.fBottom && rect.fBottom > - mPartial.fTop && mPartial.fRight + CENTER_SLOP >= rect.fLeft) { - DBG_NAV_LOGD("join mPartial=(%d, %d, %d, %d) rect=(%d, %d, %d, %d)", - mPartial.fLeft, mPartial.fTop, mPartial.fRight, mPartial.fBottom, - rect.fLeft, rect.fTop, rect.fRight, rect.fBottom); - mPartial.join(rect); - return false; - } - if (mPartial.isEmpty() == false) - doRect(); // process the previous line of text - mPartial = rect; - return false; - } - - void doRect() - { - /* Record the outer bounds of the lines of text that was 'hit' by the - touch coordinates, given some slop */ - if (SkIRect::Intersects(mPartial, mHit)) { - if (mHitLeft > mPartial.fLeft) - mHitLeft = mPartial.fLeft; - if (mHitRight < mPartial.fRight) - mHitRight = mPartial.fRight; - DBG_NAV_LOGD("mHitLeft=%d mHitRight=%d", mHitLeft, mHitRight); - } - /* If the considered text is completely to the left or right of the - touch coordinates, skip it */ - if (mPartial.fLeft > mX || mPartial.fRight < mX) - return; - int leftOver = mPartial.fLeft - mViewLeft; - int rightOver = mPartial.fRight - mViewRight; - /* If leftOver <= 0, the text starts off the screen. - If rightOver >= 0, the text ends off the screen. - */ - if (leftOver <= 0 && rightOver >= 0) // discard wider than screen - return; -#ifdef DONT_CENTER_IF_ALREADY_VISIBLE - if (leftOver > 0 && rightOver < 0) // discard already visible - return; -#endif - /* record the smallest margins on the left and right */ - if (mMostLeft > leftOver) - mMostLeft = leftOver; - if (mMostRight < rightOver) - mMostRight = rightOver; - DBG_NAV_LOGD("leftOver=%d rightOver=%d mMostLeft=%d mMostRight=%d", - leftOver, rightOver, mMostLeft, mMostRight); - } - - static const int CENTER_SLOP = 10; // space between text parts and lines - /* const */ SkIRect mHit; // sloppy hit rectangle - SkIRect mPartial; // accumulated text bounds, per line - const int mX; // touch location - const int mY; - int mHitLeft; // touched text extremes - int mHitRight; - int mMostLeft; // paragraph extremes - int mMostRight; - const int mViewLeft; // middle third of 3x-wide view - const int mViewRight; -}; - -class ImageCanvas : public ParseCanvas { -public: - ImageCanvas(SkBounder* bounder) : mURI(NULL) { - setBounder(bounder); - } - - const char* getURI() { return mURI; } - -protected: -// Currently webkit's bitmap draws always seem to be cull'd before this entry -// point is called, so we assume that any bitmap that gets here is inside our -// tiny clip (may not be true in the future) - virtual void commonDrawBitmap(const SkBitmap& bitmap, const SkIRect* rect, - const SkMatrix& , const SkPaint& ) { - SkPixelRef* pixelRef = bitmap.pixelRef(); - if (pixelRef != NULL) { - mURI = pixelRef->getURI(); - } - } - -private: - const char* mURI; -}; - -class ImageCheck : public SkBounder { -public: - virtual bool onIRect(const SkIRect& rect) { - return false; - } -}; - -class JiggleCheck : public CommonCheck { -public: - JiggleCheck(int delta, int width) : mDelta(delta), mMaxX(width) { - mMaxJiggle = 0; - mMinX = mMinJiggle = abs(delta); - mMaxWidth = width + mMinX; - } - - int jiggle() { - if (mMinJiggle > mMaxJiggle) - return mDelta; - int avg = (mMinJiggle + mMaxJiggle + 1) >> 1; - return mDelta < 0 ? -avg : avg; - } - - virtual bool onIRect(const SkIRect& rect) { - if (joinGlyphs(rect)) - return false; - if (mType != kDrawBitmap_Type && !isTextType(mType)) - return false; - int min, max; - if (mDelta < 0) { - min = mMinX - rect.fLeft; - max = mMaxWidth - rect.fRight; - } else { - min = rect.fRight - mMaxX; - max = rect.fLeft; - } - if (min <= 0) - return false; - if (max >= mMinX) - return false; - if (mMinJiggle > min) - mMinJiggle = min; - if (mMaxJiggle < max) - mMaxJiggle = max; - return false; - } - - int mDelta; - int mMaxJiggle; - int mMaxX; - int mMinJiggle; - int mMinX; - int mMaxWidth; -}; - -class RingCheck : public CommonCheck { -public: - RingCheck(const WTF::Vector<WebCore::IntRect>& rings, - const WebCore::IntRect& bitBounds, const WebCore::IntRect& testBounds, - bool singleImage) - : mTestBounds(testBounds) - , mBitBounds(bitBounds) - , mPushPop(false) - , mSingleImage(singleImage) - { - const WebCore::IntRect* r; - for (r = rings.begin(); r != rings.end(); r++) { - SkIRect fatter = {r->x(), r->y(), r->maxX(), r->maxY()}; - fatter.inset(-CURSOR_RING_HIT_TEST_RADIUS, -CURSOR_RING_HIT_TEST_RADIUS); - DBG_NAV_LOGD("RingCheck fat=(%d,%d,r=%d,b=%d)", fatter.fLeft, fatter.fTop, - fatter.fRight, fatter.fBottom); - mTextSlop.op(fatter, SkRegion::kUnion_Op); - mTextTest.op(*r, SkRegion::kUnion_Op); - } - int dx = -bitBounds.x(); - int dy = -bitBounds.y(); - DBG_NAV_LOGD("RingCheck translate=(%d,%d)", dx, dy); - mTextSlop.translate(dx, dy); - mTextTest.translate(dx, dy); - mTestBounds.translate(dx, dy); - mEmpty.setEmpty(); - } - - bool hiddenRings(SkRegion* clipped) - { - findBestLayer(); - if (!mBestLayer) { - DBG_NAV_LOG("RingCheck empty"); - clipped->setEmpty(); - return true; - } - const SkRegion* layersEnd = mLayers.end(); - const Type* layerTypes = &mLayerTypes[mBestLayer - mLayers.begin()]; - bool collectGlyphs = true; - bool collectOvers = false; - SkRegion over; - for (const SkRegion* layers = mBestLayer; layers != layersEnd; layers++) { - Type layerType = *layerTypes++; - DBG_NAV_LOGD("RingCheck #%d %s (%d,%d,r=%d,b=%d)", - layers - mLayers.begin(), TypeNames[layerType], - layers->getBounds().fLeft, layers->getBounds().fTop, - layers->getBounds().fRight, layers->getBounds().fBottom); - if (collectGlyphs && (layerType == kDrawGlyph_Type - || ((layerType == kDrawRect_Type && mTextTest.contains(*layers)) - || (layerType == kDrawBitmap_Type && mTextSlop.contains(*layers))))) { - DBG_NAV_LOGD("RingCheck #%d collectOvers", layers - mLayers.begin()); - collectOvers = true; - clipped->op(*layers, SkRegion::kUnion_Op); - continue; - } - collectGlyphs &= layerType != kPushLayer_Type; - if (collectOvers && (layerType == kDrawRect_Type - || layerType == kDrawBitmap_Type - || (!collectGlyphs && layerType == kDrawSprite_Type))) { - DBG_NAV_LOGD("RingCheck #%d over.op", layers - mLayers.begin()); - over.op(*layers, SkRegion::kUnion_Op); - } - } - bool result = !collectOvers || clipped->intersects(over); - const SkIRect t = clipped->getBounds(); - const SkIRect o = over.getBounds(); - clipped->op(over, SkRegion::kDifference_Op); - clipped->translate(mBitBounds.x(), mBitBounds.y()); - const SkIRect c = clipped->getBounds(); - DBG_NAV_LOGD("RingCheck intersects=%s text=(%d,%d,r=%d,b=%d)" - " over=(%d,%d,r=%d,b=%d) clipped=(%d,%d,r=%d,b=%d)", - result ? "true" : "false", - t.fLeft, t.fTop, t.fRight, t.fBottom, - o.fLeft, o.fTop, o.fRight, o.fBottom, - c.fLeft, c.fTop, c.fRight, c.fBottom); - return result; - } - - void push(Type type, const SkIRect& bounds) - { -#if DEBUG_NAV_UI - // this caches the push string and subquently ignores if pushSave - // is immediately followed by popLayer. Push/pop pairs happen - // frequently and just add noise to the log. - static String lastLog; - String currentLog = String("RingCheck append #") - + String::number(mLayers.size()) - + " type=" + TypeNames[type] + " bounds=(" - + String::number(bounds.fLeft) - + "," + String::number(bounds.fTop) + "," - + String::number(bounds.fRight) + "," - + String::number(bounds.fBottom) + ")"; - if (lastLog.length() == 0 || type != kPopLayer_Type) { - if (lastLog.length() != 0) - DBG_NAV_LOGD("%s", lastLog.latin1().data()); - if (type == kPushSave_Type) - lastLog = currentLog; - else - DBG_NAV_LOGD("%s", currentLog.latin1().data()); - } else - lastLog = ""; -#endif - popEmpty(); - mPushPop |= type >= kPopLayer_Type; - if (type == kPopLayer_Type) { - Type last = mLayerTypes.last(); - // remove empty brackets - if (last == kPushLayer_Type || last == kPushSave_Type) { - mLayers.removeLast(); - mLayerTypes.removeLast(); - return; - } - // remove push/pop from push/bitmap/pop - size_t pushIndex = mLayerTypes.size() - 2; - if (last == kDrawBitmap_Type - && mLayerTypes.at(pushIndex) == kPushLayer_Type) { - mLayers.at(pushIndex) = mLayers.last(); - mLayerTypes.at(pushIndex) = kDrawBitmap_Type; - mLayers.removeLast(); - mLayerTypes.removeLast(); - return; - } - // remove non-layer brackets - int stack = 0; - Type* types = mLayerTypes.end(); - while (types != mLayerTypes.begin()) { - Type type = *--types; - if (type == kPopLayer_Type) { - stack++; - continue; - } - if (type != kPushLayer_Type && type != kPushSave_Type) - continue; - if (--stack >= 0) - continue; - if (type == kPushLayer_Type) - break; - int remove = types - mLayerTypes.begin(); - DBG_NAV_LOGD("RingCheck remove=%d mLayers.size=%d" - " mLayerTypes.size=%d", remove, mLayers.size(), - mLayerTypes.size()); - mLayers.remove(remove); - mLayerTypes.remove(remove); - mAppendLikeTypes = false; - return; - } - } - mLayers.append(bounds); - mLayerTypes.append(type); - } - - void startText(const SkPaint& paint) - { - mPaint = &paint; - if (!mLayerTypes.isEmpty() && mLayerTypes.last() == kDrawGlyph_Type - && !mLayers.last().isEmpty()) { - push(kDrawGlyph_Type, mEmpty); - } - } - - bool textOutsideRings() - { - findBestLayer(); - if (!mBestLayer) { - DBG_NAV_LOG("RingCheck empty"); - return false; - } - const SkRegion* layers = mBestLayer; - const Type* layerTypes = &mLayerTypes[layers - mLayers.begin()]; - // back up to include text drawn before the best layer - SkRegion active = SkRegion(mBitBounds); - active.translate(-mBitBounds.x(), -mBitBounds.y()); - while (layers != mLayers.begin()) { - --layers; - Type layerType = *--layerTypes; - DBG_NAV_LOGD("RingCheck #%d %s" - " mTestBounds=(%d,%d,r=%d,b=%d) layers=(%d,%d,r=%d,b=%d)" - " active=(%d,%d,r=%d,b=%d)", - layers - mLayers.begin(), TypeNames[layerType], - mTestBounds.getBounds().fLeft, mTestBounds.getBounds().fTop, - mTestBounds.getBounds().fRight, mTestBounds.getBounds().fBottom, - layers->getBounds().fLeft, layers->getBounds().fTop, - layers->getBounds().fRight, layers->getBounds().fBottom, - active.getBounds().fLeft, active.getBounds().fTop, - active.getBounds().fRight, active.getBounds().fBottom); - if (layerType == kDrawRect_Type || layerType == kDrawBitmap_Type) { - SkRegion temp = *layers; - temp.op(mTestBounds, SkRegion::kIntersect_Op); - active.op(temp, SkRegion::kDifference_Op); - if (active.isEmpty()) { - DBG_NAV_LOGD("RingCheck #%d empty", layers - mLayers.begin()); - break; - } - } else if (layerType == kDrawGlyph_Type) { - SkRegion temp = *layers; - temp.op(active, SkRegion::kIntersect_Op); - if (!mTestBounds.intersects(temp)) - continue; - if (!mTestBounds.contains(temp)) - return false; - } else - break; - } - layers = mBestLayer; - layerTypes = &mLayerTypes[layers - mLayers.begin()]; - bool foundGlyph = false; - bool collectGlyphs = true; - do { - Type layerType = *layerTypes++; - DBG_NAV_LOGD("RingCheck #%d %s mTestBounds=(%d,%d,r=%d,b=%d)" - " layers=(%d,%d,r=%d,b=%d) collects=%s intersects=%s contains=%s", - layers - mLayers.begin(), TypeNames[layerType], - mTestBounds.getBounds().fLeft, mTestBounds.getBounds().fTop, - mTestBounds.getBounds().fRight, mTestBounds.getBounds().fBottom, - layers->getBounds().fLeft, layers->getBounds().fTop, - layers->getBounds().fRight, layers->getBounds().fBottom, - collectGlyphs ? "true" : "false", - mTestBounds.intersects(*layers) ? "true" : "false", - mTextSlop.contains(*layers) ? "true" : "false"); - if (collectGlyphs && layerType == kDrawGlyph_Type) { - if (!mTestBounds.intersects(*layers)) - continue; - if (!mTextSlop.contains(*layers)) - return false; - foundGlyph = true; - } - collectGlyphs &= layerType != kPushLayer_Type; - } while (++layers != mLayers.end()); - DBG_NAV_LOGD("RingCheck foundGlyph=%s", foundGlyph ? "true" : "false"); - return foundGlyph; - } - -protected: - virtual bool onIRect(const SkIRect& rect) - { - joinGlyphs(rect); - if (mType != kDrawGlyph_Type && mType != kDrawRect_Type - && mType != kDrawSprite_Type && mType != kDrawBitmap_Type) - return false; - if (mLayerTypes.isEmpty() || mLayerTypes.last() != mType - || !mAppendLikeTypes || mPushPop || mSingleImage - // if the last and current were not glyphs, - // and the two bounds have a gap between, don't join them -- push - // an empty between them - || (mType != kDrawGlyph_Type && !joinable(rect))) { - push(mType, mEmpty); - } - DBG_NAV_LOGD("RingCheck join %s (%d,%d,r=%d,b=%d) '%c'", - TypeNames[mType], rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, - mCh); - mLayers.last().op(rect, SkRegion::kUnion_Op); - mAppendLikeTypes = true; - mPushPop = false; - return false; - } - - virtual bool onIRectGlyph(const SkIRect& rect, - const SkBounder::GlyphRec& rec) - { - mCh = ' '; - if (mPaint) { - SkUnichar unichar; - SkPaint utfPaint = *mPaint; - utfPaint.setTextEncoding(SkPaint::kUTF16_TextEncoding); - utfPaint.glyphsToUnichars(&rec.fGlyphID, 1, &unichar); - mCh = unichar < 0x7f ? unichar : '?'; - } - return onIRect(rect); - } - -private: - int calcOverlap(SkRegion& testRegion) - { - if (testRegion.isEmpty()) - return INT_MAX; - testRegion.op(mTextTest, SkRegion::kXOR_Op); - SkRegion::Iterator iter(testRegion); - int area = 0; - while (!iter.done()) { - const SkIRect& cr = iter.rect(); - area += cr.width() * cr.height(); - iter.next(); - } - DBG_NAV_LOGD("RingCheck area=%d", area); - return area; - } - - void findBestLayer() - { - popEmpty(); - mBestLayer = 0; - const SkRegion* layers = mLayers.begin(); - const SkRegion* layersEnd = mLayers.end(); - if (layers == layersEnd) { - DBG_NAV_LOG("RingCheck empty"); - return; - } - // find text most like focus rings by xoring found with original - int bestArea = INT_MAX; - const SkRegion* testLayer = 0; - SkRegion testRegion; - const Type* layerTypes = &mLayerTypes[layers - mLayers.begin()]; - for (; layers != mLayers.end(); layers++) { - Type layerType = *layerTypes++; -#if DEBUG_NAV_UI - const SkIRect& gb = layers->getBounds(); - const SkIRect& tb = mTextSlop.getBounds(); - DBG_NAV_LOGD("RingCheck #%d %s mTextSlop=(%d,%d,%d,%d)" - " contains=%s bounds=(%d,%d,%d,%d)", - layers - mLayers.begin(), TypeNames[layerType], - tb.fLeft, tb.fTop, tb.fRight, tb.fBottom, - mTextSlop.contains(*layers) ? "true" : "false", - gb.fLeft, gb.fTop, gb.fRight, gb.fBottom); -#endif - if (((layerType == kDrawGlyph_Type || layerType == kDrawBitmap_Type) - && mTextSlop.contains(*layers)) - || (layerType == kDrawRect_Type - && mTextTest.contains(*layers))) { - if (!testLayer) - testLayer = layers; - testRegion.op(*layers, SkRegion::kUnion_Op); - continue; - } - if (testLayer) { - int area = calcOverlap(testRegion); - if (bestArea > area) { - bestArea = area; - mBestLayer = testLayer; - } - DBG_NAV_LOGD("RingCheck #%d push test=%d best=%d", - layers - mLayers.begin(), testLayer - mLayers.begin(), - mBestLayer ? mBestLayer - mLayers.begin() : -1); - testRegion.setEmpty(); - testLayer = 0; - } - } - if (testLayer && bestArea > calcOverlap(testRegion)) { - DBG_NAV_LOGD("RingCheck last best=%d", testLayer - mLayers.begin()); - mBestLayer = testLayer; - } - } - - bool joinable(const SkIRect& rect) - { - SkRegion region = mLayers.last(); - if (!region.isRect()) - return false; - const SkIRect& bounds1 = region.getBounds(); - int area1 = bounds1.width() * bounds1.height(); - area1 += rect.width() * rect.height(); - region.op(rect, SkRegion::kUnion_Op); - const SkIRect& bounds2 = region.getBounds(); - int area2 = bounds2.width() * bounds2.height(); - return area2 <= area1; - } - - void popEmpty() - { - if (mLayerTypes.size() == 0) - return; - Type last = mLayerTypes.last(); - if (last >= kPopLayer_Type) - return; - const SkRegion& area = mLayers.last(); - if (!area.isEmpty()) - return; - DBG_NAV_LOGD("RingCheck #%d %s", mLayers.size() - 1, TypeNames[last]); - mLayers.removeLast(); - mLayerTypes.removeLast(); - } - - SkRegion mTestBounds; - IntRect mBitBounds; - SkIRect mEmpty; - const SkRegion* mBestLayer; - SkRegion mTextSlop; // outset rects for inclusion test - SkRegion mTextTest; // exact rects for xor area test - Type mLastType; - Vector<SkRegion> mLayers; - Vector<Type> mLayerTypes; - const SkPaint* mPaint; - char mCh; - bool mAppendLikeTypes; - bool mPushPop; - bool mSingleImage; -}; - -class RingCanvas : public BoundsCanvas { -public: - RingCanvas(RingCheck* bounder) - : INHERITED(bounder) - { - } - -protected: - virtual void drawText(const void* text, size_t byteLength, SkScalar x, - SkScalar y, const SkPaint& paint) { - static_cast<RingCheck&>(mBounder).startText(paint); - INHERITED::drawText(text, byteLength, x, y, paint); - } - - virtual void drawPosText(const void* text, size_t byteLength, - const SkPoint pos[], const SkPaint& paint) { - static_cast<RingCheck&>(mBounder).startText(paint); - INHERITED::drawPosText(text, byteLength, pos, paint); - } - - virtual void drawTextOnPath(const void* text, size_t byteLength, - const SkPath& path, const SkMatrix* matrix, - const SkPaint& paint) { - static_cast<RingCheck&>(mBounder).startText(paint); - INHERITED::drawTextOnPath(text, byteLength, path, matrix, paint); - } - - virtual void drawPosTextH(const void* text, size_t byteLength, - const SkScalar xpos[], SkScalar constY, - const SkPaint& paint) { - static_cast<RingCheck&>(mBounder).startText(paint); - INHERITED::drawPosTextH(text, byteLength, xpos, constY, paint); - } - - virtual int save(SaveFlags flags) - { - RingCheck& bounder = static_cast<RingCheck&>(mBounder); - bounder.push(CommonCheck::kPushSave_Type, getTotalClip().getBounds()); - return INHERITED::save(flags); - } - - virtual int saveLayer(const SkRect* bounds, const SkPaint* paint, - SaveFlags flags) - { - RingCheck& bounder = static_cast<RingCheck&>(mBounder); - bounder.push(CommonCheck::kPushLayer_Type, getTotalClip().getBounds()); - return INHERITED::save(flags); - } - - virtual void restore() - { - RingCheck& bounder = static_cast<RingCheck&>(mBounder); - bounder.push(CommonCheck::kPopLayer_Type, getTotalClip().getBounds()); - INHERITED::restore(); - } - -private: - typedef BoundsCanvas INHERITED; -}; - -bool CachedRoot::adjustForScroll(BestData* best, CachedFrame::Direction direction, - WebCore::IntPoint* scrollPtr, bool findClosest) -{ - WebCore::IntRect newOutset; - const CachedNode* newNode = best->mNode; - // see if there's a middle node - // if the middle node is in the visited list, - // or if none was computed and the newNode is in the visited list, - // treat result as NULL - if (newNode != NULL && findClosest) { - if (best->bounds().intersects(mHistory->mPriorBounds) == false && - checkBetween(best, direction)) - newNode = best->mNode; - if (findClosest && maskIfHidden(best)) { - innerMove(document(), best, direction, scrollPtr, false); - return true; - } - newOutset = newNode->cursorRingBounds(best->mFrame); - } - int delta; - bool newNodeInView = scrollDelta(newOutset, direction, &delta); - if (delta && scrollPtr && (newNode == NULL || newNodeInView == false || - (best->mNavOutside && best->mWorkingOutside))) - *scrollPtr = WebCore::IntPoint(direction & UP_DOWN ? 0 : delta, - direction & UP_DOWN ? delta : 0); - return false; -} - -void CachedRoot::calcBitBounds(const IntRect& nodeBounds, IntRect* bitBounds) const -{ - IntRect contentBounds = IntRect(0, 0, mPicture->width(), mPicture->height()); - IntRect overBounds = nodeBounds; - overBounds.inflate(kMargin); - IntRect viewableBounds = mScrolledBounds; - viewableBounds.unite(mViewBounds); - *bitBounds = contentBounds; - bitBounds->intersect(overBounds); - if (!bitBounds->intersects(viewableBounds)) - *bitBounds = IntRect(0, 0, 0, 0); - DBG_NAV_LOGD("contentBounds=(%d,%d,r=%d,b=%d) overBounds=(%d,%d,r=%d,b=%d)" - " mScrolledBounds=(%d,%d,r=%d,b=%d) mViewBounds=(%d,%d,r=%d,b=%d)" - " bitBounds=(%d,%d,r=%d,b=%d)", - contentBounds.x(), contentBounds.y(), contentBounds.maxX(), - contentBounds.maxY(), - overBounds.x(), overBounds.y(), overBounds.maxX(), overBounds.maxY(), - mScrolledBounds.x(), mScrolledBounds.y(), mScrolledBounds.maxX(), - mScrolledBounds.maxY(), - mViewBounds.x(), mViewBounds.y(), mViewBounds.maxX(), - mViewBounds.maxY(), - bitBounds->x(), bitBounds->y(), bitBounds->maxX(), - bitBounds->maxY()); -} - - -int CachedRoot::checkForCenter(int x, int y) const -{ - int width = mViewBounds.width(); - SkPicture* picture = pictureAt(&x, &y); - CenterCheck centerCheck(x + width - mViewBounds.x(), y - mViewBounds.y(), - width); - BoundsCanvas checker(¢erCheck); - SkBitmap bitmap; - bitmap.setConfig(SkBitmap::kARGB_8888_Config, width * 3, - mViewBounds.height()); - checker.setBitmapDevice(bitmap); - checker.translate(SkIntToScalar(width - mViewBounds.x()), - SkIntToScalar(-mViewBounds.y())); - checker.drawPicture(*picture); - return centerCheck.center(); -} - -void CachedRoot::checkForJiggle(int* xDeltaPtr) const -{ - int xDelta = *xDeltaPtr; - JiggleCheck jiggleCheck(xDelta, mViewBounds.width()); - BoundsCanvas checker(&jiggleCheck); - SkBitmap bitmap; - int absDelta = abs(xDelta); - bitmap.setConfig(SkBitmap::kARGB_8888_Config, mViewBounds.width() + - absDelta, mViewBounds.height()); - checker.setBitmapDevice(bitmap); - int x = -mViewBounds.x() - (xDelta < 0 ? xDelta : 0); - int y = -mViewBounds.y(); - SkPicture* picture = pictureAt(&x, &y); - checker.translate(SkIntToScalar(x), SkIntToScalar(y)); - checker.drawPicture(*picture); - *xDeltaPtr = jiggleCheck.jiggle(); -} - -bool CachedRoot::checkRings(SkPicture* picture, const CachedNode* node, - const WebCore::IntRect& testBounds) const -{ - if (!picture) - return false; - const WTF::Vector<WebCore::IntRect>& rings = node->rings(); - const WebCore::IntRect& nodeBounds = node->rawBounds(); - IntRect bitBounds; - calcBitBounds(nodeBounds, &bitBounds); - RingCheck ringCheck(rings, bitBounds, testBounds, node->singleImage()); - RingCanvas checker(&ringCheck); - SkBitmap bitmap; - bitmap.setConfig(SkBitmap::kARGB_8888_Config, bitBounds.width(), - bitBounds.height()); - checker.setBitmapDevice(bitmap); - checker.translate(SkIntToScalar(-bitBounds.x()), - SkIntToScalar(-bitBounds.y())); - checker.drawPicture(*picture); - bool result = ringCheck.textOutsideRings(); - DBG_NAV_LOGD("bitBounds=(%d,%d,r=%d,b=%d) nodeBounds=(%d,%d,r=%d,b=%d)" - " testBounds=(%d,%d,r=%d,b=%d) success=%s", - bitBounds.x(), bitBounds.y(), bitBounds.maxX(), bitBounds.maxY(), - nodeBounds.x(), nodeBounds.y(), nodeBounds.maxX(), nodeBounds.maxY(), - testBounds.x(), testBounds.y(), testBounds.maxX(), testBounds.maxY(), - result ? "true" : "false"); - return result; -} - -void CachedRoot::draw(FindCanvas& canvas) const -{ - canvas.setLayerId(-1); // overlays change the ID as their pictures draw - canvas.drawPicture(*mPicture); -#if USE(ACCELERATED_COMPOSITING) - if (!mRootLayer) - return; - canvas.drawLayers(mRootLayer); -#endif -} - -const CachedNode* CachedRoot::findAt(const WebCore::IntRect& rect, - const CachedFrame** framePtr, int* x, int* y, bool checkForHidden) const -{ -#if DEBUG_NAV_UI - DBG_NAV_LOGD("rect=(%d,%d,w=%d,h=%d) xy=(%d,%d)", rect.x(), rect.y(), - rect.width(), rect.height(), *x, *y); -#if DUMP_NAV_CACHE - if (mRootLayer) CachedLayer::Debug::printRootLayerAndroid(mRootLayer); -#endif -#endif - int best = INT_MAX; - bool inside = false; - (const_cast<CachedRoot*>(this))->resetClippedOut(); - const CachedFrame* directHitFramePtr; - const CachedNode* directHit = NULL; - const CachedNode* node = findBestAt(rect, &best, &inside, &directHit, - &directHitFramePtr, framePtr, x, y, checkForHidden); - DBG_NAV_LOGD("node=%d (%p) xy=(%d,%d)", node == NULL ? 0 : node->index(), - node == NULL ? NULL : node->nodePointer(), *x, *y); - if (node == NULL) { - node = findBestHitAt(rect, framePtr, x, y); - DBG_NAV_LOGD("node=%d (%p)", node == NULL ? 0 : node->index(), - node == NULL ? NULL : node->nodePointer()); - } - if (node == NULL) { - *framePtr = findBestFrameAt(rect.x() + (rect.width() >> 1), - rect.y() + (rect.height() >> 1)); - } - return node; -} - -WebCore::IntPoint CachedRoot::cursorLocation() const -{ - const WebCore::IntRect& bounds = mHistory->mNavBounds; - return WebCore::IntPoint(bounds.x() + (bounds.width() >> 1), - bounds.y() + (bounds.height() >> 1)); -} - -WebCore::IntPoint CachedRoot::focusLocation() const -{ - return WebCore::IntPoint(mFocusBounds.x() + (mFocusBounds.width() >> 1), - mFocusBounds.y() + (mFocusBounds.height() >> 1)); -} - -// These reset the values because we only want to get the selection the first time. -// After that, the selection is no longer accurate. -int CachedRoot::getAndResetSelectionEnd() -{ - int end = mSelectionEnd; - mSelectionEnd = -1; - return end; -} - -int CachedRoot::getAndResetSelectionStart() -{ - int start = mSelectionStart; - mSelectionStart = -1; - return start; -} - -int CachedRoot::getBlockLeftEdge(int x, int y, float scale) const -{ - DBG_NAV_LOGD("x=%d y=%d scale=%g mViewBounds=(%d,%d,%d,%d)", x, y, scale, - mViewBounds.x(), mViewBounds.y(), mViewBounds.width(), - mViewBounds.height()); - // if (x, y) is in a textArea or textField, return that - const int slop = 1; - WebCore::IntRect rect = WebCore::IntRect(x - slop, y - slop, - slop * 2, slop * 2); - const CachedFrame* frame; - int fx, fy; - const CachedNode* node = findAt(rect, &frame, &fx, &fy, true); - if (node && node->wantsKeyEvents()) { - DBG_NAV_LOGD("x=%d (%s)", node->bounds(frame).x(), - node->isTextInput() ? "text" : "plugin"); - return node->bounds(frame).x(); - } - SkPicture* picture = node ? frame->picture(node, &x, &y) : pictureAt(&x, &y); - if (!picture) - return x; - int halfW = (int) (mViewBounds.width() * scale * 0.5f); - int fullW = halfW << 1; - int halfH = (int) (mViewBounds.height() * scale * 0.5f); - int fullH = halfH << 1; - LeftCheck leftCheck(fullW, halfH); - BoundsCanvas checker(&leftCheck); - SkBitmap bitmap; - bitmap.setConfig(SkBitmap::kARGB_8888_Config, fullW, fullH); - checker.setBitmapDevice(bitmap); - checker.translate(SkIntToScalar(fullW - x), SkIntToScalar(halfH - y)); - checker.drawPicture(*picture); - int result = x + leftCheck.left() - fullW; - DBG_NAV_LOGD("halfW=%d halfH=%d mMostLeft=%d x=%d", - halfW, halfH, leftCheck.mMostLeft, result); - return result; -} - -void CachedRoot::getSimulatedMousePosition(WebCore::IntPoint* point) const -{ -#ifndef NDEBUG - ASSERT(CachedFrame::mDebug.mInUse); -#endif - const WebCore::IntRect& mouseBounds = mHistory->mMouseBounds; - int x = mouseBounds.x(); - int y = mouseBounds.y(); - int width = mouseBounds.width(); - int height = mouseBounds.height(); - point->setX(x + (width >> 1)); // default to box center - point->setY(y + (height >> 1)); -#if DEBUG_NAV_UI - const WebCore::IntRect& navBounds = mHistory->mNavBounds; - DBG_NAV_LOGD("mHistory->mNavBounds={%d,%d,%d,%d} " - "mHistory->mMouseBounds={%d,%d,%d,%d} point={%d,%d}", - navBounds.x(), navBounds.y(), navBounds.width(), navBounds.height(), - mouseBounds.x(), mouseBounds.y(), mouseBounds.width(), - mouseBounds.height(), point->x(), point->y()); -#endif -} - -void CachedRoot::init(WebCore::Frame* frame, CachedHistory* history) -{ - CachedFrame::init(this, -1, frame); - reset(); - mHistory = history; - mPicture = NULL; -} - -bool CachedRoot::innerDown(const CachedNode* test, BestData* bestData) const -{ - ASSERT(minWorkingVertical() >= mViewBounds.x()); - ASSERT(maxWorkingVertical() <= mViewBounds.maxX()); - setupScrolledBounds(); - // (line up) - mScrolledBounds.setHeight(mScrolledBounds.height() + mMaxYScroll); - int testTop = mScrolledBounds.y(); - int viewBottom = mViewBounds.maxY(); - const WebCore::IntRect& navBounds = mHistory->mNavBounds; - if (navBounds.isEmpty() == false && - navBounds.maxY() > viewBottom && viewBottom < mContents.height()) - return false; - if (navBounds.isEmpty() == false) { - int navTop = navBounds.y(); - int scrollBottom; - if (testTop < navTop && navTop < (scrollBottom = mScrolledBounds.maxY())) { - mScrolledBounds.setHeight(scrollBottom - navTop); - mScrolledBounds.setY(navTop); - } - } - setCursorCache(0, mMaxYScroll); - frameDown(test, NULL, bestData); - return true; -} - -bool CachedRoot::innerLeft(const CachedNode* test, BestData* bestData) const -{ - ASSERT(minWorkingHorizontal() >= mViewBounds.y()); - ASSERT(maxWorkingHorizontal() <= mViewBounds.maxY()); - setupScrolledBounds(); - mScrolledBounds.setX(mScrolledBounds.x() - mMaxXScroll); - mScrolledBounds.setWidth(mScrolledBounds.width() + mMaxXScroll); - int testRight = mScrolledBounds.maxX(); - int viewLeft = mViewBounds.x(); - const WebCore::IntRect& navBounds = mHistory->mNavBounds; - if (navBounds.isEmpty() == false && - navBounds.x() < viewLeft && viewLeft > mContents.x()) - return false; - if (navBounds.isEmpty() == false) { - int navRight = navBounds.maxX(); - int scrollLeft; - if (testRight > navRight && navRight > (scrollLeft = mScrolledBounds.x())) - mScrolledBounds.setWidth(navRight - scrollLeft); - } - setCursorCache(-mMaxXScroll, 0); - frameLeft(test, NULL, bestData); - return true; -} - - -void CachedRoot::innerMove(const CachedNode* node, BestData* bestData, - Direction direction, WebCore::IntPoint* scroll, bool firstCall) -{ - bestData->reset(); - bool outOfCursor = mCursorIndex == CURSOR_CLEARED; - DBG_NAV_LOGD("mHistory->didFirstLayout()=%s && mCursorIndex=%d", - mHistory->didFirstLayout() ? "true" : "false", mCursorIndex); - if (mHistory->didFirstLayout() && mCursorIndex < CURSOR_SET) { - mHistory->reset(); - outOfCursor = true; - } - const CachedFrame* cursorFrame; - const CachedNode* cursor = currentCursor(&cursorFrame); - mHistory->setWorking(direction, cursorFrame, cursor, mViewBounds); - bool findClosest = false; - if (mScrollOnly == false) { - switch (direction) { - case LEFT: - if (outOfCursor) - mHistory->mNavBounds = WebCore::IntRect(mViewBounds.maxX(), - mViewBounds.y(), 1, mViewBounds.height()); - findClosest = innerLeft(node, bestData); - break; - case RIGHT: - if (outOfCursor) - mHistory->mNavBounds = WebCore::IntRect(mViewBounds.x() - 1, - mViewBounds.y(), 1, mViewBounds.height()); - findClosest = innerRight(node, bestData); - break; - case UP: - if (outOfCursor) - mHistory->mNavBounds = WebCore::IntRect(mViewBounds.x(), - mViewBounds.maxY(), mViewBounds.width(), 1); - findClosest = innerUp(node, bestData); - break; - case DOWN: - if (outOfCursor) - mHistory->mNavBounds = WebCore::IntRect(mViewBounds.x(), - mViewBounds.y() - 1, mViewBounds.width(), 1); - findClosest = innerDown(node, bestData); - break; - case UNINITIALIZED: - default: - ASSERT(0); - } - } - if (firstCall) - mHistory->mPriorBounds = mHistory->mNavBounds; // bounds always advances, even if new node is ultimately NULL - bestData->setMouseBounds(bestData->bounds()); - if (adjustForScroll(bestData, direction, scroll, findClosest)) - return; - if (bestData->mNode != NULL) { - mHistory->addToVisited(bestData->mNode, direction); - mHistory->mNavBounds = bestData->bounds(); - mHistory->mMouseBounds = bestData->mouseBounds(); - } else if (scroll->x() != 0 || scroll->y() != 0) { - WebCore::IntRect newBounds = mHistory->mNavBounds; - int offsetX = scroll->x(); - int offsetY = scroll->y(); - newBounds.move(offsetX, offsetY); - if (mViewBounds.x() > newBounds.x()) - offsetX = mViewBounds.x() - mHistory->mNavBounds.x(); - else if (mViewBounds.maxX() < newBounds.maxX()) - offsetX = mViewBounds.maxX() - mHistory->mNavBounds.maxX(); - if (mViewBounds.y() > newBounds.y()) - offsetY = mViewBounds.y() - mHistory->mNavBounds.y(); - else if (mViewBounds.maxY() < newBounds.maxY()) - offsetY = mViewBounds.maxY() - mHistory->mNavBounds.maxY(); - mHistory->mNavBounds.move(offsetX, offsetY); - } - mHistory->setDidFirstLayout(false); -} - -bool CachedRoot::innerRight(const CachedNode* test, BestData* bestData) const -{ - ASSERT(minWorkingHorizontal() >= mViewBounds.y()); - ASSERT(maxWorkingHorizontal() <= mViewBounds.maxY()); - setupScrolledBounds(); - // (align) - mScrolledBounds.setWidth(mScrolledBounds.width() + mMaxXScroll); - int testLeft = mScrolledBounds.x(); - int viewRight = mViewBounds.maxX(); - const WebCore::IntRect& navBounds = mHistory->mNavBounds; - if (navBounds.isEmpty() == false && - navBounds.maxX() > viewRight && viewRight < mContents.width()) - return false; - if (navBounds.isEmpty() == false) { - int navLeft = navBounds.x(); - int scrollRight; - if (testLeft < navLeft && navLeft < (scrollRight = mScrolledBounds.maxX())) { - mScrolledBounds.setWidth(scrollRight - navLeft); - mScrolledBounds.setX(navLeft); - } - } - setCursorCache(mMaxXScroll, 0); - frameRight(test, NULL, bestData); - return true; -} - -bool CachedRoot::innerUp(const CachedNode* test, BestData* bestData) const -{ - ASSERT(minWorkingVertical() >= mViewBounds.x()); - ASSERT(maxWorkingVertical() <= mViewBounds.maxX()); - setupScrolledBounds(); - mScrolledBounds.setY(mScrolledBounds.y() - mMaxYScroll); - mScrolledBounds.setHeight(mScrolledBounds.height() + mMaxYScroll); - int testBottom = mScrolledBounds.maxY(); - int viewTop = mViewBounds.y(); - const WebCore::IntRect& navBounds = mHistory->mNavBounds; - if (navBounds.isEmpty() == false && - navBounds.y() < viewTop && viewTop > mContents.y()) - return false; - if (navBounds.isEmpty() == false) { - int navBottom = navBounds.maxY(); - int scrollTop; - if (testBottom > navBottom && navBottom > (scrollTop = mScrolledBounds.y())) - mScrolledBounds.setHeight(navBottom - scrollTop); - } - setCursorCache(0, -mMaxYScroll); - frameUp(test, NULL, bestData); - return true; -} - -WTF::String CachedRoot::imageURI(int x, int y) const -{ - DBG_NAV_LOGD("x/y=(%d,%d)", x, y); - ImageCheck imageCheck; - ImageCanvas checker(&imageCheck); - SkBitmap bitmap; - bitmap.setConfig(SkBitmap::kARGB_8888_Config, 1, 1); - checker.setBitmapDevice(bitmap); - SkPicture* picture = pictureAt(&x, &y); - checker.translate(SkIntToScalar(-x), SkIntToScalar(-y)); - checker.drawPicture(*picture); - DBG_NAV_LOGD("uri=%s", checker.getURI()); - return WTF::String(checker.getURI()); -} - -bool CachedRoot::maskIfHidden(BestData* best) const -{ - const CachedNode* bestNode = best->mNode; - if (bestNode->isUnclipped()) - return false; - const CachedFrame* frame = best->mFrame; - SkPicture* picture = frame->picture(bestNode); - if (picture == NULL) { - DBG_NAV_LOG("missing picture"); - return false; - } - Vector<IntRect> rings; - bestNode->cursorRings(frame, &rings); - const WebCore::IntRect& bounds = bestNode->bounds(frame); - IntRect bitBounds; - calcBitBounds(bounds, &bitBounds); - RingCheck ringCheck(rings, bitBounds, bounds, bestNode->singleImage()); - RingCanvas checker(&ringCheck); - SkBitmap bitmap; - bitmap.setConfig(SkBitmap::kARGB_8888_Config, bitBounds.width(), - bitBounds.height()); - checker.setBitmapDevice(bitmap); - checker.translate(SkIntToScalar(-bitBounds.x()), - SkIntToScalar(-bitBounds.y())); - checker.drawPicture(*picture); - SkRegion clipRgn; - bool clipped = ringCheck.hiddenRings(&clipRgn); - CachedNode* node = const_cast<CachedNode*>(best->mNode); - DBG_NAV_LOGD("clipped=%s clipRgn.isEmpty=%s", clipped ? "true" : "false", - clipRgn.isEmpty() ? "true" : "false"); - if (clipped && clipRgn.isEmpty()) { - node->setDisabled(true); - IntRect clippedBounds = bounds; - clippedBounds.intersect(bitBounds); - node->setClippedOut(clippedBounds != bounds); - return true; - } - // was it partially occluded by later drawing? - // if partially occluded, modify the bounds so that the mouse click has a better x,y - if (clipped) { - DBG_NAV_LOGD("clipped clipRgn={%d,%d,r=%d,b=%d}", - clipRgn.getBounds().fLeft, clipRgn.getBounds().fTop, - clipRgn.getBounds().fRight, clipRgn.getBounds().fBottom); - best->setMouseBounds(clipRgn.getBounds()); - if (!node->clip(best->mouseBounds())) { - node->setDisabled(true); - node->setClippedOut(true); - return true; - } - } else - node->fixUpCursorRects(frame); - return false; -} - -const CachedNode* CachedRoot::moveCursor(Direction direction, const CachedFrame** framePtr, - WebCore::IntPoint* scroll) -{ -#ifndef NDEBUG - ASSERT(CachedFrame::mDebug.mInUse); -#endif - CachedRoot* frame = this; - const CachedNode* node = frame->document(); - if (node == NULL) - return NULL; - if (mViewBounds.isEmpty()) - return NULL; - resetClippedOut(); - setData(); - BestData bestData; - innerMove(node, &bestData, direction, scroll, true); - // if node is partially or fully concealed by layer, scroll it into view - if (mRootLayer && bestData.mNode && !bestData.mNode->isInLayer()) { -#if USE(ACCELERATED_COMPOSITING) -#if DUMP_NAV_CACHE - CachedLayer::Debug::printRootLayerAndroid(mRootLayer); -#endif - SkIRect original = bestData.mNode->cursorRingBounds(bestData.mFrame); - DBG_NAV_LOGD("original=(%d,%d,w=%d,h=%d) scroll=(%d,%d)", - original.fLeft, original.fTop, original.width(), original.height(), - scroll->x(), scroll->y()); - original.offset(-scroll->x(), -scroll->y()); - SkRegion rings(original); - SkTDArray<SkRect> region; - mRootLayer->clipArea(®ion); - SkRegion layers; - for (int index = 0; index < region.count(); index++) { - SkIRect enclosing; - region[index].round(&enclosing); - rings.op(enclosing, SkRegion::kDifference_Op); - layers.op(enclosing, SkRegion::kUnion_Op); - } - SkIRect layerBounds(layers.getBounds()); - SkIRect ringBounds(rings.getBounds()); - int scrollX = scroll->x(); - int scrollY = scroll->y(); - if (rings.getBounds() != original) { - int topOverlap = layerBounds.fBottom - original.fTop; - int bottomOverlap = original.fBottom - layerBounds.fTop; - int leftOverlap = layerBounds.fRight - original.fLeft; - int rightOverlap = original.fRight - layerBounds.fLeft; - if (direction & UP_DOWN) { - if (layerBounds.fLeft < original.fLeft && leftOverlap < 0) - scroll->setX(leftOverlap); - if (original.fRight < layerBounds.fRight && rightOverlap > 0 - && -leftOverlap > rightOverlap) - scroll->setX(rightOverlap); - bool topSet = scrollY > topOverlap && (direction == UP - || !scrollY); - if (topSet) - scroll->setY(topOverlap); - if (scrollY < bottomOverlap && (direction == DOWN || (!scrollY - && (!topSet || -topOverlap > bottomOverlap)))) - scroll->setY(bottomOverlap); - } else { - if (layerBounds.fTop < original.fTop && topOverlap < 0) - scroll->setY(topOverlap); - if (original.fBottom < layerBounds.fBottom && bottomOverlap > 0 - && -topOverlap > bottomOverlap) - scroll->setY(bottomOverlap); - bool leftSet = scrollX > leftOverlap && (direction == LEFT - || !scrollX); - if (leftSet) - scroll->setX(leftOverlap); - if (scrollX < rightOverlap && (direction == RIGHT || (!scrollX - && (!leftSet || -leftOverlap > rightOverlap)))) - scroll->setX(rightOverlap); - } - DBG_NAV_LOGD("rings=(%d,%d,w=%d,h=%d) layers=(%d,%d,w=%d,h=%d)" - " scroll=(%d,%d)", - ringBounds.fLeft, ringBounds.fTop, ringBounds.width(), ringBounds.height(), - layerBounds.fLeft, layerBounds.fTop, layerBounds.width(), layerBounds.height(), - scroll->x(), scroll->y()); - } -#endif - } - *framePtr = bestData.mFrame; - return const_cast<CachedNode*>(bestData.mNode); -} - -const CachedNode* CachedRoot::nextTextField(const CachedNode* start, - const CachedFrame** framePtr) const -{ - bool startFound = false; - return CachedFrame::nextTextField(start, framePtr, &startFound); -} - -SkPicture* CachedRoot::pictureAt(int* xPtr, int* yPtr, int* id) const -{ -#if USE(ACCELERATED_COMPOSITING) - if (mRootLayer) { - const LayerAndroid* layer = mRootLayer->find(xPtr, yPtr, mPicture); - if (layer) { - SkPicture* picture = layer->picture(); - DBG_NAV_LOGD("layer %d picture=%p (%d,%d)", layer->uniqueId(), - picture, picture ? picture->width() : 0, - picture ? picture->height() : 0); - if (picture) { - if (id) - *id = layer->uniqueId(); - return picture; - } - } - } -#endif - DBG_NAV_LOGD("root mPicture=%p (%d,%d)", mPicture, mPicture ? - mPicture->width() : 0, mPicture ? mPicture->height() : 0); - if (id) - *id = -1; - return mPicture; -} - -void CachedRoot::reset() -{ -#ifndef NDEBUG - ASSERT(CachedFrame::mDebug.mInUse); -#endif - mContents = mViewBounds = WebCore::IntRect(0, 0, 0, 0); - mMaxXScroll = mMaxYScroll = 0; - mRootLayer = 0; - mSelectionStart = mSelectionEnd = -1; - mScrollOnly = false; -} - -bool CachedRoot::scrollDelta(WebCore::IntRect& newOutset, Direction direction, int* delta) -{ - switch (direction) { - case LEFT: - *delta = -mMaxXScroll; - return newOutset.x() >= mViewBounds.x(); - case RIGHT: - *delta = mMaxXScroll; - return newOutset.maxX() <= mViewBounds.maxX(); - case UP: - *delta = -mMaxYScroll; - return newOutset.y() >= mViewBounds.y(); - case DOWN: - *delta = mMaxYScroll; - return newOutset.maxY() <= mViewBounds.maxY(); - default: - *delta = 0; - ASSERT(0); - } - return false; -} - -void CachedRoot::setCachedFocus(CachedFrame* frame, CachedNode* node) -{ - mFocusBounds = WebCore::IntRect(0, 0, 0, 0); - if (node == NULL) - return; - node->setIsFocus(true); - mFocusBounds = node->bounds(frame); - frame->setFocusIndex(node - frame->document()); - CachedFrame* parent; - while ((parent = frame->parent()) != NULL) { - parent->setFocusIndex(frame->indexInParent()); - frame = parent; - } -#if DEBUG_NAV_UI - const CachedFrame* focusFrame; - const CachedNode* focus = currentFocus(&focusFrame); - WebCore::IntRect bounds = WebCore::IntRect(0, 0, 0, 0); - if (focus) - bounds = focus->bounds(focusFrame); - DBG_NAV_LOGD("new focus %d (nodePointer=%p) bounds={%d,%d,%d,%d}", - focus ? focus->index() : 0, - focus ? focus->nodePointer() : NULL, bounds.x(), bounds.y(), - bounds.width(), bounds.height()); -#endif -} - -void CachedRoot::setCursor(CachedFrame* frame, CachedNode* node) -{ -#if DEBUG_NAV_UI - const CachedFrame* cursorFrame; - const CachedNode* cursor = currentCursor(&cursorFrame); - WebCore::IntRect bounds; - if (cursor) - bounds = cursor->bounds(cursorFrame); - DBG_NAV_LOGD("old cursor %d (nodePointer=%p) bounds={%d,%d,%d,%d}", - cursor ? cursor->index() : 0, - cursor ? cursor->nodePointer() : NULL, bounds.x(), bounds.y(), - bounds.width(), bounds.height()); -#endif - clearCursor(); - if (node == NULL) - return; - node->setIsCursor(true); - node->show(); - frame->setCursorIndex(node - frame->document()); - CachedFrame* parent; - while ((parent = frame->parent()) != NULL) { - parent->setCursorIndex(frame->indexInParent()); - frame = parent; - } -#if DEBUG_NAV_UI - cursor = currentCursor(&cursorFrame); - bounds = WebCore::IntRect(0, 0, 0, 0); - if (cursor) - bounds = cursor->bounds(cursorFrame); - DBG_NAV_LOGD("new cursor %d (nodePointer=%p) bounds={%d,%d,%d,%d}", - cursor ? cursor->index() : 0, - cursor ? cursor->nodePointer() : NULL, bounds.x(), bounds.y(), - bounds.width(), bounds.height()); -#endif -} - -void CachedRoot::setCursorCache(int scrollX, int scrollY) const -{ - mCursor = currentCursor(); - if (mCursor) - mCursorBounds = mCursor->bounds(this); - if (!mRootLayer) - return; - SkRegion baseScrolled(mScrolledBounds); - mBaseUncovered = SkRegion(mScrolledBounds); -#if USE(ACCELERATED_COMPOSITING) -#if DUMP_NAV_CACHE - CachedLayer::Debug::printRootLayerAndroid(mRootLayer); -#endif - SkTDArray<SkRect> region; - mRootLayer->clipArea(®ion); - WebCore::IntSize offset( - copysign(min(max(0, mContents.width() - mScrolledBounds.width()), - abs(scrollX)), scrollX), - copysign(min(max(0, mContents.height() - mScrolledBounds.height()), - abs(scrollY)), scrollY)); - bool hasOffset = offset.width() || offset.height(); - // restrict scrollBounds to that which is not under layer - for (int index = 0; index < region.count(); index++) { - SkIRect less; - region[index].round(&less); - DBG_NAV_LOGD("less=(%d,%d,w=%d,h=%d)", less.fLeft, less.fTop, - less.width(), less.height()); - mBaseUncovered.op(less, SkRegion::kDifference_Op); - if (!hasOffset) - continue; - less.offset(offset.width(), offset.height()); - baseScrolled.op(less, SkRegion::kDifference_Op); - } - if (hasOffset) - mBaseUncovered.op(baseScrolled, SkRegion::kUnion_Op); -#endif -} - -#if DUMP_NAV_CACHE - -#define DEBUG_PRINT_BOOL(field) \ - DUMP_NAV_LOGD("// bool " #field "=%s;\n", b->field ? "true" : "false") - -#define DEBUG_PRINT_RECT(field) \ - { const WebCore::IntRect& r = b->field; \ - DUMP_NAV_LOGD("// IntRect " #field "={%d, %d, %d, %d};\n", \ - r.x(), r.y(), r.width(), r.height()); } - -CachedRoot* CachedRoot::Debug::base() const { - CachedRoot* nav = (CachedRoot*) ((char*) this - OFFSETOF(CachedRoot, mDebug)); - return nav; -} - -void CachedRoot::Debug::print() const -{ -#ifdef DUMP_NAV_CACHE_USING_PRINTF - gWriteLogMutex.lock(); - ASSERT(gNavCacheLogFile == NULL); - gNavCacheLogFile = fopen(NAV_CACHE_LOG_FILE, "a"); -#endif - CachedRoot* b = base(); - b->CachedFrame::mDebug.print(); - b->mHistory->mDebug.print(b); - DUMP_NAV_LOGD("// int mMaxXScroll=%d, mMaxYScroll=%d;\n", - b->mMaxXScroll, b->mMaxYScroll); - if (b->mRootLayer) - CachedLayer::Debug::printRootLayerAndroid(b->mRootLayer); -#ifdef DUMP_NAV_CACHE_USING_PRINTF - if (gNavCacheLogFile) - fclose(gNavCacheLogFile); - gNavCacheLogFile = NULL; - gWriteLogMutex.unlock(); -#endif -} - -#endif - -} diff --git a/Source/WebKit/android/nav/CachedRoot.h b/Source/WebKit/android/nav/CachedRoot.h deleted file mode 100644 index 65c6062..0000000 --- a/Source/WebKit/android/nav/CachedRoot.h +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright 2007, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef CachedRoot_h -#define CachedRoot_h - -#include "CachedFrame.h" -#include "IntRect.h" -#include "SkPicture.h" -#include "SkRegion.h" -#include "wtf/Vector.h" - -class SkRect; - -namespace WebCore { - class LayerAndroid; -} - -namespace android { - -class CachedHistory; -class CachedNode; -class FindCanvas; - -class CachedRoot : public CachedFrame { -public: - bool adjustForScroll(BestData* , Direction , WebCore::IntPoint* scrollPtr, - bool findClosest); - const SkRegion& baseUncovered() const { return mBaseUncovered; } - void calcBitBounds(const IntRect& , IntRect* ) const; - int checkForCenter(int x, int y) const; - void checkForJiggle(int* ) const; - bool checkRings(SkPicture* , const CachedNode* , - const WebCore::IntRect& testBounds) const; - WebCore::IntPoint cursorLocation() const; - int documentHeight() { return mContents.height(); } - int documentWidth() { return mContents.width(); } - void draw(FindCanvas& ) const; - const CachedNode* findAt(const WebCore::IntRect& , const CachedFrame** , - int* x, int* y, bool checkForHidden) const; - const WebCore::IntRect& focusBounds() const { return mFocusBounds; } - WebCore::IntPoint focusLocation() const; - int getAndResetSelectionEnd(); - int getAndResetSelectionStart(); - int getBlockLeftEdge(int x, int y, float scale) const; - void getSimulatedMousePosition(WebCore::IntPoint* ) const; - void init(WebCore::Frame* , CachedHistory* ); - bool innerDown(const CachedNode* , BestData* ) const; - bool innerLeft(const CachedNode* , BestData* ) const; - void innerMove(const CachedNode* ,BestData* bestData, Direction , - WebCore::IntPoint* scroll, bool firstCall); - bool innerRight(const CachedNode* , BestData* ) const; - bool innerUp(const CachedNode* , BestData* ) const; - WTF::String imageURI(int x, int y) const; - bool maskIfHidden(BestData* ) const; - const CachedNode* moveCursor(Direction , const CachedFrame** , WebCore::IntPoint* scroll); - /** - * Find the next textfield/textarea - * @param start The textfield/textarea to search from. - * @param framePtr If non-zero, returns CachedFrame* containing result. - * @return CachedNode* Next textfield/textarea or null (0) if none. - */ - const CachedNode* nextTextField(const CachedNode* start, - const CachedFrame** framePtr) const; - SkPicture* pictureAt(int* xPtr, int* yPtr, int* id) const; - SkPicture* pictureAt(int* xPtr, int* yPtr) const { - return pictureAt(xPtr, yPtr, 0); } - void reset(); - CachedHistory* rootHistory() const { return mHistory; } - WebCore::LayerAndroid* rootLayer() const { return mRootLayer; } - bool scrollDelta(WebCore::IntRect& cursorRingBounds, Direction , int* delta); - const WebCore::IntRect& scrolledBounds() const { return mScrolledBounds; } - void setCursor(CachedFrame* , CachedNode* ); - void setCursorCache(int scrollX, int scrollY) const; // compute cached state used to find next cursor - void setCachedFocus(CachedFrame* , CachedNode* ); - void setFocusBounds(const WebCore::IntRect& r) { mFocusBounds = r; } - void setTextGeneration(int textGeneration) { mTextGeneration = textGeneration; } - void setMaxScroll(int x, int y) { mMaxXScroll = x; mMaxYScroll = y; } - void setPicture(SkPicture* picture) { mPicture = picture; } - void setRootLayer(WebCore::LayerAndroid* layer) { - mRootLayer = layer; - resetLayers(); - } - void setScrollOnly(bool state) { mScrollOnly = state; } - void setSelection(int start, int end) { mSelectionStart = start; mSelectionEnd = end; } - void setupScrolledBounds() const { mScrolledBounds = mViewBounds; } - void setVisibleRect(const WebCore::IntRect& r) { mViewBounds = r; } - int textGeneration() const { return mTextGeneration; } - int width() const { return mPicture ? mPicture->width() : 0; } -private: - friend class CachedFrame; - CachedHistory* mHistory; - SkPicture* mPicture; - WebCore::LayerAndroid* mRootLayer; - WebCore::IntRect mFocusBounds; // dom text input focus node bounds - mutable WebCore::IntRect mScrolledBounds; // view bounds + amount visible as result of scroll - int mTextGeneration; - int mMaxXScroll; - int mMaxYScroll; - // These two are ONLY used when the tree is rebuilt and the focus is a textfield/area - int mSelectionStart; - int mSelectionEnd; - // these four set up as cache for use by frameDown/Up/Left/Right etc - mutable WebCore::IntRect mCursorBounds; - mutable const CachedNode* mCursor; - mutable SkRegion mBaseUncovered; - bool mScrollOnly; -#if DUMP_NAV_CACHE -public: - class Debug { -public: - CachedRoot* base() const; - void print() const; - } mDebug; -#endif -}; - -} - -#endif diff --git a/Source/WebKit/android/nav/DrawExtra.cpp b/Source/WebKit/android/nav/DrawExtra.cpp new file mode 100644 index 0000000..2f57dc1 --- /dev/null +++ b/Source/WebKit/android/nav/DrawExtra.cpp @@ -0,0 +1,96 @@ +/* + * Copyright 2012, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#include "DrawExtra.h" +#include "GLExtras.h" +#include "LayerAndroid.h" +#include "SkCanvas.h" +#include "SkRegion.h" +#include "WebViewCore.h" + +RegionLayerDrawExtra::RegionLayerDrawExtra() + : m_highlightColor(COLOR_HOLO_LIGHT) +{} + +RegionLayerDrawExtra::~RegionLayerDrawExtra() +{ + HighlightRegionMap::iterator end = m_highlightRegions.end(); + for (HighlightRegionMap::iterator it = m_highlightRegions.begin(); it != end; ++it) { + delete it->second; + it->second = 0; + } +} + +SkRegion* RegionLayerDrawExtra::getHighlightRegionsForLayer(const LayerAndroid* layer) +{ + int layerId = layer ? layer->uniqueId() : 0; + return m_highlightRegions.get(layerId); +} + +void RegionLayerDrawExtra::addHighlightRegion(const LayerAndroid* layer, const Vector<IntRect>& rects, + const IntPoint& additionalOffset) +{ + if (rects.isEmpty()) + return; + int layerId = layer ? layer->uniqueId() : 0; + SkRegion* region = m_highlightRegions.get(layerId); + if (!region) { + region = new SkRegion(); + m_highlightRegions.set(layerId, region); + } + IntPoint offset = additionalOffset; + WebViewCore::layerToAbsoluteOffset(layer, offset); + for (size_t i = 0; i < rects.size(); i++) { + IntRect r = rects.at(i); + r.move(-offset.x(), -offset.y()); + region->op(r.x(), r.y(), r.maxX(), r.maxY(), SkRegion::kUnion_Op); + } +} + +void RegionLayerDrawExtra::draw(SkCanvas* canvas, LayerAndroid* layer) +{ + SkRegion* region = getHighlightRegionsForLayer(layer); + if (!region || region->isEmpty()) + return; + SkRegion::Iterator rgnIter(*region); + SkPaint paint; + paint.setColor(m_highlightColor.rgb()); + while (!rgnIter.done()) { + const SkIRect& rect = rgnIter.rect(); + canvas->drawIRect(rect, paint); + rgnIter.next(); + } +} + +void RegionLayerDrawExtra::drawGL(GLExtras* glExtras, const LayerAndroid* layer) +{ + SkRegion* region = getHighlightRegionsForLayer(layer); + if (!region || region->isEmpty()) + return; + const TransformationMatrix* transform = layer ? layer->drawTransform() : 0; + glExtras->drawRegion(*region, true, false, transform, m_highlightColor); +} diff --git a/Source/WebKit/android/nav/DrawExtra.h b/Source/WebKit/android/nav/DrawExtra.h index 6716a65..83e7dcd 100644 --- a/Source/WebKit/android/nav/DrawExtra.h +++ b/Source/WebKit/android/nav/DrawExtra.h @@ -26,11 +26,25 @@ #ifndef DrawExtra_h #define DrawExtra_h +#include "config.h" + +#include "Color.h" +#include "IntPoint.h" +#include "IntRect.h" +#include "wtf/HashMap.h" +#include "wtf/Vector.h" + +// Color of the ring copied from framework's holo_light +#define COLOR_HOLO_LIGHT 0x6633B5E5 +// Color of the ring copied from framework's holo_dark +#define COLOR_HOLO_DARK 0x660099CC + class SkCanvas; +class SkRegion; namespace WebCore { - class IntRect; class LayerAndroid; + class GLExtras; } using namespace WebCore; @@ -40,7 +54,28 @@ namespace android { class DrawExtra { public: virtual ~DrawExtra() {} - virtual void draw(SkCanvas* , LayerAndroid* , IntRect* ) = 0; + virtual void drawLegacy(SkCanvas* , LayerAndroid* , IntRect* ) {} + virtual void draw(SkCanvas*, LayerAndroid*) {} + virtual void drawGL(GLExtras*, const LayerAndroid*) {} +}; + +// A helper extra that has a SkRegion per LayerAndroid +class RegionLayerDrawExtra : public DrawExtra { +public: + RegionLayerDrawExtra(); + virtual ~RegionLayerDrawExtra(); + + void addHighlightRegion(const LayerAndroid* layer, const Vector<IntRect>& rects, + const IntPoint& additionalOffset = IntPoint()); + virtual void draw(SkCanvas*, LayerAndroid*); + virtual void drawGL(GLExtras*, const LayerAndroid*); + +private: + SkRegion* getHighlightRegionsForLayer(const LayerAndroid* layer); + + typedef HashMap<int, SkRegion* > HighlightRegionMap; + HighlightRegionMap m_highlightRegions; + Color m_highlightColor; }; } diff --git a/Source/WebKit/android/nav/FindCanvas.cpp b/Source/WebKit/android/nav/FindCanvas.cpp deleted file mode 100644 index ca3cfba..0000000 --- a/Source/WebKit/android/nav/FindCanvas.cpp +++ /dev/null @@ -1,700 +0,0 @@ -/* - * Copyright 2008, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#define LOG_TAG "webviewglue" - -#include "config.h" -#include "FindCanvas.h" -#include "LayerAndroid.h" -#include "IntRect.h" -#include "SelectText.h" -#include "SkBlurMaskFilter.h" -#include "SkCornerPathEffect.h" -#include "SkRect.h" -#include "SkUtils.h" - -#include <utils/Log.h> - -#define INTEGER_OUTSET 2 - -namespace android { - -// MatchInfo methods -//////////////////////////////////////////////////////////////////////////////// - -MatchInfo::MatchInfo() { - m_picture = 0; -} - -MatchInfo::~MatchInfo() { - SkSafeUnref(m_picture); -} - -MatchInfo::MatchInfo(const MatchInfo& src) { - m_layerId = src.m_layerId; - m_location = src.m_location; - m_picture = src.m_picture; - SkSafeRef(m_picture); -} - -void MatchInfo::set(const SkRegion& region, SkPicture* pic, int layerId) { - SkSafeUnref(m_picture); - m_layerId = layerId; - m_location = region; - m_picture = pic; - SkASSERT(pic); - pic->ref(); -} - -// GlyphSet methods -//////////////////////////////////////////////////////////////////////////////// - -GlyphSet::GlyphSet(const SkPaint& paint, const UChar* lower, const UChar* upper, - size_t byteLength) { - SkPaint clonePaint(paint); - clonePaint.setTextEncoding(SkPaint::kUTF16_TextEncoding); - mTypeface = paint.getTypeface(); - mCount = clonePaint.textToGlyphs(lower, byteLength, NULL); - if (mCount > MAX_STORAGE_COUNT) { - mLowerGlyphs = new uint16_t[2*mCount]; - } else { - mLowerGlyphs = &mStorage[0]; - } - // Use one array, and have mUpperGlyphs point to a portion of it, - // so that we can reduce the number of new/deletes - mUpperGlyphs = mLowerGlyphs + mCount; - int count2 = clonePaint.textToGlyphs(lower, byteLength, mLowerGlyphs); - SkASSERT(mCount == count2); - count2 = clonePaint.textToGlyphs(upper, byteLength, mUpperGlyphs); - SkASSERT(mCount == count2); -} - -GlyphSet::~GlyphSet() { - // Do not need to delete mTypeface, which is not owned by us. - if (mCount > MAX_STORAGE_COUNT) { - delete[] mLowerGlyphs; - } // Otherwise, we just used local storage space, so no need to delete - // Also do not need to delete mUpperGlyphs, which simply points to a - // part of mLowerGlyphs -} - -GlyphSet& GlyphSet::operator=(GlyphSet& src) { - mTypeface = src.mTypeface; - mCount = src.mCount; - if (mCount > MAX_STORAGE_COUNT) { - mLowerGlyphs = new uint16_t[2*mCount]; - } else { - mLowerGlyphs = &mStorage[0]; - } - memcpy(mLowerGlyphs, src.mLowerGlyphs, 2*mCount*sizeof(uint16_t)); - mUpperGlyphs = mLowerGlyphs + mCount; - return *this; -} - -bool GlyphSet::characterMatches(uint16_t c, int index) { - SkASSERT(index < mCount && index >= 0); - return c == mLowerGlyphs[index] || c == mUpperGlyphs[index]; -} - -// FindCanvas methods -//////////////////////////////////////////////////////////////////////////////// - -FindCanvas::FindCanvas(int width, int height, const UChar* lower, - const UChar* upper, size_t byteLength) - : mLowerText(lower) - , mUpperText(upper) - , mLength(byteLength) - , mNumFound(0) { - // the text has been provided in read order. Reverse as needed so the - // result contains left-to-right characters. - const uint16_t* start = mLowerText; - size_t count = byteLength >> 1; - const uint16_t* end = mLowerText + count; - while (start < end) { - SkUnichar ch = SkUTF16_NextUnichar(&start); - WTF::Unicode::Direction charDirection = WTF::Unicode::direction(ch); - if (WTF::Unicode::RightToLeftArabic == charDirection - || WTF::Unicode::RightToLeft == charDirection) { - mLowerReversed.clear(); - mLowerReversed.append(mLowerText, count); - WebCore::ReverseBidi(mLowerReversed.begin(), count); - mLowerText = mLowerReversed.begin(); - mUpperReversed.clear(); - mUpperReversed.append(mUpperText, count); - WebCore::ReverseBidi(mUpperReversed.begin(), count); - mUpperText = mUpperReversed.begin(); - break; - } - } - - setBounder(&mBounder); - mOutset = -SkIntToScalar(INTEGER_OUTSET); - mMatches = new WTF::Vector<MatchInfo>(); - mWorkingIndex = 0; - mWorkingCanvas = 0; - mWorkingPicture = 0; -} - -FindCanvas::~FindCanvas() { - setBounder(NULL); - /* Just in case getAndClear was not called. */ - delete mMatches; - SkSafeUnref(mWorkingPicture); -} - -// Each version of addMatch returns a rectangle for a match. -// Not all of the parameters are used by each version. -SkRect FindCanvas::addMatchNormal(int index, - const SkPaint& paint, int count, const uint16_t* glyphs, - const SkScalar pos[], SkScalar y) { - const uint16_t* lineStart = glyphs - index; - /* Use the original paint, since "text" is in glyphs */ - SkScalar before = paint.measureText(lineStart, index * sizeof(uint16_t), 0); - SkRect rect; - rect.fLeft = pos[0] + before; - int countInBytes = count * sizeof(uint16_t); - rect.fRight = paint.measureText(glyphs, countInBytes, 0) + rect.fLeft; - SkPaint::FontMetrics fontMetrics; - paint.getFontMetrics(&fontMetrics); - SkScalar baseline = y; - rect.fTop = baseline + fontMetrics.fAscent; - rect.fBottom = baseline + fontMetrics.fDescent; - const SkMatrix& matrix = getTotalMatrix(); - matrix.mapRect(&rect); - // Add the text to our picture. - SkCanvas* canvas = getWorkingCanvas(); - int saveCount = canvas->save(); - canvas->concat(matrix); - canvas->drawText(glyphs, countInBytes, pos[0] + before, y, paint); - canvas->restoreToCount(saveCount); - return rect; -} - -SkRect FindCanvas::addMatchPos(int index, - const SkPaint& paint, int count, const uint16_t* glyphs, - const SkScalar xPos[], SkScalar /* y */) { - SkRect r; - r.setEmpty(); - const SkPoint* temp = reinterpret_cast<const SkPoint*> (xPos); - const SkPoint* points = &temp[index]; - int countInBytes = count * sizeof(uint16_t); - SkPaint::FontMetrics fontMetrics; - paint.getFontMetrics(&fontMetrics); - // Need to check each character individually, since the heights may be - // different. - for (int j = 0; j < count; j++) { - SkRect bounds; - bounds.fLeft = points[j].fX; - bounds.fRight = bounds.fLeft + - paint.measureText(&glyphs[j], sizeof(uint16_t), 0); - SkScalar baseline = points[j].fY; - bounds.fTop = baseline + fontMetrics.fAscent; - bounds.fBottom = baseline + fontMetrics.fDescent; - /* Accumulate and then add the resulting rect to mMatches */ - r.join(bounds); - } - SkMatrix matrix = getTotalMatrix(); - matrix.mapRect(&r); - SkCanvas* canvas = getWorkingCanvas(); - int saveCount = canvas->save(); - canvas->concat(matrix); - canvas->drawPosText(glyphs, countInBytes, points, paint); - canvas->restoreToCount(saveCount); - return r; -} - -SkRect FindCanvas::addMatchPosH(int index, - const SkPaint& paint, int count, const uint16_t* glyphs, - const SkScalar position[], SkScalar constY) { - SkRect r; - // We only care about the positions starting at the index of our match - const SkScalar* xPos = &position[index]; - // This assumes that the position array is monotonic increasing - // The left bounds will be the position of the left most character - r.fLeft = xPos[0]; - // The right bounds will be the position of the last character plus its - // width - int lastIndex = count - 1; - r.fRight = paint.measureText(&glyphs[lastIndex], sizeof(uint16_t), 0) - + xPos[lastIndex]; - // Grab font metrics to determine the top and bottom of the bounds - SkPaint::FontMetrics fontMetrics; - paint.getFontMetrics(&fontMetrics); - r.fTop = constY + fontMetrics.fAscent; - r.fBottom = constY + fontMetrics.fDescent; - const SkMatrix& matrix = getTotalMatrix(); - matrix.mapRect(&r); - SkCanvas* canvas = getWorkingCanvas(); - int saveCount = canvas->save(); - canvas->concat(matrix); - canvas->drawPosTextH(glyphs, count * sizeof(uint16_t), xPos, constY, paint); - canvas->restoreToCount(saveCount); - return r; -} - -void FindCanvas::drawLayers(LayerAndroid* layer) { -#if USE(ACCELERATED_COMPOSITING) - SkPicture* picture = layer->picture(); - if (picture) { - setLayerId(layer->uniqueId()); - drawPicture(*picture); - } - for (int i = 0; i < layer->countChildren(); i++) - drawLayers(layer->getChild(i)); -#endif -} - -void FindCanvas::drawText(const void* text, size_t byteLength, SkScalar x, - SkScalar y, const SkPaint& paint) { - findHelper(text, byteLength, paint, &x, y, &FindCanvas::addMatchNormal); -} - -void FindCanvas::drawPosText(const void* text, size_t byteLength, - const SkPoint pos[], const SkPaint& paint) { - // Pass in the first y coordinate for y so that we can check to see whether - // it is lower than the last draw call (to check if we are continuing to - // another line). - findHelper(text, byteLength, paint, (const SkScalar*) pos, pos[0].fY, - &FindCanvas::addMatchPos); -} - -void FindCanvas::drawPosTextH(const void* text, size_t byteLength, - const SkScalar xpos[], SkScalar constY, - const SkPaint& paint) { - findHelper(text, byteLength, paint, xpos, constY, - &FindCanvas::addMatchPosH); -} - -/* The current behavior is to skip substring matches. This means that in the - * string - * batbatbat - * a search for - * batbat - * will return 1 match. If the desired behavior is to return 2 matches, define - * INCLUDE_SUBSTRING_MATCHES to be 1. - */ -#define INCLUDE_SUBSTRING_MATCHES 0 - -// Need a quick way to know a maximum distance between drawText calls to know if -// they are part of the same logical phrase when searching. By crude -// inspection, half the point size seems a good guess at the width of a space -// character. -static inline SkScalar approximateSpaceWidth(const SkPaint& paint) { - return SkScalarHalf(paint.getTextSize()); -} - -void FindCanvas::findHelper(const void* text, size_t byteLength, - const SkPaint& paint, const SkScalar positions[], - SkScalar y, - SkRect (FindCanvas::*addMatch)(int index, - const SkPaint& paint, int count, - const uint16_t* glyphs, - const SkScalar positions[], SkScalar y)) { - SkASSERT(paint.getTextEncoding() == SkPaint::kGlyphID_TextEncoding); - SkASSERT(mMatches); - GlyphSet* glyphSet = getGlyphs(paint); - const int count = glyphSet->getCount(); - int numCharacters = byteLength >> 1; - const uint16_t* chars = (const uint16_t*) text; - // This block will check to see if we are continuing from another line. If - // so, the user needs to have added a space, which we do not draw. - if (mWorkingIndex) { - SkPoint newY; - getTotalMatrix().mapXY(0, y, &newY); - SkIRect workingBounds = mWorkingRegion.getBounds(); - int newYInt = SkScalarRound(newY.fY); - if (workingBounds.fTop > newYInt) { - // The new text is above the working region, so we know it's not - // a continuation. - resetWorkingCanvas(); - mWorkingIndex = 0; - mWorkingRegion.setEmpty(); - } else if (workingBounds.fBottom < newYInt) { - // Now we know that this line is lower than our partial match. - SkPaint clonePaint(paint); - clonePaint.setTextEncoding(SkPaint::kUTF8_TextEncoding); - uint16_t space; - clonePaint.textToGlyphs(" ", 1, &space); - if (glyphSet->characterMatches(space, mWorkingIndex)) { - mWorkingIndex++; - if (mWorkingIndex == count) { - // We already know that it is not clipped out because we - // checked for that before saving the working region. - insertMatchInfo(mWorkingRegion); - - resetWorkingCanvas(); - mWorkingIndex = 0; - mWorkingRegion.setEmpty(); - // We have found a match, so continue on this line from - // scratch. - } - } else { - resetWorkingCanvas(); - mWorkingIndex = 0; - mWorkingRegion.setEmpty(); - } - } - // If neither one is true, then we are likely continuing on the same - // line, but are in a new draw call because the paint has changed. In - // this case, we can continue without adding a space. - } - // j is the position in the search text - // Start off with mWorkingIndex in case we are continuing from a prior call - int j = mWorkingIndex; - // index is the position in the drawn text - int index = 0; - for ( ; index != numCharacters; index++) { - if (glyphSet->characterMatches(chars[index], j)) { - // The jth character in the search text matches the indexth position - // in the drawn text, so increase j. - j++; - if (j != count) { - continue; - } - // The last count characters match, so we found the entire - // search string. - int remaining = count - mWorkingIndex; - int matchIndex = index - remaining + 1; - // Set up a pointer to the matching text in 'chars'. - const uint16_t* glyphs = chars + matchIndex; - SkRect rect = (this->*addMatch)(matchIndex, paint, - remaining, glyphs, positions, y); - // We need an SkIRect for SkRegion operations. - SkIRect iRect; - rect.roundOut(&iRect); - // Want to outset the drawn rectangle by the same amount as - // mOutset - iRect.inset(-INTEGER_OUTSET, -INTEGER_OUTSET); - SkRegion regionToAdd(iRect); - if (!mWorkingRegion.isEmpty()) { - // If this is on the same line as our working region, make - // sure that they are close enough together that they are - // supposed to be part of the same text string. - // The width of two spaces has arbitrarily been chosen. - const SkIRect& workingBounds = mWorkingRegion.getBounds(); - if (workingBounds.fTop <= iRect.fBottom && - workingBounds.fBottom >= iRect.fTop && - SkIntToScalar(iRect.fLeft - workingBounds.fRight) > - approximateSpaceWidth(paint)) { - index = -1; // Will increase to 0 on next run - // In this case, we need to start from the beginning of - // the text being searched and our search term. - j = 0; - mWorkingIndex = 0; - mWorkingRegion.setEmpty(); - continue; - } - // Add the mWorkingRegion, which contains rectangles from - // the previous line(s). - regionToAdd.op(mWorkingRegion, SkRegion::kUnion_Op); - } - insertMatchInfo(regionToAdd); -#if INCLUDE_SUBSTRING_MATCHES - // Reset index to the location of the match and reset j to the - // beginning, so that on the next iteration of the loop, index - // will advance by 1 and we will compare the next character in - // chars to the first character in the GlyphSet. - index = matchIndex; -#endif - // Whether the clip contained it or not, we need to start over - // with our recording canvas - resetWorkingCanvas(); - } else { - // Index needs to be set to index - j + 1. - // This is a ridiculous case, but imagine the situation where the - // user is looking for the string "jjog" in the drawText call for - // "jjjog". The first two letters match. However, when the index - // is 2, and we discover that 'o' and 'j' do not match, we should go - // back to 1, where we do, in fact, have a match - // FIXME: This does not work if (as in our example) "jj" is in one - // draw call and "jog" is in the next. Doing so would require a - // stack, keeping track of multiple possible working indeces and - // regions. This is likely an uncommon case. - index = index - j; // index will be increased by one on the next - // iteration - } - // We reach here in one of two cases: - // 1) We just completed a match, so any working rectangle/index is no - // longer needed, and we will start over from the beginning - // 2) The glyphs do not match, so we start over at the beginning of - // the search string. - j = 0; - mWorkingIndex = 0; - mWorkingRegion.setEmpty(); - } - // At this point, we have searched all of the text in the current drawText - // call. - // Keep track of a partial match that may start on this line. - if (j > 0) { // if j is greater than 0, we have a partial match - int relativeCount = j - mWorkingIndex; // Number of characters in this - // part of the match. - int partialIndex = index - relativeCount; // Index that starts our - // partial match. - const uint16_t* partialGlyphs = chars + partialIndex; - SkRect partial = (this->*addMatch)(partialIndex, paint, relativeCount, - partialGlyphs, positions, y); - partial.inset(mOutset, mOutset); - SkIRect dest; - partial.roundOut(&dest); - mWorkingRegion.op(dest, SkRegion::kUnion_Op); - mWorkingIndex = j; - return; - } - // This string doesn't go into the next drawText, so reset our working - // variables - mWorkingRegion.setEmpty(); - mWorkingIndex = 0; -} - -SkCanvas* FindCanvas::getWorkingCanvas() { - if (!mWorkingPicture) { - mWorkingPicture = new SkPicture; - mWorkingCanvas = mWorkingPicture->beginRecording(0,0); - } - return mWorkingCanvas; -} - -GlyphSet* FindCanvas::getGlyphs(const SkPaint& paint) { - SkTypeface* typeface = paint.getTypeface(); - GlyphSet* end = mGlyphSets.end(); - for (GlyphSet* ptr = mGlyphSets.begin();ptr != end; ptr++) { - if (ptr->getTypeface() == typeface) { - return ptr; - } - } - - GlyphSet set(paint, mLowerText, mUpperText, mLength); - *mGlyphSets.append() = set; - return &(mGlyphSets.top()); -} - -void FindCanvas::insertMatchInfo(const SkRegion& region) { - mNumFound++; - mWorkingPicture->endRecording(); - MatchInfo matchInfo; - mMatches->append(matchInfo); - LOGD("%s region=%p pict=%p layer=%d", __FUNCTION__, - ®ion, mWorkingPicture, mLayerId); - mMatches->last().set(region, mWorkingPicture, mLayerId); -} - -void FindCanvas::resetWorkingCanvas() { - mWorkingPicture->unref(); - mWorkingPicture = 0; - // Do not need to reset mWorkingCanvas itself because we only access it via - // getWorkingCanvas. -} - -// This function sets up the paints that are used to draw the matches. -void FindOnPage::setUpFindPaint() { - // Set up the foreground paint - m_findPaint.setAntiAlias(true); - const SkScalar roundiness = SkIntToScalar(2); - SkCornerPathEffect* cornerEffect = new SkCornerPathEffect(roundiness); - m_findPaint.setPathEffect(cornerEffect); - m_findPaint.setARGB(255, 132, 190, 0); - - // Set up the background blur paint. - m_findBlurPaint.setAntiAlias(true); - m_findBlurPaint.setARGB(204, 0, 0, 0); - m_findBlurPaint.setPathEffect(cornerEffect); - cornerEffect->unref(); - SkMaskFilter* blurFilter = SkBlurMaskFilter::Create(SK_Scalar1, - SkBlurMaskFilter::kNormal_BlurStyle); - m_findBlurPaint.setMaskFilter(blurFilter)->unref(); - m_isFindPaintSetUp = true; -} - -IntRect FindOnPage::currentMatchBounds() const { - IntRect noBounds = IntRect(0, 0, 0, 0); - if (!m_matches || !m_matches->size()) - return noBounds; - MatchInfo& info = (*m_matches)[m_findIndex]; - return info.getLocation().getBounds(); -} - -bool FindOnPage::currentMatchIsInLayer() const { - if (!m_matches || !m_matches->size()) - return false; - MatchInfo& info = (*m_matches)[m_findIndex]; - return info.isInLayer(); -} - -int FindOnPage::currentMatchLayerId() const { - return (*m_matches)[m_findIndex].layerId(); -} - -// This function is only used by findNext and setMatches. In it, we store -// upper left corner of the match specified by m_findIndex in -// m_currentMatchLocation. -void FindOnPage::storeCurrentMatchLocation() { - SkASSERT(m_findIndex < m_matches->size()); - const SkIRect& bounds = (*m_matches)[m_findIndex].getLocation().getBounds(); - m_currentMatchLocation.set(bounds.fLeft, bounds.fTop); - m_hasCurrentLocation = true; -} - -// Put a cap on the number of matches to draw. If the current page has more -// matches than this, only draw the focused match. -#define MAX_NUMBER_OF_MATCHES_TO_DRAW 101 - -void FindOnPage::draw(SkCanvas* canvas, LayerAndroid* layer, IntRect* inval) { - if (!m_lastBounds.isEmpty()) { - inval->unite(m_lastBounds); - m_lastBounds.setEmpty(); - } - if (!m_hasCurrentLocation || !m_matches || !m_matches->size()) - return; - int layerId = layer->uniqueId(); - if (m_findIndex >= m_matches->size()) - m_findIndex = 0; - const MatchInfo& matchInfo = (*m_matches)[m_findIndex]; - const SkRegion& currentMatchRegion = matchInfo.getLocation(); - - // Set up the paints used for drawing the matches - if (!m_isFindPaintSetUp) - setUpFindPaint(); - - // Draw the current match - if (matchInfo.layerId() == layerId) { - drawMatch(currentMatchRegion, canvas, true); - // Now draw the picture, so that it shows up on top of the rectangle - int saveCount = canvas->save(); - SkPath matchPath; - currentMatchRegion.getBoundaryPath(&matchPath); - canvas->clipPath(matchPath); - canvas->drawPicture(*matchInfo.getPicture()); - canvas->restoreToCount(saveCount); - const SkMatrix& matrix = canvas->getTotalMatrix(); - const SkRect& localBounds = matchPath.getBounds(); - SkRect globalBounds; - matrix.mapRect(&globalBounds, localBounds); - globalBounds.round(&m_lastBounds); - inval->unite(m_lastBounds); - } - // Draw the rest - unsigned numberOfMatches = m_matches->size(); - if (numberOfMatches > 1 - && numberOfMatches < MAX_NUMBER_OF_MATCHES_TO_DRAW) { - for (unsigned i = 0; i < numberOfMatches; i++) { - // The current match has already been drawn - if (i == m_findIndex) - continue; - if ((*m_matches)[i].layerId() != layerId) - continue; - const SkRegion& region = (*m_matches)[i].getLocation(); - // Do not draw matches which intersect the current one, or if it is - // offscreen - if (currentMatchRegion.intersects(region)) - continue; - SkRect bounds; - bounds.set(region.getBounds()); - if (canvas->quickReject(bounds, SkCanvas::kAA_EdgeType)) - continue; - drawMatch(region, canvas, false); - } - } -} - -// Draw the match specified by region to the canvas. -void FindOnPage::drawMatch(const SkRegion& region, SkCanvas* canvas, - bool focused) -{ - // For the match which has focus, use a filled paint. For the others, use - // a stroked paint. - if (focused) { - m_findPaint.setStyle(SkPaint::kFill_Style); - m_findBlurPaint.setStyle(SkPaint::kFill_Style); - } else { - m_findPaint.setStyle(SkPaint::kStroke_Style); - m_findPaint.setStrokeWidth(SK_Scalar1); - m_findBlurPaint.setStyle(SkPaint::kStroke_Style); - m_findBlurPaint.setStrokeWidth(SkIntToScalar(2)); - } - // Find the path for the current match - SkPath matchPath; - region.getBoundaryPath(&matchPath); - // Offset the path for a blurred shadow - SkPath blurPath; - matchPath.offset(SK_Scalar1, SkIntToScalar(2), &blurPath); - int saveCount = 0; - if (!focused) { - saveCount = canvas->save(); - canvas->clipPath(matchPath, SkRegion::kDifference_Op); - } - // Draw the blurred background - canvas->drawPath(blurPath, m_findBlurPaint); - if (!focused) - canvas->restoreToCount(saveCount); - // Draw the foreground - canvas->drawPath(matchPath, m_findPaint); -} - -void FindOnPage::findNext(bool forward) -{ - if (!m_matches || !m_matches->size() || !m_hasCurrentLocation) - return; - if (forward) { - m_findIndex++; - if (m_findIndex == m_matches->size()) - m_findIndex = 0; - } else { - if (m_findIndex == 0) { - m_findIndex = m_matches->size() - 1; - } else { - m_findIndex--; - } - } - storeCurrentMatchLocation(); -} - -// With this call, WebView takes ownership of matches, and is responsible for -// deleting it. -void FindOnPage::setMatches(WTF::Vector<MatchInfo>* matches) -{ - if (m_matches) - delete m_matches; - m_matches = matches; - if (m_matches->size()) { - if (m_hasCurrentLocation) { - for (unsigned i = 0; i < m_matches->size(); i++) { - const SkIRect& rect = (*m_matches)[i].getLocation().getBounds(); - if (rect.fLeft == m_currentMatchLocation.fX - && rect.fTop == m_currentMatchLocation.fY) { - m_findIndex = i; - return; - } - } - } - // If we did not have a stored location, or if we were unable to restore - // it, store the new one. - m_findIndex = 0; - storeCurrentMatchLocation(); - } else { - m_hasCurrentLocation = false; - } -} - -} diff --git a/Source/WebKit/android/nav/FindCanvas.h b/Source/WebKit/android/nav/FindCanvas.h deleted file mode 100644 index 0fa095c..0000000 --- a/Source/WebKit/android/nav/FindCanvas.h +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Copyright 2008, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef Find_Canvas_h -#define Find_Canvas_h - -#include "DrawExtra.h" -#include "IntRect.h" -#include "SkBounder.h" -#include "SkCanvas.h" -#include "SkPicture.h" -#include "SkRect.h" -#include "SkRegion.h" -#include "SkTDArray.h" - -#include <unicode/umachine.h> -#include <wtf/Vector.h> - -namespace android { - -// Stores both region information and an SkPicture of the match, so that the -// region can be drawn, followed by drawing the matching text on top of it. -// This class owns its SkPicture -class MatchInfo { -public: - MatchInfo(); - ~MatchInfo(); - MatchInfo(const MatchInfo& src); - const SkRegion& getLocation() const { return m_location; } - // Return a pointer to our picture, representing the matching text. Does - // not transfer ownership of the picture. - SkPicture* getPicture() const { return m_picture; } - // This will make a copy of the region, and increase the ref count on the - // SkPicture. If this MatchInfo already had one, unref it. - void set(const SkRegion& region, SkPicture* pic, int layerId); - bool isInLayer() const { return m_layerId >= 0; } - int layerId() const { return m_layerId; } -private: - MatchInfo& operator=(MatchInfo& src); - SkRegion m_location; - SkPicture* m_picture; - int m_layerId; -}; - -// A class containing a typeface for reference, the length in glyphs, and -// the upper and lower case representations of the search string. -class GlyphSet { -public: - GlyphSet(const SkPaint& paint, const UChar* lower, const UChar* upper, - size_t byteLength); - ~GlyphSet(); - GlyphSet& operator=(GlyphSet& src); - - // Return true iff c matches one of our glyph arrays at index - bool characterMatches(uint16_t c, int index); - - int getCount() const { return mCount; } - - const SkTypeface* getTypeface() const { return mTypeface; } - -private: - // Disallow copy constructor - GlyphSet(GlyphSet& src) { } - - // mTypeface is used for comparison only - const SkTypeface* mTypeface; - // mLowerGlyphs points to all of our storage space: the lower set followed - // by the upper set. mUpperGlyphs is purely a convenience pointer to the - // start of the upper case glyphs. - uint16_t* mLowerGlyphs; - uint16_t* mUpperGlyphs; - // mCount is the number of glyphs of the search string. Must be the same - // for both the lower case set and the upper case set. - int mCount; - - // Arbitrarily chose the maximum storage to use in the GlyphSet. This is - // based on the length of the word being searched. If users are always - // searching for 3 letter words (for example), an ideal number would be 3. - // Each time the user searches for a word longer than (in this case, 3) that - // will result in calling new/delete. - enum Storage { - MAX_STORAGE_COUNT = 16 - }; - // In order to eliminate new/deletes, create storage that will be enough - // most of the time - uint16_t mStorage[2*MAX_STORAGE_COUNT]; -}; - -class FindBounder : public SkBounder { -public: - FindBounder() {} - ~FindBounder() {} -protected: - virtual bool onIRect(const SkIRect&) { return false; } -}; - -class FindCanvas : public SkCanvas { -public: - FindCanvas(int width, int height, const UChar* , const UChar*, - size_t byteLength); - - virtual ~FindCanvas(); - - virtual void drawText(const void* text, size_t byteLength, SkScalar x, - SkScalar y, const SkPaint& paint); - - /* FIXME: This path has not been tested. */ - virtual void drawPosText(const void* text, size_t byteLength, - const SkPoint pos[], const SkPaint& paint); - - /* Also untested */ - virtual void drawPosTextH(const void* text, size_t byteLength, - const SkScalar xpos[], SkScalar constY, - const SkPaint& paint); - - /* Not sure what to do here or for drawTextOnPathHV */ - virtual void drawTextOnPath(const void* text, size_t byteLength, - const SkPath& path, const SkMatrix* matrix, - const SkPaint& paint) { - } - - void drawLayers(LayerAndroid*); - int found() const { return mNumFound; } - void setLayerId(int layerId) { mLayerId = layerId; } - - // This method detaches our array of matches and passes ownership to - // the caller, who is then responsible for deleting them. - WTF::Vector<MatchInfo>* detachMatches() { - WTF::Vector<MatchInfo>* array = mMatches; - mMatches = NULL; - return array; - } - -private: - // These calls are made by findHelper to store information about each match - // that is found. They return a rectangle which is used to highlight the - // match. They also add to our SkPicture (which can be accessed with - // getDrawnMatches) a draw of each match. This way it can be drawn after - // the rectangle. The rect that is returned is in device coordinates. - SkRect addMatchNormal(int index, - const SkPaint& paint, int count, const uint16_t* glyphs, - const SkScalar pos[], SkScalar y); - - SkRect addMatchPos(int index, - const SkPaint& paint, int count, const uint16_t* glyphs, - const SkScalar xPos[], SkScalar /* y */); - - SkRect addMatchPosH(int index, - const SkPaint& paint, int count, const uint16_t* glyphs, - const SkScalar position[], SkScalar constY); - - // Helper for each of our draw calls - void findHelper(const void* text, size_t byteLength, const SkPaint& paint, - const SkScalar xPos[], SkScalar y, - SkRect (FindCanvas::*addMatch)(int index, - const SkPaint& paint, int count, const uint16_t* glyphs, - const SkScalar pos[], SkScalar y)); - - // If we already have a working canvas, grab it. Otherwise, create a new - // one. - SkCanvas* getWorkingCanvas(); - - // Return the set of glyphs and its count for the text being searched for - // and the parameter paint. If one has already been created and cached - // for this paint, use it. If not, create a new one and cache it. - GlyphSet* getGlyphs(const SkPaint& paint); - - // Store all the accumulated info about a match in our vector. - void insertMatchInfo(const SkRegion& region); - - // Throw away our cumulative information about our working SkCanvas. After - // this call, next call to getWorkingCanvas will create a new one. - void resetWorkingCanvas(); - - // Since we may transfer ownership of this array (see detachRects()), we - // hold a pointer to the array instead of just the array itself. - WTF::Vector<MatchInfo>* mMatches; - const UChar* mLowerText; - const UChar* mUpperText; - Vector<UChar> mLowerReversed; - Vector<UChar> mUpperReversed; - size_t mLength; - FindBounder mBounder; - int mNumFound; - SkScalar mOutset; - SkTDArray<GlyphSet> mGlyphSets; - - SkPicture* mWorkingPicture; - SkCanvas* mWorkingCanvas; - SkRegion mWorkingRegion; - int mWorkingIndex; - int mLayerId; -}; - -class FindOnPage : public DrawExtra { -public: - FindOnPage() { - m_matches = 0; - m_hasCurrentLocation = false; - m_isFindPaintSetUp = false; - m_lastBounds.setEmpty(); - } - virtual ~FindOnPage() { if (m_matches) delete m_matches; } - void clearCurrentLocation() { m_hasCurrentLocation = false; } - IntRect currentMatchBounds() const; - int currentMatchIndex() const { return m_findIndex; } - bool currentMatchIsInLayer() const; - // This requires the current match to be in a layer. See - // currentMatchIsInLayer(). - int currentMatchLayerId() const; - virtual void draw(SkCanvas* , LayerAndroid* , IntRect* ); - void findNext(bool forward); - bool isCurrentLocationValid() { return m_hasCurrentLocation; } - void setMatches(WTF::Vector<MatchInfo>* matches); - WTF::Vector<MatchInfo>* matches() { return m_matches; } -private: - void drawMatch(const SkRegion& region, SkCanvas* canvas, bool focused); - void setUpFindPaint(); - void storeCurrentMatchLocation(); - WTF::Vector<MatchInfo>* m_matches; - // Stores the location of the current match. - SkIPoint m_currentMatchLocation; - // Tells whether the value in m_currentMatchLocation is valid. - bool m_hasCurrentLocation; - // Tells whether we have done the setup to draw the Find matches. - bool m_isFindPaintSetUp; - // Paint used to draw our Find matches. - SkPaint m_findPaint; - // Paint used for the background of our Find matches. - SkPaint m_findBlurPaint; - unsigned m_findIndex; - SkIRect m_lastBounds; -}; - -} - -#endif // Find_Canvas_h diff --git a/Source/WebKit/android/nav/SelectText.cpp b/Source/WebKit/android/nav/SelectText.cpp index d20c44a..22c67bc 100644 --- a/Source/WebKit/android/nav/SelectText.cpp +++ b/Source/WebKit/android/nav/SelectText.cpp @@ -25,23 +25,20 @@ #define LOG_TAG "webviewglue" -#include "CachedPrefix.h" +#include "config.h" + #include "BidiResolver.h" #include "BidiRunList.h" -#include "CachedRoot.h" +#include "GLExtras.h" #include "LayerAndroid.h" -#include "ParseCanvas.h" #include "SelectText.h" #include "SkBitmap.h" #include "SkBounder.h" -#include "SkGradientShader.h" -#include "SkMatrix.h" +#include "SkCanvas.h" #include "SkPicture.h" -#include "SkPixelXorXfermode.h" #include "SkPoint.h" #include "SkRect.h" #include "SkRegion.h" -#include "SkUtils.h" #include "TextRun.h" #ifdef DEBUG_NAV_UI @@ -52,7 +49,7 @@ // #define EXTRA_NOISY_LOGGING 1 #define DEBUG_TOUCH_HANDLES 0 #if DEBUG_TOUCH_HANDLES -#define DBG_HANDLE_LOG(format, ...) LOGD("%s " format, __FUNCTION__, __VA_ARGS__) +#define DBG_HANDLE_LOG(format, ...) ALOGD("%s " format, __FUNCTION__, __VA_ARGS__) #else #define DBG_HANDLE_LOG(...) #endif @@ -149,1919 +146,15 @@ void ReverseBidi(UChar* chars, int len) { namespace android { -#define HYPHEN_MINUS 0x2D // ASCII hyphen -#define SOLIDUS 0x2F // ASCII slash -#define REVERSE_SOLIDUS 0x5C // ASCII backslash -#define HYPHEN 0x2010 // unicode hyphen, first in range of dashes -#define HORZ_BAR 0x2015 // unicode horizontal bar, last in range of dashes -#define TOUCH_SLOP 10 // additional distance from character rect when hit - -class CommonCheck : public SkBounder { -public: - CommonCheck(const SkIRect& area) - : mArea(area) - , mLastUni(0) - { - mLastGlyph.fGlyphID = static_cast<uint16_t>(-1); - mLastCandidate.fGlyphID = static_cast<uint16_t>(-1); - mMatrix.reset(); - reset(); - } - - /* called only while the picture is parsed */ - int base() { - if (mBase == INT_MAX) { - SkPoint result; - mMatrix.mapXY(0, mY, &result); - mBase = SkScalarFloor(result.fY); - } - return mBase; - } - - /* called only while the picture is parsed */ - int bottom() { - if (mBottom == INT_MAX) { - SkPoint result; - SkPaint::FontMetrics metrics; - mPaint.getFontMetrics(&metrics); - mMatrix.mapXY(0, metrics.fDescent + mY, &result); - mBottom = SkScalarCeil(result.fY); - } - return mBottom; - } - -#if DEBUG_NAV_UI - // make current (possibily uncomputed) value visible for debugging - int bottomDebug() const - { - return mBottom; - } -#endif - - bool addNewLine(const SkBounder::GlyphRec& rec) - { - SkFixed lineSpacing = SkFixedAbs(mLastGlyph.fLSB.fY - rec.fLSB.fY); - SkFixed lineHeight = SkIntToFixed(bottom() - top()); - return lineSpacing >= lineHeight + (lineHeight >> 1); // 1.5 - } - - bool addSpace(const SkBounder::GlyphRec& rec) - { - bool newBaseLine = mLastGlyph.fLSB.fY != rec.fLSB.fY; - if (((mLastUni >= HYPHEN && mLastUni <= HORZ_BAR) - || mLastUni == HYPHEN_MINUS || mLastUni == SOLIDUS - || mLastUni == REVERSE_SOLIDUS) && newBaseLine) - { - return false; - } - return isSpace(rec); - } - - void finishGlyph() - { - mLastGlyph = mLastCandidate; - mLastUni = mLastUniCandidate; - mLastPaint = mLastPaintCandidate; - } - - const SkIRect& getArea() const { - return mArea; - } - - /* called only while the picture is parsed */ - SkUnichar getUniChar(const SkBounder::GlyphRec& rec) - { - SkUnichar unichar; - SkPaint::TextEncoding save = mPaint.getTextEncoding(); - mPaint.setTextEncoding(SkPaint::kUTF16_TextEncoding); - mPaint.glyphsToUnichars(&rec.fGlyphID, 1, &unichar); - mPaint.setTextEncoding(save); - return unichar; - } - - bool isSpace(const SkBounder::GlyphRec& rec) - { - if (mLastGlyph.fGlyphID == static_cast<uint16_t>(-1)) - return true; - DBG_NAV_LOGD("mLastGlyph=((%g, %g),(%g, %g), %d)" - " rec=((%g, %g),(%g, %g), %d) mLastUni=0x%04x '%c'", - SkFixedToScalar(mLastGlyph.fLSB.fX), - SkFixedToScalar(mLastGlyph.fLSB.fY), - SkFixedToScalar(mLastGlyph.fRSB.fX), - SkFixedToScalar(mLastGlyph.fRSB.fY), mLastGlyph.fGlyphID, - SkFixedToScalar(rec.fLSB.fX), SkFixedToScalar(rec.fLSB.fY), - SkFixedToScalar(rec.fRSB.fX), SkFixedToScalar(rec.fRSB.fY), - rec.fGlyphID, - mLastUni, mLastUni && mLastUni < 0x7f ? mLastUni : '?'); - bool newBaseLine = mLastGlyph.fLSB.fY != rec.fLSB.fY; - if (newBaseLine) - return true; - SkFixed gapOne = mLastGlyph.fLSB.fX - rec.fRSB.fX; - SkFixed gapTwo = rec.fLSB.fX - mLastGlyph.fRSB.fX; - if (gapOne < 0 && gapTwo < 0) - return false; // overlaps - const SkBounder::GlyphRec& first = mLastGlyph.fLSB.fX < rec.fLSB.fX - ? mLastGlyph : rec; - const SkBounder::GlyphRec& second = mLastGlyph.fLSB.fX < rec.fLSB.fX - ? rec : mLastGlyph; - uint16_t firstGlyph = first.fGlyphID; - SkScalar firstWidth = mLastPaint.measureText(&firstGlyph, sizeof(firstGlyph)); - SkFixed ceilWidth = SkIntToFixed(SkScalarCeil(firstWidth)); - SkFixed posNoSpace = first.fLSB.fX + ceilWidth; - SkFixed ceilSpace = SkIntToFixed(SkFixedCeil(minSpaceWidth(mLastPaint))); - SkFixed posWithSpace = posNoSpace + ceilSpace; - SkFixed diffNoSpace = SkFixedAbs(second.fLSB.fX - posNoSpace); - SkFixed diffWithSpace = SkFixedAbs(second.fLSB.fX - posWithSpace); - DBG_NAV_LOGD("second=%g width=%g (%g) noSpace=%g (%g) withSpace=%g (%g)" - " fontSize=%g", - SkFixedToScalar(second.fLSB.fX), - firstWidth, SkFixedToScalar(ceilWidth), - SkFixedToScalar(posNoSpace), SkFixedToScalar(diffNoSpace), - SkFixedToScalar(posWithSpace), SkFixedToScalar(diffWithSpace), - mLastPaint.getTextSize()); - return diffWithSpace <= diffNoSpace; - } - - SkFixed minSpaceWidth(SkPaint& paint) - { - if (mMinSpaceWidth == SK_FixedMax) { - SkPaint::TextEncoding save = paint.getTextEncoding(); - paint.setTextEncoding(SkPaint::kUTF8_TextEncoding); - SkScalar width = paint.measureText(" ", 1); - mMinSpaceWidth = SkScalarToFixed(width * mMatrix.getScaleX()); - paint.setTextEncoding(save); - DBG_NAV_LOGV("width=%g matrix sx/sy=(%g, %g) tx/ty=(%g, %g)" - " mMinSpaceWidth=%g", width, - mMatrix.getScaleX(), mMatrix.getScaleY(), - mMatrix.getTranslateX(), mMatrix.getTranslateY(), - SkFixedToScalar(mMinSpaceWidth)); - } - return mMinSpaceWidth; - } - - void recordGlyph(const SkBounder::GlyphRec& rec) - { - mLastCandidate = rec; - mLastUniCandidate = getUniChar(rec); - mLastPaintCandidate = mPaint; - } - - void reset() - { - mMinSpaceWidth = SK_FixedMax; // mark as uninitialized - mBase = mBottom = mTop = INT_MAX; // mark as uninitialized - } - - void set(CommonCheck& check) - { - mLastGlyph = check.mLastGlyph; - mLastUni = check.mLastUni; - mMatrix = check.mMatrix; - mLastPaint = check.mLastPaint; - reset(); - } - - void setGlyph(CommonCheck& check) - { - mLastGlyph = check.mLastGlyph; - mLastUni = check.mLastUni; - mLastPaint = check.mLastPaint; - } - - void setUp(const SkPaint& paint, const SkMatrix& matrix, SkScalar y, - const void* text) - { - mMatrix = matrix; - mPaint = paint; - mText = static_cast<const uint16_t*>(text); - mY = y; - reset(); - } - - /* called only while the picture is parsed */ - int top() { - if (mTop == INT_MAX) { - SkPoint result; - SkPaint::FontMetrics metrics; - mPaint.getFontMetrics(&metrics); - mMatrix.mapXY(0, metrics.fAscent + mY, &result); - mTop = SkScalarFloor(result.fY); - } - return mTop; - } - -#if DEBUG_NAV_UI - // make current (possibily uncomputed) value visible for debugging - int topDebug() const - { - return mTop; - } -#endif - -protected: - SkIRect mArea; - SkBounder::GlyphRec mLastCandidate; - SkBounder::GlyphRec mLastGlyph; - SkPaint mLastPaint; // available after picture has been parsed - SkPaint mLastPaintCandidate; // associated with candidate glyph - SkUnichar mLastUni; - SkUnichar mLastUniCandidate; - SkMatrix mMatrix; - SkPaint mPaint; // only set up while the picture is parsed - const uint16_t* mText; - SkScalar mY; -private: - int mBase; - int mBottom; - SkFixed mMinSpaceWidth; - int mTop; - friend class EdgeCheck; -}; - -// generate the limit area for the new selection -class LineCheck : public CommonCheck { -public: - LineCheck(int x, int y, const SkIRect& area) - : INHERITED(area) - , mX(x) - , mY(y) - , mInBetween(false) - { - mLast.setEmpty(); - } - - void finish(const SkRegion& selectedRgn) - { - if (!mParagraphs.count() && mLast.isEmpty()) - return; - processLine(); - bool above = false; - bool below = false; - bool selected = false; - SkRegion localRgn(selectedRgn); - localRgn.translate(-mArea.fLeft, -mArea.fTop, &localRgn); - DBG_NAV_LOGD("localRgn=(%d,%d,%d,%d)", - localRgn.getBounds().fLeft, localRgn.getBounds().fTop, - localRgn.getBounds().fRight, localRgn.getBounds().fBottom); - for (int index = 0; index < mParagraphs.count(); index++) { - const SkIRect& rect = mParagraphs[index]; - bool localSelected = localRgn.intersects(rect); - DBG_NAV_LOGD("[%d] rect=(%d,%d,%d,%d)", index, rect.fLeft, rect.fTop, - rect.fRight, rect.fBottom); - if (localSelected) { - DBG_NAV_LOGD("[%d] localSelected=true", index); - *mSelected.append() = rect; - } - if (rect.fRight <= mX || rect.fLeft >= mX) - continue; - if (mY > rect.fBottom) { - below = true; - selected |= localSelected; - DBG_NAV_LOGD("[%d] below=true localSelected=%s", index, - localSelected ? "true" : "false"); - } - if (mY < rect.fTop) { - above = true; - selected |= localSelected; - DBG_NAV_LOGD("[%d] above=true localSelected=%s", index, - localSelected ? "true" : "false"); - } - } - DBG_NAV_LOGD("mX=%d mY=%d above=%s below=%s selected=%s", - mX, mY, above ? "true" : "false", below ? "true" : "false", - selected ? "true" : "false"); - mInBetween = above && below && selected; - } - - bool inBetween() const - { - return mInBetween; - } - - bool inColumn(const SkIRect& test) const - { - for (int index = 0; index < mSelected.count(); index++) { - const SkIRect& rect = mSelected[index]; - if (rect.fRight > test.fLeft && rect.fLeft < test.fRight) - return true; - } - return false; - } - - bool inColumn(int x, int y) const - { - for (int index = 0; index < mSelected.count(); index++) { - const SkIRect& rect = mSelected[index]; - if (rect.contains(x, y)) - return true; - } - return false; - } - - virtual bool onIRect(const SkIRect& rect) - { - SkIRect bounds; - bounds.set(rect.fLeft, top(), rect.fRight, bottom()); - // assume that characters must be consecutive to describe spaces - // (i.e., don't join rects drawn at different times) - if (bounds.fTop != mLast.fTop || bounds.fBottom != mLast.fBottom - || bounds.fLeft > mLast.fRight + minSpaceWidth(mPaint) - || bounds.fLeft < mLast.fLeft) { - processLine(); - mLast = bounds; - } else - mLast.join(bounds); - return false; - } - - void processLine() - { - // assume line spacing of 1.5 - int lineHeight = bottom() - top(); - mLast.inset(0, -lineHeight >> 1); - // collect arrays of rectangles making up glyphs below or above this one - for (int index = 0; index < mParagraphs.count(); index++) { - SkIRect& rect = mParagraphs[index]; - if (SkIRect::Intersects(rect, mLast)) { - rect.join(mLast); - return; - } - } - *mParagraphs.append() = mLast; - } - -protected: - int mX; - int mY; - SkIRect mLast; - SkTDArray<SkIRect> mParagraphs; - SkTDArray<SkIRect> mSelected; - bool mInBetween; -private: - typedef CommonCheck INHERITED; -}; - -class SelectText::FirstCheck : public CommonCheck { -public: - FirstCheck(int x, int y, const SkIRect& area) - : INHERITED(area) - , mLineCheck(0) - , mFocusX(x - area.fLeft) - , mFocusY(y - area.fTop) - , mBestInColumn(false) - , mRecordGlyph(false) - { - reset(); - } - - const SkIRect& adjustedBounds(int* base) - { - *base = mBestBase + mArea.fTop; - mBestBounds.offset(mArea.fLeft, mArea.fTop); - DBG_NAV_LOGD("FirstCheck mBestBounds:(%d, %d, %d, %d) mTop=%d mBottom=%d", - mBestBounds.fLeft, mBestBounds.fTop, mBestBounds.fRight, - mBestBounds.fBottom, topDebug(), bottomDebug()); - return mBestBounds; - } - - int focusX() const { return mFocusX; } - int focusY() const { return mFocusY; } - - virtual bool onIRectGlyph(const SkIRect& rect, - const SkBounder::GlyphRec& rec) - { - /* compute distance from rectangle center. - * centerX = (rect.L + rect.R) / 2 - * multiply centerX and comparison x by 2 to retain better precision - */ - SkIRect testBounds = {rect.fLeft, top(), rect.fRight, bottom()}; - // dx and dy are the distances from the tested edge - // The edge distance is paramount if the test point is far away - int dx = std::max(0, std::max(testBounds.fLeft - mFocusX, - mFocusX - testBounds.fRight)); - int dy = std::max(0, std::max(testBounds.fTop - mFocusY, - mFocusY - testBounds.fBottom)); - bool testInColumn = false; - bool inBetween = false; - bool inFocus = false; - if (mLineCheck) { - testInColumn = mLineCheck->inColumn(testBounds); - inBetween = mLineCheck->inBetween(); - inFocus = mLineCheck->inColumn(mFocusX, mFocusY); - } -#ifdef EXTRA_NOISY_LOGGING - if (dy < 10) { - SkUnichar ch = getUniChar(rec); - DBG_NAV_LOGD("FC dx/y=%d,%d mDx/y=%d,%d test=%d,%d,%d,%d" - " best=%d,%d,%d,%d bestIn=%s tween=%s testIn=%s focus=%s ch=%c", - dx, dy, mDx, mDy, - testBounds.fLeft, testBounds.fTop, testBounds.fRight, - testBounds.fBottom, mBestBounds.fLeft, mBestBounds.fTop, - mBestBounds.fRight, mBestBounds.fBottom, - mBestInColumn ? "true" : "false", inBetween ? "true" : "false", - testInColumn ? "true" : "false", inFocus ? "true" : "false", - ch < 0x7f ? ch : '?'); - } -#endif - if ((mBestInColumn || inBetween) && !testInColumn) { -#ifdef EXTRA_NOISY_LOGGING - if (dy < 10) DBG_NAV_LOG("FirstCheck reject column"); -#endif - return false; - } - bool ignoreColumn = mBestInColumn == testInColumn || !inFocus; - if (ignoreColumn && dy > 0 && (mDy < dy - || (mDy == dy && dx > 0 && mDx <= dx))) { -#ifdef EXTRA_NOISY_LOGGING - if (dy < 10) DBG_NAV_LOG("FirstCheck reject edge"); -#endif - return false; - } - // cx and cy are the distances from the tested center - // The center distance is used when the test point is over the text - int cx = std::abs(((testBounds.fLeft + testBounds.fRight) >> 1) - - mFocusX); - int cy = std::abs(((testBounds.fTop + testBounds.fBottom) >> 1) - - mFocusY); - if (ignoreColumn && dy == 0 && mDy == 0) { - if (mCy < cy) { -#ifdef EXTRA_NOISY_LOGGING - DBG_NAV_LOGD("FirstCheck reject cy=%d mCy=%d", cy, mCy); -#endif - return false; - } - if (mCy == cy) { - if (dx == 0 && mDx == 0) { - if (mCx < cx) { -#ifdef EXTRA_NOISY_LOGGING - DBG_NAV_LOGD("FirstCheck reject cx=%d mCx=%d", cx, mCx); -#endif - return false; - } - } else if (dx > 0 && mDx <= dx) { -#ifdef EXTRA_NOISY_LOGGING - DBG_NAV_LOGD("FirstCheck reject dx=%d mDx=%d", dx, mDx); -#endif - return false; - } - } - } -#ifdef EXTRA_NOISY_LOGGING - if (dy < 10) { - DBG_NAV_LOGD("FirstCheck cx/y=(%d,%d)", cx, cy); - } -#endif - mBestBase = base(); - mBestBounds = testBounds; - mBestInColumn = testInColumn; -#ifndef EXTRA_NOISY_LOGGING - if (dy < 10 && dx < 10) -#endif - { -#if DEBUG_NAV_UI - SkUnichar ch = getUniChar(rec); -#endif - DBG_NAV_LOGD("FirstCheck dx/y=(%d,%d) mFocus=(%d,%d)" - " mBestBounds={%d,%d,r=%d,b=%d} inColumn=%s ch=%c", - dx, dy, mFocusX, mFocusY, - mBestBounds.fLeft, mBestBounds.fTop, - mBestBounds.fRight, mBestBounds.fBottom, - mBestInColumn ? "true" : "false", ch < 0x7f ? ch : '?'); - } - mCx = cx; - mCy = cy; - mDx = dx; - mDy = dy; - if (mRecordGlyph) - recordGlyph(rec); - return false; - } - - void reset() - { - mBestBounds.setEmpty(); - mDx = mDy = mCx = mCy = INT_MAX; - } - - void setLines(const LineCheck* lineCheck) { mLineCheck = lineCheck; } - void setRecordGlyph() { mRecordGlyph = true; } - -protected: - const LineCheck* mLineCheck; - int mBestBase; - SkIRect mBestBounds; - int mCx; - int mCy; - int mDx; - int mDy; - int mFocusX; - int mFocusY; - bool mBestInColumn; - bool mRecordGlyph; -private: - typedef CommonCheck INHERITED; -}; - -class SelectText::EdgeCheck : public SelectText::FirstCheck { -public: - EdgeCheck(int x, int y, const SkIRect& area, CommonCheck& last, bool left) - : INHERITED(x, y, area) - , mLast(area) - , mLeft(left) - { - mLast.set(last); // CommonCheck::set() - setGlyph(last); - } - - bool adjacent() - { - return !mLast.isSpace(mLastGlyph); - } - - const SkIRect& bestBounds(int* base) - { - *base = mBestBase; - return mBestBounds; - } - - virtual bool onIRectGlyph(const SkIRect& rect, - const SkBounder::GlyphRec& rec) - { - int dx = mLeft ? mFocusX - rect.fRight : rect.fLeft - mFocusX; - int dy = ((top() + bottom()) >> 1) - mFocusY; - dx = abs(dx); - dy = abs(dy); - if (mLeft ? mFocusX <= rect.fLeft : mFocusX >= rect.fRight) { - if (dx <= 10 && dy <= 10) { - DBG_NAV_LOGD("EdgeCheck fLeft=%d fRight=%d mFocusX=%d dx=%d dy=%d", - rect.fLeft, rect.fRight, mFocusX, dx, dy); - } - return false; - } - if (mDy > dy || (mDy == dy && mDx > dx)) { - if (rec.fLSB == mLastGlyph.fLSB && rec.fRSB == mLastGlyph.fRSB) { - DBG_NAV_LOGD("dup rec.fLSB.fX=%g rec.fRSB.fX=%g", - SkFixedToScalar(rec.fLSB.fX), SkFixedToScalar(rec.fRSB.fX)); - return false; - } - recordGlyph(rec); - mDx = dx; - mDy = dy; - mBestBase = base(); - mBestBounds.set(rect.fLeft, top(), rect.fRight, bottom()); - if (dx <= 10 && dy <= 10) { - DBG_NAV_LOGD("EdgeCheck mBestBounds={%d,%d,r=%d,b=%d} dx/y=(%d, %d)", - mBestBounds.fLeft, mBestBounds.fTop, - mBestBounds.fRight, mBestBounds.fBottom, dx, dy); - } - } - return false; - } - - void shiftStart(SkIRect bounds) - { - DBG_NAV_LOGD("EdgeCheck mFocusX=%d mLeft=%s bounds.fLeft=%d bounds.fRight=%d", - mFocusX, mLeft ? "true" : "false", bounds.fLeft, bounds.fRight); - reset(); - mFocusX = mLeft ? bounds.fLeft : bounds.fRight; - mLast.set(*this); // CommonCheck::set() - } - -protected: - CommonCheck mLast; - bool mLeft; -private: - typedef SelectText::FirstCheck INHERITED; -}; - -class FindFirst : public CommonCheck { -public: - FindFirst(const SkIRect& area) - : INHERITED(area) - { - mBestBounds.set(area.width(), area.height(), area.width(), area.height()); - } - - const SkIRect& bestBounds(int* base) - { - *base = mBestBase; - return mBestBounds; - } - - virtual bool onIRect(const SkIRect& rect) - { - if (mBestBounds.isEmpty()) { - mBestBase = base(); - mBestBounds.set(rect.fLeft, top(), rect.fRight, bottom()); - } - return false; - } - -protected: - int mBestBase; - SkIRect mBestBounds; -private: - typedef CommonCheck INHERITED; -}; - -class FindLast : public FindFirst { -public: - FindLast(const SkIRect& area) - : INHERITED(area) - { - mBestBounds.setEmpty(); - } - - virtual bool onIRect(const SkIRect& rect) - { - mBestBase = base(); - mBestBounds.set(rect.fLeft, top(), rect.fRight, bottom()); - return false; - } - -private: - typedef FindFirst INHERITED; -}; - -static bool baseLinesAgree(const SkIRect& rectA, int baseA, - const SkIRect& rectB, int baseB) -{ - return (rectA.fTop < baseB && rectA.fBottom >= baseB) - || (rectB.fTop < baseA && rectB.fBottom >= baseA); -} - -class BuilderCheck : public CommonCheck { -protected: - enum IntersectionType { - NO_INTERSECTION, // debugging printf expects this to equal zero - LAST_INTERSECTION, // debugging printf expects this to equal one - WAIT_FOR_INTERSECTION - }; - - BuilderCheck(const SkIRect& start, int startBase, const SkIRect& end, - int endBase, const SkIRect& area) - : INHERITED(area) - , mCapture(false) - , mEnd(end) - , mEndBase(endBase) - , mStart(start) - , mStartBase(startBase) - { - mEnd.offset(-area.fLeft, -area.fTop); - mEndBase -= area.fTop; - mEndExtra.setEmpty(); - mLast.setEmpty(); - mLastBase = INT_MAX; - mSelectRect.setEmpty(); - mStart.offset(-area.fLeft, -area.fTop); - mStartBase -= area.fTop; - mStartExtra.setEmpty(); - DBG_NAV_LOGD(" mStart=(%d,%d,r=%d,b=%d) mStartBase=%d" - " mEnd=(%d,%d,r=%d,b=%d) mEndBase=%d", - mStart.fLeft, mStart.fTop, mStart.fRight, mStart.fBottom, mStartBase, - mEnd.fLeft, mEnd.fTop, mEnd.fRight, mEnd.fBottom, mEndBase); - } - - int checkFlipRect(const SkIRect& full, int fullBase) { - mCollectFull = false; - // is the text to collect between the selection top and bottom? - if (fullBase < mStart.fTop || fullBase > mEnd.fBottom) { - if (VERBOSE_LOGGING && !mLast.isEmpty()) DBG_NAV_LOGD("%s 1" - " full=(%d,%d,r=%d,b=%d) fullBase=%d" - " mLast=(%d,%d,r=%d,b=%d) mLastBase=%d", - mLastIntersects ? "LAST_INTERSECTION" : "NO_INTERSECTION", - full.fLeft, full.fTop, full.fRight, full.fBottom, fullBase, - mLast.fLeft, mLast.fTop, mLast.fRight, mLast.fBottom, mLastBase); - return mLastIntersects; - } - // is the text to the left of the selection start? - if (baseLinesAgree(mStart, mStartBase, full, fullBase) - && full.fLeft < mStart.fLeft) { - if (VERBOSE_LOGGING) DBG_NAV_LOGD("%s 2" - " full=(%d,%d,r=%d,b=%d) fullBase=%d" - " mLast=(%d,%d,r=%d,b=%d) mLastBase=%d" - " mStart=(%d,%d,r=%d,b=%d) mStartBase=%d", - mLastIntersects ? "LAST_INTERSECTION" : "NO_INTERSECTION", - full.fLeft, full.fTop, full.fRight, full.fBottom, fullBase, - mLast.fLeft, mLast.fTop, mLast.fRight, mLast.fBottom, mLastBase, - mStart.fLeft, mStart.fTop, mStart.fRight, mStart.fBottom, mStartBase); - mStartExtra.join(full); - return mLastIntersects; - } - // is the text to the right of the selection end? - if (baseLinesAgree(mEnd, mEndBase, full, fullBase) - && full.fRight > mEnd.fRight) { - if (VERBOSE_LOGGING) DBG_NAV_LOGD("%s 3" - " full=(%d,%d,r=%d,b=%d) fullBase=%d" - " mLast=(%d,%d,r=%d,b=%d) mLastBase=%d" - " mEnd=(%d,%d,r=%d,b=%d) mEndBase=%d", - mLastIntersects ? "LAST_INTERSECTION" : "NO_INTERSECTION", - full.fLeft, full.fTop, full.fRight, full.fBottom, fullBase, - mLast.fLeft, mLast.fTop, mLast.fRight, mLast.fBottom, mLastBase, - mEnd.fLeft, mEnd.fTop, mEnd.fRight, mEnd.fBottom, mEndBase); - mEndExtra.join(full); - return mLastIntersects; - } - int spaceGap = SkFixedRound(minSpaceWidth(mPaint) * 3); - // should text to the left of the start be added to the selection bounds? - if (!mStartExtra.isEmpty()) { - if (VERBOSE_LOGGING) DBG_NAV_LOGD("mSelectRect=(%d,%d,r=%d,b=%d)" - " mStartExtra=(%d,%d,r=%d,b=%d)", - mSelectRect.fLeft, mSelectRect.fTop, mSelectRect.fRight, mSelectRect.fBottom, - mStartExtra.fLeft, mStartExtra.fTop, mStartExtra.fRight, mStartExtra.fBottom); - if (mStartExtra.fRight + spaceGap >= mStart.fLeft) - mSelectRect.join(mStartExtra); - mStartExtra.setEmpty(); - } - // should text to the right of the end be added to the selection bounds? - if (!mEndExtra.isEmpty()) { - if (VERBOSE_LOGGING) DBG_NAV_LOGD("mSelectRect=(%d,%d,r=%d,b=%d)" - " mEndExtra=(%d,%d,r=%d,b=%d)", - mSelectRect.fLeft, mSelectRect.fTop, mSelectRect.fRight, mSelectRect.fBottom, - mEndExtra.fLeft, mEndExtra.fTop, mEndExtra.fRight, mEndExtra.fBottom); - if (mEndExtra.fLeft - spaceGap <= mEnd.fRight) - mSelectRect.join(mEndExtra); - mEndExtra.setEmpty(); - } - bool sameBaseLine = baseLinesAgree(mLast, mLastBase, full, fullBase); - bool adjacent = (full.fLeft - mLast.fRight) < spaceGap; - // is this the first, or are there more characters on the same line? - if (mLast.isEmpty() || (sameBaseLine && adjacent)) { - if (VERBOSE_LOGGING) DBG_NAV_LOGD("WAIT_FOR_INTERSECTION" - " full=(%d,%d,r=%d,b=%d) fullBase=%d" - " mLast=(%d,%d,r=%d,b=%d) mLastBase=%d" - " mSelectRect=(%d,%d,r=%d,b=%d)", - full.fLeft, full.fTop, full.fRight, full.fBottom, fullBase, - mLast.fLeft, mLast.fTop, mLast.fRight, mLast.fBottom, mLastBase, - mSelectRect.fLeft, mSelectRect.fTop, mSelectRect.fRight, mSelectRect.fBottom); - mLast.join(full); - mLastIntersects = SkIRect::Intersects(mLast, mSelectRect); - return WAIT_FOR_INTERSECTION; - } - if (VERBOSE_LOGGING) DBG_NAV_LOGD("%s 4" - " mLast=(%d,%d,r=%d,b=%d) mLastBase=%d" - " full=(%d,%d,r=%d,b=%d) fullBase=%d" - " mSelectRect=(%d,%d,r=%d,b=%d)" - " mStartExtra=(%d,%d,r=%d,b=%d)" - " mEndExtra=(%d,%d,r=%d,b=%d)", - mLastIntersects ? "LAST_INTERSECTION" : "NO_INTERSECTION", - mLast.fLeft, mLast.fTop, mLast.fRight, mLast.fBottom, mLastBase, - full.fLeft, full.fTop, full.fRight, full.fBottom, fullBase, - mSelectRect.fLeft, mSelectRect.fTop, mSelectRect.fRight, mSelectRect.fBottom, - mStartExtra.fLeft, mStartExtra.fTop, mStartExtra.fRight, mStartExtra.fBottom, - mEndExtra.fLeft, mEndExtra.fTop, mEndExtra.fRight, mEndExtra.fBottom); - // after the caller determines what to do with the last collection, - // start the collection over with full and fullBase. - mCollectFull = true; - return mLastIntersects; - } - - bool resetLast(const SkIRect& full, int fullBase) - { - if (mCollectFull) { - mLast = full; - mLastBase = fullBase; - mLastIntersects = SkIRect::Intersects(mLast, mSelectRect); - } else { - mLast.setEmpty(); - mLastBase = INT_MAX; - mLastIntersects = false; - } - return mCollectFull; - } - - void setFlippedState() - { - mSelectRect = mStart; - mSelectRect.join(mEnd); - DBG_NAV_LOGD("mSelectRect=(%d,%d,r=%d,b=%d)", - mSelectRect.fLeft, mSelectRect.fTop, mSelectRect.fRight, mSelectRect.fBottom); - mLast.setEmpty(); - mLastBase = INT_MAX; - mLastIntersects = NO_INTERSECTION; - } - - bool mCapture; - bool mCollectFull; - SkIRect mEnd; - int mEndBase; - SkIRect mEndExtra; - bool mFlipped; - SkIRect mLast; - int mLastBase; - int mLastIntersects; - SkIRect mSelectRect; - SkIRect mStart; - SkIRect mStartExtra; - int mStartBase; -private: - typedef CommonCheck INHERITED; - -}; - -class MultilineBuilder : public BuilderCheck { -public: - MultilineBuilder(const SkIRect& start, int startBase, const SkIRect& end, - int endBase, const SkIRect& area, SkRegion* region) - : INHERITED(start, startBase, end, endBase, area) - , mSelectRegion(region) - { - mFlipped = false; - } - - void addLastToRegion() { - if (VERBOSE_LOGGING) DBG_NAV_LOGD(" mLast=(%d,%d,r=%d,b=%d)", - mLast.fLeft, mLast.fTop, mLast.fRight, mLast.fBottom); - mSelectRegion->op(mLast, SkRegion::kUnion_Op); - } - - void finish() { - if (!mFlipped || !mLastIntersects) - return; - addLastToRegion(); - } - - // return true if capture end was not found after capture begin - bool flipped() { - DBG_NAV_LOGD("flipped=%s", mCapture ? "true" : "false"); - if (!mCapture) - return false; - mFlipped = true; - setFlippedState(); - mSelectRegion->setEmpty(); - return true; - } - - virtual bool onIRect(const SkIRect& rect) { - SkIRect full; - full.set(rect.fLeft, top(), rect.fRight, bottom()); - int fullBase = base(); - if (mFlipped) { - int intersectType = checkFlipRect(full, fullBase); - if (intersectType == LAST_INTERSECTION) - addLastToRegion(); - if (intersectType != WAIT_FOR_INTERSECTION) - resetLast(full, fullBase); - return false; - } - if (full == mStart) { - if (VERBOSE_LOGGING) DBG_NAV_LOGD("full == mStart full=(%d,%d,r=%d,b=%d)", - full.fLeft, full.fTop, full.fRight, full.fBottom); - mCapture = true; - } - if (mCapture) { - bool sameLines = baseLinesAgree(mLast, mLastBase, full, fullBase); - if (sameLines) - mLast.join(full); - if (!sameLines || full == mEnd) { - if (VERBOSE_LOGGING) DBG_NAV_LOGD("finish mLast=(%d,%d,r=%d,b=%d)", - mLast.fLeft, mLast.fTop, mLast.fRight, mLast.fBottom); - addLastToRegion(); - mLast = full; - mLastBase = fullBase; - } - } - if (full == mEnd) { - if (VERBOSE_LOGGING) DBG_NAV_LOGD("full == mEnd full=(%d,%d,r=%d,b=%d)", - full.fLeft, full.fTop, full.fRight, full.fBottom); - mCapture = false; - if (full == mStart) - addLastToRegion(); - } - return false; - } - -protected: - SkRegion* mSelectRegion; -private: - typedef BuilderCheck INHERITED; -}; - -static inline bool compareBounds(const SkIRect* first, const SkIRect* second) -{ - return first->fTop < second->fTop; -} - -class TextExtractor : public BuilderCheck { -public: - TextExtractor(const SkIRect& start, int startBase, const SkIRect& end, - int endBase, const SkIRect& area, bool flipped) - : INHERITED(start, startBase, end, endBase, area) - , mSelectStartIndex(-1) - , mSkipFirstSpace(true) // don't start with a space - { - mFlipped = flipped; - if (flipped) - setFlippedState(); - } - - void addCharacter(const SkBounder::GlyphRec& rec) - { - if (mSelectStartIndex < 0) - mSelectStartIndex = mSelectText.count(); - if (!mSkipFirstSpace) { - if (addNewLine(rec)) { - DBG_NAV_LOG("write new line"); - *mSelectText.append() = '\n'; - *mSelectText.append() = '\n'; - } else if (addSpace(rec)) { - DBG_NAV_LOG("write space"); - *mSelectText.append() = ' '; - } - } else - mSkipFirstSpace = false; - recordGlyph(rec); - finishGlyph(); - if (VERBOSE_LOGGING) DBG_NAV_LOGD("glyphID=%d uni=%d '%c'", rec.fGlyphID, - mLastUni, mLastUni && mLastUni < 0x7f ? mLastUni : '?'); - if (mLastUni) { - uint16_t chars[2]; - size_t count = SkUTF16_FromUnichar(mLastUni, chars); - *mSelectText.append() = chars[0]; - if (count == 2) - *mSelectText.append() = chars[1]; - } - } - - void addLast() - { - *mSelectBounds.append() = mLast; - *mSelectStart.append() = mSelectStartIndex; - *mSelectEnd.append() = mSelectText.count(); - } - - /* Text characters are collected before it's been determined that the - characters are part of the selection. The bounds describe valid parts - of the selection, but the bounds are out of order. - - This sorts the characters by sorting the bounds, then copying the - characters that were captured. - */ - void finish() - { - if (mLastIntersects) - addLast(); - Vector<SkIRect*> sortedBounds; - SkTDArray<uint16_t> temp; - int index; - DBG_NAV_LOGD("mSelectBounds.count=%d text=%d", mSelectBounds.count(), - mSelectText.count()); - for (index = 0; index < mSelectBounds.count(); index++) - sortedBounds.append(&mSelectBounds[index]); - std::sort(sortedBounds.begin(), sortedBounds.end(), compareBounds); - int lastEnd = -1; - for (index = 0; index < mSelectBounds.count(); index++) { - int order = sortedBounds[index] - &mSelectBounds[0]; - int start = mSelectStart[order]; - int end = mSelectEnd[order]; - DBG_NAV_LOGD("order=%d start=%d end=%d top=%d", order, start, end, - mSelectBounds[order].fTop); - int count = temp.count(); - if (count > 0 && temp[count - 1] != '\n' && start != lastEnd) { - // always separate paragraphs when original text is out of order - DBG_NAV_LOG("write new line"); - *temp.append() = '\n'; - *temp.append() = '\n'; - } - temp.append(end - start, &mSelectText[start]); - lastEnd = end; - } - mSelectText.swap(temp); - } - - virtual bool onIRectGlyph(const SkIRect& rect, - const SkBounder::GlyphRec& rec) - { - SkIRect full; - full.set(rect.fLeft, top(), rect.fRight, bottom()); - int fullBase = base(); - if (mFlipped) { - int intersectType = checkFlipRect(full, fullBase); - if (WAIT_FOR_INTERSECTION == intersectType) - addCharacter(rec); // may not be copied - else { - if (LAST_INTERSECTION == intersectType) - addLast(); - else - mSkipFirstSpace = true; - mSelectStartIndex = -1; - if (resetLast(full, fullBase)) - addCharacter(rec); // may not be copied - } - return false; - } - if (full == mStart) - mCapture = true; - if (mCapture) - addCharacter(rec); - else - mSkipFirstSpace = true; - if (full == mEnd) - mCapture = false; - return false; - } - - WTF::String text() { - if (mFlipped) - finish(); - // the text has been copied in visual order. Reverse as needed if - // result contains right-to-left characters. - const uint16_t* start = mSelectText.begin(); - const uint16_t* end = mSelectText.end(); - while (start < end) { - SkUnichar ch = SkUTF16_NextUnichar(&start); - WTF::Unicode::Direction charDirection = WTF::Unicode::direction(ch); - if (WTF::Unicode::RightToLeftArabic == charDirection - || WTF::Unicode::RightToLeft == charDirection) { - WebCore::ReverseBidi(mSelectText.begin(), mSelectText.count()); - break; - } - } - return WTF::String(mSelectText.begin(), mSelectText.count()); - } - -protected: - SkIRect mEmpty; - SkTDArray<SkIRect> mSelectBounds; - SkTDArray<int> mSelectEnd; - SkTDArray<int> mSelectStart; - int mSelectStartIndex; - SkTDArray<uint16_t> mSelectText; - bool mSkipFirstSpace; -private: - typedef BuilderCheck INHERITED; -}; - -class TextCanvas : public ParseCanvas { -public: - - TextCanvas(CommonCheck* bounder) - : mBounder(*bounder) { - setBounder(bounder); - SkBitmap bitmap; - const SkIRect& area = bounder->getArea(); - bitmap.setConfig(SkBitmap::kARGB_8888_Config, area.width(), - area.height()); - setBitmapDevice(bitmap); - translate(SkIntToScalar(-area.fLeft), SkIntToScalar(-area.fTop)); -#ifdef DEBUG_NAV_UI - const SkIRect& clip = getTotalClip().getBounds(); - const SkMatrix& matrix = getTotalMatrix(); - DBG_NAV_LOGD("bitmap=(%d,%d) clip=(%d,%d,%d,%d) matrix=(%g,%g)", - bitmap.width(), bitmap.height(), clip.fLeft, clip.fTop, - clip.fRight, clip.fBottom, matrix.getTranslateX(), matrix.getTranslateY()); -#endif - } - - virtual void drawPaint(const SkPaint& paint) { - } - - virtual void drawPoints(PointMode mode, size_t count, const SkPoint pts[], - const SkPaint& paint) { - } - - virtual void drawRect(const SkRect& rect, const SkPaint& paint) { - } - - virtual void drawPath(const SkPath& path, const SkPaint& paint) { - } - - virtual void commonDrawBitmap(const SkBitmap& bitmap, const SkIRect* rect, - const SkMatrix& matrix, const SkPaint& paint) { - } - - virtual void drawSprite(const SkBitmap& bitmap, int left, int top, - const SkPaint* paint = NULL) { - } - - virtual void drawText(const void* text, size_t byteLength, SkScalar x, - SkScalar y, const SkPaint& paint) { - mBounder.setUp(paint, getTotalMatrix(), y, text); - INHERITED::drawText(text, byteLength, x, y, paint); - } - - virtual void drawPosTextH(const void* text, size_t byteLength, - const SkScalar xpos[], SkScalar constY, - const SkPaint& paint) { - mBounder.setUp(paint, getTotalMatrix(), constY, text); - INHERITED::drawPosTextH(text, byteLength, xpos, constY, paint); - } - - virtual void drawVertices(VertexMode vmode, int vertexCount, - const SkPoint vertices[], const SkPoint texs[], - const SkColor colors[], SkXfermode* xmode, - const uint16_t indices[], int indexCount, - const SkPaint& paint) { - } - - CommonCheck& mBounder; -private: - typedef ParseCanvas INHERITED; -}; - -static bool buildSelection(const SkPicture& picture, const SkIRect& area, - const SkIRect& selStart, int startBase, - const SkIRect& selEnd, int endBase, SkRegion* region) -{ - DBG_NAV_LOGD("area=(%d, %d, %d, %d) selStart=(%d, %d, %d, %d)" - " selEnd=(%d, %d, %d, %d)", - area.fLeft, area.fTop, area.fRight, area.fBottom, - selStart.fLeft, selStart.fTop, selStart.fRight, selStart.fBottom, - selEnd.fLeft, selEnd.fTop, selEnd.fRight, selEnd.fBottom); - MultilineBuilder builder(selStart, startBase, selEnd, endBase, area, region); - TextCanvas checker(&builder); - checker.drawPicture(const_cast<SkPicture&>(picture)); - bool flipped = builder.flipped(); - if (flipped) { - TextCanvas checker(&builder); - checker.drawPicture(const_cast<SkPicture&>(picture)); - } - builder.finish(); - region->translate(area.fLeft, area.fTop); - return flipped; -} - -static SkIRect findFirst(const SkPicture& picture, int* base) -{ - SkIRect area; - area.set(0, 0, picture.width(), picture.height()); - FindFirst finder(area); - TextCanvas checker(&finder); - checker.drawPicture(const_cast<SkPicture&>(picture)); - return finder.bestBounds(base); -} - -static SkIRect findLast(const SkPicture& picture, int* base) -{ - SkIRect area; - area.set(0, 0, picture.width(), picture.height()); - FindLast finder(area); - TextCanvas checker(&finder); - checker.drawPicture(const_cast<SkPicture&>(picture)); - return finder.bestBounds(base); -} - -static WTF::String text(const SkPicture& picture, const SkIRect& area, - const SkIRect& start, int startBase, const SkIRect& end, - int endBase, bool flipped) +SelectText::HandleId SelectText::mapId(HandleId id) { - TextExtractor extractor(start, startBase, end, endBase, area, flipped); - TextCanvas checker(&extractor); - checker.drawPicture(const_cast<SkPicture&>(picture)); - return extractor.text(); -} - -#define CONTROL_NOTCH 16 -// TODO: Now that java is the one actually drawing these, get the real values -// from the drawable itself -#define CONTROL_HEIGHT 47 -#define CONTROL_WIDTH 26 -#define CONTROL_SLOP 5 -#define STROKE_WIDTH 1.0f -#define STROKE_OUTSET 3.5f -#define STROKE_I_OUTSET 4 // (int) ceil(STROKE_OUTSET) -#define STROKE_COLOR 0x66000000 -#define OUTER_COLOR 0x33000000 -#define INNER_COLOR 0xe6aae300 - -SelectText::SelectText() - : m_controlWidth(CONTROL_WIDTH) - , m_controlHeight(CONTROL_HEIGHT) - , m_controlSlop(CONTROL_SLOP) -{ - m_picture = 0; - reset(); - SkPaint paint; - SkRect oval; - - SkPath startOuterPath; - oval.set(-CONTROL_WIDTH - STROKE_OUTSET, CONTROL_NOTCH - STROKE_OUTSET, - -CONTROL_WIDTH + STROKE_OUTSET, CONTROL_NOTCH + STROKE_OUTSET); - startOuterPath.arcTo(oval, 180, 45, true); - oval.set(-STROKE_OUTSET, -STROKE_OUTSET, STROKE_OUTSET, STROKE_OUTSET); - startOuterPath.arcTo(oval, 180 + 45, 135, false); - oval.set(-STROKE_OUTSET, CONTROL_HEIGHT - STROKE_OUTSET, - STROKE_OUTSET, CONTROL_HEIGHT + STROKE_OUTSET); - startOuterPath.arcTo(oval, 0, 90, false); - oval.set(-CONTROL_WIDTH - STROKE_OUTSET, CONTROL_HEIGHT - STROKE_OUTSET, - -CONTROL_WIDTH + STROKE_OUTSET, CONTROL_HEIGHT + STROKE_OUTSET); - startOuterPath.arcTo(oval, 90, 90, false); - startOuterPath.close(); - SkPath startInnerPath; - startInnerPath.moveTo(-CONTROL_WIDTH, CONTROL_NOTCH); - startInnerPath.lineTo(-CONTROL_WIDTH, CONTROL_HEIGHT); - startInnerPath.lineTo(0, CONTROL_HEIGHT); - startInnerPath.lineTo(0, 0); - startInnerPath.close(); - startOuterPath.addPath(startInnerPath, 0, 0); - - SkCanvas* canvas = m_startControl.beginRecording( - CONTROL_WIDTH + STROKE_OUTSET * 2, - CONTROL_HEIGHT + STROKE_OUTSET * 2); - paint.setAntiAlias(true); - paint.setColor(INNER_COLOR); - paint.setStyle(SkPaint::kFill_Style); - canvas->drawPath(startInnerPath, paint); - paint.setColor(OUTER_COLOR); - canvas->drawPath(startOuterPath, paint); - paint.setStyle(SkPaint::kStroke_Style); - paint.setColor(STROKE_COLOR); - paint.setStrokeWidth(STROKE_WIDTH); - canvas->drawPath(startInnerPath, paint); - m_startControl.endRecording(); - - SkPath endOuterPath; - oval.set(-STROKE_OUTSET, -STROKE_OUTSET, STROKE_OUTSET, STROKE_OUTSET); - endOuterPath.arcTo(oval, 180, 135, true); - oval.set(CONTROL_WIDTH - STROKE_OUTSET, CONTROL_NOTCH - STROKE_OUTSET, - CONTROL_WIDTH + STROKE_OUTSET, CONTROL_NOTCH + STROKE_OUTSET); - endOuterPath.arcTo(oval, 360 - 45, 45, false); - oval.set(CONTROL_WIDTH - STROKE_OUTSET, CONTROL_HEIGHT - STROKE_OUTSET, - CONTROL_WIDTH + STROKE_OUTSET, CONTROL_HEIGHT + STROKE_OUTSET); - endOuterPath.arcTo(oval, 0, 90, false); - oval.set(-STROKE_OUTSET, CONTROL_HEIGHT - STROKE_OUTSET, - STROKE_OUTSET, CONTROL_HEIGHT + STROKE_OUTSET); - endOuterPath.arcTo(oval, 90, 90, false); - startOuterPath.close(); - SkPath endInnerPath; - endInnerPath.moveTo(0, 0); - endInnerPath.lineTo(0, CONTROL_HEIGHT); - endInnerPath.lineTo(CONTROL_WIDTH, CONTROL_HEIGHT); - endInnerPath.lineTo(CONTROL_WIDTH, CONTROL_NOTCH); - endInnerPath.close(); - endOuterPath.addPath(endInnerPath, 0, 0); - - canvas = m_endControl.beginRecording(CONTROL_WIDTH + STROKE_OUTSET * 2, - CONTROL_HEIGHT + STROKE_OUTSET * 2); - paint.setColor(INNER_COLOR); - paint.setStyle(SkPaint::kFill_Style); - canvas->drawPath(endInnerPath, paint); - paint.setColor(OUTER_COLOR); - canvas->drawPath(endOuterPath, paint); - paint.setStyle(SkPaint::kStroke_Style); - paint.setColor(STROKE_COLOR); - paint.setStrokeWidth(STROKE_WIDTH); - canvas->drawPath(endInnerPath, paint); - m_endControl.endRecording(); -} - -SelectText::~SelectText() -{ - SkSafeUnref(m_picture); -} - -void SelectText::draw(SkCanvas* canvas, LayerAndroid* layer, IntRect* inval) -{ - if (m_layerId != layer->uniqueId()) - return; - // reset m_picture to match m_layerId - SkSafeUnref(m_picture); - m_picture = layer->picture(); - SkSafeRef(m_picture); - DBG_NAV_LOGD("m_extendSelection=%d m_drawPointer=%d layer [%d]", - m_extendSelection, m_drawPointer, layer->uniqueId()); - if (m_extendSelection) - drawSelectionRegion(canvas, inval); - if (m_drawPointer) - drawSelectionPointer(canvas, inval); -} - -static void addInval(IntRect* inval, const SkCanvas* canvas, - const SkRect& bounds) { - const SkMatrix& matrix = canvas->getTotalMatrix(); - SkRect transformed; - matrix.mapRect(&transformed, bounds); - SkIRect iTrans; - transformed.round(&iTrans); - inval->unite(iTrans); -} - -void SelectText::drawSelectionPointer(SkCanvas* canvas, IntRect* inval) -{ - SkPath path; - if (m_extendSelection) - getSelectionCaret(&path); - else - getSelectionArrow(&path); - SkPixelXorXfermode xorMode(SK_ColorWHITE); - SkPaint paint; - paint.setAntiAlias(true); - paint.setStyle(SkPaint::kStroke_Style); - paint.setColor(SK_ColorBLACK); - if (m_extendSelection) - paint.setXfermode(&xorMode); - else - paint.setStrokeWidth(SK_Scalar1 * 2); - int sc = canvas->save(); - canvas->scale(m_inverseScale, m_inverseScale); - canvas->translate(m_selectX, m_selectY); - canvas->drawPath(path, paint); - if (!m_extendSelection) { - paint.setStyle(SkPaint::kFill_Style); - paint.setColor(SK_ColorWHITE); - canvas->drawPath(path, paint); - } - SkRect bounds = path.getBounds(); - bounds.inset(-SK_Scalar1 * 2, -SK_Scalar1 * 2); // stroke width - addInval(inval, canvas, bounds); - canvas->restoreToCount(sc); -} - -static void addStart(SkRegion* diff, const SkIRect& rect) -{ - SkIRect bounds; - bounds.set(rect.fLeft - CONTROL_WIDTH - STROKE_I_OUTSET, - rect.fBottom - STROKE_I_OUTSET, rect.fLeft + STROKE_I_OUTSET, - rect.fBottom + CONTROL_HEIGHT + STROKE_I_OUTSET); - diff->op(bounds, SkRegion::kUnion_Op); -} - -static void addEnd(SkRegion* diff, const SkIRect& rect) -{ - SkIRect bounds; - bounds.set(rect.fRight - STROKE_I_OUTSET, rect.fBottom - STROKE_I_OUTSET, - rect.fRight + CONTROL_WIDTH + STROKE_I_OUTSET, - rect.fBottom + CONTROL_HEIGHT + STROKE_I_OUTSET); - diff->op(bounds, SkRegion::kUnion_Op); -} - -void SelectText::getSelectionRegion(const IntRect& vis, SkRegion *region, - LayerAndroid* root) -{ - SkIRect ivisBounds = vis; - ivisBounds.join(m_selStart); - ivisBounds.join(m_selEnd); - region->setEmpty(); - buildSelection(*m_picture, ivisBounds, m_selStart, m_startBase, - m_selEnd, m_endBase, region); - if (root && m_layerId) { - Layer* layer = root->findById(m_layerId); - while (layer) { - const SkPoint& pos = layer->getPosition(); - region->translate(pos.fX, pos.fY); - layer = layer->getParent(); - } - } -} - -void SelectText::drawSelectionRegion(SkCanvas* canvas, IntRect* inval) -{ - if (!m_picture) - return; - SkIRect ivisBounds = m_visibleRect; - ivisBounds.join(m_selStart); - ivisBounds.join(m_selEnd); - DBG_NAV_LOGD("m_selStart=(%d,%d,r=%d,b=%d) m_selEnd=(%d,%d,r=%d,b=%d)" - " ivisBounds=(%d,%d,r=%d,b=%d)", - m_selStart.fLeft, m_selStart.fTop, m_selStart.fRight, m_selStart.fBottom, - m_selEnd.fLeft, m_selEnd.fTop, m_selEnd.fRight, m_selEnd.fBottom, - ivisBounds.fLeft, ivisBounds.fTop, ivisBounds.fRight, ivisBounds.fBottom); - if (m_lastSelRegion != m_selRegion) - m_lastSelRegion.set(m_selRegion); - SkRegion diff(m_lastSelRegion); - m_selRegion.setEmpty(); - m_flipped = buildSelection(*m_picture, ivisBounds, m_selStart, m_startBase, - m_selEnd, m_endBase, &m_selRegion); - SkPath path; - m_selRegion.getBoundaryPath(&path); - path.setFillType(SkPath::kEvenOdd_FillType); - - SkPaint paint; - paint.setAntiAlias(true); - paint.setColor(SkColorSetARGB(0x80, 0x83, 0xCC, 0x39)); - canvas->drawPath(path, paint); - // experiment to draw touchable controls that resize the selection - float scale = m_controlHeight / (float)CONTROL_HEIGHT; - canvas->save(); - canvas->translate(m_selStart.fLeft, m_selStart.fBottom); - canvas->scale(scale, scale); - canvas->drawPicture(m_startControl); - canvas->restore(); - canvas->save(); - canvas->translate(m_selEnd.fRight, m_selEnd.fBottom); - canvas->scale(scale, scale); - canvas->drawPicture(m_endControl); - canvas->restore(); - -#if DEBUG_TOUCH_HANDLES - SkRect touchHandleRect; - paint.setColor(SkColorSetARGB(0x60, 0xFF, 0x00, 0x00)); - touchHandleRect.set(0, m_selStart.fBottom, m_selStart.fLeft, 0); - touchHandleRect.fBottom = touchHandleRect.fTop + m_controlHeight; - touchHandleRect.fLeft = touchHandleRect.fRight - m_controlWidth; - canvas->drawRect(touchHandleRect, paint); - touchHandleRect.inset(-m_controlSlop, -m_controlSlop); - canvas->drawRect(touchHandleRect, paint); - touchHandleRect.set(m_selEnd.fRight, m_selEnd.fBottom, 0, 0); - touchHandleRect.fBottom = touchHandleRect.fTop + m_controlHeight; - touchHandleRect.fRight = touchHandleRect.fLeft + m_controlWidth; - canvas->drawRect(touchHandleRect, paint); - touchHandleRect.inset(-m_controlSlop, -m_controlSlop); - canvas->drawRect(touchHandleRect, paint); -#endif - - SkIRect a = diff.getBounds(); - SkIRect b = m_selRegion.getBounds(); - diff.op(m_selRegion, SkRegion::kXOR_Op); - SkIRect c = diff.getBounds(); - DBG_NAV_LOGD("old=(%d,%d,r=%d,b=%d) new=(%d,%d,r=%d,b=%d) diff=(%d,%d,r=%d,b=%d)", - a.fLeft, a.fTop, a.fRight, a.fBottom, b.fLeft, b.fTop, b.fRight, b.fBottom, - c.fLeft, c.fTop, c.fRight, c.fBottom); - DBG_NAV_LOGD("lastStart=(%d,%d,r=%d,b=%d) m_lastEnd=(%d,%d,r=%d,b=%d)", - m_lastStart.fLeft, m_lastStart.fTop, m_lastStart.fRight, m_lastStart.fBottom, - m_lastEnd.fLeft, m_lastEnd.fTop, m_lastEnd.fRight, m_lastEnd.fBottom); - if (!m_lastDrawnStart.isEmpty()) - addStart(&diff, m_lastDrawnStart); - if (m_lastStart != m_selStart) { - m_lastDrawnStart = m_lastStart; - m_lastStart = m_selStart; - } - addStart(&diff, m_selStart); - if (!m_lastDrawnEnd.isEmpty()) - addEnd(&diff, m_lastDrawnEnd); - if (m_lastEnd != m_selEnd) { - m_lastDrawnEnd = m_lastEnd; - m_lastEnd = m_selEnd; - } - addEnd(&diff, m_selEnd); - SkIRect iBounds = diff.getBounds(); - DBG_NAV_LOGD("diff=(%d,%d,r=%d,b=%d)", - iBounds.fLeft, iBounds.fTop, iBounds.fRight, iBounds.fBottom); - SkRect bounds; - bounds.set(iBounds); - addInval(inval, canvas, bounds); -} - -void SelectText::extendSelection(const IntRect& vis, int x, int y) -{ - if (!m_picture) - return; - setVisibleRect(vis); - SkIRect clipRect = m_visibleRect; - int base; - DBG_NAV_LOGD("extend x/y=%d,%d m_startOffset=%d,%d", x, y, - m_startOffset.fX, m_startOffset.fY); - x -= m_startOffset.fX; - y -= m_startOffset.fY; - if (m_startSelection) { - if (!clipRect.contains(x, y) - || !clipRect.contains(m_original.fX, m_original.fY)) { - clipRect.set(m_original.fX, m_original.fY, x, y); - clipRect.sort(); - clipRect.inset(-m_visibleRect.width(), -m_visibleRect.height()); - } - FirstCheck center(m_original.fX, m_original.fY, clipRect); - m_selStart = m_selEnd = findClosest(center, *m_picture, &base); - if (m_selStart.isEmpty()) - return; - DBG_NAV_LOGD("selStart clip=(%d,%d,%d,%d) m_original=%d,%d" - " m_selStart=(%d,%d,%d,%d)", clipRect.fLeft, clipRect.fTop, - clipRect.fRight, clipRect.fBottom, m_original.fX, m_original.fY, - m_selStart.fLeft, m_selStart.fTop, m_selStart.fRight, m_selStart.fBottom); - m_startBase = m_endBase = base; - m_startSelection = false; - m_extendSelection = true; - m_original.fX = m_original.fY = 0; - } - DBG_NAV_LOGD("extend x/y=%d,%d m_original=%d,%d", x, y, - m_original.fX, m_original.fY); - x -= m_original.fX; - y -= m_original.fY; - if (!clipRect.contains(x, y) || !clipRect.contains(m_selStart)) { - clipRect.set(m_selStart.fLeft, m_selStart.fTop, x, y); - clipRect.sort(); - clipRect.inset(-m_visibleRect.width(), -m_visibleRect.height()); - } - DBG_NAV_LOGD("extend clip=(%d,%d,%d,%d) x/y=%d,%d wordSel=%s outsideWord=%s", - clipRect.fLeft, clipRect.fTop, clipRect.fRight, clipRect.fBottom, x, y, - m_wordSelection ? "true" : "false", m_outsideWord ? "true" : "false"); - FirstCheck extension(x, y, clipRect); - SkIRect found = findClosest(extension, *m_picture, &base); - if (m_wordSelection) { - SkIRect wordBounds = m_wordBounds; - if (!m_outsideWord) - wordBounds.inset(-TOUCH_SLOP, -TOUCH_SLOP); - DBG_NAV_LOGD("x=%d y=%d wordBounds=(%d,%d,r=%d,b=%d)" - " found=(%d,%d,r=%d,b=%d)", x, y, wordBounds.fLeft, wordBounds.fTop, - wordBounds.fRight, wordBounds.fBottom, found.fLeft, found.fTop, - found.fRight, found.fBottom); - if (wordBounds.contains(x, y)) { - DBG_NAV_LOG("wordBounds.contains=true"); - m_outsideWord = false; - return; - } - m_outsideWord = true; - if (found.fBottom <= wordBounds.fTop) - m_hitTopLeft = true; - else if (found.fTop >= wordBounds.fBottom) - m_hitTopLeft = false; - else - m_hitTopLeft = (found.fLeft + found.fRight) - < (wordBounds.fLeft + wordBounds.fRight); - } - DBG_NAV_LOGD("x=%d y=%d m_startSelection=%s %s=(%d, %d, %d, %d)" - " m_extendSelection=%s", - x, y, m_startSelection ? "true" : "false", - m_hitTopLeft ? "m_selStart" : "m_selEnd", - found.fLeft, found.fTop, found.fRight, found.fBottom, - m_extendSelection ? "true" : "false"); - if (m_hitTopLeft) { - m_startBase = base; - m_selStart = found; - } else { - m_endBase = base; - m_selEnd = found; - } - swapAsNeeded(); -} - -SkIRect SelectText::findClosest(FirstCheck& check, const SkPicture& picture, - int* base) -{ - LineCheck lineCheck(check.focusX(), check.focusY(), check.getArea()); - TextCanvas lineChecker(&lineCheck); - lineChecker.drawPicture(const_cast<SkPicture&>(picture)); - lineCheck.finish(m_selRegion); - check.setLines(&lineCheck); - TextCanvas checker(&check); - checker.drawPicture(const_cast<SkPicture&>(picture)); - check.finishGlyph(); - return check.adjustedBounds(base); -} - -SkIRect SelectText::findEdge(const SkPicture& picture, const SkIRect& area, - int x, int y, bool left, int* base) -{ - SkIRect result; - result.setEmpty(); - FirstCheck center(x, y, area); - center.setRecordGlyph(); - int closestBase; - SkIRect closest = findClosest(center, picture, &closestBase); - SkIRect sloppy = closest; - sloppy.inset(-TOUCH_SLOP, -TOUCH_SLOP); - if (!sloppy.contains(x, y)) { - DBG_NAV_LOGD("sloppy=(%d, %d, %d, %d) area=(%d, %d, %d, %d) x/y=%d,%d", - sloppy.fLeft, sloppy.fTop, sloppy.fRight, sloppy.fBottom, - area.fLeft, area.fTop, area.fRight, area.fBottom, x, y); - return result; - } - EdgeCheck edge(x, y, area, center, left); - do { // detect left or right until there's a gap - DBG_NAV_LOGD("edge=%p picture=%p area=%d,%d,%d,%d", - &edge, &picture, area.fLeft, area.fTop, area.fRight, area.fBottom); - TextCanvas checker(&edge); - checker.drawPicture(const_cast<SkPicture&>(picture)); - edge.finishGlyph(); - if (!edge.adjacent()) { - if (result.isEmpty()) { - *base = closestBase; - DBG_NAV_LOGD("closest=%d,%d,%d,%d", closest.fLeft, - closest.fTop, closest.fRight, closest.fBottom); - return closest; - } - DBG_NAV_LOG("adjacent break"); - break; - } - int nextBase; - const SkIRect& next = edge.bestBounds(&nextBase); - if (next.isEmpty()) { - DBG_NAV_LOG("empty"); - break; - } - if (result == next) { - DBG_NAV_LOG("result == next"); - break; - } - *base = nextBase; - result = next; - edge.shiftStart(result); - } while (true); - if (!result.isEmpty()) { - *base += area.fTop; - result.offset(area.fLeft, area.fTop); - } - return result; -} - -SkIRect SelectText::findLeft(const SkPicture& picture, const SkIRect& area, - int x, int y, int* base) -{ - return findEdge(picture, area, x, y, true, base); -} - -SkIRect SelectText::findRight(const SkPicture& picture, const SkIRect& area, - int x, int y, int* base) -{ - return findEdge(picture, area, x, y, false, base); -} - -const String SelectText::getSelection() -{ - if (!m_picture) - return String(); - SkIRect clipRect; - clipRect.set(0, 0, m_picture->width(), m_picture->height()); - String result = text(*m_picture, clipRect, m_selStart, m_startBase, - m_selEnd, m_endBase, m_flipped); - DBG_NAV_LOGD("clip=(%d,%d,%d,%d)" - " m_selStart=(%d, %d, %d, %d) m_selEnd=(%d, %d, %d, %d)", - clipRect.fLeft, clipRect.fTop, clipRect.fRight, clipRect.fBottom, - m_selStart.fLeft, m_selStart.fTop, m_selStart.fRight, m_selStart.fBottom, - m_selEnd.fLeft, m_selEnd.fTop, m_selEnd.fRight, m_selEnd.fBottom); - DBG_NAV_LOGD("text=%s", result.latin1().data()); // uses CString - return result; -} - -void SelectText::getSelectionArrow(SkPath* path) -{ - const int arrow[] = { - 0, 14, 3, 11, 5, 15, 9, 15, 7, 11, 11, 11 - }; - for (unsigned index = 0; index < sizeof(arrow)/sizeof(arrow[0]); index += 2) - path->lineTo(arrow[index], arrow[index + 1]); - path->close(); -} - -void SelectText::getSelectionCaret(SkPath* path) -{ - SkScalar height = m_selStart.fBottom - m_selStart.fTop; - SkScalar dist = height / 4; - path->moveTo(0, -height / 2); - path->rLineTo(0, height); - path->rLineTo(-dist, dist); - path->rMoveTo(0, -0.5f); - path->rLineTo(dist * 2, 0); - path->rMoveTo(0, 0.5f); - path->rLineTo(-dist, -dist); -} - -bool SelectText::hitCorner(int cx, int cy, int x, int y) const -{ - SkIRect test; - test.set(cx, cy, cx + m_controlWidth, cy + m_controlHeight); - test.inset(-m_controlSlop, -m_controlSlop); - DBG_HANDLE_LOG("checking if %dx%d,%d-%d contains %dx%d", - cx, cy, m_controlWidth, m_controlHeight, x, y); - return test.contains(x, y); -} - -bool SelectText::hitStartHandle(int x, int y) const -{ - int left = m_selStart.fLeft - m_controlWidth; - return hitCorner(left, m_selStart.fBottom, x, y); -} - -bool SelectText::hitEndHandle(int x, int y) const -{ - int left = m_selEnd.fRight; - return hitCorner(left, m_selEnd.fBottom, x, y); -} - -bool SelectText::hitSelection(int x, int y) const -{ - x -= m_startOffset.fX; - y -= m_startOffset.fY; - if (hitStartHandle(x, y)) - return true; - if (hitEndHandle(x, y)) - return true; - return m_selRegion.contains(x, y); -} - -void SelectText::getSelectionHandles(int* handles, LayerAndroid* root) -{ - handles[0] = m_selStart.fLeft; - handles[1] = m_selStart.fBottom; - handles[2] = m_selEnd.fRight; - handles[3] = m_selEnd.fBottom; - if (root && m_layerId) { - Layer* layer = root->findById(m_layerId); - while (layer) { - const SkPoint& pos = layer->getPosition(); - handles[0] += pos.fX; - handles[2] += pos.fX; - handles[1] += pos.fY; - handles[3] += pos.fY; - layer = layer->getParent(); - } - } -} - -void SelectText::moveSelection(const IntRect& vis, int x, int y) -{ - if (!m_picture) - return; - x -= m_startOffset.fX; - y -= m_startOffset.fY; - setVisibleRect(vis); - SkIRect clipRect = m_visibleRect; - clipRect.join(m_selStart); - clipRect.join(m_selEnd); - FirstCheck center(x, y, clipRect); - int base; - SkIRect found = findClosest(center, *m_picture, &base); - if (m_hitTopLeft || !m_extendSelection) { - m_startBase = base; - m_selStart = found; - } - if (!m_hitTopLeft || !m_extendSelection) { - m_endBase = base; - m_selEnd = found; - } - swapAsNeeded(); - DBG_NAV_LOGD("x=%d y=%d extendSelection=%s m_selStart=(%d, %d, %d, %d)" - " m_selEnd=(%d, %d, %d, %d)", x, y, m_extendSelection ? "true" : "false", - m_selStart.fLeft, m_selStart.fTop, m_selStart.fRight, m_selStart.fBottom, - m_selEnd.fLeft, m_selEnd.fTop, m_selEnd.fRight, m_selEnd.fBottom); -} - -void SelectText::reset() -{ - DBG_NAV_LOG("m_extendSelection=false"); - m_selStart.setEmpty(); - m_lastStart.setEmpty(); - m_lastDrawnStart.setEmpty(); - m_selEnd.setEmpty(); - m_lastEnd.setEmpty(); - m_lastDrawnEnd.setEmpty(); - m_extendSelection = false; - m_startSelection = false; - SkSafeUnref(m_picture); - m_picture = 0; - m_layerId = 0; -} - -IntPoint SelectText::selectableText(const CachedRoot* root) -{ - int x = 0; - int y = 0; - SkPicture* picture = root->pictureAt(&x, &y, &m_layerId); - if (!picture) { - DBG_NAV_LOG("picture==0"); - return IntPoint(0, 0); - } - int width = picture->width(); - int height = picture->height(); - IntRect vis(0, 0, width, height); - FirstCheck center(width >> 1, height >> 1, vis); - int base; - const SkIRect& closest = findClosest(center, *picture, &base); - return IntPoint((closest.fLeft + closest.fRight) >> 1, - (closest.fTop + closest.fBottom) >> 1); -} - -void SelectText::selectAll() -{ - if (!m_picture) - return; - m_selStart = findFirst(*m_picture, &m_startBase); - m_selEnd = findLast(*m_picture, &m_endBase); - m_extendSelection = true; -} - -int SelectText::selectionX() const -{ - return (m_hitTopLeft ? m_selStart.fLeft : m_selEnd.fRight) + m_startOffset.fX; -} - -int SelectText::selectionY() const -{ - const SkIRect& rect = m_hitTopLeft ? m_selStart : m_selEnd; - return ((rect.fTop + rect.fBottom) >> 1) + m_startOffset.fY; -} - -void SelectText::setVisibleRect(const IntRect& vis) -{ - DBG_NAV_LOGD("vis=(%d,%d,w=%d,h=%d) offset=(%d,%d)", - vis.x(), vis.y(), vis.width(), vis.height(), m_startOffset.fX, - m_startOffset.fY); - m_visibleRect = vis; - m_visibleRect.offset(-m_startOffset.fX, -m_startOffset.fY); -} - -bool SelectText::startSelection(const CachedRoot* root, const IntRect& vis, - int x, int y) -{ - m_wordSelection = false; - m_startOffset.set(x, y); - DBG_NAV_LOGD("x/y=(%d,%d)", x, y); - SkSafeUnref(m_picture); - m_picture = root->pictureAt(&x, &y, &m_layerId); - DBG_NAV_LOGD("m_picture=%p m_layerId=%d x/y=(%d,%d)", m_picture, m_layerId, - x, y); - if (!m_picture) { - DBG_NAV_LOG("picture==0"); - return false; - } - m_picture->ref(); - m_startOffset.fX -= x; - m_startOffset.fY -= y; - m_original.fX = x; - m_original.fY = y; - setVisibleRect(vis); - if (m_selStart.isEmpty()) { - DBG_NAV_LOGD("empty start picture=(%d,%d) x=%d y=%d", - m_picture->width(), m_picture->height(), x, y); - m_startSelection = true; - return true; - } - m_hitTopLeft = hitStartHandle(x, y); - bool hitBottomRight = hitEndHandle(x, y); - DBG_NAV_LOGD("picture=(%d,%d) left=%d top=%d right=%d bottom=%d x=%d y=%d", - m_picture->width(), m_picture->height(),left, top, right, bottom, x, y); - if (m_hitTopLeft) { - DBG_NAV_LOG("hit top left"); - m_original.fX -= m_selStart.fLeft; - m_original.fY -= (m_selStart.fTop + m_selStart.fBottom) >> 1; - } else if (hitBottomRight) { - DBG_NAV_LOG("hit bottom right"); - m_original.fX -= m_selEnd.fRight; - m_original.fY -= (m_selEnd.fTop + m_selEnd.fBottom) >> 1; - } - return m_hitTopLeft || hitBottomRight; -} - -void SelectText::updateHandleScale(float handleScale) -{ - m_controlHeight = CONTROL_HEIGHT * handleScale; - m_controlWidth = CONTROL_WIDTH * handleScale; - m_controlSlop = CONTROL_SLOP * handleScale; -} - -/* selects the word at (x, y) -* a word is normally delimited by spaces -* a string of digits (even with inside spaces) is a word (for phone numbers) -* FIXME: digit find isn't implemented yet -* returns true if a word was selected -*/ -bool SelectText::wordSelection(const CachedRoot* root, const IntRect& vis, - int x, int y) -{ - IntRect tapArea = IntRect(x - TOUCH_SLOP, y - TOUCH_SLOP, TOUCH_SLOP * 2, - TOUCH_SLOP * 2); - if (!startSelection(root, tapArea, x, y)) - return false; - extendSelection(tapArea, x, y); - if (m_selStart.isEmpty()) - return false; - setDrawPointer(false); - setVisibleRect(vis); - SkIRect ivisBounds = m_visibleRect; - ivisBounds.join(m_selStart); - ivisBounds.join(m_selEnd); - DBG_NAV_LOGD("m_selStart=(%d,%d,r=%d,b=%d) m_selEnd=(%d,%d,r=%d,b=%d)" - " ivisBounds=(%d,%d,r=%d,b=%d)", - m_selStart.fLeft, m_selStart.fTop, m_selStart.fRight, m_selStart.fBottom, - m_selEnd.fLeft, m_selEnd.fTop, m_selEnd.fRight, m_selEnd.fBottom, - ivisBounds.fLeft, ivisBounds.fTop, ivisBounds.fRight, ivisBounds.fBottom); - m_selRegion.setEmpty(); - buildSelection(*m_picture, ivisBounds, m_selStart, m_startBase, - m_selEnd, m_endBase, &m_selRegion); - x = m_selStart.fLeft; - y = (m_selStart.fTop + m_selStart.fBottom) >> 1; - SkIRect clipRect = m_visibleRect; - clipRect.fLeft -= m_visibleRect.width() >> 1; - clipRect.fLeft = std::max(clipRect.fLeft, 0); - int base; - SkIRect left = findLeft(*m_picture, clipRect, x, y, &base); - if (!left.isEmpty()) { - m_startBase = base; - m_selStart = left; - } - x = m_selEnd.fRight; - y = (m_selEnd.fTop + m_selEnd.fBottom) >> 1; - clipRect = m_visibleRect; - clipRect.fRight += m_visibleRect.width() >> 1; - SkIRect right = findRight(*m_picture, clipRect, x, y, &base); - if (!right.isEmpty()) { - m_endBase = base; - m_selEnd = right; - } - DBG_NAV_LOGD("m_selStart=(%d, %d, %d, %d) m_selEnd=(%d, %d, %d, %d)", - m_selStart.fLeft, m_selStart.fTop, m_selStart.fRight, m_selStart.fBottom, - m_selEnd.fLeft, m_selEnd.fTop, m_selEnd.fRight, m_selEnd.fBottom); - if (!left.isEmpty() || !right.isEmpty()) { - m_wordBounds = m_selStart; - m_wordBounds.join(m_selEnd); - m_extendSelection = m_wordSelection = true; - m_outsideWord = false; - return true; - } - return false; -} - -void SelectText::swapAsNeeded() -{ - if (m_selStart.fTop >= (m_selEnd.fTop + m_selEnd.fBottom) >> 1 - || (m_selEnd.fTop < (m_selStart.fTop + m_selStart.fBottom) >> 1 - && m_selStart.fRight > m_selEnd.fLeft)) - { - SkTSwap(m_startBase, m_endBase); - SkTSwap(m_selStart, m_selEnd); - m_hitTopLeft ^= true; - DBG_NAV_LOGD("m_hitTopLeft=%s", m_hitTopLeft ? "true" : "false"); - } + if (id == StartHandle || id == EndHandle) + return id; + if (isBaseFirst()) + return (HandleId) (id - 2); + if (id == BaseHandle) + return EndHandle; + return StartHandle; } } diff --git a/Source/WebKit/android/nav/SelectText.h b/Source/WebKit/android/nav/SelectText.h index b454b8e..904b2b9 100644 --- a/Source/WebKit/android/nav/SelectText.h +++ b/Source/WebKit/android/nav/SelectText.h @@ -27,90 +27,38 @@ #define SelectText_h #include "DrawExtra.h" -#include "IntPoint.h" #include "IntRect.h" #include "PlatformString.h" -#include "SkPath.h" -#include "SkPicture.h" -#include "SkRect.h" -#include "SkRegion.h" namespace android { -class CachedRoot; - -class SelectText : public DrawExtra { -public: - SelectText(); - virtual ~SelectText(); - virtual void draw(SkCanvas* , LayerAndroid* , IntRect* ); - void extendSelection(const IntRect& vis, int x, int y); - const String getSelection(); - bool hitSelection(int x, int y) const; - void moveSelection(const IntRect& vis, int x, int y); - void reset(); - IntPoint selectableText(const CachedRoot* ); - void selectAll(); - int selectionX() const; - int selectionY() const; - void setDrawPointer(bool drawPointer) { m_drawPointer = drawPointer; } - void setExtendSelection(bool extend) { m_extendSelection = extend; } - bool startSelection(const CachedRoot* , const IntRect& vis, int x, int y); - bool wordSelection(const CachedRoot* , const IntRect& vis, int x, int y); - void getSelectionRegion(const IntRect& vis, SkRegion *region, LayerAndroid* root); - void updateHandleScale(float handleScale); - void getSelectionHandles(int* handles, LayerAndroid* root); +class SelectText : public RegionLayerDrawExtra { public: - float m_inverseScale; // inverse scale, x, y used for drawing select path - int m_selectX; - int m_selectY; + enum HandleId { + StartHandle = 0, + EndHandle = 1, + BaseHandle = 2, + ExtentHandle = 3, + }; + + IntRect& caretRect(HandleId id) { return m_caretRects[mapId(id)]; } + void setCaretRect(HandleId id, const IntRect& rect) { m_caretRects[mapId(id)] = rect; } + int caretLayerId(HandleId id) { return m_caretLayerId[mapId(id)]; } + void setCaretLayerId(HandleId id, int layerId) { m_caretLayerId[mapId(id)] = layerId; } + + bool isBaseFirst() const { return m_baseIsFirst; } + void setBaseFirst(bool isFirst) { m_baseIsFirst = isFirst; } + + void setText(const String& text) { m_text = text.threadsafeCopy(); } + String& getText() { return m_text; } + private: - int m_controlWidth; - int m_controlHeight; - int m_controlSlop; - class FirstCheck; - class EdgeCheck; - void drawSelectionPointer(SkCanvas* , IntRect* ); - void drawSelectionRegion(SkCanvas* , IntRect* ); - SkIRect findClosest(FirstCheck& , const SkPicture& , int* base); - SkIRect findEdge(const SkPicture& , const SkIRect& area, - int x, int y, bool left, int* base); - SkIRect findLeft(const SkPicture& picture, const SkIRect& area, - int x, int y, int* base); - SkIRect findRight(const SkPicture& picture, const SkIRect& area, - int x, int y, int* base); - static void getSelectionArrow(SkPath* ); - void getSelectionCaret(SkPath* ); - bool hitCorner(int cx, int cy, int x, int y) const; - bool hitStartHandle(int x, int y) const; - bool hitEndHandle(int x, int y) const; - void setVisibleRect(const IntRect& ); - void swapAsNeeded(); - SkIPoint m_original; // computed start of extend selection - SkIPoint m_startOffset; // difference from global to layer - SkIRect m_selStart; - SkIRect m_selEnd; - SkIRect m_lastStart; - SkIRect m_lastEnd; - SkIRect m_lastDrawnStart; - SkIRect m_lastDrawnEnd; - SkIRect m_wordBounds; - int m_startBase; - int m_endBase; - int m_layerId; - SkIRect m_visibleRect; // constrains picture computations to visible area - SkRegion m_lastSelRegion; - SkRegion m_selRegion; // computed from sel start, end - SkPicture m_startControl; - SkPicture m_endControl; - const SkPicture* m_picture; - bool m_drawPointer; - bool m_extendSelection; // false when trackball is moving pointer - bool m_flipped; - bool m_hitTopLeft; - bool m_startSelection; - bool m_wordSelection; - bool m_outsideWord; + HandleId mapId(HandleId id); + + IntRect m_caretRects[2]; + int m_caretLayerId[2]; + bool m_baseIsFirst; + String m_text; }; } diff --git a/Source/WebKit/android/nav/WebView.cpp b/Source/WebKit/android/nav/WebView.cpp index 7cb41d9..6aed700 100644 --- a/Source/WebKit/android/nav/WebView.cpp +++ b/Source/WebKit/android/nav/WebView.cpp @@ -30,11 +30,7 @@ #include "AndroidAnimation.h" #include "AndroidLog.h" #include "BaseLayerAndroid.h" -#include "CachedFrame.h" -#include "CachedNode.h" -#include "CachedRoot.h" #include "DrawExtra.h" -#include "FindCanvas.h" #include "Frame.h" #include "GraphicsJNI.h" #include "HTMLInputElement.h" @@ -53,9 +49,6 @@ #include "SkPicture.h" #include "SkRect.h" #include "SkTime.h" -#ifdef ANDROID_INSTRUMENT -#include "TimeCounter.h" -#endif #include "TilesManager.h" #include "WebCoreJni.h" #include "WebRequestContext.h" @@ -71,7 +64,7 @@ #include <JNIUtility.h> #include <JNIHelp.h> #include <jni.h> -#include <ui/KeycodeLabels.h> +#include <androidfw/KeycodeLabels.h> #include <wtf/text/AtomicString.h> #include <wtf/text/CString.h> @@ -95,7 +88,7 @@ static jfieldID gWebViewField; static jmethodID GetJMethod(JNIEnv* env, jclass clazz, const char name[], const char signature[]) { jmethodID m = env->GetMethodID(clazz, name, signature); - LOG_ASSERT(m, "Could not find method %s", name); + ALOG_ASSERT(m, "Could not find method %s", name); return m; } @@ -110,11 +103,11 @@ enum FrameCachePermission { AllowNewer }; +#define DRAW_EXTRAS_SIZE 2 enum DrawExtras { // keep this in sync with WebView.java DrawExtrasNone = 0, - DrawExtrasFind = 1, - DrawExtrasSelection = 2, - DrawExtrasCursorRing = 3 + DrawExtrasSelection = 1, + DrawExtrasCursorRing = 2 }; struct JavaGlue { @@ -134,7 +127,6 @@ struct JavaGlue { jmethodID m_viewInvalidateRect; jmethodID m_postInvalidateDelayed; jmethodID m_pageSwapCallback; - jmethodID m_inFullScreenMode; jfieldID m_rectLeft; jfieldID m_rectTop; jmethodID m_rectWidth; @@ -143,17 +135,16 @@ struct JavaGlue { jfieldID m_rectFTop; jmethodID m_rectFWidth; jmethodID m_rectFHeight; - jmethodID m_getTextHandleScale; AutoJObject object(JNIEnv* env) { return getRealObject(env, m_obj); } } m_javaGlue; WebView(JNIEnv* env, jobject javaWebView, int viewImpl, WTF::String drawableDir, - bool isHighEndGfx) : - m_ring((WebViewCore*) viewImpl) - , m_isHighEndGfx(isHighEndGfx) + bool isHighEndGfx) + : m_isHighEndGfx(isHighEndGfx) { + memset(m_extras, 0, DRAW_EXTRAS_SIZE * sizeof(DrawExtra*)); jclass clazz = env->FindClass("android/webkit/WebView"); // m_javaGlue = new JavaGlue; m_javaGlue.m_obj = env->NewWeakGlobalRef(javaWebView); @@ -173,12 +164,10 @@ WebView(JNIEnv* env, jobject javaWebView, int viewImpl, WTF::String drawableDir, m_javaGlue.m_postInvalidateDelayed = GetJMethod(env, clazz, "viewInvalidateDelayed", "(JIIII)V"); m_javaGlue.m_pageSwapCallback = GetJMethod(env, clazz, "pageSwapCallback", "(Z)V"); - m_javaGlue.m_inFullScreenMode = GetJMethod(env, clazz, "inFullScreenMode", "()Z"); - m_javaGlue.m_getTextHandleScale = GetJMethod(env, clazz, "getTextHandleScale", "()F"); env->DeleteLocalRef(clazz); jclass rectClass = env->FindClass("android/graphics/Rect"); - LOG_ASSERT(rectClass, "Could not find Rect class"); + ALOG_ASSERT(rectClass, "Could not find Rect class"); m_javaGlue.m_rectLeft = env->GetFieldID(rectClass, "left", "I"); m_javaGlue.m_rectTop = env->GetFieldID(rectClass, "top", "I"); m_javaGlue.m_rectWidth = GetJMethod(env, rectClass, "width", "()I"); @@ -186,7 +175,7 @@ WebView(JNIEnv* env, jobject javaWebView, int viewImpl, WTF::String drawableDir, env->DeleteLocalRef(rectClass); jclass rectClassF = env->FindClass("android/graphics/RectF"); - LOG_ASSERT(rectClassF, "Could not find RectF class"); + ALOG_ASSERT(rectClassF, "Could not find RectF class"); m_javaGlue.m_rectFLeft = env->GetFieldID(rectClassF, "left", "F"); m_javaGlue.m_rectFTop = env->GetFieldID(rectClassF, "top", "F"); m_javaGlue.m_rectFWidth = GetJMethod(env, rectClassF, "width", "()F"); @@ -195,20 +184,15 @@ WebView(JNIEnv* env, jobject javaWebView, int viewImpl, WTF::String drawableDir, env->SetIntField(javaWebView, gWebViewField, (jint)this); m_viewImpl = (WebViewCore*) viewImpl; - m_frameCacheUI = 0; - m_navPictureUI = 0; m_generation = 0; m_heightCanMeasure = false; m_lastDx = 0; m_lastDxTime = 0; - m_ringAnimationEnd = 0; m_baseLayer = 0; m_glDrawFunctor = 0; m_isDrawingPaused = false; - m_buttonSkin = drawableDir.isEmpty() ? 0 : new RenderSkinButton(drawableDir); #if USE(ACCELERATED_COMPOSITING) m_glWebViewState = 0; - m_pageSwapCallbackRegistered = false; #endif } @@ -226,11 +210,17 @@ WebView(JNIEnv* env, jobject javaWebView, int viewImpl, WTF::String drawableDir, // deallocated base layer. stopGL(); #endif - delete m_frameCacheUI; - delete m_navPictureUI; SkSafeUnref(m_baseLayer); delete m_glDrawFunctor; - delete m_buttonSkin; + for (int i = 0; i < DRAW_EXTRAS_SIZE; i++) + delete m_extras[i]; +} + +DrawExtra* getDrawExtra(DrawExtras extras) +{ + if (extras == DrawExtrasNone) + return 0; + return m_extras[extras - 1]; } void stopGL() @@ -245,126 +235,6 @@ WebViewCore* getWebViewCore() const { return m_viewImpl; } -float getTextHandleScale() -{ - LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); - JNIEnv* env = JSC::Bindings::getJNIEnv(); - AutoJObject javaObject = m_javaGlue.object(env); - if (!javaObject.get()) - return 0; - float result = env->CallFloatMethod(javaObject.get(), m_javaGlue.m_getTextHandleScale); - checkException(env); - return result; -} - -void updateSelectionHandles() -{ - if (!m_baseLayer) - return; - // Adjust for device density & scale - m_selectText.updateHandleScale(getTextHandleScale()); -} - -// removes the cursor altogether (e.g., when going to a new page) -void clearCursor() -{ - CachedRoot* root = getFrameCache(AllowNewer); - if (!root) - return; - DBG_NAV_LOG(""); - m_viewImpl->m_hasCursorBounds = false; - root->clearCursor(); - viewInvalidate(); -} - -// leaves the cursor where it is, but suppresses drawing it -void hideCursor() -{ - CachedRoot* root = getFrameCache(AllowNewer); - if (!root) - return; - DBG_NAV_LOG(""); - hideCursor(root); - viewInvalidate(); -} - -void hideCursor(CachedRoot* root) -{ - DBG_NAV_LOG("inner"); - m_viewImpl->m_hasCursorBounds = false; - root->hideCursor(); -} - -#if DUMP_NAV_CACHE -void debugDump() -{ - CachedRoot* root = getFrameCache(DontAllowNewer); - if (root) - root->mDebug.print(); -} -#endif - -void scrollToCurrentMatch() -{ - if (!m_findOnPage.currentMatchIsInLayer()) { - scrollRectOnScreen(m_findOnPage.currentMatchBounds()); - return; - } - - SkRect matchBounds = m_findOnPage.currentMatchBounds(); - LayerAndroid* rootLayer = getFrameCache(DontAllowNewer)->rootLayer(); - Layer* layerContainingMatch = rootLayer->findById(m_findOnPage.currentMatchLayerId()); - ASSERT(layerContainingMatch); - - // If the match is in a fixed position layer, there's nothing to do. - if (layerContainingMatch->shouldInheritFromRootTransform()) - return; - - // If the match is in a scrollable layer or a descendant of such a layer, - // there may be a range of of scroll configurations that will make the - // current match visible. Our approach is the simplest possible. Starting at - // the layer in which the match is found, we move up the layer tree, - // scrolling any scrollable layers as little as possible to make sure that - // the current match is in view. This approach has the disadvantage that we - // may end up scrolling a larger number of elements than is necessary, which - // may be visually jarring. However, minimising the number of layers - // scrolled would complicate the code significantly. - - bool didScrollLayer = false; - for (Layer* layer = layerContainingMatch; layer; layer = layer->getParent()) { - ASSERT(layer->getParent() || layer == rootLayer); - - if (layer->contentIsScrollable()) { - // Convert the match location to layer's local space and scroll it. - // Repeatedly calling Layer::localToAncestor() is inefficient as - // each call repeats part of the calculation. It would be more - // efficient to maintain the transform here and update it on each - // iteration, but that would mean duplicating logic from - // Layer::localToAncestor() and would complicate things. - SkMatrix transform; - layerContainingMatch->localToAncestor(layer, &transform); - SkRect transformedMatchBounds; - transform.mapRect(&transformedMatchBounds, matchBounds); - SkIRect roundedTransformedMatchBounds; - transformedMatchBounds.roundOut(&roundedTransformedMatchBounds); - // Only ScrollableLayerAndroid returns true for contentIsScrollable(). - didScrollLayer |= static_cast<ScrollableLayerAndroid*>(layer)->scrollRectIntoView(roundedTransformedMatchBounds); - } - } - // Invalidate, as the call below to scroll the main page may be a no-op. - if (didScrollLayer) - viewInvalidate(); - - // Convert matchBounds to the global space so we can scroll the main page. - SkMatrix transform; - layerContainingMatch->localToGlobal(&transform); - SkRect transformedMatchBounds; - transform.mapRect(&transformedMatchBounds, matchBounds); - SkIRect roundedTransformedMatchBounds; - transformedMatchBounds.roundOut(&roundedTransformedMatchBounds); - scrollRectOnScreen(roundedTransformedMatchBounds); -} - void scrollRectOnScreen(const IntRect& rect) { if (rect.isEmpty()) @@ -392,110 +262,28 @@ 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) { #if USE(ACCELERATED_COMPOSITING) - if (!m_baseLayer || inFullScreenMode()) + if (!m_baseLayer) return false; if (!m_glWebViewState) { + TilesManager::instance()->setHighEndGfx(m_isHighEndGfx); m_glWebViewState = new GLWebViewState(); - m_glWebViewState->setHighEndGfx(m_isHighEndGfx); - m_glWebViewState->glExtras()->setCursorRingExtra(&m_ring); - m_glWebViewState->glExtras()->setFindOnPageExtra(&m_findOnPage); if (m_baseLayer->content()) { SkRegion region; SkIRect rect; rect.set(0, 0, m_baseLayer->content()->width(), m_baseLayer->content()->height()); region.setRect(rect); - m_glWebViewState->setBaseLayer(m_baseLayer, region, false, true); + m_baseLayer->markAsDirty(region); + m_glWebViewState->setBaseLayer(m_baseLayer, false, true); } } - CachedRoot* root = getFrameCache(AllowNewer); - if (!root) { - DBG_NAV_LOG("!root"); - if (extras == DrawExtrasCursorRing) - resetCursorRing(); - } - DrawExtra* extra = 0; - switch (extras) { - case DrawExtrasFind: - extra = &m_findOnPage; - break; - case DrawExtrasSelection: - // This will involve a JNI call, but under normal circumstances we will - // not hit this anyway. Only if USE_JAVA_TEXT_SELECTION is disabled - // in WebView.java will we hit this (so really debug only) - updateSelectionHandles(); - extra = &m_selectText; - break; - case DrawExtrasCursorRing: - if (drawCursorPreamble(root) && m_ring.setup()) { - if (m_ring.m_isPressed || m_ringAnimationEnd == UINT_MAX) - extra = &m_ring; - drawCursorPostamble(); - } - break; - default: - ; - } + DrawExtra* extra = getDrawExtra((DrawExtras) extras); unsigned int pic = m_glWebViewState->currentPictureCounter(); m_glWebViewState->glExtras()->setDrawExtra(extra); @@ -510,9 +298,8 @@ bool drawGL(WebCore::IntRect& viewRect, WebCore::IntRect* invalRect, bool ret = m_glWebViewState->drawGL(viewRect, m_visibleRect, invalRect, webViewRect, titleBarHeight, clip, scale, &treesSwapped, &newTreeHasAnim); - if (treesSwapped && (m_pageSwapCallbackRegistered || newTreeHasAnim)) { - m_pageSwapCallbackRegistered = false; - LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); + if (treesSwapped) { + ALOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); JNIEnv* env = JSC::Bindings::getJNIEnv(); AutoJObject javaObject = m_javaGlue.object(env); if (javaObject.get()) { @@ -526,7 +313,7 @@ bool drawGL(WebCore::IntRect& viewRect, WebCore::IntRect* invalRect, return false; } -PictureSet* draw(SkCanvas* canvas, SkColor bgColor, int extras, bool split) +PictureSet* draw(SkCanvas* canvas, SkColor bgColor, DrawExtras extras, bool split) { PictureSet* ret = 0; if (!m_baseLayer) { @@ -544,34 +331,10 @@ PictureSet* draw(SkCanvas* canvas, SkColor bgColor, int extras, bool split) if (content->draw(canvas)) ret = split ? new PictureSet(*content) : 0; - CachedRoot* root = getFrameCache(AllowNewer); - if (!root) { - DBG_NAV_LOG("!root"); - if (extras == DrawExtrasCursorRing) - resetCursorRing(); - } - LayerAndroid mainPicture(m_navPictureUI); - DrawExtra* extra = 0; - switch (extras) { - case DrawExtrasFind: - extra = &m_findOnPage; - break; - case DrawExtrasSelection: - // This will involve a JNI call, but under normal circumstances we will - // not hit this anyway. Only if USE_JAVA_TEXT_SELECTION is disabled - // in WebView.java will we hit this (so really debug only) - updateSelectionHandles(); - extra = &m_selectText; - break; - case DrawExtrasCursorRing: - if (drawCursorPreamble(root) && m_ring.setup()) { - extra = &m_ring; - drawCursorPostamble(); - } - break; - default: - ; - } + DrawExtra* extra = getDrawExtra(extras); + if (extra) + extra->draw(canvas, 0); + #if USE(ACCELERATED_COMPOSITING) LayerAndroid* compositeLayer = compositeRoot(); if (compositeLayer) { @@ -584,173 +347,19 @@ PictureSet* draw(SkCanvas* canvas, SkColor bgColor, int extras, bool split) SkAutoCanvasRestore restore(canvas, true); m_baseLayer->setMatrix(canvas->getTotalMatrix()); canvas->resetMatrix(); - m_baseLayer->draw(canvas); + m_baseLayer->draw(canvas, extra); } -#endif if (extra) { IntRect dummy; // inval area, unused for now - extra->draw(canvas, &mainPicture, &dummy); - } - return ret; -} - - -bool cursorIsTextInput(FrameCachePermission allowNewer) -{ - CachedRoot* root = getFrameCache(allowNewer); - if (!root) { - DBG_NAV_LOG("!root"); - return false; - } - const CachedNode* cursor = root->currentCursor(); - if (!cursor) { - DBG_NAV_LOG("!cursor"); - return false; - } - DBG_NAV_LOGD("%s", cursor->isTextInput() ? "true" : "false"); - return cursor->isTextInput(); -} - -void cursorRingBounds(WebCore::IntRect* bounds) -{ - DBG_NAV_LOGD("%s", ""); - CachedRoot* root = getFrameCache(DontAllowNewer); - if (root) { - const CachedFrame* cachedFrame; - const CachedNode* cachedNode = root->currentCursor(&cachedFrame); - if (cachedNode) { - *bounds = cachedNode->cursorRingBounds(cachedFrame); - DBG_NAV_LOGD("bounds={%d,%d,%d,%d}", bounds->x(), bounds->y(), - bounds->width(), bounds->height()); - return; - } - } - *bounds = WebCore::IntRect(0, 0, 0, 0); -} - -void fixCursor() -{ - m_viewImpl->gCursorBoundsMutex.lock(); - bool hasCursorBounds = m_viewImpl->m_hasCursorBounds; - IntRect bounds = m_viewImpl->m_cursorBounds; - m_viewImpl->gCursorBoundsMutex.unlock(); - if (!hasCursorBounds) - return; - int x, y; - const CachedFrame* frame; - const CachedNode* node = m_frameCacheUI->findAt(bounds, &frame, &x, &y, true); - if (!node) - return; - // require that node have approximately the same bounds (+/- 4) and the same - // center (+/- 2) - IntPoint oldCenter = IntPoint(bounds.x() + (bounds.width() >> 1), - bounds.y() + (bounds.height() >> 1)); - IntRect newBounds = node->bounds(frame); - IntPoint newCenter = IntPoint(newBounds.x() + (newBounds.width() >> 1), - newBounds.y() + (newBounds.height() >> 1)); - DBG_NAV_LOGD("oldCenter=(%d,%d) newCenter=(%d,%d)" - " bounds=(%d,%d,w=%d,h=%d) newBounds=(%d,%d,w=%d,h=%d)", - oldCenter.x(), oldCenter.y(), newCenter.x(), newCenter.y(), - bounds.x(), bounds.y(), bounds.width(), bounds.height(), - newBounds.x(), newBounds.y(), newBounds.width(), newBounds.height()); - if (abs(oldCenter.x() - newCenter.x()) > 2) - return; - if (abs(oldCenter.y() - newCenter.y()) > 2) - return; - if (abs(bounds.x() - newBounds.x()) > 4) - return; - if (abs(bounds.y() - newBounds.y()) > 4) - return; - if (abs(bounds.maxX() - newBounds.maxX()) > 4) - return; - if (abs(bounds.maxY() - newBounds.maxY()) > 4) - return; - DBG_NAV_LOGD("node=%p frame=%p x=%d y=%d bounds=(%d,%d,w=%d,h=%d)", - node, frame, x, y, bounds.x(), bounds.y(), bounds.width(), - bounds.height()); - m_frameCacheUI->setCursor(const_cast<CachedFrame*>(frame), - const_cast<CachedNode*>(node)); -} - -CachedRoot* getFrameCache(FrameCachePermission allowNewer) -{ - if (!m_viewImpl->m_updatedFrameCache) { - DBG_NAV_LOGV("%s", "!m_viewImpl->m_updatedFrameCache"); - return m_frameCacheUI; - } - if (allowNewer == DontAllowNewer && m_viewImpl->m_lastGeneration < m_generation) { - DBG_NAV_LOGD("allowNewer==DontAllowNewer m_viewImpl->m_lastGeneration=%d" - " < m_generation=%d", m_viewImpl->m_lastGeneration, m_generation); - return m_frameCacheUI; - } - DBG_NAV_LOGD("%s", "m_viewImpl->m_updatedFrameCache == true"); - const CachedFrame* oldCursorFrame; - const CachedNode* oldCursorNode = m_frameCacheUI ? - m_frameCacheUI->currentCursor(&oldCursorFrame) : 0; -#if USE(ACCELERATED_COMPOSITING) - int layerId = -1; - if (oldCursorNode && oldCursorNode->isInLayer()) { - const LayerAndroid* cursorLayer = oldCursorFrame->layer(oldCursorNode) - ->layer(m_frameCacheUI->rootLayer()); - if (cursorLayer) - layerId = cursorLayer->uniqueId(); - } -#endif - // get id from old layer and use to find new layer - bool oldFocusIsTextInput = false; - void* oldFocusNodePointer = 0; - if (m_frameCacheUI) { - const CachedNode* oldFocus = m_frameCacheUI->currentFocus(); - if (oldFocus) { - oldFocusIsTextInput = oldFocus->isTextInput(); - oldFocusNodePointer = oldFocus->nodePointer(); - } - } - m_viewImpl->gFrameCacheMutex.lock(); - delete m_frameCacheUI; - SkSafeUnref(m_navPictureUI); - m_viewImpl->m_updatedFrameCache = false; - m_frameCacheUI = m_viewImpl->m_frameCacheKit; - m_navPictureUI = m_viewImpl->m_navPictureKit; - m_viewImpl->m_frameCacheKit = 0; - m_viewImpl->m_navPictureKit = 0; - m_viewImpl->gFrameCacheMutex.unlock(); - if (m_frameCacheUI) - m_frameCacheUI->setRootLayer(compositeRoot()); -#if USE(ACCELERATED_COMPOSITING) - if (layerId >= 0) { - LayerAndroid* layer = const_cast<LayerAndroid*>( - m_frameCacheUI->rootLayer()); - if (layer) { - layer->updateFixedLayersPositions(m_visibleRect); - layer->updatePositions(); - } + extra->drawLegacy(canvas, compositeLayer, &dummy); } #endif - fixCursor(); - if (oldFocusIsTextInput) { - const CachedNode* newFocus = m_frameCacheUI->currentFocus(); - if (newFocus && oldFocusNodePointer != newFocus->nodePointer() - && newFocus->isTextInput() - && newFocus != m_frameCacheUI->currentCursor()) { - // The focus has changed. We may need to update things. - LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); - JNIEnv* env = JSC::Bindings::getJNIEnv(); - AutoJObject javaObject = m_javaGlue.object(env); - if (javaObject.get()) { - env->CallVoidMethod(javaObject.get(), m_javaGlue.m_domChangedFocus); - checkException(env); - } - } - } - if (oldCursorNode && (!m_frameCacheUI || !m_frameCacheUI->currentCursor())) - viewInvalidate(); // redraw in case cursor ring is still visible - return m_frameCacheUI; + return ret; } int getScaledMaxXScroll() { - LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); + ALOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); JNIEnv* env = JSC::Bindings::getJNIEnv(); AutoJObject javaObject = m_javaGlue.object(env); if (!javaObject.get()) @@ -762,7 +371,7 @@ int getScaledMaxXScroll() int getScaledMaxYScroll() { - LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); + ALOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); JNIEnv* env = JSC::Bindings::getJNIEnv(); AutoJObject javaObject = m_javaGlue.object(env); if (!javaObject.get()) @@ -775,7 +384,7 @@ int getScaledMaxYScroll() IntRect getVisibleRect() { IntRect rect; - LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); + ALOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); JNIEnv* env = JSC::Bindings::getJNIEnv(); AutoJObject javaObject = m_javaGlue.object(env); if (!javaObject.get()) @@ -795,250 +404,9 @@ IntRect getVisibleRect() return rect; } -static CachedFrame::Direction KeyToDirection(int32_t keyCode) -{ - switch (keyCode) { - case AKEYCODE_DPAD_RIGHT: - DBG_NAV_LOGD("keyCode=%s", "right"); - return CachedFrame::RIGHT; - case AKEYCODE_DPAD_LEFT: - DBG_NAV_LOGD("keyCode=%s", "left"); - return CachedFrame::LEFT; - case AKEYCODE_DPAD_DOWN: - DBG_NAV_LOGD("keyCode=%s", "down"); - return CachedFrame::DOWN; - case AKEYCODE_DPAD_UP: - DBG_NAV_LOGD("keyCode=%s", "up"); - return CachedFrame::UP; - default: - DBG_NAV_LOGD("bad key %d sent", keyCode); - return CachedFrame::UNINITIALIZED; - } -} - -WTF::String imageURI(int x, int y) -{ - const CachedRoot* root = getFrameCache(DontAllowNewer); - return root ? root->imageURI(x, y) : WTF::String(); -} - -bool cursorWantsKeyEvents() -{ - const CachedRoot* root = getFrameCache(DontAllowNewer); - if (root) { - const CachedNode* focus = root->currentCursor(); - if (focus) - return focus->wantsKeyEvents(); - } - return false; -} - - -/* returns true if the key had no effect (neither scrolled nor changed cursor) */ -bool moveCursor(int keyCode, int count, bool ignoreScroll) -{ - CachedRoot* root = getFrameCache(AllowNewer); - if (!root) { - DBG_NAV_LOG("!root"); - return true; - } - - m_viewImpl->m_moveGeneration++; - CachedFrame::Direction direction = KeyToDirection(keyCode); - const CachedFrame* cachedFrame, * oldFrame = 0; - const CachedNode* cursor = root->currentCursor(&oldFrame); - WebCore::IntPoint cursorLocation = root->cursorLocation(); - DBG_NAV_LOGD("old cursor %d (nativeNode=%p) cursorLocation={%d, %d}", - cursor ? cursor->index() : 0, - cursor ? cursor->nodePointer() : 0, cursorLocation.x(), cursorLocation.y()); - WebCore::IntRect visibleRect = setVisibleRect(root); - int xMax = getScaledMaxXScroll(); - int yMax = getScaledMaxYScroll(); - root->setMaxScroll(xMax, yMax); - const CachedNode* cachedNode = 0; - int dx = 0; - int dy = 0; - int counter = count; - while (--counter >= 0) { - WebCore::IntPoint scroll = WebCore::IntPoint(0, 0); - cachedNode = root->moveCursor(direction, &cachedFrame, &scroll); - dx += scroll.x(); - dy += scroll.y(); - } - DBG_NAV_LOGD("new cursor %d (nativeNode=%p) cursorLocation={%d, %d}" - "bounds={%d,%d,w=%d,h=%d}", cachedNode ? cachedNode->index() : 0, - cachedNode ? cachedNode->nodePointer() : 0, - root->cursorLocation().x(), root->cursorLocation().y(), - cachedNode ? cachedNode->bounds(cachedFrame).x() : 0, - cachedNode ? cachedNode->bounds(cachedFrame).y() : 0, - cachedNode ? cachedNode->bounds(cachedFrame).width() : 0, - cachedNode ? cachedNode->bounds(cachedFrame).height() : 0); - // If !m_heightCanMeasure (such as in the browser), we want to scroll no - // matter what - if (!ignoreScroll && (!m_heightCanMeasure || - !cachedNode || - (cursor && cursor->nodePointer() == cachedNode->nodePointer()))) - { - if (count == 1 && dx != 0 && dy == 0 && -m_lastDx == dx && - SkTime::GetMSecs() - m_lastDxTime < 1000) - root->checkForJiggle(&dx); - DBG_NAV_LOGD("scrollBy %d,%d", dx, dy); - if ((dx | dy)) - this->scrollBy(dx, dy); - m_lastDx = dx; - m_lastDxTime = SkTime::GetMSecs(); - } - bool result = false; - if (cachedNode) { - showCursorUntimed(); - m_viewImpl->updateCursorBounds(root, cachedFrame, cachedNode); - root->setCursor(const_cast<CachedFrame*>(cachedFrame), - const_cast<CachedNode*>(cachedNode)); - const CachedNode* focus = root->currentFocus(); - bool clearTextEntry = cachedNode != focus && focus - && cachedNode->nodePointer() != focus->nodePointer() && focus->isTextInput(); - // Stop painting the caret if the old focus was a text input and so is the new cursor. - bool stopPaintingCaret = clearTextEntry && cachedNode->wantsKeyEvents(); - sendMoveMouseIfLatest(clearTextEntry, stopPaintingCaret); - } else { - int docHeight = root->documentHeight(); - int docWidth = root->documentWidth(); - if (visibleRect.maxY() + dy > docHeight) - dy = docHeight - visibleRect.maxY(); - else if (visibleRect.y() + dy < 0) - dy = -visibleRect.y(); - if (visibleRect.maxX() + dx > docWidth) - dx = docWidth - visibleRect.maxX(); - else if (visibleRect.x() < 0) - dx = -visibleRect.x(); - result = direction == CachedFrame::LEFT ? dx >= 0 : - direction == CachedFrame::RIGHT ? dx <= 0 : - direction == CachedFrame::UP ? dy >= 0 : dy <= 0; - } - return result; -} - void notifyProgressFinished() { - DBG_NAV_LOGD("cursorIsTextInput=%d", cursorIsTextInput(DontAllowNewer)); rebuildWebTextView(); -#if DEBUG_NAV_UI - if (m_frameCacheUI) { - const CachedNode* focus = m_frameCacheUI->currentFocus(); - DBG_NAV_LOGD("focus %d (nativeNode=%p)", - focus ? focus->index() : 0, - focus ? focus->nodePointer() : 0); - } -#endif -} - -const CachedNode* findAt(CachedRoot* root, const WebCore::IntRect& rect, - const CachedFrame** framePtr, int* rxPtr, int* ryPtr) -{ - *rxPtr = 0; - *ryPtr = 0; - *framePtr = 0; - if (!root) - return 0; - setVisibleRect(root); - return root->findAt(rect, framePtr, rxPtr, ryPtr, true); -} - -IntRect setVisibleRect(CachedRoot* root) -{ - IntRect visibleRect = getVisibleRect(); - DBG_NAV_LOGD("getVisibleRect %d,%d,%d,%d", - visibleRect.x(), visibleRect.y(), visibleRect.width(), visibleRect.height()); - root->setVisibleRect(visibleRect); - return visibleRect; -} - -void selectBestAt(const WebCore::IntRect& rect) -{ - const CachedFrame* frame; - int rx, ry; - CachedRoot* root = getFrameCache(AllowNewer); - if (!root) - return; - const CachedNode* node = findAt(root, rect, &frame, &rx, &ry); - if (!node) { - DBG_NAV_LOGD("no nodes found root=%p", root); - root->rootHistory()->setMouseBounds(rect); - m_viewImpl->m_hasCursorBounds = false; - root->setCursor(0, 0); - viewInvalidate(); - } else { - DBG_NAV_LOGD("CachedNode:%p (%d)", node, node->index()); - WebCore::IntRect bounds = node->bounds(frame); - root->rootHistory()->setMouseBounds(bounds); - m_viewImpl->updateCursorBounds(root, frame, node); - showCursorTimed(); - root->setCursor(const_cast<CachedFrame*>(frame), - const_cast<CachedNode*>(node)); - } - sendMoveMouseIfLatest(false, false); -} - -const CachedNode* m_cacheHitNode; -const CachedFrame* m_cacheHitFrame; - -bool pointInNavCache(int x, int y, int slop) -{ - CachedRoot* root = getFrameCache(AllowNewer); - if (!root) - return false; - IntRect rect = IntRect(x - slop, y - slop, slop * 2, slop * 2); - int rx, ry; - return (m_cacheHitNode = findAt(root, rect, &m_cacheHitFrame, &rx, &ry)); -} - -bool motionUp(int x, int y, int slop) -{ - bool pageScrolled = false; - IntRect rect = IntRect(x - slop, y - slop, slop * 2, slop * 2); - int rx, ry; - CachedRoot* root = getFrameCache(AllowNewer); - if (!root) - return 0; - const CachedFrame* frame = 0; - const CachedNode* result = findAt(root, rect, &frame, &rx, &ry); - CachedHistory* history = root->rootHistory(); - if (!result) { - DBG_NAV_LOGD("no nodes found root=%p", root); - history->setNavBounds(rect); - m_viewImpl->m_hasCursorBounds = false; - root->hideCursor(); - int dx = root->checkForCenter(x, y); - if (dx) { - scrollBy(dx, 0); - pageScrolled = true; - } - sendMotionUp(frame ? (WebCore::Frame*) frame->framePointer() : 0, - 0, x, y); - viewInvalidate(); - return pageScrolled; - } - DBG_NAV_LOGD("CachedNode:%p (%d) x=%d y=%d rx=%d ry=%d", result, - result->index(), x, y, rx, ry); - WebCore::IntRect navBounds = WebCore::IntRect(rx, ry, 1, 1); - history->setNavBounds(navBounds); - history->setMouseBounds(navBounds); - m_viewImpl->updateCursorBounds(root, frame, result); - root->setCursor(const_cast<CachedFrame*>(frame), - const_cast<CachedNode*>(result)); - if (result->isSyntheticLink()) - overrideUrlLoading(result->getExport()); - else { - sendMotionUp( - (WebCore::Frame*) frame->framePointer(), - (WebCore::Node*) result->nodePointer(), rx, ry); - } - if (result->isTextInput() || result->isSelect() - || result->isContentEditable()) { - showCursorUntimed(); - } else - showCursorTimed(); - return pageScrolled; } #if USE(ACCELERATED_COMPOSITING) @@ -1099,14 +467,6 @@ void scrollLayer(int layerId, int x, int y) m_glWebViewState->scrollLayer(layerId, x, y); } -int getBlockLeftEdge(int x, int y, float scale) -{ - CachedRoot* root = getFrameCache(AllowNewer); - if (root) - return root->getBlockLeftEdge(x, y, scale); - return -1; -} - void overrideUrlLoading(const WTF::String& url) { JNIEnv* env = JSC::Bindings::getJNIEnv(); @@ -1120,31 +480,9 @@ void overrideUrlLoading(const WTF::String& url) void setFindIsUp(bool up) { - DBG_NAV_LOGD("up=%d", up); m_viewImpl->m_findIsUp = up; } -void setFindIsEmpty() -{ - DBG_NAV_LOG(""); - m_findOnPage.clearCurrentLocation(); -} - -void showCursorTimed() -{ - DBG_NAV_LOG(""); - m_ringAnimationEnd = SkTime::GetMSecs() + PRESSED_STATE_DURATION; - viewInvalidate(); -} - -void showCursorUntimed() -{ - DBG_NAV_LOG(""); - m_ring.m_isPressed = false; - m_ringAnimationEnd = UINT_MAX; - viewInvalidate(); -} - void setHeightCanMeasure(bool measure) { m_heightCanMeasure = measure; @@ -1152,90 +490,15 @@ void setHeightCanMeasure(bool measure) String getSelection() { - return m_selectText.getSelection(); -} - -void moveSelection(int x, int y) -{ - m_selectText.moveSelection(getVisibleRect(), x, y); -} - -IntPoint selectableText() -{ - const CachedRoot* root = getFrameCache(DontAllowNewer); - if (!root) - return IntPoint(0, 0); - return m_selectText.selectableText(root); -} - -void selectAll() -{ - m_selectText.selectAll(); -} - -int selectionX() -{ - return m_selectText.selectionX(); -} - -int selectionY() -{ - return m_selectText.selectionY(); -} - -void resetSelection() -{ - m_selectText.reset(); -} - -bool startSelection(int x, int y) -{ - const CachedRoot* root = getFrameCache(DontAllowNewer); - if (!root) - return false; - updateSelectionHandles(); - return m_selectText.startSelection(root, getVisibleRect(), x, y); -} - -bool wordSelection(int x, int y) -{ - const CachedRoot* root = getFrameCache(DontAllowNewer); - if (!root) - return false; - updateSelectionHandles(); - return m_selectText.wordSelection(root, getVisibleRect(), x, y); -} - -bool extendSelection(int x, int y) -{ - m_selectText.extendSelection(getVisibleRect(), x, y); - return true; -} - -bool hitSelection(int x, int y) -{ - updateSelectionHandles(); - return m_selectText.hitSelection(x, y); -} - -void setExtendSelection() -{ - m_selectText.setExtendSelection(true); -} - -void setSelectionPointer(bool set, float scale, int x, int y) -{ - m_selectText.setDrawPointer(set); - if (!set) - return; - m_selectText.m_inverseScale = scale; - m_selectText.m_selectX = x; - m_selectText.m_selectY = y; + SelectText* select = static_cast<SelectText*>( + getDrawExtra(WebView::DrawExtrasSelection)); + if (select) + return select->getText(); + return String(); } void sendMoveFocus(WebCore::Frame* framePtr, WebCore::Node* nodePtr) { - DBG_NAV_LOGD("framePtr=%p nodePtr=%p", framePtr, nodePtr); JNIEnv* env = JSC::Bindings::getJNIEnv(); AutoJObject javaObject = m_javaGlue.object(env); if (!javaObject.get()) @@ -1246,7 +509,6 @@ void sendMoveFocus(WebCore::Frame* framePtr, WebCore::Node* nodePtr) void sendMoveMouse(WebCore::Frame* framePtr, WebCore::Node* nodePtr, int x, int y) { - DBG_NAV_LOGD("framePtr=%p nodePtr=%p x=%d y=%d", framePtr, nodePtr, x, y); JNIEnv* env = JSC::Bindings::getJNIEnv(); AutoJObject javaObject = m_javaGlue.object(env); if (!javaObject.get()) @@ -1257,7 +519,7 @@ void sendMoveMouse(WebCore::Frame* framePtr, WebCore::Node* nodePtr, int x, int void sendMoveMouseIfLatest(bool clearTextEntry, bool stopPaintingCaret) { - LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); + ALOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); JNIEnv* env = JSC::Bindings::getJNIEnv(); AutoJObject javaObject = m_javaGlue.object(env); if (!javaObject.get()) @@ -1268,8 +530,7 @@ void sendMoveMouseIfLatest(bool clearTextEntry, bool stopPaintingCaret) void sendMotionUp(WebCore::Frame* framePtr, WebCore::Node* nodePtr, int x, int y) { - DBG_NAV_LOGD("m_generation=%d framePtr=%p nodePtr=%p x=%d y=%d", m_generation, framePtr, nodePtr, x, y); - LOG_ASSERT(m_javaGlue.m_obj, "A WebView was not associated with this WebViewNative!"); + ALOG_ASSERT(m_javaGlue.m_obj, "A WebView was not associated with this WebViewNative!"); JNIEnv* env = JSC::Bindings::getJNIEnv(); AutoJObject javaObject = m_javaGlue.object(env); @@ -1280,42 +541,9 @@ void sendMotionUp(WebCore::Frame* framePtr, WebCore::Node* nodePtr, int x, int y checkException(env); } -void findNext(bool forward) -{ - m_findOnPage.findNext(forward); - scrollToCurrentMatch(); - viewInvalidate(); -} - -// With this call, WebView takes ownership of matches, and is responsible for -// deleting it. -void setMatches(WTF::Vector<MatchInfo>* matches, jboolean sameAsLastSearch) -{ - // If this search is the same as the last one, check against the old - // location to determine whether to scroll. If the same word is found - // in the same place, then do not scroll. - IntRect oldLocation; - bool checkAgainstOldLocation = false; - if (sameAsLastSearch && m_findOnPage.isCurrentLocationValid()) { - oldLocation = m_findOnPage.currentMatchBounds(); - checkAgainstOldLocation = true; - } - - m_findOnPage.setMatches(matches); - - if (!checkAgainstOldLocation || oldLocation != m_findOnPage.currentMatchBounds()) - scrollToCurrentMatch(); - viewInvalidate(); -} - -int currentMatchIndex() -{ - return m_findOnPage.currentMatchIndex(); -} - bool scrollBy(int dx, int dy) { - LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); + ALOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); JNIEnv* env = JSC::Bindings::getJNIEnv(); AutoJObject javaObject = m_javaGlue.object(env); @@ -1334,34 +562,6 @@ void setIsScrolling(bool isScrolling) #endif } -bool hasCursorNode() -{ - CachedRoot* root = getFrameCache(DontAllowNewer); - if (!root) { - DBG_NAV_LOG("!root"); - return false; - } - const CachedNode* cursorNode = root->currentCursor(); - DBG_NAV_LOGD("cursorNode=%d (nodePointer=%p)", - cursorNode ? cursorNode->index() : -1, - cursorNode ? cursorNode->nodePointer() : 0); - return cursorNode; -} - -bool hasFocusNode() -{ - CachedRoot* root = getFrameCache(DontAllowNewer); - if (!root) { - DBG_NAV_LOG("!root"); - return false; - } - const CachedNode* focusNode = root->currentFocus(); - DBG_NAV_LOGD("focusNode=%d (nodePointer=%p)", - focusNode ? focusNode->index() : -1, - focusNode ? focusNode->nodePointer() : 0); - return focusNode; -} - void rebuildWebTextView() { JNIEnv* env = JSC::Bindings::getJNIEnv(); @@ -1403,17 +603,6 @@ void postInvalidateDelayed(int64_t delay, const WebCore::IntRect& bounds) checkException(env); } -bool inFullScreenMode() -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - AutoJObject javaObject = m_javaGlue.object(env); - if (!javaObject.get()) - return false; - jboolean result = env->CallBooleanMethod(javaObject.get(), m_javaGlue.m_inFullScreenMode); - checkException(env); - return result; -} - int moveGeneration() { return m_viewImpl->m_moveGeneration; @@ -1421,7 +610,7 @@ int moveGeneration() LayerAndroid* compositeRoot() const { - LOG_ASSERT(!m_baseLayer || m_baseLayer->countChildren() == 1, + ALOG_ASSERT(!m_baseLayer || m_baseLayer->countChildren() == 1, "base layer can't have more than one child %s", __FUNCTION__); if (m_baseLayer && m_baseLayer->countChildren() == 1) return static_cast<LayerAndroid*>(m_baseLayer->getChild(0)); @@ -1448,19 +637,17 @@ static void copyScrollPositionRecursive(const LayerAndroid* from, } #endif -void registerPageSwapCallback() -{ - m_pageSwapCallbackRegistered = true; -} - -void setBaseLayer(BaseLayerAndroid* layer, SkRegion& inval, bool showVisualIndicator, - bool isPictureAfterFirstLayout, bool registerPageSwapCallback) +bool setBaseLayer(BaseLayerAndroid* layer, SkRegion& inval, bool showVisualIndicator, + bool isPictureAfterFirstLayout) { + bool queueFull = false; #if USE(ACCELERATED_COMPOSITING) - if (m_glWebViewState) - m_glWebViewState->setBaseLayer(layer, inval, showVisualIndicator, - isPictureAfterFirstLayout); - m_pageSwapCallbackRegistered |= registerPageSwapCallback; + if (m_glWebViewState) { + if (layer) + layer->markAsDirty(inval); + queueFull = m_glWebViewState->setBaseLayer(layer, showVisualIndicator, + isPictureAfterFirstLayout); + } #endif #if ENABLE(ANDROID_OVERFLOW_SCROLL) @@ -1472,21 +659,8 @@ void setBaseLayer(BaseLayerAndroid* layer, SkRegion& inval, bool showVisualIndic #endif SkSafeUnref(m_baseLayer); m_baseLayer = layer; - CachedRoot* root = getFrameCache(DontAllowNewer); - if (!root) - return; - root->resetLayers(); - root->setRootLayer(compositeRoot()); -} - -void getTextSelectionRegion(SkRegion *region) -{ - m_selectText.getSelectionRegion(getVisibleRect(), region, compositeRoot()); -} -void getTextSelectionHandles(int* handles) -{ - m_selectText.getSelectionHandles(handles, compositeRoot()); + return queueFull; } void replaceBaseContent(PictureSet* set) @@ -1530,28 +704,55 @@ void setVisibleRect(SkRect& visibleRect) { m_visibleRect = visibleRect; } +void setDrawExtra(DrawExtra *extra, DrawExtras type) +{ + if (type == DrawExtrasNone) + return; + DrawExtra* old = m_extras[type - 1]; + m_extras[type - 1] = extra; + if (old != extra) { + delete old; + } +} + +void setTextSelection(SelectText *selection) { + setDrawExtra(selection, DrawExtrasSelection); +} + +int getHandleLayerId(SelectText::HandleId handleId, SkIRect& cursorRect) { + SelectText* selectText = static_cast<SelectText*>(getDrawExtra(DrawExtrasSelection)); + if (!selectText || !m_baseLayer) + return -1; + int layerId = selectText->caretLayerId(handleId); + IntRect rect = selectText->caretRect(handleId); + if (layerId != -1) { + // We need to make sure the drawTransform is up to date as this is + // called before a draw() or drawGL() + m_baseLayer->updateLayerPositions(m_visibleRect); + LayerAndroid* root = compositeRoot(); + LayerAndroid* layer = root ? root->findById(layerId) : 0; + if (layer && layer->drawTransform()) + rect = layer->drawTransform()->mapRect(rect); + } + cursorRect.set(rect.x(), rect.y(), rect.maxX(), rect.maxY()); + return layerId; +} + bool m_isDrawingPaused; private: // local state for WebView // private to getFrameCache(); other functions operate in a different thread - CachedRoot* m_frameCacheUI; // navigation data ready for use WebViewCore* m_viewImpl; int m_generation; // associate unique ID with sent kit focus to match with ui - SkPicture* m_navPictureUI; - SkMSec m_ringAnimationEnd; // Corresponds to the same-named boolean on the java side. bool m_heightCanMeasure; int m_lastDx; SkMSec m_lastDxTime; - SelectText m_selectText; - FindOnPage m_findOnPage; - CursorRing m_ring; + DrawExtra* m_extras[DRAW_EXTRAS_SIZE]; BaseLayerAndroid* m_baseLayer; Functor* m_glDrawFunctor; #if USE(ACCELERATED_COMPOSITING) GLWebViewState* m_glWebViewState; - bool m_pageSwapCallbackRegistered; #endif - RenderSkinButton* m_buttonSkin; SkRect m_visibleRect; bool m_isHighEndGfx; }; // end of WebView class @@ -1566,8 +767,7 @@ class GLDrawFunctor : Functor { public: GLDrawFunctor(WebView* _wvInstance, bool(WebView::*_funcPtr)(WebCore::IntRect&, WebCore::IntRect*, - WebCore::IntRect&, int, WebCore::IntRect&, - jfloat, jint), + WebCore::IntRect&, int, WebCore::IntRect&, jfloat, jint), WebCore::IntRect _viewRect, float _scale, int _extras) { wvInstance = _wvInstance; funcPtr = _funcPtr; @@ -1621,6 +821,9 @@ class GLDrawFunctor : Functor { void updateViewRect(WebCore::IntRect& _viewRect) { webViewRect = _viewRect; } + void updateScale(float _scale) { + scale = _scale; + } private: WebView* wvInstance; bool (WebView::*funcPtr)(WebCore::IntRect&, WebCore::IntRect*, @@ -1631,180 +834,70 @@ class GLDrawFunctor : Functor { jint extras; }; -static jobject createJavaRect(JNIEnv* env, int x, int y, int right, int bottom) -{ - jclass rectClass = env->FindClass("android/graphics/Rect"); - jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V"); - jobject rect = env->NewObject(rectClass, init, x, y, right, bottom); - env->DeleteLocalRef(rectClass); - return rect; -} - /* * Native JNI methods */ static int nativeCacheHitFramePointer(JNIEnv *env, jobject obj) { - return reinterpret_cast<int>(GET_NATIVE_VIEW(env, obj) - ->m_cacheHitFrame->framePointer()); + return 0; } static jobject nativeCacheHitNodeBounds(JNIEnv *env, jobject obj) { - WebCore::IntRect bounds = GET_NATIVE_VIEW(env, obj) - ->m_cacheHitNode->originalAbsoluteBounds(); - return createJavaRect(env, bounds.x(), bounds.y(), - bounds.maxX(), bounds.maxY()); + return 0; } static int nativeCacheHitNodePointer(JNIEnv *env, jobject obj) { - return reinterpret_cast<int>(GET_NATIVE_VIEW(env, obj) - ->m_cacheHitNode->nodePointer()); + return 0; } static bool nativeCacheHitIsPlugin(JNIEnv *env, jobject obj) { - return GET_NATIVE_VIEW(env, obj)->m_cacheHitNode->isPlugin(); + return false; } static void nativeClearCursor(JNIEnv *env, jobject obj) { - WebView* view = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(view, "view not set in %s", __FUNCTION__); - view->clearCursor(); } static void nativeCreate(JNIEnv *env, jobject obj, int viewImpl, jstring drawableDir, jboolean isHighEndGfx) { WTF::String dir = jstringToWtfString(env, drawableDir); - WebView* webview = new WebView(env, obj, viewImpl, dir, isHighEndGfx); + new WebView(env, obj, viewImpl, dir, isHighEndGfx); // NEED THIS OR SOMETHING LIKE IT! //Release(obj); } static jint nativeCursorFramePointer(JNIEnv *env, jobject obj) { - WebView* view = GET_NATIVE_VIEW(env, obj); - CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); - if (!root) - return 0; - const CachedFrame* frame = 0; - (void) root->currentCursor(&frame); - return reinterpret_cast<int>(frame ? frame->framePointer() : 0); -} - -static const CachedNode* getCursorNode(JNIEnv *env, jobject obj) -{ - WebView* view = GET_NATIVE_VIEW(env, obj); - CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); - return root ? root->currentCursor() : 0; -} - -static const CachedNode* getCursorNode(JNIEnv *env, jobject obj, - const CachedFrame** frame) -{ - WebView* view = GET_NATIVE_VIEW(env, obj); - CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); - return root ? root->currentCursor(frame) : 0; -} - -static const CachedNode* getFocusCandidate(JNIEnv *env, jobject obj, - const CachedFrame** frame) -{ - WebView* view = GET_NATIVE_VIEW(env, obj); - CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); - if (!root) - return 0; - const CachedNode* cursor = root->currentCursor(frame); - if (cursor && cursor->wantsKeyEvents()) - return cursor; - return root->currentFocus(frame); + return 0; } static bool focusCandidateHasNextTextfield(JNIEnv *env, jobject obj) { - WebView* view = GET_NATIVE_VIEW(env, obj); - CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); - if (!root) - return false; - const CachedNode* cursor = root->currentCursor(); - if (!cursor || !cursor->isTextInput()) - cursor = root->currentFocus(); - if (!cursor || !cursor->isTextInput()) return false; - return root->nextTextField(cursor, 0); -} - -static const CachedNode* getFocusNode(JNIEnv *env, jobject obj) -{ - WebView* view = GET_NATIVE_VIEW(env, obj); - CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); - return root ? root->currentFocus() : 0; -} - -static const CachedNode* getFocusNode(JNIEnv *env, jobject obj, - const CachedFrame** frame) -{ - WebView* view = GET_NATIVE_VIEW(env, obj); - CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); - return root ? root->currentFocus(frame) : 0; -} - -static const CachedInput* getInputCandidate(JNIEnv *env, jobject obj) -{ - WebView* view = GET_NATIVE_VIEW(env, obj); - CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); - if (!root) - return 0; - const CachedFrame* frame; - const CachedNode* cursor = root->currentCursor(&frame); - if (!cursor || !cursor->wantsKeyEvents()) - cursor = root->currentFocus(&frame); - return cursor ? frame->textInput(cursor) : 0; + return false; } static jboolean nativePageShouldHandleShiftAndArrows(JNIEnv *env, jobject obj) { - const CachedNode* focus = getFocusNode(env, obj); - if (!focus) return false; - // Plugins handle shift and arrows whether or not they have focus. - if (focus->isPlugin()) return true; - const CachedNode* cursor = getCursorNode(env, obj); - // ContentEditable nodes should only receive shift and arrows if they have - // both the cursor and the focus. - return cursor && cursor->nodePointer() == focus->nodePointer() - && cursor->isContentEditable(); + return true; } static jobject nativeCursorNodeBounds(JNIEnv *env, jobject obj) { - const CachedFrame* frame; - const CachedNode* node = getCursorNode(env, obj, &frame); - WebCore::IntRect bounds = node ? node->bounds(frame) - : WebCore::IntRect(0, 0, 0, 0); - return createJavaRect(env, bounds.x(), bounds.y(), - bounds.maxX(), bounds.maxY()); + return 0; } static jint nativeCursorNodePointer(JNIEnv *env, jobject obj) { - const CachedNode* node = getCursorNode(env, obj); - return reinterpret_cast<int>(node ? node->nodePointer() : 0); + return 0; } static jobject nativeCursorPosition(JNIEnv *env, jobject obj) { - WebView* view = GET_NATIVE_VIEW(env, obj); - const CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); - WebCore::IntPoint pos = WebCore::IntPoint(0, 0); - if (root) - root->getSimulatedMousePosition(&pos); - jclass pointClass = env->FindClass("android/graphics/Point"); - jmethodID init = env->GetMethodID(pointClass, "<init>", "(II)V"); - jobject point = env->NewObject(pointClass, init, pos.x(), pos.y()); - env->DeleteLocalRef(pointClass); - return point; + return 0; } static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj) @@ -1827,40 +920,26 @@ static SkRect jrectf_to_rect(JNIEnv* env, jobject obj) static bool nativeCursorIntersects(JNIEnv *env, jobject obj, jobject visRect) { - const CachedFrame* frame; - const CachedNode* node = getCursorNode(env, obj, &frame); - return node ? node->bounds(frame).intersects( - jrect_to_webrect(env, visRect)) : false; + return false; } static bool nativeCursorIsAnchor(JNIEnv *env, jobject obj) { - const CachedNode* node = getCursorNode(env, obj); - return node ? node->isAnchor() : false; + return false; } static bool nativeCursorIsTextInput(JNIEnv *env, jobject obj) { - const CachedNode* node = getCursorNode(env, obj); - return node ? node->isTextInput() : false; + return false; } static jobject nativeCursorText(JNIEnv *env, jobject obj) { - const CachedNode* node = getCursorNode(env, obj); - if (!node) - return 0; - WTF::String value = node->getExport(); - return wtfStringToJstring(env, value); + return 0; } static void nativeDebugDump(JNIEnv *env, jobject obj) { -#if DUMP_NAV_CACHE - WebView* view = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(view, "view not set in %s", __FUNCTION__); - view->debugDump(); -#endif } static jint nativeDraw(JNIEnv *env, jobject obj, jobject canv, @@ -1870,7 +949,8 @@ static jint nativeDraw(JNIEnv *env, jobject obj, jobject canv, WebView* webView = GET_NATIVE_VIEW(env, obj); SkRect visibleRect = jrectf_to_rect(env, visible); webView->setVisibleRect(visibleRect); - PictureSet* pictureSet = webView->draw(canvas, color, extras, split); + PictureSet* pictureSet = webView->draw(canvas, color, + static_cast<WebView::DrawExtras>(extras), split); return reinterpret_cast<jint>(pictureSet); } @@ -1894,7 +974,7 @@ static jint nativeGetDrawGLFunction(JNIEnv *env, jobject obj, jint nativeView, } static void nativeUpdateDrawGLFunction(JNIEnv *env, jobject obj, jobject jrect, - jobject jviewrect, jobject jvisiblerect) { + jobject jviewrect, jobject jvisiblerect, jfloat scale) { WebView *wvInstance = GET_NATIVE_VIEW(env, obj); if (wvInstance) { GLDrawFunctor* functor = (GLDrawFunctor*) wvInstance->getFunctor(); @@ -1907,6 +987,8 @@ static void nativeUpdateDrawGLFunction(JNIEnv *env, jobject obj, jobject jrect, WebCore::IntRect webViewRect = jrect_to_webrect(env, jviewrect); functor->updateViewRect(webViewRect); + + functor->updateScale(scale); } } } @@ -1924,36 +1006,16 @@ static bool nativeEvaluateLayersAnimations(JNIEnv *env, jobject obj, jint native return false; } -static void nativeSetBaseLayer(JNIEnv *env, jobject obj, jint layer, jobject inval, - jboolean showVisualIndicator, - jboolean isPictureAfterFirstLayout, - jboolean registerPageSwapCallback) +static bool nativeSetBaseLayer(JNIEnv *env, jobject obj, jint nativeView, jint layer, jobject inval, + jboolean showVisualIndicator, + jboolean isPictureAfterFirstLayout) { BaseLayerAndroid* layerImpl = reinterpret_cast<BaseLayerAndroid*>(layer); SkRegion invalRegion; if (inval) invalRegion = *GraphicsJNI::getNativeRegion(env, inval); - GET_NATIVE_VIEW(env, obj)->setBaseLayer(layerImpl, invalRegion, showVisualIndicator, - isPictureAfterFirstLayout, - registerPageSwapCallback); -} - -static void nativeGetTextSelectionRegion(JNIEnv *env, jobject obj, jint view, - jobject region) -{ - if (!region) - return; - SkRegion* nregion = GraphicsJNI::getNativeRegion(env, region); - ((WebView*)view)->getTextSelectionRegion(nregion); -} - -static void nativeGetSelectionHandles(JNIEnv *env, jobject obj, jint view, - jintArray arr) -{ - int handles[4]; - ((WebView*)view)->getTextSelectionHandles(handles); - env->SetIntArrayRegion(arr, 0, 4, handles); - checkException(env); + return ((WebView*)nativeView)->setBaseLayer(layerImpl, invalRegion, showVisualIndicator, + isPictureAfterFirstLayout); } static BaseLayerAndroid* nativeGetBaseLayer(JNIEnv *env, jobject obj) @@ -1980,202 +1042,124 @@ static bool nativeHasContent(JNIEnv *env, jobject obj) static jobject nativeImageURI(JNIEnv *env, jobject obj, jint x, jint y) { - WebView* view = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(view, "view not set in %s", __FUNCTION__); - WTF::String uri = view->imageURI(x, y); - return wtfStringToJstring(env, uri); + return 0; } static jint nativeFocusCandidateFramePointer(JNIEnv *env, jobject obj) { - WebView* view = GET_NATIVE_VIEW(env, obj); - CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); - if (!root) - return 0; - const CachedFrame* frame = 0; - const CachedNode* cursor = root->currentCursor(&frame); - if (!cursor || !cursor->wantsKeyEvents()) - (void) root->currentFocus(&frame); - return reinterpret_cast<int>(frame ? frame->framePointer() : 0); + return 0; +} + +static bool nativeFocusCandidateIsEditableText(JNIEnv* env, jobject obj, + jint nativeClass) +{ + return false; } static bool nativeFocusCandidateIsPassword(JNIEnv *env, jobject obj) { - const CachedInput* input = getInputCandidate(env, obj); - return input && input->getType() == CachedInput::PASSWORD; + return false; } static bool nativeFocusCandidateIsRtlText(JNIEnv *env, jobject obj) { - const CachedInput* input = getInputCandidate(env, obj); - return input ? input->isRtlText() : false; + return false; } static bool nativeFocusCandidateIsTextInput(JNIEnv *env, jobject obj) { - const CachedNode* node = getFocusCandidate(env, obj, 0); - return node ? node->isTextInput() : false; + return false; } static jint nativeFocusCandidateMaxLength(JNIEnv *env, jobject obj) { - const CachedInput* input = getInputCandidate(env, obj); - return input ? input->maxLength() : false; + return 0; } static jint nativeFocusCandidateIsAutoComplete(JNIEnv *env, jobject obj) { - const CachedInput* input = getInputCandidate(env, obj); - return input ? input->autoComplete() : false; + return 0; } static jobject nativeFocusCandidateName(JNIEnv *env, jobject obj) { - const CachedInput* input = getInputCandidate(env, obj); - if (!input) - return 0; - const WTF::String& name = input->name(); - return wtfStringToJstring(env, name); + return false; } static jobject nativeFocusCandidateNodeBounds(JNIEnv *env, jobject obj) { - const CachedFrame* frame; - const CachedNode* node = getFocusCandidate(env, obj, &frame); - WebCore::IntRect bounds = node ? node->originalAbsoluteBounds() - : WebCore::IntRect(0, 0, 0, 0); - // Inset the rect by 1 unit, so that the focus candidate's border can still - // be seen behind it. - return createJavaRect(env, bounds.x(), bounds.y(), - bounds.maxX(), bounds.maxY()); + return 0; } static jobject nativeFocusCandidatePaddingRect(JNIEnv *env, jobject obj) { - const CachedInput* input = getInputCandidate(env, obj); - if (!input) - return 0; - // Note that the Java Rect is being used to pass four integers, rather than - // being used as an actual rectangle. - return createJavaRect(env, input->paddingLeft(), input->paddingTop(), - input->paddingRight(), input->paddingBottom()); + return 0; } static jint nativeFocusCandidatePointer(JNIEnv *env, jobject obj) { - const CachedNode* node = getFocusCandidate(env, obj, 0); - return reinterpret_cast<int>(node ? node->nodePointer() : 0); + return 0; } static jint nativeFocusCandidateIsSpellcheck(JNIEnv *env, jobject obj) { - const CachedInput* input = getInputCandidate(env, obj); - return input ? input->spellcheck() : false; + return 0; } static jobject nativeFocusCandidateText(JNIEnv *env, jobject obj) { - const CachedNode* node = getFocusCandidate(env, obj, 0); - if (!node) - return 0; - WTF::String value = node->getExport(); - return wtfStringToJstring(env, value); + return 0; } static int nativeFocusCandidateLineHeight(JNIEnv *env, jobject obj) { - const CachedInput* input = getInputCandidate(env, obj); - return input ? input->lineHeight() : 0; + return 0; } static jfloat nativeFocusCandidateTextSize(JNIEnv *env, jobject obj) { - const CachedInput* input = getInputCandidate(env, obj); - return input ? input->textSize() : 0.f; + return 0.f; } static int nativeFocusCandidateType(JNIEnv *env, jobject obj) { - const CachedInput* input = getInputCandidate(env, obj); - if (!input) - return CachedInput::NONE; - - if (input->isTextArea()) - return CachedInput::TEXT_AREA; - - return input->getType(); + return 0; } static int nativeFocusCandidateLayerId(JNIEnv *env, jobject obj) { - const CachedFrame* frame = 0; - const CachedNode* node = getFocusNode(env, obj, &frame); - if (!node || !frame) - return -1; - const CachedLayer* layer = frame->layer(node); - if (!layer) - return -1; - return layer->uniqueId(); + return 0; } static bool nativeFocusIsPlugin(JNIEnv *env, jobject obj) { - const CachedNode* node = getFocusNode(env, obj); - return node ? node->isPlugin() : false; + return false; } static jobject nativeFocusNodeBounds(JNIEnv *env, jobject obj) { - const CachedFrame* frame; - const CachedNode* node = getFocusNode(env, obj, &frame); - WebCore::IntRect bounds = node ? node->bounds(frame) - : WebCore::IntRect(0, 0, 0, 0); - return createJavaRect(env, bounds.x(), bounds.y(), - bounds.maxX(), bounds.maxY()); + return 0; } static jint nativeFocusNodePointer(JNIEnv *env, jobject obj) { - const CachedNode* node = getFocusNode(env, obj); - return node ? reinterpret_cast<int>(node->nodePointer()) : 0; + return 0; } static bool nativeCursorWantsKeyEvents(JNIEnv* env, jobject jwebview) { - WebView* view = GET_NATIVE_VIEW(env, jwebview); - LOG_ASSERT(view, "view not set in %s", __FUNCTION__); - return view->cursorWantsKeyEvents(); + return false; } static void nativeHideCursor(JNIEnv *env, jobject obj) { - WebView* view = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(view, "view not set in %s", __FUNCTION__); - view->hideCursor(); -} - -static void nativeInstrumentReport(JNIEnv *env, jobject obj) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounter::reportNow(); -#endif } static void nativeSelectBestAt(JNIEnv *env, jobject obj, jobject jrect) { - WebView* view = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(view, "view not set in %s", __FUNCTION__); - WebCore::IntRect rect = jrect_to_webrect(env, jrect); - view->selectBestAt(rect); } static void nativeSelectAt(JNIEnv *env, jobject obj, jint x, jint y) { - WebView* view = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(view, "view not set in %s", __FUNCTION__); - WebCore::IntRect rect = IntRect(x, y , 1, 1); - view->selectBestAt(rect); - if (view->hasCursorNode()) - view->showCursorUntimed(); } static jobject nativeLayerBounds(JNIEnv* env, jobject obj, jint jlayer) @@ -2219,186 +1203,75 @@ static jobject nativeSubtractLayers(JNIEnv* env, jobject obj, jobject jrect) static jint nativeTextGeneration(JNIEnv *env, jobject obj) { - WebView* view = GET_NATIVE_VIEW(env, obj); - CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); - return root ? root->textGeneration() : 0; + return 0; } static bool nativePointInNavCache(JNIEnv *env, jobject obj, int x, int y, int slop) { - return GET_NATIVE_VIEW(env, obj)->pointInNavCache(x, y, slop); + return false; } static bool nativeMotionUp(JNIEnv *env, jobject obj, int x, int y, int slop) { - WebView* view = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(view, "view not set in %s", __FUNCTION__); - return view->motionUp(x, y, slop); + return false; } static bool nativeHasCursorNode(JNIEnv *env, jobject obj) { - return GET_NATIVE_VIEW(env, obj)->hasCursorNode(); + return false; } static bool nativeHasFocusNode(JNIEnv *env, jobject obj) { - return GET_NATIVE_VIEW(env, obj)->hasFocusNode(); + return false; } static bool nativeMoveCursor(JNIEnv *env, jobject obj, int key, int count, bool ignoreScroll) { - WebView* view = GET_NATIVE_VIEW(env, obj); - DBG_NAV_LOGD("env=%p obj=%p view=%p", env, obj, view); - LOG_ASSERT(view, "view not set in %s", __FUNCTION__); - return view->moveCursor(key, count, ignoreScroll); + return false; } static void nativeSetFindIsUp(JNIEnv *env, jobject obj, jboolean isUp) { WebView* view = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(view, "view not set in %s", __FUNCTION__); + ALOG_ASSERT(view, "view not set in %s", __FUNCTION__); view->setFindIsUp(isUp); } -static void nativeSetFindIsEmpty(JNIEnv *env, jobject obj) -{ - GET_NATIVE_VIEW(env, obj)->setFindIsEmpty(); -} - static void nativeShowCursorTimed(JNIEnv *env, jobject obj) { - GET_NATIVE_VIEW(env, obj)->showCursorTimed(); } static void nativeSetHeightCanMeasure(JNIEnv *env, jobject obj, bool measure) { WebView* view = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(view, "view not set in nativeSetHeightCanMeasure"); + ALOG_ASSERT(view, "view not set in nativeSetHeightCanMeasure"); view->setHeightCanMeasure(measure); } static jobject nativeGetCursorRingBounds(JNIEnv *env, jobject obj) { - WebView* view = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(view, "view not set in %s", __FUNCTION__); - jclass rectClass = env->FindClass("android/graphics/Rect"); - LOG_ASSERT(rectClass, "Could not find Rect class!"); - jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V"); - LOG_ASSERT(init, "Could not find constructor for Rect"); - WebCore::IntRect webRect; - view->cursorRingBounds(&webRect); - jobject rect = env->NewObject(rectClass, init, webRect.x(), - webRect.y(), webRect.maxX(), webRect.maxY()); - env->DeleteLocalRef(rectClass); - return rect; -} - -static int nativeFindAll(JNIEnv *env, jobject obj, jstring findLower, - jstring findUpper, jboolean sameAsLastSearch) -{ - // If one or the other is null, do not search. - if (!(findLower && findUpper)) - return 0; - // Obtain the characters for both the lower case string and the upper case - // string representing the same word. - const jchar* findLowerChars = env->GetStringChars(findLower, 0); - const jchar* findUpperChars = env->GetStringChars(findUpper, 0); - // If one or the other is null, do not search. - if (!(findLowerChars && findUpperChars)) { - if (findLowerChars) - env->ReleaseStringChars(findLower, findLowerChars); - if (findUpperChars) - env->ReleaseStringChars(findUpper, findUpperChars); - checkException(env); - return 0; - } - WebView* view = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(view, "view not set in nativeFindAll"); - CachedRoot* root = view->getFrameCache(WebView::AllowNewer); - if (!root) { - env->ReleaseStringChars(findLower, findLowerChars); - env->ReleaseStringChars(findUpper, findUpperChars); - checkException(env); - return 0; - } - int length = env->GetStringLength(findLower); - // If the lengths of the strings do not match, then they are not the same - // word, so do not search. - if (!length || env->GetStringLength(findUpper) != length) { - env->ReleaseStringChars(findLower, findLowerChars); - env->ReleaseStringChars(findUpper, findUpperChars); - checkException(env); - return 0; - } - int width = root->documentWidth(); - int height = root->documentHeight(); - // Create a FindCanvas, which allows us to fake draw into it so we can - // figure out where our search string is rendered (and how many times). - FindCanvas canvas(width, height, (const UChar*) findLowerChars, - (const UChar*) findUpperChars, length << 1); - SkBitmap bitmap; - bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height); - canvas.setBitmapDevice(bitmap); - root->draw(canvas); - WTF::Vector<MatchInfo>* matches = canvas.detachMatches(); - // With setMatches, the WebView takes ownership of matches - view->setMatches(matches, sameAsLastSearch); - - env->ReleaseStringChars(findLower, findLowerChars); - env->ReleaseStringChars(findUpper, findUpperChars); - checkException(env); - return canvas.found(); -} - -static void nativeFindNext(JNIEnv *env, jobject obj, bool forward) -{ - WebView* view = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(view, "view not set in nativeFindNext"); - view->findNext(forward); -} - -static int nativeFindIndex(JNIEnv *env, jobject obj) -{ - WebView* view = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(view, "view not set in nativeFindIndex"); - return view->currentMatchIndex(); + return 0; } static void nativeUpdateCachedTextfield(JNIEnv *env, jobject obj, jstring updatedText, jint generation) { - WebView* view = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(view, "view not set in nativeUpdateCachedTextfield"); - CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); - if (!root) - return; - const CachedNode* cachedFocusNode = root->currentFocus(); - if (!cachedFocusNode || !cachedFocusNode->isTextInput()) - return; - WTF::String webcoreString = jstringToWtfString(env, updatedText); - (const_cast<CachedNode*>(cachedFocusNode))->setExport(webcoreString); - root->setTextGeneration(generation); - checkException(env); } static jint nativeGetBlockLeftEdge(JNIEnv *env, jobject obj, jint x, jint y, jfloat scale) { - WebView* view = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(view, "view not set in %s", __FUNCTION__); - if (!view) - return -1; - return view->getBlockLeftEdge(x, y, scale); + return -1; } static void nativeDestroy(JNIEnv *env, jobject obj) { WebView* view = GET_NATIVE_VIEW(env, obj); - LOGD("nativeDestroy view: %p", view); - LOG_ASSERT(view, "view not set in nativeDestroy"); + ALOGD("nativeDestroy view: %p", view); + ALOG_ASSERT(view, "view not set in nativeDestroy"); delete view; } @@ -2409,31 +1282,7 @@ static void nativeStopGL(JNIEnv *env, jobject obj) static bool nativeMoveCursorToNextTextInput(JNIEnv *env, jobject obj) { - WebView* view = GET_NATIVE_VIEW(env, obj); - CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); - if (!root) - return false; - const CachedNode* current = root->currentCursor(); - if (!current || !current->isTextInput()) - current = root->currentFocus(); - if (!current || !current->isTextInput()) - return false; - const CachedFrame* frame; - const CachedNode* next = root->nextTextField(current, &frame); - if (!next) - return false; - const WebCore::IntRect& bounds = next->bounds(frame); - root->rootHistory()->setMouseBounds(bounds); - view->getWebViewCore()->updateCursorBounds(root, frame, next); - view->showCursorUntimed(); - root->setCursor(const_cast<CachedFrame*>(frame), - const_cast<CachedNode*>(next)); - view->sendMoveFocus(static_cast<WebCore::Frame*>(frame->framePointer()), - static_cast<WebCore::Node*>(next->nodePointer())); - if (!next->isInLayer()) - view->scrollRectOnScreen(bounds); - view->getWebViewCore()->m_moveGeneration++; - return true; + return false; } static int nativeMoveGeneration(JNIEnv *env, jobject obj) @@ -2444,83 +1293,19 @@ static int nativeMoveGeneration(JNIEnv *env, jobject obj) return view->moveGeneration(); } -static void nativeMoveSelection(JNIEnv *env, jobject obj, int x, int y) -{ - GET_NATIVE_VIEW(env, obj)->moveSelection(x, y); -} - -static void nativeResetSelection(JNIEnv *env, jobject obj) -{ - return GET_NATIVE_VIEW(env, obj)->resetSelection(); -} - -static jobject nativeSelectableText(JNIEnv* env, jobject obj) -{ - IntPoint pos = GET_NATIVE_VIEW(env, obj)->selectableText(); - jclass pointClass = env->FindClass("android/graphics/Point"); - jmethodID init = env->GetMethodID(pointClass, "<init>", "(II)V"); - jobject point = env->NewObject(pointClass, init, pos.x(), pos.y()); - env->DeleteLocalRef(pointClass); - return point; -} - -static void nativeSelectAll(JNIEnv* env, jobject obj) -{ - GET_NATIVE_VIEW(env, obj)->selectAll(); -} - -static void nativeSetExtendSelection(JNIEnv *env, jobject obj) -{ - GET_NATIVE_VIEW(env, obj)->setExtendSelection(); -} - -static jboolean nativeStartSelection(JNIEnv *env, jobject obj, int x, int y) -{ - return GET_NATIVE_VIEW(env, obj)->startSelection(x, y); -} - -static jboolean nativeWordSelection(JNIEnv *env, jobject obj, int x, int y) -{ - return GET_NATIVE_VIEW(env, obj)->wordSelection(x, y); -} - -static void nativeExtendSelection(JNIEnv *env, jobject obj, int x, int y) -{ - GET_NATIVE_VIEW(env, obj)->extendSelection(x, y); -} - static jobject nativeGetSelection(JNIEnv *env, jobject obj) { WebView* view = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(view, "view not set in %s", __FUNCTION__); + ALOG_ASSERT(view, "view not set in %s", __FUNCTION__); String selection = view->getSelection(); return wtfStringToJstring(env, selection); } -static jboolean nativeHitSelection(JNIEnv *env, jobject obj, int x, int y) -{ - return GET_NATIVE_VIEW(env, obj)->hitSelection(x, y); -} - -static jint nativeSelectionX(JNIEnv *env, jobject obj) -{ - return GET_NATIVE_VIEW(env, obj)->selectionX(); -} - -static jint nativeSelectionY(JNIEnv *env, jobject obj) -{ - return GET_NATIVE_VIEW(env, obj)->selectionY(); -} - -static void nativeSetSelectionPointer(JNIEnv *env, jobject obj, jint nativeView, - jboolean set, jfloat scale, jint x, jint y) +static void nativeDiscardAllTextures(JNIEnv *env, jobject obj) { - ((WebView*)nativeView)->setSelectionPointer(set, scale, x, y); -} - -static void nativeRegisterPageSwapCallback(JNIEnv *env, jobject obj) -{ - GET_NATIVE_VIEW(env, obj)->registerPageSwapCallback(); + //discard all textures for debugging/test purposes, but not gl backing memory + bool allTextures = true, deleteGLTextures = false; + TilesManager::instance()->discardTextures(allTextures, deleteGLTextures); } static void nativeTileProfilingStart(JNIEnv *env, jobject obj) @@ -2586,10 +1371,8 @@ static bool nativeSetProperty(JNIEnv *env, jobject obj, jstring jkey, jstring jv WTF::String key = jstringToWtfString(env, jkey); WTF::String value = jstringToWtfString(env, jvalue); if (key == "inverted") { - if (value == "true") - TilesManager::instance()->setInvertedScreen(true); - else - TilesManager::instance()->setInvertedScreen(false); + bool shouldInvert = (value == "true"); + TilesManager::instance()->setInvertedScreen(shouldInvert); return true; } else if (key == "inverted_contrast") { @@ -2606,19 +1389,43 @@ static bool nativeSetProperty(JNIEnv *env, jobject obj, jstring jkey, jstring jv TilesManager::instance()->setUseMinimalMemory(value == "true"); return true; } + else if (key == "use_double_buffering") { + TilesManager::instance()->setUseDoubleBuffering(value == "true"); + return true; + } + else if (key == "tree_updates") { + TilesManager::instance()->clearTreeUpdates(); + return true; + } return false; } -static jstring nativeGetProperty(JNIEnv *env, jobject obj, jstring key) +static jstring nativeGetProperty(JNIEnv *env, jobject obj, jstring jkey) { + WTF::String key = jstringToWtfString(env, jkey); + if (key == "tree_updates") { + int updates = TilesManager::instance()->getTreeUpdates(); + WTF::String wtfUpdates = WTF::String::number(updates); + return wtfStringToJstring(env, wtfUpdates); + } return 0; } static void nativeOnTrimMemory(JNIEnv *env, jobject obj, jint level) { if (TilesManager::hardwareAccelerationEnabled()) { - bool freeAllTextures = (level > TRIM_MEMORY_UI_HIDDEN); - TilesManager::instance()->deallocateTextures(freeAllTextures); + // When we got TRIM_MEMORY_MODERATE or TRIM_MEMORY_COMPLETE, we should + // make sure the transfer queue is empty and then abandon the Surface + // Texture to avoid ANR b/c framework may destroy the EGL context. + // Refer to WindowManagerImpl.java for conditions we followed. + if (level >= TRIM_MEMORY_MODERATE + && !TilesManager::instance()->highEndGfx()) { + TilesManager::instance()->transferQueue()->emptyQueue(); + TilesManager::instance()->setContextChanged(true); + } + + bool freeAllTextures = (level > TRIM_MEMORY_UI_HIDDEN), glTextures = true; + TilesManager::instance()->discardTextures(freeAllTextures, glTextures); } } @@ -2626,7 +1433,7 @@ static void nativeDumpDisplayTree(JNIEnv* env, jobject jwebview, jstring jurl) { #ifdef ANDROID_DUMP_DISPLAY_TREE WebView* view = GET_NATIVE_VIEW(env, jwebview); - LOG_ASSERT(view, "view not set in %s", __FUNCTION__); + ALOG_ASSERT(view, "view not set in %s", __FUNCTION__); if (view && view->getWebViewCore()) { FILE* file = fopen(DISPLAY_TREE_LOG_FILE, "w"); @@ -2643,7 +1450,7 @@ static void nativeDumpDisplayTree(JNIEnv* env, jobject jwebview, jstring jurl) SkDumpCanvas canvas(&dumper); // this will playback the picture into the canvas, which will // spew its contents to the dumper - view->draw(&canvas, 0, 0, false); + view->draw(&canvas, 0, WebView::DrawExtrasNone, false); // we're done with the file now fwrite("\n", 1, 1, file); fclose(file); @@ -2666,7 +1473,7 @@ static int nativeScrollableLayer(JNIEnv* env, jobject jwebview, jint x, jint y, jobject rect, jobject bounds) { WebView* view = GET_NATIVE_VIEW(env, jwebview); - LOG_ASSERT(view, "view not set in %s", __FUNCTION__); + ALOG_ASSERT(view, "view not set in %s", __FUNCTION__); SkIRect nativeRect, nativeBounds; int id = view->scrollableLayer(x, y, &nativeRect, &nativeBounds); if (rect) @@ -2698,7 +1505,7 @@ static bool nativeScrollLayer(JNIEnv* env, jobject obj, jint layerId, jint x, static void nativeSetIsScrolling(JNIEnv* env, jobject jwebview, jboolean isScrolling) { WebView* view = GET_NATIVE_VIEW(env, jwebview); - LOG_ASSERT(view, "view not set in %s", __FUNCTION__); + ALOG_ASSERT(view, "view not set in %s", __FUNCTION__); view->setIsScrolling(isScrolling); } @@ -2726,6 +1533,37 @@ static void nativeSetPauseDrawing(JNIEnv *env, jobject obj, jint nativeView, ((WebView*)nativeView)->m_isDrawingPaused = pause; } +static bool nativeDisableNavcache(JNIEnv *env, jobject obj) +{ + return true; +} + +static void nativeSetTextSelection(JNIEnv *env, jobject obj, jint nativeView, + jint selectionPtr) +{ + SelectText* selection = reinterpret_cast<SelectText*>(selectionPtr); + reinterpret_cast<WebView*>(nativeView)->setTextSelection(selection); +} + +static jint nativeGetHandleLayerId(JNIEnv *env, jobject obj, jint nativeView, + jint handleIndex, jobject cursorRect) +{ + WebView* webview = reinterpret_cast<WebView*>(nativeView); + SkIRect nativeRect; + int layerId = webview->getHandleLayerId((SelectText::HandleId) handleIndex, nativeRect); + if (cursorRect) + GraphicsJNI::irect_to_jrect(nativeRect, env, cursorRect); + return layerId; +} + +static jboolean nativeIsBaseFirst(JNIEnv *env, jobject obj, jint nativeView) +{ + WebView* webview = reinterpret_cast<WebView*>(nativeView); + SelectText* select = static_cast<SelectText*>( + webview->getDrawExtra(WebView::DrawExtrasSelection)); + return select ? select->isBaseFirst() : false; +} + /* * JNI registration */ @@ -2770,20 +1608,12 @@ static JNINativeMethod gJavaWebViewMethods[] = { (void*) nativeDraw }, { "nativeGetDrawGLFunction", "(ILandroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/RectF;FI)I", (void*) nativeGetDrawGLFunction }, - { "nativeUpdateDrawGLFunction", "(Landroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/RectF;)V", + { "nativeUpdateDrawGLFunction", "(Landroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/RectF;F)V", (void*) nativeUpdateDrawGLFunction }, { "nativeDumpDisplayTree", "(Ljava/lang/String;)V", (void*) nativeDumpDisplayTree }, { "nativeEvaluateLayersAnimations", "(I)Z", (void*) nativeEvaluateLayersAnimations }, - { "nativeExtendSelection", "(II)V", - (void*) nativeExtendSelection }, - { "nativeFindAll", "(Ljava/lang/String;Ljava/lang/String;Z)I", - (void*) nativeFindAll }, - { "nativeFindNext", "(Z)V", - (void*) nativeFindNext }, - { "nativeFindIndex", "()I", - (void*) nativeFindIndex}, { "nativeFocusCandidateFramePointer", "()I", (void*) nativeFocusCandidateFramePointer }, { "nativeFocusCandidateHasNextTextfield", "()Z", @@ -2834,12 +1664,8 @@ static JNINativeMethod gJavaWebViewMethods[] = { (void*) nativeHasFocusNode }, { "nativeHideCursor", "()V", (void*) nativeHideCursor }, - { "nativeHitSelection", "(II)Z", - (void*) nativeHitSelection }, { "nativeImageURI", "(II)Ljava/lang/String;", (void*) nativeImageURI }, - { "nativeInstrumentReport", "()V", - (void*) nativeInstrumentReport }, { "nativeLayerBounds", "(I)Landroid/graphics/Rect;", (void*) nativeLayerBounds }, { "nativeMotionUp", "(III)Z", @@ -2850,38 +1676,18 @@ static JNINativeMethod gJavaWebViewMethods[] = { (void*) nativeMoveCursorToNextTextInput }, { "nativeMoveGeneration", "()I", (void*) nativeMoveGeneration }, - { "nativeMoveSelection", "(II)V", - (void*) nativeMoveSelection }, { "nativePointInNavCache", "(III)Z", (void*) nativePointInNavCache }, - { "nativeResetSelection", "()V", - (void*) nativeResetSelection }, - { "nativeSelectableText", "()Landroid/graphics/Point;", - (void*) nativeSelectableText }, - { "nativeSelectAll", "()V", - (void*) nativeSelectAll }, { "nativeSelectBestAt", "(Landroid/graphics/Rect;)V", (void*) nativeSelectBestAt }, { "nativeSelectAt", "(II)V", (void*) nativeSelectAt }, - { "nativeSelectionX", "()I", - (void*) nativeSelectionX }, - { "nativeSelectionY", "()I", - (void*) nativeSelectionY }, - { "nativeSetExtendSelection", "()V", - (void*) nativeSetExtendSelection }, - { "nativeSetFindIsEmpty", "()V", - (void*) nativeSetFindIsEmpty }, { "nativeSetFindIsUp", "(Z)V", (void*) nativeSetFindIsUp }, { "nativeSetHeightCanMeasure", "(Z)V", (void*) nativeSetHeightCanMeasure }, - { "nativeSetBaseLayer", "(ILandroid/graphics/Region;ZZZ)V", + { "nativeSetBaseLayer", "(IILandroid/graphics/Region;ZZ)Z", (void*) nativeSetBaseLayer }, - { "nativeGetTextSelectionRegion", "(ILandroid/graphics/Region;)V", - (void*) nativeGetTextSelectionRegion }, - { "nativeGetSelectionHandles", "(I[I)V", - (void*) nativeGetSelectionHandles }, { "nativeGetBaseLayer", "()I", (void*) nativeGetBaseLayer }, { "nativeReplaceBaseContent", "(I)V", @@ -2890,12 +1696,10 @@ static JNINativeMethod gJavaWebViewMethods[] = { (void*) nativeCopyBaseContentToPicture }, { "nativeHasContent", "()Z", (void*) nativeHasContent }, - { "nativeSetSelectionPointer", "(IZFII)V", - (void*) nativeSetSelectionPointer }, { "nativeShowCursorTimed", "()V", (void*) nativeShowCursorTimed }, - { "nativeRegisterPageSwapCallback", "()V", - (void*) nativeRegisterPageSwapCallback }, + { "nativeDiscardAllTextures", "()V", + (void*) nativeDiscardAllTextures }, { "nativeTileProfilingStart", "()V", (void*) nativeTileProfilingStart }, { "nativeTileProfilingStop", "()F", @@ -2910,8 +1714,6 @@ static JNINativeMethod gJavaWebViewMethods[] = { (void*) nativeTileProfilingGetInt }, { "nativeTileProfilingGetFloat", "(IILjava/lang/String;)F", (void*) nativeTileProfilingGetFloat }, - { "nativeStartSelection", "(II)Z", - (void*) nativeStartSelection }, { "nativeStopGL", "()V", (void*) nativeStopGL }, { "nativeSubtractLayers", "(Landroid/graphics/Rect;)Landroid/graphics/Rect;", @@ -2920,8 +1722,6 @@ static JNINativeMethod gJavaWebViewMethods[] = { (void*) nativeTextGeneration }, { "nativeUpdateCachedTextfield", "(Ljava/lang/String;I)V", (void*) nativeUpdateCachedTextfield }, - { "nativeWordSelection", "(II)Z", - (void*) nativeWordSelection }, { "nativeGetBlockLeftEdge", "(IIF)I", (void*) nativeGetBlockLeftEdge }, { "nativeScrollableLayer", "(IILandroid/graphics/Rect;Landroid/graphics/Rect;)I", @@ -2942,14 +1742,24 @@ static JNINativeMethod gJavaWebViewMethods[] = { (void*) nativeOnTrimMemory }, { "nativeSetPauseDrawing", "(IZ)V", (void*) nativeSetPauseDrawing }, + { "nativeDisableNavcache", "()Z", + (void*) nativeDisableNavcache }, + { "nativeFocusCandidateIsEditableText", "(I)Z", + (void*) nativeFocusCandidateIsEditableText }, + { "nativeSetTextSelection", "(II)V", + (void*) nativeSetTextSelection }, + { "nativeGetHandleLayerId", "(IILandroid/graphics/Rect;)I", + (void*) nativeGetHandleLayerId }, + { "nativeIsBaseFirst", "(I)Z", + (void*) nativeIsBaseFirst }, }; int registerWebView(JNIEnv* env) { jclass clazz = env->FindClass("android/webkit/WebView"); - LOG_ASSERT(clazz, "Unable to find class android/webkit/WebView"); + ALOG_ASSERT(clazz, "Unable to find class android/webkit/WebView"); gWebViewField = env->GetFieldID(clazz, "mNativeClass", "I"); - LOG_ASSERT(gWebViewField, "Unable to find android/webkit/WebView.mNativeClass"); + ALOG_ASSERT(gWebViewField, "Unable to find android/webkit/WebView.mNativeClass"); env->DeleteLocalRef(clazz); return jniRegisterNativeMethods(env, "android/webkit/WebView", gJavaWebViewMethods, NELEM(gJavaWebViewMethods)); diff --git a/Source/WebKit/android/plugins/ANPSoundInterface.cpp b/Source/WebKit/android/plugins/ANPSoundInterface.cpp index c238872..12c9176 100644 --- a/Source/WebKit/android/plugins/ANPSoundInterface.cpp +++ b/Source/WebKit/android/plugins/ANPSoundInterface.cpp @@ -38,7 +38,7 @@ struct ANPAudioTrack { android::AudioTrack* mTrack; }; -static ANPSampleFormat toANPFormat(int fm) { +static ANPSampleFormat toANPFormat(audio_format_t fm) { switch (fm) { case AUDIO_FORMAT_PCM_16_BIT: return kPCM16Bit_ANPSampleFormat; @@ -49,7 +49,7 @@ static ANPSampleFormat toANPFormat(int fm) { } } -static int fromANPFormat(ANPSampleFormat fm) { +static audio_format_t fromANPFormat(ANPSampleFormat fm) { switch (fm) { case kPCM16Bit_ANPSampleFormat: return AUDIO_FORMAT_PCM_16_BIT; @@ -71,7 +71,7 @@ static void callbackProc(int event, void* user, void* info) { src = reinterpret_cast<android::AudioTrack::Buffer*>(info); dst.bufferData = src->raw; dst.channelCount = src->channelCount; - dst.format = toANPFormat(src->format); + dst.format = toANPFormat((audio_format_t) src->format); dst.size = src->size; track->mProc(kMoreData_ANPAudioEvent, track->mUser, &dst); // return the updated size field 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/android/plugins/PluginWidgetAndroid.cpp b/Source/WebKit/android/plugins/PluginWidgetAndroid.cpp index fc98837..d0af1a5 100644 --- a/Source/WebKit/android/plugins/PluginWidgetAndroid.cpp +++ b/Source/WebKit/android/plugins/PluginWidgetAndroid.cpp @@ -596,9 +596,9 @@ void PluginWidgetAndroid::scrollToVisiblePluginRect() { android::WebViewCore* core = android::WebViewCore::getWebViewCore(scrollView); #if DEBUG_VISIBLE_RECTS PLUGIN_LOG("%s call scrollTo (%d,%d) to center (%d,%d)", __FUNCTION__, - scrollDocX, scrollDocX, rectCenterX, rectCenterY); + scrollDocX, scrollDocY, rectCenterX, rectCenterY); #endif - core->scrollTo(scrollDocX, scrollDocX, true); + core->scrollTo(scrollDocX, scrollDocY, true); } void PluginWidgetAndroid::requestFullScreen() { diff --git a/Source/WebKit/android/smoke/MessageThread.cpp b/Source/WebKit/android/smoke/MessageThread.cpp index 48f2222..97ab18c 100644 --- a/Source/WebKit/android/smoke/MessageThread.cpp +++ b/Source/WebKit/android/smoke/MessageThread.cpp @@ -79,7 +79,7 @@ void MessageQueue::post(Message* message) { AutoMutex lock(m_mutex); double when = message->m_when; - LOG_ASSERT(when > 0, "Message time may not be 0"); + ALOG_ASSERT(when > 0, "Message time may not be 0"); list<Message*>::iterator it; for (it = m_messages.begin(); it != m_messages.end(); ++it) { diff --git a/Source/WebKit/android/wds/Command.cpp b/Source/WebKit/android/wds/Command.cpp index bd8536f..1a365e5 100644 --- a/Source/WebKit/android/wds/Command.cpp +++ b/Source/WebKit/android/wds/Command.cpp @@ -95,7 +95,7 @@ public: virtual ~InternalCommand() { delete m_connection; } void doCommand() const { - LOGD("Executing command '%s' (%s)", m_name, m_description); + ALOGD("Executing command '%s' (%s)", m_name, m_description); if (!m_dispatch(m_frame, m_connection)) // XXX: Have useful failure messages m_connection->write("EPIC FAIL!\n", 11); diff --git a/Source/WebKit/android/wds/Connection.cpp b/Source/WebKit/android/wds/Connection.cpp index d7e55ac..52193e5 100644 --- a/Source/WebKit/android/wds/Connection.cpp +++ b/Source/WebKit/android/wds/Connection.cpp @@ -35,7 +35,7 @@ #if ENABLE(WDS) #define MAX_CONNECTION_QUEUE 5 -#define log_errno(x) LOGE("%s: %d", x, strerror(errno)) +#define log_errno(x) ALOGE("%s: %d", x, strerror(errno)) namespace android { diff --git a/Source/WebKit/android/wds/DebugServer.cpp b/Source/WebKit/android/wds/DebugServer.cpp index f33a65b..2fde6bd 100644 --- a/Source/WebKit/android/wds/DebugServer.cpp +++ b/Source/WebKit/android/wds/DebugServer.cpp @@ -42,7 +42,7 @@ #if ENABLE(WDS) #define DEFAULT_PORT 9999 -#define log_errno(x) LOGE("%s: %d", x, strerror(errno)) +#define log_errno(x) ALOGE("%s: %d", x, strerror(errno)) namespace android { @@ -70,7 +70,7 @@ DebugServer::DebugServer() { char buf[PROPERTY_VALUE_MAX]; int ret = property_get("webcore.wds.enable", buf, NULL); if (ret != -1 && strcmp(buf, "1") == 0) { - LOGD("WDS Enabled"); + ALOGD("WDS Enabled"); m_threadId = createThread(mainThread, this, "WDS"); } // Initialize the available commands. @@ -78,26 +78,26 @@ DebugServer::DebugServer() { } void DebugServer::start() { - LOGD("DebugServer thread started"); + ALOGD("DebugServer thread started"); ConnectionServer cs; if (!cs.connect(DEFAULT_PORT)) { - LOGE("Failed to start the server socket connection"); + ALOGE("Failed to start the server socket connection"); return; } while (true ) { - LOGD("Waiting for incoming connections..."); + ALOGD("Waiting for incoming connections..."); Connection* conn = cs.accept(); if (!conn) { log_errno("Failed to accept new connections"); return; } - LOGD("...Connection established"); + ALOGD("...Connection established"); Command* c = Command::Find(conn); if (!c) { - LOGE("Could not find matching command"); + ALOGE("Could not find matching command"); delete conn; } else { // Dispatch the command, it will handle cleaning up the connection @@ -106,7 +106,7 @@ void DebugServer::start() { } } - LOGD("DebugServer thread finished"); + ALOGD("DebugServer thread finished"); } } // end namespace WDS diff --git a/Source/WebKit/android/wds/client/AdbConnection.cpp b/Source/WebKit/android/wds/client/AdbConnection.cpp index 465f9c3..7d02ecc 100644 --- a/Source/WebKit/android/wds/client/AdbConnection.cpp +++ b/Source/WebKit/android/wds/client/AdbConnection.cpp @@ -78,7 +78,7 @@ bool AdbConnection::connect() { bool AdbConnection::sendRequest(const char* fmt, ...) const { if (m_fd == -1) { - LOGE("Connection is closed"); + ALOGE("Connection is closed"); return false; } @@ -89,7 +89,7 @@ bool AdbConnection::sendRequest(const char* fmt, ...) const { int res = vsnprintf(buf, MAX_COMMAND_LENGTH, fmt, args); va_end(args); - LOGV("Sending command: %04X%.*s", res, res, buf); + ALOGV("Sending command: %04X%.*s", res, res, buf); // Construct the payload length char payloadLen[PAYLOAD_LENGTH + 1]; @@ -115,7 +115,7 @@ static void printFailureMessage(int fd) { // Grab the payload length char lenStr[PAYLOAD_LENGTH + 1]; int payloadLen = recv(fd, lenStr, sizeof(lenStr) - 1, 0); - LOG_ASSERT(payloadLen == PAYLOAD_LENGTH, "Incorrect payload size"); + ALOG_ASSERT(payloadLen == PAYLOAD_LENGTH, "Incorrect payload size"); lenStr[PAYLOAD_LENGTH] = 0; // Parse the hex payload @@ -130,13 +130,13 @@ static void printFailureMessage(int fd) { log_errno("Failure reading failure message from adb"); return; } else if (res != payloadLen) { - LOGE("Incorrect payload length %d - expected %d", res, payloadLen); + ALOGE("Incorrect payload length %d - expected %d", res, payloadLen); return; } msg[res] = 0; // Tell somebody about it - LOGE("Received failure from adb: %s", msg); + ALOGE("Received failure from adb: %s", msg); // Cleanup delete[] msg; @@ -145,7 +145,7 @@ static void printFailureMessage(int fd) { #define ADB_RESPONSE_LENGTH 4 bool AdbConnection::checkOkayResponse() const { - LOG_ASSERT(m_fd != -1, "Connection has been closed!"); + ALOG_ASSERT(m_fd != -1, "Connection has been closed!"); char buf[ADB_RESPONSE_LENGTH]; int res = recv(m_fd, buf, sizeof(buf), 0); @@ -156,14 +156,14 @@ bool AdbConnection::checkOkayResponse() const { // Check for a response other than OKAY/FAIL if ((res == ADB_RESPONSE_LENGTH) && (strncmp(buf, "OKAY", res) == 0)) { - LOGV("Command OKAY"); + ALOGV("Command OKAY"); return true; } else if (strncmp(buf, "FAIL", ADB_RESPONSE_LENGTH) == 0) { // Something happened, print out the reason for failure printFailureMessage(m_fd); return false; } - LOGE("Incorrect response from adb - '%.*s'", res, buf); + ALOGE("Incorrect response from adb - '%.*s'", res, buf); return false; } @@ -178,13 +178,13 @@ const DeviceList& AdbConnection::getDeviceList() { clearDevices(); if (m_fd == -1) { - LOGE("Connection is closed"); + ALOGE("Connection is closed"); return m_devices; } // Try to send the device list request if (!sendRequest("host:devices")) { - LOGE("Failed to get device list from adb"); + ALOGE("Failed to get device list from adb"); return m_devices; } @@ -210,7 +210,7 @@ const DeviceList& AdbConnection::getDeviceList() { log_errno("Failure reading the device list"); return m_devices; } else if (res != payloadLen) { - LOGE("Incorrect payload length %d - expected %d", res, payloadLen); + ALOGE("Incorrect payload length %d - expected %d", res, payloadLen); return m_devices; } msg[res] = 0; @@ -224,7 +224,7 @@ const DeviceList& AdbConnection::getDeviceList() { static const char emulator[] = "emulator-"; if (strncmp(serial, emulator, sizeof(emulator) - 1) == 0) t = Device::EMULATOR; - LOGV("Adding device %s (%s)", serial, state); + ALOGV("Adding device %s (%s)", serial, state); m_devices.add(new Device(serial, t, this)); // Reset for the next line diff --git a/Source/WebKit/android/wds/client/ClientUtils.h b/Source/WebKit/android/wds/client/ClientUtils.h index 7d0db30..7c4b9ce 100644 --- a/Source/WebKit/android/wds/client/ClientUtils.h +++ b/Source/WebKit/android/wds/client/ClientUtils.h @@ -37,7 +37,7 @@ #endif // Callers need to include Log.h and errno.h to use this macro -#define log_errno(str) LOGE("%s: %s", str, strerror(errno)) +#define log_errno(str) ALOGE("%s: %s", str, strerror(errno)) // Fill in the sockaddr_in structure for binding to the localhost on the given // port diff --git a/Source/WebKit/android/wds/client/main.cpp b/Source/WebKit/android/wds/client/main.cpp index 1c7d856..276affe 100644 --- a/Source/WebKit/android/wds/client/main.cpp +++ b/Source/WebKit/android/wds/client/main.cpp @@ -74,7 +74,7 @@ int main(int argc, char** argv) { Device::DeviceType type = Device::NONE; if (argc <= 1) { - LOGE("wdsclient takes at least 1 argument"); + ALOGE("wdsclient takes at least 1 argument"); return 1; } else { // Parse the options, look for -e or -d to choose a device. @@ -94,7 +94,7 @@ int main(int argc, char** argv) { } } if (optind == argc) { - LOGE("No command specified"); + ALOGE("No command specified"); return 1; } } @@ -109,10 +109,10 @@ int main(int argc, char** argv) { // No device specified and more than one connected, bail if (type == Device::NONE && devices.size() > 1) { - LOGE("More than one device/emulator, please specify with -e or -d"); + ALOGE("More than one device/emulator, please specify with -e or -d"); return 1; } else if (devices.size() == 0) { - LOGE("No devices connected"); + ALOGE("No devices connected"); return 1; } @@ -131,23 +131,23 @@ int main(int argc, char** argv) { } if (!device) { - LOGE("No device found!"); + ALOGE("No device found!"); return 1; } // Forward tcp:9999 if (!device->sendRequest("forward:tcp:" PORT_STR ";tcp:" PORT_STR)) { - LOGE("Failed to send forwarding request"); + ALOGE("Failed to send forwarding request"); return 1; } - LOGV("Connecting to localhost port " PORT_STR); + ALOGV("Connecting to localhost port " PORT_STR); const char* command = argv[optind]; int commandLen = strlen(command); #define WDS_COMMAND_LENGTH 4 if (commandLen != WDS_COMMAND_LENGTH) { - LOGE("Commands must be 4 characters '%s'", command); + ALOGE("Commands must be 4 characters '%s'", command); return 1; } 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 |