From a2c606d1d8312a5d063e4a11e5911d9c8e4a3d19 Mon Sep 17 00:00:00 2001 From: Ben Murdoch Date: Fri, 13 May 2011 16:40:46 +0100 Subject: Merge WebKit at r75993: Move WebKit/android files to Source Change-Id: Ifa871f8320bdb3a09fe189fffecc23f702c394b9 --- Source/WebKit/Android.mk | 132 + Source/WebKit/android/AndroidLog.h | 48 + Source/WebKit/android/JavaVM/jni.h | 32 + Source/WebKit/android/RenderSkinAndroid.cpp | 73 + Source/WebKit/android/RenderSkinAndroid.h | 74 + Source/WebKit/android/RenderSkinButton.cpp | 90 + Source/WebKit/android/RenderSkinButton.h | 55 + Source/WebKit/android/RenderSkinCombo.cpp | 146 + Source/WebKit/android/RenderSkinCombo.h | 69 + Source/WebKit/android/RenderSkinMediaButton.cpp | 215 + Source/WebKit/android/RenderSkinMediaButton.h | 63 + Source/WebKit/android/RenderSkinNinePatch.cpp | 89 + Source/WebKit/android/RenderSkinNinePatch.h | 48 + Source/WebKit/android/RenderSkinRadio.cpp | 100 + Source/WebKit/android/RenderSkinRadio.h | 61 + Source/WebKit/android/TimeCounter.cpp | 198 + Source/WebKit/android/TimeCounter.h | 120 + Source/WebKit/android/TimerClient.h | 42 + .../WebKit/android/WebCoreSupport/CacheResult.cpp | 251 ++ Source/WebKit/android/WebCoreSupport/CacheResult.h | 86 + .../CachedFramePlatformDataAndroid.cpp | 66 + .../CachedFramePlatformDataAndroid.h | 63 + .../android/WebCoreSupport/ChromeClientAndroid.cpp | 605 +++ .../android/WebCoreSupport/ChromeClientAndroid.h | 216 + .../android/WebCoreSupport/ChromiumIncludes.h | 104 + .../WebKit/android/WebCoreSupport/ChromiumInit.cpp | 74 + .../WebKit/android/WebCoreSupport/ChromiumInit.h | 38 + .../WebCoreSupport/ContextMenuClientAndroid.cpp | 51 + .../WebCoreSupport/ContextMenuClientAndroid.h | 51 + .../WebKit/android/WebCoreSupport/CookieClient.h | 46 + .../WebCoreSupport/DeviceMotionClientAndroid.cpp | 84 + .../WebCoreSupport/DeviceMotionClientAndroid.h | 65 + .../DeviceOrientationClientAndroid.cpp | 84 + .../DeviceOrientationClientAndroid.h | 65 + .../android/WebCoreSupport/DragClientAndroid.cpp | 46 + .../android/WebCoreSupport/DragClientAndroid.h | 51 + .../android/WebCoreSupport/EditorClientAndroid.cpp | 280 ++ .../android/WebCoreSupport/EditorClientAndroid.h | 135 + .../android/WebCoreSupport/FileSystemClient.h | 41 + .../WebCoreSupport/FrameLoaderClientAndroid.cpp | 1351 ++++++ .../WebCoreSupport/FrameLoaderClientAndroid.h | 271 ++ .../FrameNetworkingContextAndroid.cpp | 52 + .../WebCoreSupport/FrameNetworkingContextAndroid.h | 54 + .../WebCoreSupport/GeolocationPermissions.cpp | 419 ++ .../WebCoreSupport/GeolocationPermissions.h | 178 + .../WebCoreSupport/InspectorClientAndroid.h | 54 + .../android/WebCoreSupport/KeyGeneratorClient.h | 46 + .../WebCoreSupport/MediaPlayerPrivateAndroid.cpp | 654 +++ .../WebKit/android/WebCoreSupport/MemoryUsage.cpp | 81 + Source/WebKit/android/WebCoreSupport/MemoryUsage.h | 45 + .../android/WebCoreSupport/PlatformBridge.cpp | 261 ++ .../WebCoreSupport/ResourceLoaderAndroid.cpp | 71 + .../WebCoreSupport/UrlInterceptResponse.cpp | 130 + .../android/WebCoreSupport/UrlInterceptResponse.h | 70 + .../WebKit/android/WebCoreSupport/V8Counters.cpp | 116 + Source/WebKit/android/WebCoreSupport/V8Counters.h | 77 + Source/WebKit/android/WebCoreSupport/WebCache.cpp | 237 + Source/WebKit/android/WebCoreSupport/WebCache.h | 88 + .../WebKit/android/WebCoreSupport/WebCookieJar.cpp | 263 ++ .../WebKit/android/WebCoreSupport/WebCookieJar.h | 78 + .../WebKit/android/WebCoreSupport/WebRequest.cpp | 531 +++ Source/WebKit/android/WebCoreSupport/WebRequest.h | 125 + .../android/WebCoreSupport/WebRequestContext.cpp | 130 + .../android/WebCoreSupport/WebRequestContext.h | 64 + .../android/WebCoreSupport/WebResourceRequest.cpp | 96 + .../android/WebCoreSupport/WebResourceRequest.h | 86 + .../WebKit/android/WebCoreSupport/WebResponse.cpp | 167 + Source/WebKit/android/WebCoreSupport/WebResponse.h | 91 + .../WebKit/android/WebCoreSupport/WebUrlLoader.cpp | 87 + .../WebKit/android/WebCoreSupport/WebUrlLoader.h | 57 + .../android/WebCoreSupport/WebUrlLoaderClient.cpp | 482 ++ .../android/WebCoreSupport/WebUrlLoaderClient.h | 130 + .../android/WebCoreSupport/WebViewClientError.cpp | 132 + .../android/WebCoreSupport/WebViewClientError.h | 74 + .../autofill/AutoFillHostAndroid.cpp | 51 + .../WebCoreSupport/autofill/AutoFillHostAndroid.h | 54 + .../WebCoreSupport/autofill/FormFieldAndroid.cpp | 139 + .../WebCoreSupport/autofill/FormFieldAndroid.h | 96 + .../WebCoreSupport/autofill/FormManagerAndroid.cpp | 871 ++++ .../WebCoreSupport/autofill/FormManagerAndroid.h | 187 + .../WebCoreSupport/autofill/MainThreadProxy.cpp | 35 + .../WebCoreSupport/autofill/MainThreadProxy.h | 37 + .../android/WebCoreSupport/autofill/StringUtils.h | 73 + .../WebCoreSupport/autofill/WebAutoFill.cpp | 296 ++ .../android/WebCoreSupport/autofill/WebAutoFill.h | 127 + Source/WebKit/android/benchmark/Android.mk | 41 + Source/WebKit/android/benchmark/Intercept.cpp | 190 + Source/WebKit/android/benchmark/Intercept.h | 82 + Source/WebKit/android/benchmark/MyJavaVM.cpp | 130 + Source/WebKit/android/benchmark/MyJavaVM.h | 34 + Source/WebKit/android/benchmark/main.cpp | 65 + Source/WebKit/android/icu/unicode/ucnv.cpp | 50 + Source/WebKit/android/icu/unicode/ucnv.h | 47 + Source/WebKit/android/jni/CacheManager.cpp | 143 + Source/WebKit/android/jni/CookieManager.cpp | 201 + .../jni/DeviceMotionAndOrientationManager.cpp | 171 + .../jni/DeviceMotionAndOrientationManager.h | 68 + .../WebKit/android/jni/DeviceMotionClientImpl.cpp | 130 + Source/WebKit/android/jni/DeviceMotionClientImpl.h | 70 + .../android/jni/DeviceOrientationClientImpl.cpp | 130 + .../android/jni/DeviceOrientationClientImpl.h | 70 + .../android/jni/GeolocationPermissionsBridge.cpp | 113 + Source/WebKit/android/jni/JavaBridge.cpp | 514 +++ Source/WebKit/android/jni/JavaSharedClient.cpp | 137 + Source/WebKit/android/jni/JavaSharedClient.h | 65 + Source/WebKit/android/jni/JniUtil.cpp | 58 + Source/WebKit/android/jni/MIMETypeRegistry.cpp | 67 + Source/WebKit/android/jni/MockGeolocation.cpp | 84 + Source/WebKit/android/jni/PictureSet.cpp | 676 +++ Source/WebKit/android/jni/PictureSet.h | 104 + Source/WebKit/android/jni/WebCoreFrameBridge.cpp | 2125 +++++++++ Source/WebKit/android/jni/WebCoreFrameBridge.h | 173 + Source/WebKit/android/jni/WebCoreJni.cpp | 117 + Source/WebKit/android/jni/WebCoreJni.h | 96 + Source/WebKit/android/jni/WebCoreJniOnLoad.cpp | 319 ++ Source/WebKit/android/jni/WebCoreRefObject.h | 46 + .../WebKit/android/jni/WebCoreResourceLoader.cpp | 352 ++ Source/WebKit/android/jni/WebCoreResourceLoader.h | 78 + Source/WebKit/android/jni/WebCoreViewBridge.h | 106 + Source/WebKit/android/jni/WebFrameView.cpp | 104 + Source/WebKit/android/jni/WebFrameView.h | 65 + Source/WebKit/android/jni/WebHistory.cpp | 857 ++++ Source/WebKit/android/jni/WebHistory.h | 68 + Source/WebKit/android/jni/WebIconDatabase.cpp | 237 + Source/WebKit/android/jni/WebIconDatabase.h | 75 + Source/WebKit/android/jni/WebSettings.cpp | 599 +++ Source/WebKit/android/jni/WebStorage.cpp | 188 + Source/WebKit/android/jni/WebViewCore.cpp | 4598 ++++++++++++++++++++ Source/WebKit/android/jni/WebViewCore.h | 714 +++ Source/WebKit/android/nav/CacheBuilder.cpp | 3201 ++++++++++++++ Source/WebKit/android/nav/CacheBuilder.h | 297 ++ Source/WebKit/android/nav/CachedColor.cpp | 58 + Source/WebKit/android/nav/CachedColor.h | 87 + Source/WebKit/android/nav/CachedDebug.h | 72 + Source/WebKit/android/nav/CachedFrame.cpp | 1494 +++++++ Source/WebKit/android/nav/CachedFrame.h | 285 ++ Source/WebKit/android/nav/CachedHistory.cpp | 187 + Source/WebKit/android/nav/CachedHistory.h | 89 + Source/WebKit/android/nav/CachedInput.cpp | 100 + Source/WebKit/android/nav/CachedInput.h | 112 + Source/WebKit/android/nav/CachedLayer.cpp | 221 + Source/WebKit/android/nav/CachedLayer.h | 86 + Source/WebKit/android/nav/CachedNode.cpp | 432 ++ Source/WebKit/android/nav/CachedNode.h | 247 ++ Source/WebKit/android/nav/CachedNodeType.h | 56 + Source/WebKit/android/nav/CachedPrefix.h | 53 + Source/WebKit/android/nav/CachedRoot.cpp | 1813 ++++++++ Source/WebKit/android/nav/CachedRoot.h | 142 + Source/WebKit/android/nav/DrawExtra.h | 48 + Source/WebKit/android/nav/FindCanvas.cpp | 699 +++ Source/WebKit/android/nav/FindCanvas.h | 255 ++ Source/WebKit/android/nav/ParseCanvas.h | 52 + Source/WebKit/android/nav/SelectText.cpp | 1983 +++++++++ Source/WebKit/android/nav/SelectText.h | 116 + Source/WebKit/android/nav/WebView.cpp | 2673 ++++++++++++ .../WebKit/android/plugins/ANPBitmapInterface.cpp | 71 + .../WebKit/android/plugins/ANPCanvasInterface.cpp | 197 + .../WebKit/android/plugins/ANPEventInterface.cpp | 84 + Source/WebKit/android/plugins/ANPKeyCodes.h | 229 + Source/WebKit/android/plugins/ANPLogInterface.cpp | 60 + .../WebKit/android/plugins/ANPMatrixInterface.cpp | 167 + .../WebKit/android/plugins/ANPOpenGLInterface.cpp | 121 + Source/WebKit/android/plugins/ANPOpenGL_npapi.h | 63 + .../WebKit/android/plugins/ANPPaintInterface.cpp | 212 + Source/WebKit/android/plugins/ANPPathInterface.cpp | 112 + .../WebKit/android/plugins/ANPSoundInterface.cpp | 163 + .../WebKit/android/plugins/ANPSurfaceInterface.cpp | 174 + Source/WebKit/android/plugins/ANPSurface_npapi.h | 48 + .../WebKit/android/plugins/ANPSystemInterface.cpp | 222 + Source/WebKit/android/plugins/ANPSystem_npapi.h | 72 + .../android/plugins/ANPTypefaceInterface.cpp | 104 + .../WebKit/android/plugins/ANPVideoInterface.cpp | 83 + Source/WebKit/android/plugins/ANPVideo_npapi.h | 61 + .../WebKit/android/plugins/ANPWindowInterface.cpp | 103 + .../WebKit/android/plugins/PluginDebugAndroid.cpp | 137 + Source/WebKit/android/plugins/PluginDebugAndroid.h | 58 + Source/WebKit/android/plugins/PluginTimer.cpp | 135 + Source/WebKit/android/plugins/PluginTimer.h | 82 + .../android/plugins/PluginViewBridgeAndroid.cpp | 38 + .../android/plugins/PluginViewBridgeAndroid.h | 48 + .../WebKit/android/plugins/PluginWidgetAndroid.cpp | 690 +++ .../WebKit/android/plugins/PluginWidgetAndroid.h | 219 + Source/WebKit/android/plugins/SkANP.cpp | 106 + Source/WebKit/android/plugins/SkANP.h | 79 + Source/WebKit/android/plugins/SurfaceCallback.h | 42 + Source/WebKit/android/plugins/android_npapi.h | 987 +++++ Source/WebKit/android/smoke/MessageThread.cpp | 146 + Source/WebKit/android/smoke/MessageThread.h | 108 + Source/WebKit/android/smoke/MessageTypes.h | 159 + Source/WebKit/android/wds/Command.cpp | 154 + Source/WebKit/android/wds/Command.h | 108 + Source/WebKit/android/wds/Connection.cpp | 93 + Source/WebKit/android/wds/Connection.h | 86 + Source/WebKit/android/wds/DebugServer.cpp | 116 + Source/WebKit/android/wds/DebugServer.h | 77 + Source/WebKit/android/wds/client/AdbConnection.cpp | 237 + Source/WebKit/android/wds/client/AdbConnection.h | 47 + Source/WebKit/android/wds/client/Android.mk | 39 + Source/WebKit/android/wds/client/ClientUtils.cpp | 35 + Source/WebKit/android/wds/client/ClientUtils.h | 46 + Source/WebKit/android/wds/client/Device.cpp | 31 + Source/WebKit/android/wds/client/Device.h | 62 + Source/WebKit/android/wds/client/DeviceList.h | 35 + Source/WebKit/android/wds/client/main.cpp | 173 + WebKit/Android.mk | 132 - WebKit/android/AndroidLog.h | 48 - WebKit/android/JavaVM/jni.h | 32 - WebKit/android/RenderSkinAndroid.cpp | 73 - WebKit/android/RenderSkinAndroid.h | 74 - WebKit/android/RenderSkinButton.cpp | 90 - WebKit/android/RenderSkinButton.h | 55 - WebKit/android/RenderSkinCombo.cpp | 146 - WebKit/android/RenderSkinCombo.h | 69 - WebKit/android/RenderSkinMediaButton.cpp | 215 - WebKit/android/RenderSkinMediaButton.h | 63 - WebKit/android/RenderSkinNinePatch.cpp | 89 - WebKit/android/RenderSkinNinePatch.h | 48 - WebKit/android/RenderSkinRadio.cpp | 100 - WebKit/android/RenderSkinRadio.h | 61 - WebKit/android/TimeCounter.cpp | 198 - WebKit/android/TimeCounter.h | 120 - WebKit/android/TimerClient.h | 42 - WebKit/android/WebCoreSupport/CacheResult.cpp | 251 -- WebKit/android/WebCoreSupport/CacheResult.h | 86 - .../CachedFramePlatformDataAndroid.cpp | 66 - .../CachedFramePlatformDataAndroid.h | 63 - .../android/WebCoreSupport/ChromeClientAndroid.cpp | 605 --- .../android/WebCoreSupport/ChromeClientAndroid.h | 216 - WebKit/android/WebCoreSupport/ChromiumIncludes.h | 104 - WebKit/android/WebCoreSupport/ChromiumInit.cpp | 74 - WebKit/android/WebCoreSupport/ChromiumInit.h | 38 - .../WebCoreSupport/ContextMenuClientAndroid.cpp | 51 - .../WebCoreSupport/ContextMenuClientAndroid.h | 51 - WebKit/android/WebCoreSupport/CookieClient.h | 46 - .../WebCoreSupport/DeviceMotionClientAndroid.cpp | 84 - .../WebCoreSupport/DeviceMotionClientAndroid.h | 65 - .../DeviceOrientationClientAndroid.cpp | 84 - .../DeviceOrientationClientAndroid.h | 65 - .../android/WebCoreSupport/DragClientAndroid.cpp | 46 - WebKit/android/WebCoreSupport/DragClientAndroid.h | 51 - .../android/WebCoreSupport/EditorClientAndroid.cpp | 280 -- .../android/WebCoreSupport/EditorClientAndroid.h | 135 - WebKit/android/WebCoreSupport/FileSystemClient.h | 41 - .../WebCoreSupport/FrameLoaderClientAndroid.cpp | 1351 ------ .../WebCoreSupport/FrameLoaderClientAndroid.h | 271 -- .../FrameNetworkingContextAndroid.cpp | 52 - .../WebCoreSupport/FrameNetworkingContextAndroid.h | 54 - .../WebCoreSupport/GeolocationPermissions.cpp | 419 -- .../WebCoreSupport/GeolocationPermissions.h | 178 - .../WebCoreSupport/InspectorClientAndroid.h | 54 - WebKit/android/WebCoreSupport/KeyGeneratorClient.h | 46 - .../WebCoreSupport/MediaPlayerPrivateAndroid.cpp | 654 --- WebKit/android/WebCoreSupport/MemoryUsage.cpp | 81 - WebKit/android/WebCoreSupport/MemoryUsage.h | 45 - WebKit/android/WebCoreSupport/PlatformBridge.cpp | 261 -- .../WebCoreSupport/ResourceLoaderAndroid.cpp | 71 - .../WebCoreSupport/UrlInterceptResponse.cpp | 130 - .../android/WebCoreSupport/UrlInterceptResponse.h | 70 - WebKit/android/WebCoreSupport/V8Counters.cpp | 116 - WebKit/android/WebCoreSupport/V8Counters.h | 77 - WebKit/android/WebCoreSupport/WebCache.cpp | 237 - WebKit/android/WebCoreSupport/WebCache.h | 88 - WebKit/android/WebCoreSupport/WebCookieJar.cpp | 263 -- WebKit/android/WebCoreSupport/WebCookieJar.h | 78 - WebKit/android/WebCoreSupport/WebRequest.cpp | 531 --- WebKit/android/WebCoreSupport/WebRequest.h | 125 - .../android/WebCoreSupport/WebRequestContext.cpp | 130 - WebKit/android/WebCoreSupport/WebRequestContext.h | 64 - .../android/WebCoreSupport/WebResourceRequest.cpp | 96 - WebKit/android/WebCoreSupport/WebResourceRequest.h | 86 - WebKit/android/WebCoreSupport/WebResponse.cpp | 167 - WebKit/android/WebCoreSupport/WebResponse.h | 91 - WebKit/android/WebCoreSupport/WebUrlLoader.cpp | 87 - WebKit/android/WebCoreSupport/WebUrlLoader.h | 57 - .../android/WebCoreSupport/WebUrlLoaderClient.cpp | 482 -- WebKit/android/WebCoreSupport/WebUrlLoaderClient.h | 130 - .../android/WebCoreSupport/WebViewClientError.cpp | 132 - WebKit/android/WebCoreSupport/WebViewClientError.h | 74 - .../autofill/AutoFillHostAndroid.cpp | 51 - .../WebCoreSupport/autofill/AutoFillHostAndroid.h | 54 - .../WebCoreSupport/autofill/FormFieldAndroid.cpp | 139 - .../WebCoreSupport/autofill/FormFieldAndroid.h | 96 - .../WebCoreSupport/autofill/FormManagerAndroid.cpp | 871 ---- .../WebCoreSupport/autofill/FormManagerAndroid.h | 187 - .../WebCoreSupport/autofill/MainThreadProxy.cpp | 35 - .../WebCoreSupport/autofill/MainThreadProxy.h | 37 - .../android/WebCoreSupport/autofill/StringUtils.h | 73 - .../WebCoreSupport/autofill/WebAutoFill.cpp | 296 -- .../android/WebCoreSupport/autofill/WebAutoFill.h | 127 - WebKit/android/benchmark/Android.mk | 41 - WebKit/android/benchmark/Intercept.cpp | 190 - WebKit/android/benchmark/Intercept.h | 82 - WebKit/android/benchmark/MyJavaVM.cpp | 130 - WebKit/android/benchmark/MyJavaVM.h | 34 - WebKit/android/benchmark/main.cpp | 65 - WebKit/android/icu/unicode/ucnv.cpp | 50 - WebKit/android/icu/unicode/ucnv.h | 47 - WebKit/android/jni/CacheManager.cpp | 143 - WebKit/android/jni/CookieManager.cpp | 201 - .../jni/DeviceMotionAndOrientationManager.cpp | 171 - .../jni/DeviceMotionAndOrientationManager.h | 68 - WebKit/android/jni/DeviceMotionClientImpl.cpp | 130 - WebKit/android/jni/DeviceMotionClientImpl.h | 70 - WebKit/android/jni/DeviceOrientationClientImpl.cpp | 130 - WebKit/android/jni/DeviceOrientationClientImpl.h | 70 - .../android/jni/GeolocationPermissionsBridge.cpp | 113 - WebKit/android/jni/JavaBridge.cpp | 514 --- WebKit/android/jni/JavaSharedClient.cpp | 137 - WebKit/android/jni/JavaSharedClient.h | 65 - WebKit/android/jni/JniUtil.cpp | 58 - WebKit/android/jni/MIMETypeRegistry.cpp | 67 - WebKit/android/jni/MockGeolocation.cpp | 84 - WebKit/android/jni/PictureSet.cpp | 676 --- WebKit/android/jni/PictureSet.h | 104 - WebKit/android/jni/WebCoreFrameBridge.cpp | 2125 --------- WebKit/android/jni/WebCoreFrameBridge.h | 173 - WebKit/android/jni/WebCoreJni.cpp | 117 - WebKit/android/jni/WebCoreJni.h | 96 - WebKit/android/jni/WebCoreJniOnLoad.cpp | 319 -- WebKit/android/jni/WebCoreRefObject.h | 46 - WebKit/android/jni/WebCoreResourceLoader.cpp | 352 -- WebKit/android/jni/WebCoreResourceLoader.h | 78 - WebKit/android/jni/WebCoreViewBridge.h | 106 - WebKit/android/jni/WebFrameView.cpp | 104 - WebKit/android/jni/WebFrameView.h | 65 - WebKit/android/jni/WebHistory.cpp | 857 ---- WebKit/android/jni/WebHistory.h | 68 - WebKit/android/jni/WebIconDatabase.cpp | 237 - WebKit/android/jni/WebIconDatabase.h | 75 - WebKit/android/jni/WebSettings.cpp | 599 --- WebKit/android/jni/WebStorage.cpp | 188 - WebKit/android/jni/WebViewCore.cpp | 4598 -------------------- WebKit/android/jni/WebViewCore.h | 714 --- WebKit/android/nav/CacheBuilder.cpp | 3201 -------------- WebKit/android/nav/CacheBuilder.h | 297 -- WebKit/android/nav/CachedColor.cpp | 58 - WebKit/android/nav/CachedColor.h | 87 - WebKit/android/nav/CachedDebug.h | 72 - WebKit/android/nav/CachedFrame.cpp | 1494 ------- WebKit/android/nav/CachedFrame.h | 285 -- WebKit/android/nav/CachedHistory.cpp | 187 - WebKit/android/nav/CachedHistory.h | 89 - WebKit/android/nav/CachedInput.cpp | 100 - WebKit/android/nav/CachedInput.h | 112 - WebKit/android/nav/CachedLayer.cpp | 221 - WebKit/android/nav/CachedLayer.h | 86 - WebKit/android/nav/CachedNode.cpp | 432 -- WebKit/android/nav/CachedNode.h | 247 -- WebKit/android/nav/CachedNodeType.h | 56 - WebKit/android/nav/CachedPrefix.h | 53 - WebKit/android/nav/CachedRoot.cpp | 1813 -------- WebKit/android/nav/CachedRoot.h | 142 - WebKit/android/nav/DrawExtra.h | 48 - WebKit/android/nav/FindCanvas.cpp | 699 --- WebKit/android/nav/FindCanvas.h | 255 -- WebKit/android/nav/ParseCanvas.h | 52 - WebKit/android/nav/SelectText.cpp | 1983 --------- WebKit/android/nav/SelectText.h | 116 - WebKit/android/nav/WebView.cpp | 2673 ------------ WebKit/android/plugins/ANPBitmapInterface.cpp | 71 - WebKit/android/plugins/ANPCanvasInterface.cpp | 197 - WebKit/android/plugins/ANPEventInterface.cpp | 84 - WebKit/android/plugins/ANPKeyCodes.h | 229 - WebKit/android/plugins/ANPLogInterface.cpp | 60 - WebKit/android/plugins/ANPMatrixInterface.cpp | 167 - WebKit/android/plugins/ANPOpenGLInterface.cpp | 121 - WebKit/android/plugins/ANPOpenGL_npapi.h | 63 - WebKit/android/plugins/ANPPaintInterface.cpp | 212 - WebKit/android/plugins/ANPPathInterface.cpp | 112 - WebKit/android/plugins/ANPSoundInterface.cpp | 163 - WebKit/android/plugins/ANPSurfaceInterface.cpp | 174 - WebKit/android/plugins/ANPSurface_npapi.h | 48 - WebKit/android/plugins/ANPSystemInterface.cpp | 222 - WebKit/android/plugins/ANPSystem_npapi.h | 72 - WebKit/android/plugins/ANPTypefaceInterface.cpp | 104 - WebKit/android/plugins/ANPVideoInterface.cpp | 83 - WebKit/android/plugins/ANPVideo_npapi.h | 61 - WebKit/android/plugins/ANPWindowInterface.cpp | 103 - WebKit/android/plugins/PluginDebugAndroid.cpp | 137 - WebKit/android/plugins/PluginDebugAndroid.h | 58 - WebKit/android/plugins/PluginTimer.cpp | 135 - WebKit/android/plugins/PluginTimer.h | 82 - WebKit/android/plugins/PluginViewBridgeAndroid.cpp | 38 - WebKit/android/plugins/PluginViewBridgeAndroid.h | 48 - WebKit/android/plugins/PluginWidgetAndroid.cpp | 690 --- WebKit/android/plugins/PluginWidgetAndroid.h | 219 - WebKit/android/plugins/SkANP.cpp | 106 - WebKit/android/plugins/SkANP.h | 79 - WebKit/android/plugins/SurfaceCallback.h | 42 - WebKit/android/plugins/android_npapi.h | 987 ----- WebKit/android/smoke/MessageThread.cpp | 146 - WebKit/android/smoke/MessageThread.h | 108 - WebKit/android/smoke/MessageTypes.h | 159 - WebKit/android/wds/Command.cpp | 154 - WebKit/android/wds/Command.h | 108 - WebKit/android/wds/Connection.cpp | 93 - WebKit/android/wds/Connection.h | 86 - WebKit/android/wds/DebugServer.cpp | 116 - WebKit/android/wds/DebugServer.h | 77 - WebKit/android/wds/client/AdbConnection.cpp | 237 - WebKit/android/wds/client/AdbConnection.h | 47 - WebKit/android/wds/client/Android.mk | 39 - WebKit/android/wds/client/ClientUtils.cpp | 35 - WebKit/android/wds/client/ClientUtils.h | 46 - WebKit/android/wds/client/Device.cpp | 31 - WebKit/android/wds/client/Device.h | 62 - WebKit/android/wds/client/DeviceList.h | 35 - WebKit/android/wds/client/main.cpp | 173 - 408 files changed, 48905 insertions(+), 48905 deletions(-) create mode 100644 Source/WebKit/Android.mk create mode 100644 Source/WebKit/android/AndroidLog.h create mode 100644 Source/WebKit/android/JavaVM/jni.h create mode 100644 Source/WebKit/android/RenderSkinAndroid.cpp create mode 100644 Source/WebKit/android/RenderSkinAndroid.h create mode 100644 Source/WebKit/android/RenderSkinButton.cpp create mode 100644 Source/WebKit/android/RenderSkinButton.h create mode 100644 Source/WebKit/android/RenderSkinCombo.cpp create mode 100644 Source/WebKit/android/RenderSkinCombo.h create mode 100644 Source/WebKit/android/RenderSkinMediaButton.cpp create mode 100644 Source/WebKit/android/RenderSkinMediaButton.h create mode 100644 Source/WebKit/android/RenderSkinNinePatch.cpp create mode 100644 Source/WebKit/android/RenderSkinNinePatch.h create mode 100644 Source/WebKit/android/RenderSkinRadio.cpp create mode 100644 Source/WebKit/android/RenderSkinRadio.h create mode 100644 Source/WebKit/android/TimeCounter.cpp create mode 100644 Source/WebKit/android/TimeCounter.h create mode 100644 Source/WebKit/android/TimerClient.h create mode 100644 Source/WebKit/android/WebCoreSupport/CacheResult.cpp create mode 100644 Source/WebKit/android/WebCoreSupport/CacheResult.h create mode 100644 Source/WebKit/android/WebCoreSupport/CachedFramePlatformDataAndroid.cpp create mode 100644 Source/WebKit/android/WebCoreSupport/CachedFramePlatformDataAndroid.h create mode 100644 Source/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp create mode 100644 Source/WebKit/android/WebCoreSupport/ChromeClientAndroid.h create mode 100644 Source/WebKit/android/WebCoreSupport/ChromiumIncludes.h create mode 100644 Source/WebKit/android/WebCoreSupport/ChromiumInit.cpp create mode 100644 Source/WebKit/android/WebCoreSupport/ChromiumInit.h create mode 100644 Source/WebKit/android/WebCoreSupport/ContextMenuClientAndroid.cpp create mode 100644 Source/WebKit/android/WebCoreSupport/ContextMenuClientAndroid.h create mode 100644 Source/WebKit/android/WebCoreSupport/CookieClient.h create mode 100644 Source/WebKit/android/WebCoreSupport/DeviceMotionClientAndroid.cpp create mode 100644 Source/WebKit/android/WebCoreSupport/DeviceMotionClientAndroid.h create mode 100644 Source/WebKit/android/WebCoreSupport/DeviceOrientationClientAndroid.cpp create mode 100644 Source/WebKit/android/WebCoreSupport/DeviceOrientationClientAndroid.h create mode 100644 Source/WebKit/android/WebCoreSupport/DragClientAndroid.cpp create mode 100644 Source/WebKit/android/WebCoreSupport/DragClientAndroid.h create mode 100644 Source/WebKit/android/WebCoreSupport/EditorClientAndroid.cpp create mode 100644 Source/WebKit/android/WebCoreSupport/EditorClientAndroid.h create mode 100644 Source/WebKit/android/WebCoreSupport/FileSystemClient.h create mode 100644 Source/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp create mode 100644 Source/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.h create mode 100644 Source/WebKit/android/WebCoreSupport/FrameNetworkingContextAndroid.cpp create mode 100644 Source/WebKit/android/WebCoreSupport/FrameNetworkingContextAndroid.h create mode 100755 Source/WebKit/android/WebCoreSupport/GeolocationPermissions.cpp create mode 100644 Source/WebKit/android/WebCoreSupport/GeolocationPermissions.h create mode 100644 Source/WebKit/android/WebCoreSupport/InspectorClientAndroid.h create mode 100644 Source/WebKit/android/WebCoreSupport/KeyGeneratorClient.h create mode 100644 Source/WebKit/android/WebCoreSupport/MediaPlayerPrivateAndroid.cpp create mode 100644 Source/WebKit/android/WebCoreSupport/MemoryUsage.cpp create mode 100644 Source/WebKit/android/WebCoreSupport/MemoryUsage.h create mode 100644 Source/WebKit/android/WebCoreSupport/PlatformBridge.cpp create mode 100644 Source/WebKit/android/WebCoreSupport/ResourceLoaderAndroid.cpp create mode 100644 Source/WebKit/android/WebCoreSupport/UrlInterceptResponse.cpp create mode 100644 Source/WebKit/android/WebCoreSupport/UrlInterceptResponse.h create mode 100644 Source/WebKit/android/WebCoreSupport/V8Counters.cpp create mode 100644 Source/WebKit/android/WebCoreSupport/V8Counters.h create mode 100644 Source/WebKit/android/WebCoreSupport/WebCache.cpp create mode 100644 Source/WebKit/android/WebCoreSupport/WebCache.h create mode 100644 Source/WebKit/android/WebCoreSupport/WebCookieJar.cpp create mode 100644 Source/WebKit/android/WebCoreSupport/WebCookieJar.h create mode 100644 Source/WebKit/android/WebCoreSupport/WebRequest.cpp create mode 100644 Source/WebKit/android/WebCoreSupport/WebRequest.h create mode 100644 Source/WebKit/android/WebCoreSupport/WebRequestContext.cpp create mode 100644 Source/WebKit/android/WebCoreSupport/WebRequestContext.h create mode 100644 Source/WebKit/android/WebCoreSupport/WebResourceRequest.cpp create mode 100644 Source/WebKit/android/WebCoreSupport/WebResourceRequest.h create mode 100644 Source/WebKit/android/WebCoreSupport/WebResponse.cpp create mode 100644 Source/WebKit/android/WebCoreSupport/WebResponse.h create mode 100644 Source/WebKit/android/WebCoreSupport/WebUrlLoader.cpp create mode 100644 Source/WebKit/android/WebCoreSupport/WebUrlLoader.h create mode 100644 Source/WebKit/android/WebCoreSupport/WebUrlLoaderClient.cpp create mode 100644 Source/WebKit/android/WebCoreSupport/WebUrlLoaderClient.h create mode 100644 Source/WebKit/android/WebCoreSupport/WebViewClientError.cpp create mode 100644 Source/WebKit/android/WebCoreSupport/WebViewClientError.h create mode 100644 Source/WebKit/android/WebCoreSupport/autofill/AutoFillHostAndroid.cpp create mode 100644 Source/WebKit/android/WebCoreSupport/autofill/AutoFillHostAndroid.h create mode 100644 Source/WebKit/android/WebCoreSupport/autofill/FormFieldAndroid.cpp create mode 100644 Source/WebKit/android/WebCoreSupport/autofill/FormFieldAndroid.h create mode 100644 Source/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.cpp create mode 100644 Source/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.h create mode 100644 Source/WebKit/android/WebCoreSupport/autofill/MainThreadProxy.cpp create mode 100644 Source/WebKit/android/WebCoreSupport/autofill/MainThreadProxy.h create mode 100644 Source/WebKit/android/WebCoreSupport/autofill/StringUtils.h create mode 100644 Source/WebKit/android/WebCoreSupport/autofill/WebAutoFill.cpp create mode 100644 Source/WebKit/android/WebCoreSupport/autofill/WebAutoFill.h create mode 100644 Source/WebKit/android/benchmark/Android.mk create mode 100644 Source/WebKit/android/benchmark/Intercept.cpp create mode 100644 Source/WebKit/android/benchmark/Intercept.h create mode 100644 Source/WebKit/android/benchmark/MyJavaVM.cpp create mode 100644 Source/WebKit/android/benchmark/MyJavaVM.h create mode 100644 Source/WebKit/android/benchmark/main.cpp create mode 100644 Source/WebKit/android/icu/unicode/ucnv.cpp create mode 100644 Source/WebKit/android/icu/unicode/ucnv.h create mode 100644 Source/WebKit/android/jni/CacheManager.cpp create mode 100644 Source/WebKit/android/jni/CookieManager.cpp create mode 100644 Source/WebKit/android/jni/DeviceMotionAndOrientationManager.cpp create mode 100644 Source/WebKit/android/jni/DeviceMotionAndOrientationManager.h create mode 100644 Source/WebKit/android/jni/DeviceMotionClientImpl.cpp create mode 100644 Source/WebKit/android/jni/DeviceMotionClientImpl.h create mode 100644 Source/WebKit/android/jni/DeviceOrientationClientImpl.cpp create mode 100644 Source/WebKit/android/jni/DeviceOrientationClientImpl.h create mode 100755 Source/WebKit/android/jni/GeolocationPermissionsBridge.cpp create mode 100644 Source/WebKit/android/jni/JavaBridge.cpp create mode 100644 Source/WebKit/android/jni/JavaSharedClient.cpp create mode 100644 Source/WebKit/android/jni/JavaSharedClient.h create mode 100644 Source/WebKit/android/jni/JniUtil.cpp create mode 100644 Source/WebKit/android/jni/MIMETypeRegistry.cpp create mode 100755 Source/WebKit/android/jni/MockGeolocation.cpp create mode 100644 Source/WebKit/android/jni/PictureSet.cpp create mode 100644 Source/WebKit/android/jni/PictureSet.h create mode 100644 Source/WebKit/android/jni/WebCoreFrameBridge.cpp create mode 100644 Source/WebKit/android/jni/WebCoreFrameBridge.h create mode 100644 Source/WebKit/android/jni/WebCoreJni.cpp create mode 100644 Source/WebKit/android/jni/WebCoreJni.h create mode 100644 Source/WebKit/android/jni/WebCoreJniOnLoad.cpp create mode 100644 Source/WebKit/android/jni/WebCoreRefObject.h create mode 100644 Source/WebKit/android/jni/WebCoreResourceLoader.cpp create mode 100644 Source/WebKit/android/jni/WebCoreResourceLoader.h create mode 100644 Source/WebKit/android/jni/WebCoreViewBridge.h create mode 100644 Source/WebKit/android/jni/WebFrameView.cpp create mode 100644 Source/WebKit/android/jni/WebFrameView.h create mode 100644 Source/WebKit/android/jni/WebHistory.cpp create mode 100644 Source/WebKit/android/jni/WebHistory.h create mode 100644 Source/WebKit/android/jni/WebIconDatabase.cpp create mode 100644 Source/WebKit/android/jni/WebIconDatabase.h create mode 100644 Source/WebKit/android/jni/WebSettings.cpp create mode 100644 Source/WebKit/android/jni/WebStorage.cpp create mode 100644 Source/WebKit/android/jni/WebViewCore.cpp create mode 100644 Source/WebKit/android/jni/WebViewCore.h create mode 100644 Source/WebKit/android/nav/CacheBuilder.cpp create mode 100644 Source/WebKit/android/nav/CacheBuilder.h create mode 100644 Source/WebKit/android/nav/CachedColor.cpp create mode 100644 Source/WebKit/android/nav/CachedColor.h create mode 100644 Source/WebKit/android/nav/CachedDebug.h create mode 100644 Source/WebKit/android/nav/CachedFrame.cpp create mode 100644 Source/WebKit/android/nav/CachedFrame.h create mode 100644 Source/WebKit/android/nav/CachedHistory.cpp create mode 100644 Source/WebKit/android/nav/CachedHistory.h create mode 100644 Source/WebKit/android/nav/CachedInput.cpp create mode 100644 Source/WebKit/android/nav/CachedInput.h create mode 100644 Source/WebKit/android/nav/CachedLayer.cpp create mode 100644 Source/WebKit/android/nav/CachedLayer.h create mode 100644 Source/WebKit/android/nav/CachedNode.cpp create mode 100644 Source/WebKit/android/nav/CachedNode.h create mode 100644 Source/WebKit/android/nav/CachedNodeType.h create mode 100644 Source/WebKit/android/nav/CachedPrefix.h create mode 100644 Source/WebKit/android/nav/CachedRoot.cpp create mode 100644 Source/WebKit/android/nav/CachedRoot.h create mode 100644 Source/WebKit/android/nav/DrawExtra.h create mode 100644 Source/WebKit/android/nav/FindCanvas.cpp create mode 100644 Source/WebKit/android/nav/FindCanvas.h create mode 100644 Source/WebKit/android/nav/ParseCanvas.h create mode 100644 Source/WebKit/android/nav/SelectText.cpp create mode 100644 Source/WebKit/android/nav/SelectText.h create mode 100644 Source/WebKit/android/nav/WebView.cpp create mode 100644 Source/WebKit/android/plugins/ANPBitmapInterface.cpp create mode 100644 Source/WebKit/android/plugins/ANPCanvasInterface.cpp create mode 100644 Source/WebKit/android/plugins/ANPEventInterface.cpp create mode 100644 Source/WebKit/android/plugins/ANPKeyCodes.h create mode 100644 Source/WebKit/android/plugins/ANPLogInterface.cpp create mode 100644 Source/WebKit/android/plugins/ANPMatrixInterface.cpp create mode 100644 Source/WebKit/android/plugins/ANPOpenGLInterface.cpp create mode 100644 Source/WebKit/android/plugins/ANPOpenGL_npapi.h create mode 100644 Source/WebKit/android/plugins/ANPPaintInterface.cpp create mode 100644 Source/WebKit/android/plugins/ANPPathInterface.cpp create mode 100644 Source/WebKit/android/plugins/ANPSoundInterface.cpp create mode 100644 Source/WebKit/android/plugins/ANPSurfaceInterface.cpp create mode 100644 Source/WebKit/android/plugins/ANPSurface_npapi.h create mode 100644 Source/WebKit/android/plugins/ANPSystemInterface.cpp create mode 100644 Source/WebKit/android/plugins/ANPSystem_npapi.h create mode 100644 Source/WebKit/android/plugins/ANPTypefaceInterface.cpp create mode 100644 Source/WebKit/android/plugins/ANPVideoInterface.cpp create mode 100644 Source/WebKit/android/plugins/ANPVideo_npapi.h create mode 100644 Source/WebKit/android/plugins/ANPWindowInterface.cpp create mode 100644 Source/WebKit/android/plugins/PluginDebugAndroid.cpp create mode 100644 Source/WebKit/android/plugins/PluginDebugAndroid.h create mode 100644 Source/WebKit/android/plugins/PluginTimer.cpp create mode 100644 Source/WebKit/android/plugins/PluginTimer.h create mode 100644 Source/WebKit/android/plugins/PluginViewBridgeAndroid.cpp create mode 100644 Source/WebKit/android/plugins/PluginViewBridgeAndroid.h create mode 100644 Source/WebKit/android/plugins/PluginWidgetAndroid.cpp create mode 100644 Source/WebKit/android/plugins/PluginWidgetAndroid.h create mode 100644 Source/WebKit/android/plugins/SkANP.cpp create mode 100644 Source/WebKit/android/plugins/SkANP.h create mode 100644 Source/WebKit/android/plugins/SurfaceCallback.h create mode 100644 Source/WebKit/android/plugins/android_npapi.h create mode 100644 Source/WebKit/android/smoke/MessageThread.cpp create mode 100644 Source/WebKit/android/smoke/MessageThread.h create mode 100644 Source/WebKit/android/smoke/MessageTypes.h create mode 100644 Source/WebKit/android/wds/Command.cpp create mode 100644 Source/WebKit/android/wds/Command.h create mode 100644 Source/WebKit/android/wds/Connection.cpp create mode 100644 Source/WebKit/android/wds/Connection.h create mode 100644 Source/WebKit/android/wds/DebugServer.cpp create mode 100644 Source/WebKit/android/wds/DebugServer.h create mode 100644 Source/WebKit/android/wds/client/AdbConnection.cpp create mode 100644 Source/WebKit/android/wds/client/AdbConnection.h create mode 100644 Source/WebKit/android/wds/client/Android.mk create mode 100644 Source/WebKit/android/wds/client/ClientUtils.cpp create mode 100644 Source/WebKit/android/wds/client/ClientUtils.h create mode 100644 Source/WebKit/android/wds/client/Device.cpp create mode 100644 Source/WebKit/android/wds/client/Device.h create mode 100644 Source/WebKit/android/wds/client/DeviceList.h create mode 100644 Source/WebKit/android/wds/client/main.cpp delete mode 100644 WebKit/Android.mk delete mode 100644 WebKit/android/AndroidLog.h delete mode 100644 WebKit/android/JavaVM/jni.h delete mode 100644 WebKit/android/RenderSkinAndroid.cpp delete mode 100644 WebKit/android/RenderSkinAndroid.h delete mode 100644 WebKit/android/RenderSkinButton.cpp delete mode 100644 WebKit/android/RenderSkinButton.h delete mode 100644 WebKit/android/RenderSkinCombo.cpp delete mode 100644 WebKit/android/RenderSkinCombo.h delete mode 100644 WebKit/android/RenderSkinMediaButton.cpp delete mode 100644 WebKit/android/RenderSkinMediaButton.h delete mode 100644 WebKit/android/RenderSkinNinePatch.cpp delete mode 100644 WebKit/android/RenderSkinNinePatch.h delete mode 100644 WebKit/android/RenderSkinRadio.cpp delete mode 100644 WebKit/android/RenderSkinRadio.h delete mode 100644 WebKit/android/TimeCounter.cpp delete mode 100644 WebKit/android/TimeCounter.h delete mode 100644 WebKit/android/TimerClient.h delete mode 100644 WebKit/android/WebCoreSupport/CacheResult.cpp delete mode 100644 WebKit/android/WebCoreSupport/CacheResult.h delete mode 100644 WebKit/android/WebCoreSupport/CachedFramePlatformDataAndroid.cpp delete mode 100644 WebKit/android/WebCoreSupport/CachedFramePlatformDataAndroid.h delete mode 100644 WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp delete mode 100644 WebKit/android/WebCoreSupport/ChromeClientAndroid.h delete mode 100644 WebKit/android/WebCoreSupport/ChromiumIncludes.h delete mode 100644 WebKit/android/WebCoreSupport/ChromiumInit.cpp delete mode 100644 WebKit/android/WebCoreSupport/ChromiumInit.h delete mode 100644 WebKit/android/WebCoreSupport/ContextMenuClientAndroid.cpp delete mode 100644 WebKit/android/WebCoreSupport/ContextMenuClientAndroid.h delete mode 100644 WebKit/android/WebCoreSupport/CookieClient.h delete mode 100644 WebKit/android/WebCoreSupport/DeviceMotionClientAndroid.cpp delete mode 100644 WebKit/android/WebCoreSupport/DeviceMotionClientAndroid.h delete mode 100644 WebKit/android/WebCoreSupport/DeviceOrientationClientAndroid.cpp delete mode 100644 WebKit/android/WebCoreSupport/DeviceOrientationClientAndroid.h delete mode 100644 WebKit/android/WebCoreSupport/DragClientAndroid.cpp delete mode 100644 WebKit/android/WebCoreSupport/DragClientAndroid.h delete mode 100644 WebKit/android/WebCoreSupport/EditorClientAndroid.cpp delete mode 100644 WebKit/android/WebCoreSupport/EditorClientAndroid.h delete mode 100644 WebKit/android/WebCoreSupport/FileSystemClient.h delete mode 100644 WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp delete mode 100644 WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.h delete mode 100644 WebKit/android/WebCoreSupport/FrameNetworkingContextAndroid.cpp delete mode 100644 WebKit/android/WebCoreSupport/FrameNetworkingContextAndroid.h delete mode 100755 WebKit/android/WebCoreSupport/GeolocationPermissions.cpp delete mode 100644 WebKit/android/WebCoreSupport/GeolocationPermissions.h delete mode 100644 WebKit/android/WebCoreSupport/InspectorClientAndroid.h delete mode 100644 WebKit/android/WebCoreSupport/KeyGeneratorClient.h delete mode 100644 WebKit/android/WebCoreSupport/MediaPlayerPrivateAndroid.cpp delete mode 100644 WebKit/android/WebCoreSupport/MemoryUsage.cpp delete mode 100644 WebKit/android/WebCoreSupport/MemoryUsage.h delete mode 100644 WebKit/android/WebCoreSupport/PlatformBridge.cpp delete mode 100644 WebKit/android/WebCoreSupport/ResourceLoaderAndroid.cpp delete mode 100644 WebKit/android/WebCoreSupport/UrlInterceptResponse.cpp delete mode 100644 WebKit/android/WebCoreSupport/UrlInterceptResponse.h delete mode 100644 WebKit/android/WebCoreSupport/V8Counters.cpp delete mode 100644 WebKit/android/WebCoreSupport/V8Counters.h delete mode 100644 WebKit/android/WebCoreSupport/WebCache.cpp delete mode 100644 WebKit/android/WebCoreSupport/WebCache.h delete mode 100644 WebKit/android/WebCoreSupport/WebCookieJar.cpp delete mode 100644 WebKit/android/WebCoreSupport/WebCookieJar.h delete mode 100644 WebKit/android/WebCoreSupport/WebRequest.cpp delete mode 100644 WebKit/android/WebCoreSupport/WebRequest.h delete mode 100644 WebKit/android/WebCoreSupport/WebRequestContext.cpp delete mode 100644 WebKit/android/WebCoreSupport/WebRequestContext.h delete mode 100644 WebKit/android/WebCoreSupport/WebResourceRequest.cpp delete mode 100644 WebKit/android/WebCoreSupport/WebResourceRequest.h delete mode 100644 WebKit/android/WebCoreSupport/WebResponse.cpp delete mode 100644 WebKit/android/WebCoreSupport/WebResponse.h delete mode 100644 WebKit/android/WebCoreSupport/WebUrlLoader.cpp delete mode 100644 WebKit/android/WebCoreSupport/WebUrlLoader.h delete mode 100644 WebKit/android/WebCoreSupport/WebUrlLoaderClient.cpp delete mode 100644 WebKit/android/WebCoreSupport/WebUrlLoaderClient.h delete mode 100644 WebKit/android/WebCoreSupport/WebViewClientError.cpp delete mode 100644 WebKit/android/WebCoreSupport/WebViewClientError.h delete mode 100644 WebKit/android/WebCoreSupport/autofill/AutoFillHostAndroid.cpp delete mode 100644 WebKit/android/WebCoreSupport/autofill/AutoFillHostAndroid.h delete mode 100644 WebKit/android/WebCoreSupport/autofill/FormFieldAndroid.cpp delete mode 100644 WebKit/android/WebCoreSupport/autofill/FormFieldAndroid.h delete mode 100644 WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.cpp delete mode 100644 WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.h delete mode 100644 WebKit/android/WebCoreSupport/autofill/MainThreadProxy.cpp delete mode 100644 WebKit/android/WebCoreSupport/autofill/MainThreadProxy.h delete mode 100644 WebKit/android/WebCoreSupport/autofill/StringUtils.h delete mode 100644 WebKit/android/WebCoreSupport/autofill/WebAutoFill.cpp delete mode 100644 WebKit/android/WebCoreSupport/autofill/WebAutoFill.h delete mode 100644 WebKit/android/benchmark/Android.mk delete mode 100644 WebKit/android/benchmark/Intercept.cpp delete mode 100644 WebKit/android/benchmark/Intercept.h delete mode 100644 WebKit/android/benchmark/MyJavaVM.cpp delete mode 100644 WebKit/android/benchmark/MyJavaVM.h delete mode 100644 WebKit/android/benchmark/main.cpp delete mode 100644 WebKit/android/icu/unicode/ucnv.cpp delete mode 100644 WebKit/android/icu/unicode/ucnv.h delete mode 100644 WebKit/android/jni/CacheManager.cpp delete mode 100644 WebKit/android/jni/CookieManager.cpp delete mode 100644 WebKit/android/jni/DeviceMotionAndOrientationManager.cpp delete mode 100644 WebKit/android/jni/DeviceMotionAndOrientationManager.h delete mode 100644 WebKit/android/jni/DeviceMotionClientImpl.cpp delete mode 100644 WebKit/android/jni/DeviceMotionClientImpl.h delete mode 100644 WebKit/android/jni/DeviceOrientationClientImpl.cpp delete mode 100644 WebKit/android/jni/DeviceOrientationClientImpl.h delete mode 100755 WebKit/android/jni/GeolocationPermissionsBridge.cpp delete mode 100644 WebKit/android/jni/JavaBridge.cpp delete mode 100644 WebKit/android/jni/JavaSharedClient.cpp delete mode 100644 WebKit/android/jni/JavaSharedClient.h delete mode 100644 WebKit/android/jni/JniUtil.cpp delete mode 100644 WebKit/android/jni/MIMETypeRegistry.cpp delete mode 100755 WebKit/android/jni/MockGeolocation.cpp delete mode 100644 WebKit/android/jni/PictureSet.cpp delete mode 100644 WebKit/android/jni/PictureSet.h delete mode 100644 WebKit/android/jni/WebCoreFrameBridge.cpp delete mode 100644 WebKit/android/jni/WebCoreFrameBridge.h delete mode 100644 WebKit/android/jni/WebCoreJni.cpp delete mode 100644 WebKit/android/jni/WebCoreJni.h delete mode 100644 WebKit/android/jni/WebCoreJniOnLoad.cpp delete mode 100644 WebKit/android/jni/WebCoreRefObject.h delete mode 100644 WebKit/android/jni/WebCoreResourceLoader.cpp delete mode 100644 WebKit/android/jni/WebCoreResourceLoader.h delete mode 100644 WebKit/android/jni/WebCoreViewBridge.h delete mode 100644 WebKit/android/jni/WebFrameView.cpp delete mode 100644 WebKit/android/jni/WebFrameView.h delete mode 100644 WebKit/android/jni/WebHistory.cpp delete mode 100644 WebKit/android/jni/WebHistory.h delete mode 100644 WebKit/android/jni/WebIconDatabase.cpp delete mode 100644 WebKit/android/jni/WebIconDatabase.h delete mode 100644 WebKit/android/jni/WebSettings.cpp delete mode 100644 WebKit/android/jni/WebStorage.cpp delete mode 100644 WebKit/android/jni/WebViewCore.cpp delete mode 100644 WebKit/android/jni/WebViewCore.h delete mode 100644 WebKit/android/nav/CacheBuilder.cpp delete mode 100644 WebKit/android/nav/CacheBuilder.h delete mode 100644 WebKit/android/nav/CachedColor.cpp delete mode 100644 WebKit/android/nav/CachedColor.h delete mode 100644 WebKit/android/nav/CachedDebug.h delete mode 100644 WebKit/android/nav/CachedFrame.cpp delete mode 100644 WebKit/android/nav/CachedFrame.h delete mode 100644 WebKit/android/nav/CachedHistory.cpp delete mode 100644 WebKit/android/nav/CachedHistory.h delete mode 100644 WebKit/android/nav/CachedInput.cpp delete mode 100644 WebKit/android/nav/CachedInput.h delete mode 100644 WebKit/android/nav/CachedLayer.cpp delete mode 100644 WebKit/android/nav/CachedLayer.h delete mode 100644 WebKit/android/nav/CachedNode.cpp delete mode 100644 WebKit/android/nav/CachedNode.h delete mode 100644 WebKit/android/nav/CachedNodeType.h delete mode 100644 WebKit/android/nav/CachedPrefix.h delete mode 100644 WebKit/android/nav/CachedRoot.cpp delete mode 100644 WebKit/android/nav/CachedRoot.h delete mode 100644 WebKit/android/nav/DrawExtra.h delete mode 100644 WebKit/android/nav/FindCanvas.cpp delete mode 100644 WebKit/android/nav/FindCanvas.h delete mode 100644 WebKit/android/nav/ParseCanvas.h delete mode 100644 WebKit/android/nav/SelectText.cpp delete mode 100644 WebKit/android/nav/SelectText.h delete mode 100644 WebKit/android/nav/WebView.cpp delete mode 100644 WebKit/android/plugins/ANPBitmapInterface.cpp delete mode 100644 WebKit/android/plugins/ANPCanvasInterface.cpp delete mode 100644 WebKit/android/plugins/ANPEventInterface.cpp delete mode 100644 WebKit/android/plugins/ANPKeyCodes.h delete mode 100644 WebKit/android/plugins/ANPLogInterface.cpp delete mode 100644 WebKit/android/plugins/ANPMatrixInterface.cpp delete mode 100644 WebKit/android/plugins/ANPOpenGLInterface.cpp delete mode 100644 WebKit/android/plugins/ANPOpenGL_npapi.h delete mode 100644 WebKit/android/plugins/ANPPaintInterface.cpp delete mode 100644 WebKit/android/plugins/ANPPathInterface.cpp delete mode 100644 WebKit/android/plugins/ANPSoundInterface.cpp delete mode 100644 WebKit/android/plugins/ANPSurfaceInterface.cpp delete mode 100644 WebKit/android/plugins/ANPSurface_npapi.h delete mode 100644 WebKit/android/plugins/ANPSystemInterface.cpp delete mode 100644 WebKit/android/plugins/ANPSystem_npapi.h delete mode 100644 WebKit/android/plugins/ANPTypefaceInterface.cpp delete mode 100644 WebKit/android/plugins/ANPVideoInterface.cpp delete mode 100644 WebKit/android/plugins/ANPVideo_npapi.h delete mode 100644 WebKit/android/plugins/ANPWindowInterface.cpp delete mode 100644 WebKit/android/plugins/PluginDebugAndroid.cpp delete mode 100644 WebKit/android/plugins/PluginDebugAndroid.h delete mode 100644 WebKit/android/plugins/PluginTimer.cpp delete mode 100644 WebKit/android/plugins/PluginTimer.h delete mode 100644 WebKit/android/plugins/PluginViewBridgeAndroid.cpp delete mode 100644 WebKit/android/plugins/PluginViewBridgeAndroid.h delete mode 100644 WebKit/android/plugins/PluginWidgetAndroid.cpp delete mode 100644 WebKit/android/plugins/PluginWidgetAndroid.h delete mode 100644 WebKit/android/plugins/SkANP.cpp delete mode 100644 WebKit/android/plugins/SkANP.h delete mode 100644 WebKit/android/plugins/SurfaceCallback.h delete mode 100644 WebKit/android/plugins/android_npapi.h delete mode 100644 WebKit/android/smoke/MessageThread.cpp delete mode 100644 WebKit/android/smoke/MessageThread.h delete mode 100644 WebKit/android/smoke/MessageTypes.h delete mode 100644 WebKit/android/wds/Command.cpp delete mode 100644 WebKit/android/wds/Command.h delete mode 100644 WebKit/android/wds/Connection.cpp delete mode 100644 WebKit/android/wds/Connection.h delete mode 100644 WebKit/android/wds/DebugServer.cpp delete mode 100644 WebKit/android/wds/DebugServer.h delete mode 100644 WebKit/android/wds/client/AdbConnection.cpp delete mode 100644 WebKit/android/wds/client/AdbConnection.h delete mode 100644 WebKit/android/wds/client/Android.mk delete mode 100644 WebKit/android/wds/client/ClientUtils.cpp delete mode 100644 WebKit/android/wds/client/ClientUtils.h delete mode 100644 WebKit/android/wds/client/Device.cpp delete mode 100644 WebKit/android/wds/client/Device.h delete mode 100644 WebKit/android/wds/client/DeviceList.h delete mode 100644 WebKit/android/wds/client/main.cpp diff --git a/Source/WebKit/Android.mk b/Source/WebKit/Android.mk new file mode 100644 index 0000000..5998227 --- /dev/null +++ b/Source/WebKit/Android.mk @@ -0,0 +1,132 @@ +## +## +## Copyright 2008, The Android Open Source Project +## +## Licensed under the Apache License, Version 2.0 (the "License"); +## you may not use this file except in compliance with the License. +## You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## + +LOCAL_SRC_FILES := \ + android/WebCoreSupport/CachedFramePlatformDataAndroid.cpp \ + android/WebCoreSupport/ChromeClientAndroid.cpp \ + android/WebCoreSupport/ContextMenuClientAndroid.cpp \ + android/WebCoreSupport/DeviceMotionClientAndroid.cpp \ + android/WebCoreSupport/DeviceOrientationClientAndroid.cpp \ + android/WebCoreSupport/DragClientAndroid.cpp \ + android/WebCoreSupport/EditorClientAndroid.cpp \ + android/WebCoreSupport/FrameLoaderClientAndroid.cpp \ + android/WebCoreSupport/FrameNetworkingContextAndroid.cpp \ + android/WebCoreSupport/GeolocationPermissions.cpp \ + android/WebCoreSupport/MediaPlayerPrivateAndroid.cpp \ + android/WebCoreSupport/MemoryUsage.cpp \ + android/WebCoreSupport/PlatformBridge.cpp \ + android/WebCoreSupport/ResourceLoaderAndroid.cpp \ + android/WebCoreSupport/UrlInterceptResponse.cpp \ + android/WebCoreSupport/V8Counters.cpp + +ifeq ($(HTTP_STACK),chrome) +LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \ + android/WebCoreSupport/ChromiumInit.cpp \ + android/WebCoreSupport/CacheResult.cpp \ + android/WebCoreSupport/WebCache.cpp \ + android/WebCoreSupport/WebCookieJar.cpp \ + android/WebCoreSupport/WebUrlLoader.cpp \ + android/WebCoreSupport/WebUrlLoaderClient.cpp \ + android/WebCoreSupport/WebRequest.cpp \ + android/WebCoreSupport/WebRequestContext.cpp \ + android/WebCoreSupport/WebResourceRequest.cpp \ + android/WebCoreSupport/WebResponse.cpp \ + android/WebCoreSupport/WebViewClientError.cpp +endif # HTTP_STACK == chrome + +LOCAL_SRC_FILES := $(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/jni/CacheManager.cpp \ + android/jni/CookieManager.cpp \ + android/jni/DeviceMotionAndOrientationManager.cpp \ + android/jni/DeviceMotionClientImpl.cpp \ + android/jni/DeviceOrientationClientImpl.cpp \ + 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 \ + android/jni/WebStorage.cpp \ + android/jni/WebSettings.cpp \ + android/jni/WebViewCore.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/SelectText.cpp \ + android/nav/WebView.cpp \ + \ + android/plugins/ANPBitmapInterface.cpp \ + android/plugins/ANPCanvasInterface.cpp \ + android/plugins/ANPEventInterface.cpp \ + android/plugins/ANPLogInterface.cpp \ + android/plugins/ANPMatrixInterface.cpp \ + android/plugins/ANPOpenGLInterface.cpp \ + android/plugins/ANPPaintInterface.cpp \ + android/plugins/ANPPathInterface.cpp \ + android/plugins/ANPSoundInterface.cpp \ + android/plugins/ANPSurfaceInterface.cpp \ + android/plugins/ANPSystemInterface.cpp \ + android/plugins/ANPTypefaceInterface.cpp \ + android/plugins/ANPVideoInterface.cpp \ + android/plugins/ANPWindowInterface.cpp \ + android/plugins/PluginDebugAndroid.cpp \ + android/plugins/PluginTimer.cpp \ + android/plugins/PluginViewBridgeAndroid.cpp \ + android/plugins/PluginWidgetAndroid.cpp \ + android/plugins/SkANP.cpp \ + \ + android/wds/Command.cpp \ + android/wds/Connection.cpp \ + android/wds/DebugServer.cpp + +# Needed for autofill. +ifeq ($(ENABLE_AUTOFILL),true) +LOCAL_CFLAGS += -DENABLE_WEB_AUTOFILL + +LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \ + android/WebCoreSupport/autofill/AutoFillHostAndroid.cpp \ + android/WebCoreSupport/autofill/FormFieldAndroid.cpp \ + android/WebCoreSupport/autofill/FormManagerAndroid.cpp \ + android/WebCoreSupport/autofill/WebAutoFill.cpp +endif # ENABLE_AUTOFILL == true diff --git a/Source/WebKit/android/AndroidLog.h b/Source/WebKit/android/AndroidLog.h new file mode 100644 index 0000000..a69dce6 --- /dev/null +++ b/Source/WebKit/android/AndroidLog.h @@ -0,0 +1,48 @@ +/* + * 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 ANDROIDLOG_H_ +#define ANDROIDLOG_H_ + +#ifdef ANDROID_DOM_LOGGING +#include +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__); } + +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__); } +#else +#define DUMP_DOM_LOGD(...) ((void)0) +#define DUMP_RENDER_LOGD(...) ((void)0) +#endif /* ANDROID_DOM_LOGGING */ + +#define DISPLAY_TREE_LOG_FILE "/sdcard/displayTree.txt" +#define LAYERS_TREE_LOG_FILE "/sdcard/layersTree.plist" + +#endif /* ANDROIDLOG_H_ */ diff --git a/Source/WebKit/android/JavaVM/jni.h b/Source/WebKit/android/JavaVM/jni.h new file mode 100644 index 0000000..da02603 --- /dev/null +++ b/Source/WebKit/android/JavaVM/jni.h @@ -0,0 +1,32 @@ +/* + * 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 _JNI_COVER_H_ +#define _JNI_COVER_H_ + +#include "nativehelper/jni.h" +#define AttachCurrentThread(a, b) AttachCurrentThread((JNIEnv**) a, b) + +#endif diff --git a/Source/WebKit/android/RenderSkinAndroid.cpp b/Source/WebKit/android/RenderSkinAndroid.cpp new file mode 100644 index 0000000..9383a9c --- /dev/null +++ b/Source/WebKit/android/RenderSkinAndroid.cpp @@ -0,0 +1,73 @@ +/* + * 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 "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" + +namespace WebCore { + +RenderSkinAndroid::~RenderSkinAndroid() +{ + delete m_button; +} +RenderSkinAndroid::RenderSkinAndroid(android::AssetManager* am, String drawableDirectory) +{ + m_button = new RenderSkinButton(am, drawableDirectory); + RenderSkinCombo::Init(am, drawableDirectory); + RenderSkinMediaButton::Init(am, drawableDirectory); + RenderSkinRadio::Init(am, drawableDirectory); +} + +bool RenderSkinAndroid::DecodeBitmap(android::AssetManager* am, const char* fileName, SkBitmap* bitmap) +{ + android::Asset* asset = am->open(fileName, android::Asset::ACCESS_BUFFER); + if (!asset) { + asset = am->openNonAsset(fileName, android::Asset::ACCESS_BUFFER); + if (!asset) { + LOGD("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); + } + + delete asset; + return success; +} + +} // namespace WebCore diff --git a/Source/WebKit/android/RenderSkinAndroid.h b/Source/WebKit/android/RenderSkinAndroid.h new file mode 100644 index 0000000..73773ea --- /dev/null +++ b/Source/WebKit/android/RenderSkinAndroid.h @@ -0,0 +1,74 @@ +/* + * 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 RenderSkinAndroid_h +#define RenderSkinAndroid_h + +#include "PlatformString.h" + +namespace android { + class AssetManager; +} + +class SkBitmap; + +namespace WebCore { +class Node; +class RenderSkinButton; + +class RenderSkinAndroid +{ +public: + enum State { + kDisabled, + kNormal, + kFocused, + kPressed, + + kNumStates + }; + + /** + * Initialize the Android skinning system. The AssetManager may be used to find resources used + * in rendering. + */ + RenderSkinAndroid(android::AssetManager*, String drawableDirectory); + ~RenderSkinAndroid(); + + /* DecodeBitmap determines which file to use, with the given fileName of the form + * "images/bitmap.png", and uses the asset manager to select the exact one. It + * returns true if it successfully decoded the bitmap, false otherwise. + */ + static bool DecodeBitmap(android::AssetManager* am, const char* fileName, SkBitmap* bitmap); + + const RenderSkinButton* renderSkinButton() const { return m_button; } + +private: + RenderSkinButton* m_button; +}; + +} // WebCore + +#endif diff --git a/Source/WebKit/android/RenderSkinButton.cpp b/Source/WebKit/android/RenderSkinButton.cpp new file mode 100644 index 0000000..6a0ae54 --- /dev/null +++ b/Source/WebKit/android/RenderSkinButton.cpp @@ -0,0 +1,90 @@ +/* + * 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 +#include +#include +#include +#include +#include + +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(android::AssetManager* am, String drawableDirectory) +{ + m_decoded = true; + for (size_t i = 0; i < 4; i++) { + String path = String(drawableDirectory.impl()); + path.append(String(gFiles[i])); + if (!RenderSkinNinePatch::decodeAsset(am, path.utf8().data(), &m_buttons[i])) { + m_decoded = false; + LOGE("RenderSkinButton::Init: button assets failed to decode\n\tBrowser buttons will not draw"); + return; + } + } + + // 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::draw(SkCanvas* canvas, const IntRect& r, + RenderSkinAndroid::State newState) const +{ + // 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(newState) < + static_cast(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 new file mode 100644 index 0000000..e9db74c --- /dev/null +++ b/Source/WebKit/android/RenderSkinButton.h @@ -0,0 +1,55 @@ +/* + * 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: + /** + * Initialize the class before use. Uses the AssetManager to initialize any + * bitmaps the class may use. + */ + RenderSkinButton(android::AssetManager*, 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) const; +private: + bool m_decoded; + NinePatch m_buttons[4]; +}; + +} // WebCore +#endif diff --git a/Source/WebKit/android/RenderSkinCombo.cpp b/Source/WebKit/android/RenderSkinCombo.cpp new file mode 100644 index 0000000..b30dc29 --- /dev/null +++ b/Source/WebKit/android/RenderSkinCombo.cpp @@ -0,0 +1,146 @@ +/* + * 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 + +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 +}; + +// There are 2.5 different concepts of a 'border' here, which results +// in rather a lot of magic constants. In each case, there are 2 +// numbers, one for medium res and one for high-res. All sizes are in pixels. + +// 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[2] = {22, 34}; +const int RenderSkinCombo::padMargin[2] = {2, 5}; + +// 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. +static const int stretchMargin[2] = {3, 5}; // border width for the bottom and left of the 9-patch +static const int stretchTop[2] = {15, 23}; // border width for the top of the 9-patch + +// 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. +static const int arrowWidth[2] = {22, 31}; + +RenderSkinCombo::Resolution RenderSkinCombo::resolution = MedRes; + +const SkIRect RenderSkinCombo::margin[2][2] = {{{ stretchMargin[MedRes], stretchTop[MedRes], + RenderSkinCombo::arrowMargin[MedRes] + stretchMargin[MedRes], stretchMargin[MedRes] }, + {0, stretchTop[MedRes], 0, stretchMargin[MedRes]}}, + {{ stretchMargin[HighRes], stretchTop[HighRes], + RenderSkinCombo::arrowMargin[HighRes] + stretchMargin[HighRes], stretchMargin[HighRes] }, + {0, stretchTop[HighRes], 0, stretchMargin[HighRes]}}}; +static SkBitmap bitmaps[2][2]; // Collection of assets for a combo box +static bool isDecoded; // True if all assets were decoded + +void RenderSkinCombo::Init(android::AssetManager* am, String drawableDirectory) +{ + if (isDecoded) + return; + + if (drawableDirectory[drawableDirectory.length() - 5] == 'h') + resolution = HighRes; + + 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[resolution], 0, width, height); + bitmaps[kNormal][FullAsset].extractSubset(&bitmaps[kNormal][NoBorder], subset); + bitmaps[kDisabled][FullAsset].extractSubset(&bitmaps[kDisabled][NoBorder], subset); +} + + +bool RenderSkinCombo::Draw(SkCanvas* canvas, Node* element, int x, int y, int width, int height) +{ + if (!isDecoded) + return true; + + State state = (element->isElementNode() && static_cast(element)->isEnabledFormControl()) ? kNormal : kDisabled; + height = std::max(height, (stretchMargin[resolution]<<1) + 1); + + 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; + } + SkNinePatch::DrawNine(canvas, bounds, bitmaps[state][drawBorder], margin[resolution][drawBorder]); + return false; +} + +} //WebCore diff --git a/Source/WebKit/android/RenderSkinCombo.h b/Source/WebKit/android/RenderSkinCombo.h new file mode 100644 index 0000000..38cd048 --- /dev/null +++ b/Source/WebKit/android/RenderSkinCombo.h @@ -0,0 +1,69 @@ +/* + * 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: + /** + * Initialize the class before use. Uses the AssetManager to initialize any bitmaps the class may use. + */ + static void Init(android::AssetManager*, String drawableDirectory); + + /** + * 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[resolution]; } + static int padding() { return padMargin[resolution]; } + + enum Resolution { + MedRes, + HighRes + }; +private: + static Resolution resolution; + const static int arrowMargin[2]; + const static int padMargin[2]; + const static SkIRect margin[2][2]; +}; + +} // WebCore + +#endif diff --git a/Source/WebKit/android/RenderSkinMediaButton.cpp b/Source/WebKit/android/RenderSkinMediaButton.cpp new file mode 100644 index 0000000..090d55e --- /dev/null +++ b/Source/WebKit/android/RenderSkinMediaButton.cpp @@ -0,0 +1,215 @@ +/* + * 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. + */ + +#define LOG_TAG "WebCore" + +#include "config.h" +#include "android_graphics.h" +#include "Document.h" +#include "IntRect.h" +#include "Node.h" +#include "RenderObject.h" +#include "RenderSkinMediaButton.h" +#include "RenderSlider.h" +#include "SkCanvas.h" +#include "SkNinePatch.h" +#include "SkRect.h" +#include +#include +#include + +struct PatchData { + const char* name; + int8_t outset, margin; +}; + +static const PatchData gFiles[] = + { + { "scrubber_primary_holo.9.png", 0, 0 }, // SLIDER_TRACK, left of the SLIDER_THUMB + { "ic_media_pause.png", 0, 0}, // PAUSE + { "ic_media_play.png", 0, 0 }, // PLAY + { "ic_media_pause.png", 0, 0 }, // MUTE + { "ic_media_rew.png", 0, 0 }, // REWIND + { "ic_media_ff.png", 0, 0 }, // FORWARD + { "ic_media_fullscreen.png", 0, 0 }, // FULLSCREEN + { "spinner_76_outer_holo.png", 0, 0 }, // SPINNER_OUTER + { "spinner_76_inner_holo.png", 0, 0 }, // SPINNER_INNER + { "ic_media_video_poster.png", 0, 0 }, // VIDEO + { "btn_media_player_disabled.9.png", 0, 0 }, // BACKGROUND_SLIDER + { "scrubber_track_holo_dark.9.png", 0, 0 }, // SLIDER_TRACK + { "scrubber_control_holo.png", 0, 0 } // SLIDER_THUMB + }; + +static SkBitmap gButton[sizeof(gFiles)/sizeof(gFiles[0])]; +static bool gDecoded; +static bool gHighRes; + +namespace WebCore { + +void RenderSkinMediaButton::Init(android::AssetManager* am, String drawableDirectory) +{ + static bool gInited; + if (gInited) + return; + + gInited = true; + gDecoded = true; + gHighRes = drawableDirectory[drawableDirectory.length() - 5] == 'h'; + for (size_t i = 0; i < sizeof(gFiles)/sizeof(gFiles[0]); i++) { + String path = drawableDirectory + gFiles[i].name; + if (!RenderSkinAndroid::DecodeBitmap(am, path.utf8().data(), &gButton[i])) { + gDecoded = false; + LOGD("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) +{ + // 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 (!gDecoded) { + return; + } + + bool drawsNinePatch = false; + bool drawsImage = true; + bool drawsBackgroundColor = true; + + int ninePatchIndex = 0; + int imageIndex = 0; + + SkRect bounds(r); + SkScalar imageMargin = 8; + SkPaint paint; + + int alpha = 255; + if (translucent) + alpha = 190; + + SkColor backgroundColor = SkColorSetARGB(alpha, 34, 34, 34); + SkColor trackBackgroundColor = SkColorSetARGB(255, 100, 100, 100); + paint.setColor(backgroundColor); + paint.setFlags(SkPaint::kFilterBitmap_Flag); + + switch (buttonType) { + case PAUSE: + case PLAY: + case MUTE: + case REWIND: + case FORWARD: + case FULLSCREEN: + { + imageIndex = buttonType + 1; + paint.setColor(backgroundColor); + break; + } + case SPINNER_OUTER: + case SPINNER_INNER: + case VIDEO: + { + drawsBackgroundColor = false; + imageIndex = buttonType + 1; + break; + } + case BACKGROUND_SLIDER: + { + drawsBackgroundColor = false; + drawsImage = false; + break; + } + case SLIDER_TRACK: + { + drawsNinePatch = true; + drawsImage = false; + ninePatchIndex = buttonType + 1; + break; + } + case SLIDER_THUMB: + { + drawsBackgroundColor = false; + imageMargin = 0; + imageIndex = buttonType + 1; + break; + } + default: + return; + } + + if (drawsBackgroundColor) { + canvas->drawRect(r, paint); + } + + if (drawsNinePatch) { + const PatchData& pd = gFiles[ninePatchIndex]; + int marginValue = pd.margin + pd.outset; + + SkIRect margin; + margin.set(marginValue, marginValue, marginValue, marginValue); + if (buttonType == SLIDER_TRACK) { + // Cut the height in half (with some extra slop determined by trial + // and error to get the placement just right. + SkScalar quarterHeight = SkScalarHalf(SkScalarHalf(bounds.height())); + bounds.fTop += quarterHeight + SkScalarHalf(3); + bounds.fBottom += -quarterHeight + SK_ScalarHalf; + if (o && o->isSlider()) { + RenderSlider* slider = toRenderSlider(o); + IntRect thumb = slider->thumbRect(); + // Inset the track by half the width of the thumb, so the track + // does not appear to go beyond the space where the thumb can + // be. + SkScalar thumbHalfWidth = SkIntToScalar(thumb.width()/2); + bounds.fLeft += thumbHalfWidth; + bounds.fRight -= thumbHalfWidth; + if (thumb.x() > 0) { + // The video is past the starting point. Show the area to + // left of the thumb as having been played. + SkScalar alreadyPlayed = SkIntToScalar(thumb.center().x() + r.x()); + SkRect playedRect(bounds); + playedRect.fRight = alreadyPlayed; + SkNinePatch::DrawNine(canvas, playedRect, gButton[0], margin); + bounds.fLeft = alreadyPlayed; + } + + } + } + SkNinePatch::DrawNine(canvas, bounds, gButton[ninePatchIndex], margin); + } + + if (drawsImage) { + SkScalar SIZE = gButton[imageIndex].width(); + SkScalar width = r.width(); + SkScalar scale = SkScalarDiv(width - 2*imageMargin, SIZE); + int saveScaleCount = canvas->save(); + canvas->translate(bounds.fLeft + imageMargin, bounds.fTop + imageMargin); + canvas->scale(scale, scale); + canvas->drawBitmap(gButton[imageIndex], 0, 0, &paint); + canvas->restoreToCount(saveScaleCount); + } +} + +} // WebCore diff --git a/Source/WebKit/android/RenderSkinMediaButton.h b/Source/WebKit/android/RenderSkinMediaButton.h new file mode 100644 index 0000000..6aa9c4e --- /dev/null +++ b/Source/WebKit/android/RenderSkinMediaButton.h @@ -0,0 +1,63 @@ +/* + * 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 RenderSkinMediaButton_h +#define RenderSkinMediaButton_h + +#include "RenderSkinAndroid.h" + +class SkCanvas; + +namespace WebCore { +class IntRect; +class RenderObject; + +class RenderSkinMediaButton { +public: + /** + * Initialize the class before use. Uses the AssetManager to initialize any + * bitmaps the class may use. + */ + static void Init(android::AssetManager*, 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. + */ + static void Draw(SkCanvas* , const IntRect& , int buttonType, bool translucent = false, + RenderObject* o = 0); + /** + * Button types + */ + enum { PAUSE, PLAY, MUTE, REWIND, FORWARD, FULLSCREEN, SPINNER_OUTER, SPINNER_INNER , VIDEO, BACKGROUND_SLIDER, SLIDER_TRACK, SLIDER_THUMB }; + /** + * Slider dimensions + */ + static int sliderThumbWidth() { return 32; } + static int sliderThumbHeight() { return 32; } + +}; + +} // WebCore +#endif // RenderSkinMediaButton_h diff --git a/Source/WebKit/android/RenderSkinNinePatch.cpp b/Source/WebKit/android/RenderSkinNinePatch.cpp new file mode 100644 index 0000000..0c915c0 --- /dev/null +++ b/Source/WebKit/android/RenderSkinNinePatch.cpp @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "config.h" + +#include "RenderSkinNinePatch.h" +#include "NinePatchPeeker.h" +#include "SkCanvas.h" +#include "SkImageDecoder.h" +#include "SkRect.h" +#include "SkStream.h" +#include "SkTemplates.h" +#include +#include +#include +#include + +class SkPaint; +class SkRegion; + +using namespace android; + +extern void NinePatch_Draw(SkCanvas* canvas, const SkRect& bounds, + const SkBitmap& bitmap, const Res_png_9patch& chunk, + const SkPaint* paint, SkRegion** outRegion); + +bool RenderSkinNinePatch::decodeAsset(AssetManager* am, const char* filename, NinePatch* ninepatch) { + Asset* asset = am->open(filename, android::Asset::ACCESS_BUFFER); + if (!asset) { + asset = am->openNonAsset(filename, android::Asset::ACCESS_BUFFER); + if (!asset) { + return false; + } + } + + SkImageDecoder::Mode mode = SkImageDecoder::kDecodePixels_Mode; + SkBitmap::Config prefConfig = SkBitmap::kNo_Config; + SkStream* stream = new SkMemoryStream(asset->getBuffer(false), asset->getLength()); + SkImageDecoder* decoder = SkImageDecoder::Factory(stream); + if (!decoder) { + asset->close(); + LOGE("RenderSkinNinePatch::Failed to create an image decoder"); + return false; + } + + decoder->setSampleSize(1); + decoder->setDitherImage(true); + decoder->setPreferQualityOverSpeed(false); + + NinePatchPeeker peeker(decoder); + + SkAutoTDelete add(decoder); + + decoder->setPeeker(&peeker); + if (!decoder->decode(stream, &ninepatch->m_bitmap, prefConfig, mode, true)) { + asset->close(); + LOGE("RenderSkinNinePatch::Failed to decode nine patch asset"); + return false; + } + + asset->close(); + if (!peeker.fPatchIsValid) { + LOGE("RenderSkinNinePatch::Patch data not valid"); + return false; + } + void** data = &ninepatch->m_serializedPatchData; + *data = malloc(peeker.fPatch->serializedSize()); + peeker.fPatch->serialize(*data); + return true; +} + +void RenderSkinNinePatch::DrawNinePatch(SkCanvas* canvas, const SkRect& bounds, + const NinePatch& patch) { + Res_png_9patch* data = Res_png_9patch::deserialize(patch.m_serializedPatchData); + NinePatch_Draw(canvas, bounds, patch.m_bitmap, *data, 0, 0); +} diff --git a/Source/WebKit/android/RenderSkinNinePatch.h b/Source/WebKit/android/RenderSkinNinePatch.h new file mode 100644 index 0000000..e4db260 --- /dev/null +++ b/Source/WebKit/android/RenderSkinNinePatch.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef RenderSkinNinePatch_h +#define RenderSkinNinePatch_h + +#include "SkBitmap.h" +#include "utils/Asset.h" + +namespace android { + class AssetManager; +} + +class SkCanvas; +class SkRect; + +struct NinePatch { + SkBitmap m_bitmap; + void* m_serializedPatchData; + NinePatch() { + m_serializedPatchData = 0; + } + ~NinePatch() { + if (m_serializedPatchData) + free(m_serializedPatchData); + } +}; + +class RenderSkinNinePatch { +public: + static bool decodeAsset(android::AssetManager*, const char* fileName, NinePatch*); + static void DrawNinePatch(SkCanvas*, const SkRect&, const NinePatch&); +}; + +#endif // RenderSkinNinePatch_h diff --git a/Source/WebKit/android/RenderSkinRadio.cpp b/Source/WebKit/android/RenderSkinRadio.cpp new file mode 100644 index 0000000..5dfee4a --- /dev/null +++ b/Source/WebKit/android/RenderSkinRadio.cpp @@ -0,0 +1,100 @@ +/* + * 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 + +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 SIZE; + +namespace WebCore { + +static SkBitmap s_bitmap[4]; +static bool s_decoded; + +void RenderSkinRadio::Init(android::AssetManager* am, String drawableDirectory) +{ + if (s_decoded) + return; + String path = drawableDirectory + checks[0]; + s_decoded = RenderSkinAndroid::DecodeBitmap(am, path.utf8().data(), &s_bitmap[0]); + path = drawableDirectory + checks[1]; + s_decoded = RenderSkinAndroid::DecodeBitmap(am, path.utf8().data(), &s_bitmap[1]) && s_decoded; + path = drawableDirectory + checks[2]; + s_decoded = RenderSkinAndroid::DecodeBitmap(am, path.utf8().data(), &s_bitmap[2]) && s_decoded; + path = drawableDirectory + checks[3]; + s_decoded = RenderSkinAndroid::DecodeBitmap(am, path.utf8().data(), &s_bitmap[3]) && s_decoded; + SIZE = SkIntToScalar(s_bitmap[0].width()); +} + +void RenderSkinRadio::Draw(SkCanvas* canvas, Node* element, const IntRect& ir, + bool isCheckBox) +{ + if (!s_decoded || !element) { + 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)->isEnabledFormControl()) { + paint.setAlpha(0x80); + } + SkScalar width = r.width(); + SkScalar scale = SkScalarDiv(width, SIZE); + saveScaleCount = canvas->save(); + canvas->translate(r.fLeft, r.fTop); + canvas->scale(scale, scale); + + bool checked = false; + if (InputElement* inputElement = toInputElement(static_cast(element))) { + checked = inputElement->isChecked(); + } + + canvas->drawBitmap(s_bitmap[checked + 2*(!isCheckBox)], + 0, 0, &paint); + canvas->restoreToCount(saveScaleCount); +} + +} //WebCore diff --git a/Source/WebKit/android/RenderSkinRadio.h b/Source/WebKit/android/RenderSkinRadio.h new file mode 100644 index 0000000..f77e1be --- /dev/null +++ b/Source/WebKit/android/RenderSkinRadio.h @@ -0,0 +1,61 @@ +/* + * 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 RenderSkinRadio_h +#define RenderSkinRadio_h + +#include "PlatformString.h" + +class SkCanvas; + +namespace android { + class AssetManager; +} + +namespace WebCore { + +class Node; +class IntRect; + +/* RenderSkin for a radio button or a checkbox + */ +class RenderSkinRadio +{ +public: + /** + * Initialize the class before use. Uses the AssetManager to initialize any bitmaps the class may use. + */ + static void Init(android::AssetManager*, String drawableDirectory); + + /** + * 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); +}; + +} // WebCore +#endif diff --git a/Source/WebKit/android/TimeCounter.cpp b/Source/WebKit/android/TimeCounter.cpp new file mode 100644 index 0000000..2393f8a --- /dev/null +++ b/Source/WebKit/android/TimeCounter.cpp @@ -0,0 +1,198 @@ +/* + * 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 +#include +#include +#include +#include + +#if USE(JSC) +#include "JSDOMWindow.h" +#include +#include +#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((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((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 new file mode 100644 index 0000000..64908d1 --- /dev/null +++ b/Source/WebKit/android/TimeCounter.h @@ -0,0 +1,120 @@ +/* + * 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 TIME_COUNTER_H +#define TIME_COUNTER_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/TimerClient.h b/Source/WebKit/android/TimerClient.h new file mode 100644 index 0000000..0c3c84c --- /dev/null +++ b/Source/WebKit/android/TimerClient.h @@ -0,0 +1,42 @@ +/* + * 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 TIMER_CLIENT_H +#define TIMER_CLIENT_H + +namespace android { + + class TimerClient + { + public: + virtual ~TimerClient() {} + virtual void setSharedTimerCallback(void(*f)()) = 0; + virtual void setSharedTimer(long long timemillis) = 0; + virtual void stopSharedTimer() = 0; + virtual void signalServiceFuncPtrQueue() = 0; + }; + +} +#endif diff --git a/Source/WebKit/android/WebCoreSupport/CacheResult.cpp b/Source/WebKit/android/WebCoreSupport/CacheResult.cpp new file mode 100644 index 0000000..5309c66 --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/CacheResult.cpp @@ -0,0 +1,251 @@ +/* + * 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 "CacheResult.h" + +#include "WebResponse.h" +#include "WebUrlLoaderClient.h" +#include +#include + +using namespace base; +using namespace disk_cache; +using namespace net; +using namespace std; + +namespace android { + +// All public methods are called on a UI thread but we do work on the +// Chromium thread. However, because we block the WebCore thread while this +// work completes, we can never receive new public method calls while the +// Chromium thread work is in progress. + +// Copied from HttpCache +enum { + kResponseInfoIndex = 0, + kResponseContentIndex +}; + +CacheResult::CacheResult(disk_cache::Entry* entry, String url) + : m_entry(entry) + , m_onResponseHeadersDoneCallback(this, &CacheResult::onResponseHeadersDone) + , m_onReadNextChunkDoneCallback(this, &CacheResult::onReadNextChunkDone) + , m_url(url) +{ + ASSERT(m_entry); +} + +CacheResult::~CacheResult() +{ + m_entry->Close(); + // TODO: Should we also call DoneReadingFromEntry() on the cache for our + // entry? +} + +int64 CacheResult::contentSize() const +{ + // The android stack does not take the content length from the HTTP response + // headers but calculates it when writing the content to disk. It can never + // overflow a long because we limit the cache size. + return m_entry->GetDataSize(kResponseContentIndex); +} + +bool CacheResult::firstResponseHeader(const char* name, String* result, bool allowEmptyString) const +{ + string value; + if (responseHeaders() && responseHeaders()->EnumerateHeader(NULL, name, &value) && (!value.empty() || allowEmptyString)) { + *result = String(value.c_str()); + return true; + } + return false; +} + +String CacheResult::mimeType() const +{ + string mimeType; + if (responseHeaders()) + responseHeaders()->GetMimeType(&mimeType); + if (!mimeType.length() && m_url.length()) + mimeType = WebResponse::resolveMimeType(std::string(m_url.utf8().data(), m_url.length()), ""); + return String(mimeType.c_str()); +} + +int64 CacheResult::expires() const +{ + // We have to do this manually, rather than using HttpResponseHeaders::GetExpiresValue(), + // to handle the "-1" and "0" special cases. + string expiresString; + if (responseHeaders() && responseHeaders()->EnumerateHeader(NULL, "expires", &expiresString)) { + wstring expiresStringWide(expiresString.begin(), expiresString.end()); // inflate ascii + // We require the time expressed as ms since the epoch. + Time time; + if (Time::FromString(expiresStringWide.c_str(), &time)) { + // Will not overflow for a very long time! + return static_cast(1000.0 * time.ToDoubleT()); + } + + if (expiresString == "-1" || expiresString == "0") + return 0; + } + + // TODO + // The Android stack applies a heuristic to set an expiry date if the + // expires header is not set or can't be parsed. I'm not sure whether the Chromium cache + // does this, and if so, it may not be possible for us to get hold of it + // anyway to set it on the result. + return -1; +} + +int CacheResult::responseCode() const +{ + return responseHeaders() ? responseHeaders()->response_code() : 0; +} + +bool CacheResult::writeToFile(const String& filePath) const +{ + // Getting the headers is potentially async, so post to the Chromium thread + // and block here. + MutexLocker lock(m_mutex); + + base::Thread* thread = WebUrlLoaderClient::ioThread(); + if (!thread) + return false; + + CacheResult* me = const_cast(this); + thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(me, &CacheResult::writeToFileImpl)); + + m_filePath = filePath.threadsafeCopy(); + m_isAsyncOperationInProgress = true; + while (m_isAsyncOperationInProgress) + m_condition.wait(m_mutex); + + return m_wasWriteToFileSuccessful; +} + +void CacheResult::writeToFileImpl() +{ + m_bufferSize = m_entry->GetDataSize(kResponseContentIndex); + m_readOffset = 0; + m_wasWriteToFileSuccessful = false; + readNextChunk(); +} + +void CacheResult::readNextChunk() +{ + m_buffer = new IOBuffer(m_bufferSize); + int rv = m_entry->ReadData(kResponseInfoIndex, m_readOffset, m_buffer, m_bufferSize, &m_onReadNextChunkDoneCallback); + if (rv == ERR_IO_PENDING) + return; + + onReadNextChunkDone(rv); +}; + +void CacheResult::onReadNextChunkDone(int size) +{ + if (size > 0) { + // Still more reading to be done. + if (writeChunkToFile()) { + // TODO: I assume that we need to clear and resize the buffer for the next read? + m_readOffset += size; + m_bufferSize -= size; + readNextChunk(); + } else + onWriteToFileDone(); + return; + } + + if (!size) { + // Reached end of file. + if (writeChunkToFile()) + m_wasWriteToFileSuccessful = true; + } + onWriteToFileDone(); +} + +bool CacheResult::writeChunkToFile() +{ + PlatformFileHandle file; + file = openFile(m_filePath, OpenForWrite); + if (!isHandleValid(file)) + return false; + return WebCore::writeToFile(file, m_buffer->data(), m_bufferSize) == m_bufferSize; +} + +void CacheResult::onWriteToFileDone() +{ + MutexLocker lock(m_mutex); + m_isAsyncOperationInProgress = false; + m_condition.signal(); +} + +HttpResponseHeaders* CacheResult::responseHeaders() const +{ + MutexLocker lock(m_mutex); + if (m_responseHeaders) + return m_responseHeaders; + + // Getting the headers is potentially async, so post to the Chromium thread + // and block here. + base::Thread* thread = WebUrlLoaderClient::ioThread(); + if (!thread) + return 0; + + CacheResult* me = const_cast(this); + thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(me, &CacheResult::responseHeadersImpl)); + + m_isAsyncOperationInProgress = true; + while (m_isAsyncOperationInProgress) + m_condition.wait(m_mutex); + + return m_responseHeaders; +} + +void CacheResult::responseHeadersImpl() +{ + m_bufferSize = m_entry->GetDataSize(kResponseInfoIndex); + m_buffer = new IOBuffer(m_bufferSize); + + int rv = m_entry->ReadData(kResponseInfoIndex, 0, m_buffer, m_bufferSize, &m_onResponseHeadersDoneCallback); + if (rv == ERR_IO_PENDING) + return; + + onResponseHeadersDone(rv); +}; + +void CacheResult::onResponseHeadersDone(int size) +{ + MutexLocker lock(m_mutex); + // It's OK to throw away the HttpResponseInfo object as we hold our own ref + // to the headers. + HttpResponseInfo response; + bool truncated = false; // TODO: Waht is this param for? + if (size == m_bufferSize && HttpCache::ParseResponseInfo(m_buffer->data(), m_bufferSize, &response, &truncated)) + m_responseHeaders = response.headers; + m_isAsyncOperationInProgress = false; + m_condition.signal(); +} + +} // namespace android diff --git a/Source/WebKit/android/WebCoreSupport/CacheResult.h b/Source/WebKit/android/WebCoreSupport/CacheResult.h new file mode 100644 index 0000000..c39570c --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/CacheResult.h @@ -0,0 +1,86 @@ +/* + * 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 CacheResult_h +#define CacheResult_h + +#include "ChromiumIncludes.h" + +#include +#include +#include + +namespace android { + +// A wrapper around a disk_cache::Entry. Provides fields appropriate for constructing a Java CacheResult object. +class CacheResult : public base::RefCountedThreadSafe { +public: + // Takes ownership of the Entry passed to the constructor. + CacheResult(disk_cache::Entry*, String url); + ~CacheResult(); + + int64 contentSize() const; + bool firstResponseHeader(const char* name, WTF::String* result, bool allowEmptyString) const; + // The Android stack uses the empty string if no Content-Type headers are + // found, so we use the same default here. + WTF::String mimeType() const; + // Returns the value of the expires header as milliseconds since the epoch. + int64 expires() const; + int responseCode() const; + bool writeToFile(const WTF::String& filePath) const; +private: + net::HttpResponseHeaders* responseHeaders() const; + void responseHeadersImpl(); + void onResponseHeadersDone(int size); + + void writeToFileImpl(); + void readNextChunk(); + void onReadNextChunkDone(int size); + bool writeChunkToFile(); + void onWriteToFileDone(); + + disk_cache::Entry* m_entry; + + scoped_refptr m_responseHeaders; + + int m_readOffset; + bool m_wasWriteToFileSuccessful; + mutable String m_filePath; + + int m_bufferSize; + scoped_refptr m_buffer; + mutable bool m_isAsyncOperationInProgress; + mutable WTF::Mutex m_mutex; + mutable WTF::ThreadCondition m_condition; + + net::CompletionCallbackImpl m_onResponseHeadersDoneCallback; + net::CompletionCallbackImpl m_onReadNextChunkDoneCallback; + + String m_url; +}; + +} // namespace android + +#endif diff --git a/Source/WebKit/android/WebCoreSupport/CachedFramePlatformDataAndroid.cpp b/Source/WebKit/android/WebCoreSupport/CachedFramePlatformDataAndroid.cpp new file mode 100644 index 0000000..30f374f --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/CachedFramePlatformDataAndroid.cpp @@ -0,0 +1,66 @@ +/* + * 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 "config.h" + +#include "CachedFramePlatformDataAndroid.h" +#include "Settings.h" + +namespace android { + +CachedFramePlatformDataAndroid::CachedFramePlatformDataAndroid(WebCore::Settings* settings) +{ +#ifdef ANDROID_META_SUPPORT + m_viewport_width = settings->viewportWidth(); + m_viewport_height = settings->viewportHeight(); + m_viewport_initial_scale = settings->viewportInitialScale(); + m_viewport_minimum_scale = settings->viewportMinimumScale(); + m_viewport_maximum_scale = settings->viewportMaximumScale(); + m_viewport_target_densitydpi = settings->viewportTargetDensityDpi(); + m_viewport_user_scalable = settings->viewportUserScalable(); + m_format_detection_address = settings->formatDetectionAddress(); + m_format_detection_email = settings->formatDetectionEmail(); + m_format_detection_telephone = settings->formatDetectionTelephone(); +#endif + +} + +#ifdef ANDROID_META_SUPPORT +void CachedFramePlatformDataAndroid::restoreMetadata(WebCore::Settings* settings) +{ + settings->setViewportWidth(m_viewport_width); + settings->setViewportHeight(m_viewport_height); + settings->setViewportInitialScale(m_viewport_initial_scale); + settings->setViewportMinimumScale(m_viewport_minimum_scale); + settings->setViewportMaximumScale(m_viewport_maximum_scale); + settings->setViewportTargetDensityDpi(m_viewport_target_densitydpi); + settings->setViewportUserScalable(m_viewport_user_scalable); + settings->setFormatDetectionAddress(m_format_detection_address); + settings->setFormatDetectionEmail(m_format_detection_email); + settings->setFormatDetectionTelephone(m_format_detection_telephone); +} +#endif + +} diff --git a/Source/WebKit/android/WebCoreSupport/CachedFramePlatformDataAndroid.h b/Source/WebKit/android/WebCoreSupport/CachedFramePlatformDataAndroid.h new file mode 100644 index 0000000..20c7be4 --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/CachedFramePlatformDataAndroid.h @@ -0,0 +1,63 @@ +/* + * 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 CachedFramePlatformDatatAndroid_h +#define CachedFramePlatformDatatAndroid_h + +#include "CachedFramePlatformData.h" + +namespace WebCore { + class Settings; +} + +namespace android { + +class CachedFramePlatformDataAndroid : public WebCore::CachedFramePlatformData { +public: + CachedFramePlatformDataAndroid(WebCore::Settings* settings); + +#ifdef ANDROID_META_SUPPORT + void restoreMetadata(WebCore::Settings* settings); +#endif + +private: +#ifdef ANDROID_META_SUPPORT + // meta data of the frame + int m_viewport_width; + int m_viewport_height; + int m_viewport_initial_scale; + int m_viewport_minimum_scale; + int m_viewport_maximum_scale; + int m_viewport_target_densitydpi; + bool m_viewport_user_scalable : 1; + bool m_format_detection_address : 1; + bool m_format_detection_email : 1; + bool m_format_detection_telephone : 1; +#endif +}; + +} + +#endif diff --git a/Source/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp b/Source/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp new file mode 100644 index 0000000..6f872b8 --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp @@ -0,0 +1,605 @@ +/* + * 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. + */ + +#define LOG_TAG "WebCore" + +#include "config.h" + +#include "ApplicationCacheStorage.h" +#include "ChromeClientAndroid.h" +#include "DatabaseTracker.h" +#include "Document.h" +#include "PlatformString.h" +#include "FloatRect.h" +#include "Frame.h" +#include "FrameLoader.h" +#include "FrameView.h" +#include "Geolocation.h" +#include "HTMLMediaElement.h" +#include "HTMLNames.h" +#include "Icon.h" +#include "LayerAndroid.h" +#include "Page.h" +#include "PopupMenuAndroid.h" +#include "ScriptController.h" +#include "SearchPopupMenuAndroid.h" +#include "WebCoreFrameBridge.h" +#include "WebCoreViewBridge.h" +#include "WebViewCore.h" +#include "WindowFeatures.h" +#include "Settings.h" +#include "UserGestureIndicator.h" +#include + +namespace android { + +#if ENABLE(DATABASE) +static unsigned long long tryToReclaimDatabaseQuota(SecurityOrigin* originNeedingQuota); +#endif + +#if USE(ACCELERATED_COMPOSITING) + +WebCore::GraphicsLayer* ChromeClientAndroid::layersSync() +{ + if (m_rootGraphicsLayer && m_needsLayerSync && m_webFrame) { + if (FrameView* frameView = m_webFrame->page()->mainFrame()->view()) + frameView->syncCompositingStateRecursive(); + } + m_needsLayerSync = false; + return m_rootGraphicsLayer; +} + +void ChromeClientAndroid::scheduleCompositingLayerSync() +{ + if (m_needsLayerSync) + return; + m_needsLayerSync = true; + WebViewCore* webViewCore = WebViewCore::getWebViewCore(m_webFrame->page()->mainFrame()->view()); + if (webViewCore) + webViewCore->layersDraw(); +} + +void ChromeClientAndroid::setNeedsOneShotDrawingSynchronization() +{ + // This should not be needed +} + +void ChromeClientAndroid::attachRootGraphicsLayer(WebCore::Frame*, WebCore::GraphicsLayer* layer) +{ + // frame is not used in Android as we should only get root graphics layer for the main frame + m_rootGraphicsLayer = layer; + if (!layer) + return; + scheduleCompositingLayerSync(); +} + +#endif + +void ChromeClientAndroid::setWebFrame(android::WebFrame* webframe) +{ + Release(m_webFrame); + m_webFrame = webframe; + Retain(m_webFrame); +} + +void ChromeClientAndroid::chromeDestroyed() +{ + Release(m_webFrame); + delete this; +} + +void ChromeClientAndroid::setWindowRect(const FloatRect&) { notImplemented(); } + +FloatRect ChromeClientAndroid::windowRect() { + ASSERT(m_webFrame); + if (!m_webFrame) + return FloatRect(); + FrameView* frameView = m_webFrame->page()->mainFrame()->view(); + if (!frameView) + return FloatRect(); + const WebCoreViewBridge* bridge = frameView->platformWidget(); + const IntRect& rect = bridge->getWindowBounds(); + FloatRect fRect(rect.x(), rect.y(), rect.width(), rect.height()); + return fRect; +} + +FloatRect ChromeClientAndroid::pageRect() { notImplemented(); return FloatRect(); } + +float ChromeClientAndroid::scaleFactor() +{ + ASSERT(m_webFrame); + return m_webFrame->density(); +} + +void ChromeClientAndroid::focus() +{ + ASSERT(m_webFrame); + bool isUserGesture = UserGestureIndicator::processingUserGesture(); + + // Ask the application to focus this WebView if the action is intiated by the user + if (isUserGesture) + m_webFrame->requestFocus(); +} +void ChromeClientAndroid::unfocus() { notImplemented(); } + +bool ChromeClientAndroid::canTakeFocus(FocusDirection) { notImplemented(); return false; } +void ChromeClientAndroid::takeFocus(FocusDirection) { notImplemented(); } + +void ChromeClientAndroid::focusedNodeChanged(Node* node) +{ + android::WebViewCore::getWebViewCore(m_webFrame->page()->mainFrame()->view())->focusNodeChanged(node); +} + +void ChromeClientAndroid::focusedFrameChanged(Frame*) { notImplemented(); } + +Page* ChromeClientAndroid::createWindow(Frame* frame, const FrameLoadRequest&, + const WindowFeatures& features, const NavigationAction&) +{ + ASSERT(frame); +#ifdef ANDROID_MULTIPLE_WINDOWS + if (frame->settings() && !(frame->settings()->supportMultipleWindows())) + // If the client doesn't support multiple windows, just return the current page + return frame->page(); +#endif + + const WebCoreViewBridge* bridge = frame->view()->platformWidget(); + bool dialog = features.dialog || !features.resizable + || (features.heightSet && features.height < bridge->height() + && features.widthSet && features.width < bridge->width()) + || (!features.menuBarVisible && !features.statusBarVisible + && !features.toolBarVisible && !features.locationBarVisible + && !features.scrollbarsVisible); + // fullscreen definitely means no dialog + if (features.fullscreen) + dialog = false; + WebCore::Frame* newFrame = m_webFrame->createWindow(dialog, + ScriptController::processingUserGesture()); + if (newFrame) { + WebCore::Page* page = newFrame->page(); + page->setGroupName(frame->page()->groupName()); + return page; + } + return NULL; +} + +void ChromeClientAndroid::show() { notImplemented(); } + +bool ChromeClientAndroid::canRunModal() { notImplemented(); return false; } +void ChromeClientAndroid::runModal() { notImplemented(); } + +void ChromeClientAndroid::setToolbarsVisible(bool) { notImplemented(); } +bool ChromeClientAndroid::toolbarsVisible() { notImplemented(); return false; } + +void ChromeClientAndroid::setStatusbarVisible(bool) { notImplemented(); } +bool ChromeClientAndroid::statusbarVisible() { notImplemented(); return false; } + +void ChromeClientAndroid::setScrollbarsVisible(bool) { notImplemented(); } +bool ChromeClientAndroid::scrollbarsVisible() { notImplemented(); return false; } + +void ChromeClientAndroid::setMenubarVisible(bool) { notImplemented(); } +bool ChromeClientAndroid::menubarVisible() { notImplemented(); return false; } + +void ChromeClientAndroid::setResizable(bool) { notImplemented(); } + +#if ENABLE(CONTEXT_MENUS) +void ChromeClientAndroid::showContextMenu() { notImplemented(); } +#endif + +// This function is called by the JavaScript bindings to print usually an error to +// a message console. Pass the message to the java side so that the client can +// handle it as it sees fit. +void ChromeClientAndroid::addMessageToConsole(MessageSource, MessageType, MessageLevel msgLevel, const String& message, unsigned int lineNumber, const String& sourceID) { + android::WebViewCore::getWebViewCore(m_webFrame->page()->mainFrame()->view())->addMessageToConsole(message, lineNumber, sourceID, msgLevel); +} + +void ChromeClientAndroid::formDidBlur(const WebCore::Node* node) +{ + android::WebViewCore::getWebViewCore(m_webFrame->page()->mainFrame()->view())->formDidBlur(node); +} + +bool ChromeClientAndroid::canRunBeforeUnloadConfirmPanel() { return true; } +bool ChromeClientAndroid::runBeforeUnloadConfirmPanel(const String& message, Frame* frame) { + String url = frame->document()->documentURI(); + return android::WebViewCore::getWebViewCore(frame->view())->jsUnload(url, message); +} + +void ChromeClientAndroid::closeWindowSoon() +{ + ASSERT(m_webFrame); + Page* page = m_webFrame->page(); + Frame* mainFrame = page->mainFrame(); + // This will prevent javascript cross-scripting during unload + page->setGroupName(String()); + // Stop loading but do not send the unload event + mainFrame->loader()->stopLoading(UnloadEventPolicyNone); + // Cancel all pending loaders + mainFrame->loader()->stopAllLoaders(); + // Remove all event listeners so that no javascript can execute as a result + // of mouse/keyboard events. + mainFrame->document()->removeAllEventListeners(); + // Close the window. + m_webFrame->closeWindow(android::WebViewCore::getWebViewCore(mainFrame->view())); +} + +void ChromeClientAndroid::runJavaScriptAlert(Frame* frame, const String& message) +{ + String url = frame->document()->documentURI(); + + android::WebViewCore::getWebViewCore(frame->view())->jsAlert(url, message); +} + +bool ChromeClientAndroid::runJavaScriptConfirm(Frame* frame, const String& message) +{ + String url = frame->document()->documentURI(); + + return android::WebViewCore::getWebViewCore(frame->view())->jsConfirm(url, message); +} + +/* This function is called for the javascript method Window.prompt(). A dialog should be shown on + * the screen with an input put box. First param is the text, the second is the default value for + * the input box, third is return param. If the function returns true, the value set in the third parameter + * is provided to javascript, else null is returned to the script. + */ +bool ChromeClientAndroid::runJavaScriptPrompt(Frame* frame, const String& message, const String& defaultValue, String& result) +{ + String url = frame->document()->documentURI(); + return android::WebViewCore::getWebViewCore(frame->view())->jsPrompt(url, message, defaultValue, result); +} +void ChromeClientAndroid::setStatusbarText(const String&) { notImplemented(); } + +// This is called by the JavaScript interpreter when a script has been running for a long +// time. A dialog should be shown to the user asking them if they would like to cancel the +// Javascript. If true is returned, the script is cancelled. +// To make a device more responsive, we default to return true to disallow long running script. +// This implies that some of scripts will not be completed. +bool ChromeClientAndroid::shouldInterruptJavaScript() { + FrameView* frameView = m_webFrame->page()->mainFrame()->view(); + return android::WebViewCore::getWebViewCore(frameView)->jsInterrupt(); +} + +bool ChromeClientAndroid::tabsToLinks() const { return false; } + +IntRect ChromeClientAndroid::windowResizerRect() const { return IntRect(0, 0, 0, 0); } + +void ChromeClientAndroid::invalidateWindow(const IntRect&, bool) +{ + notImplemented(); +} + +void ChromeClientAndroid::invalidateContentsAndWindow(const IntRect& updateRect, bool /*immediate*/) +{ + notImplemented(); +} + +void ChromeClientAndroid::invalidateContentsForSlowScroll(const IntRect& updateRect, bool immediate) +{ + notImplemented(); +} + +// new to change 38068 (Nov 6, 2008) +void ChromeClientAndroid::scroll(const IntSize& scrollDelta, + const IntRect& rectToScroll, const IntRect& clipRect) { + notImplemented(); +} + +// new to change 38068 (Nov 6, 2008) +IntPoint ChromeClientAndroid::screenToWindow(const IntPoint&) const { + notImplemented(); + return IntPoint(); +} + +// new to change 38068 (Nov 6, 2008) +IntRect ChromeClientAndroid::windowToScreen(const IntRect&) const { + notImplemented(); + return IntRect(); +} + +PlatformPageClient ChromeClientAndroid::platformPageClient() const { + Page* page = m_webFrame->page(); + Frame* mainFrame = page->mainFrame(); + FrameView* view = mainFrame->view(); + PlatformWidget viewBridge = view->platformWidget(); + return viewBridge; +} + +void ChromeClientAndroid::contentsSizeChanged(Frame*, const IntSize&) const +{ + notImplemented(); +} + +void ChromeClientAndroid::scrollRectIntoView(const IntRect&, const ScrollView*) const +{ + notImplemented(); +} + +void ChromeClientAndroid::formStateDidChange(const Node*) +{ + notImplemented(); +} + +void ChromeClientAndroid::scrollbarsModeDidChange() const +{ + notImplemented(); +} + +void ChromeClientAndroid::mouseDidMoveOverElement(const HitTestResult&, unsigned int) {} +void ChromeClientAndroid::setToolTip(const String&, TextDirection) {} +void ChromeClientAndroid::print(Frame*) {} + +/* + * This function is called on the main (webcore) thread by SQLTransaction::deliverQuotaIncreaseCallback. + * The way that the callback mechanism is designed inside SQLTransaction means that there must be a new quota + * (which may be equal to the old quota if the user did not allow more quota) when this function returns. As + * we call into the browser thread to ask what to do with the quota, we block here and get woken up when the + * browser calls the native WebViewCore::SetDatabaseQuota method with the new quota value. + */ +#if ENABLE(DATABASE) +void ChromeClientAndroid::exceededDatabaseQuota(Frame* frame, const String& name) +{ + SecurityOrigin* origin = frame->document()->securityOrigin(); + DatabaseTracker& tracker = WebCore::DatabaseTracker::tracker(); + + // We want to wait on a new quota from the UI thread. Reset the m_newQuota variable to represent we haven't received a new quota. + m_newQuota = -1; + + // This origin is being tracked and has exceeded it's quota. Call into + // the Java side of things to inform the user. + unsigned long long currentQuota = 0; + if (tracker.hasEntryForOrigin(origin)) + currentQuota = tracker.quotaForOrigin(origin); + + unsigned long long estimatedSize = 0; + + // Only update estimatedSize if we are trying to create a a new database, i.e. the usage for the database is 0. + if (tracker.usageForDatabase(name, origin) == 0) + estimatedSize = tracker.detailsForNameAndOrigin(name, origin).expectedUsage(); + + android::WebViewCore::getWebViewCore(frame->view())->exceededDatabaseQuota(frame->document()->documentURI(), name, currentQuota, estimatedSize); + + // We've sent notification to the browser so now wait for it to come back. + m_quotaThreadLock.lock(); + while (m_newQuota == -1) { + m_quotaThreadCondition.wait(m_quotaThreadLock); + } + m_quotaThreadLock.unlock(); + + // If new quota is unavailable, we may be able to resolve the situation by shrinking the quota of an origin that asked for a lot but is only using a little. + // If we find such a site, shrink it's quota and ask Java to try again. + + if ((unsigned long long) m_newQuota == currentQuota && !m_triedToReclaimDBQuota) { + m_triedToReclaimDBQuota = true; // we should only try this once per quota overflow. + unsigned long long reclaimedQuotaBytes = tryToReclaimDatabaseQuota(origin); + + // If we were able to free up enough space, try asking Java again. + // Otherwise, give up and deny the new database. :( + if (reclaimedQuotaBytes >= estimatedSize) { + exceededDatabaseQuota(frame, name); + return; + } + } + + // Update the DatabaseTracker with the new quota value (if the user declined + // new quota, this may equal the old quota) + tracker.setQuota(origin, m_newQuota); + m_triedToReclaimDBQuota = false; +} + +static unsigned long long tryToReclaimDatabaseQuota(SecurityOrigin* originNeedingQuota) { + DatabaseTracker& tracker = WebCore::DatabaseTracker::tracker(); + Vector > origins; + tracker.origins(origins); + unsigned long long reclaimedQuotaBytes = 0; + for (unsigned i = 0; i < origins.size(); i++) { + SecurityOrigin* originToReclaimFrom = origins[i].get(); + + // Don't try to reclaim from the origin that has exceeded its quota. + if (originToReclaimFrom->equal(originNeedingQuota)) + continue; + + unsigned long long originUsage = tracker.usageForOrigin(originToReclaimFrom); + unsigned long long originQuota = tracker.quotaForOrigin(originToReclaimFrom); + // If the origin has a quota that is more than it's current usage +1MB, shrink it. + static const int ONE_MB = 1 * 1024 * 1024; + if (originUsage + ONE_MB < originQuota) { + unsigned long long newQuota = originUsage + ONE_MB; + tracker.setQuota(originToReclaimFrom, newQuota); + reclaimedQuotaBytes += originQuota - newQuota; + } + } + return reclaimedQuotaBytes; +} +#endif + +#if ENABLE(OFFLINE_WEB_APPLICATIONS) +void ChromeClientAndroid::reachedMaxAppCacheSize(int64_t spaceNeeded) +{ + // Set m_newQuota before calling into the Java side. If we do this after, + // we could overwrite the result passed from the Java side and deadlock in the + // wait call below. + m_newQuota = -1; + Page* page = m_webFrame->page(); + Frame* mainFrame = page->mainFrame(); + FrameView* view = mainFrame->view(); + android::WebViewCore::getWebViewCore(view)->reachedMaxAppCacheSize(spaceNeeded); + + // We've sent notification to the browser so now wait for it to come back. + m_quotaThreadLock.lock(); + while (m_newQuota == -1) { + m_quotaThreadCondition.wait(m_quotaThreadLock); + } + m_quotaThreadLock.unlock(); + if (m_newQuota > 0) { + WebCore::cacheStorage().setMaximumSize(m_newQuota); + // Now the app cache will retry the saving the previously failed cache. + } +} +#endif + +void ChromeClientAndroid::populateVisitedLinks() +{ + Page* page = m_webFrame->page(); + Frame* mainFrame = page->mainFrame(); + FrameView* view = mainFrame->view(); + android::WebViewCore::getWebViewCore(view)->populateVisitedLinks(&page->group()); +} + +void ChromeClientAndroid::requestGeolocationPermissionForFrame(Frame* frame, Geolocation* geolocation) +{ + ASSERT(geolocation); + if (!m_geolocationPermissions) { + m_geolocationPermissions = new GeolocationPermissions(android::WebViewCore::getWebViewCore(frame->view()), + m_webFrame->page()->mainFrame()); + } + m_geolocationPermissions->queryPermissionState(frame); +} + +void ChromeClientAndroid::cancelGeolocationPermissionRequestForFrame(Frame* frame, WebCore::Geolocation*) +{ + if (m_geolocationPermissions) + m_geolocationPermissions->cancelPermissionStateQuery(frame); +} + +void ChromeClientAndroid::provideGeolocationPermissions(const String &origin, bool allow, bool remember) +{ + ASSERT(m_geolocationPermissions); + m_geolocationPermissions->providePermissionState(origin, allow, remember); +} + +void ChromeClientAndroid::storeGeolocationPermissions() +{ + GeolocationPermissions::maybeStorePermanentPermissions(); +} + +void ChromeClientAndroid::onMainFrameLoadStarted() +{ + if (m_geolocationPermissions.get()) + m_geolocationPermissions->resetTemporaryPermissionStates(); +} + +void ChromeClientAndroid::runOpenPanel(Frame* frame, + PassRefPtr chooser) +{ + android::WebViewCore* core = android::WebViewCore::getWebViewCore( + frame->view()); + core->openFileChooser(chooser); +} + +void ChromeClientAndroid::chooseIconForFiles(const Vector&, FileChooser*) +{ + notImplemented(); +} + +void ChromeClientAndroid::setCursor(const Cursor&) +{ + notImplemented(); +} + +void ChromeClientAndroid::wakeUpMainThreadWithNewQuota(long newQuota) { + MutexLocker locker(m_quotaThreadLock); + m_newQuota = newQuota; + m_quotaThreadCondition.signal(); +} + +#if ENABLE(TOUCH_EVENTS) +void ChromeClientAndroid::needTouchEvents(bool needTouchEvents) +{ + FrameView* frameView = m_webFrame->page()->mainFrame()->view(); + android::WebViewCore* core = android::WebViewCore::getWebViewCore(frameView); + if (core) + core->needTouchEvents(needTouchEvents); +} +#endif + +bool ChromeClientAndroid::selectItemWritingDirectionIsNatural() +{ + return false; +} + +PassRefPtr ChromeClientAndroid::createPopupMenu(PopupMenuClient* client) const +{ + return adoptRef(new PopupMenuAndroid(static_cast(client))); +} + +PassRefPtr ChromeClientAndroid::createSearchPopupMenu(PopupMenuClient*) const +{ + return adoptRef(new SearchPopupMenuAndroid); +} + +void ChromeClientAndroid::reachedApplicationCacheOriginQuota(SecurityOrigin*) +{ + notImplemented(); +} + +#if ENABLE(ANDROID_INSTALLABLE_WEB_APPS) +void ChromeClientAndroid::webAppCanBeInstalled() +{ + FrameView* frameView = m_webFrame->page()->mainFrame()->view(); + android::WebViewCore* core = android::WebViewCore::getWebViewCore(frameView); + if (core) + core->notifyWebAppCanBeInstalled(); +} +#endif + +#if ENABLE(VIDEO) +bool ChromeClientAndroid::supportsFullscreenForNode(const Node* node) +{ + return node->hasTagName(HTMLNames::videoTag); +} + +void ChromeClientAndroid::enterFullscreenForNode(Node* node) +{ + if (!node->hasTagName(HTMLNames::videoTag)) + return; + + HTMLMediaElement* videoElement = static_cast(node); + String url = videoElement->currentSrc(); + LayerAndroid* layer = videoElement->platformLayer(); + if (!layer) + return; + + FrameView* frameView = m_webFrame->page()->mainFrame()->view(); + android::WebViewCore* core = android::WebViewCore::getWebViewCore(frameView); + m_webFrame->page()->mainFrame()->document()->webkitWillEnterFullScreenForElement(videoElement); + if (core) + core->enterFullscreenForVideoLayer(layer->uniqueId(), url); +} + +void ChromeClientAndroid::exitFullscreenForNode(Node* node) +{ +} +#endif + +#if ENABLE(FULLSCREEN_API) +void ChromeClientAndroid::exitFullScreenForElement(Element* element) +{ + if (!element) + return; + + HTMLMediaElement* videoElement = static_cast(element); + videoElement->exitFullscreen(); +} +#endif + +} diff --git a/Source/WebKit/android/WebCoreSupport/ChromeClientAndroid.h b/Source/WebKit/android/WebCoreSupport/ChromeClientAndroid.h new file mode 100644 index 0000000..d49cec8 --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/ChromeClientAndroid.h @@ -0,0 +1,216 @@ +/* + * 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 ChromeClientAndroid_h +#define ChromeClientAndroid_h + +#include "ChromeClient.h" + +#include "GeolocationPermissions.h" +#include "PopupMenu.h" +#include "SearchPopupMenu.h" +#include "Timer.h" +#include +#include + +namespace WebCore { +class PopupMenuClient; +class Geolocation; +} + +using namespace WebCore; + +namespace android { + class WebFrame; + + class ChromeClientAndroid : public ChromeClient { + public: + ChromeClientAndroid() : m_webFrame(0), m_geolocationPermissions(0) +#if USE(ACCELERATED_COMPOSITING) + , m_rootGraphicsLayer(0) + , m_needsLayerSync(false) +#endif + , m_triedToReclaimDBQuota(false) + { } + virtual void chromeDestroyed(); + + virtual void setWindowRect(const FloatRect&); + virtual FloatRect windowRect(); + + virtual FloatRect pageRect(); + + virtual float scaleFactor(); + + virtual void focus(); + virtual void unfocus(); + virtual void formDidBlur(const WebCore::Node*); + virtual bool canTakeFocus(FocusDirection); + virtual void takeFocus(FocusDirection); + + virtual void focusedNodeChanged(Node*); + virtual void focusedFrameChanged(Frame*); + + // The Frame pointer provides the ChromeClient with context about which + // Frame wants to create the new Page. Also, the newly created window + // should not be shown to the user until the ChromeClient of the newly + // created Page has its show method called. + virtual Page* createWindow(Frame*, const FrameLoadRequest&, const WindowFeatures&, const NavigationAction&); + virtual void show(); + + virtual bool canRunModal(); + virtual void runModal(); + + virtual void setToolbarsVisible(bool); + virtual bool toolbarsVisible(); + + virtual void setStatusbarVisible(bool); + virtual bool statusbarVisible(); + + virtual void setScrollbarsVisible(bool); + virtual bool scrollbarsVisible(); + + virtual void setMenubarVisible(bool); + virtual bool menubarVisible(); + + virtual void setResizable(bool); + + virtual void addMessageToConsole(MessageSource, MessageType, MessageLevel, const String& message, unsigned int lineNumber, const String& sourceID); + + virtual bool canRunBeforeUnloadConfirmPanel(); + virtual bool runBeforeUnloadConfirmPanel(const String& message, Frame* frame); + + virtual void closeWindowSoon(); + + virtual void runJavaScriptAlert(Frame*, const String&); + virtual bool runJavaScriptConfirm(Frame*, const String&); + virtual bool runJavaScriptPrompt(Frame*, const String& message, const String& defaultValue, String& result); + virtual void setStatusbarText(const String&); + virtual bool shouldInterruptJavaScript(); + virtual bool tabsToLinks() const; + + virtual IntRect windowResizerRect() const; + + // Methods used by HostWindow. + virtual void invalidateWindow(const WebCore::IntRect&, bool); + virtual void invalidateContentsAndWindow(const WebCore::IntRect&, bool); + virtual void invalidateContentsForSlowScroll(const WebCore::IntRect&, bool); + virtual void scroll(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect); + virtual IntPoint screenToWindow(const IntPoint&) const; + virtual IntRect windowToScreen(const IntRect&) const; + virtual PlatformPageClient platformPageClient() const; + virtual void contentsSizeChanged(Frame*, const IntSize&) const; + virtual void scrollRectIntoView(const IntRect&, const ScrollView*) const; + // End methods used by HostWindow. + + virtual void scrollbarsModeDidChange() const; + virtual void mouseDidMoveOverElement(const HitTestResult&, unsigned int); + + virtual void setToolTip(const String&, TextDirection); + + virtual void print(Frame*); +#if ENABLE(DATABASE) + virtual void exceededDatabaseQuota(Frame*, const String&); +#endif +#if ENABLE(OFFLINE_WEB_APPLICATIONS) + virtual void reachedMaxAppCacheSize(int64_t spaceNeeded); + virtual void reachedApplicationCacheOriginQuota(SecurityOrigin*); +#endif + + virtual void populateVisitedLinks(); + +#if ENABLE(TOUCH_EVENTS) + virtual void needTouchEvents(bool); +#endif + + // Methods used to request and provide Geolocation permissions. + virtual void requestGeolocationPermissionForFrame(Frame*, Geolocation*); + virtual void cancelGeolocationPermissionRequestForFrame(WebCore::Frame*, WebCore::Geolocation*); + // Android-specific + void provideGeolocationPermissions(const String &origin, bool allow, bool remember); + void storeGeolocationPermissions(); + void onMainFrameLoadStarted(); + + virtual void runOpenPanel(Frame*, PassRefPtr); + virtual void setCursor(const Cursor&); + virtual void chooseIconForFiles(const WTF::Vector&, FileChooser*); + + // Notification that the given form element has changed. This function + // will be called frequently, so handling should be very fast. + virtual void formStateDidChange(const Node*); + + virtual PassOwnPtr createHTMLParserQuirks() { return 0; } + + // Android-specific + void setWebFrame(android::WebFrame* webframe); + android::WebFrame* webFrame() { return m_webFrame; } + void wakeUpMainThreadWithNewQuota(long newQuota); + +#if USE(ACCELERATED_COMPOSITING) + virtual void attachRootGraphicsLayer(WebCore::Frame*, WebCore::GraphicsLayer* g); + virtual void setNeedsOneShotDrawingSynchronization(); + virtual void scheduleCompositingLayerSync(); + virtual bool allowsAcceleratedCompositing() const { return true; } + WebCore::GraphicsLayer* layersSync(); +#endif + + virtual bool selectItemWritingDirectionIsNatural(); + virtual PassRefPtr createPopupMenu(WebCore::PopupMenuClient*) const; + virtual PassRefPtr createSearchPopupMenu(WebCore::PopupMenuClient*) const; + +#if ENABLE(CONTEXT_MENUS) + virtual void showContextMenu(); +#endif + +#if ENABLE(ANDROID_INSTALLABLE_WEB_APPS) + virtual void webAppCanBeInstalled(); +#endif + +#if ENABLE(FULLSCREEN_API) + virtual void exitFullScreenForElement(Element*); +#endif + +#if ENABLE(VIDEO) + virtual bool supportsFullscreenForNode(const WebCore::Node*); + virtual void enterFullscreenForNode(WebCore::Node*); + virtual void exitFullscreenForNode(WebCore::Node*); +#endif + + private: + android::WebFrame* m_webFrame; + // The Geolocation permissions manager. + OwnPtr m_geolocationPermissions; +#if USE(ACCELERATED_COMPOSITING) + WebCore::GraphicsLayer* m_rootGraphicsLayer; + bool m_needsLayerSync; +#endif + WTF::ThreadCondition m_quotaThreadCondition; + WTF::Mutex m_quotaThreadLock; + long m_newQuota; + bool m_triedToReclaimDBQuota; + }; + +} + +#endif diff --git a/Source/WebKit/android/WebCoreSupport/ChromiumIncludes.h b/Source/WebKit/android/WebCoreSupport/ChromiumIncludes.h new file mode 100644 index 0000000..8166eb7 --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/ChromiumIncludes.h @@ -0,0 +1,104 @@ +/* + * 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 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). + +#ifdef LOG +#define LOG_WAS_DEFINED LOG +#undef LOG +#endif + +#ifdef LOG_ASSERT +#define LOG_ASSERT_WAS_DEFINED LOG_ASSERT +#undef LOG_ASSERT +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if ENABLE(WEB_AUTOFILL) +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +#undef LOG +#if defined(LOG_WAS_DEFINED) && defined(LOG_PRI) +#define LOG(priority, tag, ...) LOG_PRI(ANDROID_##priority, tag, __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/ChromiumInit.cpp b/Source/WebKit/android/WebCoreSupport/ChromiumInit.cpp new file mode 100644 index 0000000..1872fb9 --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/ChromiumInit.cpp @@ -0,0 +1,74 @@ +/* + * 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 "ChromiumInit.h" + +#include "ChromiumIncludes.h" + +#include +#include + +namespace android { + +bool logMessageHandler(int severity, const char* file, int line, size_t message_start, const std::string& str) { + int androidSeverity = ANDROID_LOG_VERBOSE; + switch(severity) { + case logging::LOG_FATAL: + androidSeverity = ANDROID_LOG_FATAL; + break; + case logging::LOG_ERROR_REPORT: + case logging::LOG_ERROR: + androidSeverity = ANDROID_LOG_ERROR; + break; + case logging::LOG_WARNING: + androidSeverity = ANDROID_LOG_WARN; + break; + default: + androidSeverity = ANDROID_LOG_VERBOSE; + break; + } + android_printLog(androidSeverity, "chromium", "%s:%d: %s", file, line, str.c_str()); + return false; +} + +namespace { + scoped_ptr networkChangeNotifier; +} + +void initChromium() +{ + static Lock lock; + AutoLock aLock(lock); + static bool initCalled = false; + if (!initCalled) { + logging::SetLogMessageHandler(logMessageHandler); + networkChangeNotifier.reset(net::NetworkChangeNotifier::Create()); + net::HttpNetworkLayer::EnableSpdy("npn"); + initCalled = true; + } +} + +} // namespace android diff --git a/Source/WebKit/android/WebCoreSupport/ChromiumInit.h b/Source/WebKit/android/WebCoreSupport/ChromiumInit.h new file mode 100644 index 0000000..235c3dc --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/ChromiumInit.h @@ -0,0 +1,38 @@ +/* + * 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 ChromiumLogging_h +#define ChromiumLogging_h + +namespace android { + +// Sends chromium logs to logcat +// +// This only calls into chromium once, but can be called multiple times. +// It should be called before any other calls into external/chromium. +void initChromium(); +} + +#endif diff --git a/Source/WebKit/android/WebCoreSupport/ContextMenuClientAndroid.cpp b/Source/WebKit/android/WebCoreSupport/ContextMenuClientAndroid.cpp new file mode 100644 index 0000000..3dc4b00 --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/ContextMenuClientAndroid.cpp @@ -0,0 +1,51 @@ +/* + * 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 "config.h" +#include "ContextMenuClientAndroid.h" + +#include "NotImplemented.h" +#include + +namespace WebCore { + +void ContextMenuClientAndroid::contextMenuDestroyed() { delete this; } + +PlatformMenuDescription ContextMenuClientAndroid::getCustomMenuFromDefaultItems(ContextMenu*) { notImplemented(); return 0; } +void ContextMenuClientAndroid::contextMenuItemSelected(ContextMenuItem*, const ContextMenu*) { notImplemented(); } + +void ContextMenuClientAndroid::downloadURL(const KURL& url) { notImplemented(); } +void ContextMenuClientAndroid::copyImageToClipboard(const HitTestResult&) { notImplemented(); } +void ContextMenuClientAndroid::searchWithGoogle(const Frame*) { notImplemented(); } +void ContextMenuClientAndroid::lookUpInDictionary(Frame*) { notImplemented(); } +void ContextMenuClientAndroid::speak(const String&) { notImplemented(); } +void ContextMenuClientAndroid::stopSpeaking() { notImplemented(); } +bool ContextMenuClientAndroid::isSpeaking() +{ + notImplemented(); + return false; +} + +} diff --git a/Source/WebKit/android/WebCoreSupport/ContextMenuClientAndroid.h b/Source/WebKit/android/WebCoreSupport/ContextMenuClientAndroid.h new file mode 100644 index 0000000..4563829 --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/ContextMenuClientAndroid.h @@ -0,0 +1,51 @@ +/* + * 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 ContextMenuClientAndroid_h +#define ContextMenuClientAndroid_h + +#include "ContextMenuClient.h" + +namespace WebCore { + +class ContextMenuClientAndroid : public ContextMenuClient { +public: + virtual void contextMenuDestroyed(); + + virtual PlatformMenuDescription getCustomMenuFromDefaultItems(ContextMenu*); + virtual void contextMenuItemSelected(ContextMenuItem*, const ContextMenu*); + + virtual void downloadURL(const KURL& url); + virtual void copyImageToClipboard(const HitTestResult&); + virtual void searchWithGoogle(const Frame*); + virtual void lookUpInDictionary(Frame*); + virtual void speak(const String&); + virtual void stopSpeaking(); + virtual bool isSpeaking(); +}; + +} // namespace WebCore + +#endif // ContextMenuClientAndroid_h diff --git a/Source/WebKit/android/WebCoreSupport/CookieClient.h b/Source/WebKit/android/WebCoreSupport/CookieClient.h new file mode 100644 index 0000000..56d9382 --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/CookieClient.h @@ -0,0 +1,46 @@ +/* + * 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 COOKIE_CLIENT_H +#define COOKIE_CLIENT_H + +#include +#include + +using namespace WebCore; + +namespace android { + +class CookieClient { + +public: + virtual ~CookieClient() {} + virtual void setCookies(const KURL& url, const String& value) = 0; + virtual String cookies(const KURL& url) = 0; + virtual bool cookiesEnabled() = 0; +}; + +} +#endif diff --git a/Source/WebKit/android/WebCoreSupport/DeviceMotionClientAndroid.cpp b/Source/WebKit/android/WebCoreSupport/DeviceMotionClientAndroid.cpp new file mode 100644 index 0000000..f8de733 --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/DeviceMotionClientAndroid.cpp @@ -0,0 +1,84 @@ +/* + * 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 "DeviceMotionClientAndroid.h" + +#include "WebViewCore.h" + +using namespace WebCore; + +namespace android { + +DeviceMotionClientAndroid::DeviceMotionClientAndroid() + : m_client(0) +{ +} + +void DeviceMotionClientAndroid::setWebViewCore(WebViewCore* webViewCore) +{ + m_webViewCore = webViewCore; + ASSERT(m_webViewCore); +} + +void DeviceMotionClientAndroid::setController(DeviceMotionController* controller) +{ + // This will be called by the Page constructor before the WebViewCore + // has been configured regarding the mock. We cache the controller for + // later use. + m_controller = controller; + ASSERT(m_controller); +} + +void DeviceMotionClientAndroid::startUpdating() +{ + client()->startUpdating(); +} + +void DeviceMotionClientAndroid::stopUpdating() +{ + client()->stopUpdating(); +} + +DeviceMotionData* DeviceMotionClientAndroid::currentDeviceMotion() const +{ + return client()->currentDeviceMotion(); +} + +void DeviceMotionClientAndroid::deviceMotionControllerDestroyed() +{ + delete this; +} + +DeviceMotionClient* DeviceMotionClientAndroid::client() const +{ + if (!m_client) { + m_client = m_webViewCore->deviceMotionAndOrientationManager()->motionClient(); + m_client->setController(m_controller); + } + return m_client; +} + +} // namespace android diff --git a/Source/WebKit/android/WebCoreSupport/DeviceMotionClientAndroid.h b/Source/WebKit/android/WebCoreSupport/DeviceMotionClientAndroid.h new file mode 100644 index 0000000..98d4709 --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/DeviceMotionClientAndroid.h @@ -0,0 +1,65 @@ +/* + * 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 DeviceMotionClientAndroid_h +#define DeviceMotionClientAndroid_h + +#include + +namespace WebCore { +class DeviceMotionController; +} + +namespace android { + +class WebViewCore; + +// The Android implementation of DeviceMotionClient. Acts as a proxy to +// the real or mock impl, which is owned by the WebViewCore. +class DeviceMotionClientAndroid : public WebCore::DeviceMotionClient { +public: + DeviceMotionClientAndroid(); + + void setWebViewCore(WebViewCore*); + + // DeviceMotionClient methods + virtual void setController(WebCore::DeviceMotionController*); + virtual void startUpdating(); + virtual void stopUpdating(); + virtual WebCore::DeviceMotionData* currentDeviceMotion() const; + virtual void deviceMotionControllerDestroyed(); + +private: + WebCore::DeviceMotionClient* client() const; + + WebViewCore* m_webViewCore; + WebCore::DeviceMotionController* m_controller; + // Lazily obtained cache of the client owned by the WebViewCore. + mutable WebCore::DeviceMotionClient* m_client; +}; + +} // namespace android + +#endif // DeviceMotionClientAndroid_h diff --git a/Source/WebKit/android/WebCoreSupport/DeviceOrientationClientAndroid.cpp b/Source/WebKit/android/WebCoreSupport/DeviceOrientationClientAndroid.cpp new file mode 100644 index 0000000..9d7145c --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/DeviceOrientationClientAndroid.cpp @@ -0,0 +1,84 @@ +/* + * 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 "DeviceOrientationClientAndroid.h" + +#include "WebViewCore.h" + +using namespace WebCore; + +namespace android { + +DeviceOrientationClientAndroid::DeviceOrientationClientAndroid() + : m_client(0) +{ +} + +void DeviceOrientationClientAndroid::setWebViewCore(WebViewCore* webViewCore) +{ + m_webViewCore = webViewCore; + ASSERT(m_webViewCore); +} + +void DeviceOrientationClientAndroid::setController(DeviceOrientationController* controller) +{ + // This will be called by the Page constructor before the WebViewCore + // has been configured regarding the mock. We cache the controller for + // later use. + m_controller = controller; + ASSERT(m_controller); +} + +void DeviceOrientationClientAndroid::startUpdating() +{ + client()->startUpdating(); +} + +void DeviceOrientationClientAndroid::stopUpdating() +{ + client()->stopUpdating(); +} + +DeviceOrientation* DeviceOrientationClientAndroid::lastOrientation() const +{ + return client()->lastOrientation(); +} + +void DeviceOrientationClientAndroid::deviceOrientationControllerDestroyed() +{ + delete this; +} + +DeviceOrientationClient* DeviceOrientationClientAndroid::client() const +{ + if (!m_client) { + m_client = m_webViewCore->deviceMotionAndOrientationManager()->orientationClient(); + m_client->setController(m_controller); + } + return m_client; +} + +} // namespace android diff --git a/Source/WebKit/android/WebCoreSupport/DeviceOrientationClientAndroid.h b/Source/WebKit/android/WebCoreSupport/DeviceOrientationClientAndroid.h new file mode 100644 index 0000000..7842b95 --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/DeviceOrientationClientAndroid.h @@ -0,0 +1,65 @@ +/* + * 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 DeviceOrientationClientAndroid_h +#define DeviceOrientationClientAndroid_h + +#include + +namespace WebCore { +class DeviceOrientationController; +} + +namespace android { + +class WebViewCore; + +// The Android implementation of DeviceOrientationClient. Acts as a proxy to +// the real or mock impl, which is owned by the WebViewCore. +class DeviceOrientationClientAndroid : public WebCore::DeviceOrientationClient { +public: + DeviceOrientationClientAndroid(); + + void setWebViewCore(WebViewCore*); + + // DeviceOrientationClient methods + virtual void setController(WebCore::DeviceOrientationController*); + virtual void startUpdating(); + virtual void stopUpdating(); + virtual WebCore::DeviceOrientation* lastOrientation() const; + virtual void deviceOrientationControllerDestroyed(); + +private: + WebCore::DeviceOrientationClient* client() const; + + WebViewCore* m_webViewCore; + WebCore::DeviceOrientationController* m_controller; + // Lazily obtained cache of the client owned by the WebViewCore. + mutable WebCore::DeviceOrientationClient* m_client; +}; + +} // namespace android + +#endif // DeviceOrientationClientAndroid_h diff --git a/Source/WebKit/android/WebCoreSupport/DragClientAndroid.cpp b/Source/WebKit/android/WebCoreSupport/DragClientAndroid.cpp new file mode 100644 index 0000000..f64b80c --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/DragClientAndroid.cpp @@ -0,0 +1,46 @@ +/* + * 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. + */ + +#define LOG_TAG "WebCore" + +#include "config.h" +#include "DragClientAndroid.h" +#include "NotImplemented.h" + +namespace android { + +void DragClientAndroid::dragControllerDestroyed() { notImplemented(); delete this; } + +void DragClientAndroid::willPerformDragDestinationAction(DragDestinationAction, DragData*) { notImplemented(); } + +DragDestinationAction DragClientAndroid::actionMaskForDrag(DragData*) { notImplemented(); return DragDestinationActionNone; } + +DragSourceAction DragClientAndroid::dragSourceActionMaskForPoint(const IntPoint&) { notImplemented(); return DragSourceActionNone; } + +void* DragClientAndroid::createDragImageForLink(KURL&, String const&, Frame*) { return NULL; } +void DragClientAndroid::willPerformDragSourceAction(DragSourceAction, IntPoint const&, Clipboard*) {} +void DragClientAndroid::startDrag(void*, IntPoint const&, IntPoint const&, Clipboard*, Frame*, bool) {} + +} diff --git a/Source/WebKit/android/WebCoreSupport/DragClientAndroid.h b/Source/WebKit/android/WebCoreSupport/DragClientAndroid.h new file mode 100644 index 0000000..020e1f1 --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/DragClientAndroid.h @@ -0,0 +1,51 @@ +/* + * 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 DragClientAndroid_h +#define DragClientAndroid_h + +#include "DragClient.h" + +using namespace WebCore; + +namespace android { + + class DragClientAndroid : public DragClient { + public: + virtual void willPerformDragDestinationAction(DragDestinationAction, DragData*); + virtual void willPerformDragSourceAction(DragSourceAction, const IntPoint&, Clipboard*); + virtual DragDestinationAction actionMaskForDrag(DragData*); + //We work in window rather than view coordinates here + virtual DragSourceAction dragSourceActionMaskForPoint(const IntPoint&); + + virtual void startDrag(DragImageRef dragImage, const IntPoint& dragImageOrigin, const IntPoint& eventPos, Clipboard*, Frame*, bool linkDrag = false); + virtual DragImageRef createDragImageForLink(KURL&, const String& label, Frame*); + + virtual void dragControllerDestroyed(); + }; + +} + +#endif diff --git a/Source/WebKit/android/WebCoreSupport/EditorClientAndroid.cpp b/Source/WebKit/android/WebCoreSupport/EditorClientAndroid.cpp new file mode 100644 index 0000000..250fdbf --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/EditorClientAndroid.cpp @@ -0,0 +1,280 @@ +/* + * 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. + */ + +#define LOG_TAG "WebCore" + +#include "config.h" +#include "Editor.h" +#include "EditorClientAndroid.h" +#include "Event.h" +#include "EventNames.h" +#include "FocusController.h" +#include "Frame.h" +#include "HTMLNames.h" +#include "KeyboardEvent.h" +#include "NotImplemented.h" +#include "PlatformKeyboardEvent.h" +#include "PlatformString.h" +#include "WebViewCore.h" +#include "WindowsKeyboardCodes.h" + +using namespace WebCore::HTMLNames; + +namespace android { + +void EditorClientAndroid::pageDestroyed() { + delete this; +} + +bool EditorClientAndroid::shouldDeleteRange(Range*) { return true; } +bool EditorClientAndroid::shouldShowDeleteInterface(HTMLElement*) { notImplemented(); return false; } +bool EditorClientAndroid::smartInsertDeleteEnabled() { notImplemented(); return false; } +bool EditorClientAndroid::isSelectTrailingWhitespaceEnabled(){ notImplemented(); return false; } +bool EditorClientAndroid::isContinuousSpellCheckingEnabled() { notImplemented(); return false; } +void EditorClientAndroid::toggleContinuousSpellChecking() { notImplemented(); } +bool EditorClientAndroid::isGrammarCheckingEnabled() { notImplemented(); return false; } +void EditorClientAndroid::toggleGrammarChecking() { notImplemented(); } +int EditorClientAndroid::spellCheckerDocumentTag() { notImplemented(); return -1; } + +bool EditorClientAndroid::isEditable() { /* notImplemented(); */ return false; } + +// Following Qt's implementation. For shouldBeginEditing and shouldEndEditing. +// Returning true for these fixes issue http://b/issue?id=735185 +bool EditorClientAndroid::shouldBeginEditing(Range*) +{ + return true; +} + +bool EditorClientAndroid::shouldEndEditing(Range*) +{ + return true; +} + +bool EditorClientAndroid::shouldInsertNode(Node*, Range*, EditorInsertAction) { notImplemented(); return true; } +bool EditorClientAndroid::shouldInsertText(const String&, Range*, EditorInsertAction) { return true; } +bool EditorClientAndroid::shouldApplyStyle(CSSStyleDeclaration*, Range*) { notImplemented(); return true; } + +void EditorClientAndroid::didBeginEditing() { notImplemented(); } + +// This function is called so that the platform can handle changes to content. It is called +// after the contents have been edited or unedited (ie undo) +void EditorClientAndroid::respondToChangedContents() { notImplemented(); } + +void EditorClientAndroid::didEndEditing() { notImplemented(); } +void EditorClientAndroid::didWriteSelectionToPasteboard() { notImplemented(); } +void EditorClientAndroid::didSetSelectionTypesForPasteboard() { notImplemented(); } + +// Copied from the Window's port of WebKit. +static const unsigned AltKey = 1 << 0; +static const unsigned ShiftKey = 1 << 1; + +struct KeyDownEntry { + unsigned virtualKey; + unsigned modifiers; + const char* name; +}; + +struct KeyPressEntry { + unsigned charCode; + unsigned modifiers; + const char* name; +}; + +static const KeyDownEntry keyDownEntries[] = { + { VK_LEFT, 0, "MoveLeft" }, + { VK_LEFT, ShiftKey, "MoveLeftAndModifySelection" }, + { VK_LEFT, AltKey, "MoveWordLeft" }, + { VK_LEFT, AltKey | ShiftKey, "MoveWordLeftAndModifySelection" }, + { VK_RIGHT, 0, "MoveRight" }, + { VK_RIGHT, ShiftKey, "MoveRightAndModifySelection" }, + { VK_RIGHT, AltKey, "MoveWordRight" }, + { VK_RIGHT, AltKey | ShiftKey, "MoveWordRightAndModifySelection" }, + { VK_UP, 0, "MoveUp" }, + { VK_UP, ShiftKey, "MoveUpAndModifySelection" }, + { VK_DOWN, 0, "MoveDown" }, + { VK_DOWN, ShiftKey, "MoveDownAndModifySelection" }, + + { VK_BACK, 0, "BackwardDelete" }, + { VK_BACK, ShiftKey, "ForwardDelete" }, + { VK_BACK, AltKey, "DeleteWordBackward" }, + { VK_BACK, AltKey | ShiftKey, "DeleteWordForward" }, + + { VK_ESCAPE, 0, "Cancel" }, + { VK_TAB, 0, "InsertTab" }, + { VK_TAB, ShiftKey, "InsertBacktab" }, + { VK_RETURN, 0, "InsertNewline" }, + { VK_RETURN, AltKey, "InsertNewline" }, + { VK_RETURN, AltKey | ShiftKey, "InsertNewline" } +}; + +static const KeyPressEntry keyPressEntries[] = { + { '\t', 0, "InsertTab" }, + { '\t', ShiftKey, "InsertBackTab" }, + { '\r', 0, "InsertNewline" }, + { '\r', AltKey, "InsertNewline" }, + { '\r', AltKey | ShiftKey, "InsertNewline" } +}; + +static const char* interpretKeyEvent(const KeyboardEvent* evt) +{ + const PlatformKeyboardEvent* keyEvent = evt->keyEvent(); + + static HashMap* keyDownCommandsMap = 0; + static HashMap* keyPressCommandsMap = 0; + + if (!keyDownCommandsMap) { + keyDownCommandsMap = new HashMap; + keyPressCommandsMap = new HashMap; + + for (unsigned i = 0; i < sizeof(keyDownEntries)/sizeof(KeyDownEntry); i++) + keyDownCommandsMap->set(keyDownEntries[i].modifiers << 16 | keyDownEntries[i].virtualKey, keyDownEntries[i].name); + + for (unsigned i = 0; i < sizeof(keyPressEntries)/sizeof(KeyPressEntry); i++) + keyPressCommandsMap->set(keyPressEntries[i].modifiers << 16 | keyPressEntries[i].charCode, keyPressEntries[i].name); + } + + unsigned modifiers = 0; + if (keyEvent->shiftKey()) + modifiers |= ShiftKey; + if (keyEvent->altKey()) + modifiers |= AltKey; + + if (evt->type() == eventNames().keydownEvent) { + int mapKey = modifiers << 16 | evt->keyCode(); + return mapKey ? keyDownCommandsMap->get(mapKey) : 0; + } + + int mapKey = modifiers << 16 | evt->charCode(); + return mapKey ? keyPressCommandsMap->get(mapKey) : 0; +} + +void EditorClientAndroid::handleKeyboardEvent(KeyboardEvent* event) { + ASSERT(m_page); + Frame* frame = m_page->focusController()->focusedOrMainFrame(); + if (!frame) + return; + + const PlatformKeyboardEvent* keyEvent = event->keyEvent(); + // TODO: If the event is not coming from Android Java, e.g. from JavaScript, + // PlatformKeyboardEvent is null. We should support this later. + if (!keyEvent) + return; + + Editor::Command command = frame->editor()->command(interpretKeyEvent(event)); + if (keyEvent->type() == PlatformKeyboardEvent::RawKeyDown) { + if (!command.isTextInsertion() && command.execute(event)) { + // This function mimics the Windows version. However, calling event->setDefaultHandled() + // prevents the javascript key events for the delete key from happening. + // Update: Safari doesn't send delete key events to javascript so + // we will mimic that behavior. + event->setDefaultHandled(); + } + return; + } + + if (command.execute(event)) { + event->setDefaultHandled(); + return; + } + + // Don't insert null or control characters as they can result in unexpected behaviour + if (event->charCode() < ' ') + return; + + if (frame->editor()->insertText(keyEvent->text(), event)) + event->setDefaultHandled(); +} + +//////////////////////////////////////////////////////////////////////////////////////////////// +// we just don't support Undo/Redo at the moment + +void EditorClientAndroid::registerCommandForUndo(PassRefPtr) {} +void EditorClientAndroid::registerCommandForRedo(PassRefPtr) {} +void EditorClientAndroid::clearUndoRedoOperations() {} +bool EditorClientAndroid::canUndo() const { return false; } +bool EditorClientAndroid::canRedo() const { return false; } +void EditorClientAndroid::undo() {} +void EditorClientAndroid::redo() {} + +// functions new to Jun-07 tip of tree merge: +void EditorClientAndroid::showSpellingUI(bool) {} +void EditorClientAndroid::getGuessesForWord(String const&, const String&, WTF::Vector&) {} +bool EditorClientAndroid::spellingUIIsShowing() { return false; } +void EditorClientAndroid::checkGrammarOfString(unsigned short const*, int, WTF::Vector&, int*, int*) {} +void EditorClientAndroid::checkSpellingOfString(unsigned short const*, int, int*, int*) {} +String EditorClientAndroid::getAutoCorrectSuggestionForMisspelledWord(const String&) { return String(); } +void EditorClientAndroid::textFieldDidEndEditing(Element*) {} +void EditorClientAndroid::textDidChangeInTextArea(Element*) {} +void EditorClientAndroid::textDidChangeInTextField(Element*) {} +void EditorClientAndroid::textFieldDidBeginEditing(Element*) {} +void EditorClientAndroid::ignoreWordInSpellDocument(String const&) {} + +// We need to pass the selection up to the WebTextView +void EditorClientAndroid::respondToChangedSelection() { + if (m_uiGeneratedSelectionChange) + return; + Frame* frame = m_page->focusController()->focusedOrMainFrame(); + if (!frame || !frame->view()) + return; + WebViewCore* webViewCore = WebViewCore::getWebViewCore(frame->view()); + webViewCore->updateTextSelection(); +} + +bool EditorClientAndroid::shouldChangeSelectedRange(Range*, Range*, EAffinity, + bool) { + return m_shouldChangeSelectedRange; +} + +bool EditorClientAndroid::doTextFieldCommandFromEvent(Element*, KeyboardEvent*) { return false; } +void EditorClientAndroid::textWillBeDeletedInTextField(Element*) {} +void EditorClientAndroid::updateSpellingUIWithGrammarString(String const&, GrammarDetail const&) {} +void EditorClientAndroid::updateSpellingUIWithMisspelledWord(String const&) {} +void EditorClientAndroid::learnWord(String const&) {} + +// functions new to the Nov-16-08 tip of tree merge: +bool EditorClientAndroid::shouldMoveRangeAfterDelete(Range*, Range*) { return true; } +void EditorClientAndroid::setInputMethodState(bool) {} + +// functions new to Feb-19 tip of tree merge: +void EditorClientAndroid::handleInputMethodKeydown(KeyboardEvent*) {} + +void EditorClientAndroid::willSetInputMethodState() +{ + notImplemented(); +} + +void EditorClientAndroid::requestCheckingOfString(SpellChecker*, int, const String&) {} + +#if ENABLE(WEB_AUTOFILL) +WebAutoFill* EditorClientAndroid::getAutoFill() +{ + if (!m_autoFill) + m_autoFill.set(new WebAutoFill()); + + return m_autoFill.get(); +} +#endif + +} diff --git a/Source/WebKit/android/WebCoreSupport/EditorClientAndroid.h b/Source/WebKit/android/WebCoreSupport/EditorClientAndroid.h new file mode 100644 index 0000000..94a6518 --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/EditorClientAndroid.h @@ -0,0 +1,135 @@ +/* + * 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 EditorClientAndroid_h +#define EditorClientAndroid_h + +#include "config.h" + + +#include "EditorClient.h" +#include "Page.h" +#include "autofill/WebAutoFill.h" + +#include + +using namespace WebCore; + +namespace android { + +class EditorClientAndroid : public EditorClient { +public: + EditorClientAndroid() { + m_shouldChangeSelectedRange = true; + m_uiGeneratedSelectionChange = false; + } + virtual void pageDestroyed(); + + virtual bool shouldDeleteRange(Range*); + virtual bool shouldShowDeleteInterface(HTMLElement*); + virtual bool smartInsertDeleteEnabled(); + virtual bool isSelectTrailingWhitespaceEnabled(); + virtual bool isContinuousSpellCheckingEnabled(); + virtual void toggleContinuousSpellChecking(); + virtual bool isGrammarCheckingEnabled(); + virtual void toggleGrammarChecking(); + virtual int spellCheckerDocumentTag(); + + virtual bool isEditable(); + + virtual bool shouldBeginEditing(Range*); + virtual bool shouldEndEditing(Range*); + virtual bool shouldInsertNode(Node*, Range*, EditorInsertAction); + virtual bool shouldInsertText(const String&, Range*, EditorInsertAction); + virtual bool shouldChangeSelectedRange(Range* fromRange, Range* toRange, EAffinity, bool stillSelecting); + + virtual bool shouldApplyStyle(CSSStyleDeclaration*, Range*); +// virtual bool shouldChangeTypingStyle(CSSStyleDeclaration* fromStyle, CSSStyleDeclaration* toStyle); +// virtual bool doCommandBySelector(SEL selector); + virtual bool shouldMoveRangeAfterDelete(Range*, Range*); + + virtual void didBeginEditing(); + virtual void respondToChangedContents(); + virtual void respondToChangedSelection(); + virtual void didEndEditing(); + virtual void didWriteSelectionToPasteboard(); + virtual void didSetSelectionTypesForPasteboard(); +// virtual void didChangeTypingStyle:(NSNotification *)notification; +// virtual void didChangeSelection:(NSNotification *)notification; +// virtual NSUndoManager* undoManager:(WebView *)webView; + + virtual void registerCommandForUndo(PassRefPtr); + virtual void registerCommandForRedo(PassRefPtr); + virtual void clearUndoRedoOperations(); + + virtual bool canUndo() const; + virtual bool canRedo() const; + + virtual void undo(); + virtual void redo(); + + virtual void handleKeyboardEvent(KeyboardEvent*); + virtual void handleInputMethodKeydown(KeyboardEvent*); + + virtual void textFieldDidBeginEditing(Element*); + virtual void textFieldDidEndEditing(Element*); + virtual void textDidChangeInTextField(Element*); + virtual bool doTextFieldCommandFromEvent(Element*, KeyboardEvent*); + virtual void textWillBeDeletedInTextField(Element*); + virtual void textDidChangeInTextArea(Element*); + + virtual void ignoreWordInSpellDocument(const String&); + virtual void learnWord(const String&); + virtual void checkSpellingOfString(const UChar*, int length, int* misspellingLocation, int* misspellingLength); + virtual String getAutoCorrectSuggestionForMisspelledWord(const String& misspelledWorld); + virtual void checkGrammarOfString(const UChar*, int length, WTF::Vector&, int* badGrammarLocation, int* badGrammarLength); + virtual void updateSpellingUIWithGrammarString(const String&, const GrammarDetail& detail); + virtual void updateSpellingUIWithMisspelledWord(const String&); + virtual void showSpellingUI(bool show); + virtual bool spellingUIIsShowing(); + virtual void getGuessesForWord(const String&, const String& context, WTF::Vector& guesses); + virtual void willSetInputMethodState(); + virtual void setInputMethodState(bool); + virtual void requestCheckingOfString(SpellChecker*, int, const String&); + + // Android specific: + void setPage(Page* page) { m_page = page; } + void setShouldChangeSelectedRange(bool shouldChangeSelectedRange) { m_shouldChangeSelectedRange = shouldChangeSelectedRange; } + void setUiGeneratedSelectionChange(bool uiGenerated) { m_uiGeneratedSelectionChange = uiGenerated; } +#if ENABLE(WEB_AUTOFILL) + WebAutoFill* getAutoFill(); +#endif +private: + Page* m_page; + bool m_shouldChangeSelectedRange; + bool m_uiGeneratedSelectionChange; +#if ENABLE(WEB_AUTOFILL) + OwnPtr m_autoFill; +#endif +}; + +} + +#endif diff --git a/Source/WebKit/android/WebCoreSupport/FileSystemClient.h b/Source/WebKit/android/WebCoreSupport/FileSystemClient.h new file mode 100644 index 0000000..5bde18a --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/FileSystemClient.h @@ -0,0 +1,41 @@ +/* + * 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 FILESYSTEM_CLIENT_H +#define FILESYSTEM_CLIENT_H + +#include "PlatformString.h" + +using namespace WebCore; + +namespace android { + +class FileSystemClient { +public: + virtual ~FileSystemClient() { } + virtual String resolveFilePathForContentUri(const String&) = 0; +}; +} +#endif diff --git a/Source/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp b/Source/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp new file mode 100644 index 0000000..946a4a7 --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp @@ -0,0 +1,1351 @@ +/* + * 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. + */ + +#define LOG_TAG "WebCore" + +#include "config.h" +#include "FrameLoaderClientAndroid.h" + +#include "BackForwardList.h" +#include "CachedFrame.h" +#include "CachedFramePlatformDataAndroid.h" +#include "Chrome.h" +#include "ChromeClientAndroid.h" +#include "DOMImplementation.h" +#include "Document.h" +#include "DocumentLoader.h" +#include "EditorClientAndroid.h" +#include "Frame.h" +#include "FrameLoader.h" +#include "FrameNetworkingContextAndroid.h" +#include "FrameTree.h" +#include "FrameView.h" +#include "GraphicsContext.h" +#include "HTMLFrameOwnerElement.h" +#include "HTMLPlugInElement.h" +#include "HistoryItem.h" +#include "IconDatabase.h" +#include "MIMETypeRegistry.h" +#include "NotImplemented.h" +#include "PackageNotifier.h" +#include "Page.h" +#include "PlatformBridge.h" +#include "PlatformGraphicsContext.h" +#include "PlatformString.h" +#include "PluginDatabase.h" +#include "PluginView.h" +#include "PluginViewBase.h" +#include "ProgressTracker.h" +#include "RenderPart.h" +#include "RenderView.h" +#include "RenderWidget.h" +#include "ResourceError.h" +#include "ResourceHandle.h" +#include "ResourceHandleInternal.h" +#include "SelectionController.h" +#include "Settings.h" +#include "SkCanvas.h" +#include "SkRect.h" +#include "TextEncoding.h" +#include "WebCoreFrameBridge.h" +#include "WebCoreResourceLoader.h" +#include "WebHistory.h" +#include "WebIconDatabase.h" +#include "WebFrameView.h" +#include "WebViewClientError.h" +#include "WebViewCore.h" +#include "autofill/WebAutoFill.h" +#include "android_graphics.h" + +#include +#include + +extern android::AssetManager* globalAssetManager(); + +namespace android { + +static const int EXTRA_LAYOUT_DELAY = 1000; + +FrameLoaderClientAndroid::FrameLoaderClientAndroid(WebFrame* webframe) + : m_frame(NULL) + , m_webFrame(webframe) + , m_manualLoader(NULL) + , m_hasSentResponseToPlugin(false) + , m_onDemandPluginsEnabled(false) { + Retain(m_webFrame); +} + +FrameLoaderClientAndroid* FrameLoaderClientAndroid::get(const WebCore::Frame* frame) +{ + return static_cast (frame->loader()->client()); +} + +void FrameLoaderClientAndroid::frameLoaderDestroyed() { + registerForIconNotification(false); + m_frame = 0; + Release(m_webFrame); + delete this; +} + +bool FrameLoaderClientAndroid::hasWebView() const { + // FIXME, + // there is one web view per page, or top frame. + // as android's view is created from Java side, it is always there. + return true; +} + +void FrameLoaderClientAndroid::makeRepresentation(DocumentLoader*) { + m_onDemandPluginsEnabled = false; + // don't use representation + verifiedOk(); +} + +void FrameLoaderClientAndroid::forceLayout() { + ASSERT(m_frame); + m_frame->view()->forceLayout(); + // FIXME, should we adjust view size here? + m_frame->view()->adjustViewSize(); +} + +void FrameLoaderClientAndroid::forceLayoutForNonHTML() { + notImplemented(); +} + +void FrameLoaderClientAndroid::setCopiesOnScroll() { + // this is a hint about whether we need to force redraws, or can + // just copy the scrolled content. Since we always force a redraw + // anyways, we can ignore this call. + verifiedOk(); +} + +void FrameLoaderClientAndroid::detachedFromParent2() { + // FIXME, ready to detach frame from view +} + +void FrameLoaderClientAndroid::detachedFromParent3() { + // FIXME, ready to release view + notImplemented(); +} + +// This function is responsible for associating the "id" with a given +// subresource load. The following functions that accept an "id" are +// called for each subresource, so they should not be dispatched to the m_frame. +void FrameLoaderClientAndroid::assignIdentifierToInitialRequest(unsigned long id, + DocumentLoader*, const ResourceRequest&) { + lowPriority_notImplemented(); +} + +void FrameLoaderClientAndroid::dispatchWillSendRequest(DocumentLoader*, unsigned long id, + ResourceRequest&, const ResourceResponse&) { + lowPriority_notImplemented(); +} + +bool FrameLoaderClientAndroid::shouldUseCredentialStorage(DocumentLoader*, unsigned long identifier) +{ + notImplemented(); + return false; +} + +void FrameLoaderClientAndroid::dispatchDidReceiveAuthenticationChallenge(DocumentLoader*, + unsigned long id, const AuthenticationChallenge&) { + lowPriority_notImplemented(); +} + +void FrameLoaderClientAndroid::dispatchDidCancelAuthenticationChallenge(DocumentLoader*, + unsigned long id, const AuthenticationChallenge&) { + lowPriority_notImplemented(); +} + +void FrameLoaderClientAndroid::dispatchDidReceiveResponse(DocumentLoader*, + unsigned long id, const ResourceResponse&) { + lowPriority_notImplemented(); +} + +void FrameLoaderClientAndroid::dispatchDidReceiveContentLength(DocumentLoader*, + unsigned long id, int lengthReceived) { + lowPriority_notImplemented(); +} + +void FrameLoaderClientAndroid::dispatchDidFinishLoading(DocumentLoader*, + unsigned long id) { + lowPriority_notImplemented(); +} + +void FrameLoaderClientAndroid::dispatchDidFailLoading(DocumentLoader* docLoader, + unsigned long id, const ResourceError&) { + lowPriority_notImplemented(); +} + +bool FrameLoaderClientAndroid::dispatchDidLoadResourceFromMemoryCache(DocumentLoader*, + const ResourceRequest&, const ResourceResponse&, int length) { + notImplemented(); + return false; +} + +void FrameLoaderClientAndroid::dispatchDidHandleOnloadEvents() { +} + +void FrameLoaderClientAndroid::dispatchDidReceiveServerRedirectForProvisionalLoad() { + ASSERT(m_frame); + // Tell the load it was a redirect. + m_webFrame->loadStarted(m_frame); +} + +void FrameLoaderClientAndroid::dispatchDidCancelClientRedirect() { + notImplemented(); +} + +void FrameLoaderClientAndroid::dispatchWillPerformClientRedirect(const KURL&, + double interval, double fireDate) { + notImplemented(); +} + +void FrameLoaderClientAndroid::dispatchDidChangeLocationWithinPage() { + notImplemented(); +} + +void FrameLoaderClientAndroid::dispatchDidPushStateWithinPage() +{ + notImplemented(); +} + +void FrameLoaderClientAndroid::dispatchDidReplaceStateWithinPage() +{ + notImplemented(); +} + +void FrameLoaderClientAndroid::dispatchDidPopStateWithinPage() +{ + notImplemented(); +} + +void FrameLoaderClientAndroid::dispatchWillClose() { + notImplemented(); +} + +void FrameLoaderClientAndroid::dispatchDidReceiveIcon() { + ASSERT(m_frame); + if (m_frame->tree() && m_frame->tree()->parent()) + return; + WTF::String url(m_frame->loader()->url().string()); + // Try to obtain the icon image. + WebCore::Image* icon = WebCore::iconDatabase()->iconForPageURL( + url, WebCore::IntSize(16, 16)); + // If the request fails, try the original request url. + if (!icon) { + DocumentLoader* docLoader = m_frame->loader()->activeDocumentLoader(); + KURL originalURL = docLoader->originalRequest().url(); + icon = WebCore::iconDatabase()->iconForPageURL( + originalURL, WebCore::IntSize(16, 16)); + } + // 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, + url.utf8().data()); + m_webFrame->didReceiveIcon(icon); + } else { + LOGV("Icon data for %s unavailable, registering for notification...", + url.utf8().data()); + registerForIconNotification(); + } +} + +void FrameLoaderClientAndroid::dispatchDidReceiveTouchIconURL(const String& url, bool precomposed) { + ASSERT(m_frame); + // Do not report sub frame touch icons + if (m_frame->tree() && m_frame->tree()->parent()) + return; + m_webFrame->didReceiveTouchIconURL(url, precomposed); +} + +void FrameLoaderClientAndroid::dispatchDidStartProvisionalLoad() { + notImplemented(); +} + +void FrameLoaderClientAndroid::dispatchDidReceiveTitle(const String& title) { + ASSERT(m_frame); + // Used to check for FrameLoadTypeStandard but we only want to send the title for + // the top frame and not sub-frames. + if (!m_frame->tree() || !m_frame->tree()->parent()) { + m_webFrame->setTitle(title); + } +} + +void FrameLoaderClientAndroid::dispatchDidCommitLoad() { +#if ENABLE(WEB_AUTOFILL) + if (m_frame == m_frame->page()->mainFrame()) { + EditorClientAndroid* editorC = static_cast(m_frame->page()->editorClient()); + WebAutoFill* autoFill = editorC->getAutoFill(); + autoFill->reset(); + } +#endif + verifiedOk(); +} + +static void loadDataIntoFrame(Frame* frame, KURL baseUrl, const String& url, + const String& data) { + if (baseUrl.isEmpty()) { + baseUrl = blankURL(); + } + ResourceRequest request(baseUrl); + CString cstr = data.utf8(); + RefPtr buf = WebCore::SharedBuffer::create(cstr.data(), cstr.length()); + SubstituteData subData(buf, String("text/html"), String("utf-8"), + KURL(KURL(), url)); + frame->loader()->load(request, subData, false); +} + +void FrameLoaderClientAndroid::dispatchDidFailProvisionalLoad(const ResourceError& error) { + ASSERT(m_frame); + // Ignore ErrorInterrupted since it is due to a policy interruption. This + // is caused by a decision to download the main resource rather than + // display it. + if (error.errorCode() == InternalErrorInterrupted + || error.errorCode() == InternalErrorCancelled) { + // If we decided to download the main resource or if the user cancelled + // it, make sure we report that the load is done. + didFinishLoad(); + return; + } + + AssetManager* am = globalAssetManager(); + + // Check to see if the error code was not generated internally + WebCore::PlatformBridge::rawResId id = WebCore::PlatformBridge::NoDomain; + if ((error.errorCode() == ErrorFile || + error.errorCode() == ErrorFileNotFound) && + (!error.localizedDescription().isEmpty())) { + id = WebCore::PlatformBridge::LoadError; + } + String filename = m_webFrame->getRawResourceFilename(id); + if (filename.isEmpty()) + return; + + // Grab the error page from the asset manager + Asset* a = am->openNonAsset( + filename.utf8().data(), Asset::ACCESS_BUFFER); + if (!a) + return; + + // Take the failing url and encode html entities so javascript urls are not + // executed. + CString failingUrl = error.failingURL().utf8(); + WTF::Vector url; + int len = failingUrl.length(); + const char* data = failingUrl.data(); + for (int i = 0; i < len; i++) { + char c = data[i]; + if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') + || (c >= '0' && c <= '9')) + url.append(c); + else { + char buf[16]; + int res = sprintf(buf, "&#%d;", c); + buf[res] = 0; + url.append(buf, res); + } + } + + // Replace all occurances of %s with the failing url. + String s = UTF8Encoding().decode((const char*)a->getBuffer(false), a->getLength()); + s = s.replace("%s", String(url.data(), url.size())); + + // Replace all occurances of %e with the error text + s = s.replace("%e", error.localizedDescription()); + + // Create the request and the substitute data and tell the FrameLoader to + // load with the replacement data. + // use KURL(const char*) as KURL(const String& url) can trigger ASSERT for + // invalidate URL string. + loadDataIntoFrame(m_frame, KURL(ParsedURLString, data), error.failingURL(), s); + + // Delete the asset. + delete a; + + // Report that the load is finished, since it failed. + didFinishLoad(); +} + +void FrameLoaderClientAndroid::dispatchDidFailLoad(const ResourceError&) { + // called when page is completed with error + didFinishLoad(); +} + +void FrameLoaderClientAndroid::dispatchDidFinishDocumentLoad() { + // called when finishedParsing + lowPriority_notImplemented(); +} + +void FrameLoaderClientAndroid::dispatchDidFinishLoad() { + didFinishLoad(); +} + +void FrameLoaderClientAndroid::dispatchDidFirstLayout() { + ASSERT(m_frame); + // set EXTRA_LAYOUT_DELAY if the loader is not completed yet + if (!m_frame->loader()->isComplete()) + m_frame->document()->setExtraLayoutDelay(EXTRA_LAYOUT_DELAY); + // we need to do this here instead of dispatchDidFirstVisuallyNonEmptyLayout + // so that about:blank will update the screen. + if (!m_frame->tree()->parent()) { + // Only need to notify Java side for the top frame + WebViewCore::getWebViewCore(m_frame->view())->didFirstLayout(); + } +} + +void FrameLoaderClientAndroid::dispatchDidFirstVisuallyNonEmptyLayout() +{ + notImplemented(); +} + +Frame* FrameLoaderClientAndroid::dispatchCreatePage(const NavigationAction&) { + ASSERT(m_frame); +#ifdef ANDROID_MULTIPLE_WINDOWS + if (m_frame->settings() && m_frame->settings()->supportMultipleWindows()) + // Always a user gesture since window.open maps to + // ChromeClientAndroid::createWindow + return m_webFrame->createWindow(false, true); + else +#endif + // If the client doesn't support multiple windows, just replace the + // current frame's contents. + return m_frame; +} + +void FrameLoaderClientAndroid::dispatchShow() { + ASSERT(m_frame); + m_frame->view()->invalidate(); +} + + +static bool TreatAsAttachment(const String& content_disposition) { + // Some broken sites just send + // Content-Disposition: ; filename="file" + // screen those out here. + if (content_disposition.startsWith(";")) + return false; + + if (content_disposition.startsWith("inline", false)) + return false; + + // Some broken sites just send + // Content-Disposition: filename="file" + // without a disposition token... screen those out. + if (content_disposition.startsWith("filename", false)) + return false; + + // Also in use is Content-Disposition: name="file" + if (content_disposition.startsWith("name", false)) + return false; + + // We have a content-disposition of "attachment" or unknown. + // RFC 2183, section 2.8 says that an unknown disposition + // value should be treated as "attachment" + return true; +} + +void FrameLoaderClientAndroid::dispatchDecidePolicyForMIMEType(FramePolicyFunction func, + const String& MIMEType, const ResourceRequest& request) { + ASSERT(m_frame); + ASSERT(func); + if (!func) + return; + + PolicyChecker* policy = m_frame->loader()->policyChecker(); + + if (request.isNull()) { + (policy->*func)(PolicyIgnore); + return; + } + // Default to Use (display internally). + PolicyAction action = PolicyUse; + // Check if we should Download instead. + const ResourceResponse& response = m_frame->loader()->activeDocumentLoader()->response(); + const String& content_disposition = response.httpHeaderField("Content-Disposition"); + if (!content_disposition.isEmpty() && + TreatAsAttachment(content_disposition)) { + // Server wants to override our normal policy. + // Check to see if we are a sub frame (main frame has no owner element) + if (m_frame->ownerElement() != 0) + action = PolicyIgnore; + else + action = PolicyDownload; + (policy->*func)(action); + return; + } + + // Ask if it can be handled internally. + if (!canShowMIMEType(MIMEType)) { + // Check to see if we are a sub frame (main frame has no owner element) + if (m_frame->ownerElement() != 0) + action = PolicyIgnore; + else + action = PolicyDownload; + (policy->*func)(action); + return; + } + // A status code of 204 indicates no content change. Ignore the result. + WebCore::DocumentLoader* docLoader = m_frame->loader()->activeDocumentLoader(); + if (docLoader->response().httpStatusCode() == 204) + action = PolicyIgnore; + (policy->*func)(action); +} + +void FrameLoaderClientAndroid::dispatchDecidePolicyForNewWindowAction(FramePolicyFunction func, + const NavigationAction& action, const ResourceRequest& request, + PassRefPtr formState, const String& frameName) { + ASSERT(m_frame); + ASSERT(func); + if (!func) + return; + + if (request.isNull()) { + (m_frame->loader()->policyChecker()->*func)(PolicyIgnore); + return; + } + + if (action.type() == NavigationTypeFormSubmitted || action.type() == NavigationTypeFormResubmitted) + m_frame->loader()->resetMultipleFormSubmissionProtection(); + + // If we get to this point it means that a link has a target that was not + // found by the frame tree. Instead of creating a new frame, return the + // current frame in dispatchCreatePage. + if (canHandleRequest(request)) + (m_frame->loader()->policyChecker()->*func)(PolicyUse); + else + (m_frame->loader()->policyChecker()->*func)(PolicyIgnore); +} + +void FrameLoaderClientAndroid::cancelPolicyCheck() { + lowPriority_notImplemented(); +} + +void FrameLoaderClientAndroid::dispatchUnableToImplementPolicy(const ResourceError&) { + notImplemented(); +} + +void FrameLoaderClientAndroid::dispatchDecidePolicyForNavigationAction(FramePolicyFunction func, + const NavigationAction& action, const ResourceRequest& request, + PassRefPtr formState) { + ASSERT(m_frame); + ASSERT(func); + if (!func) + return; + if (request.isNull()) { + (m_frame->loader()->policyChecker()->*func)(PolicyIgnore); + return; + } + + // Reset multiple form submission protection. If this is a resubmission, we check with the + // user and reset the protection if they choose to resubmit the form (see WebCoreFrameBridge.cpp) + if (action.type() == NavigationTypeFormSubmitted) + m_frame->loader()->resetMultipleFormSubmissionProtection(); + + if (action.type() == NavigationTypeFormResubmitted) { + m_webFrame->decidePolicyForFormResubmission(func); + return; + } else + (m_frame->loader()->policyChecker()->*func)(PolicyUse); +} + +void FrameLoaderClientAndroid::dispatchWillSubmitForm(FramePolicyFunction func, PassRefPtr) { + ASSERT(m_frame); + ASSERT(func); + (m_frame->loader()->policyChecker()->*func)(PolicyUse); +} + +void FrameLoaderClientAndroid::dispatchWillSendSubmitEvent(HTMLFormElement* form) +{ + if (m_webFrame->shouldSaveFormData()) + m_webFrame->saveFormData(form); +} + +void FrameLoaderClientAndroid::dispatchDidLoadMainResource(DocumentLoader*) { + notImplemented(); +} + +void FrameLoaderClientAndroid::revertToProvisionalState(DocumentLoader*) { + notImplemented(); +} + +void FrameLoaderClientAndroid::setMainDocumentError(DocumentLoader* docLoader, const ResourceError& error) { + ASSERT(m_frame); + if (m_manualLoader) { + m_manualLoader->didFail(error); + m_manualLoader = NULL; + m_hasSentResponseToPlugin = false; + } else { + if (!error.isNull() && error.errorCode() >= InternalErrorLast && error.errorCode() != ERROR_OK) + m_webFrame->reportError(error.errorCode(), + error.localizedDescription(), error.failingURL()); + } +} + +// This function is called right before the progress is updated. +void FrameLoaderClientAndroid::willChangeEstimatedProgress() { + verifiedOk(); +} + +// This function is called after the progress has been updated. The bad part +// about this is that when a page is completed, this function is called after +// the progress has been reset to 0. +void FrameLoaderClientAndroid::didChangeEstimatedProgress() { + verifiedOk(); +} + +// This will give us the initial estimate when the page first starts to load. +void FrameLoaderClientAndroid::postProgressStartedNotification() { + ASSERT(m_frame); + if (m_frame->page()) + m_webFrame->setProgress(m_frame->page()->progress()->estimatedProgress()); +} + +// This will give us any updated progress including the final progress. +void FrameLoaderClientAndroid::postProgressEstimateChangedNotification() { + ASSERT(m_frame); + if (m_frame->page()) + m_webFrame->setProgress(m_frame->page()->progress()->estimatedProgress()); +} + +// This is just a notification that the progress has finished. Don't call +// setProgress(1) because postProgressEstimateChangedNotification will do so. +void FrameLoaderClientAndroid::postProgressFinishedNotification() { + WebViewCore* core = WebViewCore::getWebViewCore(m_frame->view()); + if (!m_frame->tree()->parent()) { + // only need to notify Java for the top frame + core->notifyProgressFinished(); + } + // notify plugins that the frame has loaded + core->notifyPluginsOnFrameLoad(m_frame); +} + +void FrameLoaderClientAndroid::setMainFrameDocumentReady(bool) { + // this is only interesting once we provide an external API for the DOM + notImplemented(); +} + +void FrameLoaderClientAndroid::startDownload(const ResourceRequest&) { + notImplemented(); +} + +void FrameLoaderClientAndroid::willChangeTitle(DocumentLoader*) { + verifiedOk(); +} + +void FrameLoaderClientAndroid::didChangeTitle(DocumentLoader* loader) { + verifiedOk(); +} + +void FrameLoaderClientAndroid::finishedLoading(DocumentLoader* docLoader) { + // Telling the frame we received some data and passing 0 as the data is our + // way to get work done that is normally done when the first bit of data is + // received, even for the case of a document with no data (like about:blank) + if (!m_manualLoader) { + committedLoad(docLoader, 0, 0); + return; + } + + m_manualLoader->didFinishLoading(); + m_manualLoader = NULL; + m_hasSentResponseToPlugin = false; +} + +void FrameLoaderClientAndroid::updateGlobalHistory() { + ASSERT(m_frame); + + DocumentLoader* docLoader = m_frame->loader()->documentLoader(); + ASSERT(docLoader); + + // Code copied from FrameLoader.cpp:createHistoryItem + // Only add this URL to the database if it is a valid page + if (docLoader->unreachableURL().isEmpty() + && docLoader->response().httpStatusCode() < 400) { + m_webFrame->updateVisitedHistory(docLoader->urlForHistory(), false); + if (!docLoader->serverRedirectSourceForHistory().isNull()) + m_webFrame->updateVisitedHistory(KURL(ParsedURLString, docLoader->serverRedirectDestinationForHistory()), false); + } +} + +void FrameLoaderClientAndroid::updateGlobalHistoryRedirectLinks() { + // Note, do we need to do anything where there is no HistoryItem? If we call + // updateGlobalHistory(), we will add bunch of "data:xxx" urls for gmail.com + // which is not what we want. Opt to do nothing now. +} + +bool FrameLoaderClientAndroid::shouldGoToHistoryItem(HistoryItem* item) const { + // hmmm, seems like we might do a more thoughtful check + ASSERT(m_frame); + return item != NULL; +} + +void FrameLoaderClientAndroid::didDisplayInsecureContent() +{ + notImplemented(); +} + +void FrameLoaderClientAndroid::didRunInsecureContent(SecurityOrigin*) +{ + notImplemented(); +} + +void FrameLoaderClientAndroid::committedLoad(DocumentLoader* loader, const char* data, int length) { + if (!m_manualLoader) + loader->commitData(data, length); + + // commit data may have created a manual plugin loader + if (m_manualLoader) { + if (!m_hasSentResponseToPlugin) { + m_manualLoader->didReceiveResponse(loader->response()); + // Failure could cause the main document to have an error causing + // the manual loader to be reset. + if (!m_manualLoader) + return; + m_hasSentResponseToPlugin = true; + } + m_manualLoader->didReceiveData(data, length); + } +} + +ResourceError FrameLoaderClientAndroid::cancelledError(const ResourceRequest& request) { + return ResourceError(String(), InternalErrorCancelled, request.url(), String()); +} + +ResourceError FrameLoaderClientAndroid::cannotShowURLError(const ResourceRequest& request) { + return ResourceError(String(), InternalErrorCannotShowUrl, request.url(), String()); +} + +ResourceError FrameLoaderClientAndroid::interruptForPolicyChangeError(const ResourceRequest& request) { + return ResourceError(String(), InternalErrorInterrupted, request.url(), String()); +} + +ResourceError FrameLoaderClientAndroid::cannotShowMIMETypeError(const ResourceResponse& request) { + return ResourceError(String(), InternalErrorCannotShowMimeType, request.url(), String()); +} + +ResourceError FrameLoaderClientAndroid::fileDoesNotExistError(const ResourceResponse& request) { + return ResourceError(String(), InternalErrorFileDoesNotExist, request.url(), String()); +} + +ResourceError FrameLoaderClientAndroid::pluginWillHandleLoadError(const ResourceResponse& request) { + return ResourceError(String(), InternalErrorPluginWillHandleLoadError, request.url(), String()); +} + +bool FrameLoaderClientAndroid::shouldFallBack(const ResourceError&) { + notImplemented(); + return false; +} + +bool FrameLoaderClientAndroid::canHandleRequest(const ResourceRequest& request) const { + ASSERT(m_frame); + // Don't allow hijacking of intrapage navigation + if (WebCore::equalIgnoringFragmentIdentifier(request.url(), m_frame->loader()->url())) + return true; + + // Don't allow hijacking of iframe urls that are http or https + if (request.url().protocol().startsWith("http", false) && + m_frame->tree() && m_frame->tree()->parent()) + return true; + + return m_webFrame->canHandleRequest(request); +} + +bool FrameLoaderClientAndroid::canShowMIMEType(const String& mimeType) const { + // FIXME: This looks like it has to do with whether or not a type can be + // shown "internally" (i.e. inside the browser) regardless of whether + // or not the browser is doing the rendering, e.g. a full page plugin. + if (MIMETypeRegistry::isSupportedImageResourceMIMEType(mimeType) || + MIMETypeRegistry::isSupportedNonImageMIMEType(mimeType) || + MIMETypeRegistry::isSupportedJavaScriptMIMEType(mimeType) || + (m_frame && m_frame->settings() + && m_frame->settings()->arePluginsEnabled() + && PluginDatabase::installedPlugins()->isMIMETypeRegistered( + mimeType)) || + (DOMImplementation::isTextMIMEType(mimeType) && + !mimeType.startsWith("text/vnd")) || + DOMImplementation::isXMLMIMEType(mimeType)) + return true; + return false; +} + +bool FrameLoaderClientAndroid::canShowMIMETypeAsHTML(const String& mimeType) const { + return false; +} + +bool FrameLoaderClientAndroid::representationExistsForURLScheme(const String&) const { + // don't use representation + verifiedOk(); + return false; +} + +String FrameLoaderClientAndroid::generatedMIMETypeForURLScheme(const String& URLScheme) const { + // FIXME, copy from Apple's port + String mimetype("x-apple-web-kit/"); + mimetype.append(URLScheme.lower()); + return mimetype; +} + +void FrameLoaderClientAndroid::frameLoadCompleted() { + // copied from Apple port, without this back with sub-frame will trigger ASSERT + ASSERT(m_frame); +} + +void FrameLoaderClientAndroid::saveViewStateToItem(HistoryItem* item) { + ASSERT(m_frame); + ASSERT(item); + // store the current scale (only) for the top frame + if (!m_frame->tree()->parent()) { + // We should have added a bridge when the child item was added to its + // parent. + AndroidWebHistoryBridge* bridge = item->bridge(); + ASSERT(bridge); + WebViewCore* webViewCore = WebViewCore::getWebViewCore(m_frame->view()); + bridge->setScale(webViewCore->scale()); + bridge->setTextWrapScale(webViewCore->textWrapScale()); + } + + WebCore::notifyHistoryItemChanged(item); +} + +void FrameLoaderClientAndroid::restoreViewState() { + WebViewCore* webViewCore = WebViewCore::getWebViewCore(m_frame->view()); + HistoryItem* item = m_frame->loader()->history()->currentItem(); + AndroidWebHistoryBridge* bridge = item->bridge(); + // restore the scale (only) for the top frame + if (!m_frame->tree()->parent()) { + webViewCore->restoreScale(bridge->scale(), bridge->textWrapScale()); + } +} + +void FrameLoaderClientAndroid::dispatchDidAddBackForwardItem(HistoryItem* item) const { + ASSERT(m_frame); + m_webFrame->addHistoryItem(item); +} + +void FrameLoaderClientAndroid::dispatchDidRemoveBackForwardItem(HistoryItem* item) const { + ASSERT(m_frame); + m_webFrame->removeHistoryItem(0); +} + +void FrameLoaderClientAndroid::dispatchDidChangeBackForwardIndex() const { + ASSERT(m_frame); + BackForwardList* list = m_frame->page()->backForwardList(); + ASSERT(list); + m_webFrame->updateHistoryIndex(list->backListCount()); +} + +void FrameLoaderClientAndroid::provisionalLoadStarted() { + ASSERT(m_frame); + m_webFrame->loadStarted(m_frame); +} + +void FrameLoaderClientAndroid::didFinishLoad() { + ASSERT(m_frame); + m_frame->document()->setExtraLayoutDelay(0); + m_webFrame->didFinishLoad(m_frame); +} + +void FrameLoaderClientAndroid::prepareForDataSourceReplacement() { + verifiedOk(); +} + +PassRefPtr FrameLoaderClientAndroid::createDocumentLoader( + const ResourceRequest& request, const SubstituteData& data) { + RefPtr loader = DocumentLoader::create(request, data); + return loader.release(); +} + +void FrameLoaderClientAndroid::setTitle(const String& title, const KURL& url) { + // Not needed. dispatchDidReceiveTitle is called immediately after this. + // url is used to update the Apple port history items. + verifiedOk(); +} + +String FrameLoaderClientAndroid::userAgent(const KURL& u) { + return m_webFrame->userAgentForURL(&u); +} + +void FrameLoaderClientAndroid::savePlatformDataToCachedFrame(WebCore::CachedFrame* cachedFrame) { + CachedFramePlatformDataAndroid* platformData = new CachedFramePlatformDataAndroid(m_frame->settings()); + cachedFrame->setCachedFramePlatformData(platformData); +} + +void FrameLoaderClientAndroid::transitionToCommittedFromCachedFrame(WebCore::CachedFrame* cachedFrame) { + CachedFramePlatformDataAndroid* platformData = reinterpret_cast(cachedFrame->cachedFramePlatformData()); +#ifdef ANDROID_META_SUPPORT + platformData->restoreMetadata(m_frame->settings()); +#endif + m_webFrame->transitionToCommitted(m_frame); +} + +void FrameLoaderClientAndroid::transitionToCommittedForNewPage() { + ASSERT(m_frame); + +#ifdef ANDROID_META_SUPPORT + // reset metadata settings for the main frame as they are not preserved cross page + if (m_frame == m_frame->page()->mainFrame() && m_frame->settings()) + m_frame->settings()->resetMetadataSettings(); +#endif + + // Save the old WebViewCore before creating a new FrameView. There is one + // WebViewCore per page. Each frame, including the main frame and sub frame, + // has a 1:1 FrameView and WebFrameView. + WebViewCore* webViewCore = WebViewCore::getWebViewCore(m_frame->view()); + Retain(webViewCore); + + // Save the old WebFrameView's bounds and apply them to the new WebFrameView + WebFrameView* oldWebFrameView = static_cast (m_frame->view()->platformWidget()); + IntRect bounds = oldWebFrameView->getBounds(); + IntRect visBounds = oldWebFrameView->getVisibleBounds(); + IntRect windowBounds = oldWebFrameView->getWindowBounds(); + WebCore::FrameView* oldFrameView = oldWebFrameView->view(); + const float oldZoomFactor = oldFrameView->frame()->textZoomFactor(); + m_frame->createView(bounds.size(), oldFrameView->baseBackgroundColor(), oldFrameView->isTransparent(), + oldFrameView->fixedLayoutSize(), oldFrameView->useFixedLayout()); + if (oldZoomFactor != 1.0f && oldZoomFactor != m_frame->textZoomFactor()) { + m_frame->setTextZoomFactor(oldZoomFactor); + } + + // Create a new WebFrameView for the new FrameView + WebFrameView* newFrameView = new WebFrameView(m_frame->view(), webViewCore); + newFrameView->setLocation(bounds.x(), bounds.y()); + newFrameView->setSize(bounds.width(), bounds.height()); + newFrameView->setVisibleSize(visBounds.width(), visBounds.height()); + newFrameView->setWindowBounds(windowBounds.x(), windowBounds.y(), windowBounds.width(), windowBounds.height()); + // newFrameView attaches itself to FrameView which Retains the reference, so + // call Release for newFrameView + Release(newFrameView); + // WebFrameView Retains webViewCore, so call Release for webViewCore + Release(webViewCore); + + m_webFrame->transitionToCommitted(m_frame); +} + +void FrameLoaderClientAndroid::dispatchDidBecomeFrameset(bool) +{ +} + +bool FrameLoaderClientAndroid::canCachePage() const { + return true; +} + +void FrameLoaderClientAndroid::download(ResourceHandle* handle, const ResourceRequest&, + const ResourceRequest&, const ResourceResponse&) { + // Get the C++ side of the load listener and tell it to handle the download + handle->getInternal()->m_loader->downloadFile(); +} + +WTF::PassRefPtr FrameLoaderClientAndroid::createFrame(const KURL& url, const String& name, + HTMLFrameOwnerElement* ownerElement, const String& referrer, + bool allowsScrolling, int marginWidth, int marginHeight) +{ + Frame* parent = ownerElement->document()->frame(); + FrameLoaderClientAndroid* loaderC = new FrameLoaderClientAndroid(m_webFrame); + RefPtr pFrame = Frame::create(parent->page(), ownerElement, loaderC); + Frame* newFrame = pFrame.get(); + loaderC->setFrame(newFrame); + // Append the subframe to the parent and set the name of the subframe. The name must be set after + // appending the child so that the name becomes unique. + parent->tree()->appendChild(newFrame); + newFrame->tree()->setName(name); + // Create a new FrameView and WebFrameView for the child frame to draw into. + RefPtr frameView = FrameView::create(newFrame); + WebFrameView* webFrameView = new WebFrameView(frameView.get(), + WebViewCore::getWebViewCore(parent->view())); + // frameView Retains webFrameView, so call Release for webFrameView + Release(webFrameView); + // Attach the frameView to the newFrame. + newFrame->setView(frameView); + newFrame->init(); + newFrame->selection()->setFocused(true); + LOGV("::WebCore:: createSubFrame returning %p", newFrame); + + // The creation of the frame may have run arbitrary JavaScript that removed it from the page already. + if (!pFrame->page()) + return 0; + + parent->loader()->loadURLIntoChildFrame(url, referrer, pFrame.get()); + + // onLoad may cuase the frame to be removed from the document. Allow the RefPtr to delete the child frame. + if (!pFrame->tree()->parent()) + return NULL; + + return pFrame.release(); +} + +// YouTube flash url path starts with /v/ +static const char slash_v_slash[] = { '/', 'v', '/' }; +static const char slash_e_slash[] = { '/', 'e', '/' }; + +static bool isValidYouTubeVideo(const String& path) +{ + if (!charactersAreAllASCII(path.characters(), path.length())) + return false; + unsigned int len = path.length(); + if (len <= sizeof(slash_v_slash)) // check for more than just /v/ + return false; + CString str = path.lower().utf8(); + const char* data = str.data(); + // Youtube flash url can start with /v/ or /e/ + if (memcmp(data, slash_v_slash, sizeof(slash_v_slash)) != 0) + if (memcmp(data, slash_e_slash, sizeof(slash_e_slash)) != 0) + return false; + // Start after /v/ + for (unsigned int i = sizeof(slash_v_slash); i < len; i++) { + char c = data[i]; + // Check for alpha-numeric characters only. + if (WTF::isASCIIAlphanumeric(c) || c == '_' || c == '-') + continue; + // The url can have more parameters such as &hl=en after the video id. + // Once we start seeing extra parameters we can return true. + return c == '&' && i > sizeof(slash_v_slash); + } + return true; +} + +static bool isYouTubeUrl(const KURL& url, const String& mimeType) +{ + String host = url.host(); + bool youtube = host.endsWith("youtube.com") + || host.endsWith("youtube-nocookie.com"); + return youtube && isValidYouTubeVideo(url.path()) + && equalIgnoringCase(mimeType, "application/x-shockwave-flash"); +} + +static bool isYouTubeInstalled() { + return WebCore::packageNotifier().isPackageInstalled("com.google.android.youtube"); +} + +// Use PluginViewBase rather than an Android specific sub class as we do not require any +// Android specific functionality; this just renders a placeholder which will later +// activate the real plugin. +class PluginToggleWidget : public PluginViewBase { +public: + PluginToggleWidget(Frame* parent, const IntSize& size, + HTMLPlugInElement* elem, const KURL& url, + const WTF::Vector& paramNames, + const WTF::Vector& paramValues, const String& mimeType, + bool loadManually) + : PluginViewBase(0) + , m_parent(parent) + , m_size(size) + , m_element(elem) + , m_url(url) + , m_paramNames(paramNames) + , m_paramValues(paramValues) + , m_mimeType(mimeType) + , m_loadManually(loadManually) + { + resize(size); + } + + virtual void paint(GraphicsContext* ctx, const IntRect& rect) + { + // Most of this code is copied from PluginView::paintMissingPluginIcon + // with slight modification. + + static RefPtr image; + if (!image) { + image = Image::loadPlatformResource("togglePlugin"); + } + + IntRect imageRect(x(), y(), image->width(), image->height()); + + int xOffset = (width() - imageRect.width()) >> 1; + int yOffset = (height() - imageRect.height()) >> 1; + + imageRect.move(xOffset, yOffset); + + if (!rect.intersects(imageRect)) + return; + + // FIXME: We need to clip similarly to paintMissingPluginIcon but it is + // way screwed up right now. It has something to do with how we tell + // webkit the scroll position and it causes the placeholder to get + // clipped very badly. http://b/issue?id=2533303 + + ctx->save(); + ctx->clip(frameRect()); + + ctx->setFillColor(Color::white, ColorSpaceDeviceRGB); + ctx->fillRect(frameRect()); + if (frameRect().contains(imageRect)) { + // Leave a 2 pixel padding. + const int pixelWidth = 2; + IntRect innerRect = frameRect(); + innerRect.inflate(-pixelWidth); + // Draw a 2 pixel light gray border. + ctx->setStrokeColor(Color::lightGray, ColorSpaceDeviceRGB); + ctx->strokeRect(innerRect, pixelWidth); + } + + // Draw the image in the center + ctx->drawImage(image.get(), ColorSpaceDeviceRGB, imageRect.location()); + ctx->restore(); + } + + virtual void handleEvent(Event* event) + { + if (event->type() != eventNames().clickEvent) + return; + + Frame* frame = m_parent->page()->mainFrame(); + while (frame) { + RenderView* view = frame->contentRenderer(); + const HashSet widgets = view->widgets(); + HashSet::const_iterator it = widgets.begin(); + HashSet::const_iterator end = widgets.end(); + for (; it != end; ++it) { + Widget* widget = (*it)->widget(); + // PluginWidget is used only with PluginToggleWidget + if (widget && widget->isPluginViewBase()) { + PluginToggleWidget* ptw = + static_cast(widget); + ptw->swapPlugin(*it); + } + } + frame = frame->tree()->traverseNext(); + } + } + + void swapPlugin(RenderWidget* renderer) { + typedef FrameLoaderClientAndroid FLCA; + FLCA* client = static_cast(m_parent->loader()->client()); + client->enableOnDemandPlugins(); + WTF::PassRefPtr prpWidget = + PluginView::create(m_parent.get(), + m_size, + m_element, + m_url, + m_paramNames, + m_paramValues, + m_mimeType, + m_loadManually); + RefPtr myProtector(this); + prpWidget->focusPluginElement(); + renderer->setWidget(prpWidget); + } + +private: + void invalidateRect(const IntRect& rect) { } + + RefPtr m_parent; + IntSize m_size; + HTMLPlugInElement* m_element; + KURL m_url; + WTF::Vector m_paramNames; + WTF::Vector m_paramValues; + String m_mimeType; + bool m_loadManually; +}; + +WTF::PassRefPtr FrameLoaderClientAndroid::createPlugin( + const IntSize& size, + HTMLPlugInElement* element, + const KURL& url, + const WTF::Vector& names, + const WTF::Vector& values, + const String& mimeType, + bool loadManually) { + WTF::PassRefPtr prpWidget = 0; +#ifdef ANDROID_PLUGINS + // This is copied from PluginView.cpp. We need to determine if a plugin + // will be found before doing some of the work in PluginView. + String mimeTypeCopy = mimeType; + PluginPackage* plugin = + PluginDatabase::installedPlugins()->findPlugin(url, mimeTypeCopy); + if (!plugin && PluginDatabase::installedPlugins()->refresh()) { + mimeTypeCopy = mimeType; + plugin = PluginDatabase::installedPlugins()->findPlugin(url, + mimeTypeCopy); + } + Settings* settings = m_frame->settings(); + // Do the placeholder if plugins are on-demand and there is a plugin for the + // given mime type. + if (settings && settings->arePluginsOnDemand() && plugin && + !m_onDemandPluginsEnabled) { + return adoptRef(new PluginToggleWidget(m_frame, size, element, url, + names, values, mimeType, loadManually)); + } + prpWidget = PluginView::create(m_frame, + size, + element, + url, + names, + values, + mimeType, + loadManually); + // Return the plugin if it was loaded successfully. Otherwise, fallback to + // the youtube placeholder if possible. No need to check prpWidget as + // PluginView::create will create a PluginView for missing plugins. + // Note: this check really only checks if the plugin was found and not if + // the plugin was loaded. + if (prpWidget->status() == PluginStatusLoadedSuccessfully) + return prpWidget; +#endif + // Create an iframe for youtube urls. + if (isYouTubeUrl(url, mimeType) && isYouTubeInstalled()) { + WTF::RefPtr frame = createFrame(blankURL(), String(), element, + String(), false, 0, 0); + if (frame) { + // grab everything after /v/ + String videoId = url.path().substring(sizeof(slash_v_slash)); + // Extract just the video id + unsigned videoIdEnd = 0; + for (; videoIdEnd < videoId.length(); videoIdEnd++) { + if (videoId[videoIdEnd] == '&') { + videoId = videoId.left(videoIdEnd); + break; + } + } + AssetManager* am = globalAssetManager(); + Asset* a = am->open("webkit/youtube.html", + Asset::ACCESS_BUFFER); + if (!a) + return NULL; + String s = String((const char*)a->getBuffer(false), a->getLength()); + s = s.replace("VIDEO_ID", videoId); + delete a; + loadDataIntoFrame(frame.get(), + KURL(ParsedURLString, "file:///android_asset/webkit/"), String(), s); + // Transfer ownership to a local refptr. + WTF::RefPtr widget(frame->view()); + return widget.release(); + } + } + return prpWidget; +} + +void FrameLoaderClientAndroid::redirectDataToPlugin(Widget* pluginWidget) { + // Do not redirect data if the Widget is our plugin placeholder. + if (pluginWidget->isPluginView()) { + m_manualLoader = static_cast(pluginWidget); + } +} + +WTF::PassRefPtr FrameLoaderClientAndroid::createJavaAppletWidget(const IntSize&, HTMLAppletElement*, + const KURL& baseURL, const WTF::Vector& paramNames, + const WTF::Vector& paramValues) { + // don't support widget yet + notImplemented(); + return 0; +} + +void FrameLoaderClientAndroid::didTransferChildFrameToNewDocument(WebCore::Page*) +{ + ASSERT(m_frame); + // m_webFrame points to the WebFrame for the page that our frame previously + // belonged to. If the frame now belongs to a new page, we need to update + // m_webFrame to point to the WebFrame for the new page. + Page* newPage = m_frame->page(); + if (newPage != m_webFrame->page()) { + ChromeClientAndroid* chromeClient = static_cast(newPage->chrome()->client()); + Release(m_webFrame); + m_webFrame = chromeClient->webFrame(); + Retain(m_webFrame); + } +} + +void FrameLoaderClientAndroid::transferLoadingResourceFromPage(unsigned long, DocumentLoader*, const ResourceRequest&, Page*) +{ + notImplemented(); +} + +// This function is used by the element to determine the type of +// the contents and work out if it can render it. +ObjectContentType FrameLoaderClientAndroid::objectContentType(const KURL& url, + const String& mimeType) { + return FrameLoader::defaultObjectContentType(url, mimeType); +} + +// This function allows the application to set the correct CSS media +// style. Android could use it to set the media style 'handheld'. Safari +// may use it to set the media style to 'print' when the user wants to print +// a particular web page. +String FrameLoaderClientAndroid::overrideMediaType() const { + lowPriority_notImplemented(); + return String(); +} + +// This function is used to re-attach Javascript<->native code classes. +void FrameLoaderClientAndroid::dispatchDidClearWindowObjectInWorld(DOMWrapperWorld* world) +{ + if (world != mainThreadNormalWorld()) + return; + + ASSERT(m_frame); + LOGV("::WebCore:: windowObjectCleared called on frame %p for %s\n", + m_frame, m_frame->loader()->url().string().ascii().data()); + m_webFrame->windowObjectCleared(m_frame); +} + +void FrameLoaderClientAndroid::documentElementAvailable() { +} + +// functions new to Jun-07 tip of tree merge: +ResourceError FrameLoaderClientAndroid::blockedError(ResourceRequest const& request) { + return ResourceError(String(), InternalErrorFileDoesNotExist, String(), String()); +} + +// functions new to Nov-07 tip of tree merge: +void FrameLoaderClientAndroid::didPerformFirstNavigation() const { + // This seems to be just a notification that the UI can listen to, to + // know if the user has performed first navigation action. + // It is called from + // void FrameLoader::addBackForwardItemClippedAtTarget(bool doClip) + // "Navigation" here means a transition from one page to another that + // ends up in the back/forward list. +} + +void FrameLoaderClientAndroid::registerForIconNotification(bool listen) { + if (listen) + WebIconDatabase::RegisterForIconNotification(this); + else + WebIconDatabase::UnregisterForIconNotification(this); +} + +// This is the WebIconDatabaseClient method for receiving a notification when we +// get the icon for the page. +void FrameLoaderClientAndroid::didAddIconForPageUrl(const String& pageUrl) { + // This call must happen before dispatchDidReceiveIcon since that method + // may register for icon notifications again since the icon data may have + // to be read from disk. + registerForIconNotification(false); + KURL u(ParsedURLString, pageUrl); + if (equalIgnoringFragmentIdentifier(u, m_frame->loader()->url())) { + dispatchDidReceiveIcon(); + } +} + +void FrameLoaderClientAndroid::dispatchDidChangeIcons() { + notImplemented(); +} + +PassRefPtr FrameLoaderClientAndroid::createNetworkingContext() +{ + return FrameNetworkingContextAndroid::create(getFrame()); +} + +} diff --git a/Source/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.h b/Source/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.h new file mode 100644 index 0000000..25561a8 --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.h @@ -0,0 +1,271 @@ +/* + * 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 FrameLoaderClientAndroid_h +#define FrameLoaderClientAndroid_h + +#include "CacheBuilder.h" +#include "FrameLoaderClient.h" +#include "ResourceResponse.h" +#include "WebIconDatabase.h" +#include + +namespace WebCore { +class PluginManualLoader; +} + +using namespace WebCore; + +namespace android { + class WebFrame; + + class FrameLoaderClientAndroid : public FrameLoaderClient, + WebIconDatabaseClient { + public: + FrameLoaderClientAndroid(WebFrame* webframe); + + Frame* getFrame() { return m_frame; } + static FrameLoaderClientAndroid* get(const Frame* frame); + + void setFrame(Frame* frame) { m_frame = frame; } + WebFrame* webFrame() const { return m_webFrame; } + + virtual void frameLoaderDestroyed(); + + virtual bool hasWebView() const; // mainly for assertions + + virtual void makeRepresentation(DocumentLoader*); + virtual void forceLayout(); + virtual void forceLayoutForNonHTML(); + + virtual void setCopiesOnScroll(); + + virtual void detachedFromParent2(); + virtual void detachedFromParent3(); + + virtual void assignIdentifierToInitialRequest(unsigned long identifier, DocumentLoader*, const ResourceRequest&); + + virtual void dispatchWillSendRequest(DocumentLoader*, unsigned long identifier, ResourceRequest&, const ResourceResponse& redirectResponse); + virtual bool shouldUseCredentialStorage(DocumentLoader*, unsigned long identifier); + virtual void dispatchDidReceiveAuthenticationChallenge(DocumentLoader*, unsigned long identifier, const AuthenticationChallenge&); + virtual void dispatchDidCancelAuthenticationChallenge(DocumentLoader*, unsigned long identifier, const AuthenticationChallenge&); + virtual void dispatchDidReceiveResponse(DocumentLoader*, unsigned long identifier, const ResourceResponse&); + virtual void dispatchDidReceiveContentLength(DocumentLoader*, unsigned long identifier, int lengthReceived); + virtual void dispatchDidFinishLoading(DocumentLoader*, unsigned long identifier); + virtual void dispatchDidFailLoading(DocumentLoader*, unsigned long identifier, const ResourceError&); + virtual bool dispatchDidLoadResourceFromMemoryCache(DocumentLoader*, const ResourceRequest&, const ResourceResponse&, int length); + + virtual void dispatchDidHandleOnloadEvents(); + virtual void dispatchDidReceiveServerRedirectForProvisionalLoad(); + virtual void dispatchDidCancelClientRedirect(); + virtual void dispatchWillPerformClientRedirect(const KURL&, double interval, double fireDate); + virtual void dispatchDidChangeLocationWithinPage(); + virtual void dispatchDidPushStateWithinPage(); + virtual void dispatchDidReplaceStateWithinPage(); + virtual void dispatchDidPopStateWithinPage(); + virtual void dispatchWillClose(); + virtual void dispatchDidReceiveIcon(); + virtual void dispatchDidStartProvisionalLoad(); + virtual void dispatchDidReceiveTitle(const String& title); + virtual void dispatchDidCommitLoad(); + virtual void dispatchDidFailProvisionalLoad(const ResourceError&); + virtual void dispatchDidFailLoad(const ResourceError&); + virtual void dispatchDidFinishDocumentLoad(); + virtual void dispatchDidFinishLoad(); + virtual void dispatchDidFirstLayout(); + virtual void dispatchDidFirstVisuallyNonEmptyLayout(); + + virtual Frame* dispatchCreatePage(const NavigationAction&); + virtual void dispatchShow(); + + virtual void dispatchDecidePolicyForMIMEType(FramePolicyFunction, const String& MIMEType, const ResourceRequest&); + virtual void dispatchDecidePolicyForNewWindowAction(FramePolicyFunction, const NavigationAction&, const ResourceRequest&, PassRefPtr, const String& frameName); + virtual void dispatchDecidePolicyForNavigationAction(FramePolicyFunction, const NavigationAction&, const ResourceRequest&, PassRefPtr); + virtual void cancelPolicyCheck(); + + virtual void dispatchUnableToImplementPolicy(const ResourceError&); + + virtual void dispatchWillSubmitForm(FramePolicyFunction, PassRefPtr); + + virtual void dispatchDidLoadMainResource(DocumentLoader*); + virtual void revertToProvisionalState(DocumentLoader*); + virtual void setMainDocumentError(DocumentLoader*, const ResourceError&); + + virtual void willChangeEstimatedProgress(); + virtual void didChangeEstimatedProgress(); + virtual void postProgressStartedNotification(); + virtual void postProgressEstimateChangedNotification(); + virtual void postProgressFinishedNotification(); + + virtual void setMainFrameDocumentReady(bool); + + virtual void startDownload(const ResourceRequest&); + + virtual void willChangeTitle(DocumentLoader*); + virtual void didChangeTitle(DocumentLoader*); + + virtual void committedLoad(DocumentLoader*, const char*, int); + virtual void finishedLoading(DocumentLoader*); + + virtual void updateGlobalHistory(); + virtual void updateGlobalHistoryRedirectLinks(); + + virtual bool shouldGoToHistoryItem(HistoryItem*) const; + + virtual void didDisplayInsecureContent(); + virtual void didRunInsecureContent(SecurityOrigin*); + + virtual void dispatchDidAddBackForwardItem(HistoryItem*) const; + virtual void dispatchDidRemoveBackForwardItem(HistoryItem*) const; + virtual void dispatchDidChangeBackForwardIndex() const; + + virtual ResourceError cancelledError(const ResourceRequest&); + virtual ResourceError blockedError(const ResourceRequest&); + virtual ResourceError cannotShowURLError(const ResourceRequest&); + virtual ResourceError interruptForPolicyChangeError(const ResourceRequest&); + + virtual ResourceError cannotShowMIMETypeError(const ResourceResponse&); + virtual ResourceError fileDoesNotExistError(const ResourceResponse&); + virtual ResourceError pluginWillHandleLoadError(const ResourceResponse&); + + virtual bool shouldFallBack(const ResourceError&); + + virtual bool canHandleRequest(const ResourceRequest&) const; + virtual bool canShowMIMEType(const String& MIMEType) const; + virtual bool canShowMIMETypeAsHTML(const String& MIMEType) const; + virtual bool representationExistsForURLScheme(const String& URLScheme) const; + virtual String generatedMIMETypeForURLScheme(const String& URLScheme) const; + + virtual void frameLoadCompleted(); + virtual void saveViewStateToItem(HistoryItem*); + virtual void restoreViewState(); + virtual void provisionalLoadStarted(); + virtual void didFinishLoad(); + virtual void prepareForDataSourceReplacement(); + + virtual PassRefPtr createDocumentLoader(const ResourceRequest&, const SubstituteData&); + virtual void setTitle(const String& title, const KURL&); + + // This provides the userAgent to WebCore. It is used by WebCore to + // populate navigator.userAgent and to set the HTTP header in + // ResourceRequest objects. We also set a userAgent on WebRequestContext + // for the Chromium HTTP stack, which overrides the value on the + // ResourceRequest. + virtual String userAgent(const KURL&); + + virtual void savePlatformDataToCachedFrame(WebCore::CachedFrame*); + virtual void transitionToCommittedFromCachedFrame(WebCore::CachedFrame*); + virtual void transitionToCommittedForNewPage(); + + virtual void dispatchDidBecomeFrameset(bool isFrameSet); + + virtual bool canCachePage() const; + virtual void download(ResourceHandle*, const ResourceRequest&, const ResourceRequest&, const ResourceResponse&); + + virtual WTF::PassRefPtr createFrame(const KURL& url, const String& name, HTMLFrameOwnerElement* ownerElement, const String& referrer, bool allowsScrolling, int marginWidth, int marginHeight); + virtual void didTransferChildFrameToNewDocument(WebCore::Page*); + virtual void transferLoadingResourceFromPage(unsigned long identifier, DocumentLoader*, const ResourceRequest&, Page* oldPage); + virtual WTF::PassRefPtr createPlugin(const IntSize&, HTMLPlugInElement*, const KURL&, const WTF::Vector&, const WTF::Vector&, const String&, bool loadManually); + virtual void redirectDataToPlugin(Widget* pluginWidget); + + virtual WTF::PassRefPtr createJavaAppletWidget(const IntSize&, HTMLAppletElement*, const KURL& baseURL, const WTF::Vector& paramNames, const WTF::Vector& paramValues); + + virtual ObjectContentType objectContentType(const KURL& url, const String& mimeType); + virtual String overrideMediaType() const; + + virtual void dispatchDidClearWindowObjectInWorld(DOMWrapperWorld*); + virtual void documentElementAvailable(); + virtual void didPerformFirstNavigation() const; + +#if USE(V8) + // TODO(benm): Implement + virtual void didCreateScriptContextForFrame() { } + virtual void didDestroyScriptContextForFrame() { } + virtual void didCreateIsolatedScriptContext() { } + + virtual bool allowScriptExtension(const String& extensionName, int extensionGroup) { return false; } +#endif + + virtual void registerForIconNotification(bool listen = true); + + virtual void dispatchDidReceiveTouchIconURL(const String& url, bool precomposed); + + virtual PassRefPtr createNetworkingContext(); + + // 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(); + void dispatchWillSendSubmitEvent(HTMLFormElement*); + + virtual void didSaveToPageCache() { } + virtual void didRestoreFromPageCache() { } + private: + CacheBuilder m_cacheBuilder; + Frame* m_frame; + WebFrame* m_webFrame; + PluginManualLoader* m_manualLoader; + bool m_hasSentResponseToPlugin; + bool m_onDemandPluginsEnabled; + + enum ResourceErrors { + InternalErrorCancelled = -99, + InternalErrorCannotShowUrl, + InternalErrorInterrupted, + InternalErrorCannotShowMimeType, + InternalErrorFileDoesNotExist, + InternalErrorPluginWillHandleLoadError, + InternalErrorLast + }; + + /* XXX: These must match android.net.http.EventHandler */ + enum EventHandlerErrors { + Error = -1, + ErrorLookup = -2, + ErrorUnsupportedAuthScheme = -3, + ErrorAuth = -4, + ErrorProxyAuth = -5, + ErrorConnect = -6, + ErrorIO = -7, + ErrorTimeout = -8, + ErrorRedirectLoop = -9, + ErrorUnsupportedScheme = -10, + ErrorFailedSslHandshake = -11, + ErrorBadUrl = -12, + ErrorFile = -13, + ErrorFileNotFound = -14, + ErrorTooManyRequests = -15 + }; + friend class CacheBuilder; + }; + +} + +#endif diff --git a/Source/WebKit/android/WebCoreSupport/FrameNetworkingContextAndroid.cpp b/Source/WebKit/android/WebCoreSupport/FrameNetworkingContextAndroid.cpp new file mode 100644 index 0000000..a5fe494 --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/FrameNetworkingContextAndroid.cpp @@ -0,0 +1,52 @@ +/* + * 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 "FrameNetworkingContextAndroid.h" + +#include "DocumentLoader.h" +#include "MainResourceLoader.h" +#include "Settings.h" + +using namespace WebCore; + +namespace android { + +FrameNetworkingContextAndroid::FrameNetworkingContextAndroid(WebCore::Frame* frame) + : WebCore::FrameNetworkingContext(frame) +{ +} + +MainResourceLoader* FrameNetworkingContextAndroid::mainResourceLoader() const +{ + return frame()->loader()->activeDocumentLoader()->mainResourceLoader(); +} + +FrameLoaderClient* FrameNetworkingContextAndroid::frameLoaderClient() const +{ + return frame()->loader()->client(); +} + +} // namespace android diff --git a/Source/WebKit/android/WebCoreSupport/FrameNetworkingContextAndroid.h b/Source/WebKit/android/WebCoreSupport/FrameNetworkingContextAndroid.h new file mode 100644 index 0000000..d0ff979 --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/FrameNetworkingContextAndroid.h @@ -0,0 +1,54 @@ +/* + * 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 FrameNetworkingContextAndroid_h +#define FrameNetworkingContextAndroid_h + +#include "FrameNetworkingContext.h" + +namespace WebCore { +class MainResourceLoader; +class FrameLoaderClient; +} + +namespace android { + +class FrameNetworkingContextAndroid : public WebCore::FrameNetworkingContext { +public: + static PassRefPtr create(WebCore::Frame* frame) + { + return adoptRef(new FrameNetworkingContextAndroid(frame)); + } + +private: + FrameNetworkingContextAndroid(WebCore::Frame*); + + virtual WebCore::MainResourceLoader* mainResourceLoader() const; + virtual WebCore::FrameLoaderClient* frameLoaderClient() const; +}; + +} // namespace android + +#endif // FrameNetworkingContextAndroid_h diff --git a/Source/WebKit/android/WebCoreSupport/GeolocationPermissions.cpp b/Source/WebKit/android/WebCoreSupport/GeolocationPermissions.cpp new file mode 100755 index 0000000..36a9b61 --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/GeolocationPermissions.cpp @@ -0,0 +1,419 @@ +/* + * 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 "config.h" +#include "GeolocationPermissions.h" + +#include "DOMWindow.h" +#include "Frame.h" +#include "Geolocation.h" +#include "Navigator.h" +#include "SQLiteDatabase.h" +#include "SQLiteFileSystem.h" +#include "SQLiteStatement.h" +#include "SQLiteTransaction.h" +#include "WebViewCore.h" + +#include + +using namespace WebCore; + +namespace android { + +GeolocationPermissions::PermissionsMap GeolocationPermissions::s_permanentPermissions; +GeolocationPermissions::GeolocationPermissionsVector GeolocationPermissions::s_instances; +bool GeolocationPermissions::s_alwaysDeny = false; +bool GeolocationPermissions::s_permanentPermissionsLoaded = false; +bool GeolocationPermissions::s_permanentPermissionsModified = false; +String GeolocationPermissions::s_databasePath; + +static const char* databaseName = "GeolocationPermissions.db"; + +GeolocationPermissions::GeolocationPermissions(WebViewCore* webViewCore, Frame* mainFrame) + : m_webViewCore(webViewCore) + , m_mainFrame(mainFrame) + , m_timer(this, &GeolocationPermissions::timerFired) + +{ + ASSERT(m_webViewCore); + maybeLoadPermanentPermissions(); + s_instances.append(this); +} + +GeolocationPermissions::~GeolocationPermissions() +{ + size_t index = s_instances.find(this); + s_instances.remove(index); +} + +void GeolocationPermissions::queryPermissionState(Frame* frame) +{ + ASSERT(s_permanentPermissionsLoaded); + + // We use SecurityOrigin::toString to key the map. Note that testing + // the SecurityOrigin pointer for equality is insufficient. + String originString = frame->document()->securityOrigin()->toString(); + + // If we've been told to always deny requests, do so. + if (s_alwaysDeny) { + makeAsynchronousCallbackToGeolocation(originString, false); + return; + } + + // See if we have a record for this origin in the permanent permissions. + // These take precedence over temporary permissions so that changes made + // from the browser settings work as intended. + PermissionsMap::const_iterator iter = s_permanentPermissions.find(originString); + PermissionsMap::const_iterator end = s_permanentPermissions.end(); + if (iter != end) { + bool allow = iter->second; + makeAsynchronousCallbackToGeolocation(originString, allow); + return; + } + + // Check the temporary permisions. + iter = m_temporaryPermissions.find(originString); + end = m_temporaryPermissions.end(); + if (iter != end) { + bool allow = iter->second; + makeAsynchronousCallbackToGeolocation(originString, allow); + return; + } + + // If there's no pending request, prompt the user. + if (nextOriginInQueue().isEmpty()) { + // Although multiple tabs may request permissions for the same origin + // simultaneously, the routing in WebViewCore/CallbackProxy ensures that + // the result of the request will make it back to this object, so + // there's no need for a globally unique ID for the request. + m_webViewCore->geolocationPermissionsShowPrompt(originString); + } + + // Add this request to the queue so we can track which frames requested it. + if (m_queuedOrigins.find(originString) == WTF::notFound) { + m_queuedOrigins.append(originString); + FrameSet frameSet; + frameSet.add(frame); + m_queuedOriginsToFramesMap.add(originString, frameSet); + } else { + ASSERT(m_queuedOriginsToFramesMap.contains(originString)); + m_queuedOriginsToFramesMap.find(originString)->second.add(frame); + } +} + +void GeolocationPermissions::cancelPermissionStateQuery(WebCore::Frame* frame) +{ + // We cancel any queued request for the given frame. There can be at most + // one of these, since each frame maps to a single origin. We only cancel + // the request if this frame is the only one reqesting permission for this + // origin. + // + // We can use the origin string to avoid searching the map. + String originString = frame->document()->securityOrigin()->toString(); + size_t index = m_queuedOrigins.find(originString); + if (index == WTF::notFound) + return; + + ASSERT(m_queuedOriginsToFramesMap.contains(originString)); + OriginToFramesMap::iterator iter = m_queuedOriginsToFramesMap.find(originString); + ASSERT(iter->second.contains(frame)); + iter->second.remove(frame); + if (!iter->second.isEmpty()) + return; + + m_queuedOrigins.remove(index); + m_queuedOriginsToFramesMap.remove(iter); + + // If this is the origin currently being shown, cancel the prompt + // and show the next in the queue, if present. + if (index == 0) { + m_webViewCore->geolocationPermissionsHidePrompt(); + if (!nextOriginInQueue().isEmpty()) + m_webViewCore->geolocationPermissionsShowPrompt(nextOriginInQueue()); + } +} + +void GeolocationPermissions::makeAsynchronousCallbackToGeolocation(String origin, bool allow) +{ + m_callbackData.origin = origin; + m_callbackData.allow = allow; + m_timer.startOneShot(0); +} + +void GeolocationPermissions::providePermissionState(String origin, bool allow, bool remember) +{ + ASSERT(s_permanentPermissionsLoaded); + + // It's possible that this method is called with an origin that doesn't + // match m_originInProgress. This can occur if this object is reset + // while a permission result is in the process of being marshalled back to + // the WebCore thread from the browser. In this case, we simply ignore the + // call. + if (origin != nextOriginInQueue()) + return; + + maybeCallbackFrames(origin, allow); + recordPermissionState(origin, allow, remember); + + // If the permissions are set to be remembered, cancel any queued requests + // for this domain in other tabs. + if (remember) + cancelPendingRequestsInOtherTabs(origin); + + // Clear the origin from the queue. + ASSERT(!m_queuedOrigins.isEmpty()); + m_queuedOrigins.remove(0); + ASSERT(m_queuedOriginsToFramesMap.contains(origin)); + m_queuedOriginsToFramesMap.remove(origin); + + // If there are other requests queued, start the next one. + if (!nextOriginInQueue().isEmpty()) + m_webViewCore->geolocationPermissionsShowPrompt(nextOriginInQueue()); +} + +void GeolocationPermissions::recordPermissionState(String origin, bool allow, bool remember) +{ + if (remember) { + s_permanentPermissions.set(origin, allow); + s_permanentPermissionsModified = true; + } else { + // It's possible that another tab recorded a permanent permission for + // this origin while our request was in progress, but we record it + // anyway. + m_temporaryPermissions.set(origin, allow); + } +} + +void GeolocationPermissions::cancelPendingRequestsInOtherTabs(String origin) +{ + for (GeolocationPermissionsVector::const_iterator iter = s_instances.begin(); + iter != s_instances.end(); + ++iter) + (*iter)->cancelPendingRequests(origin); +} + +void GeolocationPermissions::cancelPendingRequests(String origin) +{ + size_t index = m_queuedOrigins.find(origin); + + // Don't cancel the request if it's currently being shown, in which case + // it's at index 0. + if (index == WTF::notFound || !index) + return; + + // Get the permission from the permanent list. + ASSERT(s_permanentPermissions.contains(origin)); + PermissionsMap::const_iterator iter = s_permanentPermissions.find(origin); + bool allow = iter->second; + + maybeCallbackFrames(origin, allow); + + m_queuedOrigins.remove(index); + ASSERT(m_queuedOriginsToFramesMap.contains(origin)); + m_queuedOriginsToFramesMap.remove(origin); +} + +void GeolocationPermissions::timerFired(Timer* timer) +{ + ASSERT_UNUSED(timer, timer == &m_timer); + maybeCallbackFrames(m_callbackData.origin, m_callbackData.allow); +} + +void GeolocationPermissions::resetTemporaryPermissionStates() +{ + ASSERT(s_permanentPermissionsLoaded); + m_queuedOrigins.clear(); + m_queuedOriginsToFramesMap.clear(); + m_temporaryPermissions.clear(); + // If any permission results are being marshalled back to this thread, this + // will render them inefective. + m_timer.stop(); + + m_webViewCore->geolocationPermissionsHidePrompt(); +} + +const WTF::String& GeolocationPermissions::nextOriginInQueue() +{ + static const String emptyString = ""; + return m_queuedOrigins.isEmpty() ? emptyString : m_queuedOrigins[0]; +} + +void GeolocationPermissions::maybeCallbackFrames(String origin, bool allow) +{ + // We can't track which frame issued the request, as frames can be deleted + // or have their contents replaced. Even uniqueChildName is not unique when + // frames are dynamically deleted and created. Instead, we simply call back + // to the Geolocation object in all frames from the correct origin. + for (Frame* frame = m_mainFrame; frame; frame = frame->tree()->traverseNext()) { + if (origin == frame->document()->securityOrigin()->toString()) { + // If the page has changed, it may no longer have a Geolocation + // object. + Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation(); + if (geolocation) + geolocation->setIsAllowed(allow); + } + } +} + +GeolocationPermissions::OriginSet GeolocationPermissions::getOrigins() +{ + maybeLoadPermanentPermissions(); + OriginSet origins; + PermissionsMap::const_iterator end = s_permanentPermissions.end(); + for (PermissionsMap::const_iterator iter = s_permanentPermissions.begin(); iter != end; ++iter) + origins.add(iter->first); + return origins; +} + +bool GeolocationPermissions::getAllowed(String origin) +{ + maybeLoadPermanentPermissions(); + bool allowed = false; + PermissionsMap::const_iterator iter = s_permanentPermissions.find(origin); + PermissionsMap::const_iterator end = s_permanentPermissions.end(); + if (iter != end) + allowed = iter->second; + return allowed; +} + +void GeolocationPermissions::clear(String origin) +{ + maybeLoadPermanentPermissions(); + PermissionsMap::iterator iter = s_permanentPermissions.find(origin); + if (iter != s_permanentPermissions.end()) { + s_permanentPermissions.remove(iter); + s_permanentPermissionsModified = true; + } +} + +void GeolocationPermissions::allow(String origin) +{ + maybeLoadPermanentPermissions(); + // We replace any existing permanent permission. + s_permanentPermissions.set(origin, true); + s_permanentPermissionsModified = true; +} + +void GeolocationPermissions::clearAll() +{ + maybeLoadPermanentPermissions(); + s_permanentPermissions.clear(); + s_permanentPermissionsModified = true; +} + +void GeolocationPermissions::maybeLoadPermanentPermissions() +{ + if (s_permanentPermissionsLoaded) + return; + s_permanentPermissionsLoaded = true; + + SQLiteDatabase database; + if (!openDatabase(&database)) + return; + + // Create the table here, such that even if we've just created the DB, the + // commands below should succeed. + if (!database.executeCommand("CREATE TABLE IF NOT EXISTS Permissions (origin TEXT UNIQUE NOT NULL, allow INTEGER NOT NULL)")) { + database.close(); + return; + } + + SQLiteStatement statement(database, "SELECT * FROM Permissions"); + if (statement.prepare() != SQLResultOk) { + database.close(); + return; + } + + ASSERT(s_permanentPermissions.size() == 0); + while (statement.step() == SQLResultRow) + s_permanentPermissions.set(statement.getColumnText(0), statement.getColumnInt64(1)); + + database.close(); +} + +void GeolocationPermissions::maybeStorePermanentPermissions() +{ + // If the permanent permissions haven't been modified, there's no need to + // save them to the DB. (If we haven't even loaded them, writing them now + // would overwrite the stored permissions with the empty set.) + if (!s_permanentPermissionsModified) + return; + + SQLiteDatabase database; + if (!openDatabase(&database)) + return; + + SQLiteTransaction transaction(database); + + // The number of entries should be small enough that it's not worth trying + // to perform a diff. Simply clear the table and repopulate it. + if (!database.executeCommand("DELETE FROM Permissions")) { + database.close(); + return; + } + + PermissionsMap::const_iterator end = s_permanentPermissions.end(); + for (PermissionsMap::const_iterator iter = s_permanentPermissions.begin(); iter != end; ++iter) { + SQLiteStatement statement(database, "INSERT INTO Permissions (origin, allow) VALUES (?, ?)"); + if (statement.prepare() != SQLResultOk) + continue; + statement.bindText(1, iter->first); + statement.bindInt64(2, iter->second); + statement.executeCommand(); + } + + transaction.commit(); + database.close(); + + s_permanentPermissionsModified = false; +} + +void GeolocationPermissions::setDatabasePath(String path) +{ + // Take the first non-empty value. + if (s_databasePath.length() > 0) + return; + s_databasePath = path; +} + +bool GeolocationPermissions::openDatabase(SQLiteDatabase* database) +{ + ASSERT(database); + String filename = SQLiteFileSystem::appendDatabaseFileNameToPath(s_databasePath, databaseName); + if (!database->open(filename)) + return false; + if (chmod(filename.utf8().data(), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)) { + database->close(); + return false; + } + return true; +} + +void GeolocationPermissions::setAlwaysDeny(bool deny) +{ + s_alwaysDeny = deny; +} + +} // namespace android diff --git a/Source/WebKit/android/WebCoreSupport/GeolocationPermissions.h b/Source/WebKit/android/WebCoreSupport/GeolocationPermissions.h new file mode 100644 index 0000000..fb31dfe --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/GeolocationPermissions.h @@ -0,0 +1,178 @@ +/* + * 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 GeolocationPermissions_h +#define GeolocationPermissions_h + +#include "PlatformString.h" +#include "Timer.h" + +#include +#include +#include +#include +#include + +namespace WebCore { + class Frame; + class Geolocation; + class SQLiteDatabase; +} + +namespace android { + + class WebViewCore; + + // The GeolocationPermissions class manages Geolocation permissions for the + // browser. Permissions are managed on a per-origin basis, as required by + // the Geolocation spec - http://dev.w3.org/geo/api/spec-source.html. An + // origin specifies the scheme, host and port of particular frame. An + // origin is represented here as a string, using the output of + // WebCore::SecurityOrigin::toString. + // + // Each instance handles permissions for a given main frame. The class + // enforces the following policy. + // - Non-remembered permissions last for the dureation of the main frame. + // - Remembered permissions last indefinitely. + // - All permissions are shared between child frames of a main frame. + // - Only remembered permissions are shared between main frames. + // - Remembered permissions are made available for use in the browser + // settings menu. + class GeolocationPermissions : public RefCounted { + public: + // Creates the GeolocationPermissions object to manage permissions for + // the specified main frame (i.e. tab). The WebViewCore is used to + // communicate with the browser to display UI. + GeolocationPermissions(WebViewCore* webViewCore, WebCore::Frame* mainFrame); + virtual ~GeolocationPermissions(); + + // Queries the permission state for the specified frame. If the + // permission state has not yet been set, prompts the user. Once the + // permission state has been determined, asynchronously calls back to + // the Geolocation objects in all frames in this WebView that are from + // the same origin as the requesting frame. + void queryPermissionState(WebCore::Frame* frame); + void cancelPermissionStateQuery(WebCore::Frame*); + + // Provides this object with a permission state set by the user. The + // permission is specified by 'allow' and applied to 'origin'. If + // 'remember' is set, the permission state is remembered permanently. + // The new permission state is recorded and will trigger callbacks to + // geolocation objects as described above. If any other permission + // requests are queued, the next is started. + void providePermissionState(WTF::String origin, bool allow, bool remember); + + // Clears the temporary permission state and any pending requests. Used + // when the main frame is refreshed or navigated to a new URL. + void resetTemporaryPermissionStates(); + + // Static methods for use from Java. These are used to interact with the + // browser settings menu and to update the permanent permissions when + // system settings are changed. + // Gets the list of all origins for which permanent permissions are + // recorded. + typedef HashSet OriginSet; + static OriginSet getOrigins(); + // Gets whether the specified origin is allowed. + static bool getAllowed(WTF::String origin); + // Clears the permission state for the specified origin. + static void clear(WTF::String origin); + // Sets the permission state for the specified origin to allowed. + static void allow(WTF::String origin); + // Clears the permission state for all origins. + static void clearAll(); + // Sets whether the GeolocationPermissions object should always deny + // permission requests, irrespective of previously recorded permission + // states. + static void setAlwaysDeny(bool deny); + + static void setDatabasePath(WTF::String path); + static bool openDatabase(WebCore::SQLiteDatabase*); + + // Saves the permanent permissions to the DB if required. + static void maybeStorePermanentPermissions(); + + private: + // Records the permission state for the specified origin and whether + // this should be remembered. + void recordPermissionState(WTF::String origin, bool allow, bool remember); + + // Used to make an asynchronous callback to the Geolocation objects. + void makeAsynchronousCallbackToGeolocation(WTF::String origin, bool allow); + void timerFired(WebCore::Timer* timer); + + // Calls back to the Geolocation objects in all frames from the + // specified origin. There may be no such objects, as the frames using + // Geolocation from the specified origin may no longer use Geolocation, + // or may have been navigated to a different origin.. + void maybeCallbackFrames(WTF::String origin, bool allow); + + // Cancels pending permission requests for the specified origin in + // other main frames (ie browser tabs). This is used when the user + // specifies permission to be remembered. + static void cancelPendingRequestsInOtherTabs(WTF::String origin); + void cancelPendingRequests(WTF::String origin); + + static void maybeLoadPermanentPermissions(); + + const WTF::String& nextOriginInQueue(); + + WebViewCore* m_webViewCore; + WebCore::Frame* m_mainFrame; + // A vector of the origins queued to make a permission request. + // The first in the vector is the origin currently making the request. + typedef Vector OriginVector; + OriginVector m_queuedOrigins; + // A map from a queued origin to the set of frames that have requested + // permission for that origin. + typedef HashSet FrameSet; + typedef HashMap OriginToFramesMap; + OriginToFramesMap m_queuedOriginsToFramesMap; + + typedef WTF::HashMap PermissionsMap; + PermissionsMap m_temporaryPermissions; + static PermissionsMap s_permanentPermissions; + + typedef WTF::Vector GeolocationPermissionsVector; + static GeolocationPermissionsVector s_instances; + + WebCore::Timer m_timer; + + struct CallbackData { + WTF::String origin; + bool allow; + }; + CallbackData m_callbackData; + + static bool s_alwaysDeny; + + static bool s_permanentPermissionsLoaded; + static bool s_permanentPermissionsModified; + static WTF::String s_databasePath; + }; + +} // namespace android + +#endif diff --git a/Source/WebKit/android/WebCoreSupport/InspectorClientAndroid.h b/Source/WebKit/android/WebCoreSupport/InspectorClientAndroid.h new file mode 100644 index 0000000..9d734e8 --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/InspectorClientAndroid.h @@ -0,0 +1,54 @@ +/* + * 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 InspectorClientAndroid_h +#define InspectorClientAndroid_h + +#include "InspectorClient.h" + +#include + +namespace android { + +class InspectorClientAndroid : public InspectorClient { +public: + virtual ~InspectorClientAndroid() { } + + virtual void inspectorDestroyed() { delete this; } + + virtual void openInspectorFrontend(WebCore::InspectorController*) {} + + virtual void highlight(Node*) {} + virtual void hideHighlight() {} + + virtual void populateSetting(const String& key, String* value) {} + virtual void storeSetting(const String& key, const String& value) {} + + virtual bool sendMessageToFrontend(const WTF::String&) { return false; } +}; + +} + +#endif diff --git a/Source/WebKit/android/WebCoreSupport/KeyGeneratorClient.h b/Source/WebKit/android/WebCoreSupport/KeyGeneratorClient.h new file mode 100644 index 0000000..1bcd8e8 --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/KeyGeneratorClient.h @@ -0,0 +1,46 @@ +/* + * 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 KEY_GENERATOR_CLIENT_H +#define KEY_GENERATOR_CLIENT_H + +#include "KURL.h" +#include "PlatformString.h" + +#include + +using namespace WebCore; + +namespace android { + +class KeyGeneratorClient { +public: + virtual ~KeyGeneratorClient() { } + virtual WTF::Vector getSupportedKeyStrengthList() = 0; + virtual String getSignedPublicKeyAndChallengeString(unsigned index, + const String& challenge, const KURL& url) = 0; + }; +} +#endif diff --git a/Source/WebKit/android/WebCoreSupport/MediaPlayerPrivateAndroid.cpp b/Source/WebKit/android/WebCoreSupport/MediaPlayerPrivateAndroid.cpp new file mode 100644 index 0000000..e6a2710 --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/MediaPlayerPrivateAndroid.cpp @@ -0,0 +1,654 @@ +/* + * 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 "config.h" +#include "MediaPlayerPrivateAndroid.h" + +#if ENABLE(VIDEO) + +#include "BaseLayerAndroid.h" +#include "DocumentLoader.h" +#include "Frame.h" +#include "FrameLoader.h" +#include "FrameView.h" +#include "GraphicsContext.h" +#include "SkiaUtils.h" +#include "VideoLayerAndroid.h" +#include "WebCoreJni.h" +#include "WebViewCore.h" +#include +#include +#include +#include +#include + +using namespace android; +// Forward decl +namespace android { +sp SurfaceTexture_getSurfaceTexture(JNIEnv* env, jobject thiz); +}; + +namespace WebCore { + +static const char* g_ProxyJavaClass = "android/webkit/HTML5VideoViewProxy"; +static const char* g_ProxyJavaClassAudio = "android/webkit/HTML5Audio"; + +struct MediaPlayerPrivate::JavaGlue { + jobject m_javaProxy; + jmethodID m_play; + jmethodID m_teardown; + jmethodID m_seek; + jmethodID m_pause; + // Audio + jmethodID m_newInstance; + jmethodID m_setDataSource; + jmethodID m_getMaxTimeSeekable; + // Video + jmethodID m_getInstance; + jmethodID m_loadPoster; +}; + +MediaPlayerPrivate::~MediaPlayerPrivate() +{ + // m_videoLayer is reference counted, unref is enough here. + m_videoLayer->unref(); + if (m_glue->m_javaProxy) { + JNIEnv* env = JSC::Bindings::getJNIEnv(); + if (env) { + env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_teardown); + env->DeleteGlobalRef(m_glue->m_javaProxy); + } + } + delete m_glue; +} + +void MediaPlayerPrivate::registerMediaEngine(MediaEngineRegistrar registrar) +{ + registrar(create, getSupportedTypes, supportsType); +} + +MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String& type, const String& codecs) +{ + if (WebViewCore::isSupportedMediaMimeType(type)) + return MediaPlayer::MayBeSupported; + return MediaPlayer::IsNotSupported; +} + +void MediaPlayerPrivate::pause() +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + if (!env || !m_glue->m_javaProxy || !m_url.length()) + return; + + m_paused = true; + m_player->playbackStateChanged(); + env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_pause); + checkException(env); +} + +void MediaPlayerPrivate::setVisible(bool visible) +{ + m_isVisible = visible; + if (m_isVisible) + createJavaPlayerIfNeeded(); +} + +void MediaPlayerPrivate::seek(float time) +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + if (!env || !m_url.length()) + return; + + if (m_glue->m_javaProxy) { + env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_seek, static_cast(time * 1000.0f)); + m_currentTime = time; + } + checkException(env); +} + +void MediaPlayerPrivate::prepareToPlay() +{ + // We are about to start playing. Since our Java VideoView cannot + // buffer any data, we just simply transition to the HaveEnoughData + // state in here. This will allow the MediaPlayer to transition to + // the "play" state, at which point our VideoView will start downloading + // the content and start the playback. + m_networkState = MediaPlayer::Loaded; + m_player->networkStateChanged(); + m_readyState = MediaPlayer::HaveEnoughData; + m_player->readyStateChanged(); +} + +MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player) + : m_player(player), + m_glue(0), + m_duration(1), // keep this minimal to avoid initial seek problem + m_currentTime(0), + m_paused(true), + m_readyState(MediaPlayer::HaveNothing), + m_networkState(MediaPlayer::Empty), + m_poster(0), + m_naturalSize(100, 100), + m_naturalSizeUnknown(true), + m_isVisible(false), + m_videoLayer(new VideoLayerAndroid()) +{ +} + +void MediaPlayerPrivate::onEnded() +{ + m_currentTime = duration(); + m_player->timeChanged(); + m_paused = true; + m_player->playbackStateChanged(); + m_networkState = MediaPlayer::Idle; +} + +void MediaPlayerPrivate::onPaused() +{ + m_paused = true; + m_player->playbackStateChanged(); + m_networkState = MediaPlayer::Idle; + m_player->playbackStateChanged(); +} + +void MediaPlayerPrivate::onTimeupdate(int position) +{ + m_currentTime = position / 1000.0f; + m_player->timeChanged(); +} + +void MediaPlayerPrivate::onStopFullscreen() +{ + if (m_player && m_player->mediaPlayerClient() + && m_player->mediaPlayerClient()->mediaPlayerOwningDocument()) { + m_player->mediaPlayerClient()->mediaPlayerOwningDocument()->webkitCancelFullScreen(); + } +} + +class MediaPlayerVideoPrivate : public MediaPlayerPrivate { +public: + void load(const String& url) + { + m_url = url; + // Cheat a bit here to make sure Window.onLoad event can be triggered + // at the right time instead of real video play time, since only full + // screen video play is supported in Java's VideoView. + // See also comments in prepareToPlay function. + m_networkState = MediaPlayer::Loading; + m_player->networkStateChanged(); + m_readyState = MediaPlayer::HaveCurrentData; + m_player->readyStateChanged(); + } + + void play() + { + JNIEnv* env = JSC::Bindings::getJNIEnv(); + if (!env || !m_url.length() || !m_glue->m_javaProxy) + return; + + // We only play video fullscreen on Android, so stop sites playing fullscreen video in the onload handler. + Frame* frame = m_player->frameView()->frame(); + if (frame && !frame->loader()->documentLoader()->wasOnloadHandled()) + return; + + m_paused = false; + m_player->playbackStateChanged(); + + if (m_currentTime == duration()) + m_currentTime = 0; + + jstring jUrl = wtfStringToJstring(env, m_url); + env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_play, jUrl, + static_cast(m_currentTime * 1000.0f), + m_videoLayer->uniqueId()); + env->DeleteLocalRef(jUrl); + + checkException(env); + } + bool canLoadPoster() const { return true; } + void setPoster(const String& url) + { + if (m_posterUrl == url) + return; + + m_posterUrl = url; + JNIEnv* env = JSC::Bindings::getJNIEnv(); + if (!env || !m_glue->m_javaProxy || !m_posterUrl.length()) + return; + // Send the poster + jstring jUrl = wtfStringToJstring(env, m_posterUrl); + env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_loadPoster, jUrl); + env->DeleteLocalRef(jUrl); + } + void paint(GraphicsContext* ctxt, const IntRect& r) + { + if (ctxt->paintingDisabled()) + return; + + if (!m_isVisible) + return; + + if (!m_poster || (!m_poster->getPixels() && !m_poster->pixelRef())) + return; + + SkCanvas* canvas = ctxt->platformContext()->mCanvas; + // We paint with the following rules in mind: + // - only downscale the poster, never upscale + // - maintain the natural aspect ratio of the poster + // - the poster should be centered in the target rect + float originalRatio = static_cast(m_poster->width()) / static_cast(m_poster->height()); + int posterWidth = r.width() > m_poster->width() ? m_poster->width() : r.width(); + int posterHeight = posterWidth / originalRatio; + int posterX = ((r.width() - posterWidth) / 2) + r.x(); + int posterY = ((r.height() - posterHeight) / 2) + r.y(); + IntRect targetRect(posterX, posterY, posterWidth, posterHeight); + canvas->drawBitmapRect(*m_poster, 0, targetRect, 0); + } + + void onPosterFetched(SkBitmap* poster) + { + m_poster = poster; + if (m_naturalSizeUnknown) { + // We had to fake the size at startup, or else our paint + // method would not be called. If we haven't yet received + // the onPrepared event, update the intrinsic size to the size + // of the poster. That will be overriden when onPrepare comes. + // In case of an error, we should report the poster size, rather + // than our initial fake value. + m_naturalSize = IntSize(poster->width(), poster->height()); + m_player->sizeChanged(); + } + } + + void onPrepared(int duration, int width, int height) + { + m_duration = duration / 1000.0f; + m_naturalSize = IntSize(width, height); + m_naturalSizeUnknown = false; + m_player->durationChanged(); + m_player->sizeChanged(); + } + + virtual bool hasAudio() const { return false; } // do not display the audio UI + virtual bool hasVideo() const { return true; } + virtual bool supportsFullscreen() const { return true; } + + MediaPlayerVideoPrivate(MediaPlayer* player) : MediaPlayerPrivate(player) + { + JNIEnv* env = JSC::Bindings::getJNIEnv(); + if (!env) + return; + + jclass clazz = env->FindClass(g_ProxyJavaClass); + + if (!clazz) + return; + + m_glue = new JavaGlue; + m_glue->m_getInstance = env->GetStaticMethodID(clazz, "getInstance", "(Landroid/webkit/WebViewCore;I)Landroid/webkit/HTML5VideoViewProxy;"); + m_glue->m_loadPoster = env->GetMethodID(clazz, "loadPoster", "(Ljava/lang/String;)V"); + m_glue->m_play = env->GetMethodID(clazz, "play", "(Ljava/lang/String;II)V"); + + m_glue->m_teardown = env->GetMethodID(clazz, "teardown", "()V"); + m_glue->m_seek = env->GetMethodID(clazz, "seek", "(I)V"); + m_glue->m_pause = env->GetMethodID(clazz, "pause", "()V"); + m_glue->m_javaProxy = 0; + env->DeleteLocalRef(clazz); + // An exception is raised if any of the above fails. + checkException(env); + } + + void createJavaPlayerIfNeeded() + { + // Check if we have been already created. + if (m_glue->m_javaProxy) + return; + + JNIEnv* env = JSC::Bindings::getJNIEnv(); + if (!env) + return; + + jclass clazz = env->FindClass(g_ProxyJavaClass); + + if (!clazz) + return; + + jobject obj = 0; + + FrameView* frameView = m_player->frameView(); + if (!frameView) + return; + WebViewCore* webViewCore = WebViewCore::getWebViewCore(frameView); + ASSERT(webViewCore); + + // Get the HTML5VideoViewProxy instance + obj = env->CallStaticObjectMethod(clazz, m_glue->m_getInstance, webViewCore->getJavaObject().get(), this); + m_glue->m_javaProxy = env->NewGlobalRef(obj); + // Send the poster + jstring jUrl = 0; + if (m_posterUrl.length()) + jUrl = wtfStringToJstring(env, m_posterUrl); + // Sending a NULL jUrl allows the Java side to try to load the default poster. + env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_loadPoster, jUrl); + if (jUrl) + env->DeleteLocalRef(jUrl); + + // Clean up. + if (obj) + env->DeleteLocalRef(obj); + env->DeleteLocalRef(clazz); + checkException(env); + } + + float maxTimeSeekable() const + { + return m_duration; + } +}; + +class MediaPlayerAudioPrivate : public MediaPlayerPrivate { +public: + void load(const String& url) + { + m_url = url; + JNIEnv* env = JSC::Bindings::getJNIEnv(); + if (!env || !m_url.length()) + return; + + createJavaPlayerIfNeeded(); + + if (!m_glue->m_javaProxy) + return; + + jstring jUrl = wtfStringToJstring(env, m_url); + // start loading the data asynchronously + env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_setDataSource, jUrl); + env->DeleteLocalRef(jUrl); + checkException(env); + } + + void play() + { + JNIEnv* env = JSC::Bindings::getJNIEnv(); + if (!env || !m_url.length()) + return; + + createJavaPlayerIfNeeded(); + + if (!m_glue->m_javaProxy) + return; + + m_paused = false; + m_player->playbackStateChanged(); + env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_play); + checkException(env); + } + + virtual bool hasAudio() const { return true; } + virtual bool hasVideo() const { return false; } + virtual bool supportsFullscreen() const { return false; } + + float maxTimeSeekable() const + { + if (m_glue->m_javaProxy) { + JNIEnv* env = JSC::Bindings::getJNIEnv(); + if (env) { + float maxTime = env->CallFloatMethod(m_glue->m_javaProxy, + m_glue->m_getMaxTimeSeekable); + checkException(env); + return maxTime; + } + } + return 0; + } + + MediaPlayerAudioPrivate(MediaPlayer* player) : MediaPlayerPrivate(player) + { + JNIEnv* env = JSC::Bindings::getJNIEnv(); + if (!env) + return; + + jclass clazz = env->FindClass(g_ProxyJavaClassAudio); + + if (!clazz) + return; + + m_glue = new JavaGlue; + m_glue->m_newInstance = env->GetMethodID(clazz, "", "(I)V"); + m_glue->m_setDataSource = env->GetMethodID(clazz, "setDataSource", "(Ljava/lang/String;)V"); + m_glue->m_play = env->GetMethodID(clazz, "play", "()V"); + m_glue->m_getMaxTimeSeekable = env->GetMethodID(clazz, "getMaxTimeSeekable", "()F"); + m_glue->m_teardown = env->GetMethodID(clazz, "teardown", "()V"); + m_glue->m_seek = env->GetMethodID(clazz, "seek", "(I)V"); + m_glue->m_pause = env->GetMethodID(clazz, "pause", "()V"); + m_glue->m_javaProxy = 0; + env->DeleteLocalRef(clazz); + // An exception is raised if any of the above fails. + checkException(env); + } + + void createJavaPlayerIfNeeded() + { + // Check if we have been already created. + if (m_glue->m_javaProxy) + return; + + JNIEnv* env = JSC::Bindings::getJNIEnv(); + if (!env) + return; + + jclass clazz = env->FindClass(g_ProxyJavaClassAudio); + + if (!clazz) + return; + + jobject obj = 0; + + // Get the HTML5Audio instance + obj = env->NewObject(clazz, m_glue->m_newInstance, this); + m_glue->m_javaProxy = env->NewGlobalRef(obj); + + // Clean up. + if (obj) + env->DeleteLocalRef(obj); + env->DeleteLocalRef(clazz); + checkException(env); + } + + void onPrepared(int duration, int width, int height) + { + // Android media player gives us a duration of 0 for a live + // stream, so in that case set the real duration to infinity. + // We'll still be able to handle the case that we genuinely + // get an audio clip with a duration of 0s as we'll get the + // ended event when it stops playing. + if (duration > 0) { + m_duration = duration / 1000.0f; + } else { + m_duration = std::numeric_limits::infinity(); + } + m_player->durationChanged(); + m_player->sizeChanged(); + m_player->prepareToPlay(); + } +}; + +MediaPlayerPrivateInterface* MediaPlayerPrivate::create(MediaPlayer* player) +{ + if (player->mediaElementType() == MediaPlayer::Video) + return new MediaPlayerVideoPrivate(player); + return new MediaPlayerAudioPrivate(player); +} + +} + +namespace android { + +static void OnPrepared(JNIEnv* env, jobject obj, int duration, int width, int height, int pointer) +{ + if (pointer) { + WebCore::MediaPlayerPrivate* player = reinterpret_cast(pointer); + player->onPrepared(duration, width, height); + } +} + +static void OnEnded(JNIEnv* env, jobject obj, int pointer) +{ + if (pointer) { + WebCore::MediaPlayerPrivate* player = reinterpret_cast(pointer); + player->onEnded(); + } +} + +static void OnPaused(JNIEnv* env, jobject obj, int pointer) +{ + if (pointer) { + WebCore::MediaPlayerPrivate* player = reinterpret_cast(pointer); + player->onPaused(); + } +} + +static void OnPosterFetched(JNIEnv* env, jobject obj, jobject poster, int pointer) +{ + if (!pointer || !poster) + return; + + WebCore::MediaPlayerPrivate* player = reinterpret_cast(pointer); + SkBitmap* posterNative = GraphicsJNI::getNativeBitmap(env, poster); + if (!posterNative) + return; + player->onPosterFetched(posterNative); +} + +static void OnBuffering(JNIEnv* env, jobject obj, int percent, int pointer) +{ + if (pointer) { + WebCore::MediaPlayerPrivate* player = reinterpret_cast(pointer); + // TODO: player->onBuffering(percent); + } +} + +static void OnTimeupdate(JNIEnv* env, jobject obj, int position, int pointer) +{ + if (pointer) { + WebCore::MediaPlayerPrivate* player = reinterpret_cast(pointer); + player->onTimeupdate(position); + } +} + +// 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 +// video layers on the UI thread. Therefore, on the UI thread, we have to use +// the videoLayerId from Java side to find the exact video layer in the tree +// to set the surface texture. +// Every time a play call into Java side, the videoLayerId will be sent and +// saved in Java side. Then every time setBaseLayer call, the saved +// videoLayerId will be passed to this function to find the Video Layer. +// Return value: true when the video layer is found. +static bool SendSurfaceTexture(JNIEnv* env, jobject obj, jobject surfTex, + int baseLayer, int videoLayerId, + int textureName, int playerState) { + if (!surfTex) + return false; + + sp texture = android::SurfaceTexture_getSurfaceTexture(env, surfTex); + if (!texture.get()) + return false; + + BaseLayerAndroid* layerImpl = reinterpret_cast(baseLayer); + if (!layerImpl) + return false; + if (!layerImpl->countChildren()) + return false; + LayerAndroid* compositedRoot = static_cast(layerImpl->getChild(0)); + if (!compositedRoot) + return false; + + VideoLayerAndroid* videoLayer = + static_cast(compositedRoot->findById(videoLayerId)); + if (!videoLayer) + return false; + + // Set the SurfaceTexture to the layer we found + videoLayer->setSurfaceTexture(texture, textureName, static_cast(playerState)); + return true; +} + +static void OnStopFullscreen(JNIEnv* env, jobject obj, int pointer) +{ + if (pointer) { + WebCore::MediaPlayerPrivate* player = + reinterpret_cast(pointer); + player->onStopFullscreen(); + } +} + +/* + * JNI registration + */ +static JNINativeMethod g_MediaPlayerMethods[] = { + { "nativeOnPrepared", "(IIII)V", + (void*) OnPrepared }, + { "nativeOnEnded", "(I)V", + (void*) OnEnded }, + { "nativeOnStopFullscreen", "(I)V", + (void*) OnStopFullscreen }, + { "nativeOnPaused", "(I)V", + (void*) OnPaused }, + { "nativeOnPosterFetched", "(Landroid/graphics/Bitmap;I)V", + (void*) OnPosterFetched }, + { "nativeSendSurfaceTexture", "(Landroid/graphics/SurfaceTexture;IIII)Z", + (void*) SendSurfaceTexture }, + { "nativeOnTimeupdate", "(II)V", + (void*) OnTimeupdate }, +}; + +static JNINativeMethod g_MediaAudioPlayerMethods[] = { + { "nativeOnBuffering", "(II)V", + (void*) OnBuffering }, + { "nativeOnEnded", "(I)V", + (void*) OnEnded }, + { "nativeOnPrepared", "(IIII)V", + (void*) OnPrepared }, + { "nativeOnTimeupdate", "(II)V", + (void*) OnTimeupdate }, +}; + +int registerMediaPlayerVideo(JNIEnv* env) +{ + return jniRegisterNativeMethods(env, g_ProxyJavaClass, + g_MediaPlayerMethods, NELEM(g_MediaPlayerMethods)); +} + +int registerMediaPlayerAudio(JNIEnv* env) +{ + return jniRegisterNativeMethods(env, g_ProxyJavaClassAudio, + g_MediaAudioPlayerMethods, NELEM(g_MediaAudioPlayerMethods)); +} + +} +#endif // VIDEO diff --git a/Source/WebKit/android/WebCoreSupport/MemoryUsage.cpp b/Source/WebKit/android/WebCoreSupport/MemoryUsage.cpp new file mode 100644 index 0000000..32cdebf --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/MemoryUsage.cpp @@ -0,0 +1,81 @@ +/* + * 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 "MemoryUsage.h" + +#include +#include + +#if USE(V8) +#include +#endif // USE(V8) + +using namespace WTF; + +class MemoryUsageCache { +public: + MemoryUsageCache() + : m_cachedMemoryUsage(0) + , m_cacheTime(0) + { + } + + int getCachedMemoryUsage(bool forceFresh); + +private: + unsigned m_cachedMemoryUsage; + double m_cacheTime; + static const int CACHE_VALIDITY_MS = 2000; +}; + +int MemoryUsageCache::getCachedMemoryUsage(bool forceFresh) +{ + if (!forceFresh && currentTimeMS() <= m_cacheTime + CACHE_VALIDITY_MS) + return m_cachedMemoryUsage; + + 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; +} + +int MemoryUsage::memoryUsageMb(bool forceFresh) +{ + static MemoryUsageCache cache; + return cache.getCachedMemoryUsage(forceFresh); +} + +int MemoryUsage::m_lowMemoryUsageMb = 0; +int MemoryUsage::m_highMemoryUsageMb = 0; +int MemoryUsage::m_highUsageDeltaMb = 0; diff --git a/Source/WebKit/android/WebCoreSupport/MemoryUsage.h b/Source/WebKit/android/WebCoreSupport/MemoryUsage.h new file mode 100644 index 0000000..2a3d7ed --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/MemoryUsage.h @@ -0,0 +1,45 @@ +/* + * 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 MemoryUsage_h +#define MemoryUsage_h + +class MemoryUsage { +public: + static int memoryUsageMb(bool forceFresh); + static int lowMemoryUsageMb() { return m_lowMemoryUsageMb; } + static int highMemoryUsageMb() { return m_highMemoryUsageMb; } + static int highUsageDeltaMb() { return m_highUsageDeltaMb; } + static void setHighMemoryUsageMb(int highMemoryUsageMb) { m_highMemoryUsageMb = highMemoryUsageMb; } + static void setLowMemoryUsageMb(int lowMemoryUsageMb) { m_lowMemoryUsageMb = lowMemoryUsageMb; } + static void setHighUsageDeltaMb(int highUsageDeltaMb) { m_highUsageDeltaMb = highUsageDeltaMb; } + +private: + static int m_lowMemoryUsageMb; + static int m_highMemoryUsageMb; + static int m_highUsageDeltaMb; +}; + +#endif diff --git a/Source/WebKit/android/WebCoreSupport/PlatformBridge.cpp b/Source/WebKit/android/WebCoreSupport/PlatformBridge.cpp new file mode 100644 index 0000000..8d8d809 --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/PlatformBridge.cpp @@ -0,0 +1,261 @@ +/* + * 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 "config.h" +#include + +#include "CookieClient.h" +#include "Document.h" +#include "FileSystemClient.h" +#include "FrameView.h" +#include "JavaSharedClient.h" +#include "KeyGeneratorClient.h" +#include "MemoryUsage.h" +#include "PluginView.h" +#include "Settings.h" +#include "WebCookieJar.h" +#include "WebRequestContext.h" +#include "WebViewCore.h" +#include "npruntime.h" + +#include +#include +#include +#include +#include + +using namespace android; + +namespace WebCore { + +WTF::Vector PlatformBridge::getSupportedKeyStrengthList() +{ + KeyGeneratorClient* client = JavaSharedClient::GetKeyGeneratorClient(); + if (!client) + return WTF::Vector(); + + return client->getSupportedKeyStrengthList(); +} + +String PlatformBridge::getSignedPublicKeyAndChallengeString(unsigned index, const String& challenge, const KURL& url) +{ + KeyGeneratorClient* client = JavaSharedClient::GetKeyGeneratorClient(); + if (!client) + return String(); + + return client->getSignedPublicKeyAndChallengeString(index, challenge, url); +} + +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(widget); + return pluginView->getNPObject(); +#else + return 0; +#endif +} + +bool PlatformBridge::isWebViewPaused(const WebCore::FrameView* frameView) +{ + android::WebViewCore* webViewCore = android::WebViewCore::getWebViewCore(frameView); + return webViewCore->isPaused(); +} + +bool PlatformBridge::popupsAllowed(NPP) +{ + return false; +} + +String PlatformBridge::resolveFilePathForContentUri(const String& contentUri) +{ + FileSystemClient* client = JavaSharedClient::GetFileSystemClient(); + return client->resolveFilePathForContentUri(contentUri); +} + +int PlatformBridge::PlatformBridge::screenDepth() +{ + android::DisplayInfo info; + android::SurfaceComposerClient::getDisplayInfo(android::DisplayID(0), &info); + return info.pixelFormatInfo.bitsPerPixel; +} + +FloatRect PlatformBridge::screenRect() +{ + android::DisplayInfo info; + android::SurfaceComposerClient::getDisplayInfo(android::DisplayID(0), &info); + return FloatRect(0.0, 0.0, info.w, info.h); +} + +// The visible size on screen in document coordinate +int PlatformBridge::screenWidthInDocCoord(const WebCore::FrameView* frameView) +{ + android::WebViewCore* webViewCore = android::WebViewCore::getWebViewCore(frameView); + return webViewCore->screenWidth(); +} + +int PlatformBridge::screenHeightInDocCoord(const WebCore::FrameView* frameView) +{ + android::WebViewCore* webViewCore = android::WebViewCore::getWebViewCore(frameView); + return webViewCore->screenHeight(); +} + +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) +{ + android::WebViewCore* webViewCore = android::WebViewCore::getWebViewCore(frameView); + webViewCore->updateViewport(); +} + +void PlatformBridge::updateTextfield(FrameView* frameView, Node* nodePtr, bool changeToPassword, const WTF::String& text) +{ + android::WebViewCore* webViewCore = android::WebViewCore::getWebViewCore(frameView); + webViewCore->updateTextfield(nodePtr, changeToPassword, text); +} + +void PlatformBridge::setScrollPosition(ScrollView* scrollView, int x, int y) { + // Check to make sure the view is the main FrameView. + android::WebViewCore *webViewCore = android::WebViewCore::getWebViewCore(scrollView); + if (webViewCore->mainFrame()->view() == scrollView) + webViewCore->scrollTo(x, y); +} + +int PlatformBridge::lowMemoryUsageMB() +{ + return MemoryUsage::lowMemoryUsageMb(); +} + +int PlatformBridge::highMemoryUsageMB() +{ + return MemoryUsage::highMemoryUsageMb(); +} + +int PlatformBridge::highUsageDeltaMB() +{ + return MemoryUsage::highUsageDeltaMb(); +} + +int PlatformBridge::memoryUsageMB() +{ + return MemoryUsage::memoryUsageMb(false); +} + +int PlatformBridge::actualMemoryUsageMB() +{ + return MemoryUsage::memoryUsageMb(true); +} + +} // namespace WebCore + + +// This is the implementation of AndroidThreading, which is declared in +// JavaScriptCore/wtf/android/AndroidThreading.h. It is provided here, rather +// than in its own source file, to avoid linker problems. +// +// By default, when building a shared library, the linker strips from static +// libraries any compilation units which do not contain any code referenced from +// that static library. Since +// AndroidThreading::scheduleDispatchFunctionsOnMainThread is not referenced +// from libwebcore.a, implementing it in its own compilation unit results in it +// being stripped. This stripping can be avoided by using the linker option +// --whole-archive for libwebcore.a, but this adds considerably to the size of +// libwebcore.so. + +namespace WTF { + +// Callback in the main thread. +static void timeoutFired(void*) +{ + dispatchFunctionsFromMainThread(); +} + +void AndroidThreading::scheduleDispatchFunctionsOnMainThread() +{ + JavaSharedClient::EnqueueFunctionPtr(timeoutFired, 0); +} + +} // namespace WTF diff --git a/Source/WebKit/android/WebCoreSupport/ResourceLoaderAndroid.cpp b/Source/WebKit/android/WebCoreSupport/ResourceLoaderAndroid.cpp new file mode 100644 index 0000000..7f54810 --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/ResourceLoaderAndroid.cpp @@ -0,0 +1,71 @@ +/* + * 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 +#include + +#include "Frame.h" +#include "FrameLoaderClientAndroid.h" +#include "WebCoreFrameBridge.h" +#include "WebCoreResourceLoader.h" +#include "WebUrlLoader.h" +#include "WebViewCore.h" + +using namespace android; + +namespace WebCore { + +PassRefPtr ResourceLoaderAndroid::start( + ResourceHandle* handle, const ResourceRequest& request, FrameLoaderClient* client, bool isMainResource, bool isSync) +{ + // Called on main thread + FrameLoaderClientAndroid* clientAndroid = static_cast(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 + // out the cache entry by the time we fetch it. + // + // So, we always say yes here, to prevent the FrameLoader from initiating a + // reload. Then in FrameLoaderClientImpl::dispatchWillSendRequest, we + // fix-up the cache policy of the request to force a load from the cache. + return true; +#else + return WebCoreResourceLoader::willLoadFromCache(url, identifier); +#endif +} + +} diff --git a/Source/WebKit/android/WebCoreSupport/UrlInterceptResponse.cpp b/Source/WebKit/android/WebCoreSupport/UrlInterceptResponse.cpp new file mode 100644 index 0000000..3779ba8 --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/UrlInterceptResponse.cpp @@ -0,0 +1,130 @@ +/* + * 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. + */ + +#define LOG_TAG "UrlInterceptResponse" +#include "config.h" + +#include "JNIUtility.h" +#include "UrlInterceptResponse.h" +#include "WebCoreJni.h" + +#include + +namespace android { + +class JavaInputStreamWrapper { +public: + JavaInputStreamWrapper(JNIEnv* env, jobject inputStream) + : m_inputStream(env->NewGlobalRef(inputStream)) + , m_buffer(0) { + LOG_ALWAYS_FATAL_IF(!inputStream); + jclass inputStreamClass = env->FindClass("java/io/InputStream"); + LOG_ALWAYS_FATAL_IF(!inputStreamClass); + m_read = env->GetMethodID(inputStreamClass, "read", "([B)I"); + LOG_ALWAYS_FATAL_IF(!m_read); + m_close = env->GetMethodID(inputStreamClass, "close", "()V"); + LOG_ALWAYS_FATAL_IF(!m_close); + } + + ~JavaInputStreamWrapper() { + JNIEnv* env = JSC::Bindings::getJNIEnv(); + env->CallVoidMethod(m_inputStream, m_close); + checkException(env); + env->DeleteGlobalRef(m_inputStream); + // In case we never call read(). + if (m_buffer) + env->DeleteGlobalRef(m_buffer); + } + + void read(std::vector* out) { + JNIEnv* env = JSC::Bindings::getJNIEnv(); + // Initialize our read buffer to the capacity of out. + if (!m_buffer) { + m_buffer = env->NewByteArray(out->capacity()); + m_buffer = (jbyteArray) env->NewGlobalRef(m_buffer); + } + int size = (int) env->CallIntMethod(m_inputStream, m_read, m_buffer); + if (checkException(env) || size < 0) + return; + // Copy from m_buffer to out. + out->resize(size); + env->GetByteArrayRegion(m_buffer, 0, size, (jbyte*)&out->front()); + } + +private: + jobject m_inputStream; + jbyteArray m_buffer; + jmethodID m_read; + jmethodID m_close; +}; + +UrlInterceptResponse::UrlInterceptResponse(JNIEnv* env, jobject response) { + jclass javaResponse = env->FindClass("android/webkit/WebResourceResponse"); + LOG_ALWAYS_FATAL_IF(!javaResponse); + jfieldID mimeType = env->GetFieldID(javaResponse, "mMimeType", + "Ljava/lang/String;"); + LOG_ALWAYS_FATAL_IF(!mimeType); + jfieldID encoding = env->GetFieldID(javaResponse, "mEncoding", + "Ljava/lang/String;"); + LOG_ALWAYS_FATAL_IF(!encoding); + jfieldID inputStream = env->GetFieldID(javaResponse, "mInputStream", + "Ljava/io/InputStream;"); + LOG_ALWAYS_FATAL_IF(!inputStream); + + jobject stream = env->GetObjectField(response, inputStream); + if (stream) + m_inputStream.set(new JavaInputStreamWrapper(env, stream)); + + jstring mimeStr = (jstring) env->GetObjectField(response, mimeType); + jstring encodingStr = (jstring) env->GetObjectField(response, encoding); + + if (mimeStr) { + const char* s = env->GetStringUTFChars(mimeStr, NULL); + m_mimeType.assign(s, env->GetStringUTFLength(mimeStr)); + env->ReleaseStringUTFChars(mimeStr, s); + } + if (encodingStr) { + const char* s = env->GetStringUTFChars(encodingStr, NULL); + m_encoding.assign(s, env->GetStringUTFLength(encodingStr)); + env->ReleaseStringUTFChars(encodingStr, s); + } + + env->DeleteLocalRef(javaResponse); + env->DeleteLocalRef(mimeStr); + env->DeleteLocalRef(encodingStr); +} + +UrlInterceptResponse::~UrlInterceptResponse() { + // Cannot be inlined because of JavaInputStreamWrapper visibility. +} + +bool UrlInterceptResponse::readStream(std::vector* out) const { + if (!m_inputStream) + return false; + m_inputStream->read(out); + return true; +} + +} // namespace android diff --git a/Source/WebKit/android/WebCoreSupport/UrlInterceptResponse.h b/Source/WebKit/android/WebCoreSupport/UrlInterceptResponse.h new file mode 100644 index 0000000..64dad69 --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/UrlInterceptResponse.h @@ -0,0 +1,70 @@ +/* + * 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 UrlInterceptResponse_h +#define UrlInterceptResponse_h + +#include "PlatformString.h" +#include "wtf/Noncopyable.h" +#include "wtf/OwnPtr.h" + +#include +#include +#include + +namespace android { + +class JavaInputStreamWrapper; + +class UrlInterceptResponse : public Noncopyable { +public: + UrlInterceptResponse(JNIEnv* env, jobject response); + ~UrlInterceptResponse(); + + const std::string& mimeType() const { + return m_mimeType; + } + + const std::string& encoding() const { + return m_encoding; + } + + int status() const { + return m_inputStream ? 200 : 404; + } + + // Read from the input stream. Returns false if reading failed. + // A size of 0 indicates eof. + bool readStream(std::vector* out) const; + +private: + std::string m_mimeType; + std::string m_encoding; + OwnPtr m_inputStream; +}; + +} // namespace android + +#endif diff --git a/Source/WebKit/android/WebCoreSupport/V8Counters.cpp b/Source/WebKit/android/WebCoreSupport/V8Counters.cpp new file mode 100644 index 0000000..d164f9a --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/V8Counters.cpp @@ -0,0 +1,116 @@ +/* + * 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 +#include +#include + +#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 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(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::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 new file mode 100644 index 0000000..499b856 --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/V8Counters.h @@ -0,0 +1,77 @@ +/* + * 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 +#include +#include + +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 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 new file mode 100644 index 0000000..be9a700 --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/WebCache.cpp @@ -0,0 +1,237 @@ +/* + * 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 "WebCache.h" + +#include "JNIUtility.h" +#include "WebCoreJni.h" +#include "WebRequestContext.h" +#include "WebUrlLoaderClient.h" + +#include + +using namespace WTF; +using namespace disk_cache; +using namespace net; +using namespace std; + +namespace android { + +static WTF::Mutex instanceMutex; + +static const string& rootDirectory() +{ + // This method may be called on any thread, as the Java method is + // synchronized. + static WTF::Mutex mutex; + MutexLocker lock(mutex); + static string cacheDirectory; + if (cacheDirectory.empty()) { + JNIEnv* env = JSC::Bindings::getJNIEnv(); + jclass bridgeClass = env->FindClass("android/webkit/JniUtil"); + jmethodID method = env->GetStaticMethodID(bridgeClass, "getCacheDirectory", "()Ljava/lang/String;"); + cacheDirectory = jstringToStdString(env, static_cast(env->CallStaticObjectMethod(bridgeClass, method))); + env->DeleteLocalRef(bridgeClass); + } + return cacheDirectory; +} + +static string storageDirectory() +{ + // Private cache is currently in memory only + static const char* const kDirectory = "/webviewCacheChromium"; + string storageDirectory = rootDirectory(); + storageDirectory.append(kDirectory); + return storageDirectory; +} + +static scoped_refptr* instance(bool isPrivateBrowsing) +{ + static scoped_refptr regularInstance; + static scoped_refptr privateInstance; + return isPrivateBrowsing ? &privateInstance : ®ularInstance; +} + +WebCache* WebCache::get(bool isPrivateBrowsing) +{ + MutexLocker lock(instanceMutex); + scoped_refptr* instancePtr = instance(isPrivateBrowsing); + if (!instancePtr->get()) + *instancePtr = new WebCache(isPrivateBrowsing); + return instancePtr->get(); +} + +void WebCache::cleanup(bool isPrivateBrowsing) +{ + MutexLocker lock(instanceMutex); + scoped_refptr* instancePtr = instance(isPrivateBrowsing); + *instancePtr = 0; +} + +WebCache::WebCache(bool isPrivateBrowsing) + : m_doomAllEntriesCallback(this, &WebCache::doomAllEntries) + , m_onClearDoneCallback(this, &WebCache::onClearDone) + , m_isClearInProgress(false) + , m_openEntryCallback(this, &WebCache::openEntry) + , m_onGetEntryDoneCallback(this, &WebCache::onGetEntryDone) + , m_isGetEntryInProgress(false) + , m_cacheBackend(0) +{ + base::Thread* ioThread = WebUrlLoaderClient::ioThread(); + scoped_refptr cacheMessageLoopProxy = ioThread->message_loop_proxy(); + + static const int kMaximumCacheSizeBytes = 20 * 1024 * 1024; + m_hostResolver = net::CreateSystemHostResolver(net::HostResolver::kDefaultParallelism, 0, 0); + + m_proxyConfigService = new ProxyConfigServiceAndroid(); + net::HttpCache::BackendFactory* backendFactory; + if (isPrivateBrowsing) + backendFactory = net::HttpCache::DefaultBackend::InMemory(kMaximumCacheSizeBytes / 2); + else { + FilePath directoryPath(storageDirectory().c_str()); + backendFactory = new net::HttpCache::DefaultBackend(net::DISK_CACHE, directoryPath, kMaximumCacheSizeBytes, cacheMessageLoopProxy); + } + + m_cache = new net::HttpCache(m_hostResolver.get(), + 0, // dnsrr_resolver + 0, // dns_cert_checker + net::ProxyService::CreateWithoutProxyResolver(m_proxyConfigService, 0 /* net_log */), + net::SSLConfigService::CreateSystemSSLConfigService(), + net::HttpAuthHandlerFactory::CreateDefault(m_hostResolver.get()), + 0, // network_delegate + 0, // net_log + backendFactory); +} + +void WebCache::clear() +{ + base::Thread* thread = WebUrlLoaderClient::ioThread(); + if (thread) + thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this, &WebCache::clearImpl)); +} + +void WebCache::clearImpl() +{ + if (m_isClearInProgress) + return; + m_isClearInProgress = true; + + if (!m_cacheBackend) { + int code = m_cache->GetBackend(&m_cacheBackend, &m_doomAllEntriesCallback); + // Code ERR_IO_PENDING indicates that the operation is still in progress and + // the supplied callback will be invoked when it completes. + if (code == ERR_IO_PENDING) + return; + else if (code != OK) { + onClearDone(0 /*unused*/); + return; + } + } + doomAllEntries(0 /*unused*/); +} + +void WebCache::doomAllEntries(int) +{ + if (!m_cacheBackend) { + onClearDone(0 /*unused*/); + return; + } + + // Code ERR_IO_PENDING indicates that the operation is still in progress and + // the supplied callback will be invoked when it completes. + if (m_cacheBackend->DoomAllEntries(&m_onClearDoneCallback) == ERR_IO_PENDING) + return; + onClearDone(0 /*unused*/); +} + +void WebCache::onClearDone(int) +{ + m_isClearInProgress = false; +} + +scoped_refptr WebCache::getCacheResult(String url) +{ + // This is called on the UI thread. + MutexLocker lock(m_getEntryMutex); + if (m_isGetEntryInProgress) + return 0; // TODO: OK? Or can we queue 'em up? + + // The Chromium methods are asynchronous, but we need this method to be + // synchronous. Do the work on the Chromium thread but block this thread + // here waiting for the work to complete. + base::Thread* thread = WebUrlLoaderClient::ioThread(); + if (!thread) + return 0; + + m_entry = 0; + m_isGetEntryInProgress = true; + m_entryUrl = url.threadsafeCopy(); + thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this, &WebCache::getEntryImpl)); + + while (m_isGetEntryInProgress) + m_getEntryCondition.wait(m_getEntryMutex); + + if (!m_entry) + return 0; + + return new CacheResult(m_entry, url); +} + +void WebCache::getEntryImpl() +{ + if (!m_cacheBackend) { + int code = m_cache->GetBackend(&m_cacheBackend, &m_openEntryCallback); + if (code == ERR_IO_PENDING) + return; + else if (code != OK) { + onGetEntryDone(0 /*unused*/); + return; + } + } + openEntry(0 /*unused*/); +} + +void WebCache::openEntry(int) +{ + if (!m_cacheBackend) { + onGetEntryDone(0 /*unused*/); + return; + } + + if (m_cacheBackend->OpenEntry(string(m_entryUrl.utf8().data()), &m_entry, &m_onGetEntryDoneCallback) == ERR_IO_PENDING) + return; + onGetEntryDone(0 /*unused*/); +} + +void WebCache::onGetEntryDone(int) +{ + // Unblock the UI thread in getEntry(); + MutexLocker lock(m_getEntryMutex); + m_isGetEntryInProgress = false; + m_getEntryCondition.signal(); +} + +} // namespace android diff --git a/Source/WebKit/android/WebCoreSupport/WebCache.h b/Source/WebKit/android/WebCoreSupport/WebCache.h new file mode 100644 index 0000000..7149fcc --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/WebCache.h @@ -0,0 +1,88 @@ +/* + * 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 WebCache_h +#define WebCache_h + +#include "CacheResult.h" +#include "ChromiumIncludes.h" + +#include +#include +#include + +namespace android { + +// This class is not generally threadsafe. However, get() and cleanup() are +// threadsafe. +class WebCache : public base::RefCountedThreadSafe { +public: + static WebCache* get(bool isPrivateBrowsing); + static void cleanup(bool isPrivateBrowsing); + + void clear(); + scoped_refptr getCacheResult(WTF::String url); + net::HostResolver* hostResolver() { return m_hostResolver.get(); } + net::HttpCache* cache() { return m_cache.get(); } + net::ProxyConfigServiceAndroid* proxy() { return m_proxyConfigService; } + +private: + WebCache(bool isPrivateBrowsing); + + // For clear() + void clearImpl(); + void doomAllEntries(int); + void onClearDone(int); + + // For getEntry() + void getEntryImpl(); + void openEntry(int); + void onGetEntryDone(int); + + OwnPtr m_hostResolver; + OwnPtr m_cache; + // This is owned by the ProxyService, which is owned by the HttpNetworkLayer, + // which is owned by the HttpCache, which is owned by this class. + net::ProxyConfigServiceAndroid* m_proxyConfigService; + + // For clear() + net::CompletionCallbackImpl m_doomAllEntriesCallback; + net::CompletionCallbackImpl m_onClearDoneCallback; + bool m_isClearInProgress; + // For getEntry() + net::CompletionCallbackImpl m_openEntryCallback; + net::CompletionCallbackImpl m_onGetEntryDoneCallback; + bool m_isGetEntryInProgress; + String m_entryUrl; + disk_cache::Entry* m_entry; + WTF::Mutex m_getEntryMutex; + WTF::ThreadCondition m_getEntryCondition; + + disk_cache::Backend* m_cacheBackend; +}; + +} // namespace android + +#endif diff --git a/Source/WebKit/android/WebCoreSupport/WebCookieJar.cpp b/Source/WebKit/android/WebCoreSupport/WebCookieJar.cpp new file mode 100644 index 0000000..99de67e --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/WebCookieJar.cpp @@ -0,0 +1,263 @@ +/* + * 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 "WebCookieJar.h" + +#include "JNIUtility.h" +#include "WebCoreJni.h" +#include "WebRequestContext.h" +#include "WebUrlLoaderClient.h" + +#include +#include + +#undef ASSERT +#define ASSERT(assertion, ...) do \ + if (!(assertion)) { \ + android_printLog(ANDROID_LOG_ERROR, __FILE__, __VA_ARGS__); \ + } \ +while (0) + +namespace android { + +static WTF::Mutex instanceMutex; +static bool isFirstInstanceCreated = false; +static bool fileSchemeCookiesEnabled = false; + +static const std::string& databaseDirectory() +{ + // This method may be called on any thread, as the Java method is + // synchronized. + static WTF::Mutex databaseDirectoryMutex; + MutexLocker lock(databaseDirectoryMutex); + static std::string databaseDirectory; + if (databaseDirectory.empty()) { + JNIEnv* env = JSC::Bindings::getJNIEnv(); + jclass bridgeClass = env->FindClass("android/webkit/JniUtil"); + jmethodID method = env->GetStaticMethodID(bridgeClass, "getDatabaseDirectory", "()Ljava/lang/String;"); + databaseDirectory = jstringToStdString(env, static_cast(env->CallStaticObjectMethod(bridgeClass, method))); + env->DeleteLocalRef(bridgeClass); + } + return databaseDirectory; +} + +static void removeFileOrDirectory(const char* filename) +{ + struct stat filetype; + if (stat(filename, &filetype) != 0) + return; + if (S_ISDIR(filetype.st_mode)) { + DIR* directory = opendir(filename); + if (directory) { + while (struct dirent* entry = readdir(directory)) { + if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) + continue; + std::string entryName(filename); + entryName.append("/"); + entryName.append(entry->d_name); + removeFileOrDirectory(entryName.c_str()); + } + closedir(directory); + rmdir(filename); + } + return; + } + unlink(filename); +} + +static std::string databaseDirectory(bool isPrivateBrowsing) +{ + static const char* const kDatabaseFilename = "/webviewCookiesChromium.db"; + static const char* const kDatabaseFilenamePrivateBrowsing = "/webviewCookiesChromiumPrivate.db"; + + std::string databaseFilePath = databaseDirectory(); + databaseFilePath.append(isPrivateBrowsing ? kDatabaseFilenamePrivateBrowsing : kDatabaseFilename); + return databaseFilePath; +} + +scoped_refptr* instance(bool isPrivateBrowsing) +{ + static scoped_refptr regularInstance; + static scoped_refptr privateInstance; + return isPrivateBrowsing ? &privateInstance : ®ularInstance; +} + +WebCookieJar* WebCookieJar::get(bool isPrivateBrowsing) +{ + MutexLocker lock(instanceMutex); + if (!isFirstInstanceCreated && fileSchemeCookiesEnabled) + net::CookieMonster::EnableFileScheme(); + isFirstInstanceCreated = true; + scoped_refptr* instancePtr = instance(isPrivateBrowsing); + if (!instancePtr->get()) + *instancePtr = new WebCookieJar(databaseDirectory(isPrivateBrowsing)); + return instancePtr->get(); +} + +void WebCookieJar::cleanup(bool isPrivateBrowsing) +{ + // This is called on the UI thread. + MutexLocker lock(instanceMutex); + scoped_refptr* instancePtr = instance(isPrivateBrowsing); + *instancePtr = 0; + removeFileOrDirectory(databaseDirectory(isPrivateBrowsing).c_str()); +} + +WebCookieJar::WebCookieJar(const std::string& databaseFilePath) + : m_allowCookies(true) +{ + // Setup the permissions for the file + const char* cDatabasePath = databaseFilePath.c_str(); + mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP; + if (access(cDatabasePath, F_OK) == 0) + chmod(cDatabasePath, mode); + else { + int fd = open(cDatabasePath, O_CREAT, mode); + if (fd >= 0) + close(fd); + } + + FilePath cookiePath(databaseFilePath.c_str()); + m_cookieDb = new SQLitePersistentCookieStore(cookiePath); + m_cookieStore = new net::CookieMonster(m_cookieDb.get(), 0); +} + +bool WebCookieJar::allowCookies() +{ + MutexLocker lock(m_allowCookiesMutex); + return m_allowCookies; +} + +void WebCookieJar::setAllowCookies(bool allow) +{ + MutexLocker lock(m_allowCookiesMutex); + 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&, net::CompletionCallback*) +{ + MutexLocker lock(m_allowCookiesMutex); + return m_allowCookies ? net::OK : net::ERR_ACCESS_DENIED; +} + +// From CookiePolicy in chromium +int WebCookieJar::CanSetCookie(const GURL&, const GURL&, const std::string&, net::CompletionCallback*) +{ + MutexLocker lock(m_allowCookiesMutex); + return m_allowCookies ? net::OK : net::ERR_ACCESS_DENIED; +} + +class FlushSemaphore : public base::RefCounted +{ +public: + FlushSemaphore() + : m_condition(&m_lock) + , m_count(0) + {} + + void SendFlushRequest(net::CookieMonster* monster) { + // FlushStore() needs to run on a Chrome thread (because it will need + // to post the callback, and it may want to do so on its own thread.) + // We use the IO thread for this purpose. + // + // TODO(husky): Our threads are hidden away in various files. Clean this + // up and consider integrating with Chrome's browser_thread.h. Might be + // a better idea to use the DB thread here rather than the IO thread. + + base::Thread* ioThread = WebUrlLoaderClient::ioThread(); + if (ioThread) { + Task* callback = NewRunnableMethod(this, &FlushSemaphore::Callback); + ioThread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod( + monster, &net::CookieMonster::FlushStore, callback)); + } else { + Callback(); + } + } + + // Block until the given number of callbacks has been made. + void Wait(int numCallbacks) { + AutoLock al(m_lock); + int lastCount = m_count; + while (m_count < numCallbacks) { + // TODO(husky): Maybe use TimedWait() here? But it's not obvious what + // to do if the flush fails. Might be okay just to let the OS kill us. + m_condition.Wait(); + ASSERT(lastCount != m_count, "Wait finished without incrementing m_count %d %d", m_count, lastCount); + lastCount = m_count; + } + m_count -= numCallbacks; + } + +private: + friend class base::RefCounted; + + void Callback() { + AutoLock al(m_lock); + m_count++; + m_condition.Broadcast(); + } + + Lock m_lock; + ConditionVariable m_condition; + volatile int m_count; +}; + +void WebCookieJar::flush() +{ + // Flush both cookie stores (private and non-private), wait for 2 callbacks. + static scoped_refptr semaphore(new FlushSemaphore()); + semaphore->SendFlushRequest(get(false)->cookieStore()->GetCookieMonster()); + semaphore->SendFlushRequest(get(true)->cookieStore()->GetCookieMonster()); + semaphore->Wait(2); +} + +bool WebCookieJar::acceptFileSchemeCookies() +{ + MutexLocker lock(instanceMutex); + return fileSchemeCookiesEnabled; +} + +void WebCookieJar::setAcceptFileSchemeCookies(bool accept) +{ + // The Chromium HTTP stack only reflects changes to this flag when creating + // a new CookieMonster instance. While we could track whether any + // CookieMonster instances currently exist, this would be complicated and is + // not required, so we only allow this flag to be changed before the first + // instance is created. + MutexLocker lock(instanceMutex); + if (!isFirstInstanceCreated) + fileSchemeCookiesEnabled = accept; +} + +} diff --git a/Source/WebKit/android/WebCoreSupport/WebCookieJar.h b/Source/WebKit/android/WebCoreSupport/WebCookieJar.h new file mode 100644 index 0000000..1f4266c --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/WebCookieJar.h @@ -0,0 +1,78 @@ +/* + * 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 WebCookieJar_h +#define WebCookieJar_h + +#include "ChromiumIncludes.h" + +#include + +namespace android { + +// This class is threadsafe. It is used from the IO, WebCore and Chromium IO +// threads. +class WebCookieJar : public net::CookiePolicy, public base::RefCountedThreadSafe { +public: + static WebCookieJar* get(bool isPrivateBrowsing); + static void cleanup(bool isPrivateBrowsing); + + // Flush all cookies to disk. Synchronous. + static void flush(); + + // CookiePolicy implementation from external/chromium + virtual int CanGetCookies(const GURL& url, const GURL& first_party_for_cookies, net::CompletionCallback*); + virtual int CanSetCookie(const GURL& url, const GURL& first_party_for_cookies, const std::string& cookie_line, net::CompletionCallback*); + + bool allowCookies(); + void setAllowCookies(bool allow); + + // Getter and setter for whether we accept cookies for file scheme URLS. + // Defaults to false. Note that calls to the setter are ignored once the + // first instance of this class has been created. + static bool acceptFileSchemeCookies(); + static void setAcceptFileSchemeCookies(bool); + + // 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::CookiePolicy* cookiePolicy() { return this; } + + // Get the number of cookies that have actually been saved to flash. + // (This is used to implement CookieManager.hasCookies() in the Java framework.) + int getNumCookiesInDatabase(); + +private: + WebCookieJar(const std::string& databaseFilePath); + + scoped_refptr m_cookieDb; + scoped_refptr m_cookieStore; + bool m_allowCookies; + WTF::Mutex m_allowCookiesMutex; +}; + +} + +#endif diff --git a/Source/WebKit/android/WebCoreSupport/WebRequest.cpp b/Source/WebKit/android/WebCoreSupport/WebRequest.cpp new file mode 100644 index 0000000..a7321da --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/WebRequest.cpp @@ -0,0 +1,531 @@ +/* + * 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 "WebRequest.h" + +#include "JNIUtility.h" +#include "MainThread.h" +#include "UrlInterceptResponse.h" +#include "WebCoreFrameBridge.h" +#include "WebRequestContext.h" +#include "WebResourceRequest.h" +#include "WebUrlLoaderClient.h" +#include "jni.h" + +#include +#include +#include + +extern android::AssetManager* globalAssetManager(); + +// TODO: +// - Finish the file upload. Testcase is mobile buzz +// - Add network throttle needed by Android plugins + +// TODO: Turn off asserts crashing before release +// http://b/issue?id=2951985 +#undef ASSERT +#define ASSERT(assertion, ...) do \ + if (!(assertion)) { \ + android_printLog(ANDROID_LOG_ERROR, __FILE__, __VA_ARGS__); \ + } \ +while (0) + +namespace android { + +namespace { + const int kInitialReadBufSize = 32768; +} + +WebRequest::WebRequest(WebUrlLoaderClient* loader, const WebResourceRequest& webResourceRequest) + : m_urlLoader(loader) + , m_androidUrl(false) + , m_url(webResourceRequest.url()) + , m_userAgent(webResourceRequest.userAgent()) + , m_loadState(Created) + , m_authRequestCount(0) + , m_cacheMode(0) + , m_runnableFactory(this) + , m_wantToPause(false) + , m_isPaused(false) + , m_isSync(false) +{ + GURL gurl(m_url); + + m_request = new URLRequest(gurl, this); + + m_request->SetExtraRequestHeaders(webResourceRequest.requestHeaders()); + m_request->set_referrer(webResourceRequest.referrer()); + m_request->set_method(webResourceRequest.method()); + m_request->set_load_flags(webResourceRequest.loadFlags()); +} + +// This is a special URL for Android. Query the Java InputStream +// for data and send to WebCore +WebRequest::WebRequest(WebUrlLoaderClient* loader, const WebResourceRequest& webResourceRequest, UrlInterceptResponse* intercept) + : m_urlLoader(loader) + , m_interceptResponse(intercept) + , m_androidUrl(true) + , m_url(webResourceRequest.url()) + , m_userAgent(webResourceRequest.userAgent()) + , m_loadState(Created) + , m_authRequestCount(0) + , m_cacheMode(0) + , m_runnableFactory(this) + , m_wantToPause(false) + , m_isPaused(false) + , m_isSync(false) +{ +} + +WebRequest::~WebRequest() +{ + ASSERT(m_loadState == Finished, "dtor called on a WebRequest in a different state than finished (%d)", m_loadState); + + m_loadState = Deleted; +} + +const std::string& WebRequest::getUrl() const +{ + return m_url; +} + +const std::string& WebRequest::getUserAgent() const +{ + return m_userAgent; +} + +#ifdef LOG_REQUESTS +namespace { +int remaining = 0; +} +#endif + +void WebRequest::finish(bool success) +{ + m_runnableFactory.RevokeAll(); + ASSERT(m_loadState < Finished, "(%p) called finish on an already finished WebRequest (%d) (%s)", this, m_loadState, m_url.c_str()); + if (m_loadState >= Finished) + return; +#ifdef LOG_REQUESTS + time_t finish; + time(&finish); + finish = finish - m_startTime; + struct tm * timeinfo; + char buffer[80]; + timeinfo = localtime(&finish); + strftime(buffer, 80, "Time: %M:%S",timeinfo); + android_printLog(ANDROID_LOG_DEBUG, "KM", "(%p) finish (%d) (%s) (%d) (%s)", this, --remaining, buffer, success, m_url.c_str()); +#endif + + // Make sure WebUrlLoaderClient doesn't delete us in the middle of this method. + scoped_refptr guard(this); + + m_loadState = Finished; + if (success) { + m_urlLoader->maybeCallOnMainThread(NewRunnableMethod( + m_urlLoader.get(), &WebUrlLoaderClient::didFinishLoading)); + } else { + if (m_interceptResponse == NULL) { + OwnPtr webResponse(new WebResponse(m_request.get())); + m_urlLoader->maybeCallOnMainThread(NewRunnableMethod( + m_urlLoader.get(), &WebUrlLoaderClient::didFail, webResponse.release())); + } else { + OwnPtr webResponse(new WebResponse(m_url, m_interceptResponse->mimeType(), 0, + m_interceptResponse->encoding(), m_interceptResponse->status())); + m_urlLoader->maybeCallOnMainThread(NewRunnableMethod( + m_urlLoader.get(), &WebUrlLoaderClient::didFail, webResponse.release())); + } + } + m_networkBuffer = 0; + m_request = 0; + m_urlLoader = 0; +} + +void WebRequest::appendFileToUpload(const std::string& filename) +{ + // AppendFileToUpload is only valid before calling start + ASSERT(m_loadState == Created, "appendFileToUpload called on a WebRequest not in CREATED state: (%s)", m_url.c_str()); + FilePath filePath(filename); + m_request->AppendFileToUpload(filePath); +} + +void WebRequest::appendBytesToUpload(WTF::Vector* data) +{ + // AppendBytesToUpload is only valid before calling start + ASSERT(m_loadState == Created, "appendBytesToUpload called on a WebRequest not in CREATED state: (%s)", m_url.c_str()); + m_request->AppendBytesToUpload(data->data(), data->size()); + delete data; +} + +void WebRequest::setRequestContext(WebRequestContext* context) +{ + m_cacheMode = context->getCacheMode(); + if (m_request) + m_request->set_context(context); +} + +void WebRequest::updateLoadFlags(int& loadFlags) +{ + if (m_cacheMode == 1) { // LOAD_CACHE_ELSE_NETWORK + loadFlags |= net::LOAD_PREFERRING_CACHE; + loadFlags &= ~net::LOAD_VALIDATE_CACHE; + } + if (m_cacheMode == 2) // LOAD_NO_CACHE + loadFlags |= net::LOAD_BYPASS_CACHE; + if (m_cacheMode == 3) // LOAD_CACHE_ONLY + loadFlags |= net::LOAD_ONLY_FROM_CACHE; + + if (m_isSync) + loadFlags |= net::LOAD_IGNORE_LIMITS; +} + +void WebRequest::start() +{ + ASSERT(m_loadState == Created, "Start called on a WebRequest not in CREATED state: (%s)", m_url.c_str()); +#ifdef LOG_REQUESTS + android_printLog(ANDROID_LOG_DEBUG, "KM", "(%p) start (%d) (%s)", this, ++remaining, m_url.c_str()); + time(&m_startTime); +#endif + + m_loadState = Started; + + if (m_interceptResponse != NULL) + return handleInterceptedURL(); + + // Handle data urls before we send it off to the http stack + if (m_request->url().SchemeIs("data")) + return handleDataURL(m_request->url()); + + if (m_request->url().SchemeIs("browser")) + return handleBrowserURL(m_request->url()); + + // Update load flags with settings from WebSettings + int loadFlags = m_request->load_flags(); + updateLoadFlags(loadFlags); + m_request->set_load_flags(loadFlags); + + m_request->Start(); +} + +void WebRequest::cancel() +{ + ASSERT(m_loadState >= Started, "Cancel called on a not started WebRequest: (%s)", m_url.c_str()); + ASSERT(m_loadState != Cancelled, "Cancel called on an already cancelled WebRequest: (%s)", m_url.c_str()); + + // There is a possible race condition between the IO thread finishing the request and + // the WebCore thread cancelling it. If the request has already finished, do + // nothing to avoid sending duplicate finish messages to WebCore. + if (m_loadState > Cancelled) { + return; + } + ASSERT(m_request, "Request set to 0 before it is finished"); + + m_loadState = Cancelled; + + m_request->Cancel(); + finish(true); +} + +void WebRequest::pauseLoad(bool pause) +{ + ASSERT(m_loadState >= GotData, "PauseLoad in state other than RESPONSE and GOTDATA"); + if (pause) { + if (!m_isPaused) + m_wantToPause = true; + } else { + m_wantToPause = false; + if (m_isPaused) { + m_isPaused = false; + MessageLoop::current()->PostTask(FROM_HERE, m_runnableFactory.NewRunnableMethod(&WebRequest::startReading)); + } + } +} + +void WebRequest::handleInterceptedURL() +{ + m_loadState = Response; + + const std::string& mime = m_interceptResponse->mimeType(); + // Get the MIME type from the URL. "text/html" is a last resort, hopefully overridden. + std::string mimeType("text/html"); + if (mime == "") { + // Gmail appends the MIME to the end of the URL, with a ? separator. + size_t mimeTypeIndex = m_url.find_last_of('?'); + if (mimeTypeIndex != std::string::npos) { + mimeType.assign(m_url.begin() + mimeTypeIndex + 1, m_url.end()); + } else { + // Get the MIME type from the file extension, if any. + FilePath path(m_url); + net::GetMimeTypeFromFile(path, &mimeType); + } + } else { + // Set from the intercept response. + mimeType = mime; + } + + + OwnPtr webResponse(new WebResponse(m_url, mimeType, 0, m_interceptResponse->encoding(), m_interceptResponse->status())); + m_urlLoader->maybeCallOnMainThread(NewRunnableMethod( + m_urlLoader.get(), &WebUrlLoaderClient::didReceiveResponse, webResponse.release())); + + do { + // data is deleted in WebUrlLoaderClient::didReceiveAndroidFileData + // data is sent to the webcore thread + OwnPtr > data(new std::vector); + data->reserve(kInitialReadBufSize); + + // Read returns false on error and size of 0 on eof. + if (!m_interceptResponse->readStream(data.get()) || data->size() == 0) + break; + + m_loadState = GotData; + m_urlLoader->maybeCallOnMainThread(NewRunnableMethod( + m_urlLoader.get(), &WebUrlLoaderClient::didReceiveAndroidFileData, data.release())); + } while (true); + + finish(m_interceptResponse->status() == 200); +} + +void WebRequest::handleDataURL(GURL url) +{ + OwnPtr data(new std::string); + std::string mimeType; + std::string charset; + + if (net::DataURL::Parse(url, &mimeType, &charset, data.get())) { + // PopulateURLResponse from chrome implementation + // weburlloader_impl.cc + m_loadState = Response; + OwnPtr webResponse(new WebResponse(url.spec(), mimeType, data->size(), charset, 200)); + m_urlLoader->maybeCallOnMainThread(NewRunnableMethod( + m_urlLoader.get(), &WebUrlLoaderClient::didReceiveResponse, webResponse.release())); + + if (!data->empty()) { + m_loadState = GotData; + m_urlLoader->maybeCallOnMainThread(NewRunnableMethod( + m_urlLoader.get(), &WebUrlLoaderClient::didReceiveDataUrl, data.release())); + } + } else { + // handle the failed case + } + + finish(true); +} + +void WebRequest::handleBrowserURL(GURL url) +{ + std::string data("data:text/html;charset=utf-8,"); + if (url.spec() == "browser:incognito") { + AssetManager* assetManager = globalAssetManager(); + Asset* asset = assetManager->open("webkit/incognito_mode_start_page.html", Asset::ACCESS_BUFFER); + if (asset) { + data.append((const char*)asset->getBuffer(false), asset->getLength()); + delete asset; + } + } + GURL dataURL(data.c_str()); + handleDataURL(dataURL); +} + +// Called upon a server-initiated redirect. The delegate may call the +// request's Cancel method to prevent the redirect from being followed. +// Since there may be multiple chained redirects, there may also be more +// than one redirect call. +// +// When this function is called, the request will still contain the +// original URL, the destination of the redirect is provided in 'new_url'. +// If the delegate does not cancel the request and |*defer_redirect| is +// false, then the redirect will be followed, and the request's URL will be +// changed to the new URL. Otherwise if the delegate does not cancel the +// request and |*defer_redirect| is true, then the redirect will be +// followed once FollowDeferredRedirect is called on the URLRequest. +// +// The caller must set |*defer_redirect| to false, so that delegates do not +// need to set it if they are happy with the default behavior of not +// deferring redirect. +void WebRequest::OnReceivedRedirect(URLRequest* newRequest, const GURL& newUrl, bool* deferRedirect) +{ + ASSERT(m_loadState < Response, "Redirect after receiving response"); + ASSERT(newRequest && newRequest->status().is_success(), "Invalid redirect"); + + OwnPtr webResponse(new WebResponse(newRequest)); + webResponse->setUrl(newUrl.spec()); + m_urlLoader->maybeCallOnMainThread(NewRunnableMethod( + m_urlLoader.get(), &WebUrlLoaderClient::willSendRequest, webResponse.release())); + + // Defer the redirect until followDeferredRedirect() is called. + *deferRedirect = true; +} + +// Called when we receive an authentication failure. The delegate should +// call request->SetAuth() with the user's credentials once it obtains them, +// or request->CancelAuth() to cancel the login and display the error page. +// When it does so, the request will be reissued, restarting the sequence +// of On* callbacks. +void WebRequest::OnAuthRequired(URLRequest* request, net::AuthChallengeInfo* authInfo) +{ + ASSERT(m_loadState == Started, "OnAuthRequired called on a WebRequest not in STARTED state (state=%d)", m_loadState); + + scoped_refptr authInfoPtr(authInfo); + bool firstTime = (m_authRequestCount == 0); + ++m_authRequestCount; + + m_urlLoader->maybeCallOnMainThread(NewRunnableMethod( + m_urlLoader.get(), &WebUrlLoaderClient::authRequired, authInfoPtr, firstTime)); +} + +// Called when we received an SSL certificate error. The delegate will provide +// the user the options to proceed, cancel, or view certificates. +void WebRequest::OnSSLCertificateError(URLRequest* request, int cert_error, net::X509Certificate* cert) +{ + m_urlLoader->maybeCallOnMainThread(NewRunnableMethod( + m_urlLoader.get(), &WebUrlLoaderClient::reportSslCertError, cert_error, cert)); +} + +// After calling Start(), the delegate will receive an OnResponseStarted +// callback when the request has completed. If an error occurred, the +// request->status() will be set. On success, all redirects have been +// followed and the final response is beginning to arrive. At this point, +// meta data about the response is available, including for example HTTP +// response headers if this is a request for a HTTP resource. +void WebRequest::OnResponseStarted(URLRequest* request) +{ + ASSERT(m_loadState == Started, "Got response after receiving response"); + + m_loadState = Response; + if (request && request->status().is_success()) { + OwnPtr webResponse(new WebResponse(request)); + m_urlLoader->maybeCallOnMainThread(NewRunnableMethod( + m_urlLoader.get(), &WebUrlLoaderClient::didReceiveResponse, webResponse.release())); + + // Start reading the response + startReading(); + } else { + finish(false); + } +} + +void WebRequest::setAuth(const string16& username, const string16& password) +{ + ASSERT(m_loadState == Started, "setAuth called on a WebRequest not in STARTED state (state=%d)", m_loadState); + + m_request->SetAuth(username, password); +} + +void WebRequest::cancelAuth() +{ + ASSERT(m_loadState == Started, "cancelAuth called on a WebRequest not in STARTED state (state=%d)", m_loadState); + + m_request->CancelAuth(); +} + +void WebRequest::followDeferredRedirect() +{ + ASSERT(m_loadState < Response, "Redirect after receiving response"); + + m_request->FollowDeferredRedirect(); +} + +void WebRequest::proceedSslCertError() +{ + m_request->ContinueDespiteLastError(); +} + +void WebRequest::cancelSslCertError(int cert_error) +{ + m_request->SimulateError(cert_error); +} + +void WebRequest::startReading() +{ + ASSERT(m_networkBuffer == 0, "startReading called with a nonzero buffer"); + ASSERT(m_isPaused == 0, "startReading called in paused state"); + ASSERT(m_loadState == Response || m_loadState == GotData, "StartReading in state other than RESPONSE and GOTDATA"); + if (m_loadState > GotData) // We have been cancelled between reads + return; + + if (m_wantToPause) { + m_isPaused = true; + return; + } + + int bytesRead = 0; + + if (!read(&bytesRead)) { + if (m_request && m_request->status().is_io_pending()) + return; // Wait for OnReadCompleted() + return finish(false); + } + + // bytesRead == 0 indicates finished + if (!bytesRead) + return finish(true); + + m_loadState = GotData; + // Read ok, forward buffer to webcore + m_urlLoader->maybeCallOnMainThread(NewRunnableMethod(m_urlLoader.get(), &WebUrlLoaderClient::didReceiveData, m_networkBuffer, bytesRead)); + m_networkBuffer = 0; + MessageLoop::current()->PostTask(FROM_HERE, m_runnableFactory.NewRunnableMethod(&WebRequest::startReading)); +} + +bool WebRequest::read(int* bytesRead) +{ + ASSERT(m_loadState == Response || m_loadState == GotData, "read in state other than RESPONSE and GOTDATA"); + ASSERT(m_networkBuffer == 0, "Read called with a nonzero buffer"); + + // TODO: when asserts work, check that the buffer is 0 here + m_networkBuffer = new net::IOBuffer(kInitialReadBufSize); + return m_request->Read(m_networkBuffer, kInitialReadBufSize, bytesRead); +} + +// This is called when there is data available + +// Called when the a Read of the response body is completed after an +// IO_PENDING status from a Read() call. +// The data read is filled into the buffer which the caller passed +// to Read() previously. +// +// If an error occurred, request->status() will contain the error, +// and bytes read will be -1. +void WebRequest::OnReadCompleted(URLRequest* request, int bytesRead) +{ + ASSERT(m_loadState == Response || m_loadState == GotData, "OnReadCompleted in state other than RESPONSE and GOTDATA"); + + if (request->status().is_success()) { + m_loadState = GotData; + m_urlLoader->maybeCallOnMainThread(NewRunnableMethod( + m_urlLoader.get(), &WebUrlLoaderClient::didReceiveData, m_networkBuffer, bytesRead)); + m_networkBuffer = 0; + + // Get the rest of the data + startReading(); + } else { + finish(false); + } +} + +} // namespace android diff --git a/Source/WebKit/android/WebCoreSupport/WebRequest.h b/Source/WebKit/android/WebCoreSupport/WebRequest.h new file mode 100644 index 0000000..252267b --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/WebRequest.h @@ -0,0 +1,125 @@ +/* + * 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 WebRequest_h +#define WebRequest_h + +#include "ChromiumIncludes.h" +#include + +class MessageLoop; + +namespace android { + +enum LoadState { + Created, + Started, + Response, + GotData, + Cancelled, + Finished, + Deleted +}; + +class UrlInterceptResponse; +class WebFrame; +class WebRequestContext; +class WebResourceRequest; +class WebUrlLoaderClient; + +// All methods in this class must be called on the io thread +class WebRequest : public URLRequest::Delegate, public base::RefCountedThreadSafe { +public: + WebRequest(WebUrlLoaderClient*, const WebResourceRequest&); + + // If this is an android specific url or the application wants to load + // custom data, we load the data through an input stream. + // Used for: + // - file:///android_asset + // - file:///android_res + // - content:// + WebRequest(WebUrlLoaderClient*, const WebResourceRequest&, UrlInterceptResponse* intercept); + + // Optional, but if used has to be called before start + void appendBytesToUpload(Vector* data); + void appendFileToUpload(const std::string& filename); + + void setRequestContext(WebRequestContext* context); + void start(); + void cancel(); + void pauseLoad(bool pause); + + // From URLRequest::Delegate + virtual void OnReceivedRedirect(URLRequest*, const GURL&, bool* deferRedirect); + virtual void OnResponseStarted(URLRequest*); + virtual void OnReadCompleted(URLRequest*, int bytesRead); + virtual void OnAuthRequired(URLRequest*, net::AuthChallengeInfo*); + virtual void OnSSLCertificateError(URLRequest* request, int cert_error, net::X509Certificate* cert); + + // Methods called during a request by the UI code (via WebUrlLoaderClient). + void setAuth(const string16& username, const string16& password); + void cancelAuth(); + void followDeferredRedirect(); + void proceedSslCertError(); + void cancelSslCertError(int cert_error); + + const std::string& getUrl() const; + const std::string& getUserAgent() const; + + void setSync(bool sync) { m_isSync = sync; } +private: + void startReading(); + bool read(int* bytesRead); + + friend class base::RefCountedThreadSafe; + virtual ~WebRequest(); + void handleDataURL(GURL); + void handleBrowserURL(GURL); + void handleInterceptedURL(); + void finish(bool success); + void updateLoadFlags(int& loadFlags); + + scoped_refptr m_urlLoader; + OwnPtr m_request; + scoped_refptr m_networkBuffer; + scoped_ptr m_interceptResponse; + bool m_androidUrl; + std::string m_url; + std::string m_userAgent; + LoadState m_loadState; + int m_authRequestCount; + int m_cacheMode; + ScopedRunnableMethodFactory m_runnableFactory; + bool m_wantToPause; + bool m_isPaused; + bool m_isSync; +#ifdef LOG_REQUESTS + time_t m_startTime; +#endif +}; + +} // namespace android + +#endif diff --git a/Source/WebKit/android/WebCoreSupport/WebRequestContext.cpp b/Source/WebKit/android/WebCoreSupport/WebRequestContext.cpp new file mode 100644 index 0000000..78c3501 --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/WebRequestContext.cpp @@ -0,0 +1,130 @@ +/* + * 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 "WebRequestContext.h" + +#include "ChromiumIncludes.h" +#include "ChromiumInit.h" +#include "WebCache.h" +#include "WebCookieJar.h" + +#include + +static std::string acceptLanguageStdString(""); +static WTF::String acceptLanguageWtfString(""); +static WTF::Mutex acceptLanguageMutex; + +static int numPrivateBrowsingInstances; + +extern void ANPSystemInterface_CleanupIncognito(); + +using namespace WTF; + +namespace android { + +WebRequestContext::WebRequestContext(bool isPrivateBrowsing) + : m_isPrivateBrowsing(isPrivateBrowsing) +{ + // Initialize chromium logging, needs to be done before any chromium code is called. + initChromium(); + + if (m_isPrivateBrowsing) { + // Delete the old files if this is the first private browsing instance + // They are probably leftovers from a power cycle + // We do not need to clear the cache as it is in memory only for private browsing + if (!numPrivateBrowsingInstances) + WebCookieJar::cleanup(true); + numPrivateBrowsingInstances++; + } + + WebCache* cache = WebCache::get(m_isPrivateBrowsing); + host_resolver_ = cache->hostResolver(); + http_transaction_factory_ = cache->cache(); + + WebCookieJar* cookieJar = WebCookieJar::get(m_isPrivateBrowsing); + cookie_store_ = cookieJar->cookieStore(); + cookie_policy_ = cookieJar; + + // Also hardcoded in FrameLoader.java + accept_charset_ = "utf-8, iso-8859-1, utf-16, *;q=0.7"; +} + +WebRequestContext::~WebRequestContext() +{ + if (m_isPrivateBrowsing) { + numPrivateBrowsingInstances--; + + // This is the last private browsing context, delete the cookies and cache + if (!numPrivateBrowsingInstances) { + WebCookieJar::cleanup(true); + WebCache::cleanup(true); + ANPSystemInterface_CleanupIncognito(); + } + } +} + +void WebRequestContext::setUserAgent(const String& string) +{ + MutexLocker lock(m_userAgentMutex); + m_userAgent = string.utf8().data(); +} + +void WebRequestContext::setCacheMode(int mode) +{ + m_cacheMode = mode; +} + +int WebRequestContext::getCacheMode() +{ + return m_cacheMode; +} + +const std::string& WebRequestContext::GetUserAgent(const GURL& url) const +{ + MutexLocker lock(m_userAgentMutex); + return m_userAgent; +} + +void WebRequestContext::setAcceptLanguage(const String& string) +{ + MutexLocker lock(acceptLanguageMutex); + acceptLanguageStdString = string.utf8().data(); + acceptLanguageWtfString = string; +} + +const std::string& WebRequestContext::GetAcceptLanguage() const +{ + MutexLocker lock(acceptLanguageMutex); + return acceptLanguageStdString; +} + +const String& WebRequestContext::acceptLanguage() +{ + MutexLocker lock(acceptLanguageMutex); + return acceptLanguageWtfString; +} + +} // namespace android diff --git a/Source/WebKit/android/WebCoreSupport/WebRequestContext.h b/Source/WebKit/android/WebCoreSupport/WebRequestContext.h new file mode 100644 index 0000000..51f0514 --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/WebRequestContext.h @@ -0,0 +1,64 @@ +/* + * 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 WebRequestContext_h +#define WebRequestContext_h + +#include "ChromiumIncludes.h" +#include "PlatformString.h" + +#include + +namespace android { + +// This class is generally not threadsafe. +class WebRequestContext : public URLRequestContext { +public: + // URLRequestContext overrides. + virtual const std::string& GetUserAgent(const GURL&) const; + virtual const std::string& GetAcceptLanguage() const; + + WebRequestContext(bool isPrivateBrowsing); + + // These methods are threadsafe. + void setUserAgent(const WTF::String&); + void setCacheMode(int); + int getCacheMode(); + static void setAcceptLanguage(const WTF::String&); + static const WTF::String& acceptLanguage(); + +private: + WebRequestContext(); + ~WebRequestContext(); + + std::string m_userAgent; + int m_cacheMode; + mutable WTF::Mutex m_userAgentMutex; + bool m_isPrivateBrowsing; +}; + +} // namespace android + +#endif diff --git a/Source/WebKit/android/WebCoreSupport/WebResourceRequest.cpp b/Source/WebKit/android/WebCoreSupport/WebResourceRequest.cpp new file mode 100644 index 0000000..9b70fce --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/WebResourceRequest.cpp @@ -0,0 +1,96 @@ +/* + * 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 "WebResourceRequest.h" + +#include "ResourceRequest.h" + +#include + +using namespace WebCore; + +namespace android { + +WebResourceRequest::WebResourceRequest(const WebCore::ResourceRequest& resourceRequest) +{ + // Set the load flags based on the WebCore request. + m_loadFlags = net::LOAD_NORMAL; + switch (resourceRequest.cachePolicy()) { + case ReloadIgnoringCacheData: + m_loadFlags |= net::LOAD_VALIDATE_CACHE; + break; + case ReturnCacheDataElseLoad: + m_loadFlags |= net::LOAD_PREFERRING_CACHE; + break; + case ReturnCacheDataDontLoad: + m_loadFlags |= net::LOAD_ONLY_FROM_CACHE; + break; + case UseProtocolCachePolicy: + break; + } + + // TODO: We should consider setting these flags and net::LOAD_DO_NOT_SEND_AUTH_DATA + // when FrameLoaderClient::shouldUseCredentialStorage() is false. However, + // the required WebKit logic is not yet in place. See Chromium's + // FrameLoaderClientImpl::shouldUseCredentialStorage(). + if (!resourceRequest.allowCookies()) { + m_loadFlags |= net::LOAD_DO_NOT_SAVE_COOKIES; + m_loadFlags |= net::LOAD_DO_NOT_SEND_COOKIES; + } + + + // Set the request headers + const HTTPHeaderMap& map = resourceRequest.httpHeaderFields(); + for (HTTPHeaderMap::const_iterator it = map.begin(); it != map.end(); ++it) { + const std::string& nameUtf8 = it->first.string().utf8().data(); + const std::string& valueUtf8 = it->second.utf8().data(); + + // Skip over referrer headers found in the header map because we already + // pulled it out as a separate parameter. We likewise prune the UA since + // that will be added back by the network layer. + if (LowerCaseEqualsASCII(nameUtf8, "referer") || LowerCaseEqualsASCII(nameUtf8, "user-agent")) + continue; + + // Skip over "Cache-Control: max-age=0" header if the corresponding + // load flag is already specified. FrameLoader sets both the flag and + // the extra header -- the extra header is redundant since our network + // implementation will add the necessary headers based on load flags. + // See http://code.google.com/p/chromium/issues/detail?id=3434. + if ((m_loadFlags & net::LOAD_VALIDATE_CACHE) && + LowerCaseEqualsASCII(nameUtf8, "cache-control") && LowerCaseEqualsASCII(valueUtf8, "max-age=0")) + continue; + + m_requestHeaders.SetHeader(nameUtf8, valueUtf8); + } + + m_method = resourceRequest.httpMethod().utf8().data(); + m_referrer = resourceRequest.httpReferrer().utf8().data(); + m_userAgent = resourceRequest.httpUserAgent().utf8().data(); + + m_url = resourceRequest.url().string().utf8().data(); +} + +} // namespace android diff --git a/Source/WebKit/android/WebCoreSupport/WebResourceRequest.h b/Source/WebKit/android/WebCoreSupport/WebResourceRequest.h new file mode 100644 index 0000000..38f37b5 --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/WebResourceRequest.h @@ -0,0 +1,86 @@ +/* + * 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 WebResourceRequest_h +#define WebResourceRequest_h + +#include "ChromiumIncludes.h" + +#include + +namespace WebCore { +class ResourceRequest; +} + +namespace android { + +class WebResourceRequest { + +public: + WebResourceRequest(const WebCore::ResourceRequest&); + + const std::string& method() const + { + return m_method; + } + + const std::string& referrer() const + { + return m_referrer; + } + + const std::string& userAgent() const + { + return m_userAgent; + } + + const net::HttpRequestHeaders& requestHeaders() const + { + return m_requestHeaders; + } + + const std::string& url() const + { + return m_url; + } + + int loadFlags() const + { + return m_loadFlags; + } + +private: + std::string m_method; + std::string m_referrer; + std::string m_userAgent; + net::HttpRequestHeaders m_requestHeaders; + std::string m_url; + int m_loadFlags; +}; + +} // namespace android + + +#endif diff --git a/Source/WebKit/android/WebCoreSupport/WebResponse.cpp b/Source/WebKit/android/WebCoreSupport/WebResponse.cpp new file mode 100644 index 0000000..4d297d7 --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/WebResponse.cpp @@ -0,0 +1,167 @@ +/* + * 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 "WebResponse.h" + +#include "MIMETypeRegistry.h" +#include "PlatformString.h" +#include "ResourceResponse.h" +#include "ResourceError.h" + +#include + +using namespace std; + +namespace android { + +WebResponse::WebResponse(URLRequest* request) + : m_httpStatusCode(0) +{ + // The misleadingly-named os_error() is actually a net::Error enum constant. + m_error = net::Error(request->status().os_error()); + + m_url = request->url().spec(); + m_host = request->url().HostNoBrackets(); + request->GetMimeType(&m_mime); + + request->GetCharset(&m_encoding); + m_expectedSize = request->GetExpectedContentSize(); + + m_sslInfo = request->ssl_info(); + + net::HttpResponseHeaders* responseHeaders = request->response_headers(); + if (!responseHeaders) + return; + + m_httpStatusCode = responseHeaders->response_code(); + m_httpStatusText = responseHeaders->GetStatusText(); + + string value; + string name; + void* iter = 0; + while (responseHeaders->EnumerateHeaderLines(&iter, &name, &value)) + m_headerFields[name] = value; +} + +WebResponse::WebResponse(const string &url, const string &mimeType, long long expectedSize, const string &encoding, int httpStatusCode) + : m_error(net::OK) + , m_encoding(encoding) + , m_httpStatusCode(httpStatusCode) + , m_expectedSize(expectedSize) + , m_mime(mimeType) + , m_url(url) +{ +} + +WebCore::ResourceResponse WebResponse::createResourceResponse() +{ + WebCore::ResourceResponse resourceResponse(createKurl(), getMimeType().c_str(), m_expectedSize, m_encoding.c_str(), ""); + resourceResponse.setHTTPStatusCode(m_httpStatusCode); + resourceResponse.setHTTPStatusText(m_httpStatusText.c_str()); + + map::const_iterator it; + for (it = m_headerFields.begin(); it != m_headerFields.end(); ++it) + resourceResponse.setHTTPHeaderField(it->first.c_str(), it->second.c_str()); + + return resourceResponse; +} + +WebCore::ResourceError WebResponse::createResourceError() +{ + WebCore::ResourceError error(m_host.c_str(), ToWebViewClientError(m_error), m_url.c_str(), WTF::String()); + return error; +} + + +WebCore::KURL WebResponse::createKurl() +{ + WebCore::KURL kurl(WebCore::ParsedURLString, m_url.c_str()); + return kurl; +} + +const string& WebResponse::getUrl() const +{ + return m_url; +} + +void WebResponse::setUrl(const string& url) +{ + m_url = url; +} + +// Calls WebCore APIs so should only be called from the WebCore thread. +// TODO: can we return a WTF::String directly? Need to check all callsites. +const string& WebResponse::getMimeType() +{ + if (!m_url.length()) + return m_mime; + + if (!m_mime.length() || !m_mime.compare("text/plain") || !m_mime.compare("application/octet-stream")) + m_mime = resolveMimeType(m_url, m_mime); + + return m_mime; +} + +const string WebResponse::resolveMimeType(const string& url, const string& old_mime) +{ + // Use "text/html" as a default (matching the behaviour of the Apache + // HTTP stack -- see guessMimeType() in LoadListener.java). + string mimeType = old_mime.length() ? old_mime : "text/html"; + // Try to guess a better MIME type from the URL. We call + // getMIMETypeForExtension rather than getMIMETypeForPath because the + // latter defaults to "application/octet-stream" on failure. + WebCore::KURL kurl(WebCore::ParsedURLString, url.c_str()); + WTF::String path = kurl.path(); + size_t extensionPos = path.reverseFind('.'); + if (extensionPos != WTF::notFound) { + // We found a file extension. + path.remove(0, extensionPos + 1); + // TODO: Should use content-disposition instead of url if it is there + WTF::String mime = WebCore::MIMETypeRegistry::getMIMETypeForExtension(path); + if (!mime.isEmpty()) { + // Great, we found a MIME type. + mimeType = std::string(mime.utf8().data(), mime.length()); + } + } + return mimeType; +} + +bool WebResponse::getHeader(const string& header, string* result) const +{ + map::const_iterator iter = m_headerFields.find(header); + if (iter == m_headerFields.end()) + return false; + if (result) + *result = iter->second; + return true; +} + +long long WebResponse::getExpectedSize() const +{ + return m_expectedSize; +} + +} // namespace android diff --git a/Source/WebKit/android/WebCoreSupport/WebResponse.h b/Source/WebKit/android/WebCoreSupport/WebResponse.h new file mode 100644 index 0000000..88c8917 --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/WebResponse.h @@ -0,0 +1,91 @@ +/* + * 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 WebResponse_h +#define WebResponse_h + +#include "ChromiumIncludes.h" +#include "KURL.h" +#include "WebViewClientError.h" + +#include +#include + +namespace WebCore { +class ResourceResponse; +class ResourceError; +} + +namespace android { + +class WebResponse { + +public: + WebResponse() {} + WebResponse(URLRequest*); + WebResponse(const std::string &url, const std::string &mimeType, long long expectedSize, const std::string &encoding, int httpStatusCode); + + const std::string& getUrl() const; + void setUrl(const std::string&); + + const std::string& getMimeType(); // Use only on WebCore thread. + bool getHeader(const std::string& header, std::string* result) const; + long long getExpectedSize() const; + + const net::SSLInfo& getSslInfo() const { return m_sslInfo; } + + // The create() methods create WebCore objects. They must only be called on the WebKit thread. + WebCore::KURL createKurl(); + WebCore::ResourceResponse createResourceResponse(); + WebCore::ResourceError createResourceError(); + + static const std::string resolveMimeType(const std::string& url, const std::string& old_mime); + +private: + net::Error m_error; + std::string m_encoding; + int m_httpStatusCode; + std::string m_host; + std::string m_httpStatusText; + long long m_expectedSize; + std::string m_mime; + std::string m_url; + net::SSLInfo m_sslInfo; + + struct CaseInsensitiveLessThan { + bool operator()(const std::string& lhs, const std::string& rhs) const { + return strcasecmp(lhs.c_str(), rhs.c_str()) < 0; + } + }; + + // Header fields are case insensitive, so we use a case-insensitive map. + // See RFC 822, 3.4.7, "CASE INDEPENDENCE". + std::map m_headerFields; + +}; + +} // namespace android + +#endif diff --git a/Source/WebKit/android/WebCoreSupport/WebUrlLoader.cpp b/Source/WebKit/android/WebCoreSupport/WebUrlLoader.cpp new file mode 100644 index 0000000..0c90bc5 --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/WebUrlLoader.cpp @@ -0,0 +1,87 @@ +/* + * 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 "WebUrlLoader.h" + +#include "FrameLoaderClientAndroid.h" +#include "WebCoreFrameBridge.h" +#include "WebUrlLoaderClient.h" + +namespace android { + +// on main thread +WebUrlLoader::WebUrlLoader(WebFrame* webFrame, WebCore::ResourceHandle* resourceHandle, const WebCore::ResourceRequest& resourceRequest) +{ + m_loaderClient = new WebUrlLoaderClient(webFrame, resourceHandle, resourceRequest); +} + +// on main thread +WebUrlLoader::~WebUrlLoader() +{ +} + +PassRefPtr WebUrlLoader::start(FrameLoaderClient* client, WebCore::ResourceHandle* resourceHandle, + const WebCore::ResourceRequest& resourceRequest, bool isMainResource, bool isMainFrame, bool isSync, WebRequestContext* context) +{ + FrameLoaderClientAndroid* androidClient = static_cast(client); + WebFrame* webFrame = androidClient->webFrame(); + + if (webFrame->blockNetworkLoads() && + (resourceRequest.url().protocolIs("http") || + resourceRequest.url().protocolIs("https"))) + return NULL; + + webFrame->maybeSavePassword(androidClient->getFrame(), resourceRequest); + + RefPtr loader = WebUrlLoader::create(webFrame, resourceHandle, resourceRequest); + loader->m_loaderClient->start(isMainResource, isMainFrame, isSync, context); + + return loader.release(); +} + +PassRefPtr WebUrlLoader::create(WebFrame* webFrame, WebCore::ResourceHandle* resourceHandle, const WebCore::ResourceRequest& resourceRequest) +{ + return adoptRef(new WebUrlLoader(webFrame, resourceHandle, resourceRequest)); +} + +// on main thread +void WebUrlLoader::cancel() +{ + m_loaderClient->cancel(); +} + +void WebUrlLoader::downloadFile() +{ + m_loaderClient->downloadFile(); +} + +void WebUrlLoader::pauseLoad(bool pause) +{ + m_loaderClient->pauseLoad(pause); +} + +} // namespace android diff --git a/Source/WebKit/android/WebCoreSupport/WebUrlLoader.h b/Source/WebKit/android/WebCoreSupport/WebUrlLoader.h new file mode 100644 index 0000000..dd88e73 --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/WebUrlLoader.h @@ -0,0 +1,57 @@ +/* + * 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 WebUrlLoader_h +#define WebUrlLoader_h + +#include "ChromiumIncludes.h" +#include "ResourceLoaderAndroid.h" + +using namespace WebCore; + +namespace android { +class WebUrlLoaderClient; +class WebFrame; +class WebRequestContext; + +class WebUrlLoader : public ResourceLoaderAndroid { +public: + virtual ~WebUrlLoader(); + static PassRefPtr start(FrameLoaderClient* client, WebCore::ResourceHandle*, const WebCore::ResourceRequest&, bool isMainResource, bool isMainFrame, bool sync, WebRequestContext*); + + virtual void cancel(); + virtual void downloadFile(); + virtual void pauseLoad(bool pause); + +private: + WebUrlLoader(WebFrame*, WebCore::ResourceHandle*, const WebCore::ResourceRequest&); + static PassRefPtr create(WebFrame*, WebCore::ResourceHandle*, const WebCore::ResourceRequest&); + + scoped_refptr m_loaderClient; +}; + +} // namespace android + +#endif diff --git a/Source/WebKit/android/WebCoreSupport/WebUrlLoaderClient.cpp b/Source/WebKit/android/WebCoreSupport/WebUrlLoaderClient.cpp new file mode 100644 index 0000000..cf218e7 --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/WebUrlLoaderClient.cpp @@ -0,0 +1,482 @@ +/* + * 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. + */ + +#define LOG_TAG "WebUrlLoaderClient" + +#include "config.h" +#include "WebUrlLoaderClient.h" + +#include "ChromiumIncludes.h" +#include "OwnPtr.h" +#include "ResourceHandle.h" +#include "ResourceHandleClient.h" +#include "ResourceResponse.h" +#include "WebCoreFrameBridge.h" +#include "WebRequest.h" +#include "WebResourceRequest.h" + +#include + +namespace android { + +base::Thread* WebUrlLoaderClient::ioThread() +{ + static base::Thread* networkThread = 0; + static Lock networkThreadLock; + + // Multiple threads appear to access the ioThread so we must ensure the + // critical section ordering. + AutoLock lock(networkThreadLock); + + if (!networkThread) + networkThread = new base::Thread("network"); + + if (!networkThread) + return 0; + + if (networkThread->IsRunning()) + return networkThread; + + base::Thread::Options options; + options.message_loop_type = MessageLoop::TYPE_IO; + if (!networkThread->StartWithOptions(options)) { + delete networkThread; + networkThread = 0; + } + + return networkThread; +} + +Lock* WebUrlLoaderClient::syncLock() { + static Lock s_syncLock; + return &s_syncLock; +} + +ConditionVariable* WebUrlLoaderClient::syncCondition() { + static ConditionVariable s_syncCondition(syncLock()); + return &s_syncCondition; +} + +WebUrlLoaderClient::~WebUrlLoaderClient() +{ +} + +bool WebUrlLoaderClient::isActive() const +{ + if (m_cancelling) + return false; + if (!m_resourceHandle) + return false; + if (!m_resourceHandle->client()) + return false; + if (m_finished) + return false; + + return true; +} + +WebUrlLoaderClient::WebUrlLoaderClient(WebFrame* webFrame, WebCore::ResourceHandle* resourceHandle, const WebCore::ResourceRequest& resourceRequest) + : m_webFrame(webFrame) + , m_resourceHandle(resourceHandle) + , m_isMainResource(false) + , m_isMainFrame(false) + , m_isCertMimeType(false) + , m_cancelling(false) + , m_sync(false) + , m_finished(false) +{ + WebResourceRequest webResourceRequest(resourceRequest); + UrlInterceptResponse* intercept = webFrame->shouldInterceptRequest(resourceRequest.url().string()); + if (intercept) { + m_request = new WebRequest(this, webResourceRequest, intercept); + return; + } + + m_request = new WebRequest(this, webResourceRequest); + + // Set uploads before start is called on the request + if (resourceRequest.httpBody() && !(webResourceRequest.method() == "GET" || webResourceRequest.method() == "HEAD")) { + Vector::iterator iter; + Vector elements = resourceRequest.httpBody()->elements(); + for (iter = elements.begin(); iter != elements.end(); iter++) { + FormDataElement element = *iter; + + switch (element.m_type) { + case FormDataElement::data: + if (!element.m_data.isEmpty()) { + // WebKit sometimes gives up empty data to append. These aren't + // necessary so we just optimize those out here. + base::Thread* thread = ioThread(); + if (thread) { + Vector* data = new Vector(element.m_data); + thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request.get(), &WebRequest::appendBytesToUpload, data)); + } + } + break; + case FormDataElement::encodedFile: + { + // Chromium check if it is a directory by checking + // element.m_fileLength, that doesn't work in Android + std::string filename = element.m_filename.utf8().data(); + if (filename.size()) { + // Change from a url string to a filename + if (filename.find("file://") == 0) // Found at pos 0 + filename.erase(0, 7); + base::Thread* thread = ioThread(); + if (thread) + thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request.get(), &WebRequest::appendFileToUpload, filename)); + } + } + break; +#if ENABLE(BLOB) + case FormDataElement::encodedBlob: + LOG_ASSERT(false, "Unexpected use of FormDataElement::encodedBlob"); + break; +#endif // ENABLE(BLOB) + default: + LOG_ASSERT(false, "Unexpected default case in WebUrlLoaderClient.cpp"); + break; + } + } + } +} + +bool WebUrlLoaderClient::start(bool isMainResource, bool isMainFrame, bool sync, WebRequestContext* context) +{ + base::Thread* thread = ioThread(); + if (!thread) { + return false; + } + + m_isMainResource = isMainResource; + m_isMainFrame = isMainFrame; + m_sync = sync; + if (m_sync) { + AutoLock autoLock(*syncLock()); + m_request->setSync(sync); + m_request->setRequestContext(context); + thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request.get(), &WebRequest::start)); + + // Run callbacks until the queue is exhausted and m_finished is true. + // Sometimes, a sync load can wait forever and lock up the WebCore thread, + // here we use TimedWait() with multiple tries to avoid locking. + const int kMaxNumTimeout = 3; + const int kCallbackWaitingTime = 10; + int num_timeout = 0; + while(!m_finished) { + while (!m_queue.empty()) { + OwnPtr task(m_queue.front()); + m_queue.pop_front(); + task->Run(); + } + if (m_finished) break; + + syncCondition()->TimedWait(base::TimeDelta::FromSeconds(kCallbackWaitingTime)); + if (m_queue.empty()) { + LOGE("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) { + cancel(); + m_resourceHandle = 0; + return false; + } + } + } + + // This may be the last reference to us, so we may be deleted now. + // Don't access any more member variables after releasing this reference. + m_resourceHandle = 0; + } else { + // Asynchronous start. + // Important to set this before the thread starts so it has a reference and can't be deleted + // before the task starts running on the IO thread. + m_request->setRequestContext(context); + thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request.get(), &WebRequest::start)); + } + return true; +} + +namespace { +// Check if the mime type is for certificate installation. +// The items must be consistent with the sCertificateTypeMap +// in frameworks/base/core/java/android/webkit/CertTool.java. +bool isMimeTypeForCert(const std::string& mimeType) +{ + static std::hash_set sCertificateTypeSet; + if (sCertificateTypeSet.empty()) { + sCertificateTypeSet.insert("application/x-x509-ca-cert"); + sCertificateTypeSet.insert("application/x-x509-user-cert"); + sCertificateTypeSet.insert("application/x-pkcs12"); + } + return sCertificateTypeSet.find(mimeType) != sCertificateTypeSet.end(); +} +} + +void WebUrlLoaderClient::downloadFile() +{ + if (m_response) { + std::string contentDisposition; + m_response->getHeader("content-disposition", &contentDisposition); + m_webFrame->downloadStart(m_response->getUrl(), m_request->getUserAgent(), contentDisposition, m_response->getMimeType(), m_response->getExpectedSize()); + + m_isCertMimeType = isMimeTypeForCert(m_response->getMimeType()); + // Currently, only certificate mime type needs to receive the data. + // Other mime type, e.g. wav, will send the url to other application + // which will load the data by url. + if (!m_isCertMimeType) + cancel(); + } else { + LOGE("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(); + } +} + +void WebUrlLoaderClient::cancel() +{ + if (!isActive()) + return; + + m_cancelling = true; + + base::Thread* thread = ioThread(); + if (thread) + thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request.get(), &WebRequest::cancel)); +} + +void WebUrlLoaderClient::pauseLoad(bool pause) +{ + if (!isActive()) + return; + + base::Thread* thread = ioThread(); + if (thread) + thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request.get(), &WebRequest::pauseLoad, pause)); +} + +void WebUrlLoaderClient::setAuth(const std::string& username, const std::string& password) +{ + if (!isActive()) + return; + + base::Thread* thread = ioThread(); + if (!thread) { + return; + } + string16 username16 = ASCIIToUTF16(username); + string16 password16 = ASCIIToUTF16(password); + thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request.get(), &WebRequest::setAuth, username16, password16)); +} + +void WebUrlLoaderClient::cancelAuth() +{ + if (!isActive()) + return; + + base::Thread* thread = ioThread(); + if (!thread) { + return; + } + thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request.get(), &WebRequest::cancelAuth)); +} + +void WebUrlLoaderClient::proceedSslCertError() +{ + base::Thread* thread = ioThread(); + if (isActive() && thread) + thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request.get(), &WebRequest::proceedSslCertError)); + this->Release(); +} + +void WebUrlLoaderClient::cancelSslCertError(int cert_error) +{ + base::Thread* thread = ioThread(); + if (isActive() && thread) + thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request.get(), &WebRequest::cancelSslCertError, cert_error)); + this->Release(); +} + + +void WebUrlLoaderClient::finish() +{ + m_finished = true; + if (!m_sync) { + // This is the last reference to us, so we will be deleted now. + // We only release the reference here if start() was called asynchronously! + m_resourceHandle = 0; + } + m_request = 0; +} + +namespace { +// Trampoline to wrap a Chromium Task* in a WebKit-style static function + void*. +static void RunTask(void* v) { + OwnPtr task(static_cast(v)); + task->Run(); +} +} + +// This is called from the IO thread, and dispatches the callback to the main thread. +void WebUrlLoaderClient::maybeCallOnMainThread(Task* task) +{ + if (m_sync) { + AutoLock autoLock(*syncLock()); + if (m_queue.empty()) { + syncCondition()->Broadcast(); + } + m_queue.push_back(task); + } else { + // Let WebKit handle it. + callOnMainThread(RunTask, task); + } +} + +// Response methods +void WebUrlLoaderClient::didReceiveResponse(PassOwnPtr webResponse) +{ + if (!isActive()) + return; + + m_response = webResponse; + m_resourceHandle->client()->didReceiveResponse(m_resourceHandle.get(), m_response->createResourceResponse()); + + // Set the main page's certificate to WebView. + if (m_isMainResource && m_isMainFrame) { + const net::SSLInfo& ssl_info = m_response->getSslInfo(); + if (ssl_info.is_valid()) { + std::vector chain_bytes; + ssl_info.cert->GetChainDEREncodedBytes(&chain_bytes); + m_webFrame->setCertificate(chain_bytes[0]); + } + + // Look for X-Auto-Login on the main resource to log in the user. + std::string login; + if (m_response->getHeader("x-auto-login", &login)) + m_webFrame->autoLogin(login); + } +} + +void WebUrlLoaderClient::didReceiveData(scoped_refptr buf, int size) +{ + if (m_isMainResource && m_isCertMimeType) { + m_webFrame->didReceiveData(buf->data(), size); + } + + if (!isActive() || !size) + return; + + // didReceiveData will take a copy of the data + if (m_resourceHandle && m_resourceHandle->client()) + m_resourceHandle->client()->didReceiveData(m_resourceHandle.get(), buf->data(), size, size); +} + +// For data url's +void WebUrlLoaderClient::didReceiveDataUrl(PassOwnPtr str) +{ + if (!isActive() || !str->size()) + return; + + // didReceiveData will take a copy of the data + m_resourceHandle->client()->didReceiveData(m_resourceHandle.get(), str->data(), str->size(), str->size()); +} + +// For special android files +void WebUrlLoaderClient::didReceiveAndroidFileData(PassOwnPtr > vector) +{ + if (!isActive() || !vector->size()) + return; + + // didReceiveData will take a copy of the data + m_resourceHandle->client()->didReceiveData(m_resourceHandle.get(), vector->begin(), vector->size(), vector->size()); +} + +void WebUrlLoaderClient::didFail(PassOwnPtr webResponse) +{ + if (isActive()) + m_resourceHandle->client()->didFail(m_resourceHandle.get(), webResponse->createResourceError()); + + // Always finish a request, if not it will leak + finish(); +} + +void WebUrlLoaderClient::willSendRequest(PassOwnPtr webResponse) +{ + if (!isActive()) + return; + + KURL url = webResponse->createKurl(); + OwnPtr resourceRequest(new WebCore::ResourceRequest(url)); + m_resourceHandle->client()->willSendRequest(m_resourceHandle.get(), *resourceRequest, webResponse->createResourceResponse()); + + // WebKit may have killed the request. + if (!isActive()) + return; + + // Like Chrome, we only follow the redirect if WebKit left the URL unmodified. + if (url == resourceRequest->url()) { + ioThread()->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request.get(), &WebRequest::followDeferredRedirect)); + } else { + cancel(); + } +} + +void WebUrlLoaderClient::didFinishLoading() +{ + if (isActive()) + m_resourceHandle->client()->didFinishLoading(m_resourceHandle.get(), 0); + + if (m_isMainResource && m_isCertMimeType) { + m_webFrame->didFinishLoading(); + } + + // Always finish a request, if not it will leak + finish(); +} + +void WebUrlLoaderClient::authRequired(scoped_refptr authChallengeInfo, bool firstTime) +{ + if (!isActive()) + return; + + std::string host = base::SysWideToUTF8(authChallengeInfo->host_and_port); + std::string realm = base::SysWideToUTF8(authChallengeInfo->realm); + + m_webFrame->didReceiveAuthenticationChallenge(this, host, realm, firstTime); +} + +void WebUrlLoaderClient::reportSslCertError(int cert_error, net::X509Certificate* cert) +{ + if (!isActive()) + return; + + std::vector chain_bytes; + cert->GetChainDEREncodedBytes(&chain_bytes); + this->AddRef(); + m_webFrame->reportSslCertError(this, cert_error, chain_bytes[0]); +} + +} // namespace android diff --git a/Source/WebKit/android/WebCoreSupport/WebUrlLoaderClient.h b/Source/WebKit/android/WebCoreSupport/WebUrlLoaderClient.h new file mode 100644 index 0000000..dc101db --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/WebUrlLoaderClient.h @@ -0,0 +1,130 @@ +/* + * 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 WebUrlLoaderClient_h +#define WebUrlLoaderClient_h + +#include "ChromiumIncludes.h" +#include "RefCounted.h" +#include "WebResponse.h" +#include "WebUrlLoader.h" + +#include +#include +#include +#include + +class Lock; +class ConditionVariable; + +namespace base { +class Thread; +} + +namespace net { +class IOBuffer; +class AuthChallengeInfo; +} + +namespace android { + +class WebFrame; +class WebRequest; +class WebRequestContext; + +// This class handles communication between the IO thread where loading happens +// and the webkit main thread. +// TODO: +// - Implement didFail +// - Implement sync requests +// - Implement downloadFile +// - Implement pauseLoad +class WebUrlLoaderClient : public base::RefCountedThreadSafe { +public: + WebUrlLoaderClient(WebFrame*, WebCore::ResourceHandle*, const WebCore::ResourceRequest&); + + // Called from WebCore, will be forwarded to the IO thread + bool start(bool isMainResource, bool isMainFrame, bool sync, WebRequestContext*); + void cancel(); + void downloadFile(); + void pauseLoad(bool pause); + void setAuth(const std::string& username, const std::string& password); + void cancelAuth(); + void proceedSslCertError(); + void cancelSslCertError(int cert_error); + + typedef void CallbackFunction(void*); + + // This is called from the IO thread, and dispatches the callback to the main thread. + // (For asynchronous calls, we just delegate to WebKit's callOnMainThread.) + void maybeCallOnMainThread(Task* task); + + // Called by WebRequest (using maybeCallOnMainThread), should be forwarded to WebCore. + void didReceiveResponse(PassOwnPtr); + void didReceiveData(scoped_refptr, int size); + void didReceiveDataUrl(PassOwnPtr); + void didReceiveAndroidFileData(PassOwnPtr >); + void didFinishLoading(); + void didFail(PassOwnPtr); + void willSendRequest(PassOwnPtr); + void authRequired(scoped_refptr, bool firstTime); + void reportSslCertError(int cert_error, net::X509Certificate* cert); + + // Handle to the chrome IO thread + static base::Thread* ioThread(); + +private: + friend class base::RefCountedThreadSafe; + virtual ~WebUrlLoaderClient(); + + void finish(); + + WebFrame* m_webFrame; + RefPtr m_resourceHandle; + bool m_isMainResource; + bool m_isMainFrame; + bool m_isCertMimeType; + bool m_cancelling; + bool m_sync; + volatile bool m_finished; + + scoped_refptr m_request; + OwnPtr m_response; // NULL until didReceiveResponse is called. + + // Check if a request is active + bool isActive() const; + + // Mutex and condition variable used for synchronous requests. + // Note that these are static. This works because there's only one main thread. + static Lock* syncLock(); + static ConditionVariable* syncCondition(); + + // Queue of callbacks to be executed by the main thread. Must only be accessed inside mutex. + std::deque m_queue; +}; + +} // namespace android + +#endif diff --git a/Source/WebKit/android/WebCoreSupport/WebViewClientError.cpp b/Source/WebKit/android/WebCoreSupport/WebViewClientError.cpp new file mode 100644 index 0000000..59542da --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/WebViewClientError.cpp @@ -0,0 +1,132 @@ +/* + * 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 "WebViewClientError.h" + +using namespace net; + +namespace android { + +WebViewClientError ToWebViewClientError(net::Error error) { + // Note: many net::Error constants don't have an obvious mapping. + // These will be handled by the default case, ERROR_UNKNOWN. + switch(error) { + case ERR_UNSUPPORTED_AUTH_SCHEME: + return ERROR_UNSUPPORTED_AUTH_SCHEME; + + case ERR_INVALID_AUTH_CREDENTIALS: + case ERR_MISSING_AUTH_CREDENTIALS: + case ERR_MISCONFIGURED_AUTH_ENVIRONMENT: + return ERROR_AUTHENTICATION; + + case ERR_TOO_MANY_REDIRECTS: + return ERROR_REDIRECT_LOOP; + + case ERR_UPLOAD_FILE_CHANGED: + return ERROR_FILE_NOT_FOUND; + + case ERR_INVALID_URL: + return ERROR_BAD_URL; + + case ERR_DISALLOWED_URL_SCHEME: + case ERR_UNKNOWN_URL_SCHEME: + return ERROR_UNSUPPORTED_SCHEME; + + case ERR_IO_PENDING: + case ERR_NETWORK_IO_SUSPENDED: + return ERROR_IO; + + case ERR_CONNECTION_TIMED_OUT: + case ERR_TIMED_OUT: + return ERROR_TIMEOUT; + + case ERR_FILE_TOO_BIG: + return ERROR_FILE; + + case ERR_HOST_RESOLVER_QUEUE_TOO_LARGE: + case ERR_INSUFFICIENT_RESOURCES: + case ERR_OUT_OF_MEMORY: + return ERROR_TOO_MANY_REQUESTS; + + case ERR_CONNECTION_CLOSED: + case ERR_CONNECTION_RESET: + case ERR_CONNECTION_REFUSED: + case ERR_CONNECTION_ABORTED: + case ERR_CONNECTION_FAILED: + case ERR_SOCKET_NOT_CONNECTED: + return ERROR_CONNECT; + + case ERR_ADDRESS_INVALID: + case ERR_ADDRESS_UNREACHABLE: + case ERR_NAME_NOT_RESOLVED: + case ERR_NAME_RESOLUTION_FAILED: + return ERROR_HOST_LOOKUP; + + case ERR_SSL_PROTOCOL_ERROR: + case ERR_SSL_CLIENT_AUTH_CERT_NEEDED: + case ERR_TUNNEL_CONNECTION_FAILED: + case ERR_NO_SSL_VERSIONS_ENABLED: + case ERR_SSL_VERSION_OR_CIPHER_MISMATCH: + case ERR_SSL_RENEGOTIATION_REQUESTED: + case ERR_CERT_ERROR_IN_SSL_RENEGOTIATION: + case ERR_BAD_SSL_CLIENT_AUTH_CERT: + case ERR_SSL_NO_RENEGOTIATION: + case ERR_SSL_DECOMPRESSION_FAILURE_ALERT: + case ERR_SSL_BAD_RECORD_MAC_ALERT: + case ERR_SSL_UNSAFE_NEGOTIATION: + case ERR_SSL_WEAK_SERVER_EPHEMERAL_DH_KEY: + case ERR_SSL_SNAP_START_NPN_MISPREDICTION: + case ERR_SSL_CLIENT_AUTH_PRIVATE_KEY_ACCESS_DENIED: + case ERR_SSL_CLIENT_AUTH_CERT_NO_PRIVATE_KEY: + return ERROR_FAILED_SSL_HANDSHAKE; + + case ERR_PROXY_AUTH_UNSUPPORTED: + case ERR_PROXY_AUTH_REQUESTED: + case ERR_PROXY_CONNECTION_FAILED: + case ERR_UNEXPECTED_PROXY_AUTH: + return ERROR_PROXY_AUTHENTICATION; + + /* The certificate errors are handled by their own dialog + * and don't need to be reported to the framework again. + */ + case ERR_CERT_COMMON_NAME_INVALID: + case ERR_CERT_DATE_INVALID: + case ERR_CERT_AUTHORITY_INVALID: + case ERR_CERT_CONTAINS_ERRORS: + case ERR_CERT_NO_REVOCATION_MECHANISM: + case ERR_CERT_UNABLE_TO_CHECK_REVOCATION: + case ERR_CERT_REVOKED: + case ERR_CERT_INVALID: + case ERR_CERT_WEAK_SIGNATURE_ALGORITHM: + case ERR_CERT_NOT_IN_DNS: + return ERROR_OK; + + default: + return ERROR_UNKNOWN; + } +} + +} diff --git a/Source/WebKit/android/WebCoreSupport/WebViewClientError.h b/Source/WebKit/android/WebCoreSupport/WebViewClientError.h new file mode 100644 index 0000000..d274dc7 --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/WebViewClientError.h @@ -0,0 +1,74 @@ +/* + * 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 WebViewClientError_h +#define WebViewClientError_h + +#include "ChromiumIncludes.h" + +namespace android { + +// This enum must be kept in sync with WebViewClient.java +enum WebViewClientError { + /** Success */ + ERROR_OK = 0, + /** Generic error */ + ERROR_UNKNOWN = -1, + /** Server or proxy hostname lookup failed */ + ERROR_HOST_LOOKUP = -2, + /** Unsupported authentication scheme (not basic or digest) */ + ERROR_UNSUPPORTED_AUTH_SCHEME = -3, + /** User authentication failed on server */ + ERROR_AUTHENTICATION = -4, + /** User authentication failed on proxy */ + ERROR_PROXY_AUTHENTICATION = -5, + /** Failed to connect to the server */ + ERROR_CONNECT = -6, + /** Failed to read or write to the server */ + ERROR_IO = -7, + /** Connection timed out */ + ERROR_TIMEOUT = -8, + /** Too many redirects */ + ERROR_REDIRECT_LOOP = -9, + /** Unsupported URI scheme */ + ERROR_UNSUPPORTED_SCHEME = -10, + /** Failed to perform SSL handshake */ + ERROR_FAILED_SSL_HANDSHAKE = -11, + /** Malformed URL */ + ERROR_BAD_URL = -12, + /** Generic file error */ + ERROR_FILE = -13, + /** File not found */ + ERROR_FILE_NOT_FOUND = -14, + /** Too many requests during this load */ + ERROR_TOO_MANY_REQUESTS = -15, +}; + +// Get the closest WebViewClient match to the given Chrome error code. +WebViewClientError ToWebViewClientError(net::Error); + +} // namespace android + +#endif // WebViewClientError_h diff --git a/Source/WebKit/android/WebCoreSupport/autofill/AutoFillHostAndroid.cpp b/Source/WebKit/android/WebCoreSupport/autofill/AutoFillHostAndroid.cpp new file mode 100644 index 0000000..5bc4c92 --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/autofill/AutoFillHostAndroid.cpp @@ -0,0 +1,51 @@ +/* + * 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 "AutoFillHostAndroid.h" + +#include "autofill/WebAutoFill.h" + +namespace android { + +AutoFillHostAndroid::AutoFillHostAndroid(WebAutoFill* autoFill) + : mAutoFill(autoFill) +{ +} + +void AutoFillHostAndroid::AutoFillSuggestionsReturned(const std::vector& names, const std::vector& labels, const std::vector& icons, const std::vector& uniqueIds) +{ + // TODO: what do we do with icons? + if (mAutoFill) + mAutoFill->querySuccessful(names[0], labels[0], uniqueIds[0]); +} + +void AutoFillHostAndroid::AutoFillFormDataFilled(int queryId, const webkit_glue::FormData& form) +{ + if (mAutoFill) + mAutoFill->fillFormInPage(queryId, form); +} + +} diff --git a/Source/WebKit/android/WebCoreSupport/autofill/AutoFillHostAndroid.h b/Source/WebKit/android/WebCoreSupport/autofill/AutoFillHostAndroid.h new file mode 100644 index 0000000..9677b46 --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/autofill/AutoFillHostAndroid.h @@ -0,0 +1,54 @@ +/* + * 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 AutoFillHostAndroid_h +#define AutoFillHostAndroid_h + +#include "ChromiumIncludes.h" + +#include + +namespace webkit_glue { +class FormData; +} + +namespace android { +class WebAutoFill; + +// This class receives the callbacks from the AutoFillManager in the Chromium code. +class AutoFillHostAndroid : public AutoFillHost { +public: + AutoFillHostAndroid(WebAutoFill* autoFill); + virtual ~AutoFillHostAndroid() { } + + virtual void AutoFillSuggestionsReturned(const std::vector& names, const std::vector& labels, const std::vector& icons, const std::vector& uniqueIds); + virtual void AutoFillFormDataFilled(int queryId, const webkit_glue::FormData&); + +private: + WebAutoFill* mAutoFill; +}; +} + +#endif diff --git a/Source/WebKit/android/WebCoreSupport/autofill/FormFieldAndroid.cpp b/Source/WebKit/android/WebCoreSupport/autofill/FormFieldAndroid.cpp new file mode 100644 index 0000000..6af0875 --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/autofill/FormFieldAndroid.cpp @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2010 The Chromium Authors. All rights reserved. + * 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 "FormFieldAndroid.h" + +#include "ChromiumIncludes.h" +#include "Element.h" +#include "HTMLFormControlElement.h" +#include "HTMLInputElement.h" +#include "HTMLNames.h" +#include "HTMLOptionElement.h" +#include "HTMLSelectElement.h" +#include "StringUtils.h" +#include + +using WebCore::Element; +using WebCore::HTMLFormControlElement; +using WebCore::HTMLInputElement; +using WebCore::HTMLOptionElement; +using WebCore::HTMLSelectElement; + +using namespace WebCore::HTMLNames; + +// TODO: This file is taken from chromium/webkit/glue/form_field.cc and +// customised to use WebCore types rather than WebKit API types. It would +// be nice and would ease future merge pain if the two could be combined. + +namespace webkit_glue { + +FormField::FormField() + : max_length_(0), + is_autofilled_(false) { +} + +// TODO: This constructor should probably be deprecated and the +// functionality moved to FormManager. +FormField::FormField(const HTMLFormControlElement& element) + : max_length_(0), + is_autofilled_(false) { + name_ = nameForAutoFill(element); + + // TODO: Extract the field label. For now we just use the field + // name. + label_ = name_; + + form_control_type_ = formControlType(element); + if (form_control_type_ == kText) { + const HTMLInputElement& input_element = static_cast(element); + value_ = WTFStringToString16(input_element.value()); + max_length_ = input_element.size(); + is_autofilled_ = input_element.isAutofilled(); + } else if (form_control_type_ == kSelectOne) { + const HTMLSelectElement& const_select_element = static_cast(element); + HTMLSelectElement& select_element = const_cast(const_select_element); + value_ = WTFStringToString16(select_element.value()); + + // For select-one elements copy option strings. + WTF::Vector list_items = select_element.listItems(); + option_strings_.reserve(list_items.size()); + for (size_t i = 0; i < list_items.size(); ++i) { + if (list_items[i]->hasTagName(optionTag)) + option_strings_.push_back(WTFStringToString16(static_cast(list_items[i])->value())); + } + } + + TrimWhitespace(value_, TRIM_LEADING, &value_); +} + +FormField::FormField(const string16& label, const string16& name, const string16& value, const string16& form_control_type, int max_length, bool is_autofilled) + : label_(label), + name_(name), + value_(value), + form_control_type_(form_control_type), + max_length_(max_length), + is_autofilled_(is_autofilled) { +} + +FormField::~FormField() { +} + +bool FormField::operator==(const FormField& field) const { + // A FormField stores a value, but the value is not part of the identity of + // the field, so we don't want to compare the values. + return (label_ == field.label_ && + name_ == field.name_ && + form_control_type_ == field.form_control_type_ && + max_length_ == field.max_length_); +} + +bool FormField::operator!=(const FormField& field) const { + return !operator==(field); +} + +bool FormField::StrictlyEqualsHack(const FormField& field) const { + return (label_ == field.label_ && + name_ == field.name_ && + value_ == field.value_ && + form_control_type_ == field.form_control_type_ && + max_length_ == field.max_length_); +} + +std::ostream& operator<<(std::ostream& os, const FormField& field) { + return os + << UTF16ToUTF8(field.label()) + << " " + << UTF16ToUTF8(field.name()) + << " " + << UTF16ToUTF8(field.value()) + << " " + << UTF16ToUTF8(field.form_control_type()) + << " " + << field.max_length(); +} + +} // namespace webkit_glue diff --git a/Source/WebKit/android/WebCoreSupport/autofill/FormFieldAndroid.h b/Source/WebKit/android/WebCoreSupport/autofill/FormFieldAndroid.h new file mode 100644 index 0000000..c5e3ecc --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/autofill/FormFieldAndroid.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2010 The Chromium Authors. All rights reserved. + * 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 FormFieldAndroid_h +#define FormFieldAndroid_h + +#include +#include + +// TODO: This file is taken from chromium/webkit/glue/form_field.h and +// customised to use WebCore types rather than WebKit API types. It would +// be nice and would ease future merge pain if the two could be combined. + +namespace WebCore { +class HTMLFormControlElement; +} + +namespace webkit_glue { + +// Stores information about a field in a form. +class FormField { +public: + FormField(); + explicit FormField(const WebCore::HTMLFormControlElement& element); + FormField(const string16& label, const string16& name, const string16& value, const string16& form_control_type, int max_length, bool is_autofilled); + virtual ~FormField(); + + const string16& label() const { return label_; } + const string16& name() const { return name_; } + const string16& value() const { return value_; } + const string16& form_control_type() const { return form_control_type_; } + int max_length() const { return max_length_; } + bool is_autofilled() const { return is_autofilled_; } + + // Returns option string for elements for which they make sense (select-one, + // for example) for the rest of elements return an empty array. + const std::vector& option_strings() const { return option_strings_; } + + void set_label(const string16& label) { label_ = label; } + void set_name(const string16& name) { name_ = name; } + void set_value(const string16& value) { value_ = value; } + void set_form_control_type(const string16& form_control_type) { form_control_type_ = form_control_type; } + void set_max_length(int max_length) { max_length_ = max_length; } + void set_autofilled(bool is_autofilled) { is_autofilled_ = is_autofilled; } + void set_option_strings(const std::vector& strings) { option_strings_ = strings; } + + // Equality tests for identity which does not include |value_| or |size_|. + // Use |StrictlyEqualsHack| method to test all members. + // TODO: These operators need to be revised when we implement field + // ids. + bool operator==(const FormField& field) const; + bool operator!=(const FormField& field) const; + + // Test equality of all data members. + // TODO: This will be removed when we implement field ids. + bool StrictlyEqualsHack(const FormField& field) const; + +private: + string16 label_; + string16 name_; + string16 value_; + string16 form_control_type_; + int max_length_; + bool is_autofilled_; + std::vector option_strings_; +}; + +// So we can compare FormFields with EXPECT_EQ(). +std::ostream& operator<<(std::ostream& os, const FormField& field); + +} // namespace webkit_glue + +#endif // WEBKIT_GLUE_FORM_FIELD_H_ diff --git a/Source/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.cpp b/Source/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.cpp new file mode 100644 index 0000000..9652794 --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.cpp @@ -0,0 +1,871 @@ +/* + * Copyright (c) 2010 The Chromium Authors. All rights reserved. + * 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 "FormManagerAndroid.h" + +#include "DocumentLoader.h" +#include "Element.h" +#include "Frame.h" +#include "FrameLoader.h" +#include "HTMLCollection.h" +#include "HTMLFormControlElement.h" +#include "HTMLFormElement.h" +#include "HTMLInputElement.h" +#include "HTMLLabelElement.h" +#include "HTMLNames.h" +#include "HTMLOptionElement.h" +#include "HTMLSelectElement.h" +#include "Node.h" +#include "NodeList.h" +#include "HTMLCollection.h" +#include "FormAssociatedElement.h" +#include "FormFieldAndroid.h" +#include "QualifiedName.h" +#include "StringUtils.h" + +// TODO: This file is taken from chromium/chrome/renderer/form_manager.cc and +// customised to use WebCore types rather than WebKit API types. It would be +// nice and would ease future merge pain if the two could be combined. + +using webkit_glue::FormData; +using webkit_glue::FormField; +using WebCore::Element; +using WebCore::FormAssociatedElement; +using WebCore::HTMLCollection; +using WebCore::HTMLElement; +using WebCore::HTMLFormControlElement; +using WebCore::HTMLFormElement; +using WebCore::HTMLInputElement; +using WebCore::HTMLLabelElement; +using WebCore::HTMLOptionElement; +using WebCore::HTMLSelectElement; +using WebCore::Node; +using WebCore::NodeList; + +using namespace WebCore::HTMLNames; + +namespace { + +// The number of fields required by AutoFill. Ideally we could send the forms +// to AutoFill no matter how many fields are in the forms; however, finding the +// label for each field is a costly operation and we can't spare the cycles if +// it's not necessary. +// Note the on ANDROID we reduce this from Chromium's 3 as it allows us to +// autofill simple name/email forms for example. This improves the mobile +// device experience where form filling can be time consuming and frustrating. +const size_t kRequiredAutoFillFields = 2; + +// The maximum length allowed for form data. +const size_t kMaxDataLength = 1024; + +// This is a helper function for the FindChildText() function. +// Returns the aggregated values of the descendants or siblings of |node| that +// are non-empty text nodes. This is a faster alternative to |innerText()| for +// performance critical operations. It does a full depth-first search so +// can be used when the structure is not directly known. The text is +// accumulated after the whitespace has been stropped. Search depth is limited +// with the |depth| parameter. +string16 FindChildTextInner(Node* node, int depth) { + string16 element_text; + if (!node || depth <= 0) + return element_text; + + string16 node_text = WTFStringToString16(node->nodeValue()); + TrimWhitespace(node_text, TRIM_ALL, &node_text); + if (!node_text.empty()) + element_text = node_text; + + string16 child_text = FindChildTextInner(node->firstChild(), depth-1); + if (!child_text.empty()) + element_text = element_text + child_text; + + string16 sibling_text = FindChildTextInner(node->nextSibling(), depth-1); + if (!sibling_text.empty()) + element_text = element_text + sibling_text; + + return element_text; +} + +// Returns the node value of the first decendant of |element| that is a +// non-empty text node. "Non-empty" in this case means non-empty after the +// whitespace has been stripped. Search is limited to withing 10 siblings and/or +// descendants. +string16 FindChildText(Element* element) { + Node* child = element->firstChild(); + + const int kChildSearchDepth = 10; + return FindChildTextInner(child, kChildSearchDepth); +} + +string16 InferLabelFromPrevious(const HTMLFormControlElement& element) { + string16 inferred_label; + Node* previous = element.previousSibling(); + if (!previous) + return string16(); + + if (previous->isTextNode()) { + inferred_label = WTFStringToString16(previous->nodeValue()); + TrimWhitespace(inferred_label, TRIM_ALL, &inferred_label); + } + + // If we didn't find text, check for previous paragraph. + // Eg.

Some Text

+ // Note the lack of whitespace between

and elements. + if (inferred_label.empty() && previous->isElementNode()) { + Element* element = static_cast(previous); + if (element->hasTagName(pTag)) + inferred_label = FindChildText(element); + } + + // If we didn't find paragraph, check for previous paragraph to this. + // Eg.

Some Text

+ // Note the whitespace between

and elements. + if (inferred_label.empty()) { + Node* sibling = previous->previousSibling(); + if (sibling && sibling->isElementNode()) { + Element* element = static_cast(sibling); + if (element->hasTagName(pTag)) + inferred_label = FindChildText(element); + } + } + + // Look for text node prior to tag. + // Eg. Some Text + if (inferred_label.empty()) { + while (inferred_label.empty() && previous) { + if (previous->isTextNode()) { + inferred_label = WTFStringToString16(previous->nodeValue()); + TrimWhitespace(inferred_label, TRIM_ALL, &inferred_label); + } else if (previous->isElementNode()) { + Element* element = static_cast(previous); + if (!element->hasTagName(imgTag)) + break; + } else + break; + previous = previous->previousSibling(); + } + } + + // Look for label node prior to tag. + // Eg. + if (inferred_label.empty()) { + while (inferred_label.empty() && previous) { + if (previous->isTextNode()) { + inferred_label = WTFStringToString16(previous->nodeValue()); + TrimWhitespace(inferred_label, TRIM_ALL, &inferred_label); + } else if (previous->isElementNode()) { + Element* element = static_cast(previous); + if (element->hasTagName(labelTag)) { + inferred_label = FindChildText(element); + } else { + break; + } + } else { + break; + } + + previous = previous->previousSibling(); + } + } + + return inferred_label; +} + +// Helper for |InferLabelForElement()| that infers a label, if possible, from +// surrounding table structure. +// Eg. Some Text +// Eg. Some Text +string16 InferLabelFromTable(const HTMLFormControlElement& element) { + string16 inferred_label; + Node* parent = element.parentNode(); + while (parent && parent->isElementNode() && !static_cast(parent)->hasTagName(tdTag)) + parent = parent->parentNode(); + + // Check all previous siblings, skipping non-element nodes, until we find a + // non-empty text block. + Node* previous = parent; + while(previous) { + if (previous->isElementNode()) { + Element* e = static_cast(previous); + if (e->hasTagName(tdTag)) { + inferred_label = FindChildText(e); + if (!inferred_label.empty()) + break; + } + } + previous = previous->previousSibling(); + } + return inferred_label; +} + +// Helper for |InferLabelForElement()| that infers a label, if possible, from +// a surrounding div table. +// Eg.

Some Text
+string16 InferLabelFromDivTable(const HTMLFormControlElement& element) { + Node* parent = element.parentNode(); + while (parent && parent->isElementNode() && !static_cast(parent)->hasTagName(divTag)) + parent = parent->parentNode(); + + if (!parent || !parent->isElementNode()) + return string16(); + + Element* e = static_cast(parent); + if (!e || !e->hasTagName(divTag)) + return string16(); + + return FindChildText(e); +} + +// Helper for |InferLabelForElement()| that infers a label, if possible, from +// a surrounding definition list. +// Eg.
Some Text
+// Eg.
Some Text
+string16 InferLabelFromDefinitionList(const HTMLFormControlElement& element) { + string16 inferred_label; + Node* parent = element.parentNode(); + while (parent && parent->isElementNode() && !static_cast(parent)->hasTagName(ddTag)) + parent = parent->parentNode(); + + if (parent && parent->isElementNode()) { + Element* element = static_cast(parent); + if (element->hasTagName(ddTag)) { + Node* previous = parent->previousSibling(); + + // Skip by any intervening text nodes. + while (previous && previous->isTextNode()) + previous = previous->previousSibling(); + + if (previous && previous->isElementNode()) { + element = static_cast(previous); + if (element->hasTagName(dtTag)) + inferred_label = FindChildText(element); + } + } + } + return inferred_label; +} + +void GetOptionStringsFromElement(HTMLFormControlElement* element, std::vector* option_strings) { + DCHECK(element); + DCHECK(option_strings); + option_strings->clear(); + if (formControlType(*element) == kSelectOne) { + HTMLSelectElement* select_element = static_cast(element); + + // For select-one elements copy option strings. + WTF::Vector list_items = select_element->listItems(); + option_strings->reserve(list_items.size()); + for (size_t i = 0; i < list_items.size(); ++i) { + if (list_items[i]->hasTagName(optionTag)) + option_strings->push_back(WTFStringToString16(static_cast(list_items[i])->value())); + } + } +} + +} // namespace + +namespace android { + +struct FormManager::FormElement { + RefPtr form_element; + std::vector > control_elements; + std::vector control_values; +}; + +FormManager::FormManager() { +} + +FormManager::~FormManager() { + Reset(); +} + +// static +void FormManager::HTMLFormControlElementToFormField(HTMLFormControlElement* element, ExtractMask extract_mask, FormField* field) { + DCHECK(field); + + // The label is not officially part of a HTMLFormControlElement; however, the + // labels for all form control elements are scraped from the DOM and set in + // WebFormElementToFormData. + field->set_name(nameForAutoFill(*element)); + field->set_form_control_type(formControlType(*element)); + + if (extract_mask & EXTRACT_OPTIONS) { + std::vector option_strings; + GetOptionStringsFromElement(element, &option_strings); + field->set_option_strings(option_strings); + } + + if (formControlType(*element) == kText) { + HTMLInputElement* input_element = static_cast(element); + field->set_max_length(input_element->maxLength()); + field->set_autofilled(input_element->isAutofilled()); + } + + if (!(extract_mask & EXTRACT_VALUE)) + return; + + // TODO: In WebKit, move value() and setValue() to + // WebFormControlElement. + string16 value; + if (formControlType(*element) == kText || + formControlType(*element) == kHidden) { + HTMLInputElement* input_element = static_cast(element); + value = WTFStringToString16(input_element->value()); + } else if (formControlType(*element) == kSelectOne) { + HTMLSelectElement* select_element = static_cast(element); + value = WTFStringToString16(select_element->value()); + + // Convert the |select_element| value to text if requested. + if (extract_mask & EXTRACT_OPTION_TEXT) { + Vector list_items = select_element->listItems(); + for (size_t i = 0; i < list_items.size(); ++i) { + if (list_items[i]->hasTagName(optionTag) && + WTFStringToString16(static_cast(list_items[i])->value()) == value) { + value = WTFStringToString16(static_cast(list_items[i])->text()); + break; + } + } + } + } + + // TODO: This is a temporary stop-gap measure designed to prevent + // a malicious site from DOS'ing the browser with extremely large profile + // data. The correct solution is to parse this data asynchronously. + // See http://crbug.com/49332. + if (value.size() > kMaxDataLength) + value = value.substr(0, kMaxDataLength); + + field->set_value(value); +} + +// static +string16 FormManager::LabelForElement(const HTMLFormControlElement& element) { + // Don't scrape labels for hidden elements. + if (formControlType(element) == kHidden) + return string16(); + + RefPtr labels = element.document()->getElementsByTagName("label"); + for (unsigned i = 0; i < labels->length(); ++i) { + Node* e = labels->item(i); + if (e->hasTagName(labelTag)) { + HTMLLabelElement* label = static_cast(e); + if (label->control() == &element) + return FindChildText(label); + } + } + + // Infer the label from context if not found in label element. + return FormManager::InferLabelForElement(element); +} + +// static +bool FormManager::HTMLFormElementToFormData(HTMLFormElement* element, RequirementsMask requirements, ExtractMask extract_mask, FormData* form) { + DCHECK(form); + + Frame* frame = element->document()->frame(); + if (!frame) + return false; + + if (requirements & REQUIRE_AUTOCOMPLETE && !element->autoComplete()) + return false; + + form->name = WTFStringToString16(element->name()); + form->method = WTFStringToString16(element->method()); + form->origin = GURL(WTFStringToString16(frame->loader()->documentLoader()->url().string())); + form->action = GURL(WTFStringToString16(frame->document()->completeURL(element->action()))); + form->user_submitted = element->wasUserSubmitted(); + + // If the completed URL is not valid, just use the action we get from + // WebKit. + if (!form->action.is_valid()) + form->action = GURL(WTFStringToString16(element->action())); + + // A map from a FormField's name to the FormField itself. + std::map name_map; + + // The extracted FormFields. We use pointers so we can store them in + // |name_map|. + ScopedVector form_fields; + + WTF::Vector control_elements = element->associatedElements(); + + // A vector of bools that indicate whether each field in the form meets the + // requirements and thus will be in the resulting |form|. + std::vector fields_extracted(control_elements.size(), false); + + for (size_t i = 0; i < control_elements.size(); ++i) { + if (!control_elements[i]->isFormControlElement()) + continue; + + HTMLFormControlElement* control_element = static_cast(control_elements[i]); + if (!(control_element->hasTagName(inputTag) || control_element->hasTagName(selectTag))) + continue; + + if (requirements & REQUIRE_AUTOCOMPLETE && + formControlType(*control_element) == kText) { + const WebCore::HTMLInputElement* input_element = static_cast(control_element); + if (!input_element->autoComplete()) + continue; + } + + if (requirements & REQUIRE_ENABLED && !control_element->isEnabledFormControl()) + continue; + + // Create a new FormField, fill it out and map it to the field's name. + FormField* field = new FormField; + HTMLFormControlElementToFormField(control_element, extract_mask, field); + form_fields.push_back(field); + // TODO: A label element is mapped to a form control element's id. + // field->name() will contain the id only if the name does not exist. Add + // an id() method to HTMLFormControlElement and use that here. + name_map[field->name()] = field; + fields_extracted[i] = true; + } + + // Don't extract field labels if we have no fields. + if (form_fields.empty()) + return false; + + // Loop through the label elements inside the form element. For each label + // element, get the corresponding form control element, use the form control + // element's name as a key into the map to find the + // previously created FormField and set the FormField's label to the + // label.firstChild().nodeValue() of the label element. + RefPtr labels = element->getElementsByTagName("label"); + for (unsigned i = 0; i < labels->length(); ++i) { + HTMLLabelElement* label = static_cast(labels->item(i)); + HTMLFormControlElement* field_element = label->control(); + if (!field_element || field_element->type() == "hidden") + continue; + + std::map::iterator iter = + name_map.find(nameForAutoFill(*field_element)); + if (iter != name_map.end()) + iter->second->set_label(FindChildText(label)); + } + + // Loop through the form control elements, extracting the label text from the + // DOM. We use the |fields_extracted| vector to make sure we assign the + // extracted label to the correct field, as it's possible |form_fields| will + // not contain all of the elements in |control_elements|. + for (size_t i = 0, field_idx = 0; i < control_elements.size() && field_idx < form_fields.size(); ++i) { + // This field didn't meet the requirements, so don't try to find a label for + // it. + if (!fields_extracted[i]) + continue; + + if (!control_elements[i]->isFormControlElement()) + continue; + + const HTMLFormControlElement* control_element = static_cast(control_elements[i]); + if (form_fields[field_idx]->label().empty()) + form_fields[field_idx]->set_label(FormManager::InferLabelForElement(*control_element)); + + ++field_idx; + + } + // Copy the created FormFields into the resulting FormData object. + for (ScopedVector::const_iterator iter = form_fields.begin(); iter != form_fields.end(); ++iter) + form->fields.push_back(**iter); + + return true; +} + +void FormManager::ExtractForms(Frame* frame) { + + ResetFrame(frame); + + WTF::PassRefPtr web_forms = frame->document()->forms(); + + for (size_t i = 0; i < web_forms->length(); ++i) { + FormElement* form_element = new FormElement; + HTMLFormElement* html_form_element = static_cast(web_forms->item(i)); + form_element->form_element = html_form_element; + + WTF::Vector control_elements = html_form_element->associatedElements(); + for (size_t j = 0; j < control_elements.size(); ++j) { + if (!control_elements[j]->isFormControlElement()) + continue; + + HTMLFormControlElement* element = static_cast(control_elements[j]); + form_element->control_elements.push_back(element); + + // Save original values of "select-one" inputs so we can restore them + // when |ClearFormWithNode()| is invoked. + if (formControlType(*element) == kSelectOne) { + HTMLSelectElement* select_element = static_cast(element); + string16 value = WTFStringToString16(select_element->value()); + form_element->control_values.push_back(value); + } else + form_element->control_values.push_back(string16()); + } + + form_elements_.push_back(form_element); + } +} + +void FormManager::GetFormsInFrame(const Frame* frame, RequirementsMask requirements, std::vector* forms) { + DCHECK(frame); + DCHECK(forms); + + for (FormElementList::const_iterator form_iter = form_elements_.begin(); form_iter != form_elements_.end(); ++form_iter) { + FormElement* form_element = *form_iter; + + if (form_element->form_element->document()->frame() != frame) + continue; + + // We need at least |kRequiredAutoFillFields| fields before appending this + // form to |forms|. + if (form_element->control_elements.size() < kRequiredAutoFillFields) + continue; + + if (requirements & REQUIRE_AUTOCOMPLETE && !form_element->form_element->autoComplete()) + continue; + + FormData form; + HTMLFormElementToFormData(form_element->form_element.get(), requirements, EXTRACT_VALUE, &form); + if (form.fields.size() >= kRequiredAutoFillFields) + forms->push_back(form); + } +} + +bool FormManager::FindFormWithFormControlElement(HTMLFormControlElement* element, RequirementsMask requirements, FormData* form) { + DCHECK(form); + + const Frame* frame = element->document()->frame(); + if (!frame) + return false; + + for (FormElementList::const_iterator iter = form_elements_.begin(); iter != form_elements_.end(); ++iter) { + const FormElement* form_element = *iter; + + if (form_element->form_element->document()->frame() != frame) + continue; + + for (std::vector >::const_iterator iter = form_element->control_elements.begin(); iter != form_element->control_elements.end(); ++iter) { + HTMLFormControlElement* candidate = iter->get(); + if (nameForAutoFill(*candidate) == nameForAutoFill(*element)) { + ExtractMask extract_mask = static_cast(EXTRACT_VALUE | EXTRACT_OPTIONS); + return HTMLFormElementToFormData(form_element->form_element.get(), requirements, extract_mask, form); + } + } + } + return false; +} + +bool FormManager::FillForm(const FormData& form, Node* node) { + FormElement* form_element = NULL; + if (!FindCachedFormElement(form, &form_element)) + return false; + + RequirementsMask requirements = static_cast(REQUIRE_AUTOCOMPLETE | REQUIRE_ENABLED | REQUIRE_EMPTY); + ForEachMatchingFormField(form_element, node, requirements, form, NewCallback(this, &FormManager::FillFormField)); + + return true; +} + +bool FormManager::PreviewForm(const FormData& form, Node* node) { + FormElement* form_element = NULL; + if (!FindCachedFormElement(form, &form_element)) + return false; + + RequirementsMask requirements = static_cast(REQUIRE_AUTOCOMPLETE | REQUIRE_ENABLED | REQUIRE_EMPTY); + ForEachMatchingFormField(form_element, node, requirements, form, NewCallback(this, &FormManager::PreviewFormField)); + + return true; +} + +bool FormManager::ClearFormWithNode(Node* node) { + FormElement* form_element = NULL; + if (!FindCachedFormElementWithNode(node, &form_element)) + return false; + + for (size_t i = 0; i < form_element->control_elements.size(); ++i) { + HTMLFormControlElement* element = form_element->control_elements[i].get(); + if (formControlType(*element) == kText) { + HTMLInputElement* input_element = static_cast(element); + + // We don't modify the value of disabled fields. + if (!input_element->isEnabledFormControl()) + continue; + + input_element->setValue(""); + input_element->setAutofilled(false); + // Clearing the value in the focused node (above) can cause selection + // to be lost. We force selection range to restore the text cursor. + if (node == input_element) { + int length = input_element->value().length(); + input_element->setSelectionRange(length, length); + } + } else if (formControlType(*element) == kSelectOne) { + HTMLSelectElement* select_element = static_cast(element); + select_element->setValue(form_element->control_values[i].c_str()); + } + } + + return true; +} + +bool FormManager::ClearPreviewedFormWithNode(Node* node, bool was_autofilled) { + FormElement* form_element = NULL; + if (!FindCachedFormElementWithNode(node, &form_element)) + return false; + + for (size_t i = 0; i < form_element->control_elements.size(); ++i) { + HTMLFormControlElement* element = form_element->control_elements[i].get(); + + // Only input elements can be previewed. + if (formControlType(*element) != kText) + continue; + + // If the input element has not been auto-filled, FormManager has not + // previewed this field, so we have nothing to reset. + HTMLInputElement* input_element = static_cast(element); + if (!input_element->isAutofilled()) + continue; + + // There might be unrelated elements in this form which have already been + // auto-filled. For example, the user might have already filled the address + // part of a form and now be dealing with the credit card section. We only + // want to reset the auto-filled status for fields that were previewed. + if (input_element->suggestedValue().isEmpty()) + continue; + + // Clear the suggested value. For the initiating node, also restore the + // original value. + input_element->setSuggestedValue(""); + bool is_initiating_node = (node == input_element); + if (is_initiating_node) { + // Call |setValue()| to force the renderer to update the field's displayed + // value. + input_element->setValue(input_element->value()); + input_element->setAutofilled(was_autofilled); + } else { + input_element->setAutofilled(false); + } + + // Clearing the suggested value in the focused node (above) can cause + // selection to be lost. We force selection range to restore the text + // cursor. + if (is_initiating_node) { + int length = input_element->value().length(); + input_element->setSelectionRange(length, length); + } + } + + return true; +} + +void FormManager::Reset() { + STLDeleteElements(&form_elements_); +} + +void FormManager::ResetFrame(const Frame* frame) { + FormElementList::iterator iter = form_elements_.begin(); + while (iter != form_elements_.end()) { + if ((*iter)->form_element->document()->frame() == frame) { + delete *iter; + iter = form_elements_.erase(iter); + } else + ++iter; + } +} + +bool FormManager::FormWithNodeIsAutoFilled(Node* node) { + FormElement* form_element = NULL; + if (!FindCachedFormElementWithNode(node, &form_element)) + return false; + + for (size_t i = 0; i < form_element->control_elements.size(); ++i) { + HTMLFormControlElement* element = form_element->control_elements[i].get(); + if (formControlType(*element) != kText) + continue; + + HTMLInputElement* input_element = static_cast(element); + if (input_element->isAutofilled()) + return true; + } + + return false; +} + +// static +string16 FormManager::InferLabelForElement(const HTMLFormControlElement& element) { + // Don't scrape labels for hidden elements. + if (formControlType(element) == kHidden) + return string16(); + + string16 inferred_label = InferLabelFromPrevious(element); + + // If we didn't find a label, check for table cell case. + if (inferred_label.empty()) + inferred_label = InferLabelFromTable(element); + + // If we didn't find a label, check for div table case. + if (inferred_label.empty()) + inferred_label = InferLabelFromDivTable(element); + + // If we didn't find a label, check for definition list case. + if (inferred_label.empty()) + inferred_label = InferLabelFromDefinitionList(element); + + return inferred_label; +} + +bool FormManager::FindCachedFormElementWithNode(Node* node, + FormElement** form_element) { + for (FormElementList::const_iterator form_iter = form_elements_.begin(); form_iter != form_elements_.end(); ++form_iter) { + for (std::vector >::const_iterator iter = (*form_iter)->control_elements.begin(); iter != (*form_iter)->control_elements.end(); ++iter) { + if (iter->get() == node) { + *form_element = *form_iter; + return true; + } + } + } + + return false; +} + +bool FormManager::FindCachedFormElement(const FormData& form, FormElement** form_element) { + for (FormElementList::iterator form_iter = form_elements_.begin(); form_iter != form_elements_.end(); ++form_iter) { + // TODO: matching on form name here which is not guaranteed to + // be unique for the page, nor is it guaranteed to be non-empty. Need to + // find a way to uniquely identify the form cross-process. For now we'll + // check form name and form action for identity. + // http://crbug.com/37990 test file sample8.html. + // Also note that WebString() == WebString(string16()) does not seem to + // evaluate to |true| for some reason TBD, so forcing to string16. + string16 element_name(WTFStringToString16((*form_iter)->form_element->name())); + GURL action(WTFStringToString16((*form_iter)->form_element->document()->completeURL((*form_iter)->form_element->action()).string())); + if (element_name == form.name && action == form.action) { + *form_element = *form_iter; + return true; + } + } + + return false; +} + + +void FormManager::ForEachMatchingFormField(FormElement* form, Node* node, RequirementsMask requirements, const FormData& data, Callback* callback) { + // It's possible that the site has injected fields into the form after the + // page has loaded, so we can't assert that the size of the cached control + // elements is equal to the size of the fields in |form|. Fortunately, the + // one case in the wild where this happens, paypal.com signup form, the fields + // are appended to the end of the form and are not visible. + for (size_t i = 0, j = 0; i < form->control_elements.size() && j < data.fields.size(); ++i) { + HTMLFormControlElement* element = form->control_elements[i].get(); + string16 element_name = nameForAutoFill(*element); + + if (element_name.empty()) + continue; + + // Search forward in the |form| for a corresponding field. + size_t k = j; + while (k < data.fields.size() && element_name != data.fields[k].name()) + k++; + + if (k >= data.fields.size()) + continue; + + DCHECK_EQ(data.fields[k].name(), element_name); + + bool is_initiating_node = false; + + // More than likely |requirements| will contain REQUIRE_AUTOCOMPLETE and/or + // REQUIRE_EMPTY, which both require text form control elements, so special- + // case this type of element. + if (formControlType(*element) == kText) { + HTMLInputElement* input_element = static_cast(element); + + // TODO: WebKit currently doesn't handle the autocomplete + // attribute for select control elements, but it probably should. + if (requirements & REQUIRE_AUTOCOMPLETE && !input_element->autoComplete()) + continue; + + is_initiating_node = (input_element == node); + // Don't require the node that initiated the auto-fill process to be + // empty. The user is typing in this field and we should complete the + // value when the user selects a value to fill out. + if (requirements & REQUIRE_EMPTY && !is_initiating_node && !input_element->value().isEmpty()) + continue; + } + + if (requirements & REQUIRE_ENABLED && !element->isEnabledFormControl()) + continue; + + callback->Run(element, &data.fields[k], is_initiating_node); + + // We found a matching form field so move on to the next. + ++j; + } + + delete callback; +} + +void FormManager::FillFormField(HTMLFormControlElement* field, const FormField* data, bool is_initiating_node) { + // Nothing to fill. + if (data->value().empty()) + return; + + if (formControlType(*field) == kText) { + HTMLInputElement* input_element = static_cast(field); + + // If the maxlength attribute contains a negative value, maxLength() + // returns the default maxlength value. + input_element->setValue(data->value().substr(0, input_element->maxLength()).c_str()); + input_element->setAutofilled(true); + if (is_initiating_node) { + int length = input_element->value().length(); + input_element->setSelectionRange(length, length); + } + } else if (formControlType(*field) == kSelectOne) { + HTMLSelectElement* select_element = static_cast(field); + select_element->setValue(data->value().c_str()); + } +} + +void FormManager::PreviewFormField(HTMLFormControlElement* field, const FormField* data, bool is_initiating_node) { + // Nothing to preview. + if (data->value().empty()) + return; + + // Only preview input fields. + if (formControlType(*field) != kText) + return; + + HTMLInputElement* input_element = static_cast(field); + + // If the maxlength attribute contains a negative value, maxLength() + // returns the default maxlength value. + input_element->setSuggestedValue(data->value().substr(0, input_element->maxLength()).c_str()); + input_element->setAutofilled(true); + if (is_initiating_node) + input_element->setSelectionRange(0, input_element->suggestedValue().length()); +} + +} diff --git a/Source/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.h b/Source/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.h new file mode 100644 index 0000000..e844981 --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.h @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2010 The Chromium Authors. All rights reserved. + * 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 FormManagerAndroid_h +#define FormManagerAndroid_h + +#include "ChromiumIncludes.h" + +#include +#include + +// TODO: This file is taken from chromium/chrome/renderer/form_manager.h and +// customised to use WebCore types rather than WebKit API types. It would be +// nice and would ease future merge pain if the two could be combined. + +namespace webkit_glue { +struct FormData; +class FormField; +} // namespace webkit_glue + +namespace WebCore { +class Frame; +class HTMLFormControlElement; +class HTMLFormElement; +class Node; +} + +using WebCore::Frame; +using WebCore::HTMLFormControlElement; +using WebCore::HTMLFormElement; +using WebCore::Node; + +namespace android { + +// Manages the forms in a Document. +class FormManager { +public: + // A bit field mask for form requirements. + enum RequirementsMask { + REQUIRE_NONE = 0, // No requirements. + REQUIRE_AUTOCOMPLETE = 1 << 0, // Require that autocomplete != off. + REQUIRE_ENABLED = 1 << 1, // Require that disabled attribute is off. + REQUIRE_EMPTY = 1 << 2, // Require that the fields are empty. + }; + + // A bit field mask to extract data from HTMLFormControlElement. + enum ExtractMask { + EXTRACT_NONE = 0, + EXTRACT_VALUE = 1 << 0, // Extract value from HTMLFormControlElement. + EXTRACT_OPTION_TEXT = 1 << 1, // Extract option text from HTMLFormSelectElement. Only valid when |EXTRACT_VALUE| is set. This is used for form submission where humand readable value is captured. + EXTRACT_OPTIONS = 1 << 2, // Extract options from HTMLFormControlElement. + }; + + FormManager(); + virtual ~FormManager(); + + // Fills out a FormField object from a given HTMLFormControlElement. + // |extract_mask|: See the enum ExtractMask above for details. + static void HTMLFormControlElementToFormField(HTMLFormControlElement* element, ExtractMask extract_mask, webkit_glue::FormField* field); + + // Returns the corresponding label for |element|. WARNING: This method can + // potentially be very slow. Do not use during any code paths where the page + // is loading. + static string16 LabelForElement(const HTMLFormControlElement& element); + + // Fills out a FormData object from a given WebFormElement. If |get_values| + // is true, the fields in |form| will have the values filled out. Returns + // true if |form| is filled out; it's possible that |element| won't meet the + // requirements in |requirements|. This also returns false if there are no + // fields in |form|. + // TODO: Remove the user of this in RenderView and move this to + // private. + static bool HTMLFormElementToFormData(HTMLFormElement* element, RequirementsMask requirements, ExtractMask extract_mask, webkit_glue::FormData* form); + + // Scans the DOM in |frame| extracting and storing forms. + void ExtractForms(Frame* frame); + + // Returns a vector of forms in |frame| that match |requirements|. + void GetFormsInFrame(const Frame* frame, RequirementsMask requirements, std::vector* forms); + + // Finds the form that contains |element| and returns it in |form|. Returns + // false if the form is not found. + bool FindFormWithFormControlElement(HTMLFormControlElement* element, RequirementsMask requirements, webkit_glue::FormData* form); + + // Fills the form represented by |form|. |form| should have the name set to + // the name of the form to fill out, and the number of elements and values + // must match the number of stored elements in the form. |node| is the form + // control element that initiated the auto-fill process. + // TODO: Is matching on name alone good enough? It's possible to + // store multiple forms with the same names from different frames. + bool FillForm(const webkit_glue::FormData& form, Node* node); + + // Previews the form represented by |form|. |node| is the form control element + // that initiated the preview process. Same conditions as FillForm. + bool PreviewForm(const webkit_glue::FormData& form, Node* node); + + // Clears the values of all input elements in the form that contains |node|. + // Returns false if the form is not found. + bool ClearFormWithNode(Node* node); + + // Clears the placeholder values and the auto-filled background for any fields + // in the form containing |node| that have been previewed. Resets the + // autofilled state of |node| to |was_autofilled|. Returns false if the form + // is not found. + bool ClearPreviewedFormWithNode(Node* node, bool was_autofilled); + + // Resets the stored set of forms. + void Reset(); + + // Resets the forms for the specified |frame|. + void ResetFrame(const Frame* frame); + + // Returns true if |form| has any auto-filled fields. + bool FormWithNodeIsAutoFilled(Node* node); + +private: + // Stores the HTMLFormElement and the form control elements for a form. + // Original form values are stored so when we clear a form we can reset + // "select-one" values to their original state. + struct FormElement; + + // Type for cache of FormElement objects. + typedef std::vector FormElementList; + + // The callback type used by ForEachMatchingFormField(). + typedef Callback3::Type Callback; + + // Infers corresponding label for |element| from surrounding context in the + // DOM. Contents of preceeding

tag or preceeding text element found in + // the form. + static string16 InferLabelForElement(const HTMLFormControlElement& element); + + // Finds the cached FormElement that contains |node|. + bool FindCachedFormElementWithNode(Node* node, FormElement** form_element); + + // Uses the data in |form| to find the cached FormElement. + bool FindCachedFormElement(const webkit_glue::FormData& form, FormElement** form_element); + + // For each field in |data| that matches the corresponding field in |form| + // and meets the |requirements|, |callback| is called with the actual + // WebFormControlElement and the FormField data from |form|. The field that + // matches |node| is not required to be empty if |requirements| includes + // REQUIRE_EMPTY. This method owns |callback|. + void ForEachMatchingFormField(FormElement* form, Node* node, RequirementsMask requirements, const webkit_glue::FormData& data, Callback* callback); + + // A ForEachMatchingFormField() callback that sets |field|'s value using the + // value in |data|. This method also sets the autofill attribute, causing the + // background to be yellow. + void FillFormField(HTMLFormControlElement* field, const webkit_glue::FormField* data, bool is_initiating_node); + + // A ForEachMatchingFormField() callback that sets |field|'s placeholder value + // using the value in |data|, causing the test to be greyed-out. This method + // also sets the autofill attribute, causing the background to be yellow. + void PreviewFormField(HTMLFormControlElement* field, const webkit_glue::FormField* data, bool is_initiaiting_node); + + // The cached FormElement objects. + FormElementList form_elements_; + + DISALLOW_COPY_AND_ASSIGN(FormManager); +}; + +} // namespace android + +#endif // FormManagerAndroid_h diff --git a/Source/WebKit/android/WebCoreSupport/autofill/MainThreadProxy.cpp b/Source/WebKit/android/WebCoreSupport/autofill/MainThreadProxy.cpp new file mode 100644 index 0000000..598b9c4 --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/autofill/MainThreadProxy.cpp @@ -0,0 +1,35 @@ +/* + * 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 "MainThreadProxy.h" + +#include + +void MainThreadProxy::CallOnMainThread(CallOnMainThreadFunction f, void* c) +{ + callOnMainThread(f, c); +} diff --git a/Source/WebKit/android/WebCoreSupport/autofill/MainThreadProxy.h b/Source/WebKit/android/WebCoreSupport/autofill/MainThreadProxy.h new file mode 100644 index 0000000..d9310bb --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/autofill/MainThreadProxy.h @@ -0,0 +1,37 @@ +/* + * 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 MAIN_THREAD_PROXY_H +#define MAIN_THREAD_PROXY_H + +typedef void CallOnMainThreadFunction(void*); + +class MainThreadProxy +{ +public: + static void CallOnMainThread(CallOnMainThreadFunction, void*); +}; + +#endif diff --git a/Source/WebKit/android/WebCoreSupport/autofill/StringUtils.h b/Source/WebKit/android/WebCoreSupport/autofill/StringUtils.h new file mode 100644 index 0000000..aa408a5 --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/autofill/StringUtils.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2010 The Android Open Source Project. 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. + * + * 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 AutoFillStringUtils_h_ +#define AutoFillStringUtils_h_ + +#include "ChromiumIncludes.h" +#include "HTMLFormControlElement.h" +#include + +using WebCore::HTMLFormControlElement; + +const string16 kText = ASCIIToUTF16("text"); +const string16 kHidden = ASCIIToUTF16("hidden"); +const string16 kSelectOne = ASCIIToUTF16("select-one"); + +inline string16 WTFStringToString16(const WTF::String& wtfString) +{ + WTF::String str = wtfString; + + if (str.charactersWithNullTermination()) + return string16(str.charactersWithNullTermination()); + else + return string16(); +} + +inline string16 nameForAutoFill(const HTMLFormControlElement& element) +{ + // Taken from WebKit/chromium/src/WebFormControlElement.cpp, ported + // to use WebCore types for accessing element properties. + String name = element.name(); + String trimmedName = name.stripWhiteSpace(); + if (!trimmedName.isEmpty()) + return WTFStringToString16(trimmedName); + name = element.getIdAttribute(); + trimmedName = name.stripWhiteSpace(); + if (!trimmedName.isEmpty()) + return WTFStringToString16(trimmedName); + return string16(); +} + +inline string16 formControlType(const HTMLFormControlElement& element) +{ + // Taken from WebKit/chromium/src/WebFormControlElement.cpp, ported + // to use WebCore types for accessing element properties. + return WTFStringToString16(element.type()); +} + +#endif + diff --git a/Source/WebKit/android/WebCoreSupport/autofill/WebAutoFill.cpp b/Source/WebKit/android/WebCoreSupport/autofill/WebAutoFill.cpp new file mode 100644 index 0000000..a80636c --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/autofill/WebAutoFill.cpp @@ -0,0 +1,296 @@ +/* + * 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 "WebAutoFill.h" + +#if ENABLE(WEB_AUTOFILL) + +#include "AutoFillHostAndroid.h" +#include "Frame.h" +#include "FormData.h" +#include "FormManagerAndroid.h" +#include "FrameLoader.h" +#include "HTMLFormControlElement.h" +#include "MainThreadProxy.h" +#include "Node.h" +#include "Page.h" +#include "Settings.h" +#include "WebFrame.h" +#include "WebRequestContext.h" +#include "WebUrlLoaderClient.h" +#include "WebViewCore.h" + +#define NO_PROFILE_SET 0 +#define FORM_NOT_AUTOFILLABLE -1 + +namespace android +{ +WebAutoFill::WebAutoFill() + : mQueryId(1) + , mWebViewCore(0) + , mLastSearchDomVersion(0) + , mParsingForms(false) +{ + mTabContents = new TabContents(); + setEmptyProfile(); +} + +void WebAutoFill::init() +{ + if (mAutoFillManager) + return; + + mFormManager = new FormManager(); + // We use the WebView's WebRequestContext, which may be a private browsing context. + ASSERT(mWebViewCore); + mAutoFillManager = new AutoFillManager(mTabContents.get()); + mAutoFillHost = new AutoFillHostAndroid(this); + mTabContents->SetProfileRequestContext(new AndroidURLRequestContextGetter(mWebViewCore->webRequestContext(), WebUrlLoaderClient::ioThread())); + mTabContents->SetAutoFillHost(mAutoFillHost.get()); +} + +WebAutoFill::~WebAutoFill() +{ + cleanUpQueryMap(); + mUniqueIdMap.clear(); +} + +void WebAutoFill::cleanUpQueryMap() +{ + for (AutoFillQueryFormDataMap::iterator it = mQueryMap.begin(); it != mQueryMap.end(); it++) + delete it->second; + mQueryMap.clear(); +} + +void WebAutoFill::searchDocument(WebCore::Frame* frame) +{ + if (!enabled()) + return; + + MutexLocker lock(mFormsSeenMutex); + + init(); + + cleanUpQueryMap(); + mUniqueIdMap.clear(); + mForms.clear(); + mQueryId = 1; + + ASSERT(mFormManager); + ASSERT(mAutoFillManager); + + mAutoFillManager->Reset(); + mFormManager->Reset(); + + mFormManager->ExtractForms(frame); + mFormManager->GetFormsInFrame(frame, FormManager::REQUIRE_AUTOCOMPLETE, &mForms); + + // Needs to be done on a Chrome thread as it will make a URL request to the AutoFill server. + // TODO: Use our own Autofill thread instead of the IO thread. + // TODO: For now, block here. Would like to make this properly async. + base::Thread* thread = WebUrlLoaderClient::ioThread(); + mParsingForms = true; + thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this, &WebAutoFill::formsSeenImpl)); + while (mParsingForms) + mFormsSeenCondition.wait(mFormsSeenMutex); +} + +// Called on the Chromium IO thread. +void WebAutoFill::formsSeenImpl() +{ + MutexLocker lock(mFormsSeenMutex); + mAutoFillManager->FormsSeen(mForms); + mParsingForms = false; + mFormsSeenCondition.signal(); +} + +void WebAutoFill::formFieldFocused(WebCore::HTMLFormControlElement* formFieldElement) +{ + ASSERT(formFieldElement); + + Document* doc = formFieldElement->document(); + Frame* frame = doc->frame(); + + // FIXME: AutoFill only works in main frame for now. Should consider + // child frames. + if (frame != frame->page()->mainFrame()) + return; + + unsigned domVersion = doc->domTreeVersion(); + ASSERT(domVersion > 0); + + if (mLastSearchDomVersion != domVersion) { + // Need to extract forms as DOM version has changed since the last time + // we searched. + searchDocument(formFieldElement->document()->frame()); + mLastSearchDomVersion = domVersion; + } + + if (!enabled()) { + // In case that we've just been disabled and the last time we got autofill + // suggestions and told Java about them, clear that bit Java side now + // we're disabled. + mWebViewCore->setWebTextViewAutoFillable(FORM_NOT_AUTOFILLABLE, string16()); + return; + } + + // Get the FormField from the Node. + webkit_glue::FormField* formField = new webkit_glue::FormField; + FormManager::HTMLFormControlElementToFormField(formFieldElement, FormManager::EXTRACT_NONE, formField); + formField->set_label(FormManager::LabelForElement(*formFieldElement)); + + webkit_glue::FormData* form = new webkit_glue::FormData; + mFormManager->FindFormWithFormControlElement(formFieldElement, FormManager::REQUIRE_AUTOCOMPLETE, form); + mQueryMap[mQueryId] = new FormDataAndField(form, formField); + + bool suggestions = mAutoFillManager->GetAutoFillSuggestions(*form, *formField); + + mQueryId++; + if (!suggestions) { + ASSERT(mWebViewCore); + // Tell Java no autofill suggestions for this form. + mWebViewCore->setWebTextViewAutoFillable(FORM_NOT_AUTOFILLABLE, string16()); + return; + } +} + +void WebAutoFill::querySuccessful(const string16& value, const string16& label, int uniqueId) +{ + if (!enabled()) + return; + + // Store the unique ID for the query and inform java that autofill suggestions for this form are available. + // Pass java the queryId so that it can pass it back if the user decides to use autofill. + mUniqueIdMap[mQueryId] = uniqueId; + + ASSERT(mWebViewCore); + mWebViewCore->setWebTextViewAutoFillable(mQueryId, mAutoFillProfile->Label()); +} + +void WebAutoFill::fillFormFields(int queryId) +{ + if (!enabled()) + return; + + webkit_glue::FormData* form = mQueryMap[queryId]->form(); + webkit_glue::FormField* field = mQueryMap[queryId]->field(); + ASSERT(form); + ASSERT(field); + + AutoFillQueryToUniqueIdMap::iterator iter = mUniqueIdMap.find(queryId); + if (iter == mUniqueIdMap.end()) { + // The user has most likely tried to AutoFill the form again without + // refocussing the form field. The UI should protect against this + // but stop here to be certain. + return; + } + mAutoFillManager->FillAutoFillFormData(queryId, *form, *field, iter->second); + mUniqueIdMap.erase(iter); +} + +void WebAutoFill::fillFormInPage(int queryId, const webkit_glue::FormData& form) +{ + if (!enabled()) + return; + + // FIXME: Pass a pointer to the Node that triggered the AutoFill flow here instead of 0. + // The consquence of passing 0 is that we should always fail the test in FormManader::ForEachMathcingFormField():169 + // that says "only overwrite an elements current value if the user triggered autofill through that element" + // for elements that have a value already. But by a quirk of Android text views we are OK. We should still + // fix this though. + mFormManager->FillForm(form, 0); +} + +bool WebAutoFill::enabled() const +{ + Page* page = mWebViewCore->mainFrame()->page(); + return page ? page->settings()->autoFillEnabled() : false; +} + +void WebAutoFill::setProfile(const string16& fullName, const string16& emailAddress, const string16& companyName, + const string16& addressLine1, const string16& addressLine2, const string16& city, + const string16& state, const string16& zipCode, const string16& country, const string16& phoneNumber) +{ + if (!mAutoFillProfile) + mAutoFillProfile.set(new AutoFillProfile()); + + // Update the profile. + // Constants for AutoFill field types are found in external/chromium/chrome/browser/autofill/field_types.h. + mAutoFillProfile->SetInfo(AutoFillType(NAME_FULL), fullName); + mAutoFillProfile->SetInfo(AutoFillType(EMAIL_ADDRESS), emailAddress); + mAutoFillProfile->SetInfo(AutoFillType(COMPANY_NAME), companyName); + mAutoFillProfile->SetInfo(AutoFillType(ADDRESS_HOME_LINE1), addressLine1); + mAutoFillProfile->SetInfo(AutoFillType(ADDRESS_HOME_LINE2), addressLine2); + mAutoFillProfile->SetInfo(AutoFillType(ADDRESS_HOME_CITY), city); + mAutoFillProfile->SetInfo(AutoFillType(ADDRESS_HOME_STATE), state); + mAutoFillProfile->SetInfo(AutoFillType(ADDRESS_HOME_ZIP), zipCode); + mAutoFillProfile->SetInfo(AutoFillType(ADDRESS_HOME_COUNTRY), country); + mAutoFillProfile->SetInfo(AutoFillType(PHONE_HOME_WHOLE_NUMBER), phoneNumber); + + std::vector profiles; + profiles.push_back(*mAutoFillProfile); + updateProfileLabel(); + mTabContents->profile()->GetPersonalDataManager()->SetProfiles(&profiles); +} + +bool WebAutoFill::updateProfileLabel() +{ + std::vector profiles; + profiles.push_back(mAutoFillProfile.get()); + return AutoFillProfile::AdjustInferredLabels(&profiles); +} + +void WebAutoFill::clearProfiles() +{ + if (!mAutoFillProfile) + return; + // For now Chromium only ever knows about one profile, so we can just + // remove it. If we support multiple profiles in the future + // we need to remove them all here. + std::string profileGuid = mAutoFillProfile->guid(); + mTabContents->profile()->GetPersonalDataManager()->RemoveProfile(profileGuid); + setEmptyProfile(); +} + +void WebAutoFill::setEmptyProfile() +{ + // Set an empty profile. This will ensure that when autofill is enabled, + // we will still search the document for autofillable forms and inform + // java of their presence so we can invite the user to set up + // their own profile. + + // Chromium code will strip the values sent into the profile so we need them to be + // at least one non-whitespace character long. We need to set all fields of the + // profile to a non-empty string so that any field type can trigger the autofill + // suggestion. AutoFill will not detect form fields if the profile value for that + // field is an empty string. + static const string16 empty = string16(ASCIIToUTF16("a")); + setProfile(empty, empty, empty, empty, empty, empty, empty, empty, empty, empty); +} + +} + +#endif diff --git a/Source/WebKit/android/WebCoreSupport/autofill/WebAutoFill.h b/Source/WebKit/android/WebCoreSupport/autofill/WebAutoFill.h new file mode 100644 index 0000000..97e478e --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/autofill/WebAutoFill.h @@ -0,0 +1,127 @@ +/* + * 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 WebAutoFill_h +#define WebAutoFill_h + +#if ENABLE(WEB_AUTOFILL) + +#include "ChromiumIncludes.h" + +#include +#include +#include +#include +#include + +class AutoFillManager; +class AutoFillProfile; +class AutoFillHost; + +namespace WebCore { +class Frame; +class HTMLFormControlElement; +} + +namespace android +{ +class FormManager; +class WebViewCore; + +class FormDataAndField { +public: + FormDataAndField(webkit_glue::FormData* form, webkit_glue::FormField* field) + : mForm(form) + , mField(field) + { + } + + webkit_glue::FormData* form() { return mForm.get(); } + webkit_glue::FormField* field() { return mField.get(); } + +private: + OwnPtr mForm; + OwnPtr mField; +}; + +class WebAutoFill : public Noncopyable +{ +public: + WebAutoFill(); + virtual ~WebAutoFill(); + void formFieldFocused(WebCore::HTMLFormControlElement*); + void fillFormFields(int queryId); + void querySuccessful(const string16& value, const string16& label, int uniqueId); + void fillFormInPage(int queryId, const webkit_glue::FormData& form); + void setWebViewCore(WebViewCore* webViewCore) { mWebViewCore = webViewCore; } + bool enabled() const; + + void setProfile(const string16& fullName, const string16& emailAddress, const string16& companyName, + const string16& addressLine1, const string16& addressLine2, const string16& city, + const string16& state, const string16& zipCode, const string16& country, const string16& phoneNumber); + void clearProfiles(); + + bool updateProfileLabel(); + + void reset() { mLastSearchDomVersion = 0; } + +private: + void init(); + void searchDocument(WebCore::Frame*); + void setEmptyProfile(); + void formsSeenImpl(); + void cleanUpQueryMap(); + + OwnPtr mFormManager; + OwnPtr mAutoFillManager; + OwnPtr mAutoFillHost; + OwnPtr mTabContents; + OwnPtr mAutoFillProfile; + + typedef std::vector > FormList; + FormList mForms; + + typedef std::map AutoFillQueryFormDataMap; + AutoFillQueryFormDataMap mQueryMap; + + typedef std::map AutoFillQueryToUniqueIdMap; + AutoFillQueryToUniqueIdMap mUniqueIdMap; + int mQueryId; + + WebViewCore* mWebViewCore; + + unsigned mLastSearchDomVersion; + + WTF::Mutex mFormsSeenMutex; // Guards mFormsSeenCondition and mParsingForms. + WTF::ThreadCondition mFormsSeenCondition; + bool volatile mParsingForms; +}; + +} + +DISABLE_RUNNABLE_METHOD_REFCOUNT(android::WebAutoFill); + +#endif // ENABLE(WEB_AUTOFILL) +#endif // WebAutoFill_h diff --git a/Source/WebKit/android/benchmark/Android.mk b/Source/WebKit/android/benchmark/Android.mk new file mode 100644 index 0000000..5b189e1 --- /dev/null +++ b/Source/WebKit/android/benchmark/Android.mk @@ -0,0 +1,41 @@ +## +## +## 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 new file mode 100644 index 0000000..deffac2 --- /dev/null +++ b/Source/WebKit/android/benchmark/Intercept.cpp @@ -0,0 +1,190 @@ +/* + * 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 +#include +#include +#include + +PassRefPtr MyResourceLoader::create( + ResourceHandle* handle, String url) +{ + return adoptRef( + 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 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 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 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 MyWebFrame::startLoadingResource( + ResourceHandle* handle, const ResourceRequest& req, bool ignore, + bool ignore2) +{ + RefPtr 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*) +{ + LOGD("Handling requests..."); + Vector > reqs; + reqs.swap(m_requests); + Vector >::iterator i = reqs.begin(); + Vector >::iterator end = reqs.end(); + for (; i != end; i++) + static_cast((*i).get())->handleRequest(); + + LOGD("...done"); +} diff --git a/Source/WebKit/android/benchmark/Intercept.h b/Source/WebKit/android/benchmark/Intercept.h new file mode 100644 index 0000000..edd5123 --- /dev/null +++ b/Source/WebKit/android/benchmark/Intercept.h @@ -0,0 +1,82 @@ +/* + * 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 +#include + +namespace WebCore { + class Page; + class ResourceHandle; + class ResourceRequest; +} + +using namespace android; +using namespace WebCore; +using namespace WTF; + +class MyResourceLoader : public WebCoreResourceLoader { +public: + static PassRefPtr 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 startLoadingResource( + ResourceHandle* handle, const ResourceRequest& req, bool, bool); + + virtual bool canHandleRequest(const ResourceRequest&) { return true; } + +private: + void timerFired(Timer*); + Vector > m_requests; + Timer m_timer; +}; + +#endif diff --git a/Source/WebKit/android/benchmark/MyJavaVM.cpp b/Source/WebKit/android/benchmark/MyJavaVM.cpp new file mode 100644 index 0000000..574c745 --- /dev/null +++ b/Source/WebKit/android/benchmark/MyJavaVM.cpp @@ -0,0 +1,130 @@ +/* + * 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 +#include + +static JNIEnv* s_env; +static JavaVM* s_jvm; + +// JavaVM functions +jint vm_attachCurrentThread(JavaVM*, JNIEnv** env, void*) { + *env = s_env; + return JNI_OK; +} + +// JNIEnv functions +jobject env_callObjectMethodV(JNIEnv*, jobject, jmethodID, va_list) { + return MY_JOBJECT; +} +void env_callVoidMethodV(JNIEnv*, jobject, jmethodID, va_list) {} +void env_deleteRef(JNIEnv*, jobject) {} +jboolean env_exceptionCheck(JNIEnv*) { + return false; +} +jclass env_findClass(JNIEnv*, const char*) { + return (jclass) 1; +} +jbyte* env_getByteArrayElements(JNIEnv*, jbyteArray, jboolean*) { + return NULL; +} +jmethodID env_getMethodID(JNIEnv*, jclass, const char*, const char*) { + return (jmethodID) 1; +} +jclass env_getObjectClass(JNIEnv*, jobject) { + return (jclass) 1; +} +static const char* s_fakeString = "Fake Java String"; +const jchar* env_getStringChars(JNIEnv*, jstring, jboolean* isCopy) { + if (isCopy) + *isCopy = false; + return (const jchar*)s_fakeString; +} +jsize env_getStringLength(JNIEnv*, jstring) { + return sizeof(s_fakeString) - 1; +} +jbyteArray env_newByteArray(JNIEnv*, jsize) { + return (jbyteArray) 1; +} +jobject env_newRef(JNIEnv*, jobject obj) { + return obj; +} +jobject env_newObjectV(JNIEnv*, jclass, jmethodID, va_list) { + return MY_JOBJECT; +} +jstring env_newString(JNIEnv*, const jchar*, jsize) { + return (jstring) 1; +} +void env_releaseByteArrayElements(JNIEnv*, jbyteArray, jbyte*, jint) {} +void env_releaseStringChars(JNIEnv*, jstring, const jchar*) {} +void env_setByteArrayRegion(JNIEnv*, jbyteArray, jsize, jsize, const jbyte*) {} +void env_setIntField(JNIEnv*, jobject, jfieldID, jint) {} + +void InitializeJavaVM() { + // First, create the fake vm + s_jvm = new JavaVM; + JNIInvokeInterface* i = new JNIInvokeInterface; + memset(i, 0, sizeof(JNIInvokeInterface)); + s_jvm->functions = i; + + // Now, assign the functions of the vm to our fake ones. + i->AttachCurrentThread = vm_attachCurrentThread; + + // Create the fake env next + s_env = new JNIEnv; + JNINativeInterface* n = new JNINativeInterface; + memset(n, 0, sizeof(JNINativeInterface)); + s_env->functions = n; + + // Point the functions we care about to out fake ones. + n->CallObjectMethodV = env_callObjectMethodV; + n->CallVoidMethodV = env_callVoidMethodV; + n->DeleteLocalRef = env_deleteRef; + n->DeleteGlobalRef = env_deleteRef; + n->DeleteWeakGlobalRef = env_deleteRef; + n->ExceptionCheck = env_exceptionCheck; + n->FindClass = env_findClass; + n->GetByteArrayElements = env_getByteArrayElements; + n->GetMethodID = env_getMethodID; + n->GetObjectClass = env_getObjectClass; + n->GetStringChars = env_getStringChars; + n->GetStringLength = env_getStringLength; + n->NewByteArray = env_newByteArray; + n->NewLocalRef = env_newRef; + n->NewGlobalRef = env_newRef; + n->NewWeakGlobalRef = env_newRef; + n->NewObjectV = env_newObjectV; + n->NewString = env_newString; + n->ReleaseByteArrayElements = env_releaseByteArrayElements; + n->ReleaseStringChars = env_releaseStringChars; + n->SetByteArrayRegion = env_setByteArrayRegion; + n->SetIntField = env_setIntField; + + // Tell WebCore about the vm + JSC::Bindings::setJavaVM(s_jvm); +} diff --git a/Source/WebKit/android/benchmark/MyJavaVM.h b/Source/WebKit/android/benchmark/MyJavaVM.h new file mode 100644 index 0000000..36d478d --- /dev/null +++ b/Source/WebKit/android/benchmark/MyJavaVM.h @@ -0,0 +1,34 @@ +/* + * 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 MY_JAVA_VM_H +#define MY_JAVA_VM_H + +// Make it 1 just to appease any assertions or checks for valid objects +#define MY_JOBJECT ((jobject) 1) + +void InitializeJavaVM(); + +#endif diff --git a/Source/WebKit/android/benchmark/main.cpp b/Source/WebKit/android/benchmark/main.cpp new file mode 100644 index 0000000..fcb797d --- /dev/null +++ b/Source/WebKit/android/benchmark/main.cpp @@ -0,0 +1,65 @@ +/* + * 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 +#include +#include +#include + +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/icu/unicode/ucnv.cpp b/Source/WebKit/android/icu/unicode/ucnv.cpp new file mode 100644 index 0000000..1b40573 --- /dev/null +++ b/Source/WebKit/android/icu/unicode/ucnv.cpp @@ -0,0 +1,50 @@ +/* + * 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. + */ + +// BEGIN android-added +// Add config.h to avoid compiler error in uobject.h +// ucnv.h includes uobject.h indirectly and uobjetcs.h defines new/delete. +// new/delete are also defined in WebCorePrefix.h which auto included in Android make. +// +// config.h has to be on top of the include list. +#include "config.h" +// END android-added + +#include "EmojiFont.h" +#include + +namespace android { + +U_STABLE UConverter* U_EXPORT2 +ucnv_open_emoji(const char *converterName, UErrorCode *err) { + if (EmojiFont::IsAvailable()) { + if (strcmp(converterName, "Shift_JIS") == 0) { + converterName = EmojiFont::GetShiftJisConverterName(); + } + } + return ucnv_open(converterName, err); +} + +} // end namespace android diff --git a/Source/WebKit/android/icu/unicode/ucnv.h b/Source/WebKit/android/icu/unicode/ucnv.h new file mode 100644 index 0000000..5ddaedb --- /dev/null +++ b/Source/WebKit/android/icu/unicode/ucnv.h @@ -0,0 +1,47 @@ +/* + * 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 ANDROID_UCNV_H +#define ANDROID_UCNV_H + +// Include the real ucnv.h file from icu. Use a more exact reference so we do +// not conflict with this file. +#include + +namespace android { + +U_STABLE UConverter* U_EXPORT2 +ucnv_open_emoji(const char *converterName, UErrorCode *err); + +} + +// Redefine ucnv_open to android::ucnv_open_emoji. This relies heavily on the +// fact that this file will be included before any of the real icu headers. +// This is done in Android.mk by including WebKit/android/icu before the +// regular icu directory. +#undef ucnv_open +#define ucnv_open android::ucnv_open_emoji + +#endif diff --git a/Source/WebKit/android/jni/CacheManager.cpp b/Source/WebKit/android/jni/CacheManager.cpp new file mode 100644 index 0000000..144b62a --- /dev/null +++ b/Source/WebKit/android/jni/CacheManager.cpp @@ -0,0 +1,143 @@ +/* + * 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" + +#if USE(CHROME_NETWORK_STACK) + +#include "ChromiumIncludes.h" +#include "WebCache.h" +#include "WebCoreJni.h" + +#include +#include +#include +#include +#include + +using namespace WebCore; +using namespace base; +using namespace disk_cache; +using namespace net; +using namespace std; + +namespace android { + +// JNI for android.webkit.CacheManager +static const char* javaCacheManagerClass = "android/webkit/CacheManager"; + +static void setStringField(JNIEnv* env, const jobject& object, const jfieldID& field, const String& str) +{ + jstring jstr = wtfStringToJstring(env, str); + env->SetObjectField(object, field, jstr); + env->DeleteLocalRef(jstr); +} + +static void setFieldFromHeaderIfPresent(CacheResult* result, const char* header, JNIEnv* env, const jobject& object, const jfieldID& field, bool allowEmptyString) +{ + String value; + if (result->firstResponseHeader(header, &value, allowEmptyString)) + setStringField(env, object, field, value); +} + +static String getCacheFileBaseDir(JNIEnv* env) +{ + static String baseDir; + if (baseDir.isEmpty()) { + jclass cacheManagerClass = env->FindClass("android/webkit/CacheManager"); + jmethodID getCacheFileBaseDirMethod = env->GetStaticMethodID(cacheManagerClass, "getCacheFileBaseDir", "()Ljava/io/File;"); + jclass fileClass = env->FindClass("java/io/File"); + jmethodID getPathMethod = env->GetMethodID(fileClass, "getPath", "()Ljava/lang/String;"); + jobject fileObject = env->CallStaticObjectMethod(cacheManagerClass, getCacheFileBaseDirMethod); + baseDir = jstringToWtfString(env, static_cast(env->CallObjectMethod(fileObject, getPathMethod))); + } + return baseDir; +} + +static jobject getCacheResult(JNIEnv* env, jobject, jstring url) +{ + // This is called on the UI thread. + scoped_refptr result = WebCache::get(false /*privateBrowsing*/)->getCacheResult(jstringToWtfString(env, url)); + if (!result) + return 0; + + // We create and populate a file with the cache entry. This allows us to + // replicate the behaviour of the Android HTTP stack in the Java + // CacheManager, which opens the cache file and provides an input stream to + // the file as part of the Java CacheResult object! + String urlWtfString = jstringToWtfString(env, url); + Vector encodedUrl; + base64Encode(urlWtfString.utf8().data(), urlWtfString.length(), encodedUrl, false /*insertLFs*/); + String filePath = pathByAppendingComponent(getCacheFileBaseDir(env), encodedUrl.data()); + if (!result->writeToFile(filePath)) + return 0; + + jclass cacheResultClass = env->FindClass("android/webkit/CacheManager$CacheResult"); + jmethodID constructor = env->GetMethodID(cacheResultClass, "", "()V"); + // We only bother with the fields that are made accessible through the public API. + jfieldID contentdispositionField = env->GetFieldID(cacheResultClass, "contentdisposition", "Ljava/lang/String;"); + jfieldID contentLengthField = env->GetFieldID(cacheResultClass, "contentLength", "J"); + jfieldID etagField = env->GetFieldID(cacheResultClass, "etag", "Ljava/lang/String;"); + jfieldID encodingField = env->GetFieldID(cacheResultClass, "encoding", "Ljava/lang/String;"); + jfieldID expiresField = env->GetFieldID(cacheResultClass, "expires", "J"); + jfieldID expiresStringField = env->GetFieldID(cacheResultClass, "expiresString", "Ljava/lang/String;"); + jfieldID httpStatusCodeField = env->GetFieldID(cacheResultClass, "httpStatusCode", "I"); + jfieldID lastModifiedField = env->GetFieldID(cacheResultClass, "lastModified", "Ljava/lang/String;"); + jfieldID localPathField = env->GetFieldID(cacheResultClass, "localPath", "Ljava/lang/String;"); + jfieldID locationField = env->GetFieldID(cacheResultClass, "location", "Ljava/lang/String;"); + jfieldID mimeTypeField = env->GetFieldID(cacheResultClass, "mimeType", "Ljava/lang/String;"); + + jobject javaResult = env->NewObject(cacheResultClass, constructor); + setFieldFromHeaderIfPresent(result.get(), "content-disposition", env, javaResult, contentdispositionField, true); + env->SetLongField(javaResult, contentLengthField, result->contentSize()); + setFieldFromHeaderIfPresent(result.get(), "etag", env, javaResult, etagField, false); + setStringField(env, javaResult, encodingField, "TODO"); // TODO: Where does the Android stack set this? + env->SetLongField(javaResult, expiresField, result->expires()); + env->SetIntField(javaResult, httpStatusCodeField, result->responseCode()); + setFieldFromHeaderIfPresent(result.get(), "last-modified", env, javaResult, lastModifiedField, false); + setStringField(env, javaResult, localPathField, encodedUrl.data()); + setFieldFromHeaderIfPresent(result.get(), "location", env, javaResult, locationField, false); + setStringField(env, javaResult, mimeTypeField, result->mimeType()); + + return javaResult; +} + +static JNINativeMethod gCacheManagerMethods[] = { + { "nativeGetCacheResult", "(Ljava/lang/String;)Landroid/webkit/CacheManager$CacheResult;", (void*) getCacheResult }, +}; + +int registerCacheManager(JNIEnv* env) +{ +#ifndef NDEBUG + jclass cacheManager = env->FindClass(javaCacheManagerClass); + LOG_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 new file mode 100644 index 0000000..0bdf303 --- /dev/null +++ b/Source/WebKit/android/jni/CookieManager.cpp @@ -0,0 +1,201 @@ +/* + * 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 "WebCookieJar.h" +#include "WebCoreJni.h" +#include + +using namespace base; +using namespace net; + +namespace android { + +// JNI for android.webkit.CookieManager +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 + // for such contexts are cleared up when we're done with them. + // TODO: Consider adding an optimisation to not create the context if it + // doesn't already exist. + WebCookieJar::get(true)->cookieStore()->GetCookieMonster()->DeleteAll(true); + + // 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(); + CookieMonster::CookieList cookies = cookieMonster->GetAllCookies(); + for (CookieMonster::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[] = { + { "nativeAcceptCookie", "()Z", (void*) acceptCookie }, + { "nativeGetCookie", "(Ljava/lang/String;Z)Ljava/lang/String;", (void*) getCookie }, + { "nativeHasCookies", "(Z)Z", (void*) hasCookies }, + { "nativeRemoveAllCookie", "()V", (void*) removeAllCookie }, + { "nativeRemoveExpiredCookie", "()V", (void*) removeExpiredCookie }, + { "nativeRemoveSessionCookie", "()V", (void*) removeSessionCookie }, + { "nativeSetAcceptCookie", "(Z)V", (void*) setAcceptCookie }, + { "nativeSetCookie", "(Ljava/lang/String;Ljava/lang/String;Z)V", (void*) setCookie }, + { "nativeFlushCookieStore", "()V", (void*) flushCookieStore }, + { "nativeAcceptFileSchemeCookies", "()Z", (void*) acceptFileSchemeCookies }, + { "nativeSetAcceptFileSchemeCookies", "(Z)V", (void*) setAcceptFileSchemeCookies }, +}; + +int registerCookieManager(JNIEnv* env) +{ +#ifndef NDEBUG + jclass cookieManager = env->FindClass(javaCookieManagerClass); + LOG_ASSERT(cookieManager, "Unable to find class"); + env->DeleteLocalRef(cookieManager); +#endif + return jniRegisterNativeMethods(env, javaCookieManagerClass, gCookieManagerMethods, NELEM(gCookieManagerMethods)); +} + +} // namespace android diff --git a/Source/WebKit/android/jni/DeviceMotionAndOrientationManager.cpp b/Source/WebKit/android/jni/DeviceMotionAndOrientationManager.cpp new file mode 100644 index 0000000..8beb372 --- /dev/null +++ b/Source/WebKit/android/jni/DeviceMotionAndOrientationManager.cpp @@ -0,0 +1,171 @@ +/* + * 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 "DeviceMotionAndOrientationManager.h" + +#include "DeviceMotionClientImpl.h" +#include "DeviceOrientationClientImpl.h" +#include "DeviceOrientationController.h" +#include "WebViewCore.h" +#include "Frame.h" +#include "Page.h" + +#include +#include + +using namespace WebCore; + +namespace android { + +DeviceMotionAndOrientationManager::DeviceMotionAndOrientationManager(WebViewCore* webViewCore) + : m_useMock(false) + , m_webViewCore(webViewCore) +{ +} + +void DeviceMotionAndOrientationManager::useMock() +{ + m_useMock = true; +} + +void DeviceMotionAndOrientationManager::setMockMotion(PassRefPtr motion) +{ + // TODO: There is not yet a DeviceMotion mock. +} + +void DeviceMotionAndOrientationManager::onMotionChange(PassRefPtr motion) +{ + ASSERT(!m_useMock); + static_cast(m_motionClient.get())->onMotionChange(motion); +} + +void DeviceMotionAndOrientationManager::setMockOrientation(PassRefPtr orientation) +{ + if (m_useMock) + static_cast(orientationClient())->setOrientation(orientation); +} + +void DeviceMotionAndOrientationManager::onOrientationChange(PassRefPtr orientation) +{ + ASSERT(!m_useMock); + static_cast(m_orientationClient.get())->onOrientationChange(orientation); +} + +void DeviceMotionAndOrientationManager::maybeSuspendClients() +{ + if (!m_useMock) { + if (m_motionClient) + static_cast(m_motionClient.get())->suspend(); + if (m_orientationClient) + static_cast(m_orientationClient.get())->suspend(); + } +} + +void DeviceMotionAndOrientationManager::maybeResumeClients() +{ + if (!m_useMock) { + if (m_motionClient) + static_cast(m_motionClient.get())->resume(); + if (m_orientationClient) + static_cast(m_orientationClient.get())->resume(); + } +} + +DeviceMotionClient* DeviceMotionAndOrientationManager::motionClient() +{ + // TODO: There is not yet a DeviceMotion mock. + if (!m_motionClient) + m_motionClient.set(m_useMock ? 0 + : static_cast(new DeviceMotionClientImpl(m_webViewCore))); + ASSERT(m_motionClient); + return m_motionClient.get(); +} + +DeviceOrientationClient* DeviceMotionAndOrientationManager::orientationClient() +{ + if (!m_orientationClient) + m_orientationClient.set(m_useMock ? new DeviceOrientationClientMock + : static_cast(new DeviceOrientationClientImpl(m_webViewCore))); + ASSERT(m_orientationClient); + return m_orientationClient.get(); +} + +// JNI for android.webkit.DeviceMotionAndOrientationManager +static const char* javaDeviceMotionAndOrientationManagerClass = "android/webkit/DeviceMotionAndOrientationManager"; + +static WebViewCore* getWebViewCore(JNIEnv* env, jobject webViewCoreObject) +{ + jclass webViewCoreClass = env->FindClass("android/webkit/WebViewCore"); + jfieldID nativeClassField = env->GetFieldID(webViewCoreClass, "mNativeClass", "I"); + env->DeleteLocalRef(webViewCoreClass); + return reinterpret_cast(env->GetIntField(webViewCoreObject, nativeClassField)); +} + +static void useMock(JNIEnv* env, jobject, jobject webViewCoreObject) +{ + getWebViewCore(env, webViewCoreObject)->deviceMotionAndOrientationManager()->useMock(); +} + +static void onMotionChange(JNIEnv* env, jobject, jobject webViewCoreObject, bool canProvideX, double x, bool canProvideY, double y, bool canProvideZ, double z, double interval) +{ + // We only provide accelerationIncludingGravity. + RefPtr accelerationIncludingGravity = DeviceMotionData::Acceleration::create(canProvideX, x, canProvideY, y, canProvideZ, z); + bool canProvideInterval = canProvideX || canProvideY || canProvideZ; + RefPtr motion = DeviceMotionData::create(0, accelerationIncludingGravity.release(), 0, canProvideInterval, interval); + getWebViewCore(env, webViewCoreObject)->deviceMotionAndOrientationManager()->onMotionChange(motion.release()); +} + +static void setMockOrientation(JNIEnv* env, jobject, jobject webViewCoreObject, bool canProvideAlpha, double alpha, bool canProvideBeta, double beta, bool canProvideGamma, double gamma) +{ + RefPtr orientation = DeviceOrientation::create(canProvideAlpha, alpha, canProvideBeta, beta, canProvideGamma, gamma); + getWebViewCore(env, webViewCoreObject)->deviceMotionAndOrientationManager()->setMockOrientation(orientation.release()); +} + +static void onOrientationChange(JNIEnv* env, jobject, jobject webViewCoreObject, bool canProvideAlpha, double alpha, bool canProvideBeta, double beta, bool canProvideGamma, double gamma) +{ + RefPtr orientation = DeviceOrientation::create(canProvideAlpha, alpha, canProvideBeta, beta, canProvideGamma, gamma); + getWebViewCore(env, webViewCoreObject)->deviceMotionAndOrientationManager()->onOrientationChange(orientation.release()); +} + +static JNINativeMethod gDeviceMotionAndOrientationManagerMethods[] = { + { "nativeUseMock", "(Landroid/webkit/WebViewCore;)V", (void*) useMock }, + { "nativeOnMotionChange", "(Landroid/webkit/WebViewCore;ZDZDZDD)V", (void*) onMotionChange }, + { "nativeSetMockOrientation", "(Landroid/webkit/WebViewCore;ZDZDZD)V", (void*) setMockOrientation }, + { "nativeOnOrientationChange", "(Landroid/webkit/WebViewCore;ZDZDZD)V", (void*) onOrientationChange } +}; + +int registerDeviceMotionAndOrientationManager(JNIEnv* env) +{ +#ifndef NDEBUG + jclass deviceMotionAndOrientationManager = env->FindClass(javaDeviceMotionAndOrientationManagerClass); + LOG_ASSERT(deviceMotionAndOrientationManager, "Unable to find class"); + env->DeleteLocalRef(deviceMotionAndOrientationManager); +#endif + + return jniRegisterNativeMethods(env, javaDeviceMotionAndOrientationManagerClass, gDeviceMotionAndOrientationManagerMethods, NELEM(gDeviceMotionAndOrientationManagerMethods)); +} + +} // namespace android diff --git a/Source/WebKit/android/jni/DeviceMotionAndOrientationManager.h b/Source/WebKit/android/jni/DeviceMotionAndOrientationManager.h new file mode 100644 index 0000000..44463c1 --- /dev/null +++ b/Source/WebKit/android/jni/DeviceMotionAndOrientationManager.h @@ -0,0 +1,68 @@ +/* + * 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 DeviceMotionAndOrientationManager_h +#define DeviceMotionAndOrientationManager_h + +#include +#include +#include +#include +#include +#include +#include + +namespace android { + +class WebViewCore; + +// This class takes care of the fact that the clients used for DeviceMotion and +// DeviceOrientation may be either the real implementations or mocks. It also +// handles setting the data on both the real and mock clients. This class is +// owned by WebViewCore and exists to keep cruft out of that class. +class DeviceMotionAndOrientationManager { +public: + DeviceMotionAndOrientationManager(WebViewCore*); + + void useMock(); + void setMockMotion(PassRefPtr); + void onMotionChange(PassRefPtr); + void setMockOrientation(PassRefPtr); + void onOrientationChange(PassRefPtr); + void maybeSuspendClients(); + void maybeResumeClients(); + WebCore::DeviceMotionClient* motionClient(); + WebCore::DeviceOrientationClient* orientationClient(); + +private: + bool m_useMock; + WebViewCore* m_webViewCore; + OwnPtr m_motionClient; + OwnPtr m_orientationClient; +}; + +} // namespace android + +#endif // DeviceMotionAndOrientationManager_h diff --git a/Source/WebKit/android/jni/DeviceMotionClientImpl.cpp b/Source/WebKit/android/jni/DeviceMotionClientImpl.cpp new file mode 100644 index 0000000..82f3c35 --- /dev/null +++ b/Source/WebKit/android/jni/DeviceMotionClientImpl.cpp @@ -0,0 +1,130 @@ +/* + * 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 "DeviceMotionClientImpl.h" + +#include "WebViewCore.h" +#include +#include +#include + +namespace android { + +using JSC::Bindings::getJNIEnv; + +enum javaServiceClassMethods { + ServiceMethodStart = 0, + ServiceMethodStop, + ServiceMethodSuspend, + ServiceMethodResume, + ServiceMethodCount +}; +static jmethodID javaServiceClassMethodIDs[ServiceMethodCount]; + +DeviceMotionClientImpl::DeviceMotionClientImpl(WebViewCore* webViewCore) + : m_webViewCore(webViewCore) + , m_javaServiceObject(0) +{ + ASSERT(m_webViewCore); +} + +DeviceMotionClientImpl::~DeviceMotionClientImpl() +{ + releaseJavaInstance(); +} + +jobject DeviceMotionClientImpl::getJavaInstance() +{ + // Lazily get the Java object. We can't do this until the WebViewCore is all + // set up. + if (m_javaServiceObject) + return m_javaServiceObject; + + JNIEnv* env = getJNIEnv(); + + ASSERT(m_webViewCore); + jobject object = m_webViewCore->getDeviceMotionService(); + + // Get the Java DeviceMotionService class. + jclass javaServiceClass = env->GetObjectClass(object); + ASSERT(javaServiceClass); + + // Set up the methods we wish to call on the Java DeviceMotionService + // class. + javaServiceClassMethodIDs[ServiceMethodStart] = + env->GetMethodID(javaServiceClass, "start", "()V"); + javaServiceClassMethodIDs[ServiceMethodStop] = + env->GetMethodID(javaServiceClass, "stop", "()V"); + javaServiceClassMethodIDs[ServiceMethodSuspend] = + env->GetMethodID(javaServiceClass, "suspend", "()V"); + javaServiceClassMethodIDs[ServiceMethodResume] = + env->GetMethodID(javaServiceClass, "resume", "()V"); + env->DeleteLocalRef(javaServiceClass); + + m_javaServiceObject = getJNIEnv()->NewGlobalRef(object); + getJNIEnv()->DeleteLocalRef(object); + + ASSERT(m_javaServiceObject); + return m_javaServiceObject; +} + +void DeviceMotionClientImpl::releaseJavaInstance() +{ + ASSERT(m_javaServiceObject); + getJNIEnv()->DeleteGlobalRef(m_javaServiceObject); +} + +void DeviceMotionClientImpl::startUpdating() +{ + getJNIEnv()->CallVoidMethod(getJavaInstance(), + javaServiceClassMethodIDs[ServiceMethodStart]); +} + +void DeviceMotionClientImpl::stopUpdating() +{ + getJNIEnv()->CallVoidMethod(getJavaInstance(), + javaServiceClassMethodIDs[ServiceMethodStop]); +} + +void DeviceMotionClientImpl::onMotionChange(PassRefPtr motion) +{ + m_lastMotion = motion; + m_controller->didChangeDeviceMotion(m_lastMotion.get()); +} + +void DeviceMotionClientImpl::suspend() +{ + getJNIEnv()->CallVoidMethod(getJavaInstance(), + javaServiceClassMethodIDs[ServiceMethodSuspend]); +} + +void DeviceMotionClientImpl::resume() +{ + getJNIEnv()->CallVoidMethod(getJavaInstance(), + javaServiceClassMethodIDs[ServiceMethodResume]); +} + +} // namespace android diff --git a/Source/WebKit/android/jni/DeviceMotionClientImpl.h b/Source/WebKit/android/jni/DeviceMotionClientImpl.h new file mode 100644 index 0000000..c979098 --- /dev/null +++ b/Source/WebKit/android/jni/DeviceMotionClientImpl.h @@ -0,0 +1,70 @@ +/* + * 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 DeviceMotionClientImpl_h +#define DeviceMotionClientImpl_h + +#include +#include +#include +#include +#include + +using namespace WebCore; + +namespace android { + +class DeviceMotionAndOrientationManager; +class WebViewCore; + +class DeviceMotionClientImpl : public DeviceMotionClient { +public: + DeviceMotionClientImpl(WebViewCore*); + virtual ~DeviceMotionClientImpl(); + + void onMotionChange(PassRefPtr); + void suspend(); + void resume(); + + // DeviceMotionClient methods + virtual void startUpdating(); + virtual void stopUpdating(); + virtual DeviceMotionData* currentDeviceMotion() const { return m_lastMotion.get(); } + virtual void setController(DeviceMotionController* controller) { m_controller = controller; } + virtual void deviceMotionControllerDestroyed() { } + +private: + jobject getJavaInstance(); + void releaseJavaInstance(); + + WebViewCore* m_webViewCore; + jobject m_javaServiceObject; + DeviceMotionController* m_controller; + RefPtr m_lastMotion; +}; + +} // namespace android + +#endif // DeviceMotionClientImpl_h diff --git a/Source/WebKit/android/jni/DeviceOrientationClientImpl.cpp b/Source/WebKit/android/jni/DeviceOrientationClientImpl.cpp new file mode 100644 index 0000000..bf3b3c3 --- /dev/null +++ b/Source/WebKit/android/jni/DeviceOrientationClientImpl.cpp @@ -0,0 +1,130 @@ +/* + * 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 "DeviceOrientationClientImpl.h" + +#include "WebViewCore.h" +#include +#include +#include + +namespace android { + +using JSC::Bindings::getJNIEnv; + +enum javaDeviceOrientationServiceClassMethods { + DeviceOrientationServiceMethodStart = 0, + DeviceOrientationServiceMethodStop, + DeviceOrientationServiceMethodSuspend, + DeviceOrientationServiceMethodResume, + DeviceOrientationServiceMethodCount +}; +static jmethodID javaDeviceOrientationServiceClassMethodIDs[DeviceOrientationServiceMethodCount]; + +DeviceOrientationClientImpl::DeviceOrientationClientImpl(WebViewCore* webViewCore) + : m_webViewCore(webViewCore) + , m_javaDeviceOrientationServiceObject(0) +{ + ASSERT(m_webViewCore); +} + +DeviceOrientationClientImpl::~DeviceOrientationClientImpl() +{ + releaseJavaInstance(); +} + +jobject DeviceOrientationClientImpl::getJavaInstance() +{ + // Lazily get the Java object. We can't do this until the WebViewCore is all + // set up. + if (m_javaDeviceOrientationServiceObject) + return m_javaDeviceOrientationServiceObject; + + JNIEnv* env = getJNIEnv(); + + ASSERT(m_webViewCore); + jobject object = m_webViewCore->getDeviceOrientationService(); + + // Get the Java DeviceOrientationService class. + jclass javaDeviceOrientationServiceClass = env->GetObjectClass(object); + ASSERT(javaDeviceOrientationServiceClass); + + // Set up the methods we wish to call on the Java DeviceOrientationService + // class. + javaDeviceOrientationServiceClassMethodIDs[DeviceOrientationServiceMethodStart] = + env->GetMethodID(javaDeviceOrientationServiceClass, "start", "()V"); + javaDeviceOrientationServiceClassMethodIDs[DeviceOrientationServiceMethodStop] = + env->GetMethodID(javaDeviceOrientationServiceClass, "stop", "()V"); + javaDeviceOrientationServiceClassMethodIDs[DeviceOrientationServiceMethodSuspend] = + env->GetMethodID(javaDeviceOrientationServiceClass, "suspend", "()V"); + javaDeviceOrientationServiceClassMethodIDs[DeviceOrientationServiceMethodResume] = + env->GetMethodID(javaDeviceOrientationServiceClass, "resume", "()V"); + env->DeleteLocalRef(javaDeviceOrientationServiceClass); + + m_javaDeviceOrientationServiceObject = getJNIEnv()->NewGlobalRef(object); + getJNIEnv()->DeleteLocalRef(object); + + ASSERT(m_javaDeviceOrientationServiceObject); + return m_javaDeviceOrientationServiceObject; +} + +void DeviceOrientationClientImpl::releaseJavaInstance() +{ + ASSERT(m_javaDeviceOrientationServiceObject); + getJNIEnv()->DeleteGlobalRef(m_javaDeviceOrientationServiceObject); +} + +void DeviceOrientationClientImpl::startUpdating() +{ + getJNIEnv()->CallVoidMethod(getJavaInstance(), + javaDeviceOrientationServiceClassMethodIDs[DeviceOrientationServiceMethodStart]); +} + +void DeviceOrientationClientImpl::stopUpdating() +{ + getJNIEnv()->CallVoidMethod(getJavaInstance(), + javaDeviceOrientationServiceClassMethodIDs[DeviceOrientationServiceMethodStop]); +} + +void DeviceOrientationClientImpl::onOrientationChange(PassRefPtr orientation) +{ + m_lastOrientation = orientation; + m_controller->didChangeDeviceOrientation(m_lastOrientation.get()); +} + +void DeviceOrientationClientImpl::suspend() +{ + getJNIEnv()->CallVoidMethod(getJavaInstance(), + javaDeviceOrientationServiceClassMethodIDs[DeviceOrientationServiceMethodSuspend]); +} + +void DeviceOrientationClientImpl::resume() +{ + getJNIEnv()->CallVoidMethod(getJavaInstance(), + javaDeviceOrientationServiceClassMethodIDs[DeviceOrientationServiceMethodResume]); +} + +} // namespace android diff --git a/Source/WebKit/android/jni/DeviceOrientationClientImpl.h b/Source/WebKit/android/jni/DeviceOrientationClientImpl.h new file mode 100644 index 0000000..0e3f6b3 --- /dev/null +++ b/Source/WebKit/android/jni/DeviceOrientationClientImpl.h @@ -0,0 +1,70 @@ +/* + * 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 DeviceOrientationClientImpl_h +#define DeviceOrientationClientImpl_h + +#include +#include +#include +#include +#include + +using namespace WebCore; + +namespace android { + +class DeviceMotionAndOrientationManager; +class WebViewCore; + +class DeviceOrientationClientImpl : public DeviceOrientationClient { +public: + DeviceOrientationClientImpl(WebViewCore*); + virtual ~DeviceOrientationClientImpl(); + + void onOrientationChange(PassRefPtr); + void suspend(); + void resume(); + + // DeviceOrientationClient methods + virtual void startUpdating(); + virtual void stopUpdating(); + virtual DeviceOrientation* lastOrientation() const { return m_lastOrientation.get(); } + virtual void setController(DeviceOrientationController* controller) { m_controller = controller; } + virtual void deviceOrientationControllerDestroyed() { } + +private: + jobject getJavaInstance(); + void releaseJavaInstance(); + + WebViewCore* m_webViewCore; + jobject m_javaDeviceOrientationServiceObject; + DeviceOrientationController* m_controller; + RefPtr m_lastOrientation; +}; + +} // namespace android + +#endif // DeviceOrientationClientImpl_h diff --git a/Source/WebKit/android/jni/GeolocationPermissionsBridge.cpp b/Source/WebKit/android/jni/GeolocationPermissionsBridge.cpp new file mode 100755 index 0000000..a366601 --- /dev/null +++ b/Source/WebKit/android/jni/GeolocationPermissionsBridge.cpp @@ -0,0 +1,113 @@ +/* + * 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 "config.h" + +#include // For jniRegisterNativeMethods +#include "GeolocationPermissions.h" +#include "WebCoreJni.h" // For jstringToWtfString + + +/** + * This file provides a set of functions to bridge between the Java and C++ + * GeolocationPermissions classes. The java GeolocationPermissions object calls + * the functions provided here, which in turn call static methods on the C++ + * GeolocationPermissions class. + */ + +namespace android { + +static jobject getOrigins(JNIEnv* env, jobject obj) +{ + GeolocationPermissions::OriginSet origins = GeolocationPermissions::getOrigins(); + + jclass setClass = env->FindClass("java/util/HashSet"); + jmethodID constructor = env->GetMethodID(setClass, "", "()V"); + jmethodID addMethod = env->GetMethodID(setClass, "add", "(Ljava/lang/Object;)Z"); + jobject set = env->NewObject(setClass, constructor); + env->DeleteLocalRef(setClass); + + GeolocationPermissions::OriginSet::const_iterator end = origins.end(); + for (GeolocationPermissions::OriginSet::const_iterator iter = origins.begin(); iter != end; ++iter) { + jstring originString = wtfStringToJstring(env, *iter); + env->CallBooleanMethod(set, addMethod, originString); + env->DeleteLocalRef(originString); + } + return set; +} + +static bool getAllowed(JNIEnv* env, jobject obj, jstring origin) +{ + WTF::String originString = jstringToWtfString(env, origin); + return GeolocationPermissions::getAllowed(originString); +} + +static void clear(JNIEnv* env, jobject obj, jstring origin) +{ + WTF::String originString = jstringToWtfString(env, origin); + GeolocationPermissions::clear(originString); +} + +static void allow(JNIEnv* env, jobject obj, jstring origin) +{ + WTF::String originString = jstringToWtfString(env, origin); + GeolocationPermissions::allow(originString); +} + +static void clearAll(JNIEnv* env, jobject obj) +{ + GeolocationPermissions::clearAll(); +} + +/* + * JNI registration + */ +static JNINativeMethod gGeolocationPermissionsMethods[] = { + { "nativeGetOrigins", "()Ljava/util/Set;", + (void*) getOrigins }, + { "nativeGetAllowed", "(Ljava/lang/String;)Z", + (void*) getAllowed }, + { "nativeClear", "(Ljava/lang/String;)V", + (void*) clear }, + { "nativeAllow", "(Ljava/lang/String;)V", + (void*) allow }, + { "nativeClearAll", "()V", + (void*) clearAll } +}; + +int registerGeolocationPermissions(JNIEnv* env) +{ + const char* kGeolocationPermissionsClass = "android/webkit/GeolocationPermissions"; +#ifndef NDEBUG + jclass geolocationPermissions = env->FindClass(kGeolocationPermissionsClass); + LOG_ASSERT(geolocationPermissions, "Unable to find class"); + env->DeleteLocalRef(geolocationPermissions); +#endif + + return jniRegisterNativeMethods(env, kGeolocationPermissionsClass, + gGeolocationPermissionsMethods, NELEM(gGeolocationPermissionsMethods)); +} + +} diff --git a/Source/WebKit/android/jni/JavaBridge.cpp b/Source/WebKit/android/jni/JavaBridge.cpp new file mode 100644 index 0000000..2fa12fc --- /dev/null +++ b/Source/WebKit/android/jni/JavaBridge.cpp @@ -0,0 +1,514 @@ +/* + * 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 "MemoryCache.h" +#include "Connection.h" +#include "CookieClient.h" +#include "FileSystemClient.h" +#include "JavaSharedClient.h" +#include "KeyGeneratorClient.h" +#include "KURL.h" +#include "NetworkStateNotifier.h" +#include "PackageNotifier.h" +#include "Page.h" +#include "PluginClient.h" +#include "PluginDatabase.h" +#include "Timer.h" +#include "TimerClient.h" +#ifdef ANDROID_INSTRUMENT +#include "TimeCounter.h" +#endif +#include "WebCache.h" +#include "WebCoreJni.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace android { + +// ---------------------------------------------------------------------------- + +static jfieldID gJavaBridge_ObjectID; + +// ---------------------------------------------------------------------------- + +class JavaBridge : public TimerClient, public CookieClient, public PluginClient, public KeyGeneratorClient, public FileSystemClient +{ +public: + JavaBridge(JNIEnv* env, jobject obj); + virtual ~JavaBridge(); + + /* + * WebCore -> Java API + */ + virtual void setSharedTimer(long long timemillis); + virtual void stopSharedTimer(); + + virtual void setCookies(WebCore::KURL const& url, WTF::String const& value); + virtual WTF::String cookies(WebCore::KURL const& url); + virtual bool cookiesEnabled(); + + virtual WTF::Vector getPluginDirectories(); + virtual WTF::String getPluginSharedDataDirectory(); + + virtual WTF::Vector getSupportedKeyStrengthList(); + virtual WTF::String getSignedPublicKeyAndChallengeString(unsigned index, + const WTF::String& challenge, const WebCore::KURL& url); + virtual WTF::String resolveFilePathForContentUri(const WTF::String& uri); + + //////////////////////////////////////////// + + virtual void setSharedTimerCallback(void (*f)()); + + //////////////////////////////////////////// + + virtual void signalServiceFuncPtrQueue(); + + // jni functions + static void Constructor(JNIEnv* env, jobject obj); + static void Finalize(JNIEnv* env, jobject obj); + static void SharedTimerFired(JNIEnv* env, jobject); + static void SetCacheSize(JNIEnv* env, jobject obj, jint bytes); + static void SetNetworkOnLine(JNIEnv* env, jobject obj, jboolean online); + static void SetNetworkType(JNIEnv* env, jobject obj, jstring type, jstring subtype); + static void SetDeferringTimers(JNIEnv* env, jobject obj, jboolean defer); + static void ServiceFuncPtrQueue(JNIEnv*); + static void UpdatePluginDirectories(JNIEnv* env, jobject obj, jobjectArray array, jboolean reload); + static void AddPackageNames(JNIEnv* env, jobject obj, jobject packageNames); + static void AddPackageName(JNIEnv* env, jobject obj, jstring packageName); + static void RemovePackageName(JNIEnv* env, jobject obj, jstring packageName); + static void UpdateProxy(JNIEnv* env, jobject obj, jstring newProxy); + + +private: + jweak mJavaObject; + jmethodID mSetSharedTimer; + jmethodID mStopSharedTimer; + jmethodID mSetCookies; + jmethodID mCookies; + jmethodID mCookiesEnabled; + jmethodID mGetPluginDirectories; + jmethodID mGetPluginSharedDataDirectory; + jmethodID mSignalFuncPtrQueue; + jmethodID mGetKeyStrengthList; + jmethodID mGetSignedPublicKey; + jmethodID mResolveFilePathForContentUri; + AutoJObject javaObject(JNIEnv* env) { return getRealObject(env, mJavaObject); } +}; + +static void (*sSharedTimerFiredCallback)(); + +JavaBridge::JavaBridge(JNIEnv* env, jobject obj) +{ + mJavaObject = env->NewWeakGlobalRef(obj); + jclass clazz = env->GetObjectClass(obj); + + mSetSharedTimer = env->GetMethodID(clazz, "setSharedTimer", "(J)V"); + mStopSharedTimer = env->GetMethodID(clazz, "stopSharedTimer", "()V"); + mSetCookies = env->GetMethodID(clazz, "setCookies", "(Ljava/lang/String;Ljava/lang/String;)V"); + mCookies = env->GetMethodID(clazz, "cookies", "(Ljava/lang/String;)Ljava/lang/String;"); + mCookiesEnabled = env->GetMethodID(clazz, "cookiesEnabled", "()Z"); + mGetPluginDirectories = env->GetMethodID(clazz, "getPluginDirectories", "()[Ljava/lang/String;"); + mGetPluginSharedDataDirectory = env->GetMethodID(clazz, "getPluginSharedDataDirectory", "()Ljava/lang/String;"); + mSignalFuncPtrQueue = env->GetMethodID(clazz, "signalServiceFuncPtrQueue", "()V"); + mGetKeyStrengthList = env->GetMethodID(clazz, "getKeyStrengthList", "()[Ljava/lang/String;"); + mGetSignedPublicKey = env->GetMethodID(clazz, "getSignedPublicKey", "(ILjava/lang/String;Ljava/lang/String;)Ljava/lang/String;"); + 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"); + + JavaSharedClient::SetTimerClient(this); + JavaSharedClient::SetCookieClient(this); + JavaSharedClient::SetPluginClient(this); + JavaSharedClient::SetKeyGeneratorClient(this); + JavaSharedClient::SetFileSystemClient(this); +} + +JavaBridge::~JavaBridge() +{ + if (mJavaObject) { + JNIEnv* env = JSC::Bindings::getJNIEnv(); + env->DeleteWeakGlobalRef(mJavaObject); + mJavaObject = 0; + } + + JavaSharedClient::SetTimerClient(NULL); + JavaSharedClient::SetCookieClient(NULL); + JavaSharedClient::SetPluginClient(NULL); + JavaSharedClient::SetKeyGeneratorClient(NULL); + JavaSharedClient::SetFileSystemClient(NULL); +} + +void +JavaBridge::setSharedTimer(long long timemillis) +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + AutoJObject obj = javaObject(env); + env->CallVoidMethod(obj.get(), mSetSharedTimer, timemillis); +} + +void +JavaBridge::stopSharedTimer() +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + AutoJObject obj = javaObject(env); + env->CallVoidMethod(obj.get(), mStopSharedTimer); +} + +void +JavaBridge::setCookies(WebCore::KURL const& url, WTF::String const& value) +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + const WTF::String& urlStr = url.string(); + jstring jUrlStr = wtfStringToJstring(env, urlStr); + jstring jValueStr = wtfStringToJstring(env, value); + + AutoJObject obj = javaObject(env); + env->CallVoidMethod(obj.get(), mSetCookies, jUrlStr, jValueStr); + env->DeleteLocalRef(jUrlStr); + env->DeleteLocalRef(jValueStr); +} + +WTF::String +JavaBridge::cookies(WebCore::KURL const& url) +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + const WTF::String& urlStr = url.string(); + jstring jUrlStr = wtfStringToJstring(env, urlStr); + + AutoJObject obj = javaObject(env); + jstring string = (jstring)(env->CallObjectMethod(obj.get(), mCookies, jUrlStr)); + + WTF::String ret = jstringToWtfString(env, string); + env->DeleteLocalRef(jUrlStr); + env->DeleteLocalRef(string); + return ret; +} + +bool +JavaBridge::cookiesEnabled() +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + AutoJObject obj = javaObject(env); + jboolean ret = env->CallBooleanMethod(obj.get(), mCookiesEnabled); + return (ret != 0); +} + +WTF::Vector +JavaBridge::getPluginDirectories() +{ + WTF::Vector directories; + JNIEnv* env = JSC::Bindings::getJNIEnv(); + AutoJObject obj = javaObject(env); + jobjectArray array = (jobjectArray) + env->CallObjectMethod(obj.get(), mGetPluginDirectories); + int count = env->GetArrayLength(array); + for (int i = 0; i < count; i++) { + jstring dir = (jstring) env->GetObjectArrayElement(array, i); + directories.append(jstringToWtfString(env, dir)); + env->DeleteLocalRef(dir); + } + env->DeleteLocalRef(array); + checkException(env); + return directories; +} + +WTF::String +JavaBridge::getPluginSharedDataDirectory() +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + AutoJObject obj = javaObject(env); + jstring ret = (jstring)env->CallObjectMethod(obj.get(), mGetPluginSharedDataDirectory); + WTF::String path = jstringToWtfString(env, ret); + checkException(env); + return path; +} + +void +JavaBridge::setSharedTimerCallback(void (*f)()) +{ + LOG_ASSERT(!sSharedTimerFiredCallback || sSharedTimerFiredCallback==f, + "Shared timer callback may already be set or null!"); + + sSharedTimerFiredCallback = f; +} + +void JavaBridge::signalServiceFuncPtrQueue() +{ + // In order to signal the main thread we must go through JNI. This + // is the only usage on most threads, so we need to ensure a JNI + // environment is setup. + JNIEnv* env = JSC::Bindings::getJNIEnv(); + AutoJObject obj = javaObject(env); + env->CallVoidMethod(obj.get(), mSignalFuncPtrQueue); +} + +WTF::VectorJavaBridge::getSupportedKeyStrengthList() { + WTF::Vector list; + JNIEnv* env = JSC::Bindings::getJNIEnv(); + AutoJObject obj = javaObject(env); + jobjectArray array = (jobjectArray) env->CallObjectMethod(obj.get(), + mGetKeyStrengthList); + int count = env->GetArrayLength(array); + for (int i = 0; i < count; ++i) { + jstring keyStrength = (jstring) env->GetObjectArrayElement(array, i); + list.append(jstringToWtfString(env, keyStrength)); + env->DeleteLocalRef(keyStrength); + } + env->DeleteLocalRef(array); + checkException(env); + return list; +} + +WTF::String JavaBridge::getSignedPublicKeyAndChallengeString(unsigned index, + const WTF::String& challenge, const WebCore::KURL& url) { + JNIEnv* env = JSC::Bindings::getJNIEnv(); + jstring jChallenge = wtfStringToJstring(env, challenge); + const WTF::String& urlStr = url.string(); + jstring jUrl = wtfStringToJstring(env, urlStr); + AutoJObject obj = javaObject(env); + jstring key = (jstring) env->CallObjectMethod(obj.get(), + mGetSignedPublicKey, index, jChallenge, jUrl); + WTF::String ret = jstringToWtfString(env, key); + env->DeleteLocalRef(jChallenge); + env->DeleteLocalRef(jUrl); + env->DeleteLocalRef(key); + return ret; +} + +WTF::String JavaBridge::resolveFilePathForContentUri(const WTF::String& uri) { + JNIEnv* env = JSC::Bindings::getJNIEnv(); + jstring jUri = wtfStringToJstring(env, uri); + AutoJObject obj = javaObject(env); + jstring path = static_cast(env->CallObjectMethod(obj.get(), mResolveFilePathForContentUri, jUri)); + WTF::String ret = jstringToWtfString(env, path); + env->DeleteLocalRef(jUri); + env->DeleteLocalRef(path); + return ret; +} + +// ---------------------------------------------------------------------------- + +void JavaBridge::Constructor(JNIEnv* env, jobject obj) +{ + JavaBridge* javaBridge = new JavaBridge(env, obj); + env->SetIntField(obj, gJavaBridge_ObjectID, (jint)javaBridge); +} + +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); + delete javaBridge; + env->SetIntField(obj, gJavaBridge_ObjectID, 0); +} + +// we don't use the java bridge object, as we're just looking at a global +void JavaBridge::SharedTimerFired(JNIEnv* env, jobject) +{ + if (sSharedTimerFiredCallback) + { +#ifdef ANDROID_INSTRUMENT + TimeCounter::start(TimeCounter::SharedTimerTimeCounter); +#endif + SkAutoMemoryUsageProbe mup("JavaBridge::sharedTimerFired"); + sSharedTimerFiredCallback(); +#ifdef ANDROID_INSTRUMENT + TimeCounter::record(TimeCounter::SharedTimerTimeCounter, __FUNCTION__); +#endif + } +} + +void JavaBridge::SetCacheSize(JNIEnv* env, jobject obj, jint bytes) +{ + WebCore::cache()->setCapacities(0, bytes/2, bytes); +} + +void JavaBridge::SetNetworkOnLine(JNIEnv* env, jobject obj, jboolean online) +{ + WebCore::networkStateNotifier().networkStateChange(online); +} + +void JavaBridge::SetNetworkType(JNIEnv* env, jobject obj, jstring javatype, jstring javasubtype) +{ + DEFINE_STATIC_LOCAL(AtomicString, wifi, ("wifi")); + DEFINE_STATIC_LOCAL(AtomicString, mobile, ("mobile")); + DEFINE_STATIC_LOCAL(AtomicString, mobileSupl, ("mobile_supl")); + DEFINE_STATIC_LOCAL(AtomicString, gprs, ("gprs")); + DEFINE_STATIC_LOCAL(AtomicString, edge, ("edge")); + DEFINE_STATIC_LOCAL(AtomicString, umts, ("umts")); + + String type = jstringToWtfString(env, javatype); + String subtype = jstringToWtfString(env, javasubtype); + Connection::ConnectionType connectionType = Connection::UNKNOWN; + if (type == wifi) + connectionType = Connection::WIFI; + else if (type == mobile || type == mobileSupl) { + if (subtype == edge || subtype == gprs) + connectionType = Connection::CELL_2G; + else if (subtype == umts) + connectionType = Connection::CELL_3G; + } + WebCore::networkStateNotifier().networkTypeChange(connectionType); +} + +void JavaBridge::ServiceFuncPtrQueue(JNIEnv*) +{ + JavaSharedClient::ServiceFunctionPtrQueue(); +} + +void JavaBridge::UpdatePluginDirectories(JNIEnv* env, jobject obj, + jobjectArray array, jboolean reload) { + WTF::Vector directories; + int count = env->GetArrayLength(array); + for (int i = 0; i < count; i++) { + jstring dir = (jstring) env->GetObjectArrayElement(array, i); + directories.append(jstringToWtfString(env, dir)); + env->DeleteLocalRef(dir); + } + checkException(env); + WebCore::PluginDatabase *pluginDatabase = + WebCore::PluginDatabase::installedPlugins(); + pluginDatabase->setPluginDirectories(directories); + // refreshPlugins() should refresh both PluginDatabase and Page's PluginData + WebCore::Page::refreshPlugins(reload); +} + +void JavaBridge::AddPackageNames(JNIEnv* env, jobject obj, jobject packageNames) +{ + if (!packageNames) + return; + + // dalvikvm will raise exception if any of these fail + jclass setClass = env->FindClass("java/util/Set"); + jmethodID iterator = env->GetMethodID(setClass, "iterator", + "()Ljava/util/Iterator;"); + jobject iter = env->CallObjectMethod(packageNames, iterator); + + jclass iteratorClass = env->FindClass("java/util/Iterator"); + jmethodID hasNext = env->GetMethodID(iteratorClass, "hasNext", "()Z"); + jmethodID next = env->GetMethodID(iteratorClass, "next", "()Ljava/lang/Object;"); + + HashSet namesSet; + while (env->CallBooleanMethod(iter, hasNext)) { + jstring name = static_cast(env->CallObjectMethod(iter, next)); + namesSet.add(jstringToWtfString(env, name)); + env->DeleteLocalRef(name); + } + + packageNotifier().addPackageNames(namesSet); + + env->DeleteLocalRef(iteratorClass); + env->DeleteLocalRef(iter); + env->DeleteLocalRef(setClass); +} + +void JavaBridge::AddPackageName(JNIEnv* env, jobject obj, jstring packageName) +{ + packageNotifier().addPackageName(jstringToWtfString(env, packageName)); +} + +void JavaBridge::RemovePackageName(JNIEnv* env, jobject obj, jstring packageName) +{ + packageNotifier().removePackageName(jstringToWtfString(env, packageName)); +} + +void JavaBridge::UpdateProxy(JNIEnv* env, jobject obj, jstring newProxy) +{ +#if USE(CHROME_NETWORK_STACK) + std::string proxy = jstringToStdString(env, newProxy); + WebCache::get(false)->proxy()->UpdateProxySettings(proxy); + WebCache::get(true)->proxy()->UpdateProxySettings(proxy); +#endif +} + + +// ---------------------------------------------------------------------------- + +/* + * JNI registration. + */ +static JNINativeMethod gWebCoreJavaBridgeMethods[] = { + /* name, signature, funcPtr */ + { "nativeConstructor", "()V", + (void*) JavaBridge::Constructor }, + { "nativeFinalize", "()V", + (void*) JavaBridge::Finalize }, + { "sharedTimerFired", "()V", + (void*) JavaBridge::SharedTimerFired }, + { "setCacheSize", "(I)V", + (void*) JavaBridge::SetCacheSize }, + { "setNetworkOnLine", "(Z)V", + (void*) JavaBridge::SetNetworkOnLine }, + { "setNetworkType", "(Ljava/lang/String;Ljava/lang/String;)V", + (void*) JavaBridge::SetNetworkType }, + { "nativeServiceFuncPtrQueue", "()V", + (void*) JavaBridge::ServiceFuncPtrQueue }, + { "nativeUpdatePluginDirectories", "([Ljava/lang/String;Z)V", + (void*) JavaBridge::UpdatePluginDirectories }, + { "addPackageNames", "(Ljava/util/Set;)V", + (void*) JavaBridge::AddPackageNames }, + { "addPackageName", "(Ljava/lang/String;)V", + (void*) JavaBridge::AddPackageName }, + { "removePackageName", "(Ljava/lang/String;)V", + (void*) JavaBridge::RemovePackageName }, + { "updateProxy", "(Ljava/lang/String;)V", + (void*) JavaBridge::UpdateProxy } +}; + +int registerJavaBridge(JNIEnv* env) +{ + jclass javaBridge = env->FindClass("android/webkit/JWebCoreJavaBridge"); + LOG_FATAL_IF(javaBridge == NULL, "Unable to find class android/webkit/JWebCoreJavaBridge"); + gJavaBridge_ObjectID = env->GetFieldID(javaBridge, "mNativeBridge", "I"); + LOG_FATAL_IF(gJavaBridge_ObjectID == NULL, "Unable to find android/webkit/JWebCoreJavaBridge.mNativeBridge"); + env->DeleteLocalRef(javaBridge); + + return jniRegisterNativeMethods(env, "android/webkit/JWebCoreJavaBridge", + gWebCoreJavaBridgeMethods, NELEM(gWebCoreJavaBridgeMethods)); +} + +} /* namespace android */ diff --git a/Source/WebKit/android/jni/JavaSharedClient.cpp b/Source/WebKit/android/jni/JavaSharedClient.cpp new file mode 100644 index 0000000..e884c99 --- /dev/null +++ b/Source/WebKit/android/jni/JavaSharedClient.cpp @@ -0,0 +1,137 @@ +/* + * 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 "config.h" +#include "FileSystemClient.h" +#include "JavaSharedClient.h" +#include "TimerClient.h" +#include "SkDeque.h" +#include "SkThread.h" + +namespace android { + TimerClient* JavaSharedClient::GetTimerClient() + { + return gTimerClient; + } + + CookieClient* JavaSharedClient::GetCookieClient() + { + return gCookieClient; + } + + PluginClient* JavaSharedClient::GetPluginClient() + { + return gPluginClient; + } + + KeyGeneratorClient* JavaSharedClient::GetKeyGeneratorClient() + { + return gKeyGeneratorClient; + } + + FileSystemClient* JavaSharedClient::GetFileSystemClient() + { + return gFileSystemClient; + } + + void JavaSharedClient::SetTimerClient(TimerClient* client) + { + gTimerClient = client; + } + + void JavaSharedClient::SetCookieClient(CookieClient* client) + { + gCookieClient = client; + } + + void JavaSharedClient::SetPluginClient(PluginClient* client) + { + gPluginClient = client; + } + + void JavaSharedClient::SetKeyGeneratorClient(KeyGeneratorClient* client) + { + gKeyGeneratorClient = client; + } + + void JavaSharedClient::SetFileSystemClient(FileSystemClient* client) + { + gFileSystemClient = client; + } + + TimerClient* JavaSharedClient::gTimerClient = NULL; + CookieClient* JavaSharedClient::gCookieClient = NULL; + PluginClient* JavaSharedClient::gPluginClient = NULL; + KeyGeneratorClient* JavaSharedClient::gKeyGeneratorClient = NULL; + FileSystemClient* JavaSharedClient::gFileSystemClient = NULL; + + /////////////////////////////////////////////////////////////////////////// + + struct FuncPtrRec { + void (*fProc)(void* payload); + void* fPayload; + }; + + static SkMutex gFuncPtrQMutex; + static SkDeque gFuncPtrQ(sizeof(FuncPtrRec)); + + void JavaSharedClient::EnqueueFunctionPtr(void (*proc)(void* payload), + void* payload) + { + gFuncPtrQMutex.acquire(); + + 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); + } + } +} diff --git a/Source/WebKit/android/jni/JavaSharedClient.h b/Source/WebKit/android/jni/JavaSharedClient.h new file mode 100644 index 0000000..9a09280 --- /dev/null +++ b/Source/WebKit/android/jni/JavaSharedClient.h @@ -0,0 +1,65 @@ +/* + * 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 JAVA_SHARED_CLIENT_H +#define JAVA_SHARED_CLIENT_H + +namespace android { + + class TimerClient; + class CookieClient; + class PluginClient; + class KeyGeneratorClient; + class FileSystemClient; + + class JavaSharedClient + { + public: + static TimerClient* GetTimerClient(); + static CookieClient* GetCookieClient(); + static PluginClient* GetPluginClient(); + static KeyGeneratorClient* GetKeyGeneratorClient(); + static FileSystemClient* GetFileSystemClient(); + + static void SetTimerClient(TimerClient* client); + static void SetCookieClient(CookieClient* client); + static void SetPluginClient(PluginClient* client); + static void SetKeyGeneratorClient(KeyGeneratorClient* client); + static void SetFileSystemClient(FileSystemClient* client); + + // can be called from any thread, to be executed in webkit thread + static void EnqueueFunctionPtr(void (*proc)(void*), void* payload); + // only call this from webkit thread + static void ServiceFunctionPtrQueue(); + + private: + static TimerClient* gTimerClient; + static CookieClient* gCookieClient; + static PluginClient* gPluginClient; + static KeyGeneratorClient* gKeyGeneratorClient; + static FileSystemClient* gFileSystemClient; + }; +} +#endif diff --git a/Source/WebKit/android/jni/JniUtil.cpp b/Source/WebKit/android/jni/JniUtil.cpp new file mode 100644 index 0000000..ee1e3f9 --- /dev/null +++ b/Source/WebKit/android/jni/JniUtil.cpp @@ -0,0 +1,58 @@ +/* + * 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 + +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 new file mode 100644 index 0000000..40f8cef --- /dev/null +++ b/Source/WebKit/android/jni/MIMETypeRegistry.cpp @@ -0,0 +1,67 @@ +/* + * 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. + */ + +#define LOG_TAG "WebCore" + +#include "config.h" +#include "MIMETypeRegistry.h" + +#include "PlatformString.h" +#include "WebCoreJni.h" + +#include +#include +#include + +using namespace android; + +namespace WebCore { + +String MIMETypeRegistry::getMIMETypeForExtension(const String& ext) +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + jclass mimeClass = env->FindClass("android/webkit/MimeTypeMap"); + LOG_ASSERT(mimeClass, "Could not find class MimeTypeMap"); + jmethodID mimeTypeFromExtension = env->GetStaticMethodID(mimeClass, + "mimeTypeFromExtension", + "(Ljava/lang/String;)Ljava/lang/String;"); + LOG_ASSERT(mimeTypeFromExtension, + "Could not find method mimeTypeFromExtension"); + jstring extString = wtfStringToJstring(env, ext); + jobject mimeType = env->CallStaticObjectMethod(mimeClass, + mimeTypeFromExtension, extString); + String result = android::jstringToWtfString(env, (jstring) mimeType); + env->DeleteLocalRef(mimeClass); + env->DeleteLocalRef(extString); + env->DeleteLocalRef(mimeType); + return result; +} + +bool MIMETypeRegistry::isApplicationPluginMIMEType(const String&) +{ + return false; +} + +} diff --git a/Source/WebKit/android/jni/MockGeolocation.cpp b/Source/WebKit/android/jni/MockGeolocation.cpp new file mode 100755 index 0000000..1370715 --- /dev/null +++ b/Source/WebKit/android/jni/MockGeolocation.cpp @@ -0,0 +1,84 @@ +/* + * 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. + */ + +// The functions in this file are used to configure the mock GeolocationService +// for the LayoutTests. + +#include "config.h" + +#include "Coordinates.h" +#include "GeolocationServiceMock.h" +#include "Geoposition.h" +#include "JavaSharedClient.h" +#include "PositionError.h" +#include "WebCoreJni.h" +#include +#include +#include + +using namespace WebCore; + +namespace android { + +static const char* javaMockGeolocationClass = "android/webkit/MockGeolocation"; + +static void setPosition(JNIEnv* env, jobject, double latitude, double longitude, double accuracy) +{ + RefPtr coordinates = Coordinates::create(latitude, + longitude, + false, 0.0, // altitude, + accuracy, + false, 0.0, // altitudeAccuracy, + false, 0.0, // heading + false, 0.0); // speed + RefPtr position = Geoposition::create(coordinates.release(), WTF::currentTimeMS()); + GeolocationServiceMock::setPosition(position.release()); +} + +static void setError(JNIEnv* env, jobject, int code, jstring message) +{ + PositionError::ErrorCode codeEnum = static_cast(code); + String messageString = jstringToWtfString(env, message); + RefPtr error = PositionError::create(codeEnum, messageString); + GeolocationServiceMock::setError(error.release()); +} + +static JNINativeMethod gMockGeolocationMethods[] = { + { "nativeSetPosition", "(DDD)V", (void*) setPosition }, + { "nativeSetError", "(ILjava/lang/String;)V", (void*) setError } +}; + +int registerMockGeolocation(JNIEnv* env) +{ +#ifndef NDEBUG + jclass mockGeolocation = env->FindClass(javaMockGeolocationClass); + LOG_ASSERT(mockGeolocation, "Unable to find class"); + env->DeleteLocalRef(mockGeolocation); +#endif + + return jniRegisterNativeMethods(env, javaMockGeolocationClass, gMockGeolocationMethods, NELEM(gMockGeolocationMethods)); +} + +} diff --git a/Source/WebKit/android/jni/PictureSet.cpp b/Source/WebKit/android/jni/PictureSet.cpp new file mode 100644 index 0000000..6dafd26 --- /dev/null +++ b/Source/WebKit/android/jni/PictureSet.cpp @@ -0,0 +1,676 @@ +/* + * Copyright 2008, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define LOG_NDEBUG 0 +#define LOG_TAG "pictureset" + +//#include +#include "CachedPrefix.h" +#include "android_graphics.h" +#include "PictureSet.h" +#include "SkBounder.h" +#include "SkCanvas.h" +#include "SkPicture.h" +#include "SkRect.h" +#include "SkRegion.h" +#include "SkStream.h" +#include "TimeCounter.h" + +#define MAX_DRAW_TIME 100 +#define MIN_SPLITTABLE 400 + +#if PICTURE_SET_DEBUG +class MeasureStream : public SkWStream { +public: + MeasureStream() : mTotal(0) {} + virtual bool write(const void* , size_t size) { + mTotal += size; + return true; + } + size_t mTotal; +}; +#endif + +namespace android { + +PictureSet::PictureSet() +{ + mWidth = mHeight = 0; +} + +PictureSet::~PictureSet() +{ + clear(); +} + +void PictureSet::add(const Pictures* temp) +{ + Pictures pictureAndBounds = *temp; + SkSafeRef(pictureAndBounds.mPicture); + pictureAndBounds.mWroteElapsed = false; + mPictures.append(pictureAndBounds); +} + +void PictureSet::add(const SkRegion& area, SkPicture* picture, + uint32_t elapsed, bool split, bool empty) +{ + DBG_SET_LOGD("%p area={%d,%d,r=%d,b=%d} pict=%p elapsed=%d split=%d", this, + area.getBounds().fLeft, area.getBounds().fTop, + area.getBounds().fRight, area.getBounds().fBottom, picture, + elapsed, split); + SkSafeRef(picture); + /* if nothing is drawn beneath part of the new picture, mark it as a base */ + SkRegion diff = SkRegion(area); + Pictures* last = mPictures.end(); + for (Pictures* working = mPictures.begin(); working != last; working++) + diff.op(working->mArea, SkRegion::kDifference_Op); + Pictures pictureAndBounds = {area, picture, area.getBounds(), + elapsed, split, false, diff.isEmpty() == false, empty}; + mPictures.append(pictureAndBounds); +} + +/* +Pictures are discarded when they are fully drawn over. +When a picture is partially drawn over, it is discarded if it is not a base, and +its rectangular bounds is reduced if it is a base. +*/ +bool PictureSet::build() +{ + bool rebuild = false; + DBG_SET_LOGD("%p", this); + // walk pictures back to front, removing or trimming obscured ones + SkRegion drawn; + SkRegion inval; + Pictures* first = mPictures.begin(); + Pictures* last = mPictures.end(); + Pictures* working; + bool checkForNewBases = false; + for (working = last; working != first; ) { + --working; + SkRegion& area = working->mArea; + SkRegion visibleArea(area); + visibleArea.op(drawn, SkRegion::kDifference_Op); +#if PICTURE_SET_DEBUG + const SkIRect& a = area.getBounds(); + const SkIRect& d = drawn.getBounds(); + const SkIRect& i = inval.getBounds(); + const SkIRect& v = visibleArea.getBounds(); + DBG_SET_LOGD("%p [%d] area={%d,%d,r=%d,b=%d} drawn={%d,%d,r=%d,b=%d}" + " inval={%d,%d,r=%d,b=%d} vis={%d,%d,r=%d,b=%d}", + this, working - first, + a.fLeft, a.fTop, a.fRight, a.fBottom, + d.fLeft, d.fTop, d.fRight, d.fBottom, + i.fLeft, i.fTop, i.fRight, i.fBottom, + v.fLeft, v.fTop, v.fRight, v.fBottom); +#endif + bool tossPicture = false; + if (working->mBase == false) { + if (area != visibleArea) { + if (visibleArea.isEmpty() == false) { + DBG_SET_LOGD("[%d] partially overdrawn", working - first); + inval.op(visibleArea, SkRegion::kUnion_Op); + } else + DBG_SET_LOGD("[%d] fully hidden", working - first); + area.setEmpty(); + tossPicture = true; + } + } else { + const SkIRect& visibleBounds = visibleArea.getBounds(); + const SkIRect& areaBounds = area.getBounds(); + if (visibleBounds != areaBounds) { + DBG_SET_LOGD("[%d] base to be reduced", working - first); + area.setRect(visibleBounds); + checkForNewBases = tossPicture = true; + } + if (area.intersects(inval)) { + DBG_SET_LOGD("[%d] base to be redrawn", working - first); + tossPicture = true; + } + } + if (tossPicture) { + SkSafeUnref(working->mPicture); + working->mPicture = NULL; // mark to redraw + } + if (working->mPicture == NULL) // may have been set to null elsewhere + rebuild = true; + drawn.op(area, SkRegion::kUnion_Op); + } + // collapse out empty regions + Pictures* writer = first; + for (working = first; working != last; working++) { + if (working->mArea.isEmpty()) + continue; + *writer++ = *working; + } +#if PICTURE_SET_DEBUG + if ((unsigned) (writer - first) != mPictures.size()) + DBG_SET_LOGD("shrink=%d (was %d)", writer - first, mPictures.size()); +#endif + mPictures.shrink(writer - first); + /* When a base is discarded because it was entirely drawn over, all + remaining pictures are checked to see if one has become a base. */ + if (checkForNewBases) { + drawn.setEmpty(); + Pictures* last = mPictures.end(); + for (working = mPictures.begin(); working != last; working++) { + SkRegion& area = working->mArea; + if (drawn.contains(working->mArea) == false) { + working->mBase = true; + DBG_SET_LOGD("[%d] new base", working - mPictures.begin()); + } + drawn.op(working->mArea, SkRegion::kUnion_Op); + } + } + validate(__FUNCTION__); + return rebuild; +} + +void PictureSet::checkDimensions(int width, int height, SkRegion* inval) +{ + if (mWidth == width && mHeight == height) + return; + DBG_SET_LOGD("%p old:(w=%d,h=%d) new:(w=%d,h=%d)", this, + mWidth, mHeight, width, height); + if (mWidth == width && height > mHeight) { // only grew vertically + SkIRect rect; + rect.set(0, mHeight, width, height - mHeight); + inval->op(rect, SkRegion::kUnion_Op); + } else { + clear(); // if both width/height changed, clear the old cache + inval->setRect(0, 0, width, height); + } + mWidth = width; + mHeight = height; +} + +void PictureSet::clear() +{ + DBG_SET_LOG(""); + Pictures* last = mPictures.end(); + for (Pictures* working = mPictures.begin(); working != last; working++) { + working->mArea.setEmpty(); + SkSafeUnref(working->mPicture); + } + mPictures.clear(); + mWidth = mHeight = 0; +} + +bool PictureSet::draw(SkCanvas* canvas) +{ + validate(__FUNCTION__); + Pictures* first = mPictures.begin(); + Pictures* last = mPictures.end(); + Pictures* working; + SkRect bounds; + if (canvas->getClipBounds(&bounds) == false) + return false; + SkIRect irect; + bounds.roundOut(&irect); + for (working = last; working != first; ) { + --working; + if (working->mArea.contains(irect)) { +#if PICTURE_SET_DEBUG + const SkIRect& b = working->mArea.getBounds(); + DBG_SET_LOGD("contains working->mArea={%d,%d,%d,%d}" + " irect={%d,%d,%d,%d}", b.fLeft, b.fTop, b.fRight, b.fBottom, + irect.fLeft, irect.fTop, irect.fRight, irect.fBottom); +#endif + first = working; + break; + } + } + DBG_SET_LOGD("%p first=%d last=%d", this, first - mPictures.begin(), + last - mPictures.begin()); + uint32_t maxElapsed = 0; + for (working = first; working != last; working++) { + const SkRegion& area = working->mArea; + if (area.quickReject(irect)) { +#if PICTURE_SET_DEBUG + const SkIRect& b = area.getBounds(); + DBG_SET_LOGD("[%d] %p quickReject working->mArea={%d,%d,%d,%d}" + " irect={%d,%d,%d,%d}", working - first, working, + b.fLeft, b.fTop, b.fRight, b.fBottom, + irect.fLeft, irect.fTop, irect.fRight, irect.fBottom); +#endif + working->mElapsed = 0; + continue; + } + int saved = canvas->save(); + SkRect pathBounds; + if (area.isComplex()) { + SkPath pathClip; + area.getBoundaryPath(&pathClip); + canvas->clipPath(pathClip); + pathBounds = pathClip.getBounds(); + } else { + pathBounds.set(area.getBounds()); + canvas->clipRect(pathBounds); + } + canvas->translate(pathBounds.fLeft, pathBounds.fTop); + canvas->save(); + uint32_t startTime = getThreadMsec(); + canvas->drawPicture(*working->mPicture); + size_t elapsed = working->mElapsed = getThreadMsec() - startTime; + working->mWroteElapsed = true; + if (maxElapsed < elapsed && (pathBounds.width() >= MIN_SPLITTABLE || + pathBounds.height() >= MIN_SPLITTABLE)) + maxElapsed = elapsed; + canvas->restoreToCount(saved); +#define DRAW_TEST_IMAGE 01 +#if DRAW_TEST_IMAGE && PICTURE_SET_DEBUG + SkColor color = 0x3f000000 | (0xffffff & (unsigned) working); + canvas->drawColor(color); + SkPaint paint; + color ^= 0x00ffffff; + paint.setColor(color); + char location[256]; + for (int x = area.getBounds().fLeft & ~0x3f; + x < area.getBounds().fRight; x += 0x40) { + for (int y = area.getBounds().fTop & ~0x3f; + y < area.getBounds().fBottom; y += 0x40) { + int len = snprintf(location, sizeof(location) - 1, "(%d,%d)", x, y); + canvas->drawText(location, len, x, y, paint); + } + } +#endif + DBG_SET_LOGD("[%d] %p working->mArea={%d,%d,%d,%d} elapsed=%d base=%s", + working - first, working, + area.getBounds().fLeft, area.getBounds().fTop, + area.getBounds().fRight, area.getBounds().fBottom, + working->mElapsed, working->mBase ? "true" : "false"); + } + // dump(__FUNCTION__); + return maxElapsed >= MAX_DRAW_TIME; +} + +void PictureSet::dump(const char* label) const +{ +#if PICTURE_SET_DUMP + DBG_SET_LOGD("%p %s (%d) (w=%d,h=%d)", this, label, mPictures.size(), + mWidth, mHeight); + const Pictures* last = mPictures.end(); + for (const Pictures* working = mPictures.begin(); working != last; working++) { + const SkIRect& bounds = working->mArea.getBounds(); + const SkIRect& unsplit = working->mUnsplit; + MeasureStream measure; + if (working->mPicture != NULL) + working->mPicture->serialize(&measure); + LOGD(" [%d]" + " mArea.bounds={%d,%d,r=%d,b=%d}" + " mPicture=%p" + " mUnsplit={%d,%d,r=%d,b=%d}" + " mElapsed=%d" + " mSplit=%s" + " mWroteElapsed=%s" + " mBase=%s" + " pict-size=%d", + working - mPictures.begin(), + bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, + working->mPicture, + unsplit.fLeft, unsplit.fTop, unsplit.fRight, unsplit.fBottom, + working->mElapsed, working->mSplit ? "true" : "false", + working->mWroteElapsed ? "true" : "false", + working->mBase ? "true" : "false", + measure.mTotal); + } +#endif +} + +class IsEmptyBounder : public SkBounder { + virtual bool onIRect(const SkIRect& rect) { + return false; + } +}; + +class IsEmptyCanvas : public SkCanvas { +public: + IsEmptyCanvas(SkBounder* bounder, SkPicture* picture) : + mPicture(picture), mEmpty(true) { + setBounder(bounder); + } + + void notEmpty() { + mEmpty = false; + mPicture->abortPlayback(); + } + + virtual bool clipPath(const SkPath&, SkRegion::Op) { + // this can be expensive to actually do, and doesn't affect the + // question of emptiness, so we make it a no-op + return true; + } + + virtual void commonDrawBitmap(const SkBitmap& bitmap, const SkIRect* rect, + const SkMatrix& , const SkPaint& ) { + if (bitmap.width() <= 1 || bitmap.height() <= 1) + return; + DBG_SET_LOGD("abort {%d,%d}", bitmap.width(), bitmap.height()); + notEmpty(); + } + + virtual void drawPaint(const SkPaint& paint) { + } + + virtual void drawPath(const SkPath& , const SkPaint& paint) { + DBG_SET_LOG("abort"); + notEmpty(); + } + + virtual void drawPoints(PointMode , size_t , const SkPoint [], + const SkPaint& paint) { + } + + virtual void drawRect(const SkRect& , const SkPaint& paint) { + // wait for visual content + if (paint.getColor() != SK_ColorWHITE) + notEmpty(); + } + + virtual void drawSprite(const SkBitmap& , int , int , + const SkPaint* paint = NULL) { + DBG_SET_LOG("abort"); + notEmpty(); + } + + virtual void drawText(const void* , size_t byteLength, SkScalar , + SkScalar , const SkPaint& paint) { + DBG_SET_LOGD("abort %d", byteLength); + notEmpty(); + } + + virtual void drawPosText(const void* , size_t byteLength, + const SkPoint [], const SkPaint& paint) { + DBG_SET_LOGD("abort %d", byteLength); + notEmpty(); + } + + virtual void drawPosTextH(const void* , size_t byteLength, + const SkScalar [], SkScalar , + const SkPaint& paint) { + DBG_SET_LOGD("abort %d", byteLength); + notEmpty(); + } + + virtual void drawTextOnPath(const void* , size_t byteLength, + const SkPath& , const SkMatrix* , + const SkPaint& paint) { + DBG_SET_LOGD("abort %d", byteLength); + notEmpty(); + } + + virtual void drawPicture(SkPicture& picture) { + SkCanvas::drawPicture(picture); + } + + SkPicture* mPicture; + bool mEmpty; +}; + +bool PictureSet::emptyPicture(SkPicture* picture) const +{ + IsEmptyBounder isEmptyBounder; + IsEmptyCanvas checker(&isEmptyBounder, picture); + SkBitmap bitmap; + bitmap.setConfig(SkBitmap::kARGB_8888_Config, mWidth, mHeight); + checker.setBitmapDevice(bitmap); + checker.drawPicture(*picture); + return checker.mEmpty; +} + +bool PictureSet::isEmpty() const +{ + const Pictures* last = mPictures.end(); + for (const Pictures* working = mPictures.begin(); working != last; working++) { + if (!working->mEmpty) + return false; + } + return true; +} + +bool PictureSet::reuseSubdivided(const SkRegion& inval) +{ + validate(__FUNCTION__); + if (inval.isComplex()) + return false; + Pictures* working, * last = mPictures.end(); + const SkIRect& invalBounds = inval.getBounds(); + bool steal = false; + for (working = mPictures.begin(); working != last; working++) { + if (working->mSplit && invalBounds == working->mUnsplit) { + steal = true; + continue; + } + if (steal == false) + continue; + SkRegion temp = SkRegion(inval); + temp.op(working->mArea, SkRegion::kIntersect_Op); + if (temp.isEmpty() || temp == working->mArea) + continue; + return false; + } + if (steal == false) + return false; + for (working = mPictures.begin(); working != last; working++) { + if ((working->mSplit == false || invalBounds != working->mUnsplit) && + inval.contains(working->mArea) == false) + continue; + SkSafeUnref(working->mPicture); + working->mPicture = NULL; + } + return true; +} + +void PictureSet::set(const PictureSet& src) +{ + DBG_SET_LOGD("start %p src=%p", this, &src); + clear(); + mWidth = src.mWidth; + mHeight = src.mHeight; + const Pictures* last = src.mPictures.end(); + for (const Pictures* working = src.mPictures.begin(); working != last; working++) + add(working); + // dump(__FUNCTION__); + validate(__FUNCTION__); + DBG_SET_LOG("end"); +} + +void PictureSet::setDrawTimes(const PictureSet& src) +{ + validate(__FUNCTION__); + if (mWidth != src.mWidth || mHeight != src.mHeight) + return; + Pictures* last = mPictures.end(); + Pictures* working = mPictures.begin(); + if (working == last) + return; + const Pictures* srcLast = src.mPictures.end(); + const Pictures* srcWorking = src.mPictures.begin(); + for (; srcWorking != srcLast; srcWorking++) { + if (srcWorking->mWroteElapsed == false) + continue; + while ((srcWorking->mArea != working->mArea || + srcWorking->mPicture != working->mPicture)) { + if (++working == last) + return; + } + DBG_SET_LOGD("%p [%d] [%d] {%d,%d,r=%d,b=%d} working->mElapsed=%d <- %d", + this, working - mPictures.begin(), srcWorking - src.mPictures.begin(), + working->mArea.getBounds().fLeft, working->mArea.getBounds().fTop, + working->mArea.getBounds().fRight, working->mArea.getBounds().fBottom, + working->mElapsed, srcWorking->mElapsed); + working->mElapsed = srcWorking->mElapsed; + } +} + +void PictureSet::setPicture(size_t i, SkPicture* p) +{ + SkSafeUnref(mPictures[i].mPicture); + mPictures[i].mPicture = p; + mPictures[i].mEmpty = emptyPicture(p); +} + +void PictureSet::split(PictureSet* out) const +{ + dump(__FUNCTION__); + DBG_SET_LOGD("%p", this); + SkIRect totalBounds; + out->mWidth = mWidth; + out->mHeight = mHeight; + totalBounds.set(0, 0, mWidth, mHeight); + SkRegion* total = new SkRegion(totalBounds); + const Pictures* last = mPictures.end(); + const Pictures* working; + uint32_t balance = 0; + int multiUnsplitFastPictures = 0; // > 1 has more than 1 + for (working = mPictures.begin(); working != last; working++) { + if (working->mElapsed >= MAX_DRAW_TIME || working->mSplit) + continue; + if (++multiUnsplitFastPictures > 1) + break; + } + for (working = mPictures.begin(); working != last; working++) { + uint32_t elapsed = working->mElapsed; + if (elapsed < MAX_DRAW_TIME) { + bool split = working->mSplit; + DBG_SET_LOGD("elapsed=%d working=%p total->getBounds()=" + "{%d,%d,r=%d,b=%d} split=%s", elapsed, working, + total->getBounds().fLeft, total->getBounds().fTop, + total->getBounds().fRight, total->getBounds().fBottom, + split ? "true" : "false"); + if (multiUnsplitFastPictures <= 1 || split) { + total->op(working->mArea, SkRegion::kDifference_Op); + out->add(working->mArea, working->mPicture, elapsed, split, + working->mEmpty); + } else if (balance < elapsed) + balance = elapsed; + continue; + } + total->op(working->mArea, SkRegion::kDifference_Op); + const SkIRect& bounds = working->mArea.getBounds(); + int width = bounds.width(); + int height = bounds.height(); + int across = 1; + int down = 1; + while (height >= MIN_SPLITTABLE || width >= MIN_SPLITTABLE) { + if (height >= width) { + height >>= 1; + down <<= 1; + } else { + width >>= 1; + across <<= 1 ; + } + if ((elapsed >>= 1) < MAX_DRAW_TIME) + break; + } + width = bounds.width(); + height = bounds.height(); + int top = bounds.fTop; + for (int indexY = 0; indexY < down; ) { + int bottom = bounds.fTop + height * ++indexY / down; + int left = bounds.fLeft; + for (int indexX = 0; indexX < across; ) { + int right = bounds.fLeft + width * ++indexX / across; + SkIRect cBounds; + cBounds.set(left, top, right, bottom); + out->add(SkRegion(cBounds), (across | down) != 1 ? NULL : + working->mPicture, elapsed, true, + (across | down) != 1 ? false : working->mEmpty); + left = right; + } + top = bottom; + } + } + DBG_SET_LOGD("%p w=%d h=%d total->isEmpty()=%s multiUnsplitFastPictures=%d", + this, mWidth, mHeight, total->isEmpty() ? "true" : "false", + multiUnsplitFastPictures); + if (!total->isEmpty() && multiUnsplitFastPictures > 1) + out->add(*total, NULL, balance, false, false); + delete total; + validate(__FUNCTION__); + out->dump("split-out"); +} + +bool PictureSet::validate(const char* funct) const +{ + bool valid = true; +#if PICTURE_SET_VALIDATE + SkRegion all; + const Pictures* first = mPictures.begin(); + for (const Pictures* working = mPictures.end(); working != first; ) { + --working; + const SkPicture* pict = working->mPicture; + const SkRegion& area = working->mArea; + const SkIRect& bounds = area.getBounds(); + bool localValid = false; + if (working->mUnsplit.isEmpty()) + LOGD("%s working->mUnsplit.isEmpty()", funct); + else if (working->mUnsplit.contains(bounds) == false) + LOGD("%s working->mUnsplit.contains(bounds) == false", funct); + else if (working->mElapsed >= 1000) + LOGD("%s working->mElapsed >= 1000", funct); + else if ((working->mSplit & 0xfe) != 0) + LOGD("%s (working->mSplit & 0xfe) != 0", funct); + else if ((working->mWroteElapsed & 0xfe) != 0) + LOGD("%s (working->mWroteElapsed & 0xfe) != 0", funct); + else if (pict != NULL) { + int pictWidth = pict->width(); + int pictHeight = pict->height(); + if (pictWidth < bounds.width()) + LOGD("%s pictWidth=%d < bounds.width()=%d", funct, pictWidth, bounds.width()); + else if (pictHeight < bounds.height()) + LOGD("%s pictHeight=%d < bounds.height()=%d", funct, pictHeight, bounds.height()); + else if (working->mArea.isEmpty()) + LOGD("%s working->mArea.isEmpty()", funct); + else + localValid = true; + } else + localValid = true; + working->mArea.validate(); + if (localValid == false) { + if (all.contains(area) == true) + LOGD("%s all.contains(area) == true", funct); + else + localValid = true; + } + valid &= localValid; + all.op(area, SkRegion::kUnion_Op); + } + const SkIRect& allBounds = all.getBounds(); + if (valid) { + valid = false; + if (allBounds.width() != mWidth) + LOGD("%s allBounds.width()=%d != mWidth=%d", funct, allBounds.width(), mWidth); + else if (allBounds.height() != mHeight) + LOGD("%s allBounds.height()=%d != mHeight=%d", funct, allBounds.height(), mHeight); + else + valid = true; + } + while (valid == false) + ; +#endif + return valid; +} + +} /* namespace android */ diff --git a/Source/WebKit/android/jni/PictureSet.h b/Source/WebKit/android/jni/PictureSet.h new file mode 100644 index 0000000..b177958 --- /dev/null +++ b/Source/WebKit/android/jni/PictureSet.h @@ -0,0 +1,104 @@ +/* + * Copyright 2008, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef PICTURESET_H +#define PICTURESET_H + +#define PICTURE_SET_DUMP 0 +#define PICTURE_SET_DEBUG 0 +#define PICTURE_SET_VALIDATE 0 + +#if PICTURE_SET_DEBUG +#define DBG_SET_LOG(message) LOGD("%s %s", __FUNCTION__, message) +#define DBG_SET_LOGD(format, ...) LOGD("%s " format, __FUNCTION__, __VA_ARGS__) +#define DEBUG_SET_UI_LOGD(...) LOGD(__VA_ARGS__) +#else +#define DBG_SET_LOG(message) ((void)0) +#define DBG_SET_LOGD(format, ...) ((void)0) +#define DEBUG_SET_UI_LOGD(...) ((void)0) +#endif + +#include "jni.h" +#include "SkRegion.h" +#include + +class SkCanvas; +class SkPicture; +class SkIRect; + +namespace android { + + class PictureSet { + public: + PictureSet(); + PictureSet(const PictureSet& src) { set(src); } + virtual ~PictureSet(); + void add(const SkRegion& area, SkPicture* picture, + uint32_t elapsed, bool split) + { + add(area, picture, elapsed, split, emptyPicture(picture)); + } + void add(const SkRegion& area, SkPicture* picture, + uint32_t elapsed, bool split, bool empty); + const SkIRect& bounds(size_t i) const { + return mPictures[i].mArea.getBounds(); } + bool build(); + // Update mWidth/mHeight, and adds any additional inval region + void checkDimensions(int width, int height, SkRegion* inval); + void clear(); + bool draw(SkCanvas* ); + static PictureSet* GetNativePictureSet(JNIEnv* env, jobject jpic); + int height() const { return mHeight; } + bool isEmpty() const; // returns true if empty or only trivial content + bool reuseSubdivided(const SkRegion& ); + void set(const PictureSet& ); + void setDrawTimes(const PictureSet& ); + void setPicture(size_t i, SkPicture* p); + size_t size() const { return mPictures.size(); } + void split(PictureSet* result) const; + bool upToDate(size_t i) const { return mPictures[i].mPicture != NULL; } + int width() const { return mWidth; } + void dump(const char* label) const; + bool validate(const char* label) const; + private: + bool emptyPicture(SkPicture* ) const; // true if no text, images, paths + struct Pictures { + SkRegion mArea; + SkPicture* mPicture; + SkIRect mUnsplit; + uint32_t mElapsed; + bool mSplit : 8; + bool mWroteElapsed : 8; + bool mBase : 8; // true if nothing is drawn underneath this + bool mEmpty : 8; // true if the picture only draws white + }; + void add(const Pictures* temp); + WTF::Vector mPictures; + int mHeight; + int mWidth; + }; +} + +#endif diff --git a/Source/WebKit/android/jni/WebCoreFrameBridge.cpp b/Source/WebKit/android/jni/WebCoreFrameBridge.cpp new file mode 100644 index 0000000..15b6d20 --- /dev/null +++ b/Source/WebKit/android/jni/WebCoreFrameBridge.cpp @@ -0,0 +1,2125 @@ +/* + * 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 "WebCoreFrameBridge.h" + +#include "Arena.h" +#include "BackForwardList.h" +#include "MemoryCache.h" +#include "Chrome.h" +#include "ChromeClientAndroid.h" +#include "ChromiumInit.h" +#include "ContextMenuClientAndroid.h" +#include "DeviceMotionClientAndroid.h" +#include "DeviceOrientationClientAndroid.h" +#include "Document.h" +#include "DocumentLoader.h" +#include "DragClientAndroid.h" +#include "EditorClientAndroid.h" +#include "Element.h" +#include "FocusController.h" +#include "Font.h" +#include "Frame.h" +#include "FrameLoader.h" +#include "FrameLoaderClientAndroid.h" +#include "FrameLoadRequest.h" +#include "FrameTree.h" +#include "FrameView.h" +#include "GraphicsContext.h" +#include "HistoryItem.h" +#include "HTMLCollection.h" +#include "HTMLElement.h" +#include "HTMLFormElement.h" +#include "HTMLInputElement.h" +#include "HTMLNames.h" +#include "IconDatabase.h" +#include "Image.h" +#include "InspectorClientAndroid.h" +#include "KURL.h" +#include "Page.h" +#include "PageCache.h" +#include "PlatformString.h" +#include "RenderPart.h" +#include "RenderSkinAndroid.h" +#include "RenderTreeAsText.h" +#include "RenderView.h" +#include "ResourceHandle.h" +#include "ResourceHandleInternal.h" +#include "ScriptController.h" +#include "ScriptValue.h" +#include "SecurityOrigin.h" +#include "SelectionController.h" +#include "Settings.h" +#include "SubstituteData.h" +#include "UrlInterceptResponse.h" +#include "UserGestureIndicator.h" +#include "WebCache.h" +#include "WebCoreJni.h" +#include "WebCoreResourceLoader.h" +#include "WebHistory.h" +#include "WebIconDatabase.h" +#include "WebFrameView.h" +#include "WebUrlLoaderClient.h" +#include "WebViewCore.h" +#include "android_graphics.h" +#include "jni.h" +#include "wds/DebugServer.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if USE(JSC) +#include "GCController.h" +#include "JSDOMWindow.h" +#include "JavaInstanceJSC.h" +#include +#include +#include +#elif USE(V8) +#include "JavaNPObjectV8.h" +#include "JavaInstanceV8.h" +#include "V8Counters.h" +#endif // USE(JSC) + +#ifdef ANDROID_INSTRUMENT +#include "TimeCounter.h" +#endif + +#if ENABLE(ARCHIVE) +#include "WebArchiveAndroid.h" +#endif + +#if ENABLE(WEB_AUTOFILL) +#include "autofill/WebAutoFill.h" +#endif + +using namespace JSC::Bindings; + +static String* gUploadFileLabel; +static String* gResetLabel; +static String* gSubmitLabel; +static String* gNoFileChosenLabel; + +String* WebCore::PlatformBridge::globalLocalizedName( + WebCore::PlatformBridge::rawResId resId) +{ + switch (resId) { + case WebCore::PlatformBridge::FileUploadLabel: + return gUploadFileLabel; + case WebCore::PlatformBridge::ResetLabel: + return gResetLabel; + case WebCore::PlatformBridge::SubmitLabel: + return gSubmitLabel; + case WebCore::PlatformBridge::FileUploadNoFileChosenLabel: + return gNoFileChosenLabel; + + default: + return 0; + } +} +/** + * Instantiate the localized name desired. + */ +void initGlobalLocalizedName(WebCore::PlatformBridge::rawResId resId, + android::WebFrame* webFrame) +{ + String** pointer; + switch (resId) { + case WebCore::PlatformBridge::FileUploadLabel: + pointer = &gUploadFileLabel; + break; + case WebCore::PlatformBridge::ResetLabel: + pointer = &gResetLabel; + break; + case WebCore::PlatformBridge::SubmitLabel: + pointer = &gSubmitLabel; + break; + case WebCore::PlatformBridge::FileUploadNoFileChosenLabel: + pointer = &gNoFileChosenLabel; + break; + default: + return; + } + if (!(*pointer) && webFrame) { + (*pointer) = new String(webFrame->getRawResourceFilename(resId).impl()); + } +} + +namespace android { + +// ---------------------------------------------------------------------------- + +#define WEBCORE_MEMORY_CAP 15 * 1024 * 1024 + +// ---------------------------------------------------------------------------- + +struct WebFrame::JavaBrowserFrame +{ + jweak mObj; + jweak mHistoryList; // WebBackForwardList object + jmethodID mStartLoadingResource; + jmethodID mMaybeSavePassword; + jmethodID mShouldInterceptRequest; + jmethodID mLoadStarted; + jmethodID mTransitionToCommitted; + jmethodID mLoadFinished; + jmethodID mReportError; + jmethodID mSetTitle; + jmethodID mWindowObjectCleared; + jmethodID mSetProgress; + jmethodID mDidReceiveIcon; + jmethodID mDidReceiveTouchIconUrl; + jmethodID mUpdateVisitedHistory; + jmethodID mHandleUrl; + jmethodID mCreateWindow; + jmethodID mCloseWindow; + jmethodID mDecidePolicyForFormResubmission; + jmethodID mRequestFocus; + jmethodID mGetRawResFilename; + jmethodID mDensity; + jmethodID mGetFileSize; + jmethodID mGetFile; + jmethodID mDidReceiveAuthenticationChallenge; + jmethodID mReportSslCertError; + jmethodID mDownloadStart; + jmethodID mDidReceiveData; + jmethodID mDidFinishLoading; + jmethodID mSetCertificate; + jmethodID mShouldSaveFormData; + jmethodID mSaveFormData; + jmethodID mAutoLogin; + AutoJObject frame(JNIEnv* env) { + return getRealObject(env, mObj); + } + AutoJObject history(JNIEnv* env) { + return getRealObject(env, mHistoryList); + } +}; + +static jfieldID gFrameField; +#define GET_NATIVE_FRAME(env, obj) ((WebCore::Frame*)env->GetIntField(obj, gFrameField)) +#define SET_NATIVE_FRAME(env, obj, frame) (env->SetIntField(obj, gFrameField, frame)) + +// ---------------------------------------------------------------------------- + +WebFrame::WebFrame(JNIEnv* env, jobject obj, jobject historyList, WebCore::Page* page) + : mPage(page) +{ + jclass clazz = env->GetObjectClass(obj); + 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 = + env->GetMethodID(clazz, "shouldInterceptRequest", + "(Ljava/lang/String;)Landroid/webkit/WebResourceResponse;"); + mJavaFrame->mLoadStarted = env->GetMethodID(clazz, "loadStarted", + "(Ljava/lang/String;Landroid/graphics/Bitmap;IZ)V"); + mJavaFrame->mTransitionToCommitted = env->GetMethodID(clazz, "transitionToCommitted", + "(IZ)V"); + mJavaFrame->mLoadFinished = env->GetMethodID(clazz, "loadFinished", + "(Ljava/lang/String;IZ)V"); + mJavaFrame->mReportError = env->GetMethodID(clazz, "reportError", + "(ILjava/lang/String;Ljava/lang/String;)V"); + mJavaFrame->mSetTitle = env->GetMethodID(clazz, "setTitle", + "(Ljava/lang/String;)V"); + mJavaFrame->mWindowObjectCleared = env->GetMethodID(clazz, "windowObjectCleared", + "(I)V"); + mJavaFrame->mSetProgress = env->GetMethodID(clazz, "setProgress", + "(I)V"); + mJavaFrame->mDidReceiveIcon = env->GetMethodID(clazz, "didReceiveIcon", + "(Landroid/graphics/Bitmap;)V"); + mJavaFrame->mDidReceiveTouchIconUrl = env->GetMethodID(clazz, "didReceiveTouchIconUrl", + "(Ljava/lang/String;Z)V"); + mJavaFrame->mUpdateVisitedHistory = env->GetMethodID(clazz, "updateVisitedHistory", + "(Ljava/lang/String;Z)V"); + mJavaFrame->mHandleUrl = env->GetMethodID(clazz, "handleUrl", + "(Ljava/lang/String;)Z"); + mJavaFrame->mCreateWindow = env->GetMethodID(clazz, "createWindow", + "(ZZ)Landroid/webkit/BrowserFrame;"); + mJavaFrame->mCloseWindow = env->GetMethodID(clazz, "closeWindow", + "(Landroid/webkit/WebViewCore;)V"); + mJavaFrame->mDecidePolicyForFormResubmission = env->GetMethodID(clazz, + "decidePolicyForFormResubmission", "(I)V"); + mJavaFrame->mRequestFocus = env->GetMethodID(clazz, "requestFocus", + "()V"); + mJavaFrame->mGetRawResFilename = env->GetMethodID(clazz, "getRawResFilename", + "(I)Ljava/lang/String;"); + mJavaFrame->mDensity = env->GetMethodID(clazz, "density","()F"); + mJavaFrame->mGetFileSize = env->GetMethodID(clazz, "getFileSize", "(Ljava/lang/String;)I"); + mJavaFrame->mGetFile = env->GetMethodID(clazz, "getFile", "(Ljava/lang/String;[BII)I"); + mJavaFrame->mDidReceiveAuthenticationChallenge = env->GetMethodID(clazz, "didReceiveAuthenticationChallenge", + "(ILjava/lang/String;Ljava/lang/String;Z)V"); + mJavaFrame->mReportSslCertError = env->GetMethodID(clazz, "reportSslCertError", "(II[B)V"); + mJavaFrame->mDownloadStart = env->GetMethodID(clazz, "downloadStart", + "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;J)V"); + mJavaFrame->mDidReceiveData = env->GetMethodID(clazz, "didReceiveData", "([BI)V"); + mJavaFrame->mDidFinishLoading = env->GetMethodID(clazz, "didFinishLoading", "()V"); + mJavaFrame->mSetCertificate = env->GetMethodID(clazz, "setCertificate", "([B)V"); + mJavaFrame->mShouldSaveFormData = env->GetMethodID(clazz, "shouldSaveFormData", "()Z"); + mJavaFrame->mSaveFormData = env->GetMethodID(clazz, "saveFormData", "(Ljava/util/HashMap;)V"); + mJavaFrame->mAutoLogin = env->GetMethodID(clazz, "autoLogin", + "(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->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"); + + mUserAgent = WTF::String(); + mUserInitiatedAction = false; + mBlockNetworkLoads = false; + m_renderSkins = 0; +} + +WebFrame::~WebFrame() +{ + if (mJavaFrame->mObj) { + JNIEnv* env = getJNIEnv(); + env->DeleteWeakGlobalRef(mJavaFrame->mObj); + env->DeleteWeakGlobalRef(mJavaFrame->mHistoryList); + mJavaFrame->mObj = 0; + } + delete mJavaFrame; + delete m_renderSkins; +} + +WebFrame* WebFrame::getWebFrame(const WebCore::Frame* frame) +{ + FrameLoaderClientAndroid* client = + static_cast (frame->loader()->client()); + return client->webFrame(); +} + +static jobject createJavaMapFromHTTPHeaders(JNIEnv* env, const WebCore::HTTPHeaderMap& map) +{ + jclass mapClass = env->FindClass("java/util/HashMap"); + LOG_ASSERT(mapClass, "Could not find HashMap class!"); + jmethodID init = env->GetMethodID(mapClass, "", "(I)V"); + LOG_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"); + 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"); + + WebCore::HTTPHeaderMap::const_iterator end = map.end(); + for (WebCore::HTTPHeaderMap::const_iterator i = map.begin(); i != end; ++i) { + if (i->first.length() == 0 || i->second.length() == 0) + continue; + jstring key = wtfStringToJstring(env, i->first); + jstring val = wtfStringToJstring(env, i->second); + if (key && val) { + env->CallObjectMethod(hashMap, put, key, val); + } + env->DeleteLocalRef(key); + env->DeleteLocalRef(val); + } + + env->DeleteLocalRef(mapClass); + + return hashMap; +} + +// This class stores the URI and the size of each file for upload. The URI is +// stored so we do not have to create it again. The size is stored so we can +// compare the actual size of the file with the stated size. If the actual size +// is larger, we will not copy it, since we will not have enough space in our +// buffer. +class FileInfo { +public: + FileInfo(JNIEnv* env, const WTF::String& name) { + m_uri = wtfStringToJstring(env, name); + checkException(env); + m_size = 0; + m_env = env; + } + ~FileInfo() { + m_env->DeleteLocalRef(m_uri); + } + int getSize() { return m_size; } + jstring getUri() { return m_uri; } + void setSize(int size) { m_size = size; } +private: + // This is only a pointer to the JNIEnv* returned by + // JSC::Bindings::getJNIEnv(). Used to delete the jstring when finished. + JNIEnv* m_env; + jstring m_uri; + int m_size; +}; + +PassRefPtr +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()); + + WTF::String method = request.httpMethod(); + WebCore::HTTPHeaderMap headers = request.httpHeaderFields(); + + JNIEnv* env = getJNIEnv(); + 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(mJavaFrame->frame(env).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 NULL; + + PassRefPtr 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()); + + JNIEnv* env = getJNIEnv(); + jstring urlStr = wtfStringToJstring(env, url); + jobject response = env->CallObjectMethod(mJavaFrame->frame(env).get(), mJavaFrame->mShouldInterceptRequest, urlStr); + env->DeleteLocalRef(urlStr); + if (response == 0) + return 0; + return new UrlInterceptResponse(env, response); +} + +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()); + JNIEnv* env = getJNIEnv(); + + jstring descStr = wtfStringToJstring(env, description); + jstring failUrl = wtfStringToJstring(env, failingUrl); + env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mReportError, + errorCode, descStr, failUrl); + env->DeleteLocalRef(descStr); + env->DeleteLocalRef(failUrl); +} + +void +WebFrame::loadStarted(WebCore::Frame* frame) +{ +#ifdef ANDROID_INSTRUMENT + TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); +#endif + // activeDocumentLoader() can return null. + DocumentLoader* documentLoader = frame->loader()->activeDocumentLoader(); + if (documentLoader == NULL) + return; + + const WebCore::KURL& url = documentLoader->url(); + if (url.isEmpty()) + return; + LOGV("::WebCore:: loadStarted %s", url.string().ascii().data()); + + bool isMainFrame = (!frame->tree() || !frame->tree()->parent()); + WebCore::FrameLoadType loadType = frame->loader()->loadType(); + + if (loadType == WebCore::FrameLoadTypeReplace || + (loadType == WebCore::FrameLoadTypeRedirectWithLockedBackForwardList && + !isMainFrame)) + return; + + JNIEnv* env = getJNIEnv(); + const WTF::String& urlString = url.string(); + // If this is the main frame and we already have a favicon in the database, + // send it along with the page started notification. + jobject favicon = NULL; + if (isMainFrame) { + WebCore::Image* icon = WebCore::iconDatabase()->iconForPageURL(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()); + } + jstring urlStr = wtfStringToJstring(env, urlString); + + env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mLoadStarted, urlStr, favicon, + (int)loadType, isMainFrame); + checkException(env); + env->DeleteLocalRef(urlStr); + if (favicon) + env->DeleteLocalRef(favicon); + + // Inform the client that the main frame has started a new load. + if (isMainFrame && mPage) { + Chrome* chrome = mPage->chrome(); + if (chrome) { + ChromeClientAndroid* client = static_cast(chrome->client()); + if (client) + client->onMainFrameLoadStarted(); + } + } +} + +void +WebFrame::transitionToCommitted(WebCore::Frame* frame) +{ +#ifdef ANDROID_INSTRUMENT + TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); +#endif + JNIEnv* env = getJNIEnv(); + WebCore::FrameLoadType loadType = frame->loader()->loadType(); + bool isMainFrame = (!frame->tree() || !frame->tree()->parent()); + env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mTransitionToCommitted, + (int)loadType, isMainFrame); + checkException(env); +} + +void +WebFrame::didFinishLoad(WebCore::Frame* frame) +{ +#ifdef ANDROID_INSTRUMENT + TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); +#endif + JNIEnv* env = getJNIEnv(); + + // activeDocumentLoader() can return null. + WebCore::FrameLoader* loader = frame->loader(); + DocumentLoader* documentLoader = loader->activeDocumentLoader(); + if (documentLoader == NULL) + return; + + const WebCore::KURL& url = documentLoader->url(); + if (url.isEmpty()) + return; + LOGV("::WebCore:: didFinishLoad %s", url.string().ascii().data()); + + bool isMainFrame = (!frame->tree() || !frame->tree()->parent()); + WebCore::FrameLoadType loadType = loader->loadType(); + const WTF::String& urlString = url.string(); + jstring urlStr = wtfStringToJstring(env, urlString); + env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mLoadFinished, urlStr, + (int)loadType, isMainFrame); + checkException(env); + env->DeleteLocalRef(urlStr); +} + +void +WebFrame::addHistoryItem(WebCore::HistoryItem* item) +{ +#ifdef ANDROID_INSTRUMENT + TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); +#endif + LOGV("::WebCore:: addHistoryItem"); + JNIEnv* env = getJNIEnv(); + WebHistory::AddItem(mJavaFrame->history(env), item); +} + +void +WebFrame::removeHistoryItem(int index) +{ +#ifdef ANDROID_INSTRUMENT + TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); +#endif + LOGV("::WebCore:: removeHistoryItem at %d", index); + JNIEnv* env = getJNIEnv(); + WebHistory::RemoveItem(mJavaFrame->history(env), index); +} + +void +WebFrame::updateHistoryIndex(int newIndex) +{ +#ifdef ANDROID_INSTRUMENT + TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); +#endif + LOGV("::WebCore:: updateHistoryIndex to %d", newIndex); + JNIEnv* env = getJNIEnv(); + WebHistory::UpdateHistoryIndex(mJavaFrame->history(env), newIndex); +} + +void +WebFrame::setTitle(const WTF::String& title) +{ +#ifdef ANDROID_INSTRUMENT + TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); +#endif +#ifndef NDEBUG + LOGV("setTitle(%s)", title.ascii().data()); +#endif + JNIEnv* env = getJNIEnv(); + jstring jTitleStr = wtfStringToJstring(env, title); + + env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mSetTitle, jTitleStr); + checkException(env); + env->DeleteLocalRef(jTitleStr); +} + +void +WebFrame::windowObjectCleared(WebCore::Frame* frame) +{ +#ifdef ANDROID_INSTRUMENT + TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); +#endif + LOGV("::WebCore:: windowObjectCleared"); + JNIEnv* env = getJNIEnv(); + + env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mWindowObjectCleared, (int)frame); + checkException(env); +} + +void +WebFrame::setProgress(float newProgress) +{ +#ifdef ANDROID_INSTRUMENT + TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); +#endif + JNIEnv* env = getJNIEnv(); + int progress = (int) (100 * newProgress); + env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mSetProgress, progress); + checkException(env); +} + +const WTF::String +WebFrame::userAgentForURL(const WebCore::KURL* url) +{ + return mUserAgent; +} + +void +WebFrame::didReceiveIcon(WebCore::Image* icon) +{ +#ifdef ANDROID_INSTRUMENT + TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); +#endif + LOG_ASSERT(icon, "DidReceiveIcon called without an image!"); + JNIEnv* env = getJNIEnv(); + jobject bitmap = webcoreImageToJavaBitmap(env, icon); + if (!bitmap) + return; + + env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mDidReceiveIcon, bitmap); + env->DeleteLocalRef(bitmap); + checkException(env); +} + +void +WebFrame::didReceiveTouchIconURL(const WTF::String& url, bool precomposed) +{ +#ifdef ANDROID_INSTRUMENT + TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); +#endif + JNIEnv* env = getJNIEnv(); + jstring jUrlStr = wtfStringToJstring(env, url); + + env->CallVoidMethod(mJavaFrame->frame(env).get(), + mJavaFrame->mDidReceiveTouchIconUrl, jUrlStr, precomposed); + env->DeleteLocalRef(jUrlStr); + checkException(env); +} + +void +WebFrame::updateVisitedHistory(const WebCore::KURL& url, bool reload) +{ +#ifdef ANDROID_INSTRUMENT + TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); +#endif + const WTF::String& urlStr = url.string(); + JNIEnv* env = getJNIEnv(); + jstring jUrlStr = wtfStringToJstring(env, urlStr); + + env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mUpdateVisitedHistory, jUrlStr, reload); + env->DeleteLocalRef(jUrlStr); + checkException(env); +} + +bool +WebFrame::canHandleRequest(const WebCore::ResourceRequest& request) +{ +#ifdef ANDROID_INSTRUMENT + TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); +#endif + // always handle "POST" in place + if (equalIgnoringCase(request.httpMethod(), "POST")) + return true; + const WebCore::KURL& requestUrl = request.url(); + bool isUserGesture = UserGestureIndicator::processingUserGesture(); + if (!mUserInitiatedAction && !isUserGesture && + (requestUrl.protocolIs("http") || requestUrl.protocolIs("https") || + requestUrl.protocolIs("file") || requestUrl.protocolIs("about") || + WebCore::protocolIsJavaScript(requestUrl.string()))) + return true; + const WTF::String& url = requestUrl.string(); + // Empty urls should not be sent to java + if (url.isEmpty()) + return true; + JNIEnv* env = getJNIEnv(); + jstring jUrlStr = wtfStringToJstring(env, url); + + // check to see whether browser app wants to hijack url loading. + // if browser app handles the url, we will return false to bail out WebCore loading + jboolean ret = env->CallBooleanMethod(mJavaFrame->frame(env).get(), mJavaFrame->mHandleUrl, jUrlStr); + checkException(env); + env->DeleteLocalRef(jUrlStr); + return (ret == 0); +} + +bool +WebFrame::shouldSaveFormData() +{ + JNIEnv* env = getJNIEnv(); + jboolean ret = env->CallBooleanMethod(mJavaFrame->frame(env).get(), + mJavaFrame->mShouldSaveFormData); + checkException(env); + return ret; +} + +WebCore::Frame* +WebFrame::createWindow(bool dialog, bool userGesture) +{ +#ifdef ANDROID_INSTRUMENT + TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); +#endif + JNIEnv* env = getJNIEnv(); + jobject obj = env->CallObjectMethod(mJavaFrame->frame(env).get(), + mJavaFrame->mCreateWindow, dialog, userGesture); + if (obj) { + WebCore::Frame* frame = GET_NATIVE_FRAME(env, obj); + return frame; + } + return NULL; +} + +void +WebFrame::requestFocus() const +{ +#ifdef ANDROID_INSTRUMENT + TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); +#endif + JNIEnv* env = getJNIEnv(); + env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mRequestFocus); + checkException(env); +} + +void +WebFrame::closeWindow(WebViewCore* webViewCore) +{ +#ifdef ANDROID_INSTRUMENT + TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); +#endif + assert(webViewCore); + JNIEnv* env = getJNIEnv(); + env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mCloseWindow, + webViewCore->getJavaObject().get()); +} + +struct PolicyFunctionWrapper { + WebCore::FramePolicyFunction func; +}; + +void +WebFrame::decidePolicyForFormResubmission(WebCore::FramePolicyFunction func) +{ +#ifdef ANDROID_INSTRUMENT + TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); +#endif + JNIEnv* env = getJNIEnv(); + PolicyFunctionWrapper* p = new PolicyFunctionWrapper; + p->func = func; + env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mDecidePolicyForFormResubmission, p); +} + +WTF::String +WebFrame::getRawResourceFilename(WebCore::PlatformBridge::rawResId id) const +{ + JNIEnv* env = getJNIEnv(); + jstring ret = (jstring) env->CallObjectMethod(mJavaFrame->frame(env).get(), + mJavaFrame->mGetRawResFilename, (int)id); + + return jstringToWtfString(env, ret); +} + +float +WebFrame::density() const +{ + JNIEnv* env = getJNIEnv(); + jfloat dpi = env->CallFloatMethod(mJavaFrame->frame(env).get(), mJavaFrame->mDensity); + checkException(env); + return dpi; +} + +#if USE(CHROME_NETWORK_STACK) +void +WebFrame::didReceiveAuthenticationChallenge(WebUrlLoaderClient* client, const std::string& host, const std::string& realm, bool useCachedCredentials) +{ +#ifdef ANDROID_INSTRUMENT + TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); +#endif + JNIEnv* env = getJNIEnv(); + int jHandle = reinterpret_cast(client); + jstring jHost = stdStringToJstring(env, host, true); + jstring jRealm = stdStringToJstring(env, realm, true); + + env->CallVoidMethod(mJavaFrame->frame(env).get(), + mJavaFrame->mDidReceiveAuthenticationChallenge, jHandle, jHost, jRealm, useCachedCredentials); + env->DeleteLocalRef(jHost); + env->DeleteLocalRef(jRealm); + checkException(env); +} +#endif + +void +WebFrame::reportSslCertError(WebUrlLoaderClient* client, int cert_error, const std::string& cert) +{ +#ifdef ANDROID_INSTRUMENT + TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); +#endif + JNIEnv* env = getJNIEnv(); + int jHandle = reinterpret_cast(client); + + int len = cert.length(); + jbyteArray jCert = env->NewByteArray(len); + jbyte* bytes = env->GetByteArrayElements(jCert, NULL); + cert.copy(reinterpret_cast(bytes), len); + + env->CallVoidMethod(mJavaFrame->frame(env).get(), + mJavaFrame->mReportSslCertError, jHandle, cert_error, jCert); + env->DeleteLocalRef(jCert); + checkException(env); +} + +#if USE(CHROME_NETWORK_STACK) +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(); + jstring jUrl = stdStringToJstring(env, url, true); + jstring jUserAgent = stdStringToJstring(env, userAgent, true); + jstring jContentDisposition = stdStringToJstring(env, contentDisposition, true); + jstring jMimetype = stdStringToJstring(env, mimetype, true); + + env->CallVoidMethod(mJavaFrame->frame(env).get(), + mJavaFrame->mDownloadStart, jUrl, jUserAgent, jContentDisposition, jMimetype, contentLength); + + env->DeleteLocalRef(jUrl); + env->DeleteLocalRef(jUserAgent); + env->DeleteLocalRef(jContentDisposition); + env->DeleteLocalRef(jMimetype); + checkException(env); +} + +void +WebFrame::didReceiveData(const char* data, int size) { +#ifdef ANDROID_INSTRUMENT + TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); +#endif + JNIEnv* env = getJNIEnv(); + + jbyteArray jData = env->NewByteArray(size); + jbyte* bytes = env->GetByteArrayElements(jData, NULL); + memcpy(reinterpret_cast(bytes), data, size); + + env->CallVoidMethod(mJavaFrame->frame(env).get(), + mJavaFrame->mDidReceiveData, jData, size); + env->DeleteLocalRef(jData); + checkException(env); +} + +void +WebFrame::didFinishLoading() { +#ifdef ANDROID_INSTRUMENT + TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); +#endif + JNIEnv* env = getJNIEnv(); + + env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mDidFinishLoading); + checkException(env); +} + +#endif + +#if USE(CHROME_NETWORK_STACK) +void WebFrame::setCertificate(const std::string& cert) +{ +#ifdef ANDROID_INSTRUMENT + TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); +#endif + JNIEnv* env = getJNIEnv(); + + int len = cert.length(); + jbyteArray jCert = env->NewByteArray(len); + jbyte* bytes = env->GetByteArrayElements(jCert, NULL); + cert.copy(reinterpret_cast(bytes), len); + + env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mSetCertificate, jCert); + + env->DeleteLocalRef(jCert); + checkException(env); +} +#endif + +void WebFrame::autoLogin(const std::string& loginHeader) +{ +#ifdef ANDROID_INSTRUMENT + TimeCounterAuto counter(TimerCoutner::JavaCallbackTimeCounter); +#endif + WTF::String header(loginHeader.c_str(), loginHeader.length()); + WTF::Vector split; + header.split('&', split); + if (!split.isEmpty()) { + WTF::String realm; + WTF::String account; + WTF::String args; + int len = split.size(); + while (len--) { + WTF::String& str = split[len]; + size_t equals = str.find('='); + if (equals == WTF::notFound) + continue; + + WTF::String* result = 0; + if (str.startsWith("realm", false)) + result = &realm; + else if (str.startsWith("account", false)) + result = &account; + else if (str.startsWith("args", false)) + result = &args; + + if (result) + // Decode url escape sequences before sending to the app. + *result = WebCore::decodeURLEscapeSequences(str.substring(equals + 1)); + } + + // realm and args are required parameters. + if (realm.isEmpty() || args.isEmpty()) + return; + + JNIEnv* env = getJNIEnv(); + jstring jRealm = wtfStringToJstring(env, realm, true); + jstring jAccount = wtfStringToJstring(env, account); + jstring jArgs = wtfStringToJstring(env, args, true); + env->CallVoidMethod(mJavaFrame->frame(env).get(), + mJavaFrame->mAutoLogin, jRealm, jAccount, jArgs); + } +} + +void WebFrame::maybeSavePassword(WebCore::Frame* frame, const WebCore::ResourceRequest& request) +{ + if (request.httpMethod() != "POST") + return; + + WTF::String username; + WTF::String password; + if (!getUsernamePasswordFromDom(frame, username, password)) + return; + + JNIEnv* env = getJNIEnv(); + jstring jUsername = wtfStringToJstring(env, username); + jstring jPassword = wtfStringToJstring(env, password); + jbyteArray jPostData = getPostData(request); + if (jPostData) { + env->CallVoidMethod(mJavaFrame->frame(env).get(), + mJavaFrame->mMaybeSavePassword, jPostData, jUsername, jPassword); + } + + env->DeleteLocalRef(jPostData); + env->DeleteLocalRef(jUsername); + env->DeleteLocalRef(jPassword); + checkException(env); +} + +bool WebFrame::getUsernamePasswordFromDom(WebCore::Frame* frame, WTF::String& username, WTF::String& password) +{ + bool found = false; + WTF::PassRefPtr form = frame->document()->forms(); + WebCore::Node* node = form->firstItem(); + while (node && !found && !node->namespaceURI().isNull() && + !node->namespaceURI().isEmpty()) { + const WTF::Vector& elements = + ((WebCore::HTMLFormElement*)node)->associatedElements(); + size_t size = elements.size(); + for (size_t i = 0; i< size && !found; i++) { + WebCore::HTMLElement* e = toHTMLElement(elements[i]); + if (e->hasLocalName(WebCore::HTMLNames::inputTag)) { + WebCore::HTMLInputElement* input = (WebCore::HTMLInputElement*)e; + if (input->autoComplete() == false) + continue; + if (input->isPasswordField()) + password = input->value(); + else if (input->isTextField() || input->isEmailField()) + username = input->value(); + if (!username.isNull() && !password.isNull()) + found = true; + } + } + node = form->nextItem(); + } + return found; +} + +jbyteArray WebFrame::getPostData(const WebCore::ResourceRequest& request) +{ + jbyteArray jPostDataStr = NULL; + WebCore::FormData* formdata = request.httpBody(); + if (formdata) { + JNIEnv* env = getJNIEnv(); + AutoJObject obj = mJavaFrame->frame(env); + + // We can use the formdata->flatten() but it will result in two + // memcpys, first through loading up the vector with the form data + // then another to copy it out of the vector and into the java byte + // array. Instead, we copy the form data ourselves below saving a + // memcpy. + const WTF::Vector& elements = + formdata->elements(); + + // Sizing pass + int size = 0; + size_t n = elements.size(); + FileInfo** fileinfos = new FileInfo*[n]; + for (size_t i = 0; i < n; ++i) { + fileinfos[i] = 0; + const WebCore::FormDataElement& e = elements[i]; + if (e.m_type == WebCore::FormDataElement::data) { + size += e.m_data.size(); + } else if (e.m_type == WebCore::FormDataElement::encodedFile) { + fileinfos[i] = new FileInfo(env, e.m_filename); + int delta = env->CallIntMethod(obj.get(), + mJavaFrame->mGetFileSize, fileinfos[i]->getUri()); + checkException(env); + fileinfos[i]->setSize(delta); + size += delta; + } + } + + // Only create the byte array if there is POST data to pass up. + // The Java code is expecting null if there is no data. + if (size > 0) { + // Copy the actual form data. + jPostDataStr = env->NewByteArray(size); + if (jPostDataStr) { + // Write the form data to the java array. + jbyte* bytes = env->GetByteArrayElements(jPostDataStr, NULL); + int offset = 0; + for (size_t i = 0; i < n; ++i) { + const WebCore::FormDataElement& e = elements[i]; + if (e.m_type == WebCore::FormDataElement::data) { + int delta = e.m_data.size(); + memcpy(bytes + offset, e.m_data.data(), delta); + offset += delta; + } else if (e.m_type + == WebCore::FormDataElement::encodedFile) { + int delta = env->CallIntMethod(obj.get(), + mJavaFrame->mGetFile, fileinfos[i]->getUri(), + jPostDataStr, offset, fileinfos[i]->getSize()); + checkException(env); + offset += delta; + } + } + env->ReleaseByteArrayElements(jPostDataStr, bytes, 0); + } + } + delete[] fileinfos; + } + return jPostDataStr; +} + +// ---------------------------------------------------------------------------- + +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!"); + PolicyFunctionWrapper* pFunc = (PolicyFunctionWrapper*)func; + LOG_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) + pFrame->loader()->resetMultipleFormSubmissionProtection(); + + (pFrame->loader()->policyChecker()->*(pFunc->func))((WebCore::PolicyAction)decision); +} + +static void CreateFrame(JNIEnv* env, jobject obj, jobject javaview, jobject jAssetManager, jobject historyList) +{ + 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; + DeviceMotionClientAndroid* deviceMotionC = new DeviceMotionClientAndroid; + DeviceOrientationClientAndroid* deviceOrientationC = new DeviceOrientationClientAndroid; + + WebCore::Page::PageClients pageClients; + pageClients.chromeClient = chromeC; + pageClients.contextMenuClient = new ContextMenuClientAndroid; + pageClients.editorClient = editorC; + pageClients.dragClient = new DragClientAndroid; + pageClients.inspectorClient = new InspectorClientAndroid; + pageClients.deviceMotionClient = deviceMotionC; + pageClients.deviceOrientationClient = deviceOrientationC; + WebCore::Page* page = new WebCore::Page(pageClients); + + editorC->setPage(page); + page->setGroupName("android.webkit"); + + // Create a WebFrame to access the Java BrowserFrame associated with this page + WebFrame* webFrame = new WebFrame(env, obj, historyList, page); + // Attach webFrame to pageClients.chromeClient and release our ownership + chromeC->setWebFrame(webFrame); + Release(webFrame); + + FrameLoaderClientAndroid* loaderC = new FrameLoaderClientAndroid(webFrame); + // Create a Frame and the page holds its reference + WebCore::Frame* frame = WebCore::Frame::create(page, NULL, loaderC).get(); + loaderC->setFrame(frame); +#if ENABLE(WDS) + WDS::server()->addFrame(frame); +#endif + + // Create a WebViewCore to access the Java WebViewCore associated with this page + WebViewCore* webViewCore = new WebViewCore(env, javaview, frame); + +#if ENABLE(WEB_AUTOFILL) + editorC->getAutoFill()->setWebViewCore(webViewCore); +#endif + + // Create a FrameView + RefPtr frameView = WebCore::FrameView::create(frame); + // Create a WebFrameView + WebFrameView* webFrameView = new WebFrameView(frameView.get(), webViewCore); + // As webFrameView Retains webViewCore, release our ownership + Release(webViewCore); + // As frameView Retains webFrameView, release our ownership + Release(webFrameView); + // Attach the frameView to the frame and release our ownership + frame->setView(frameView); + // Set the frame to active to turn on keyboard focus. + frame->init(); + frame->selection()->setFocused(true); + frame->page()->focusController()->setFocused(true); + deviceMotionC->setWebViewCore(webViewCore); + deviceOrientationC->setWebViewCore(webViewCore); + + // Allow local access to file:/// and substitute data + WebCore::SecurityOrigin::setLocalLoadPolicy( + WebCore::SecurityOrigin::AllowLocalLoadsForLocalAndSubstituteData); + + LOGV("::WebCore:: createFrame %p", frame); + + // Set the mNativeFrame field in Frame + SET_NATIVE_FRAME(env, obj, (int)frame); + + String directory = webFrame->getRawResourceFilename( + WebCore::PlatformBridge::DrawableDir); + if (directory.isEmpty()) + LOGE("Can't find the drawable directory"); + else { + // Setup the asset manager. + AssetManager* am = assetManagerForJavaObject(env, jAssetManager); + // Initialize our skinning classes + webFrame->setRenderSkins(new WebCore::RenderSkinAndroid(am, directory)); + } + for (int i = WebCore::PlatformBridge::FileUploadLabel; + i <= WebCore::PlatformBridge::FileUploadNoFileChosenLabel; i++) + initGlobalLocalizedName( + static_cast(i), webFrame); +} + +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!"); + + LOGV("::WebCore:: deleting frame %p", pFrame); + + WebCore::FrameView* view = pFrame->view(); + view->ref(); + // detachFromParent will cause the page to be closed. + WebCore::FrameLoader* fl = pFrame->loader(); + // retain a pointer because detachFromParent will set the page to null. + WebCore::Page* page = pFrame->page(); + if (fl) + fl->detachFromParent(); + delete page; + view->deref(); + + SET_NATIVE_FRAME(env, obj, 0); +#if ENABLE(WDS) + WDS::server()->removeFrame(pFrame); +#endif +} + +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!"); + + WTF::String webcoreUrl = jstringToWtfString(env, url); + WebCore::KURL kurl(WebCore::KURL(), webcoreUrl); + WebCore::ResourceRequest request(kurl); + if (headers) { + // dalvikvm will raise exception if any of these fail + jclass mapClass = env->FindClass("java/util/Map"); + jmethodID entrySet = env->GetMethodID(mapClass, "entrySet", + "()Ljava/util/Set;"); + jobject set = env->CallObjectMethod(headers, entrySet); + + jclass setClass = env->FindClass("java/util/Set"); + jmethodID iterator = env->GetMethodID(setClass, "iterator", + "()Ljava/util/Iterator;"); + jobject iter = env->CallObjectMethod(set, iterator); + + jclass iteratorClass = env->FindClass("java/util/Iterator"); + jmethodID hasNext = env->GetMethodID(iteratorClass, "hasNext", "()Z"); + jmethodID next = env->GetMethodID(iteratorClass, "next", + "()Ljava/lang/Object;"); + jclass entryClass = env->FindClass("java/util/Map$Entry"); + jmethodID getKey = env->GetMethodID(entryClass, "getKey", + "()Ljava/lang/Object;"); + jmethodID getValue = env->GetMethodID(entryClass, "getValue", + "()Ljava/lang/Object;"); + + while (env->CallBooleanMethod(iter, hasNext)) { + jobject entry = env->CallObjectMethod(iter, next); + jstring key = (jstring) env->CallObjectMethod(entry, getKey); + jstring value = (jstring) env->CallObjectMethod(entry, getValue); + request.setHTTPHeaderField(jstringToWtfString(env, key), jstringToWtfString(env, value)); + env->DeleteLocalRef(entry); + env->DeleteLocalRef(key); + env->DeleteLocalRef(value); + } + + env->DeleteLocalRef(entryClass); + env->DeleteLocalRef(iteratorClass); + env->DeleteLocalRef(iter); + env->DeleteLocalRef(setClass); + env->DeleteLocalRef(set); + env->DeleteLocalRef(mapClass); + } + LOGV("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!"); + + WebCore::KURL kurl(WebCore::KURL(), jstringToWtfString(env, url)); + WebCore::ResourceRequest request(kurl); + request.setHTTPMethod("POST"); + request.setHTTPContentType("application/x-www-form-urlencoded"); + + if (postData) { + jsize size = env->GetArrayLength(postData); + jbyte* bytes = env->GetByteArrayElements(postData, NULL); + RefPtr formData = FormData::create((const void*)bytes, size); + // the identifier uses the same logic as generateFormDataIdentifier() in + // HTMLFormElement.cpp + formData->setIdentifier(static_cast(WTF::currentTime() * 1000000.0)); + request.setHTTPBody(formData); + env->ReleaseByteArrayElements(postData, bytes, 0); + } + + LOGV("PostUrl %s", kurl.string().latin1().data()); + WebCore::FrameLoadRequest frameRequest(pFrame->document()->securityOrigin(), request); + pFrame->loader()->loadFrameRequest(frameRequest, false, false, 0, 0, WebCore::SendReferrer); +} + +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!"); + + // Setup the resource request + WebCore::ResourceRequest request(jstringToWtfString(env, baseUrl)); + + // Setup the substituteData + const char* dataStr = env->GetStringUTFChars(data, NULL); + WTF::PassRefPtr sharedBuffer = + WebCore::SharedBuffer::create(); + LOG_ASSERT(dataStr, "nativeLoadData has a null data string."); + sharedBuffer->append(dataStr, strlen(dataStr)); + env->ReleaseStringUTFChars(data, dataStr); + + WebCore::SubstituteData substituteData(sharedBuffer, + jstringToWtfString(env, mimeType), jstringToWtfString(env, encoding), + WebCore::KURL(ParsedURLString, jstringToWtfString(env, failUrl))); + + // Perform the load + pFrame->loader()->load(request, substituteData, false); +} + +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); + + // Stop loading the page and do not send an unload event + pFrame->loader()->stopForUserCancel(); +} + +#if ENABLE(ARCHIVE) +static String saveArchiveAutoname(String basename, String name, String extension) { + if (name.isNull() || name.isEmpty()) { + name = String("index"); + } + + String testname = basename; + testname.append(name); + testname.append(extension); + + errno = 0; + struct stat permissions; + if (stat(testname.utf8().data(), &permissions) < 0) { + if (errno == ENOENT) + return testname; + return String(); + } + + const int maxAttempts = 100; + for (int i = 1; i < maxAttempts; i++) { + String testname = basename; + testname.append(name); + testname.append("-"); + testname.append(String::number(i)); + testname.append(extension); + + errno = 0; + if (stat(testname.utf8().data(), &permissions) < 0) { + if (errno == ENOENT) + return testname; + return String(); + } + } + + return String(); +} +#endif + +static jstring SaveWebArchive(JNIEnv *env, jobject obj, jstring basename, jboolean autoname) +{ +#if ENABLE(ARCHIVE) + WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj); + LOG_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; + + const char* basenameNative = getCharactersFromJStringInEnv(env, basename); + String basenameString = String::fromUTF8(basenameNative); + String filename; + + if (autoname) { + String name = pFrame->loader()->documentLoader()->originalURL().lastPathComponent(); + String extension = String(".webarchivexml"); + filename = saveArchiveAutoname(basenameString, name, extension); + } else { + filename = basenameString; + } + + if (filename.isNull() || filename.isEmpty()) { + LOGD("saveWebArchive: Failed to select a filename to save."); + releaseCharactersForJStringInEnv(env, basename, basenameNative); + return NULL; + } + + const int noCompression = 0; + xmlTextWriterPtr writer = xmlNewTextWriterFilename(filename.utf8().data(), noCompression); + if (writer == NULL) { + LOGD("saveWebArchive: Failed to initialize xml writer."); + releaseCharactersForJStringInEnv(env, basename, basenameNative); + return NULL; + } + + RefPtr archive = WebCore::WebArchiveAndroid::create(pFrame); + + bool result = archive->saveWebArchive(writer); + + releaseCharactersForJStringInEnv(env, basename, basenameNative); + xmlFreeTextWriter(writer); + + if (result) + return wtfStringToJstring(env, filename); + + return NULL; +#endif +} + +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!"); + + // Request external representation of the render tree + WTF::String renderDump = WebCore::externalRepresentation(pFrame); + return wtfStringToJstring(env, renderDump); +} + +static StringBuilder FrameAsText(WebCore::Frame *pFrame, jboolean dumpChildFrames) { + StringBuilder renderDump; + if (!pFrame) + return renderDump; + WebCore::Element *documentElement = pFrame->document()->documentElement(); + if (!documentElement) + return renderDump; + if (pFrame->tree()->parent()) { + renderDump.append("\n--------\nFrame: '"); + renderDump.append(pFrame->tree()->name()); + renderDump.append("'\n--------\n"); + } + renderDump.append(((WebCore::HTMLElement*)documentElement)->innerText()); + renderDump.append("\n"); + if (dumpChildFrames) { + for (unsigned i = 0; i < pFrame->tree()->childCount(); ++i) { + renderDump.append(FrameAsText(pFrame->tree()->child(i), dumpChildFrames).toString()); + } + } + return renderDump; +} + +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!"); + + WTF::String renderDump = FrameAsText(pFrame, false /* dumpChildFrames */).toString(); + return wtfStringToJstring(env, renderDump); +} + +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!"); + + StringBuilder renderDumpBuilder; + for (unsigned i = 0; i < pFrame->tree()->childCount(); ++i) { + renderDumpBuilder.append(FrameAsText(pFrame->tree()->child(i), true /* dumpChildFrames */).toString()); + } + WTF::String renderDump = renderDumpBuilder.toString(); + return wtfStringToJstring(env, renderDump); +} + +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!"); + + WebCore::FrameLoader* loader = pFrame->loader(); + if (allowStale) { + // load the current page with FrameLoadTypeIndexedBackForward so that it + // will use cache when it is possible + WebCore::Page* page = pFrame->page(); + WebCore::HistoryItem* item = page->backForwardList()->currentItem(); + if (item) + page->goToItem(item, FrameLoadTypeIndexedBackForward); + } else + loader->reload(true); +} + +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!"); + + if (pos == 1) + pFrame->page()->goForward(); + else if (pos == -1) + pFrame->page()->goBack(); + else + pFrame->page()->goBackOrForward(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!"); + + WebCore::ScriptValue value = + pFrame->script()->executeScript(jstringToWtfString(env, script), true); + WTF::String result = WTF::String(); + ScriptState* scriptState = mainWorldScriptState(pFrame); + if (!value.getString(scriptState, result)) + return NULL; + return wtfStringToJstring(env, result); +} + +// 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. +class WeakJavaInstance : public JavaInstance { +public: +#if USE(JSC) + static PassRefPtr create(jobject obj, PassRefPtr root) + { + return adoptRef(new WeakJavaInstance(obj, root)); + } +#elif USE(V8) + static PassRefPtr create(jobject obj) + { + return adoptRef(new WeakJavaInstance(obj)); + } +#endif + +private: +#if USE(JSC) + WeakJavaInstance(jobject instance, PassRefPtr rootObject) + : JavaInstance(instance, rootObject) +#elif USE(V8) + WeakJavaInstance(jobject instance) + : JavaInstance(instance) +#endif + , m_beginEndDepth(0) + { + JNIEnv* env = getJNIEnv(); + // JavaInstance creates a global ref to instance in its constructor. + env->DeleteGlobalRef(m_instance->instance()); + // Set the object to a weak reference. + m_instance->setInstance(env->NewWeakGlobalRef(instance)); + } + ~WeakJavaInstance() + { + JNIEnv* env = getJNIEnv(); + // Store the weak reference so we can delete it later. + jweak weak = m_instance->instance(); + // The JavaInstance destructor attempts to delete the global ref stored + // in m_instance. Since we replaced it in our constructor with a weak + // reference, restore the global ref here so the vm will not complain. + m_instance->setInstance(env->NewGlobalRef( + getRealObject(env, m_instance->instance()).get())); + // Delete the weak reference. + env->DeleteWeakGlobalRef(weak); + } + + virtual void virtualBegin() + { + if (m_beginEndDepth++ > 0) + return; + m_weakRef = m_instance->instance(); + JNIEnv* env = getJNIEnv(); + // This is odd. getRealObject returns an AutoJObject which is used to + // cleanly create and delete a local reference. But, here we need to + // maintain the local reference across calls to virtualBegin() and + // virtualEnd(). So, release the local reference from the AutoJObject + // and delete the local reference in virtualEnd(). + m_realObject = getRealObject(env, m_weakRef).release(); + // Point to the real object + m_instance->setInstance(m_realObject); + // Call the base class method + INHERITED::virtualBegin(); + } + + virtual void virtualEnd() + { + if (--m_beginEndDepth > 0) + return; + // Call the base class method first to pop the local frame. + INHERITED::virtualEnd(); + // Get rid of the local reference to the real object. + getJNIEnv()->DeleteLocalRef(m_realObject); + // Point back to the WeakReference. + m_instance->setInstance(m_weakRef); + } + +private: + typedef JavaInstance INHERITED; + jobject m_realObject; + jweak m_weakRef; + // The current depth of nested calls to virtualBegin and virtualEnd. + int m_beginEndDepth; +}; + +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!"); + + 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) + if (pFrame) { + RefPtr addedObject = WeakJavaInstance::create(javascriptObj); + const char* name = getCharactersFromJStringInEnv(env, interfaceName); + // Pass ownership of the added object to bindToWindowObject. + NPObject* npObject = JavaInstanceToNPObject(addedObject.get()); + pFrame->script()->bindToWindowObject(pFrame, name, npObject); + // bindToWindowObject calls NPN_RetainObject on the + // returned one (see createV8ObjectForNPObject in V8NPObject.cpp). + // bindToWindowObject also increases obj's ref count and decreases + // the ref count when the object is not reachable from JavaScript + // side. Code here must release the reference count increased by + // bindToWindowObject. + + // Note that while this function is declared in WebCore/bridge/npruntime.h, for V8 builds + // we use WebCore/bindings/v8/npruntime.cpp (rather than + // WebCore/bridge/npruntime.cpp), so the function is implemented there. + // TODO: Combine the two versions of these NPAPI files. + 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::cache()->setDisabled(disabled); +} + +static jboolean CacheDisabled(JNIEnv *env, jobject obj) +{ +#ifdef ANDROID_INSTRUMENT + TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter); +#endif + return WebCore::cache()->disabled(); +} + +static void ClearWebCoreCache() +{ + if (!WebCore::cache()->disabled()) { + // Disabling the cache will remove all resources from the cache. They may + // still live on if they are referenced by some Web page though. + WebCore::cache()->setDisabled(true); + WebCore::cache()->setDisabled(false); + } + + // clear page cache + int pageCapacity = WebCore::pageCache()->capacity(); + // Setting size to 0, makes all pages be released. + WebCore::pageCache()->setCapacity(0); + WebCore::pageCache()->releaseAutoreleasedPagesNow(); + WebCore::pageCache()->setCapacity(pageCapacity); +} + +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", + cache()->getLiveSize(), cache()->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!"); + + 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!"); + + bool found = false; + WTF::PassRefPtr 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. + while (node && !found && !node->namespaceURI().isNull() && + !node->namespaceURI().isEmpty()) { + const WTF::Vector& elements = + ((WebCore::HTMLFormElement*)node)->associatedElements(); + size_t size = elements.size(); + for (size_t i = 0; i< size && !found; i++) { + WebCore::HTMLElement* e = toHTMLElement(elements[i]); + if (e->hasLocalName(WebCore::HTMLNames::inputTag)) { + if (static_cast(e)->isPasswordField()) + found = true; + } + } + node = form->nextItem(); + } + return found; +} + +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!"); + jobjectArray strArray = NULL; + WTF::String username; + WTF::String password; + if (WebFrame::getWebFrame(pFrame)->getUsernamePasswordFromDom(pFrame, username, password)) { + jclass stringClass = env->FindClass("java/lang/String"); + strArray = env->NewObjectArray(2, stringClass, NULL); + env->DeleteLocalRef(stringClass); + env->SetObjectArrayElement(strArray, 0, wtfStringToJstring(env, username)); + env->SetObjectArrayElement(strArray, 1, wtfStringToJstring(env, password)); + } + return strArray; +} + +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!"); + + WebCore::HTMLInputElement* usernameEle = NULL; + WebCore::HTMLInputElement* passwordEle = NULL; + bool found = false; + WTF::PassRefPtr form = pFrame->document()->forms(); + WebCore::Node* node = form->firstItem(); + while (node && !found && !node->namespaceURI().isNull() && + !node->namespaceURI().isEmpty()) { + const WTF::Vector& elements = + ((WebCore::HTMLFormElement*)node)->associatedElements(); + size_t size = elements.size(); + for (size_t i = 0; i< size && !found; i++) { + WebCore::HTMLElement* e = toHTMLElement(elements[i]); + if (e->hasLocalName(WebCore::HTMLNames::inputTag)) { + WebCore::HTMLInputElement* input = (WebCore::HTMLInputElement*)e; + if (input->autoComplete() == false) + continue; + if (input->isPasswordField()) + passwordEle = input; + else if (input->isTextField() || input->isEmailField()) + usernameEle = input; + if (usernameEle != NULL && passwordEle != NULL) + found = true; + } + } + node = form->nextItem(); + } + if (found) { + usernameEle->setValue(jstringToWtfString(env, username)); + passwordEle->setValue(jstringToWtfString(env, password)); + } +} + +void +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!"); + jmethodID init = env->GetMethodID(mapClass, "", "(I)V"); + LOG_ASSERT(init, "Could not find constructor for HashMap"); + jobject hashMap = env->NewObject(mapClass, init, 1); + LOG_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"); + WTF::Vector elements = form->associatedElements(); + size_t size = elements.size(); + for (size_t i = 0; i < size; i++) { + WebCore::HTMLElement* e = toHTMLElement(elements[i]); + if (e->hasTagName(WebCore::HTMLNames::inputTag)) { + WebCore::HTMLInputElement* input = static_cast(e); + if (input->isTextField() && !input->isPasswordField() + && input->autoComplete()) { + WTF::String value = input->value(); + int len = value.length(); + if (len) { + 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"); + env->CallObjectMethod(hashMap, put, key, val); + env->DeleteLocalRef(key); + env->DeleteLocalRef(val); + } + } + } + } + env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mSaveFormData, hashMap); + env->DeleteLocalRef(hashMap); + env->DeleteLocalRef(mapClass); + } +} + +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); + pFrame->sendOrientationChangeEvent(orientation); +} + +#if USE(CHROME_NETWORK_STACK) + +static void AuthenticationProceed(JNIEnv *env, jobject obj, int handle, jstring jUsername, jstring jPassword) +{ + WebUrlLoaderClient* client = reinterpret_cast(handle); + std::string username = jstringToStdString(env, jUsername); + std::string password = jstringToStdString(env, jPassword); + client->setAuth(username, password); +} + +static void AuthenticationCancel(JNIEnv *env, jobject obj, int handle) +{ + WebUrlLoaderClient* client = reinterpret_cast(handle); + client->cancelAuth(); +} + +static void SslCertErrorProceed(JNIEnv *env, jobject obj, int handle) +{ + WebUrlLoaderClient* client = reinterpret_cast(handle); + client->proceedSslCertError(); +} + +static void SslCertErrorCancel(JNIEnv *env, jobject obj, int handle, int cert_error) +{ + WebUrlLoaderClient* client = reinterpret_cast(handle); + client->cancelSslCertError(cert_error); +} + +#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"); +} + +#endif // USE(CHROME_NETWORK_STACK) + +// ---------------------------------------------------------------------------- + +/* + * JNI registration. + */ +static JNINativeMethod gBrowserFrameNativeMethods[] = { + /* name, signature, funcPtr */ + { "nativeCallPolicyFunction", "(II)V", + (void*) CallPolicyFunction }, + { "nativeCreateFrame", "(Landroid/webkit/WebViewCore;Landroid/content/res/AssetManager;Landroid/webkit/WebBackForwardList;)V", + (void*) CreateFrame }, + { "nativeDestroyFrame", "()V", + (void*) DestroyFrame }, + { "nativeStopLoading", "()V", + (void*) StopLoading }, + { "nativeLoadUrl", "(Ljava/lang/String;Ljava/util/Map;)V", + (void*) LoadUrl }, + { "nativePostUrl", "(Ljava/lang/String;[B)V", + (void*) PostUrl }, + { "nativeLoadData", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V", + (void*) LoadData }, + { "nativeSaveWebArchive", "(Ljava/lang/String;Z)Ljava/lang/String;", + (void*) SaveWebArchive }, + { "externalRepresentation", "()Ljava/lang/String;", + (void*) ExternalRepresentation }, + { "documentAsText", "()Ljava/lang/String;", + (void*) DocumentAsText }, + { "childFramesAsText", "()Ljava/lang/String;", + (void*) ChildFramesAsText }, + { "reload", "(Z)V", + (void*) Reload }, + { "nativeGoBackOrForward", "(I)V", + (void*) GoBackOrForward }, + { "nativeAddJavascriptInterface", "(ILjava/lang/Object;Ljava/lang/String;)V", + (void*) AddJavascriptInterface }, + { "stringByEvaluatingJavaScriptFromString", + "(Ljava/lang/String;)Ljava/lang/String;", + (void*) StringByEvaluatingJavaScriptFromString }, + { "setCacheDisabled", "(Z)V", + (void*) SetCacheDisabled }, + { "cacheDisabled", "()Z", + (void*) CacheDisabled }, + { "clearCache", "()V", + (void*) ClearCache }, + { "documentHasImages", "()Z", + (void*) DocumentHasImages }, + { "hasPasswordField", "()Z", + (void*) HasPasswordField }, + { "getUsernamePassword", "()[Ljava/lang/String;", + (void*) GetUsernamePassword }, + { "setUsernamePassword", "(Ljava/lang/String;Ljava/lang/String;)V", + (void*) SetUsernamePassword }, + { "nativeOrientationChanged", "(I)V", + (void*) OrientationChanged }, + { "nativeAuthenticationProceed", "(ILjava/lang/String;Ljava/lang/String;)V", + (void*) AuthenticationProceed }, + { "nativeAuthenticationCancel", "(I)V", + (void*) AuthenticationCancel }, + { "nativeSslCertErrorProceed", "(I)V", + (void*) SslCertErrorProceed }, + { "nativeSslCertErrorCancel", "(II)V", + (void*) SslCertErrorCancel }, +}; + +int registerWebFrame(JNIEnv* env) +{ + jclass clazz = env->FindClass("android/webkit/BrowserFrame"); + LOG_ASSERT(clazz, "Cannot find BrowserFrame"); + gFrameField = env->GetFieldID(clazz, "mNativeFrame", "I"); + LOG_ASSERT(gFrameField, "Cannot find mNativeFrame on BrowserFrame"); + env->DeleteLocalRef(clazz); + + return jniRegisterNativeMethods(env, "android/webkit/BrowserFrame", + gBrowserFrameNativeMethods, NELEM(gBrowserFrameNativeMethods)); +} + +} /* namespace android */ diff --git a/Source/WebKit/android/jni/WebCoreFrameBridge.h b/Source/WebKit/android/jni/WebCoreFrameBridge.h new file mode 100644 index 0000000..6522a5f --- /dev/null +++ b/Source/WebKit/android/jni/WebCoreFrameBridge.h @@ -0,0 +1,173 @@ +/* + * 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. + */ + +// TODO: change name to WebFrame.h + +#ifndef WEBFRAME_H +#define WEBFRAME_H + +#include "FrameLoaderClient.h" +#include "PlatformBridge.h" +#include "PlatformString.h" +#include "WebCoreRefObject.h" +#include +#include +#include + +namespace WebCore { + class HTMLFormElement; + class Frame; + class HistoryItem; + class Image; + class Page; + class RenderPart; + class RenderSkinAndroid; + class ResourceHandle; + class ResourceLoaderAndroid; + class ResourceRequest; +} + +namespace android { + +class WebViewCore; +class WebUrlLoaderClient; +class UrlInterceptResponse; + +// one instance of WebFrame per Page for calling into Java's BrowserFrame +class WebFrame : public WebCoreRefObject { + public: + WebFrame(JNIEnv* env, jobject obj, jobject historyList, WebCore::Page* page); + ~WebFrame(); + + // helper function + static WebFrame* getWebFrame(const WebCore::Frame* frame); + + virtual PassRefPtr 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, + const WTF::String& failingUrl); + + void loadStarted(WebCore::Frame* frame); + + void transitionToCommitted(WebCore::Frame* frame); + + void didFinishLoad(WebCore::Frame* frame); + + void addHistoryItem(WebCore::HistoryItem* item); + + void removeHistoryItem(int index); + + void updateHistoryIndex(int newIndex); + + void setTitle(const WTF::String& title); + + void windowObjectCleared(WebCore::Frame* frame); + + void setProgress(float newProgress); + + const WTF::String userAgentForURL(const WebCore::KURL* url); + + void didReceiveIcon(WebCore::Image* icon); + + void didReceiveTouchIconURL(const WTF::String& url, bool precomposed); + + void updateVisitedHistory(const WebCore::KURL& url, bool reload); + + virtual bool canHandleRequest(const WebCore::ResourceRequest& request); + + WebCore::Frame* createWindow(bool dialog, bool userGesture); + + void requestFocus() const; + + void closeWindow(WebViewCore* webViewCore); + + void decidePolicyForFormResubmission(WebCore::FramePolicyFunction func); + + void setUserAgent(WTF::String userAgent) { mUserAgent = userAgent; } + + WTF::String getRawResourceFilename(WebCore::PlatformBridge::rawResId) const; + + float density() const; + + void didReceiveAuthenticationChallenge(WebUrlLoaderClient*, const std::string& host, const std::string& realm, bool useCachedCredentials); + + void reportSslCertError(WebUrlLoaderClient* client, int cert_error, const std::string& cert); + + void downloadStart(const std::string& url, const std::string& userAgent, const std::string& contentDisposition, const std::string& mimetype, long long contentLength); + + void didReceiveData(const char* data, int size); + + void didFinishLoading(); + + void maybeSavePassword(WebCore::Frame* frame, const WebCore::ResourceRequest& request); + + void setCertificate(const std::string& cert); + + // Parse the x-auto-login header and propagate the parameters to the + // application. + void autoLogin(const std::string& loginHeader); + + /** + * When the user initiates a click, we set mUserInitiatedAction to true. + * If a load happens due to this click, then we ask the application if it wants + * to override the load. Otherwise, we attempt to load the resource internally. + */ + void setUserInitiatedAction(bool userInitiatedAction) { mUserInitiatedAction = userInitiatedAction; } + + WebCore::Page* page() const { return mPage; } + + // Currently used only by the chrome net stack. A similar field is used by + // FrameLoader.java to block java network loads. + void setBlockNetworkLoads(bool block) { mBlockNetworkLoads = block; } + bool blockNetworkLoads() const { return mBlockNetworkLoads; } + + /** + * Helper methods. These are typically chunks of code that are called in + * slightly different ways by the Apache and Chrome HTTP stacks. + */ + bool getUsernamePasswordFromDom(WebCore::Frame* frame, WTF::String& username, WTF::String& password); + jbyteArray getPostData(const WebCore::ResourceRequest& request); + + bool shouldSaveFormData(); + void saveFormData(WebCore::HTMLFormElement*); + const WebCore::RenderSkinAndroid* renderSkins() const { return m_renderSkins; } + void setRenderSkins(const WebCore::RenderSkinAndroid* skins) { m_renderSkins = skins; } +private: + struct JavaBrowserFrame; + JavaBrowserFrame* mJavaFrame; + WebCore::Page* mPage; + WTF::String mUserAgent; + bool mBlockNetworkLoads; + bool mUserInitiatedAction; + const WebCore::RenderSkinAndroid* m_renderSkins; +}; + +} // namespace android + +#endif // WEBFRAME_H diff --git a/Source/WebKit/android/jni/WebCoreJni.cpp b/Source/WebKit/android/jni/WebCoreJni.cpp new file mode 100644 index 0000000..2a07999 --- /dev/null +++ b/Source/WebKit/android/jni/WebCoreJni.cpp @@ -0,0 +1,117 @@ +/* + * 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. + */ + +#define LOG_TAG "webcoreglue" + +#include "config.h" +#include "WebCoreJni.h" + +#include "NotImplemented.h" +#include +#include +#include + +namespace android { + +AutoJObject getRealObject(JNIEnv* env, jobject obj) +{ + jobject real = env->NewLocalRef(obj); + LOG_ASSERT(real, "The real object has been deleted!"); + return AutoJObject(env, real); +} + +/** + * Helper method for checking java exceptions + * @return true if an exception occurred. + */ +bool checkException(JNIEnv* env) +{ + if (env->ExceptionCheck() != 0) + { + LOGE("*** Uncaught exception returned from Java call!\n"); + env->ExceptionDescribe(); + return true; + } + return false; +} + +// This method is safe to call from the ui thread and the WebCore thread. +WTF::String jstringToWtfString(JNIEnv* env, jstring str) +{ + if (!str || !env) + return WTF::String(); + const jchar* s = env->GetStringChars(str, NULL); + if (!s) + return WTF::String(); + WTF::String ret(s, env->GetStringLength(str)); + env->ReleaseStringChars(str, s); + checkException(env); + return ret; +} + +jstring wtfStringToJstring(JNIEnv* env, const WTF::String& str, bool validOnZeroLength) +{ + int length = str.length(); + return length || validOnZeroLength ? env->NewString(str.characters(), length) : 0; +} + + +#if USE(CHROME_NETWORK_STACK) +string16 jstringToString16(JNIEnv* env, jstring jstr) +{ + if (!jstr || !env) + return string16(); + + const char* s = env->GetStringUTFChars(jstr, 0); + if (!s) + return string16(); + string16 str = UTF8ToUTF16(s); + env->ReleaseStringUTFChars(jstr, s); + checkException(env); + return str; +} + +std::string jstringToStdString(JNIEnv* env, jstring jstr) +{ + if (!jstr || !env) + return std::string(); + + const char* s = env->GetStringUTFChars(jstr, 0); + if (!s) + return std::string(); + std::string str(s); + env->ReleaseStringUTFChars(jstr, s); + checkException(env); + return str; +} + +jstring stdStringToJstring(JNIEnv* env, const std::string& str, bool validOnZeroLength) +{ + return !str.empty() || validOnZeroLength ? env->NewStringUTF(str.c_str()) : 0; +} + +#endif + +} diff --git a/Source/WebKit/android/jni/WebCoreJni.h b/Source/WebKit/android/jni/WebCoreJni.h new file mode 100644 index 0000000..ec25c8f --- /dev/null +++ b/Source/WebKit/android/jni/WebCoreJni.h @@ -0,0 +1,96 @@ +/* + * 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 ANDROID_WEBKIT_WEBCOREJNI_H +#define ANDROID_WEBKIT_WEBCOREJNI_H + +#include "ChromiumIncludes.h" +#include "PlatformString.h" +#include + +namespace android { + +// A helper class that automatically deletes the local reference to the jobject +// returned from getRealObject. +class AutoJObject { +public: + AutoJObject(const AutoJObject& other) + : m_env(other.m_env) + , m_obj(other.m_obj ? other.m_env->NewLocalRef(other.m_obj) : NULL) {} + ~AutoJObject() { + if (m_obj) + m_env->DeleteLocalRef(m_obj); + } + jobject get() const { + return m_obj; + } + // Releases the local reference to the caller. The caller *must* delete the + // local reference when it is done with it. + jobject release() { + jobject obj = m_obj; + m_obj = 0; + return obj; + } + JNIEnv* env() const { + return m_env; + } +private: + AutoJObject(); // Not permitted. + AutoJObject(JNIEnv* env, jobject obj) + : m_env(env) + , m_obj(obj) {} + JNIEnv* m_env; + jobject m_obj; + friend AutoJObject getRealObject(JNIEnv*, jobject); +}; + +// Get the real object stored in the weak reference returned as an +// AutoJObject. +AutoJObject getRealObject(JNIEnv*, jobject); + +// Helper method for check java exceptions. Returns true if an exception +// occurred and logs the exception. +bool checkException(JNIEnv* env); + +// Create a WTF::String object from a jstring object. +WTF::String jstringToWtfString(JNIEnv*, jstring); +// Returns a local reference to a new jstring. If validOnZeroLength is true then +// passing in an empty WTF String will result in an empty jstring. Otherwise +// 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); +// Returns a local reference to a new jstring. If validOnZeroLength is true then +// 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 + +} + +#endif diff --git a/Source/WebKit/android/jni/WebCoreJniOnLoad.cpp b/Source/WebKit/android/jni/WebCoreJniOnLoad.cpp new file mode 100644 index 0000000..1f264a2 --- /dev/null +++ b/Source/WebKit/android/jni/WebCoreJniOnLoad.cpp @@ -0,0 +1,319 @@ +/* + * 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 "webcoreglue" + +#include "config.h" + +#include "BackForwardList.h" +#include "ChromeClientAndroid.h" +#include "ContextMenuClientAndroid.h" +#include "CookieClient.h" +#include "DeviceMotionClientAndroid.h" +#include "DeviceOrientationClientAndroid.h" +#include "DragClientAndroid.h" +#include "EditorClientAndroid.h" +#include "FocusController.h" +#include "Frame.h" +#include "FrameLoader.h" +#include "FrameLoaderClientAndroid.h" +#include "FrameView.h" +#include "GraphicsContext.h" +#include "HistoryItem.h" +#include "InspectorClientAndroid.h" +#include "IntRect.h" +#include "JavaSharedClient.h" +#include "Page.h" +#include "PlatformGraphicsContext.h" +#include "ResourceRequest.h" +#include "ScriptController.h" +#include "SecurityOrigin.h" +#include "SelectionController.h" +#include "Settings.h" +#include "SharedBuffer.h" +#include "SkBitmap.h" +#include "SkCanvas.h" +#include "SkImageEncoder.h" +#include "SubstituteData.h" +#include "TimerClient.h" +#include "TextEncoding.h" +#include "WebCoreViewBridge.h" +#include "WebFrameView.h" +#include "WebViewCore.h" +#include "benchmark/Intercept.h" +#include "benchmark/MyJavaVM.h" + +#include +#include +#include + +#define EXPORT __attribute__((visibility("default"))) + +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*); +extern int registerWebIconDatabase(JNIEnv*); +extern int registerWebSettings(JNIEnv*); +extern int registerWebView(JNIEnv*); +#if ENABLE(DATABASE) +extern int registerWebStorage(JNIEnv*); +#endif +extern int registerGeolocationPermissions(JNIEnv*); +extern int registerMockGeolocation(JNIEnv*); +#if ENABLE(VIDEO) +extern int registerMediaPlayerAudio(JNIEnv*); +extern int registerMediaPlayerVideo(JNIEnv*); +#endif +extern int registerDeviceMotionAndOrientationManager(JNIEnv*); +extern int registerCookieManager(JNIEnv*); +#if USE(CHROME_NETWORK_STACK) +extern int registerCacheManager(JNIEnv*); +#endif + +} + +struct RegistrationMethod { + const char* name; + int (*func)(JNIEnv*); +}; + +static RegistrationMethod gWebCoreRegMethods[] = { + { "JavaBridge", android::registerJavaBridge }, + { "JniUtil", android::registerJniUtil }, + { "WebFrame", android::registerWebFrame }, + { "WebCoreResourceLoader", android::registerResourceLoader }, + { "WebViewCore", android::registerWebViewCore }, + { "WebHistory", android::registerWebHistory }, + { "WebIconDatabase", android::registerWebIconDatabase }, + { "WebSettings", android::registerWebSettings }, +#if ENABLE(DATABASE) + { "WebStorage", android::registerWebStorage }, +#endif + { "WebView", android::registerWebView }, + { "GeolocationPermissions", android::registerGeolocationPermissions }, + { "MockGeolocation", android::registerMockGeolocation }, +#if ENABLE(VIDEO) + { "HTML5Audio", android::registerMediaPlayerAudio }, + { "HTML5VideoViewProxy", android::registerMediaPlayerVideo }, +#endif + { "DeviceMotionAndOrientationManager", android::registerDeviceMotionAndOrientationManager }, + { "CookieManager", android::registerCookieManager }, +#if USE(CHROME_NETWORK_STACK) + { "CacheManager", android::registerCacheManager }, +#endif +}; + +EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) +{ + // Save the JavaVM pointer for use globally. + JSC::Bindings::setJavaVM(vm); + + JNIEnv* env = NULL; + jint result = -1; + + if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { + LOGE("GetEnv failed!"); + return result; + } + LOG_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); + return result; + } + method++; + } + + // Initialize rand() function. The rand() function is used in + // FileSystemAndroid to create a random temporary filename. + srand(time(NULL)); + + 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::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::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, NULL); + 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/WebCoreRefObject.h b/Source/WebKit/android/jni/WebCoreRefObject.h new file mode 100644 index 0000000..4228db6 --- /dev/null +++ b/Source/WebKit/android/jni/WebCoreRefObject.h @@ -0,0 +1,46 @@ +/* + * 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 WEBCORE_FOUNDATION_h +#define WEBCORE_FOUNDATION_h + +#include "SkRefCnt.h" + +typedef SkRefCnt WebCoreRefObject; + +static inline WebCoreRefObject* Retain(WebCoreRefObject* obj) +{ + if (obj) + obj->ref(); + return obj; +} + +static inline void Release(WebCoreRefObject* obj) +{ + if (obj) + obj->unref(); +} + +#endif // WEBCORE_FOUNDATION_h diff --git a/Source/WebKit/android/jni/WebCoreResourceLoader.cpp b/Source/WebKit/android/jni/WebCoreResourceLoader.cpp new file mode 100644 index 0000000..f9acc97 --- /dev/null +++ b/Source/WebKit/android/jni/WebCoreResourceLoader.cpp @@ -0,0 +1,352 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include + +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 WebCoreResourceLoader::create(JNIEnv *env, jobject jLoadListener) +{ + return adoptRef(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 new file mode 100644 index 0000000..c60b3f5 --- /dev/null +++ b/Source/WebKit/android/jni/WebCoreResourceLoader.h @@ -0,0 +1,78 @@ +/* + * 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 ANDROID_WEBKIT_RESOURCELOADLISTENER_H +#define ANDROID_WEBKIT_RESOURCELOADLISTENER_H + +#include +#include +#include + +namespace android { + +class WebCoreResourceLoader : public WebCore::ResourceLoaderAndroid +{ +public: + static PassRefPtr create(JNIEnv *env, jobject jLoadListener); + virtual ~WebCoreResourceLoader(); + + /** + * Call to java to cancel the current load. + */ + virtual void cancel(); + + /** + * Call to java to download the current load rather than feed it + * back to WebCore + */ + virtual void downloadFile(); + + virtual void pauseLoad(bool); + + /** + * Call to java to find out if this URL is in the cache + */ + static bool willLoadFromCache(const WebCore::KURL& url, int64_t identifier); + + // Native jni functions + static void SetResponseHeader(JNIEnv*, jobject, jint, jstring, jstring); + static jint CreateResponse(JNIEnv*, jobject, jstring, jint, jstring, + jstring, jlong, jstring); + static void ReceivedResponse(JNIEnv*, jobject, jint); + static void AddData(JNIEnv*, jobject, jbyteArray, jint); + static void Finished(JNIEnv*, jobject); + static jstring RedirectedToUrl(JNIEnv*, jobject, jstring, jstring, jint); + static void Error(JNIEnv*, jobject, jint, jstring, jstring); + +protected: + WebCoreResourceLoader(JNIEnv *env, jobject jLoadListener); +private: + jobject mJLoader; + bool mPausedLoad; +}; + +} // end namespace android + +#endif diff --git a/Source/WebKit/android/jni/WebCoreViewBridge.h b/Source/WebKit/android/jni/WebCoreViewBridge.h new file mode 100644 index 0000000..59e1c9a --- /dev/null +++ b/Source/WebKit/android/jni/WebCoreViewBridge.h @@ -0,0 +1,106 @@ +/* + * 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 WEBCORE_VIEW_BRIDGE_H +#define WEBCORE_VIEW_BRIDGE_H + +// TODO: move this outside of jni directory + +#include "IntRect.h" +#include "WebCoreRefObject.h" + +namespace WebCore +{ + class GraphicsContext; +} + +class WebCoreViewBridge : public WebCoreRefObject { +public: + WebCoreViewBridge() { } + virtual ~WebCoreViewBridge() { } + + virtual void draw(WebCore::GraphicsContext* ctx, + const WebCore::IntRect& rect) = 0; + + const WebCore::IntRect& getBounds() const + { + return m_bounds; + } + + const WebCore::IntRect& getVisibleBounds() const + { + return m_visibleBounds; + } + + const WebCore::IntRect& getWindowBounds() const + { + return m_windowBounds; + } + + void setSize(int w, int h) + { + m_bounds.setWidth(w); + m_bounds.setHeight(h); + } + + void setVisibleSize(int w, int h) + { + m_visibleBounds.setWidth(w); + m_visibleBounds.setHeight(h); + } + + void setLocation(int x, int y) + { + m_bounds.setX(x); + m_bounds.setY(y); + m_visibleBounds.setX(x); + m_visibleBounds.setY(y); + } + + void setWindowBounds(int x, int y, int h, int v) + { + m_windowBounds = WebCore::IntRect(x, y, h, v); + } + + int width() const { return m_bounds.width(); } + int height() const { return m_bounds.height(); } + int locX() const { return m_bounds.x(); } + int locY() const { return m_bounds.y(); } + + int visibleWidth() const { return m_visibleBounds.width(); } + int visibleHeight() const { return m_visibleBounds.height(); } + int visibleX() const { return m_visibleBounds.x(); } + int visibleY() const { return m_visibleBounds.y(); } + + virtual bool forFrameView() const { return false; } + virtual bool forPluginView() const { return false; } + +private: + WebCore::IntRect m_bounds; + WebCore::IntRect m_windowBounds; + WebCore::IntRect m_visibleBounds; +}; + +#endif // WEBCORE_VIEW_BRIDGE_H diff --git a/Source/WebKit/android/jni/WebFrameView.cpp b/Source/WebKit/android/jni/WebFrameView.cpp new file mode 100644 index 0000000..8e5eac4 --- /dev/null +++ b/Source/WebKit/android/jni/WebFrameView.cpp @@ -0,0 +1,104 @@ +/* + * 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 "webcoreglue" + +#include +#include "WebFrameView.h" + +#include "android_graphics.h" +#include "GraphicsContext.h" +#include "Frame.h" +#include "FrameTree.h" +#include "FrameView.h" +#include "HostWindow.h" +#include "PlatformGraphicsContext.h" +#include "WebViewCore.h" + +#include + +namespace android { + +WebFrameView::WebFrameView(WebCore::FrameView* frameView, WebViewCore* webViewCore) + : WebCoreViewBridge() + , mFrameView(frameView) + , mWebViewCore(webViewCore) { + // attach itself to mFrameView + mFrameView->setPlatformWidget(this); + Retain(mWebViewCore); +} + +WebFrameView::~WebFrameView() { + Release(mWebViewCore); +} + +void WebFrameView::draw(WebCore::GraphicsContext* ctx, const WebCore::IntRect& rect) { + WebCore::Frame* frame = mFrameView->frame(); + + if (NULL == frame->contentRenderer()) { + // We only do this if there is nothing else to draw. + // If there is a renderer, it will fill the bg itself, so we don't want to + // double-draw (slow) + SkCanvas* canvas = ctx->platformContext()->mCanvas; + canvas->drawColor(SK_ColorWHITE); + } else if (frame->tree()->parent()) { + // Note: this code was moved from FrameLoaderClientAndroid + // + // For subframe, create a new translated rect from the given rectangle. + WebCore::IntRect transRect(rect); + // In Frame::markAllMatchesForText(), it does a fake paint. So we need + // to handle the case where platformContext() is null. However, we still + // want to call paint, since WebKit must have called the paint for a reason. + SkCanvas* canvas = ctx->platformContext() ? ctx->platformContext()->mCanvas : NULL; + if (canvas) { + const WebCore::IntRect& bounds = getBounds(); + + // Grab the intersection of transRect and the frame's bounds. + transRect.intersect(bounds); + if (transRect.isEmpty()) + return; + + // Move the transRect into the frame's local coordinates. + transRect.move(-bounds.x(), -bounds.y()); + + // Translate the canvas, add a clip. + canvas->save(); + canvas->translate(SkIntToScalar(bounds.x()), SkIntToScalar(bounds.y())); + canvas->clipRect(transRect); + } + mFrameView->paintContents(ctx, transRect); + if (canvas) + canvas->restore(); + } else { + mFrameView->paintContents(ctx, rect); + } +} + +void WebFrameView::setView(WebCore::FrameView* frameView) { + mFrameView = frameView; + mFrameView->setPlatformWidget(this); +} + +} // namespace android diff --git a/Source/WebKit/android/jni/WebFrameView.h b/Source/WebKit/android/jni/WebFrameView.h new file mode 100644 index 0000000..823f2b4 --- /dev/null +++ b/Source/WebKit/android/jni/WebFrameView.h @@ -0,0 +1,65 @@ +/* + * 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 WEB_FRAMEVIEW_H +#define WEB_FRAMEVIEW_H + +#include "WebCoreViewBridge.h" + +namespace WebCore { + class FrameView; +} + +namespace android { + class WebViewCore; + + class WebFrameView: public WebCoreViewBridge { + public: + WebFrameView(WebCore::FrameView* frameView, WebViewCore* webViewCore); + virtual ~WebFrameView(); + + virtual void draw(WebCore::GraphicsContext* ctx, + const WebCore::IntRect& rect); + + WebViewCore* webViewCore() const { + return mWebViewCore; + } + + void setView(WebCore::FrameView* frameView); + + WebCore::FrameView* view() const { + return mFrameView; + } + + virtual bool forFrameView() const { return true; } + + private: + WebCore::FrameView* mFrameView; + WebViewCore* mWebViewCore; + }; + +} // namespace android + +#endif // WEB_FRAMEVIEW_H diff --git a/Source/WebKit/android/jni/WebHistory.cpp b/Source/WebKit/android/jni/WebHistory.cpp new file mode 100644 index 0000000..97ce23b --- /dev/null +++ b/Source/WebKit/android/jni/WebHistory.cpp @@ -0,0 +1,857 @@ +/* + * 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. + */ + +#define LOG_TAG "webhistory" + +#include "config.h" +#include "WebHistory.h" + +#include "BackForwardList.h" +#include "BackForwardListImpl.h" +#include "DocumentLoader.h" +#include "Frame.h" +#include "FrameLoader.h" +#include "FrameLoaderClientAndroid.h" +#include "FrameTree.h" +#include "HistoryItem.h" +#include "IconDatabase.h" +#include "Page.h" +#include "TextEncoding.h" +#include "WebCoreFrameBridge.h" +#include "WebCoreJni.h" +#include "WebIconDatabase.h" + +#include +#include "JNIUtility.h" +#include +#include +#include +#include +#include + +namespace android { + +// Forward declarations +static void write_item(WTF::Vector& v, WebCore::HistoryItem* item); +static void write_children_recursive(WTF::Vector& v, WebCore::HistoryItem* parent); +static bool read_item_recursive(WebCore::HistoryItem* child, const char** pData, int length); + +// Field ids for WebHistoryItems +struct WebHistoryItemFields { + jmethodID mInit; + jmethodID mUpdate; + jfieldID mTitle; + jfieldID mUrl; +} gWebHistoryItem; + +struct WebBackForwardListFields { + jmethodID mAddHistoryItem; + jmethodID mRemoveHistoryItem; + jmethodID mSetCurrentIndex; +} gWebBackForwardList; + +//-------------------------------------------------------------------------- +// WebBackForwardList native methods. +//-------------------------------------------------------------------------- + +static void WebHistoryClose(JNIEnv* env, jobject obj, jint frame) +{ + LOG_ASSERT(frame, "Close needs a valid Frame pointer!"); + WebCore::Frame* pFrame = (WebCore::Frame*)frame; + + WebCore::BackForwardListImpl* list = static_cast(pFrame->page()->backForwardList()); + RefPtr current = list->currentItem(); + // Remove each item instead of using close(). close() is intended to be used + // right before the list is deleted. + WebCore::HistoryItemVector& entries = list->entries(); + int size = entries.size(); + for (int i = size - 1; i >= 0; --i) + list->removeItem(entries[i].get()); + // Add the current item back to the list. + if (current) { + current->setBridge(0); + // addItem will update the children to match the newly created bridge + list->addItem(current); + + /* + * The Grand Prix site uses anchor navigations to change the display. + * WebKit tries to be smart and not load child frames that have the + * same history urls during an anchor navigation. This means that the + * current history item stored in the child frame's loader does not + * match the item found in the history tree. If we remove all the + * entries in the back/foward list, we have to restore the entire tree + * or else a HistoryItem might have a deleted parent. + * + * In order to restore the history tree correctly, we have to look up + * all the frames first and then look up the history item. We do this + * because the history item in the tree may be null at this point. + * Unfortunately, a HistoryItem can only search its immediately + * children so we do a breadth-first rebuild of the tree. + */ + + // Keep a small list of child frames to traverse. + WTF::Vector frameQueue; + // Fix the top-level item. + pFrame->loader()->history()->setCurrentItem(current.get()); + WebCore::Frame* child = pFrame->tree()->firstChild(); + // Remember the parent history item so we can search for a child item. + RefPtr parent = current; + while (child) { + // Use the old history item since the current one may have a + // deleted parent. + WebCore::HistoryItem* item = parent->childItemWithTarget(child->tree()->name()); + child->loader()->history()->setCurrentItem(item); + // Append the first child to the queue if it exists. If there is no + // item, then we do not need to traverse the children since there + // will be no parent history item. + WebCore::Frame* firstChild; + if (item && (firstChild = child->tree()->firstChild())) + frameQueue.append(firstChild); + child = child->tree()->nextSibling(); + // If we don't have a sibling for this frame and the queue isn't + // empty, use the next entry in the queue. + if (!child && !frameQueue.isEmpty()) { + child = frameQueue.at(0); + frameQueue.remove(0); + // Figure out the parent history item used when searching for + // the history item to use. + parent = child->tree()->parent()->loader()->history()->currentItem(); + } + } + } +} + +static void WebHistoryRestoreIndex(JNIEnv* env, jobject obj, jint frame, jint index) +{ + LOG_ASSERT(frame, "RestoreState needs a valid Frame pointer!"); + WebCore::Frame* pFrame = (WebCore::Frame*)frame; + WebCore::Page* page = pFrame->page(); + WebCore::HistoryItem* currentItem = + static_cast(page->backForwardList())->entries()[index].get(); + + // load the current page with FrameLoadTypeIndexedBackForward so that it + // will use cache when it is possible + page->goToItem(currentItem, FrameLoadTypeIndexedBackForward); +} + +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!"); + + // Get the actual bytes and the length from the java array. + const jbyte* bytes = env->GetByteArrayElements(data, NULL); + jsize size = env->GetArrayLength(data); + + // Inflate the history tree into one HistoryItem or null if the inflation + // failed. + RefPtr newItem = WebCore::HistoryItem::create(); + WebHistoryItem* bridge = new WebHistoryItem(env, obj, newItem.get()); + newItem->setBridge(bridge); + + // Inflate the item recursively. If it fails, that is ok. We'll have an + // incomplete HistoryItem but that is better than crashing due to a null + // item. + // We have a 2nd local variable since read_item_recursive may change the + // ptr's value. We can't pass &bytes since we have to send bytes to + // ReleaseByteArrayElements unchanged. + const char* ptr = reinterpret_cast(bytes); + read_item_recursive(newItem.get(), &ptr, (int)size); + env->ReleaseByteArrayElements(data, const_cast(bytes), JNI_ABORT); + bridge->setActive(); + + // Add the new item to the back/forward list. + WebCore::Frame* pFrame = (WebCore::Frame*)frame; + pFrame->page()->backForwardList()->addItem(newItem); + + // Update the item. + bridge->updateHistoryItem(newItem.get()); +} + +// 6 empty strings + no document state + children count + 2 scales = 10 unsigned values +// 1 char for isTargetItem. +#define HISTORY_MIN_SIZE ((int)(sizeof(unsigned) * 10 + sizeof(char))) + +jbyteArray WebHistory::Flatten(JNIEnv* env, WTF::Vector& v, 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); + + // Write the top-level history item and then write all the children + // recursively. + LOG_ASSERT(item->bridge(), "Why don't we have a bridge object here?"); + write_item(v, item); + write_children_recursive(v, item); + + // Try to create a new java byte array. + jbyteArray b = env->NewByteArray(v.size()); + if (!b) + return NULL; + + // Write our flattened data to the java array. + env->SetByteArrayRegion(b, 0, v.size(), (const jbyte*)v.data()); + return b; +} + +WebHistoryItem::WebHistoryItem(JNIEnv* env, jobject obj, + WebCore::HistoryItem* item) : WebCore::AndroidWebHistoryBridge(item) { + m_object = env->NewWeakGlobalRef(obj); + m_parent = 0; +} + +WebHistoryItem::~WebHistoryItem() { + if (m_object) { + JNIEnv* env = JSC::Bindings::getJNIEnv(); + if (!env) + return; + env->DeleteWeakGlobalRef(m_object); + } +} + +void WebHistoryItem::updateHistoryItem(WebCore::HistoryItem* item) { + // Do not want to update during inflation. + if (!m_active) + return; + WebHistoryItem* webItem = this; + // Now we need to update the top-most WebHistoryItem based on the top-most + // HistoryItem. + if (m_parent) { + webItem = m_parent.get(); + if (webItem->hasOneRef()) { + // 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"); + return; + } + while (webItem->parent()) + webItem = webItem->parent(); + item = webItem->historyItem(); + if (!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"); + return; + } + } + JNIEnv* env = JSC::Bindings::getJNIEnv(); + if (!env) + return; + + // Don't do anything if the item has been gc'd already + AutoJObject realItem = getRealObject(env, webItem->m_object); + if (!realItem.get()) + return; + + const WTF::String& urlString = item->urlString(); + jstring urlStr = NULL; + if (!urlString.isNull()) + urlStr = wtfStringToJstring(env, urlString); + const WTF::String& originalUrlString = item->originalURLString(); + jstring originalUrlStr = NULL; + if (!originalUrlString.isNull()) + originalUrlStr = wtfStringToJstring(env, originalUrlString); + const WTF::String& titleString = item->title(); + jstring titleStr = NULL; + if (!titleString.isNull()) + titleStr = wtfStringToJstring(env, titleString); + + // Try to get the favicon from the history item. For some pages like Grand + // Prix, there are history items with anchors. If the icon fails for the + // item, try to get the icon using the url without the ref. + jobject favicon = NULL; + WTF::String url = item->urlString(); + if (item->url().hasFragmentIdentifier()) { + int refIndex = url.reverseFind('#'); + url = url.substring(0, refIndex); + } + WebCore::Image* icon = WebCore::iconDatabase()->iconForPageURL(url, + WebCore::IntSize(16, 16)); + + if (icon) + favicon = webcoreImageToJavaBitmap(env, icon); + + WTF::Vector data; + jbyteArray array = WebHistory::Flatten(env, data, item); + env->CallVoidMethod(realItem.get(), gWebHistoryItem.mUpdate, urlStr, + originalUrlStr, titleStr, favicon, array); + env->DeleteLocalRef(urlStr); + env->DeleteLocalRef(originalUrlStr); + env->DeleteLocalRef(titleStr); + if (favicon) + env->DeleteLocalRef(favicon); + env->DeleteLocalRef(array); +} + +static void historyItemChanged(WebCore::HistoryItem* item) { + LOG_ASSERT(item, "historyItemChanged called with a null item"); + + if (item->bridge()) + item->bridge()->updateHistoryItem(item); +} + +void WebHistory::AddItem(const AutoJObject& list, WebCore::HistoryItem* item) +{ + LOG_ASSERT(item, "newItem must take a valid HistoryItem!"); + // Item already added. Should only happen when we are inflating the list. + if (item->bridge() || !list.get()) + return; + + JNIEnv* env = list.env(); + // Allocate a blank WebHistoryItem + jclass clazz = env->FindClass("android/webkit/WebHistoryItem"); + jobject newItem = env->NewObject(clazz, gWebHistoryItem.mInit); + env->DeleteLocalRef(clazz); + + // Create the bridge, make it active, and attach it to the item. + WebHistoryItem* bridge = new WebHistoryItem(env, newItem, item); + bridge->setActive(); + item->setBridge(bridge); + + // Update the history item which will flatten the data and call update on + // the java item. + bridge->updateHistoryItem(item); + + // Add it to the list. + env->CallVoidMethod(list.get(), gWebBackForwardList.mAddHistoryItem, newItem); + + // Delete our local reference. + env->DeleteLocalRef(newItem); +} + +void WebHistory::RemoveItem(const AutoJObject& list, int index) +{ + if (list.get()) + list.env()->CallVoidMethod(list.get(), gWebBackForwardList.mRemoveHistoryItem, index); +} + +void WebHistory::UpdateHistoryIndex(const AutoJObject& list, int newIndex) +{ + if (list.get()) + list.env()->CallVoidMethod(list.get(), gWebBackForwardList.mSetCurrentIndex, newIndex); +} + +static void write_string(WTF::Vector& v, const WTF::String& str) +{ + unsigned strLen = str.length(); + // Only do work if the string has data. + if (strLen) { + // 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 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); + // Grab the position to write to. + char* data = v.begin() + vectorLen; + // Write the actual string + int l = SkUTF16_ToUTF8(str.characters(), strLen, data); + LOGV("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); + } else + v.append((char*)&strLen, sizeof(unsigned)); +} + +static void write_item(WTF::Vector& v, WebCore::HistoryItem* item) +{ + // Original url + write_string(v, item->originalURLString()); + + // Url + write_string(v, item->urlString()); + + // Title + write_string(v, item->title()); + + // Form content type + write_string(v, item->formContentType()); + + // Form data + const WebCore::FormData* formData = item->formData(); + if (formData) { + write_string(v, 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)); + } else + write_string(v, WTF::String()); // Empty constructor does not allocate a buffer. + + // Target + write_string(v, item->target()); + + AndroidWebHistoryBridge* bridge = item->bridge(); + LOG_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)); + const float textWrapScale = bridge->textWrapScale(); + LOGV("Writing text wrap scale %f", textWrapScale); + v.append((char*)&textWrapScale, sizeof(float)); + + // Scroll position. + const int scrollX = item->scrollPoint().x(); + v.append((char*)&scrollX, sizeof(int)); + const int scrollY = item->scrollPoint().y(); + v.append((char*)&scrollY, sizeof(int)); + + // Document state + const WTF::Vector& docState = item->documentState(); + WTF::Vector::const_iterator end = docState.end(); + unsigned stateSize = docState.size(); + LOGV("Writing docState %d", stateSize); + v.append((char*)&stateSize, sizeof(unsigned)); + for (WTF::Vector::const_iterator i = docState.begin(); i != end; ++i) { + write_string(v, *i); + } + + // Is target item + LOGV("Writing isTargetItem %d", item->isTargetItem()); + v.append((char)item->isTargetItem()); + + // Children count + unsigned childCount = item->children().size(); + LOGV("Writing childCount %d", childCount); + v.append((char*)&childCount, sizeof(unsigned)); +} + +static void write_children_recursive(WTF::Vector& v, 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(), + "The parent item should have a bridge object!"); + if (!item->bridge()) { + WebHistoryItem* bridge = new WebHistoryItem(static_cast(parent->bridge())); + item->setBridge(bridge); + bridge->setActive(); + } else { + // The only time this item's parent may not be the same as the + // parent's bridge is during history close. In that case, the + // parent must not have a parent bridge. + WebHistoryItem* bridge = static_cast(item->bridge()); + WebHistoryItem* parentBridge = static_cast(parent->bridge()); + LOG_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); + } +} + +static bool read_item_recursive(WebCore::HistoryItem* newItem, + const char** pData, int length) +{ + if (!pData || length < HISTORY_MIN_SIZE) + return false; + + const WebCore::TextEncoding& e = WebCore::UTF8Encoding(); + const char* data = *pData; + const char* end = data + length; + int sizeofUnsigned = (int)sizeof(unsigned); + + // Read the original url + // Read the expected length of the string. + int 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) + 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) + 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) + return false; + + // Generate a new ResourceRequest object for populating form information. + WTF::String formContentType; + WTF::PassRefPtr formData = NULL; + + // 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) + 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 + 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); + } + } + if (end - data < sizeofUnsigned) + return false; + + // Set up the form info + if (formData != NULL) { + WebCore::ResourceRequest r; + r.setHTTPMethod("POST"); + r.setHTTPContentType(formContentType); + r.setHTTPBody(formData); + newItem->setFormInfoFromRequest(r); + } + + // 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) + return false; + + AndroidWebHistoryBridge* bridge = newItem->bridge(); + LOG_ASSERT(bridge, "There should be a bridge object during inflate"); + float fValue; + // 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); + + if (end - data < sizeofUnsigned) + 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) + return false; + + // 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; + // Create a new vector and reserve enough space for the document state. + WTF::Vector 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)); + 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) + return false; + + // Read the child count + memcpy(&l, data, sizeofUnsigned); + LOGV("Child count %d", l); + data += sizeofUnsigned; + *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--) { + // 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 child = WebCore::HistoryItem::create(); + // Set a bridge that will not call into java. + child->setBridge(new WebHistoryItem(static_cast(bridge))); + // Read the child item. + if (!read_item_recursive(child.get(), pData, end - data)) { + child.clear(); + return false; + } + child->bridge()->setActive(); + newItem->addChildItem(child); + } + } + return true; +} + +// On arm, this test will cause memory corruption since converting char* will +// byte align the result and this test does not use memset (it probably +// should). +// On the simulator, using HistoryItem will invoke the IconDatabase which will +// initialize the main thread. Since this is invoked by the Zygote process, the +// 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() +{ + LOGD("Entering history unit test!"); + const char* test1 = new char[0]; + WTF::RefPtr 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!"); + delete[] test1; + const char* test2 = new char[2]; + LOG_ASSERT(!read_item_recursive(testItem, &test2, 2), "Small array should fail!"); + delete[] test2; + LOG_ASSERT(!read_item_recursive(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!"); + // 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!"); + // 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!"); + // 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!"); + // 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!"); + // 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 + // 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!"); + // 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!"); + // 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; + // Test document state + 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!"); + delete[] test3; + test3 = new char[HISTORY_MIN_SIZE + 2 * sizeof(unsigned)]; + memset(test3, 0, HISTORY_MIN_SIZE + 2 * sizeof(unsigned)); + ptr = (const char*)test3; + *(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!"); + delete[] test3; +} +#endif + +//--------------------------------------------------------- +// JNI registration +//--------------------------------------------------------- +static JNINativeMethod gWebBackForwardListMethods[] = { + { "nativeClose", "(I)V", + (void*) WebHistoryClose }, + { "restoreIndex", "(II)V", + (void*) WebHistoryRestoreIndex } +}; + +static JNINativeMethod gWebHistoryItemMethods[] = { + { "inflate", "(I[B)V", + (void*) WebHistoryInflate } +}; + +int registerWebHistory(JNIEnv* env) +{ + // Get notified of all changes to history items. + WebCore::notifyHistoryItemChanged = historyItemChanged; +#ifdef UNIT_TEST + unit_test(); +#endif + // Find WebHistoryItem, its constructor, and the update method. + jclass clazz = env->FindClass("android/webkit/WebHistoryItem"); + LOG_ASSERT(clazz, "Unable to find class android/webkit/WebHistoryItem"); + gWebHistoryItem.mInit = env->GetMethodID(clazz, "", "()V"); + LOG_ASSERT(gWebHistoryItem.mInit, "Could not find WebHistoryItem constructor"); + gWebHistoryItem.mUpdate = env->GetMethodID(clazz, "update", + "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Landroid/graphics/Bitmap;[B)V"); + LOG_ASSERT(gWebHistoryItem.mUpdate, "Could not find method update in WebHistoryItem"); + + // Find the field ids for mTitle and mUrl. + gWebHistoryItem.mTitle = env->GetFieldID(clazz, "mTitle", "Ljava/lang/String;"); + LOG_ASSERT(gWebHistoryItem.mTitle, "Could not find field mTitle in WebHistoryItem"); + gWebHistoryItem.mUrl = env->GetFieldID(clazz, "mUrl", "Ljava/lang/String;"); + LOG_ASSERT(gWebHistoryItem.mUrl, "Could not find field mUrl in WebHistoryItem"); + 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"); + gWebBackForwardList.mAddHistoryItem = env->GetMethodID(clazz, "addHistoryItem", + "(Landroid/webkit/WebHistoryItem;)V"); + LOG_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"); + gWebBackForwardList.mSetCurrentIndex = env->GetMethodID(clazz, "setCurrentIndex", "(I)V"); + LOG_ASSERT(gWebBackForwardList.mSetCurrentIndex, "Could not find method setCurrentIndex"); + env->DeleteLocalRef(clazz); + + int result = jniRegisterNativeMethods(env, "android/webkit/WebBackForwardList", + gWebBackForwardListMethods, NELEM(gWebBackForwardListMethods)); + return (result < 0) ? result : jniRegisterNativeMethods(env, "android/webkit/WebHistoryItem", + gWebHistoryItemMethods, NELEM(gWebHistoryItemMethods)); +} + +} /* namespace android */ diff --git a/Source/WebKit/android/jni/WebHistory.h b/Source/WebKit/android/jni/WebHistory.h new file mode 100644 index 0000000..2d86aa4 --- /dev/null +++ b/Source/WebKit/android/jni/WebHistory.h @@ -0,0 +1,68 @@ +/* + * 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 ANDROID_WEBKIT_WEBHISTORY_H +#define ANDROID_WEBKIT_WEBHISTORY_H + +#include "AndroidWebHistoryBridge.h" + +#include +#include +#include + +namespace android { + +class AutoJObject; + +class WebHistory { +public: + static jbyteArray Flatten(JNIEnv*, WTF::Vector&, WebCore::HistoryItem*); + static void AddItem(const AutoJObject&, WebCore::HistoryItem*); + static void RemoveItem(const AutoJObject&, int); + static void UpdateHistoryIndex(const AutoJObject&, int); +}; + +// there are two scale factors saved with each history item. m_scale reflects the +// viewport scale factor, default to 100 means 100%. m_textWrapScale records +// the scale factor for wrapping the text paragraph. +class WebHistoryItem : public WebCore::AndroidWebHistoryBridge { +public: + WebHistoryItem(WebHistoryItem* parent) + : WebCore::AndroidWebHistoryBridge(0) + , m_parent(parent) + , m_object(NULL) { } + WebHistoryItem(JNIEnv*, jobject, WebCore::HistoryItem*); + ~WebHistoryItem(); + void updateHistoryItem(WebCore::HistoryItem* item); + void setParent(WebHistoryItem* parent) { m_parent = parent; } + WebHistoryItem* parent() const { return m_parent.get(); } +private: + RefPtr m_parent; + jweak m_object; +}; + +}; + +#endif diff --git a/Source/WebKit/android/jni/WebIconDatabase.cpp b/Source/WebKit/android/jni/WebIconDatabase.cpp new file mode 100644 index 0000000..2a660d1 --- /dev/null +++ b/Source/WebKit/android/jni/WebIconDatabase.cpp @@ -0,0 +1,237 @@ +/* + * 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 "favicons" + +#include "config.h" +#include "WebIconDatabase.h" + +#include "FileSystem.h" +#include "GraphicsJNI.h" +#include "IconDatabase.h" +#include "Image.h" +#include "IntRect.h" +#include "JavaSharedClient.h" +#include "KURL.h" +#include "WebCoreJni.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace android { + +jobject webcoreImageToJavaBitmap(JNIEnv* env, WebCore::Image* icon) +{ + if (!icon) + return NULL; + SkBitmap bm; + WebCore::SharedBuffer* buffer = icon->data(); + if (!buffer || !SkImageDecoder::DecodeMemory(buffer->data(), buffer->size(), + &bm, SkBitmap::kNo_Config, + SkImageDecoder::kDecodePixels_Mode)) + return NULL; + + return GraphicsJNI::createBitmap(env, new SkBitmap(bm), false, NULL); +} + +static WebIconDatabase* gIconDatabaseClient = new WebIconDatabase(); + +// XXX: Called by the IconDatabase thread +void WebIconDatabase::dispatchDidAddIconForPageURL(const WTF::String& pageURL) +{ + mNotificationsMutex.lock(); + mNotifications.append(pageURL); + if (!mDeliveryRequested) { + mDeliveryRequested = true; + JavaSharedClient::EnqueueFunctionPtr(DeliverNotifications, this); + } + mNotificationsMutex.unlock(); +} + +// Called in the WebCore thread +void WebIconDatabase::RegisterForIconNotification(WebIconDatabaseClient* client) +{ + WebIconDatabase* db = gIconDatabaseClient; + for (unsigned i = 0; i < db->mClients.size(); ++i) { + // Do not add the same client twice. + if (db->mClients[i] == client) + return; + } + gIconDatabaseClient->mClients.append(client); +} + +// Called in the WebCore thread +void WebIconDatabase::UnregisterForIconNotification(WebIconDatabaseClient* client) +{ + WebIconDatabase* db = gIconDatabaseClient; + for (unsigned i = 0; i < db->mClients.size(); ++i) { + if (db->mClients[i] == client) { + db->mClients.remove(i); + break; + } + } +} + +// Called in the WebCore thread +void WebIconDatabase::DeliverNotifications(void* v) +{ + ASSERT(v); + ((WebIconDatabase*)v)->deliverNotifications(); +} + +// Called in the WebCore thread +void WebIconDatabase::deliverNotifications() +{ + ASSERT(mDeliveryRequested); + + // Swap the notifications queue + Vector queue; + mNotificationsMutex.lock(); + queue.swap(mNotifications); + mDeliveryRequested = false; + mNotificationsMutex.unlock(); + + // Swap the clients queue + Vector clients; + clients.swap(mClients); + + for (unsigned i = 0; i < queue.size(); ++i) { + for (unsigned j = 0; j < clients.size(); ++j) { + clients[j]->didAddIconForPageUrl(queue[i]); + } + } +} + +static void Open(JNIEnv* env, jobject obj, jstring path) +{ + WebCore::IconDatabase* iconDb = WebCore::iconDatabase(); + if (iconDb->isOpen()) + return; + iconDb->setEnabled(true); + iconDb->setClient(gIconDatabaseClient); + LOG_ASSERT(path, "No path given to nativeOpen"); + WTF::String pathStr = jstringToWtfString(env, path); + WTF::CString fullPath = WebCore::pathByAppendingComponent(pathStr, + WebCore::IconDatabase::defaultDatabaseFilename()).utf8(); + mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP; + bool didSetPermissions = false; + if (access(fullPath.data(), F_OK) == 0) { + if (chmod(fullPath.data(), mode) == 0) + didSetPermissions = true; + } else { + int fd = open(fullPath.data(), O_CREAT, mode); + if (fd >= 0) { + close(fd); + didSetPermissions = true; + } + } + if (didSetPermissions) { + LOGV("Opening WebIconDatabase file '%s'", pathStr.latin1().data()); + bool res = iconDb->open(pathStr); + if (!res) + LOGE("Open failed!"); + } else + LOGE("Failed to set permissions on '%s'", fullPath.data()); +} + +static void Close(JNIEnv* env, jobject obj) +{ + WebCore::iconDatabase()->close(); +} + +static void RemoveAllIcons(JNIEnv* env, jobject obj) +{ + LOGV("Removing all icons"); + WebCore::iconDatabase()->removeAllIcons(); +} + +static jobject IconForPageUrl(JNIEnv* env, jobject obj, jstring url) +{ + LOG_ASSERT(url, "No url given to iconForPageUrl"); + WTF::String urlStr = jstringToWtfString(env, url); + + WebCore::Image* icon = WebCore::iconDatabase()->iconForPageURL(urlStr, + WebCore::IntSize(16, 16)); + LOGV("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"); + WTF::String urlStr = jstringToWtfString(env, url); + + LOGV("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"); + WTF::String urlStr = jstringToWtfString(env, url); + + LOGV("Releasing icon for '%s'", urlStr.latin1().data()); + WebCore::iconDatabase()->releaseIconForPageURL(urlStr); +} + +/* + * JNI registration + */ +static JNINativeMethod gWebIconDatabaseMethods[] = { + { "nativeOpen", "(Ljava/lang/String;)V", + (void*) Open }, + { "nativeClose", "()V", + (void*) Close }, + { "nativeRemoveAllIcons", "()V", + (void*) RemoveAllIcons }, + { "nativeIconForPageUrl", "(Ljava/lang/String;)Landroid/graphics/Bitmap;", + (void*) IconForPageUrl }, + { "nativeRetainIconForPageUrl", "(Ljava/lang/String;)V", + (void*) RetainIconForPageUrl }, + { "nativeReleaseIconForPageUrl", "(Ljava/lang/String;)V", + (void*) ReleaseIconForPageUrl } +}; + +int registerWebIconDatabase(JNIEnv* env) +{ +#ifndef NDEBUG + jclass webIconDatabase = env->FindClass("android/webkit/WebIconDatabase"); + LOG_ASSERT(webIconDatabase, "Unable to find class android.webkit.WebIconDatabase"); + env->DeleteLocalRef(webIconDatabase); +#endif + + return jniRegisterNativeMethods(env, "android/webkit/WebIconDatabase", + gWebIconDatabaseMethods, NELEM(gWebIconDatabaseMethods)); +} + +} diff --git a/Source/WebKit/android/jni/WebIconDatabase.h b/Source/WebKit/android/jni/WebIconDatabase.h new file mode 100644 index 0000000..b2169aa --- /dev/null +++ b/Source/WebKit/android/jni/WebIconDatabase.h @@ -0,0 +1,75 @@ +/* + * 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 ANDROID_WEBKIT_WEBICONDATABASE_H +#define ANDROID_WEBKIT_WEBICONDATABASE_H + +#include "IconDatabaseClient.h" +#include "PlatformString.h" +#include "utils/threads.h" +#include +#include + +namespace WebCore { + class Image; +} + +namespace android { + + class WebIconDatabaseClient { + public: + virtual ~WebIconDatabaseClient() {} + virtual void didAddIconForPageUrl(const WTF::String& pageUrl) = 0; + }; + + class WebIconDatabase : public WebCore::IconDatabaseClient { + public: + WebIconDatabase() : mDeliveryRequested(false) {} + // IconDatabaseClient method + virtual void dispatchDidAddIconForPageURL(const WTF::String& pageURL); + + static void RegisterForIconNotification(WebIconDatabaseClient* client); + static void UnregisterForIconNotification(WebIconDatabaseClient* client); + static void DeliverNotifications(void*); + + private: + // Deliver all the icon notifications + void deliverNotifications(); + + // List of clients. + Vector mClients; + + // Queue of page urls that have received an icon. + Vector mNotifications; + android::Mutex mNotificationsMutex; + // Flag to indicate that we have requested a delivery of notifications. + bool mDeliveryRequested; + }; + + jobject webcoreImageToJavaBitmap(JNIEnv* env, WebCore::Image* icon); + +}; + +#endif diff --git a/Source/WebKit/android/jni/WebSettings.cpp b/Source/WebKit/android/jni/WebSettings.cpp new file mode 100644 index 0000000..468e7b0 --- /dev/null +++ b/Source/WebKit/android/jni/WebSettings.cpp @@ -0,0 +1,599 @@ +/* + * 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. + */ + +#define LOG_TAG "websettings" + +#include +#include + +#include "ApplicationCacheStorage.h" +#include "BitmapAllocatorAndroid.h" +#include "CachedResourceLoader.h" +#include "ChromiumIncludes.h" +#include "DatabaseTracker.h" +#include "Database.h" +#include "Document.h" +#include "EditorClientAndroid.h" +#include "FileSystem.h" +#include "Frame.h" +#include "FrameLoader.h" +#include "FrameView.h" +#include "GeolocationPermissions.h" +#include "GeolocationPositionCache.h" +#include "Page.h" +#include "PageCache.h" +#include "RenderTable.h" +#include "SQLiteFileSystem.h" +#include "Settings.h" +#include "WebCoreFrameBridge.h" +#include "WebCoreJni.h" +#if USE(V8) +#include "WorkerContextExecutionProxy.h" +#endif +#include "WebRequestContext.h" +#include "WebViewCore.h" + +#include +#include +#include + +namespace android { + +static const int permissionFlags660 = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP; + +struct FieldIds { + FieldIds(JNIEnv* env, jclass clazz) { + mLayoutAlgorithm = env->GetFieldID(clazz, "mLayoutAlgorithm", + "Landroid/webkit/WebSettings$LayoutAlgorithm;"); + mTextSize = env->GetFieldID(clazz, "mTextSize", + "Landroid/webkit/WebSettings$TextSize;"); + mStandardFontFamily = env->GetFieldID(clazz, "mStandardFontFamily", + "Ljava/lang/String;"); + mFixedFontFamily = env->GetFieldID(clazz, "mFixedFontFamily", + "Ljava/lang/String;"); + mSansSerifFontFamily = env->GetFieldID(clazz, "mSansSerifFontFamily", + "Ljava/lang/String;"); + mSerifFontFamily = env->GetFieldID(clazz, "mSerifFontFamily", + "Ljava/lang/String;"); + mCursiveFontFamily = env->GetFieldID(clazz, "mCursiveFontFamily", + "Ljava/lang/String;"); + mFantasyFontFamily = env->GetFieldID(clazz, "mFantasyFontFamily", + "Ljava/lang/String;"); + mDefaultTextEncoding = env->GetFieldID(clazz, "mDefaultTextEncoding", + "Ljava/lang/String;"); + mUserAgent = env->GetFieldID(clazz, "mUserAgent", + "Ljava/lang/String;"); + mAcceptLanguage = env->GetFieldID(clazz, "mAcceptLanguage", "Ljava/lang/String;"); + mMinimumFontSize = env->GetFieldID(clazz, "mMinimumFontSize", "I"); + mMinimumLogicalFontSize = env->GetFieldID(clazz, "mMinimumLogicalFontSize", "I"); + mDefaultFontSize = env->GetFieldID(clazz, "mDefaultFontSize", "I"); + mDefaultFixedFontSize = env->GetFieldID(clazz, "mDefaultFixedFontSize", "I"); + mLoadsImagesAutomatically = env->GetFieldID(clazz, "mLoadsImagesAutomatically", "Z"); +#ifdef ANDROID_BLOCK_NETWORK_IMAGE + mBlockNetworkImage = env->GetFieldID(clazz, "mBlockNetworkImage", "Z"); +#endif + mBlockNetworkLoads = env->GetFieldID(clazz, "mBlockNetworkLoads", "Z"); + mJavaScriptEnabled = env->GetFieldID(clazz, "mJavaScriptEnabled", "Z"); + mPluginState = env->GetFieldID(clazz, "mPluginState", + "Landroid/webkit/WebSettings$PluginState;"); +#if ENABLE(DATABASE) + mDatabaseEnabled = env->GetFieldID(clazz, "mDatabaseEnabled", "Z"); +#endif +#if ENABLE(DOM_STORAGE) + mDomStorageEnabled = env->GetFieldID(clazz, "mDomStorageEnabled", "Z"); +#endif +#if ENABLE(DATABASE) || ENABLE(DOM_STORAGE) + // The databases saved to disk for both the SQL and DOM Storage APIs are stored + // in the same base directory. + mDatabasePath = env->GetFieldID(clazz, "mDatabasePath", "Ljava/lang/String;"); + mDatabasePathHasBeenSet = env->GetFieldID(clazz, "mDatabasePathHasBeenSet", "Z"); +#endif +#if ENABLE(OFFLINE_WEB_APPLICATIONS) + mAppCacheEnabled = env->GetFieldID(clazz, "mAppCacheEnabled", "Z"); + mAppCachePath = env->GetFieldID(clazz, "mAppCachePath", "Ljava/lang/String;"); + mAppCacheMaxSize = env->GetFieldID(clazz, "mAppCacheMaxSize", "J"); +#endif +#if ENABLE(WORKERS) + mWorkersEnabled = env->GetFieldID(clazz, "mWorkersEnabled", "Z"); +#endif + mGeolocationEnabled = env->GetFieldID(clazz, "mGeolocationEnabled", "Z"); + mGeolocationDatabasePath = env->GetFieldID(clazz, "mGeolocationDatabasePath", "Ljava/lang/String;"); + mXSSAuditorEnabled = env->GetFieldID(clazz, "mXSSAuditorEnabled", "Z"); + mJavaScriptCanOpenWindowsAutomatically = env->GetFieldID(clazz, + "mJavaScriptCanOpenWindowsAutomatically", "Z"); + mUseWideViewport = env->GetFieldID(clazz, "mUseWideViewport", "Z"); + mSupportMultipleWindows = env->GetFieldID(clazz, "mSupportMultipleWindows", "Z"); + mShrinksStandaloneImagesToFit = env->GetFieldID(clazz, "mShrinksStandaloneImagesToFit", "Z"); + mMaximumDecodedImageSize = env->GetFieldID(clazz, "mMaximumDecodedImageSize", "J"); + mPrivateBrowsingEnabled = env->GetFieldID(clazz, "mPrivateBrowsingEnabled", "Z"); + mSyntheticLinksEnabled = env->GetFieldID(clazz, "mSyntheticLinksEnabled", "Z"); + mUseDoubleTree = env->GetFieldID(clazz, "mUseDoubleTree", "Z"); + mPageCacheCapacity = env->GetFieldID(clazz, "mPageCacheCapacity", "I"); +#if ENABLE(WEB_AUTOFILL) + mAutoFillEnabled = env->GetFieldID(clazz, "mAutoFillEnabled", "Z"); + mAutoFillProfile = env->GetFieldID(clazz, "mAutoFillProfile", "Landroid/webkit/WebSettings$AutoFillProfile;"); + jclass autoFillProfileClass = env->FindClass("android/webkit/WebSettings$AutoFillProfile"); + mAutoFillProfileFullName = env->GetFieldID(autoFillProfileClass, "mFullName", "Ljava/lang/String;"); + mAutoFillProfileEmailAddress = env->GetFieldID(autoFillProfileClass, "mEmailAddress", "Ljava/lang/String;"); + mAutoFillProfileCompanyName = env->GetFieldID(autoFillProfileClass, "mCompanyName", "Ljava/lang/String;"); + mAutoFillProfileAddressLine1 = env->GetFieldID(autoFillProfileClass, "mAddressLine1", "Ljava/lang/String;"); + mAutoFillProfileAddressLine2 = env->GetFieldID(autoFillProfileClass, "mAddressLine2", "Ljava/lang/String;"); + mAutoFillProfileCity = env->GetFieldID(autoFillProfileClass, "mCity", "Ljava/lang/String;"); + mAutoFillProfileState = env->GetFieldID(autoFillProfileClass, "mState", "Ljava/lang/String;"); + mAutoFillProfileZipCode = env->GetFieldID(autoFillProfileClass, "mZipCode", "Ljava/lang/String;"); + mAutoFillProfileCountry = env->GetFieldID(autoFillProfileClass, "mCountry", "Ljava/lang/String;"); + 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"); +#ifdef ANDROID_BLOCK_NETWORK_IMAGE + LOG_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"); +#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"); +#endif +#if ENABLE(WORKERS) + LOG_ASSERT(mWorkersEnabled, "Could not find field mWorkersEnabled"); +#endif + LOG_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"); + + jclass enumClass = env->FindClass("java/lang/Enum"); + LOG_ASSERT(enumClass, "Could not find Enum class!"); + mOrdinal = env->GetMethodID(enumClass, "ordinal", "()I"); + LOG_ASSERT(mOrdinal, "Could not find method ordinal"); + env->DeleteLocalRef(enumClass); + + jclass textSizeClass = env->FindClass("android/webkit/WebSettings$TextSize"); + LOG_ASSERT(textSizeClass, "Could not find TextSize enum"); + mTextSizeValue = env->GetFieldID(textSizeClass, "value", "I"); + env->DeleteLocalRef(textSizeClass); + } + + // Field ids + jfieldID mLayoutAlgorithm; + jfieldID mTextSize; + jfieldID mStandardFontFamily; + jfieldID mFixedFontFamily; + jfieldID mSansSerifFontFamily; + jfieldID mSerifFontFamily; + jfieldID mCursiveFontFamily; + jfieldID mFantasyFontFamily; + jfieldID mDefaultTextEncoding; + jfieldID mUserAgent; + jfieldID mAcceptLanguage; + jfieldID mMinimumFontSize; + jfieldID mMinimumLogicalFontSize; + jfieldID mDefaultFontSize; + jfieldID mDefaultFixedFontSize; + jfieldID mLoadsImagesAutomatically; +#ifdef ANDROID_BLOCK_NETWORK_IMAGE + jfieldID mBlockNetworkImage; +#endif + jfieldID mBlockNetworkLoads; + jfieldID mJavaScriptEnabled; + jfieldID mPluginState; +#if ENABLE(OFFLINE_WEB_APPLICATIONS) + jfieldID mAppCacheEnabled; + jfieldID mAppCachePath; + jfieldID mAppCacheMaxSize; +#endif +#if ENABLE(WORKERS) + jfieldID mWorkersEnabled; +#endif + jfieldID mJavaScriptCanOpenWindowsAutomatically; + jfieldID mUseWideViewport; + jfieldID mSupportMultipleWindows; + jfieldID mShrinksStandaloneImagesToFit; + jfieldID mMaximumDecodedImageSize; + jfieldID mPrivateBrowsingEnabled; + jfieldID mSyntheticLinksEnabled; + jfieldID mUseDoubleTree; + jfieldID mPageCacheCapacity; + // Ordinal() method and value field for enums + jmethodID mOrdinal; + jfieldID mTextSizeValue; + +#if ENABLE(DATABASE) + jfieldID mDatabaseEnabled; +#endif +#if ENABLE(DOM_STORAGE) + jfieldID mDomStorageEnabled; +#endif + jfieldID mGeolocationEnabled; + jfieldID mGeolocationDatabasePath; + jfieldID mXSSAuditorEnabled; +#if ENABLE(DATABASE) || ENABLE(DOM_STORAGE) + jfieldID mDatabasePath; + jfieldID mDatabasePathHasBeenSet; +#endif +#if ENABLE(WEB_AUTOFILL) + jfieldID mAutoFillEnabled; + jfieldID mAutoFillProfile; + jfieldID mAutoFillProfileFullName; + jfieldID mAutoFillProfileEmailAddress; + jfieldID mAutoFillProfileCompanyName; + jfieldID mAutoFillProfileAddressLine1; + jfieldID mAutoFillProfileAddressLine2; + jfieldID mAutoFillProfileCity; + jfieldID mAutoFillProfileState; + jfieldID mAutoFillProfileZipCode; + jfieldID mAutoFillProfileCountry; + jfieldID mAutoFillProfilePhoneNumber; +#endif +#if USE(CHROME_NETWORK_STACK) + jfieldID mOverrideCacheMode; +#endif +}; + +static struct FieldIds* gFieldIds; + +// Note: This is moved from the old FrameAndroid.cpp +static void recursiveCleanupForFullLayout(WebCore::RenderObject* obj) +{ + obj->setNeedsLayout(true, false); +#ifdef ANDROID_LAYOUT + if (obj->isTable()) + (static_cast(obj))->clearSingleColumn(); +#endif + for (WebCore::RenderObject* n = obj->firstChild(); n; n = n->nextSibling()) + recursiveCleanupForFullLayout(n); +} + +#if ENABLE(WEB_AUTOFILL) +inline string16 getStringFieldAsString16(JNIEnv* env, jobject autoFillProfile, jfieldID fieldId) +{ + jstring str = static_cast(env->GetObjectField(autoFillProfile, fieldId)); + return str ? jstringToString16(env, str) : string16(); +} + +void syncAutoFillProfile(JNIEnv* env, jobject autoFillProfile, WebAutoFill* webAutoFill) +{ + string16 fullName = getStringFieldAsString16(env, autoFillProfile, gFieldIds->mAutoFillProfileFullName); + string16 emailAddress = getStringFieldAsString16(env, autoFillProfile, gFieldIds->mAutoFillProfileEmailAddress); + string16 companyName = getStringFieldAsString16(env, autoFillProfile, gFieldIds->mAutoFillProfileCompanyName); + string16 addressLine1 = getStringFieldAsString16(env, autoFillProfile, gFieldIds->mAutoFillProfileAddressLine1); + string16 addressLine2 = getStringFieldAsString16(env, autoFillProfile, gFieldIds->mAutoFillProfileAddressLine2); + string16 city = getStringFieldAsString16(env, autoFillProfile, gFieldIds->mAutoFillProfileCity); + string16 state = getStringFieldAsString16(env, autoFillProfile, gFieldIds->mAutoFillProfileState); + string16 zipCode = getStringFieldAsString16(env, autoFillProfile, gFieldIds->mAutoFillProfileZipCode); + string16 country = getStringFieldAsString16(env, autoFillProfile, gFieldIds->mAutoFillProfileCountry); + string16 phoneNumber = getStringFieldAsString16(env, autoFillProfile, gFieldIds->mAutoFillProfilePhoneNumber); + + webAutoFill->setProfile(fullName, emailAddress, companyName, addressLine1, addressLine2, city, state, zipCode, country, phoneNumber); +} +#endif + +class WebSettings { +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__); + WebCore::Settings* s = pFrame->settings(); + if (!s) + return; + WebCore::CachedResourceLoader* cachedResourceLoader = pFrame->document()->cachedResourceLoader(); + +#ifdef ANDROID_LAYOUT + jobject layout = env->GetObjectField(obj, gFieldIds->mLayoutAlgorithm); + WebCore::Settings::LayoutAlgorithm l = (WebCore::Settings::LayoutAlgorithm) + env->CallIntMethod(layout, gFieldIds->mOrdinal); + if (s->layoutAlgorithm() != l) { + s->setLayoutAlgorithm(l); + if (pFrame->document()) { + 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"); + 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 + // WebViewCore, on the UI side, so there needs to be a new way to do this. + //pFrame->makeFocusVisible(); + } + } + } +#endif + jobject textSize = env->GetObjectField(obj, gFieldIds->mTextSize); + float zoomFactor = env->GetIntField(textSize, gFieldIds->mTextSizeValue) / 100.0f; + if (pFrame->textZoomFactor() != zoomFactor) + pFrame->setTextZoomFactor(zoomFactor); + + jstring str = (jstring)env->GetObjectField(obj, gFieldIds->mStandardFontFamily); + s->setStandardFontFamily(jstringToWtfString(env, str)); + + str = (jstring)env->GetObjectField(obj, gFieldIds->mFixedFontFamily); + s->setFixedFontFamily(jstringToWtfString(env, str)); + + str = (jstring)env->GetObjectField(obj, gFieldIds->mSansSerifFontFamily); + s->setSansSerifFontFamily(jstringToWtfString(env, str)); + + str = (jstring)env->GetObjectField(obj, gFieldIds->mSerifFontFamily); + s->setSerifFontFamily(jstringToWtfString(env, str)); + + str = (jstring)env->GetObjectField(obj, gFieldIds->mCursiveFontFamily); + s->setCursiveFontFamily(jstringToWtfString(env, str)); + + str = (jstring)env->GetObjectField(obj, gFieldIds->mFantasyFontFamily); + s->setFantasyFontFamily(jstringToWtfString(env, str)); + + str = (jstring)env->GetObjectField(obj, gFieldIds->mDefaultTextEncoding); + s->setDefaultTextEncodingName(jstringToWtfString(env, str)); + + 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); + WebViewCore::getWebViewCore(pFrame->view())->setWebRequestContextCacheMode(cacheMode); + + str = (jstring)env->GetObjectField(obj, gFieldIds->mAcceptLanguage); + WebRequestContext::setAcceptLanguage(jstringToWtfString(env, str)); +#endif + + jint size = env->GetIntField(obj, gFieldIds->mMinimumFontSize); + s->setMinimumFontSize(size); + + size = env->GetIntField(obj, gFieldIds->mMinimumLogicalFontSize); + s->setMinimumLogicalFontSize(size); + + size = env->GetIntField(obj, gFieldIds->mDefaultFontSize); + s->setDefaultFontSize(size); + + size = env->GetIntField(obj, gFieldIds->mDefaultFixedFontSize); + s->setDefaultFixedFontSize(size); + + jboolean flag = env->GetBooleanField(obj, gFieldIds->mLoadsImagesAutomatically); + s->setLoadsImagesAutomatically(flag); + if (flag) + cachedResourceLoader->setAutoLoadImages(true); + +#ifdef ANDROID_BLOCK_NETWORK_IMAGE + flag = env->GetBooleanField(obj, gFieldIds->mBlockNetworkImage); + s->setBlockNetworkImage(flag); + if(!flag) + cachedResourceLoader->setBlockNetworkImage(false); +#endif + flag = env->GetBooleanField(obj, gFieldIds->mBlockNetworkLoads); + WebFrame* webFrame = WebFrame::getWebFrame(pFrame); + webFrame->setBlockNetworkLoads(flag); + + flag = env->GetBooleanField(obj, gFieldIds->mJavaScriptEnabled); + s->setJavaScriptEnabled(flag); + + // ON = 0 + // ON_DEMAND = 1 + // OFF = 2 + jobject pluginState = env->GetObjectField(obj, gFieldIds->mPluginState); + int state = env->CallIntMethod(pluginState, gFieldIds->mOrdinal); + s->setPluginsEnabled(state < 2); +#ifdef ANDROID_PLUGINS + s->setPluginsOnDemand(state == 1); +#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); + // 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) + close(fd); + } + } + jlong maxsize = env->GetLongField(obj, gFieldIds->mAppCacheMaxSize); + cacheStorage().setMaximumSize(maxsize); +#endif + + flag = env->GetBooleanField(obj, gFieldIds->mJavaScriptCanOpenWindowsAutomatically); + s->setJavaScriptCanOpenWindowsAutomatically(flag); + +#ifdef ANDROID_LAYOUT + flag = env->GetBooleanField(obj, gFieldIds->mUseWideViewport); + s->setUseWideViewport(flag); +#endif + +#ifdef ANDROID_MULTIPLE_WINDOWS + flag = env->GetBooleanField(obj, gFieldIds->mSupportMultipleWindows); + s->setSupportMultipleWindows(flag); +#endif + flag = env->GetBooleanField(obj, gFieldIds->mShrinksStandaloneImagesToFit); + s->setShrinksStandaloneImagesToFit(flag); + jlong maxImage = env->GetLongField(obj, gFieldIds->mMaximumDecodedImageSize); + // Since in ImageSourceAndroid.cpp, the image will always not exceed + // MAX_SIZE_BEFORE_SUBSAMPLE, there's no need to pass the max value to + // WebCore, which checks (image_width * image_height * 4) as an + // estimation against the max value, which is done in CachedImage.cpp. + // And there're cases where the decoded image size will not + // exceed the max, but the WebCore estimation will. So the following + // code is commented out to fix those cases. + // if (maxImage == 0) + // maxImage = computeMaxBitmapSizeForCache(); + s->setMaximumDecodedImageSize(maxImage); + + flag = env->GetBooleanField(obj, gFieldIds->mPrivateBrowsingEnabled); + s->setPrivateBrowsingEnabled(flag); + + flag = env->GetBooleanField(obj, gFieldIds->mSyntheticLinksEnabled); + s->setDefaultFormatDetection(flag); + s->setFormatDetectionAddress(flag); + s->setFormatDetectionEmail(flag); + s->setFormatDetectionTelephone(flag); +#if ENABLE(DATABASE) + flag = env->GetBooleanField(obj, gFieldIds->mDatabaseEnabled); + WebCore::Database::setIsAvailable(flag); + + flag = env->GetBooleanField(obj, gFieldIds->mDatabasePathHasBeenSet); + if (flag) { + // If the user has set the database path, sync it to the DatabaseTracker. + str = (jstring)env->GetObjectField(obj, gFieldIds->mDatabasePath); + if (str) { + String path = jstringToWtfString(env, str); + DatabaseTracker::tracker().setDatabaseDirectoryPath(path); + // This database is created when the first HTML5 Database object is + // instantiated. If the file doesn't exist, we create it and set its + // permissions. The filename must match that in + // DatabaseTracker.cpp. + String filename = SQLiteFileSystem::appendDatabaseFileNameToPath(path, "Databases.db"); + int fd = open(filename.utf8().data(), O_CREAT | O_EXCL, permissionFlags660); + if (fd >= 0) + close(fd); + } + } +#endif +#if ENABLE(DOM_STORAGE) + flag = env->GetBooleanField(obj, gFieldIds->mDomStorageEnabled); + s->setLocalStorageEnabled(flag); + str = (jstring)env->GetObjectField(obj, gFieldIds->mDatabasePath); + if (str) { + WTF::String localStorageDatabasePath = jstringToWtfString(env,str); + if (localStorageDatabasePath.length()) { + localStorageDatabasePath = WebCore::pathByAppendingComponent( + localStorageDatabasePath, "localstorage"); + // We need 770 for folders + mkdir(localStorageDatabasePath.utf8().data(), + permissionFlags660 | S_IXUSR | S_IXGRP); + s->setLocalStorageDatabasePath(localStorageDatabasePath); + } + } +#endif + + flag = env->GetBooleanField(obj, gFieldIds->mGeolocationEnabled); + GeolocationPermissions::setAlwaysDeny(!flag); + str = (jstring)env->GetObjectField(obj, gFieldIds->mGeolocationDatabasePath); + if (str) { + String path = jstringToWtfString(env, str); + GeolocationPermissions::setDatabasePath(path); + GeolocationPositionCache::instance()->setDatabasePath(path); + // This database is created when the first Geolocation object is + // instantiated. If the file doesn't exist, we create it and set its + // permissions. The filename must match that in + // GeolocationPositionCache.cpp. + String filename = SQLiteFileSystem::appendDatabaseFileNameToPath(path, "CachedGeoposition.db"); + int fd = open(filename.utf8().data(), O_CREAT | O_EXCL, permissionFlags660); + if (fd >= 0) + close(fd); + } + + flag = env->GetBooleanField(obj, gFieldIds->mXSSAuditorEnabled); + s->setXSSAuditorEnabled(flag); + + size = env->GetIntField(obj, gFieldIds->mPageCacheCapacity); + if (size > 0) { + s->setUsesPageCache(true); + WebCore::pageCache()->setCapacity(size); + } else + s->setUsesPageCache(false); + +#if ENABLE(WEB_AUTOFILL) + flag = env->GetBooleanField(obj, gFieldIds->mAutoFillEnabled); + // TODO: This updates the Settings WebCore side with the user's + // preference for autofill and will stop WebCore making requests + // into the chromium autofill code. That code in Chromium also has + // a notion of being enabled/disabled that gets read from the users + // preferences. At the moment, it's hardcoded to true on Android + // (see chrome/browser/autofill/autofill_manager.cc:405). This + // setting should probably be synced into Chromium also. + + s->setAutoFillEnabled(flag); + + if (flag) { + EditorClientAndroid* editorC = static_cast(pFrame->page()->editorClient()); + WebAutoFill* webAutoFill = editorC->getAutoFill(); + // Set the active AutoFillProfile data. + jobject autoFillProfile = env->GetObjectField(obj, gFieldIds->mAutoFillProfile); + if (autoFillProfile) + syncAutoFillProfile(env, autoFillProfile, webAutoFill); + else { + // The autofill profile is null. We need to tell Chromium about this because + // this may be because the user just deleted their profile but left the + // autofill feature setting enabled. + webAutoFill->clearProfiles(); + } + } +#endif + } +}; + + +//------------------------------------------------------------- +// JNI registration +//------------------------------------------------------------- + +static JNINativeMethod gWebSettingsMethods[] = { + { "nativeSync", "(I)V", + (void*) WebSettings::Sync } +}; + +int registerWebSettings(JNIEnv* env) +{ + jclass clazz = env->FindClass("android/webkit/WebSettings"); + LOG_ASSERT(clazz, "Unable to find class WebSettings!"); + gFieldIds = new FieldIds(env, clazz); + env->DeleteLocalRef(clazz); + return jniRegisterNativeMethods(env, "android/webkit/WebSettings", + gWebSettingsMethods, NELEM(gWebSettingsMethods)); +} + +} diff --git a/Source/WebKit/android/jni/WebStorage.cpp b/Source/WebKit/android/jni/WebStorage.cpp new file mode 100644 index 0000000..9ce207d --- /dev/null +++ b/Source/WebKit/android/jni/WebStorage.cpp @@ -0,0 +1,188 @@ +/* + * 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 "config.h" + +#if ENABLE(DATABASE) + +#include "ApplicationCacheStorage.h" +#include "DatabaseTracker.h" +#include "JNIUtility.h" +#include "JavaSharedClient.h" +#include "KURL.h" +#include "PageGroup.h" +#include "SecurityOrigin.h" +#include "WebCoreJni.h" + +#include + +namespace android { + +static jobject GetOrigins(JNIEnv* env, jobject obj) +{ + Vector > coreOrigins; + WebCore::DatabaseTracker::tracker().origins(coreOrigins); + Vector manifestUrls; + if (WebCore::cacheStorage().manifestURLs(&manifestUrls)) { + int size = manifestUrls.size(); + for (int i = 0; i < size; ++i) { + RefPtr manifestOrigin = WebCore::SecurityOrigin::create(manifestUrls[i]); + if (manifestOrigin.get() == 0) + continue; + coreOrigins.append(manifestOrigin); + } + } + + jclass setClass = env->FindClass("java/util/HashSet"); + jmethodID cid = env->GetMethodID(setClass, "", "()V"); + jmethodID mid = env->GetMethodID(setClass, "add", "(Ljava/lang/Object;)Z"); + jobject set = env->NewObject(setClass, cid); + env->DeleteLocalRef(setClass); + + for (unsigned i = 0; i < coreOrigins.size(); ++i) { + WebCore::SecurityOrigin* origin = coreOrigins[i].get(); + WTF::String url = origin->toString(); + jstring jUrl = wtfStringToJstring(env, url); + env->CallBooleanMethod(set, mid, jUrl); + env->DeleteLocalRef(jUrl); + } + + return set; +} + +static unsigned long long GetQuotaForOrigin(JNIEnv* env, jobject obj, jstring origin) +{ + WTF::String originStr = jstringToWtfString(env, origin); + RefPtr securityOrigin = WebCore::SecurityOrigin::createFromString(originStr); + unsigned long long quota = WebCore::DatabaseTracker::tracker().quotaForOrigin(securityOrigin.get()); + return quota; +} + +static unsigned long long GetUsageForOrigin(JNIEnv* env, jobject obj, jstring origin) +{ + WTF::String originStr = jstringToWtfString(env, origin); + RefPtr securityOrigin = WebCore::SecurityOrigin::createFromString(originStr); + unsigned long long usage = WebCore::DatabaseTracker::tracker().usageForOrigin(securityOrigin.get()); + Vector manifestUrls; + if (!WebCore::cacheStorage().manifestURLs(&manifestUrls)) + return usage; + int size = manifestUrls.size(); + for (int i = 0; i < size; ++i) { + RefPtr manifestOrigin = WebCore::SecurityOrigin::create(manifestUrls[i]); + if (manifestOrigin.get() == 0) + continue; + if (manifestOrigin->isSameSchemeHostPort(securityOrigin.get())) { + int64_t cacheSize = 0; + WebCore::cacheStorage().cacheGroupSize(manifestUrls[i].string(), &cacheSize); + usage += cacheSize; + } + } + return usage; +} + +static void SetQuotaForOrigin(JNIEnv* env, jobject obj, jstring origin, unsigned long long quota) +{ + WTF::String originStr = jstringToWtfString(env, origin); + RefPtr securityOrigin = WebCore::SecurityOrigin::createFromString(originStr); + WebCore::DatabaseTracker::tracker().setQuota(securityOrigin.get(), quota); +} + +static void DeleteOrigin(JNIEnv* env, jobject obj, jstring origin) +{ + WTF::String originStr = jstringToWtfString(env, origin); + RefPtr securityOrigin = WebCore::SecurityOrigin::createFromString(originStr); + WebCore::DatabaseTracker::tracker().deleteOrigin(securityOrigin.get()); + + Vector manifestUrls; + if (!WebCore::cacheStorage().manifestURLs(&manifestUrls)) + return; + int size = manifestUrls.size(); + for (int i = 0; i < size; ++i) { + RefPtr manifestOrigin = WebCore::SecurityOrigin::create(manifestUrls[i]); + if (manifestOrigin.get() == 0) + continue; + if (manifestOrigin->isSameSchemeHostPort(securityOrigin.get())) + WebCore::cacheStorage().deleteCacheGroup(manifestUrls[i]); + } +} + +static void DeleteAllData(JNIEnv* env, jobject obj) +{ + WebCore::DatabaseTracker::tracker().deleteAllDatabases(); + + Vector manifestUrls; + if (!WebCore::cacheStorage().manifestURLs(&manifestUrls)) + return; + int size = manifestUrls.size(); + for (int i = 0; i < size; ++i) + WebCore::cacheStorage().deleteCacheGroup(manifestUrls[i]); + + // FIXME: this is a workaround for eliminating any DOM Storage data (both + // session and local storage) as there is no functionality inside WebKit at the + // moment to do it. That functionality is a WIP in https://bugs.webkit.org/show_bug.cgi?id=51878 + // and when that patch lands and we merge it, we should move towards that approach instead. + WebCore::PageGroup::clearDomStorage(); +} + +static void SetAppCacheMaximumSize(JNIEnv* env, jobject obj, unsigned long long size) +{ + WebCore::cacheStorage().setMaximumSize(size); +} + +/* + * JNI registration + */ +static JNINativeMethod gWebStorageMethods[] = { + { "nativeGetOrigins", "()Ljava/util/Set;", + (void*) GetOrigins }, + { "nativeGetUsageForOrigin", "(Ljava/lang/String;)J", + (void*) GetUsageForOrigin }, + { "nativeGetQuotaForOrigin", "(Ljava/lang/String;)J", + (void*) GetQuotaForOrigin }, + { "nativeSetQuotaForOrigin", "(Ljava/lang/String;J)V", + (void*) SetQuotaForOrigin }, + { "nativeDeleteOrigin", "(Ljava/lang/String;)V", + (void*) DeleteOrigin }, + { "nativeDeleteAllData", "()V", + (void*) DeleteAllData }, + { "nativeSetAppCacheMaximumSize", "(J)V", + (void*) SetAppCacheMaximumSize } +}; + +int registerWebStorage(JNIEnv* env) +{ +#ifndef NDEBUG + jclass webStorage = env->FindClass("android/webkit/WebStorage"); + LOG_ASSERT(webStorage, "Unable to find class android.webkit.WebStorage"); + env->DeleteLocalRef(webStorage); +#endif + + return jniRegisterNativeMethods(env, "android/webkit/WebStorage", + gWebStorageMethods, NELEM(gWebStorageMethods)); +} + +} + +#endif //ENABLE(DATABASE) diff --git a/Source/WebKit/android/jni/WebViewCore.cpp b/Source/WebKit/android/jni/WebViewCore.cpp new file mode 100644 index 0000000..f2680b5 --- /dev/null +++ b/Source/WebKit/android/jni/WebViewCore.cpp @@ -0,0 +1,4598 @@ +/* + * 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 "WebViewCore.h" + +#include "AccessibilityObject.h" +#include "Attribute.h" +#include "BaseLayerAndroid.h" +#include "CachedNode.h" +#include "CachedRoot.h" +#include "Chrome.h" +#include "ChromeClientAndroid.h" +#include "ChromiumIncludes.h" +#include "ClientRect.h" +#include "ClientRectList.h" +#include "Color.h" +#include "CSSPropertyNames.h" +#include "CSSValueKeywords.h" +#include "DatabaseTracker.h" +#include "Document.h" +#include "DOMWindow.h" +#include "DOMSelection.h" +#include "Element.h" +#include "Editor.h" +#include "EditorClientAndroid.h" +#include "EventHandler.h" +#include "EventNames.h" +#include "ExceptionCode.h" +#include "FocusController.h" +#include "Font.h" +#include "Frame.h" +#include "FrameLoader.h" +#include "FrameLoaderClientAndroid.h" +#include "FrameTree.h" +#include "FrameView.h" +#include "Geolocation.h" +#include "GraphicsContext.h" +#include "GraphicsJNI.h" +#include "HTMLAnchorElement.h" +#include "HTMLAreaElement.h" +#include "HTMLElement.h" +#include "HTMLFormControlElement.h" +#include "HTMLImageElement.h" +#include "HTMLInputElement.h" +#include "HTMLLabelElement.h" +#include "HTMLMapElement.h" +#include "HTMLNames.h" +#include "HTMLOptGroupElement.h" +#include "HTMLOptionElement.h" +#include "HTMLSelectElement.h" +#include "HTMLTextAreaElement.h" +#include "HistoryItem.h" +#include "HitTestRequest.h" +#include "HitTestResult.h" +#include "InlineTextBox.h" +#include "MemoryUsage.h" +#include "NamedNodeMap.h" +#include "Navigator.h" +#include "Node.h" +#include "NodeList.h" +#include "Page.h" +#include "PageGroup.h" +#include "PlatformKeyboardEvent.h" +#include "PlatformString.h" +#include "PluginWidgetAndroid.h" +#include "PluginView.h" +#include "Position.h" +#include "ProgressTracker.h" +#include "Range.h" +#include "RenderBox.h" +#include "RenderInline.h" +#include "RenderLayer.h" +#include "RenderPart.h" +#include "RenderText.h" +#include "RenderTextControl.h" +#include "RenderThemeAndroid.h" +#include "RenderView.h" +#include "ResourceRequest.h" +#include "SchemeRegistry.h" +#include "SelectionController.h" +#include "Settings.h" +#include "SkANP.h" +#include "SkTemplates.h" +#include "SkTDArray.h" +#include "SkTypes.h" +#include "SkCanvas.h" +#include "SkPicture.h" +#include "SkUtils.h" +#include "Text.h" +#include "TypingCommand.h" +#include "WebCoreFrameBridge.h" +#include "WebFrameView.h" +#include "WindowsKeyboardCodes.h" +#include "android_graphics.h" +#include "autofill/WebAutoFill.h" +#include "htmlediting.h" +#include "markup.h" + +#include +#include +#include +#include +#include +#include + +#if USE(V8) +#include "ScriptController.h" +#include "V8Counters.h" +#include +#endif + +#if DEBUG_NAV_UI +#include "SkTime.h" +#endif + +#if ENABLE(TOUCH_EVENTS) // Android +#include "PlatformTouchEvent.h" +#endif + +#ifdef ANDROID_DOM_LOGGING +#include "AndroidLog.h" +#include "RenderTreeAsText.h" +#include + +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 + +/* We pass this flag when recording the actual content, so that we don't spend + time actually regionizing complex path clips, when all we really want to do + is record them. + */ +#define PICT_RECORD_FLAGS SkPicture::kUsePathBoundsForClip_RecordingFlag + +//////////////////////////////////////////////////////////////////////////////////////////////// + +namespace android { + +static SkTDArray gInstanceList; + +void WebViewCore::addInstance(WebViewCore* inst) { + *gInstanceList.append() = inst; +} + +void WebViewCore::removeInstance(WebViewCore* inst) { + int index = gInstanceList.find(inst); + LOG_ASSERT(index >= 0, "RemoveInstance inst not found"); + if (index >= 0) { + gInstanceList.removeShuffle(index); + } +} + +bool WebViewCore::isInstance(WebViewCore* inst) { + return gInstanceList.find(inst) >= 0; +} + +jobject WebViewCore::getApplicationContext() { + + // check to see if there is a valid webviewcore object + if (gInstanceList.isEmpty()) + return 0; + + // get the context from the webview + jobject context = gInstanceList[0]->getContext(); + + if (!context) + return 0; + + // get the application context using JNI + JNIEnv* env = JSC::Bindings::getJNIEnv(); + jclass contextClass = env->GetObjectClass(context); + jmethodID appContextMethod = env->GetMethodID(contextClass, "getApplicationContext", "()Landroid/content/Context;"); + env->DeleteLocalRef(contextClass); + jobject result = env->CallObjectMethod(context, appContextMethod); + checkException(env); + return result; +} + + +struct WebViewCoreStaticMethods { + jmethodID m_isSupportedMediaMimeType; +} gWebViewCoreStaticMethods; + +// Check whether a media mimeType is supported in Android media framework. +bool WebViewCore::isSupportedMediaMimeType(const WTF::String& mimeType) { + JNIEnv* env = JSC::Bindings::getJNIEnv(); + jstring jMimeType = wtfStringToJstring(env, mimeType); + jclass webViewCore = env->FindClass("android/webkit/WebViewCore"); + bool val = env->CallStaticBooleanMethod(webViewCore, + gWebViewCoreStaticMethods.m_isSupportedMediaMimeType, jMimeType); + checkException(env); + env->DeleteLocalRef(webViewCore); + env->DeleteLocalRef(jMimeType); + + return val; +} + +// ---------------------------------------------------------------------------- + +#define GET_NATIVE_VIEW(env, obj) ((WebViewCore*)env->GetIntField(obj, gWebViewCoreFields.m_nativeClass)) + +// Field ids for WebViewCore +struct WebViewCoreFields { + jfieldID m_nativeClass; + jfieldID m_viewportWidth; + jfieldID m_viewportHeight; + jfieldID m_viewportInitialScale; + jfieldID m_viewportMinimumScale; + jfieldID m_viewportMaximumScale; + jfieldID m_viewportUserScalable; + jfieldID m_viewportDensityDpi; + jfieldID m_webView; + jfieldID m_drawIsPaused; + jfieldID m_lowMemoryUsageMb; + jfieldID m_highMemoryUsageMb; + jfieldID m_highUsageDeltaMb; +} gWebViewCoreFields; + +// ---------------------------------------------------------------------------- + +struct WebViewCore::JavaGlue { + jweak m_obj; + jmethodID m_scrollTo; + jmethodID m_contentDraw; + jmethodID m_layersDraw; + jmethodID m_requestListBox; + jmethodID m_openFileChooser; + jmethodID m_requestSingleListBox; + jmethodID m_jsAlert; + jmethodID m_jsConfirm; + jmethodID m_jsPrompt; + jmethodID m_jsUnload; + jmethodID m_jsInterrupt; + jmethodID m_didFirstLayout; + jmethodID m_updateViewport; + jmethodID m_sendNotifyProgressFinished; + jmethodID m_sendViewInvalidate; + jmethodID m_updateTextfield; + jmethodID m_updateTextSelection; + jmethodID m_clearTextEntry; + jmethodID m_restoreScale; + jmethodID m_needTouchEvents; + jmethodID m_requestKeyboard; + jmethodID m_requestKeyboardWithSelection; + jmethodID m_exceededDatabaseQuota; + jmethodID m_reachedMaxAppCacheSize; + jmethodID m_populateVisitedLinks; + jmethodID m_geolocationPermissionsShowPrompt; + jmethodID m_geolocationPermissionsHidePrompt; + jmethodID m_getDeviceMotionService; + jmethodID m_getDeviceOrientationService; + jmethodID m_addMessageToConsole; + jmethodID m_formDidBlur; + jmethodID m_getPluginClass; + jmethodID m_showFullScreenPlugin; + jmethodID m_hideFullScreenPlugin; + jmethodID m_createSurface; + jmethodID m_addSurface; + jmethodID m_updateSurface; + 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_setWebTextViewAutoFillable; + jmethodID m_selectAt; + AutoJObject object(JNIEnv* env) { + return getRealObject(env, m_obj); + } +}; + +/* + * WebViewCore Implementation + */ + +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); + return m; +} + +Mutex WebViewCore::gFrameCacheMutex; +Mutex WebViewCore::gButtonMutex; +Mutex WebViewCore::gCursorBoundsMutex; + +WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* mainframe) + : m_pluginInvalTimer(this, &WebViewCore::pluginInvalTimerFired) + , m_deviceMotionAndOrientationManager(this) +{ + m_mainFrame = mainframe; + + m_popupReply = 0; + m_moveGeneration = 0; + m_lastGeneration = 0; + m_touchGeneration = 0; + m_blockTextfieldUpdates = false; + // just initial values. These should be set by client + m_maxXScroll = 320/4; + m_maxYScroll = 240/4; + m_textGeneration = 0; + m_screenWidth = 320; + m_textWrapWidth = 320; + m_scale = 1; +#if ENABLE(TOUCH_EVENTS) + m_forwardingTouchEvents = false; +#endif + m_isPaused = false; + m_screenOnCounter = 0; + m_shouldPaintCaret = true; + + LOG_ASSERT(m_mainFrame, "Uh oh, somehow a frameview was made without an initial frame!"); + + jclass clazz = env->GetObjectClass(javaWebViewCore); + m_javaGlue = new JavaGlue; + m_javaGlue->m_obj = env->NewWeakGlobalRef(javaWebViewCore); + m_javaGlue->m_scrollTo = GetJMethod(env, clazz, "contentScrollTo", "(IIZZ)V"); + m_javaGlue->m_contentDraw = GetJMethod(env, clazz, "contentDraw", "()V"); + m_javaGlue->m_layersDraw = GetJMethod(env, clazz, "layersDraw", "()V"); + m_javaGlue->m_requestListBox = GetJMethod(env, clazz, "requestListBox", "([Ljava/lang/String;[I[I)V"); + m_javaGlue->m_openFileChooser = GetJMethod(env, clazz, "openFileChooser", "(Ljava/lang/String;)Ljava/lang/String;"); + m_javaGlue->m_requestSingleListBox = GetJMethod(env, clazz, "requestListBox", "([Ljava/lang/String;[II)V"); + m_javaGlue->m_jsAlert = GetJMethod(env, clazz, "jsAlert", "(Ljava/lang/String;Ljava/lang/String;)V"); + m_javaGlue->m_jsConfirm = GetJMethod(env, clazz, "jsConfirm", "(Ljava/lang/String;Ljava/lang/String;)Z"); + m_javaGlue->m_jsPrompt = GetJMethod(env, clazz, "jsPrompt", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"); + m_javaGlue->m_jsUnload = GetJMethod(env, clazz, "jsUnload", "(Ljava/lang/String;Ljava/lang/String;)Z"); + m_javaGlue->m_jsInterrupt = GetJMethod(env, clazz, "jsInterrupt", "()Z"); + m_javaGlue->m_didFirstLayout = GetJMethod(env, clazz, "didFirstLayout", "(Z)V"); + m_javaGlue->m_updateViewport = GetJMethod(env, clazz, "updateViewport", "()V"); + m_javaGlue->m_sendNotifyProgressFinished = GetJMethod(env, clazz, "sendNotifyProgressFinished", "()V"); + m_javaGlue->m_sendViewInvalidate = GetJMethod(env, clazz, "sendViewInvalidate", "(IIII)V"); + m_javaGlue->m_updateTextfield = GetJMethod(env, clazz, "updateTextfield", "(IZLjava/lang/String;I)V"); + m_javaGlue->m_updateTextSelection = GetJMethod(env, clazz, "updateTextSelection", "(IIII)V"); + m_javaGlue->m_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"); + m_javaGlue->m_geolocationPermissionsShowPrompt = GetJMethod(env, clazz, "geolocationPermissionsShowPrompt", "(Ljava/lang/String;)V"); + m_javaGlue->m_geolocationPermissionsHidePrompt = GetJMethod(env, clazz, "geolocationPermissionsHidePrompt", "()V"); + m_javaGlue->m_getDeviceMotionService = GetJMethod(env, clazz, "getDeviceMotionService", "()Landroid/webkit/DeviceMotionService;"); + m_javaGlue->m_getDeviceOrientationService = GetJMethod(env, clazz, "getDeviceOrientationService", "()Landroid/webkit/DeviceOrientationService;"); + m_javaGlue->m_addMessageToConsole = GetJMethod(env, clazz, "addMessageToConsole", "(Ljava/lang/String;ILjava/lang/String;I)V"); + m_javaGlue->m_formDidBlur = GetJMethod(env, clazz, "formDidBlur", "(I)V"); + m_javaGlue->m_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;I)V"); + m_javaGlue->m_hideFullScreenPlugin = GetJMethod(env, clazz, "hideFullScreenPlugin", "()V"); + m_javaGlue->m_createSurface = GetJMethod(env, clazz, "createSurface", "(Landroid/view/View;)Landroid/webkit/ViewManager$ChildView;"); + m_javaGlue->m_addSurface = GetJMethod(env, clazz, "addSurface", "(Landroid/view/View;IIII)Landroid/webkit/ViewManager$ChildView;"); + m_javaGlue->m_updateSurface = GetJMethod(env, clazz, "updateSurface", "(Landroid/webkit/ViewManager$ChildView;IIII)V"); + 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"); +#endif + m_javaGlue->m_setWebTextViewAutoFillable = GetJMethod(env, clazz, "setWebTextViewAutoFillable", "(ILjava/lang/String;)V"); + m_javaGlue->m_selectAt = GetJMethod(env, clazz, "selectAt", "(II)V"); + env->DeleteLocalRef(clazz); + + env->SetIntField(javaWebViewCore, gWebViewCoreFields.m_nativeClass, (jint)this); + + m_scrollOffsetX = m_scrollOffsetY = 0; + + PageGroup::setShouldTrackVisitedLinks(true); + + reset(true); + + MemoryUsage::setLowMemoryUsageMb(env->GetIntField(javaWebViewCore, gWebViewCoreFields.m_lowMemoryUsageMb)); + MemoryUsage::setHighMemoryUsageMb(env->GetIntField(javaWebViewCore, gWebViewCoreFields.m_highMemoryUsageMb)); + MemoryUsage::setHighUsageDeltaMb(env->GetIntField(javaWebViewCore, gWebViewCoreFields.m_highUsageDeltaMb)); + + WebViewCore::addInstance(this); + +#if USE(CHROME_NETWORK_STACK) + AndroidNetworkLibraryImpl::InitWithApplicationContext(env, 0); +#endif +} + +WebViewCore::~WebViewCore() +{ + WebViewCore::removeInstance(this); + + // Release the focused view + Release(m_popupReply); + + if (m_javaGlue->m_obj) { + JNIEnv* env = JSC::Bindings::getJNIEnv(); + env->DeleteWeakGlobalRef(m_javaGlue->m_obj); + m_javaGlue->m_obj = 0; + } + delete m_javaGlue; + delete m_frameCacheKit; + delete m_navPictureKit; +} + +WebViewCore* WebViewCore::getWebViewCore(const WebCore::FrameView* view) +{ + return getWebViewCore(static_cast(view)); +} + +WebViewCore* WebViewCore::getWebViewCore(const WebCore::ScrollView* view) +{ + if (!view) + return 0; + + WebFrameView* webFrameView = static_cast(view->platformWidget()); + if (!webFrameView) + return 0; + return webFrameView->webViewCore(); +} + +void WebViewCore::reset(bool fromConstructor) +{ + DBG_SET_LOG(""); + if (fromConstructor) { + m_frameCacheKit = 0; + m_navPictureKit = 0; + } else { + gFrameCacheMutex.lock(); + delete m_frameCacheKit; + delete m_navPictureKit; + m_frameCacheKit = 0; + m_navPictureKit = 0; + gFrameCacheMutex.unlock(); + } + + m_lastFocused = 0; + m_blurringNodePointer = 0; + m_lastFocusedBounds = WebCore::IntRect(0,0,0,0); + m_focusBoundsChanged = false; + m_lastFocusedSelStart = 0; + m_lastFocusedSelEnd = 0; + clearContent(); + m_updatedFrameCache = true; + m_frameCacheOutOfDate = true; + m_skipContentDraw = false; + m_findIsUp = false; + m_domtree_version = 0; + m_check_domtree_version = true; + m_progressDone = false; + m_hasCursorBounds = false; + + m_scrollOffsetX = 0; + m_scrollOffsetY = 0; + m_screenWidth = 0; + m_screenHeight = 0; + m_groupForVisitedLinks = 0; + m_currentNodeDomNavigationAxis = 0; +} + +static bool layoutIfNeededRecursive(WebCore::Frame* f) +{ + if (!f) + return true; + + WebCore::FrameView* v = f->view(); + if (!v) + return true; + + if (v->needsLayout()) + v->layout(f->tree()->parent()); + + WebCore::Frame* child = f->tree()->firstChild(); + bool success = true; + while (child) { + success &= layoutIfNeededRecursive(child); + child = child->tree()->nextSibling(); + } + + return success && !v->needsLayout(); +} + +CacheBuilder& WebViewCore::cacheBuilder() +{ + return FrameLoaderClientAndroid::get(m_mainFrame)->getCacheBuilder(); +} + +WebCore::Node* WebViewCore::currentFocus() +{ + return cacheBuilder().currentFocus(); +} + +void WebViewCore::recordPicture(SkPicture* picture) +{ + // if there is no document yet, just return + if (!m_mainFrame->document()) { + DBG_NAV_LOG("no document"); + return; + } + // Call layout to ensure that the contentWidth and contentHeight are correct + if (!layoutIfNeededRecursive(m_mainFrame)) { + DBG_NAV_LOG("layout failed"); + return; + } + // draw into the picture's recording canvas + WebCore::FrameView* view = m_mainFrame->view(); + DBG_NAV_LOGD("view=(w=%d,h=%d)", view->contentsWidth(), + view->contentsHeight()); + SkAutoPictureRecord arp(picture, view->contentsWidth(), + view->contentsHeight(), PICT_RECORD_FLAGS); + SkAutoMemoryUsageProbe mup(__FUNCTION__); + + // Copy m_buttons so we can pass it to our graphics context. + gButtonMutex.lock(); + WTF::Vector buttons(m_buttons); + gButtonMutex.unlock(); + + WebCore::PlatformGraphicsContext pgc(arp.getRecordingCanvas(), &buttons); + WebCore::GraphicsContext gc(&pgc); + view->platformWidget()->draw(&gc, WebCore::IntRect(0, 0, + view->contentsWidth(), view->contentsHeight())); + + gButtonMutex.lock(); + updateButtonList(&buttons); + gButtonMutex.unlock(); +} + +void WebViewCore::recordPictureSet(PictureSet* content) +{ + // if there is no document yet, just return + if (!m_mainFrame->document()) { + DBG_SET_LOG("!m_mainFrame->document()"); + return; + } + // If there is a pending style recalculation, just return. + if (m_mainFrame->document()->isPendingStyleRecalc()) { + LOGW("recordPictureSet: pending style recalc, ignoring."); + return; + } + if (m_addInval.isEmpty()) { + DBG_SET_LOG("m_addInval.isEmpty()"); + return; + } + // Call layout to ensure that the contentWidth and contentHeight are correct + // it's fine for layout to gather invalidates, but defeat sending a message + // back to java to call webkitDraw, since we're already in the middle of + // doing that + m_skipContentDraw = true; + bool success = layoutIfNeededRecursive(m_mainFrame); + m_skipContentDraw = false; + + // We may be mid-layout and thus cannot draw. + if (!success) + return; + + { // collect WebViewCoreRecordTimeCounter after layoutIfNeededRecursive +#ifdef ANDROID_INSTRUMENT + TimeCounterAuto counter(TimeCounter::WebViewCoreRecordTimeCounter); +#endif + + // if the webkit page dimensions changed, discard the pictureset and redraw. + WebCore::FrameView* view = m_mainFrame->view(); + int width = view->contentsWidth(); + int height = view->contentsHeight(); + + // Use the contents width and height as a starting point. + SkIRect contentRect; + contentRect.set(0, 0, width, height); + SkIRect total(contentRect); + + // Traverse all the frames and add their sizes if they are in the visible + // rectangle. + for (WebCore::Frame* frame = m_mainFrame->tree()->traverseNext(); frame; + frame = frame->tree()->traverseNext()) { + // If the frame doesn't have an owner then it is the top frame and the + // view size is the frame size. + WebCore::RenderPart* owner = frame->ownerRenderer(); + if (owner && owner->style()->visibility() == VISIBLE) { + int x = owner->x(); + int y = owner->y(); + + // Traverse the tree up to the parent to find the absolute position + // of this frame. + WebCore::Frame* parent = frame->tree()->parent(); + while (parent) { + WebCore::RenderPart* parentOwner = parent->ownerRenderer(); + if (parentOwner) { + x += parentOwner->x(); + y += parentOwner->y(); + } + parent = parent->tree()->parent(); + } + // Use the owner dimensions so that padding and border are + // included. + int right = x + owner->width(); + int bottom = y + owner->height(); + SkIRect frameRect = {x, y, right, bottom}; + // Ignore a width or height that is smaller than 1. Some iframes + // have small dimensions in order to be hidden. The iframe + // expansion code does not expand in that case so we should ignore + // them here. + if (frameRect.width() > 1 && frameRect.height() > 1 + && SkIRect::Intersects(total, frameRect)) + total.join(x, y, right, bottom); + } + } + + // If the new total is larger than the content, resize the view to include + // all the content. + if (!contentRect.contains(total)) { + // Resize the view to change the overflow clip. + view->resize(total.fRight, total.fBottom); + + // We have to force a layout in order for the clip to change. + m_mainFrame->contentRenderer()->setNeedsLayoutAndPrefWidthsRecalc(); + view->forceLayout(); + + // Relayout similar to above + m_skipContentDraw = true; + bool success = layoutIfNeededRecursive(m_mainFrame); + m_skipContentDraw = false; + if (!success) + return; + + // Set the computed content width + width = view->contentsWidth(); + height = view->contentsHeight(); + } + + if (cacheBuilder().pictureSetDisabled()) + content->clear(); + + content->checkDimensions(width, height, &m_addInval); + + // The inval region may replace existing pictures. The existing pictures + // may have already been split into pieces. If reuseSubdivided() returns + // true, the split pieces are the last entries in the picture already. They + // are marked as invalid, and are rebuilt by rebuildPictureSet(). + + // If the new region doesn't match a set of split pieces, add it to the end. + if (!content->reuseSubdivided(m_addInval)) { + const SkIRect& inval = m_addInval.getBounds(); + SkPicture* picture = rebuildPicture(inval); + DBG_SET_LOGD("{%d,%d,w=%d,h=%d}", inval.fLeft, + inval.fTop, inval.width(), inval.height()); + content->add(m_addInval, picture, 0, false); + SkSafeUnref(picture); + } + // Remove any pictures already in the set that are obscured by the new one, + // and check to see if any already split pieces need to be redrawn. + if (content->build()) + 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(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(); + env->CallVoidMethod(m_javaGlue->object(env).get(), + m_javaGlue->m_sendFindAgain); + checkException(env); + } +} + +void WebViewCore::updateButtonList(WTF::Vector* buttons) +{ + // All the entries in buttons are either updates of previous entries in + // m_buttons or they need to be added to it. + Container* end = buttons->end(); + for (Container* updatedContainer = buttons->begin(); + updatedContainer != end; updatedContainer++) { + bool updated = false; + // Search for a previous entry that references the same node as our new + // data + Container* lastPossibleMatch = m_buttons.end(); + for (Container* possibleMatch = m_buttons.begin(); + possibleMatch != lastPossibleMatch; possibleMatch++) { + if (updatedContainer->matches(possibleMatch->node())) { + // Update our record, and skip to the next one. + possibleMatch->setRect(updatedContainer->rect()); + updated = true; + break; + } + } + if (!updated) { + // This is a brand new button, so append it to m_buttons + m_buttons.append(*updatedContainer); + } + } + size_t i = 0; + // count will decrease each time one is removed, so check count each time. + while (i < m_buttons.size()) { + if (m_buttons[i].canBeRemoved()) { + m_buttons[i] = m_buttons.last(); + m_buttons.removeLast(); + } else { + i++; + } + } +} + +// 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() +{ + DBG_SET_LOG(""); + m_content.clear(); + m_addInval.setEmpty(); + m_rebuildInval.setEmpty(); +} + +bool WebViewCore::focusBoundsChanged() +{ + bool result = m_focusBoundsChanged; + m_focusBoundsChanged = false; + return result; +} + +SkPicture* WebViewCore::rebuildPicture(const SkIRect& inval) +{ + WebCore::FrameView* view = m_mainFrame->view(); + int width = view->contentsWidth(); + int height = view->contentsHeight(); + SkPicture* picture = new SkPicture(); + SkAutoPictureRecord arp(picture, width, height, PICT_RECORD_FLAGS); + SkAutoMemoryUsageProbe mup(__FUNCTION__); + SkCanvas* recordingCanvas = arp.getRecordingCanvas(); + + gButtonMutex.lock(); + WTF::Vector buttons(m_buttons); + gButtonMutex.unlock(); + + WebCore::PlatformGraphicsContext pgc(recordingCanvas, &buttons); + WebCore::GraphicsContext gc(&pgc); + recordingCanvas->translate(-inval.fLeft, -inval.fTop); + recordingCanvas->save(); + view->platformWidget()->draw(&gc, WebCore::IntRect(inval.fLeft, + inval.fTop, inval.width(), inval.height())); + m_rebuildInval.op(inval, SkRegion::kUnion_Op); + DBG_SET_LOGD("m_rebuildInval={%d,%d,r=%d,b=%d}", + m_rebuildInval.getBounds().fLeft, m_rebuildInval.getBounds().fTop, + m_rebuildInval.getBounds().fRight, m_rebuildInval.getBounds().fBottom); + + gButtonMutex.lock(); + updateButtonList(&buttons); + gButtonMutex.unlock(); + + return picture; +} + +void WebViewCore::rebuildPictureSet(PictureSet* pictureSet) +{ + WebCore::FrameView* view = m_mainFrame->view(); + size_t size = pictureSet->size(); + for (size_t index = 0; index < size; index++) { + if (pictureSet->upToDate(index)) + continue; + const SkIRect& inval = pictureSet->bounds(index); + DBG_SET_LOGD("pictSet=%p [%d] {%d,%d,w=%d,h=%d}", pictureSet, index, + inval.fLeft, inval.fTop, inval.width(), inval.height()); + pictureSet->setPicture(index, rebuildPicture(inval)); + } + pictureSet->validate(__FUNCTION__); +} + +BaseLayerAndroid* WebViewCore::createBaseLayer() +{ + BaseLayerAndroid* base = new BaseLayerAndroid(); + base->setContent(m_content); + + bool layoutSucceeded = layoutIfNeededRecursive(m_mainFrame); + // Layout only fails if called during a layout. + LOG_ASSERT(layoutSucceeded, "Can never be called recursively"); + +#if USE(ACCELERATED_COMPOSITING) + // We set the background color + if (m_mainFrame && m_mainFrame->document() + && m_mainFrame->document()->body()) { + Document* document = m_mainFrame->document(); + RefPtr style = document->styleForElementIgnoringPendingStylesheets(document->body()); + if (style->hasBackground()) { + Color color = style->visitedDependentColor(CSSPropertyBackgroundColor); + if (color.isValid() && color.alpha() > 0) + base->setBackgroundColor(color); + } + } + + // We update the layers + ChromeClientAndroid* chromeC = static_cast(m_mainFrame->page()->chrome()->client()); + GraphicsLayerAndroid* root = static_cast(chromeC->layersSync()); + if (root) { + root->notifyClientAnimationStarted(); + LayerAndroid* copyLayer = new LayerAndroid(*root->contentLayer()); + base->addChild(copyLayer); + copyLayer->unref(); + } +#endif + + return base; +} + +BaseLayerAndroid* WebViewCore::recordContent(SkRegion* region, SkIPoint* point) +{ + DBG_SET_LOG("start"); + float progress = (float) m_mainFrame->page()->progress()->estimatedProgress(); + m_progressDone = progress <= 0.0f || progress >= 1.0f; + recordPictureSet(&m_content); + if (!m_progressDone && m_content.isEmpty()) { + DBG_SET_LOGD("empty (progress=%g)", progress); + return 0; + } + region->set(m_addInval); + m_addInval.setEmpty(); + region->op(m_rebuildInval, SkRegion::kUnion_Op); + m_rebuildInval.setEmpty(); + point->fX = m_content.width(); + point->fY = m_content.height(); + DBG_SET_LOGD("region={%d,%d,r=%d,b=%d}", region->getBounds().fLeft, + region->getBounds().fTop, region->getBounds().fRight, + region->getBounds().fBottom); + DBG_SET_LOG("end"); + + return createBaseLayer(); +} + +void WebViewCore::splitContent(PictureSet* content) +{ + bool layoutSucceeded = layoutIfNeededRecursive(m_mainFrame); + LOG_ASSERT(layoutSucceeded, "Can never be called recursively"); + content->split(&m_content); + rebuildPictureSet(&m_content); + content->set(m_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!"); + +// LOGD("WebViewCore::scrollTo(%d %d)\n", x, y); + + JNIEnv* env = JSC::Bindings::getJNIEnv(); + env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_scrollTo, + x, y, animate, false); + checkException(env); +} + +void WebViewCore::sendNotifyProgressFinished() +{ + LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); + JNIEnv* env = JSC::Bindings::getJNIEnv(); + env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_sendNotifyProgressFinished); + checkException(env); +} + +void WebViewCore::viewInvalidate(const WebCore::IntRect& rect) +{ + LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); + JNIEnv* env = JSC::Bindings::getJNIEnv(); + env->CallVoidMethod(m_javaGlue->object(env).get(), + m_javaGlue->m_sendViewInvalidate, + rect.x(), rect.y(), rect.right(), rect.bottom()); + checkException(env); +} + +void WebViewCore::contentDraw() +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_contentDraw); + checkException(env); +} + +void WebViewCore::layersDraw() +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_layersDraw); + checkException(env); +} + +void WebViewCore::contentInvalidate(const WebCore::IntRect &r) +{ + DBG_SET_LOGD("rect={%d,%d,w=%d,h=%d}", r.x(), r.y(), r.width(), r.height()); + SkIRect rect(r); + if (!rect.intersect(0, 0, INT_MAX, INT_MAX)) + return; + m_addInval.op(rect, SkRegion::kUnion_Op); + DBG_SET_LOGD("m_addInval={%d,%d,r=%d,b=%d}", + m_addInval.getBounds().fLeft, m_addInval.getBounds().fTop, + m_addInval.getBounds().fRight, m_addInval.getBounds().fBottom); + if (!m_skipContentDraw) + contentDraw(); +} + +void WebViewCore::contentInvalidateAll() +{ + WebCore::FrameView* view = m_mainFrame->view(); + contentInvalidate(WebCore::IntRect(0, 0, + view->contentsWidth(), view->contentsHeight())); +} + +void WebViewCore::offInvalidate(const WebCore::IntRect &r) +{ + // FIXME: these invalidates are offscreen, and can be throttled or + // deferred until the area is visible. For now, treat them as + // regular invals so that drawing happens (inefficiently) for now. + 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!"); + + WebCore::FrameLoader* loader = m_mainFrame->loader(); + const WebCore::KURL& url = loader->url(); + if (url.isEmpty()) + return; + LOGV("::WebCore:: didFirstLayout %s", url.string().ascii().data()); + + WebCore::FrameLoadType loadType = loader->loadType(); + + JNIEnv* env = JSC::Bindings::getJNIEnv(); + env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_didFirstLayout, + loadType == WebCore::FrameLoadTypeStandard + // When redirect with locked history, we would like to reset the + // scale factor. This is important for www.yahoo.com as it is + // redirected to www.yahoo.com/?rs=1 on load. + || loadType == WebCore::FrameLoadTypeRedirectWithLockedBackForwardList); + 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!"); + + JNIEnv* env = JSC::Bindings::getJNIEnv(); + env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_updateViewport); + checkException(env); +} + +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!"); + + JNIEnv* env = JSC::Bindings::getJNIEnv(); + env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_restoreScale, scale, textWrapScale); + checkException(env); +} + +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!"); + +#if ENABLE(TOUCH_EVENTS) + if (m_forwardingTouchEvents == need) + return; + + JNIEnv* env = JSC::Bindings::getJNIEnv(); + env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_needTouchEvents, need); + checkException(env); + + m_forwardingTouchEvents = 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(); + env->CallVoidMethod(m_javaGlue->object(env).get(), + m_javaGlue->m_requestKeyboardWithSelection, + reinterpret_cast(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!"); + + JNIEnv* env = JSC::Bindings::getJNIEnv(); + env->CallVoidMethod(m_javaGlue->object(env).get(), + m_javaGlue->m_requestKeyboard, showKeyboard); + checkException(env); +} + +void WebViewCore::notifyProgressFinished() +{ + m_check_domtree_version = true; + sendNotifyProgressFinished(); +} + +void WebViewCore::doMaxScroll(CacheBuilder::Direction dir) +{ + int dx = 0, dy = 0; + + switch (dir) { + case CacheBuilder::LEFT: + dx = -m_maxXScroll; + break; + case CacheBuilder::UP: + dy = -m_maxYScroll; + break; + case CacheBuilder::RIGHT: + dx = m_maxXScroll; + break; + case CacheBuilder::DOWN: + dy = m_maxYScroll; + break; + case CacheBuilder::UNINITIALIZED: + default: + LOG_ASSERT(0, "unexpected focus selector"); + } + WebCore::FrameView* view = m_mainFrame->view(); + this->scrollTo(view->scrollX() + dx, view->scrollY() + dy, true); +} + +void WebViewCore::setScrollOffset(int moveGeneration, bool sendScrollEvent, int dx, int dy) +{ + 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; + // The visible rect is located within our coordinate space so it + // contains the actual scroll position. Setting the location makes hit + // testing work correctly. + m_mainFrame->view()->platformWidget()->setLocation(m_scrollOffsetX, + m_scrollOffsetY); + if (sendScrollEvent) { + m_mainFrame->eventHandler()->sendScrollEvent(); + + // Only update history position if it's user scrolled. + // Update history item to reflect the new scroll position. + // This also helps save the history information when the browser goes to + // background, so scroll position will be restored if browser gets + // killed while in background. + WebCore::HistoryController* history = m_mainFrame->loader()->history(); + // Because the history item saving could be heavy for large sites and + // scrolling can generate lots of small scroll offset, the following code + // reduces the saving frequency. + static const int MIN_SCROLL_DIFF = 32; + if (history->currentItem()) { + WebCore::IntPoint currentPoint = history->currentItem()->scrollPoint(); + if (std::abs(currentPoint.x() - dx) >= MIN_SCROLL_DIFF || + std::abs(currentPoint.y() - dy) >= MIN_SCROLL_DIFF) { + history->saveScrollPositionAndViewStateToItem(history->currentItem()); + } + } + } + + // 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); +} + +void WebViewCore::setSizeScreenWidthAndScale(int width, int height, + int textWrapWidth, float scale, int screenWidth, int screenHeight, + int anchorX, int anchorY, bool ignoreHeight) +{ + WebCoreViewBridge* window = m_mainFrame->view()->platformWidget(); + int ow = window->width(); + int oh = window->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; + if (scale >= 0) // negative means keep the current scale + m_scale = scale; + m_maxXScroll = screenWidth >> 2; + m_maxYScroll = m_maxXScroll * height / width; + // Don't reflow if the diff is small. + const bool reflow = otw && textWrapWidth && + ((float) abs(otw - textWrapWidth) / textWrapWidth) >= 0.01f; + + // When the screen size change, fixed positioned element should be updated. + // This is supposed to be light weighted operation without a full layout. + if (osh != screenHeight || osw != screenWidth) + m_mainFrame->view()->updatePositionedObjects(); + + 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 node; + WebCore::IntRect bounds; + WebCore::IntPoint offset; + // If the text wrap changed, it is probably zoom change or + // orientation change. Try to keep the anchor at the same place. + if (otw && textWrapWidth && otw != textWrapWidth && + (anchorX != 0 || anchorY != 0)) { + WebCore::HitTestResult hitTestResult = + m_mainFrame->eventHandler()->hitTestResultAtPoint( + anchorPoint, false); + node = hitTestResult.innerNode(); + } + if (node) { + bounds = node->getRect(); + DBG_NAV_LOGD("ob:(x=%d,y=%d,w=%d,h=%d)", + bounds.x(), bounds.y(), bounds.width(), bounds.height()); + // sites like nytimes.com insert a non-standard tag + // in the html. If it is the HitTestResult, it may have zero + // width and height. In this case, use its parent node. + if (bounds.width() == 0) { + 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()); + } + } + } + + // Set the size after finding the old anchor point as + // hitTestResultAtPoint causes a layout. + window->setSize(width, height); + window->setVisibleSize(screenWidth, screenHeight); + if (width != screenWidth) { + m_mainFrame->view()->setUseFixedLayout(true); + m_mainFrame->view()->setFixedLayoutSize(IntSize(width, height)); + } else { + m_mainFrame->view()->setUseFixedLayout(false); + } + r->setNeedsLayoutAndPrefWidthsRecalc(); + m_mainFrame->view()->forceLayout(); + + // 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(); + // force left align if width is not changed while height changed. + // the anchorPoint is probably at some white space in the node + // which is affected by text wrap around the screen width. + const bool leftAlign = (otw != textWrapWidth) + && (bounds.width() == newBounds.width()) + && (bounds.height() != newBounds.height()); + const float xPercentInDoc = + leftAlign ? 0.0 : (float) (anchorX - bounds.x()) / bounds.width(); + const float xPercentInView = + leftAlign ? 0.0 : (float) (anchorX - m_scrollOffsetX) / osw; + const float yPercentInDoc = (float) (anchorY - bounds.y()) / bounds.height(); + const float yPercentInView = (float) (anchorY - m_scrollOffsetY) / osh; + showRect(newBounds.x(), newBounds.y(), newBounds.width(), + newBounds.height(), view->contentsWidth(), + view->contentsHeight(), + xPercentInDoc, xPercentInView, + yPercentInDoc, yPercentInView); + } + } + } + } else { + window->setSize(width, height); + window->setVisibleSize(screenWidth, screenHeight); + m_mainFrame->view()->resize(width, height); + if (width != screenWidth) { + m_mainFrame->view()->setUseFixedLayout(true); + m_mainFrame->view()->setFixedLayoutSize(IntSize(width, height)); + } else { + m_mainFrame->view()->setUseFixedLayout(false); + } + } + + // update the currently visible screen as perceived by the plugin + sendPluginVisibleScreen(); +} + +void WebViewCore::dumpDomTree(bool useFile) +{ +#ifdef ANDROID_DOM_LOGGING + if (useFile) + gDomTreeFile = fopen(DOM_TREE_LOG_FILE, "w"); + m_mainFrame->document()->showTreeForThis(); + if (gDomTreeFile) { + fclose(gDomTreeFile); + gDomTreeFile = 0; + } +#endif +} + +void WebViewCore::dumpRenderTree(bool useFile) +{ +#ifdef ANDROID_DOM_LOGGING + WTF::CString renderDump = WebCore::externalRepresentation(m_mainFrame).utf8(); + const char* data = renderDump.data(); + if (useFile) { + gRenderTreeFile = fopen(RENDER_TREE_LOG_FILE, "w"); + DUMP_RENDER_LOGD("%s", data); + fclose(gRenderTreeFile); + gRenderTreeFile = 0; + } else { + // adb log can only output 1024 characters, so write out line by line. + // exclude '\n' as adb log adds it for each output. + int length = renderDump.length(); + for (int i = 0, last = 0; i < length; i++) { + if (data[i] == '\n') { + if (i != last) + DUMP_RENDER_LOGD("%.*s", (i - last), &(data[last])); + last = i + 1; + } + } + } +#endif +} + +void WebViewCore::dumpNavTree() +{ +#if DUMP_NAV_CACHE + cacheBuilder().mDebug.print(); +#endif +} + +HTMLElement* WebViewCore::retrieveElement(int x, int y, + const QualifiedName& tagName) +{ + HitTestResult hitTestResult = m_mainFrame->eventHandler() + ->hitTestResultAtPoint(IntPoint(x, y), false, false, + DontHitTestScrollbars, HitTestRequest::Active | HitTestRequest::ReadOnly, + IntSize(1, 1)); + if (!hitTestResult.innerNode() || !hitTestResult.innerNode()->inDocument()) { + LOGE("Should not happen: no in document Node found"); + return 0; + } + const ListHashSet >& list = hitTestResult.rectBasedTestResult(); + if (list.isEmpty()) { + LOGE("Should not happen: no rect-based-test nodes found"); + return 0; + } + Node* node = hitTestResult.innerNode(); + Node* element = node; + while (element && (!element->isElementNode() + || !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() : ""); + return static_cast(element); +} + +HTMLAnchorElement* WebViewCore::retrieveAnchorElement(int x, int y) +{ + return static_cast + (retrieveElement(x, y, HTMLNames::aTag)); +} + +HTMLImageElement* WebViewCore::retrieveImageElement(int x, int y) +{ + return static_cast + (retrieveElement(x, y, HTMLNames::imgTag)); +} + +WTF::String WebViewCore::retrieveHref(int x, int y) +{ + WebCore::HTMLAnchorElement* anchor = retrieveAnchorElement(x, y); + return anchor ? anchor->href() : WTF::String(); +} + +WTF::String WebViewCore::retrieveAnchorText(int x, int y) +{ + WebCore::HTMLAnchorElement* anchor = retrieveAnchorElement(x, y); + return anchor ? anchor->text() : WTF::String(); +} + +WTF::String WebViewCore::retrieveImageSource(int x, int y) +{ + HTMLImageElement* image = retrieveImageElement(x, y); + return image ? image->src().string() : WTF::String(); +} + +WTF::String WebViewCore::requestLabel(WebCore::Frame* frame, + WebCore::Node* node) +{ + if (node && CacheBuilder::validNode(m_mainFrame, frame, node)) { + RefPtr list = node->document()->getElementsByTagName("label"); + unsigned length = list->length(); + for (unsigned i = 0; i < length; i++) { + WebCore::HTMLLabelElement* label = static_cast( + list->item(i)); + if (label->control() == node) { + Node* node = label; + String result; + while ((node = node->traverseNextNode(label))) { + if (node->isTextNode()) { + Text* textNode = static_cast(node); + result += textNode->dataImpl(); + } + } + return result; + } + } + } + return WTF::String(); +} + +static bool isContentEditable(const WebCore::Node* node) +{ + if (!node) return false; + return node->document()->frame()->selection()->isContentEditable(); +} + +// Returns true if the node is a textfield, textarea, or contentEditable +static bool isTextInput(const WebCore::Node* node) +{ + if (isContentEditable(node)) + return true; + if (!node) + return false; + WebCore::RenderObject* renderer = node->renderer(); + return renderer && (renderer->isTextField() || renderer->isTextArea()); +} + +void WebViewCore::revealSelection() +{ + WebCore::Node* focus = currentFocus(); + if (!focus) + return; + if (!isTextInput(focus)) + return; + WebCore::Frame* focusedFrame = focus->document()->frame(); + if (!focusedFrame->page()->focusController()->isActive()) + return; + 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; +#if DEBUG_NAV_UI + m_now = SkTime::GetMSecs(); +#endif + 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; + IntRect mBounds; +}; + +// get the bounding box of the Node +static IntRect getAbsoluteBoundingBox(Node* node) { + IntRect rect; + RenderObject* render = node->renderer(); + if (render->isRenderInline()) + rect = toRenderInline(render)->linesVisualOverflowBoundingBox(); + else if (render->isBox()) + rect = toRenderBox(render)->visualOverflowRect(); + else if (render->isText()) + rect = toRenderText(render)->linesBoundingBox(); + else + LOGE("getAbsoluteBoundingBox failed for node %p, name %s", node, render->renderName()); + FloatPoint absPos = render->localToAbsolute(); + rect.move(absPos.x(), absPos.y()); + return rect; +} + +// get the highlight rectangles for the touch point (x, y) with the slop +Vector WebViewCore::getTouchHighlightRects(int x, int y, int slop) +{ + Vector rects; + m_mousePos = IntPoint(x - m_scrollOffsetX, y - m_scrollOffsetY); + HitTestResult hitTestResult = m_mainFrame->eventHandler()->hitTestResultAtPoint(IntPoint(x, y), + false, false, DontHitTestScrollbars, HitTestRequest::Active | HitTestRequest::ReadOnly, IntSize(slop, slop)); + if (!hitTestResult.innerNode() || !hitTestResult.innerNode()->inDocument()) { + LOGE("Should not happen: no in document Node found"); + return rects; + } + const ListHashSet >& list = hitTestResult.rectBasedTestResult(); + if (list.isEmpty()) { + LOGE("Should not happen: no rect-based-test nodes found"); + return rects; + } + Frame* frame = hitTestResult.innerNode()->document()->frame(); + Vector nodeDataList; + ListHashSet >::const_iterator last = list.end(); + for (ListHashSet >::const_iterator it = list.begin(); it != last; ++it) { + // TODO: it seems reasonable to not search across the frame. Isn't it? + // if the node is not in the same frame as the innerNode, skip it + if (it->get()->document()->frame() != frame) + continue; + // traverse up the tree to find the first node that needs highlight + bool found = false; + Node* eventNode = it->get(); + while (eventNode) { + RenderObject* render = eventNode->renderer(); + if (render->isBody() || render->isRenderView()) + break; + if (eventNode->supportsFocus() + || eventNode->hasEventListeners(eventNames().clickEvent) + || eventNode->hasEventListeners(eventNames().mousedownEvent) + || eventNode->hasEventListeners(eventNames().mouseupEvent)) { + found = true; + break; + } + // the nodes in the rectBasedTestResult() are ordered based on z-index during hit testing. + // so do not search for the eventNode across explicit z-index border. + // TODO: this is a hard one to call. z-index is quite complicated as its value only + // matters when you compare two RenderLayer in the same hierarchy level. e.g. in + // the following example, "b" is on the top as its z level is the highest. even "c" + // has 100 as z-index, it is still below "d" as its parent has the same z-index as + // "d" and logically before "d". Of course "a" is the lowest in the z level. + // + // z-index:auto "a" + // z-index:2 "b" + // z-index:1 + // z-index:100 "c" + // z-index:1 "d" + // + // If the fat point touches everyone, the order in the list should be "b", "d", "c" + // and "a". When we search for the event node for "b", we really don't want "a" as + // in the z-order it is behind everything else. + if (!render->style()->hasAutoZIndex()) + break; + eventNode = eventNode->parentNode(); + } + // didn't find any eventNode, skip it + if (!found) + continue; + // first quick check whether it is a duplicated node before computing bounding box + Vector::const_iterator nlast = nodeDataList.end(); + for (Vector::const_iterator n = nodeDataList.begin(); n != nlast; ++n) { + // found the same node, skip it + if (eventNode == n->mNode) { + found = false; + break; + } + } + if (!found) + continue; + // next check whether the node is fully covered by or fully covering another node. + found = false; + IntRect rect = getAbsoluteBoundingBox(eventNode); + if (rect.isEmpty()) { + // if the node's bounds is empty and it is not a ContainerNode, skip it. + if (!eventNode->isContainerNode()) + continue; + // if the node's children are all positioned objects, its bounds can be empty. + // Walk through the children to find the bounding box. + Node* child = static_cast(eventNode)->firstChild(); + while (child) { + IntRect childrect; + if (child->renderer()) + childrect = getAbsoluteBoundingBox(child); + if (!childrect.isEmpty()) { + rect.unite(childrect); + child = child->traverseNextSibling(eventNode); + } else + child = child->traverseNextNode(eventNode); + } + } + for (int i = nodeDataList.size() - 1; i >= 0; i--) { + TouchNodeData n = nodeDataList.at(i); + // the new node is enclosing an existing node, skip it + if (rect.contains(n.mBounds)) { + found = true; + break; + } + // the new node is fully inside an existing node, remove the existing node + if (n.mBounds.contains(rect)) + nodeDataList.remove(i); + } + if (!found) { + TouchNodeData newNode; + newNode.mNode = eventNode; + newNode.mBounds = rect; + nodeDataList.append(newNode); + } + } + if (!nodeDataList.size()) + return rects; + // finally select the node with the largest overlap with the fat point + TouchNodeData final; + final.mNode = 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; + Vector::const_iterator nlast = nodeDataList.end(); + for (Vector::const_iterator n = nodeDataList.begin(); n != nlast; ++n) { + IntRect rect = n->mBounds; + rect.intersect(testRect); + int a = rect.width() * rect.height(); + if (a > area) { + final = *n; + area = a; + } + } + // now get the node's highlight rectangles in the page coordinate system + if (final.mNode) { + IntPoint frameAdjust; + if (frame != m_mainFrame) { + frameAdjust = frame->view()->contentsToWindow(IntPoint()); + frameAdjust.move(m_scrollOffsetX, m_scrollOffsetY); + } + if (final.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].right()) { + 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].bottom()) { + if (y - rects[i].bottom() + 1 < distance) { + newx = x; + newy = rects[i].bottom() - 1; + distance = y - rects[i].bottom() + 1; + } + } + } else if (y >= rects[i].y() && y < rects[i].bottom()) { + 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].right()) { + if (x - rects[i].right() + 1 < distance) { + newx = rects[i].right() - 1; + newy = y; + distance = x - rects[i].right() + 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); + } + } + return rects; +} + +/////////////////////////////////////////////////////////////////////////////// + +void WebViewCore::addPlugin(PluginWidgetAndroid* w) +{ +// SkDebugf("----------- addPlugin %p", w); + /* The plugin must be appended to the end of the array. This ensures that if + the plugin is added while iterating through the array (e.g. sendEvent(...)) + that the iteration process is not corrupted. + */ + *m_plugins.append() = w; +} + +void WebViewCore::removePlugin(PluginWidgetAndroid* w) +{ +// SkDebugf("----------- removePlugin %p", w); + int index = m_plugins.find(w); + if (index < 0) { + SkDebugf("--------------- pluginwindow not found! %p\n", w); + } else { + m_plugins.removeShuffle(index); + } +} + +bool WebViewCore::isPlugin(PluginWidgetAndroid* w) const +{ + return m_plugins.find(w) >= 0; +} + +void WebViewCore::invalPlugin(PluginWidgetAndroid* w) +{ + const double PLUGIN_INVAL_DELAY = 1.0 / 60; + + if (!m_pluginInvalTimer.isActive()) { + m_pluginInvalTimer.startOneShot(PLUGIN_INVAL_DELAY); + } +} + +void WebViewCore::drawPlugins() +{ + SkRegion inval; // accumualte what needs to be redrawn + PluginWidgetAndroid** iter = m_plugins.begin(); + PluginWidgetAndroid** stop = m_plugins.end(); + + for (; iter < stop; ++iter) { + PluginWidgetAndroid* w = *iter; + SkIRect dirty; + if (w->isDirty(&dirty)) { + w->draw(); + inval.op(dirty, SkRegion::kUnion_Op); + } + } + + if (!inval.isEmpty()) { + // inval.getBounds() is our rectangle + const SkIRect& bounds = inval.getBounds(); + WebCore::IntRect r(bounds.fLeft, bounds.fTop, + bounds.width(), bounds.height()); + this->viewInvalidate(r); + } +} + +void WebViewCore::notifyPluginsOnFrameLoad(const Frame* frame) { + // if frame is the parent then notify all plugins + if (!frame->tree()->parent()) { + // trigger an event notifying the plugins that the page has loaded + ANPEvent event; + SkANP::InitEvent(&event, kLifecycle_ANPEventType); + event.data.lifecycle.action = kOnLoad_ANPLifecycleAction; + sendPluginEvent(event); + // trigger the on/off screen notification if the page was reloaded + sendPluginVisibleScreen(); + } + // else if frame's parent has completed + else if (!frame->tree()->parent()->loader()->isLoading()) { + // send to all plugins who have this frame in their heirarchy + PluginWidgetAndroid** iter = m_plugins.begin(); + PluginWidgetAndroid** stop = m_plugins.end(); + for (; iter < stop; ++iter) { + Frame* currentFrame = (*iter)->pluginView()->parentFrame(); + while (currentFrame) { + if (frame == currentFrame) { + ANPEvent event; + SkANP::InitEvent(&event, kLifecycle_ANPEventType); + event.data.lifecycle.action = kOnLoad_ANPLifecycleAction; + (*iter)->sendEvent(event); + + // trigger the on/off screen notification if the page was reloaded + ANPRectI visibleRect; + getVisibleScreen(visibleRect); + (*iter)->setVisibleScreen(visibleRect, m_scale); + + break; + } + currentFrame = currentFrame->tree()->parent(); + } + } + } +} + +void WebViewCore::getVisibleScreen(ANPRectI& visibleRect) +{ + visibleRect.left = m_scrollOffsetX; + visibleRect.top = m_scrollOffsetY; + visibleRect.right = m_scrollOffsetX + m_screenWidth; + visibleRect.bottom = m_scrollOffsetY + m_screenHeight; +} + +void WebViewCore::sendPluginVisibleScreen() +{ + /* We may want to cache the previous values and only send the notification + to the plugin in the event that one of the values has changed. + */ + + ANPRectI visibleRect; + getVisibleScreen(visibleRect); + + PluginWidgetAndroid** iter = m_plugins.begin(); + PluginWidgetAndroid** stop = m_plugins.end(); + for (; iter < stop; ++iter) { + (*iter)->setVisibleScreen(visibleRect, m_scale); + } +} + +void WebViewCore::sendPluginEvent(const ANPEvent& evt) +{ + /* The list of plugins may be manipulated as we iterate through the list. + This implementation allows for the addition of new plugins during an + iteration, but may fail if a plugin is removed. Currently, there are not + any use cases where a plugin is deleted while processing this loop, but + if it does occur we will have to use an alternate data structure and/or + iteration mechanism. + */ + for (int x = 0; x < m_plugins.count(); x++) { + m_plugins[x]->sendEvent(evt); + } +} + +PluginWidgetAndroid* WebViewCore::getPluginWidget(NPP npp) +{ + PluginWidgetAndroid** iter = m_plugins.begin(); + PluginWidgetAndroid** stop = m_plugins.end(); + for (; iter < stop; ++iter) { + if ((*iter)->pluginView()->instance() == npp) { + return (*iter); + } + } + return 0; +} + +static PluginView* nodeIsPlugin(Node* node) { + RenderObject* renderer = node->renderer(); + if (renderer && renderer->isWidget()) { + Widget* widget = static_cast(renderer)->widget(); + if (widget && widget->isPluginView()) + return static_cast(widget); + } + return 0; +} + +Node* WebViewCore::cursorNodeIsPlugin() { + gCursorBoundsMutex.lock(); + bool hasCursorBounds = m_hasCursorBounds; + Frame* frame = (Frame*) m_cursorFrame; + Node* node = (Node*) m_cursorNode; + gCursorBoundsMutex.unlock(); + if (hasCursorBounds && CacheBuilder::validNode(m_mainFrame, frame, node) + && nodeIsPlugin(node)) { + return node; + } + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// +void WebViewCore::moveMouseIfLatest(int moveGeneration, + WebCore::Frame* frame, int x, int y) +{ + DBG_NAV_LOGD("m_moveGeneration=%d moveGeneration=%d" + " frame=%p x=%d y=%d", + m_moveGeneration, moveGeneration, frame, x, y); + if (m_moveGeneration > moveGeneration) { + DBG_NAV_LOGD("m_moveGeneration=%d > moveGeneration=%d", + m_moveGeneration, moveGeneration); + return; // short-circuit if a newer move has already been generated + } + m_lastGeneration = moveGeneration; + moveMouse(frame, x, y); +} + +void WebViewCore::moveFocus(WebCore::Frame* frame, WebCore::Node* node) +{ + DBG_NAV_LOGD("frame=%p node=%p", frame, node); + if (!node || !CacheBuilder::validNode(m_mainFrame, frame, node) + || !node->isElementNode()) + return; + // Code borrowed from FocusController::advanceFocus + WebCore::FocusController* focusController + = m_mainFrame->page()->focusController(); + WebCore::Document* oldDoc + = focusController->focusedOrMainFrame()->document(); + if (oldDoc->focusedNode() == node) + return; + if (node->document() != oldDoc) + oldDoc->setFocusedNode(0); + focusController->setFocusedFrame(frame); + static_cast(node)->focus(false); +} + +// Update mouse position +void WebViewCore::moveMouse(WebCore::Frame* frame, int x, int y) +{ + DBG_NAV_LOGD("frame=%p x=%d y=%d scrollOffset=(%d,%d)", frame, + x, y, m_scrollOffsetX, m_scrollOffsetY); + if (!frame || !CacheBuilder::validNode(m_mainFrame, frame, 0)) + frame = m_mainFrame; + // mouse event expects the position in the window coordinate + m_mousePos = WebCore::IntPoint(x - m_scrollOffsetX, y - m_scrollOffsetY); + // validNode will still return true if the node is null, as long as we have + // a valid frame. Do not want to make a call on frame unless it is valid. + WebCore::PlatformMouseEvent mouseEvent(m_mousePos, m_mousePos, + WebCore::NoButton, WebCore::MouseEventMoved, 1, false, false, false, + false, WTF::currentTime()); + frame->eventHandler()->handleMouseMoveEvent(mouseEvent); + updateCacheOnNodeChange(); +} + +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; + } + // 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( + m_mainFrame->editor()->client()); + client->setUiGeneratedSelectionChange(true); + setSelectionRange(focus, start, end); + client->setUiGeneratedSelectionChange(false); + WebCore::Frame* focusedFrame = focus->document()->frame(); + bool isPasswordField = false; + if (focus->isElementNode()) { + WebCore::Element* element = static_cast(focus); + if (WebCore::InputElement* inputElement = WebCore::toInputElement(element)) + isPasswordField = static_cast(inputElement)->isPasswordField(); + } + // For password fields, this is done in the UI side via + // bringPointIntoView, since the UI does the drawing. + if (renderer->isTextArea() || !isPasswordField) + revealSelection(); +} + +String WebViewCore::modifySelection(const int direction, const int axis) +{ + DOMSelection* selection = m_mainFrame->domWindow()->getSelection(); + if (selection->rangeCount() > 1) + selection->removeAllRanges(); + switch (axis) { + case AXIS_CHARACTER: + case AXIS_WORD: + case AXIS_SENTENCE: + return modifySelectionTextNavigationAxis(selection, direction, axis); + case AXIS_HEADING: + case AXIS_SIBLING: + case AXIS_PARENT_FIRST_CHILD: + case AXIS_DOCUMENT: + return modifySelectionDomNavigationAxis(selection, direction, axis); + default: + LOGE("Invalid navigation axis: %d", axis); + return String(); + } +} + +void WebViewCore::scrollNodeIntoView(Frame* frame, Node* node) +{ + if (!frame || !node) + return; + + Element* elementNode = 0; + + // If not an Element, find a visible predecessor + // Element to scroll into view. + if (!node->isElementNode()) { + HTMLElement* body = frame->document()->body(); + do { + if (!node || node == body) + return; + node = node->parentNode(); + } while (!node->isElementNode() && !isVisible(node)); + } + + elementNode = static_cast(node); + elementNode->scrollIntoViewIfNeeded(true); +} + +String WebViewCore::modifySelectionTextNavigationAxis(DOMSelection* selection, int direction, int axis) +{ + Node* body = m_mainFrame->document()->body(); + + ExceptionCode ec = 0; + String markup; + + // initialize the selection if necessary + if (selection->rangeCount() == 0) { + if (m_currentNodeDomNavigationAxis + && CacheBuilder::validNode(m_mainFrame, + m_mainFrame, m_currentNodeDomNavigationAxis)) { + PassRefPtr rangeRef = + selection->frame()->document()->createRange(); + rangeRef->selectNode(m_currentNodeDomNavigationAxis, ec); + m_currentNodeDomNavigationAxis = 0; + if (ec) + return String(); + 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 rangeRef = + selection->frame()->document()->createRange(); + rangeRef->selectNode(reinterpret_cast(m_cursorNode), ec); + if (ec) + return String(); + selection->addRange(rangeRef.get()); + } else { + selection->setPosition(body, 0, ec); + } + if (ec) + return String(); + } + + // collapse the selection + if (direction == DIRECTION_FORWARD) + selection->collapseToEnd(ec); + else + selection->collapseToStart(ec); + if (ec) + return String(); + + // Make sure the anchor node is a text node since we are generating + // the markup of the selection which includes the anchor, the focus, + // and any crossed nodes. Forcing the condition that the selection + // starts and ends on text nodes guarantees symmetric selection markup. + // Also this way the text content, rather its container, is highlighted. + Node* anchorNode = selection->anchorNode(); + if (anchorNode->isElementNode()) { + // Collapsed selection while moving forward points to the + // next unvisited node and while moving backward to the + // last visited node. + if (direction == DIRECTION_FORWARD) + advanceAnchorNode(selection, direction, markup, false, ec); + else + advanceAnchorNode(selection, direction, markup, true, ec); + if (ec) + return String(); + if (!markup.isEmpty()) + return markup; + } + + // If the selection is at the end of a non white space text move + // it to the next visible text node with non white space content. + // This is a workaround for the selection getting stuck. + anchorNode = selection->anchorNode(); + if (anchorNode->isTextNode()) { + if (direction == DIRECTION_FORWARD) { + String suffix = anchorNode->textContent().substring( + selection->anchorOffset(), caretMaxOffset(anchorNode)); + // If at the end of non white space text we advance the + // anchor node to either an input element or non empty text. + if (suffix.stripWhiteSpace().isEmpty()) { + advanceAnchorNode(selection, direction, markup, true, ec); + } + } else { + String prefix = anchorNode->textContent().substring(0, + selection->anchorOffset()); + // If at the end of non white space text we advance the + // anchor node to either an input element or non empty text. + if (prefix.stripWhiteSpace().isEmpty()) { + advanceAnchorNode(selection, direction, markup, true, ec); + } + } + if (ec) + return String(); + if (!markup.isEmpty()) + return markup; + } + + // extend the selection + String directionStr; + if (direction == DIRECTION_FORWARD) + directionStr = "forward"; + else + directionStr = "backward"; + + String axisStr; + if (axis == AXIS_CHARACTER) + axisStr = "character"; + else if (axis == AXIS_WORD) + axisStr = "word"; + else + axisStr = "sentence"; + + selection->modify("extend", directionStr, axisStr); + + // Make sure the focus node is a text node in order to have the + // selection generate symmetric markup because the latter + // includes all nodes crossed by the selection. Also this way + // the text content, rather its container, is highlighted. + Node* focusNode = selection->focusNode(); + if (focusNode->isElementNode()) { + focusNode = getImplicitBoundaryNode(selection->focusNode(), + selection->focusOffset(), direction); + if (!focusNode) + return String(); + if (direction == DIRECTION_FORWARD) { + focusNode = focusNode->traversePreviousSiblingPostOrder(body); + if (focusNode && !isContentTextNode(focusNode)) { + Node* textNode = traverseNextContentTextNode(focusNode, + anchorNode, DIRECTION_BACKWARD); + if (textNode) + anchorNode = textNode; + } + if (focusNode && isContentTextNode(focusNode)) { + selection->extend(focusNode, caretMaxOffset(focusNode), ec); + if (ec) + return String(); + } + } else { + focusNode = focusNode->traverseNextSibling(); + if (focusNode && !isContentTextNode(focusNode)) { + Node* textNode = traverseNextContentTextNode(focusNode, + anchorNode, DIRECTION_FORWARD); + if (textNode) + anchorNode = textNode; + } + if (anchorNode && isContentTextNode(anchorNode)) { + selection->extend(focusNode, 0, ec); + if (ec) + return String(); + } + } + } + + // Enforce that the selection does not cross anchor boundaries. This is + // a workaround for the asymmetric behavior of WebKit while crossing + // anchors. + anchorNode = getImplicitBoundaryNode(selection->anchorNode(), + selection->anchorOffset(), direction); + focusNode = getImplicitBoundaryNode(selection->focusNode(), + selection->focusOffset(), direction); + if (anchorNode && focusNode && anchorNode != focusNode) { + Node* inputControl = getIntermediaryInputElement(anchorNode, focusNode, + direction); + if (inputControl) { + if (direction == DIRECTION_FORWARD) { + if (isDescendantOf(inputControl, anchorNode)) { + focusNode = inputControl; + } else { + focusNode = inputControl->traversePreviousSiblingPostOrder( + body); + if (!focusNode) + focusNode = inputControl; + } + // We prefer a text node contained in the input element. + if (!isContentTextNode(focusNode)) { + Node* textNode = traverseNextContentTextNode(focusNode, + anchorNode, DIRECTION_BACKWARD); + if (textNode) + focusNode = textNode; + } + // If we found text in the input select it. + // Otherwise, select the input element itself. + if (isContentTextNode(focusNode)) { + selection->extend(focusNode, caretMaxOffset(focusNode), ec); + } else if (anchorNode != focusNode) { + // Note that the focusNode always has parent and that + // the offset can be one more that the index of the last + // element - this is how WebKit selects such elements. + selection->extend(focusNode->parentNode(), + focusNode->nodeIndex() + 1, ec); + } + if (ec) + return String(); + } else { + if (isDescendantOf(inputControl, anchorNode)) { + focusNode = inputControl; + } else { + focusNode = inputControl->traverseNextSibling(); + if (!focusNode) + focusNode = inputControl; + } + // We prefer a text node contained in the input element. + if (!isContentTextNode(focusNode)) { + Node* textNode = traverseNextContentTextNode(focusNode, + anchorNode, DIRECTION_FORWARD); + if (textNode) + focusNode = textNode; + } + // If we found text in the input select it. + // Otherwise, select the input element itself. + if (isContentTextNode(focusNode)) { + selection->extend(focusNode, caretMinOffset(focusNode), ec); + } else if (anchorNode != focusNode) { + // Note that the focusNode always has parent and that + // the offset can be one more that the index of the last + // element - this is how WebKit selects such elements. + selection->extend(focusNode->parentNode(), + focusNode->nodeIndex() + 1, ec); + } + if (ec) + return String(); + } + } + } + + // make sure the selection is visible + if (direction == DIRECTION_FORWARD) + scrollNodeIntoView(m_mainFrame, selection->focusNode()); + else + scrollNodeIntoView(m_mainFrame, selection->anchorNode()); + + // format markup for the visible content + PassRefPtr 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()); + + return markup; +} + +Node* WebViewCore::getImplicitBoundaryNode(Node* node, unsigned offset, int direction) +{ + if (node->offsetInCharacters()) + return node; + if (!node->hasChildNodes()) + return node; + if (offset < node->childNodeCount()) + return node->childNode(offset); + else + if (direction == DIRECTION_FORWARD) + return node->traverseNextSibling(); + else + return node->traversePreviousNodePostOrder( + node->document()->body()); +} + +Node* WebViewCore::getNextAnchorNode(Node* anchorNode, bool ignoreFirstNode, int direction) +{ + Node* body = 0; + Node* currentNode = 0; + if (direction == DIRECTION_FORWARD) { + if (ignoreFirstNode) + currentNode = anchorNode->traverseNextNode(body); + else + currentNode = anchorNode; + } else { + body = anchorNode->document()->body(); + if (ignoreFirstNode) + currentNode = anchorNode->traversePreviousSiblingPostOrder(body); + else + currentNode = anchorNode; + } + while (currentNode) { + if (isContentTextNode(currentNode) + || isContentInputElement(currentNode)) + return currentNode; + if (direction == DIRECTION_FORWARD) + currentNode = currentNode->traverseNextNode(); + else + currentNode = currentNode->traversePreviousNodePostOrder(body); + } + return 0; +} + +void WebViewCore::advanceAnchorNode(DOMSelection* selection, int direction, + String& markup, bool ignoreFirstNode, ExceptionCode& ec) +{ + Node* anchorNode = getImplicitBoundaryNode(selection->anchorNode(), + selection->anchorOffset(), direction); + if (!anchorNode) { + ec = NOT_FOUND_ERR; + return; + } + // If the anchor offset is invalid i.e. the anchor node has no + // child with that index getImplicitAnchorNode returns the next + // logical node in the current direction. In such a case our + // position in the DOM tree was has already been advanced, + // therefore we there is no need to do that again. + if (selection->anchorNode()->isElementNode()) { + unsigned anchorOffset = selection->anchorOffset(); + unsigned childNodeCount = selection->anchorNode()->childNodeCount(); + if (anchorOffset >= childNodeCount) + ignoreFirstNode = false; + } + // Find the next anchor node given our position in the DOM and + // whether we want the current node to be considered as well. + Node* nextAnchorNode = getNextAnchorNode(anchorNode, ignoreFirstNode, + direction); + if (!nextAnchorNode) { + ec = NOT_FOUND_ERR; + return; + } + if (nextAnchorNode->isElementNode()) { + // If this is an input element tell the WebView thread + // to set the cursor to that control. + if (isContentInputElement(nextAnchorNode)) { + IntRect bounds = nextAnchorNode->getRect(); + selectAt(bounds.center().x(), bounds.center().y()); + } + Node* textNode = 0; + // Treat the text content of links as any other text but + // for the rest input elements select the control itself. + if (nextAnchorNode->hasTagName(WebCore::HTMLNames::aTag)) + textNode = traverseNextContentTextNode(nextAnchorNode, + nextAnchorNode, direction); + // We prefer to select the text content of the link if such, + // otherwise just select the element itself. + if (textNode) { + nextAnchorNode = textNode; + } else { + if (direction == DIRECTION_FORWARD) { + selection->setBaseAndExtent(nextAnchorNode, + caretMinOffset(nextAnchorNode), nextAnchorNode, + caretMaxOffset(nextAnchorNode), ec); + } else { + selection->setBaseAndExtent(nextAnchorNode, + caretMaxOffset(nextAnchorNode), nextAnchorNode, + caretMinOffset(nextAnchorNode), ec); + } + if (!ec) + markup = formatMarkup(selection); + // make sure the selection is visible + scrollNodeIntoView(selection->frame(), nextAnchorNode); + return; + } + } + if (direction == DIRECTION_FORWARD) + selection->setPosition(nextAnchorNode, + caretMinOffset(nextAnchorNode), ec); + else + selection->setPosition(nextAnchorNode, + caretMaxOffset(nextAnchorNode), ec); +} + +bool WebViewCore::isContentInputElement(Node* node) +{ + return (isVisible(node) + && (node->hasTagName(WebCore::HTMLNames::selectTag) + || node->hasTagName(WebCore::HTMLNames::aTag) + || node->hasTagName(WebCore::HTMLNames::inputTag) + || node->hasTagName(WebCore::HTMLNames::buttonTag))); +} + +bool WebViewCore::isContentTextNode(Node* node) +{ + if (!node || !node->isTextNode()) + return false; + Text* textNode = static_cast(node); + return (isVisible(textNode) && textNode->length() > 0 + && !textNode->containsOnlyWhitespace()); +} + +Text* WebViewCore::traverseNextContentTextNode(Node* fromNode, Node* toNode, int direction) +{ + Node* currentNode = fromNode; + do { + if (direction == DIRECTION_FORWARD) + currentNode = currentNode->traverseNextNode(toNode); + else + currentNode = currentNode->traversePreviousNodePostOrder(toNode); + } while (currentNode && !isContentTextNode(currentNode)); + return static_cast(currentNode); +} + +Node* WebViewCore::getIntermediaryInputElement(Node* fromNode, Node* toNode, int direction) +{ + if (fromNode == toNode) + return 0; + if (direction == DIRECTION_FORWARD) { + Node* currentNode = fromNode; + while (currentNode && currentNode != toNode) { + if (isContentInputElement(currentNode)) + return currentNode; + currentNode = currentNode->traverseNextNodePostOrder(); + } + currentNode = fromNode; + while (currentNode && currentNode != toNode) { + if (isContentInputElement(currentNode)) + return currentNode; + currentNode = currentNode->traverseNextNode(); + } + } else { + Node* currentNode = fromNode->traversePreviousNode(); + while (currentNode && currentNode != toNode) { + if (isContentInputElement(currentNode)) + return currentNode; + currentNode = currentNode->traversePreviousNode(); + } + currentNode = fromNode->traversePreviousNodePostOrder(); + while (currentNode && currentNode != toNode) { + if (isContentInputElement(currentNode)) + return currentNode; + currentNode = currentNode->traversePreviousNodePostOrder(); + } + } + return 0; +} + +bool WebViewCore::isDescendantOf(Node* parent, Node* node) +{ + Node* currentNode = node; + while (currentNode) { + if (currentNode == parent) { + return true; + } + currentNode = currentNode->parentNode(); + } + return false; +} + +String WebViewCore::modifySelectionDomNavigationAxis(DOMSelection* selection, int direction, int axis) +{ + HTMLElement* body = m_mainFrame->document()->body(); + if (!m_currentNodeDomNavigationAxis && selection->focusNode()) { + m_currentNodeDomNavigationAxis = selection->focusNode(); + selection->empty(); + if (m_currentNodeDomNavigationAxis->isTextNode()) + m_currentNodeDomNavigationAxis = + m_currentNodeDomNavigationAxis->parentNode(); + } + if (!m_currentNodeDomNavigationAxis) + m_currentNodeDomNavigationAxis = currentFocus(); + if (!m_currentNodeDomNavigationAxis + || !CacheBuilder::validNode(m_mainFrame, m_mainFrame, + m_currentNodeDomNavigationAxis)) + m_currentNodeDomNavigationAxis = body; + Node* currentNode = m_currentNodeDomNavigationAxis; + if (axis == AXIS_HEADING) { + if (currentNode == body && direction == DIRECTION_BACKWARD) + currentNode = currentNode->lastDescendant(); + do { + if (direction == DIRECTION_FORWARD) + currentNode = currentNode->traverseNextNode(body); + else + currentNode = currentNode->traversePreviousNode(body); + } while (currentNode && (currentNode->isTextNode() + || !isVisible(currentNode) || !isHeading(currentNode))); + } else if (axis == AXIS_PARENT_FIRST_CHILD) { + if (direction == DIRECTION_FORWARD) { + currentNode = currentNode->firstChild(); + while (currentNode && (currentNode->isTextNode() + || !isVisible(currentNode))) + currentNode = currentNode->nextSibling(); + } else { + do { + if (currentNode == body) + return String(); + currentNode = currentNode->parentNode(); + } while (currentNode && (currentNode->isTextNode() + || !isVisible(currentNode))); + } + } else if (axis == AXIS_SIBLING) { + do { + if (direction == DIRECTION_FORWARD) + currentNode = currentNode->nextSibling(); + else { + if (currentNode == body) + return String(); + currentNode = currentNode->previousSibling(); + } + } while (currentNode && (currentNode->isTextNode() + || !isVisible(currentNode))); + } else if (axis == AXIS_DOCUMENT) { + currentNode = body; + if (direction == DIRECTION_FORWARD) + currentNode = currentNode->lastDescendant(); + } else { + LOGE("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()); + return selectionString; + } + return String(); +} + +bool WebViewCore::isHeading(Node* node) +{ + if (node->hasTagName(WebCore::HTMLNames::h1Tag) + || node->hasTagName(WebCore::HTMLNames::h2Tag) + || node->hasTagName(WebCore::HTMLNames::h3Tag) + || node->hasTagName(WebCore::HTMLNames::h4Tag) + || node->hasTagName(WebCore::HTMLNames::h5Tag) + || node->hasTagName(WebCore::HTMLNames::h6Tag)) { + return true; + } + + if (node->isElementNode()) { + Element* element = static_cast(node); + String roleAttribute = + element->getAttribute(WebCore::HTMLNames::roleAttr).string(); + if (equalIgnoringCase(roleAttribute, "heading")) + return true; + } + + return false; +} + +bool WebViewCore::isVisible(Node* node) +{ + // start off an element + Element* element = 0; + if (node->isElementNode()) + element = static_cast(node); + else + element = node->parentElement(); + // check renderer + if (!element->renderer()) { + return false; + } + // check size + if (element->offsetHeight() == 0 || element->offsetWidth() == 0) { + return false; + } + // check style + Node* body = m_mainFrame->document()->body(); + Node* currentNode = element; + while (currentNode && currentNode != body) { + RenderStyle* style = currentNode->computedStyle(); + if (style && + (style->display() == NONE || style->visibility() == HIDDEN)) { + return false; + } + currentNode = currentNode->parentNode(); + } + return true; +} + +String WebViewCore::formatMarkup(DOMSelection* selection) +{ + ExceptionCode ec = 0; + String markup = String(); + PassRefPtr wholeRange = selection->getRangeAt(0, ec); + if (ec) + return String(); + if (!wholeRange->startContainer() || !wholeRange->startContainer()) + return String(); + // Since formatted markup contains invisible nodes it + // is created from the concatenation of the visible fragments. + Node* firstNode = wholeRange->firstNode(); + Node* pastLastNode = wholeRange->pastLastNode(); + Node* currentNode = firstNode; + PassRefPtr currentRange; + + while (currentNode != pastLastNode) { + Node* nextNode = currentNode->traverseNextNode(); + if (!isVisible(currentNode)) { + if (currentRange) { + markup = markup + currentRange->toHTML().utf8().data(); + currentRange = 0; + } + } else { + if (!currentRange) { + currentRange = selection->frame()->document()->createRange(); + if (ec) + break; + if (currentNode == firstNode) { + currentRange->setStart(wholeRange->startContainer(), + wholeRange->startOffset(), ec); + if (ec) + break; + } else { + currentRange->setStart(currentNode->parentNode(), + currentNode->nodeIndex(), ec); + if (ec) + break; + } + } + if (nextNode == pastLastNode) { + currentRange->setEnd(wholeRange->endContainer(), + wholeRange->endOffset(), ec); + if (ec) + break; + markup = markup + currentRange->toHTML().utf8().data(); + } else { + if (currentNode->offsetInCharacters()) + currentRange->setEnd(currentNode, + currentNode->maxCharacterOffset(), ec); + else + currentRange->setEnd(currentNode->parentNode(), + currentNode->nodeIndex() + 1, ec); + if (ec) + break; + } + } + currentNode = nextNode; + } + return markup.stripWhiteSpace(); +} + +void WebViewCore::selectAt(int x, int y) +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_selectAt, + x, y); + checkException(env); +} + +void WebViewCore::deleteSelection(int start, int end, int textGeneration) +{ + setSelection(start, end); + if (start == end) + return; + WebCore::Node* focus = currentFocus(); + if (!focus) + return; + // Prevent our editor client from passing a message to change the + // selection. + EditorClientAndroid* client = static_cast( + m_mainFrame->editor()->client()); + client->setUiGeneratedSelectionChange(true); + PlatformKeyboardEvent down(AKEYCODE_DEL, 0, 0, true, false, false, false); + PlatformKeyboardEvent up(AKEYCODE_DEL, 0, 0, false, false, false, false); + key(down); + key(up); + client->setUiGeneratedSelectionChange(false); + m_textGeneration = textGeneration; + m_shouldPaintCaret = true; +} + +void WebViewCore::replaceTextfieldText(int oldStart, + int oldEnd, const WTF::String& replace, int start, int end, + int textGeneration) +{ + WebCore::Node* focus = currentFocus(); + if (!focus) + return; + setSelection(oldStart, oldEnd); + // Prevent our editor client from passing a message to change the + // selection. + EditorClientAndroid* client = static_cast( + m_mainFrame->editor()->client()); + client->setUiGeneratedSelectionChange(true); + WebCore::TypingCommand::insertText(focus->document(), replace, + false); + 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, + const PlatformKeyboardEvent& event) +{ + 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; + } + // Block text field updates during a key press. + m_blockTextfieldUpdates = true; + // Also prevent our editor client from passing a message to change the + // selection. + EditorClientAndroid* client = static_cast( + m_mainFrame->editor()->client()); + client->setUiGeneratedSelectionChange(true); + key(event); + client->setUiGeneratedSelectionChange(false); + m_blockTextfieldUpdates = false; + m_textGeneration = generation; + WebCore::RenderTextControl* renderText = + static_cast(renderer); + WTF::String test = renderText->text(); + 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); + clearTextEntry(); + return; + } + WebCore::RenderTextControl* renderText = + static_cast(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); +} + +void WebViewCore::setFocusControllerActive(bool active) +{ + m_mainFrame->page()->focusController()->setActive(active); +} + +void WebViewCore::saveDocumentState(WebCore::Frame* frame) +{ + if (!CacheBuilder::validNode(m_mainFrame, frame, 0)) + frame = m_mainFrame; + WebCore::HistoryItem *item = frame->loader()->history()->currentItem(); + + // item can be null when there is no offical URL for the current page. This happens + // when the content is loaded using with WebCoreFrameBridge::LoadData() and there + // is no failing URL (common case is when content is loaded using data: scheme) + if (item) { + item->setDocumentState(frame->document()->formElementsState()); + } +} + +// Create an array of java Strings. +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"); + jobjectArray array = env->NewObjectArray(count, stringClass, 0); + LOG_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]); + env->SetObjectArrayElement(array, i, newString); + env->DeleteLocalRef(newString); + checkException(env); + } + env->DeleteLocalRef(stringClass); + return array; +} + +void WebViewCore::openFileChooser(PassRefPtr chooser) { + if (!chooser) + return; + JNIEnv* env = JSC::Bindings::getJNIEnv(); + + WTF::String acceptType = chooser->acceptTypes(); + jstring jAcceptType = wtfStringToJstring(env, acceptType, true); + jstring jName = (jstring) env->CallObjectMethod( + m_javaGlue->object(env).get(), m_javaGlue->m_openFileChooser, jAcceptType); + checkException(env); + env->DeleteLocalRef(jAcceptType); + + const UChar* string = static_cast(env->GetStringChars(jName, NULL)); + + if (!string) + return; + + WTF::String webcoreString = jstringToWtfString(env, jName); + env->ReleaseStringChars(jName, string); + + if (webcoreString.length()) + chooser->chooseFile(webcoreString); +} + +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) +{ + // If m_popupReply is not null, then we already have a list showing. + if (m_popupReply != 0) + return; + + LOG_ASSERT(m_javaGlue->m_obj, "No java widget associated with this view!"); + + // Create an array of java Strings for the drop down. + JNIEnv* env = JSC::Bindings::getJNIEnv(); + jobjectArray labelArray = makeLabelArray(env, labels, count); + + // Create an array determining whether each item is enabled. + jintArray enabledArray = env->NewIntArray(enabledCount); + checkException(env); + jint* ptrArray = env->GetIntArrayElements(enabledArray, 0); + checkException(env); + for (size_t i = 0; i < enabledCount; i++) { + ptrArray[i] = enabled[i]; + } + env->ReleaseIntArrayElements(enabledArray, ptrArray, 0); + checkException(env); + + if (multiple) { + // Pass up an array representing which items are selected. + jintArray selectedArray = env->NewIntArray(selectedCountOrSelection); + checkException(env); + jint* selArray = env->GetIntArrayElements(selectedArray, 0); + checkException(env); + for (size_t i = 0; i < selectedCountOrSelection; i++) { + selArray[i] = selected[i]; + } + env->ReleaseIntArrayElements(selectedArray, selArray, 0); + + env->CallVoidMethod(m_javaGlue->object(env).get(), + m_javaGlue->m_requestListBox, labelArray, enabledArray, + selectedArray); + env->DeleteLocalRef(selectedArray); + } else { + // Pass up the single selection. + env->CallVoidMethod(m_javaGlue->object(env).get(), + m_javaGlue->m_requestSingleListBox, labelArray, enabledArray, + selectedCountOrSelection); + } + + env->DeleteLocalRef(labelArray); + env->DeleteLocalRef(enabledArray); + checkException(env); + + Retain(reply); + m_popupReply = reply; +} + +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(); + bool handled = eventHandler->keyEvent(event); + 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 + // return false so that the key will be sent back to our navigation + // system. + handled |= frame->selection()->selection() != old; + } + return handled; + } else { + eventHandler = m_mainFrame->eventHandler(); + } + return eventHandler->keyEvent(event); +} + +// For when the user clicks the trackball, presses dpad center, or types into an +// unfocused textfield. In the latter case, 'fake' will be true +void WebViewCore::click(WebCore::Frame* frame, WebCore::Node* node, bool fake) { + if (!node) { + WebCore::IntPoint pt = m_mousePos; + pt.move(m_scrollOffsetX, m_scrollOffsetY); + WebCore::HitTestResult hitTestResult = m_mainFrame->eventHandler()-> + hitTestResultAtPoint(pt, false); + node = hitTestResult.innerNode(); + frame = node->document()->frame(); + DBG_NAV_LOGD("m_mousePos=(%d,%d) m_scrollOffset=(%d,%d) pt=(%d,%d)" + " node=%p", m_mousePos.x(), m_mousePos.y(), + m_scrollOffsetX, m_scrollOffsetY, pt.x(), pt.y(), node); + } + if (node) { + EditorClientAndroid* client + = static_cast( + m_mainFrame->editor()->client()); + client->setShouldChangeSelectedRange(false); + handleMouseClick(frame, node, fake); + client->setShouldChangeSelectedRange(true); + } +} + +#if USE(ACCELERATED_COMPOSITING) +GraphicsLayerAndroid* WebViewCore::graphicsRootLayer() const +{ + RenderView* contentRenderer = m_mainFrame->contentRenderer(); + if (!contentRenderer) + return 0; + return static_cast( + contentRenderer->compositor()->rootPlatformLayer()); +} +#endif + +bool WebViewCore::handleTouchEvent(int action, Vector& ids, Vector& points, int actionIndex, int metaState) +{ + bool preventDefault = false; + +#if USE(ACCELERATED_COMPOSITING) + GraphicsLayerAndroid* rootLayer = graphicsRootLayer(); + if (rootLayer) + rootLayer->pauseDisplay(true); +#endif + +#if ENABLE(TOUCH_EVENTS) // Android + #define MOTION_EVENT_ACTION_POINTER_DOWN 5 + #define MOTION_EVENT_ACTION_POINTER_UP 6 + + WebCore::TouchEventType type = WebCore::TouchStart; + WebCore::PlatformTouchPoint::State defaultTouchState; + Vector touchStates(points.size()); + + switch (action) { + case 0: // MotionEvent.ACTION_DOWN + type = WebCore::TouchStart; + defaultTouchState = WebCore::PlatformTouchPoint::TouchPressed; + break; + case 1: // MotionEvent.ACTION_UP + type = WebCore::TouchEnd; + defaultTouchState = WebCore::PlatformTouchPoint::TouchReleased; + break; + case 2: // MotionEvent.ACTION_MOVE + type = WebCore::TouchMove; + defaultTouchState = WebCore::PlatformTouchPoint::TouchMoved; + break; + case 3: // MotionEvent.ACTION_CANCEL + type = WebCore::TouchCancel; + defaultTouchState = WebCore::PlatformTouchPoint::TouchCancelled; + break; + case 5: // MotionEvent.ACTION_POINTER_DOWN + type = WebCore::TouchStart; + defaultTouchState = WebCore::PlatformTouchPoint::TouchStationary; + break; + case 6: // MotionEvent.ACTION_POINTER_UP + type = WebCore::TouchEnd; + defaultTouchState = WebCore::PlatformTouchPoint::TouchStationary; + break; + case 0x100: // WebViewCore.ACTION_LONGPRESS + type = WebCore::TouchLongPress; + defaultTouchState = WebCore::PlatformTouchPoint::TouchPressed; + break; + case 0x200: // WebViewCore.ACTION_DOUBLETAP + type = WebCore::TouchDoubleTap; + defaultTouchState = WebCore::PlatformTouchPoint::TouchPressed; + break; + default: + // We do not support other kinds of touch event inside WebCore + // at the moment. + LOGW("Java passed a touch event type that we do not support in WebCore: %d", action); + return 0; + } + + for (int c = 0; c < static_cast(points.size()); c++) { + points[c].setX(points[c].x() - m_scrollOffsetX); + points[c].setY(points[c].y() - m_scrollOffsetY); + + // Setting the touch state for each point. + // Note: actionIndex will be 0 for all actions that are not ACTION_POINTER_DOWN/UP. + if (action == MOTION_EVENT_ACTION_POINTER_DOWN && c == actionIndex) { + touchStates[c] = WebCore::PlatformTouchPoint::TouchPressed; + } else if (action == MOTION_EVENT_ACTION_POINTER_UP && c == actionIndex) { + touchStates[c] = WebCore::PlatformTouchPoint::TouchReleased; + } else { + touchStates[c] = defaultTouchState; + }; + } + + WebCore::PlatformTouchEvent te(ids, points, type, touchStates, metaState); + preventDefault = m_mainFrame->eventHandler()->handleTouchEvent(te); +#endif + +#if USE(ACCELERATED_COMPOSITING) + if (rootLayer) + rootLayer->pauseDisplay(false); +#endif + return preventDefault; +} + +void WebViewCore::touchUp(int touchGeneration, + WebCore::Frame* frame, WebCore::Node* node, int x, int y) +{ + if (touchGeneration == 0) { + // m_mousePos should be set in getTouchHighlightRects() + WebCore::HitTestResult hitTestResult = m_mainFrame->eventHandler()->hitTestResultAtPoint(m_mousePos, false); + node = hitTestResult.innerNode(); + if (node) + frame = node->document()->frame(); + else + frame = 0; + DBG_NAV_LOGD("touch up on (%d, %d), scrollOffset is (%d, %d), node:%p, frame:%p", m_mousePos.x() + m_scrollOffsetX, m_mousePos.y() + m_scrollOffsetY, m_scrollOffsetX, m_scrollOffsetY, node, frame); + } else { + if (m_touchGeneration > touchGeneration) { + DBG_NAV_LOGD("m_touchGeneration=%d > touchGeneration=%d" + " x=%d y=%d", m_touchGeneration, touchGeneration, x, y); + return; // short circuit if a newer touch has been generated + } + // This moves m_mousePos to the correct place, and handleMouseClick uses + // m_mousePos to determine where the click happens. + moveMouse(frame, x, y); + m_lastGeneration = touchGeneration; + } + if (frame && CacheBuilder::validNode(m_mainFrame, frame, 0)) { + frame->loader()->resetMultipleFormSubmissionProtection(); + } + DBG_NAV_LOGD("touchGeneration=%d handleMouseClick frame=%p node=%p" + " x=%d y=%d", touchGeneration, frame, node, x, y); + handleMouseClick(frame, node, false); +} + +// Check for the "x-webkit-soft-keyboard" attribute. If it is there and +// set to hidden, do not show the soft keyboard. Node passed as a parameter +// must not be null. +static bool shouldSuppressKeyboard(const WebCore::Node* node) { + LOG_ASSERT(node, "node passed to shouldSuppressKeyboard cannot be null"); + const NamedNodeMap* attributes = node->attributes(); + if (!attributes) return false; + size_t length = attributes->length(); + for (size_t i = 0; i < length; i++) { + const Attribute* a = attributes->attributeItem(i); + if (a->localName() == "x-webkit-soft-keyboard" && a->value() == "hidden") + return true; + } + return false; +} + +// Common code for both clicking with the trackball and touchUp +// Also used when typing into a non-focused textfield to give the textfield focus, +// in which case, 'fake' is set to true +bool WebViewCore::handleMouseClick(WebCore::Frame* framePtr, WebCore::Node* nodePtr, bool fake) +{ + bool valid = !framePtr || CacheBuilder::validNode(m_mainFrame, framePtr, nodePtr); + WebFrame* webFrame = WebFrame::getWebFrame(m_mainFrame); + if (valid && nodePtr) { + // Need to special case area tags because an image map could have an area element in the middle + // so when attempting to get the default, the point chosen would be follow the wrong link. + if (nodePtr->hasTagName(WebCore::HTMLNames::areaTag)) { + webFrame->setUserInitiatedAction(true); + nodePtr->dispatchSimulatedClick(0, true, true); + webFrame->setUserInitiatedAction(false); + DBG_NAV_LOG("area"); + return true; + } + } + if (!valid || !framePtr) + framePtr = m_mainFrame; + webFrame->setUserInitiatedAction(true); + WebCore::PlatformMouseEvent mouseDown(m_mousePos, m_mousePos, WebCore::LeftButton, + WebCore::MouseEventPressed, 1, false, false, false, false, + WTF::currentTime()); + // ignore the return from as it will return true if the hit point can trigger selection change + framePtr->eventHandler()->handleMousePressEvent(mouseDown); + WebCore::PlatformMouseEvent mouseUp(m_mousePos, m_mousePos, WebCore::LeftButton, + WebCore::MouseEventReleased, 1, false, false, false, false, + WTF::currentTime()); + bool handled = framePtr->eventHandler()->handleMouseReleaseEvent(mouseUp); + webFrame->setUserInitiatedAction(false); + + // If the user clicked on a textfield, make the focusController active + // so we show the blinking cursor. + WebCore::Node* focusNode = currentFocus(); + DBG_NAV_LOGD("m_mousePos={%d,%d} focusNode=%p handled=%s", m_mousePos.x(), + m_mousePos.y(), focusNode, handled ? "true" : "false"); + if (focusNode) { + WebCore::RenderObject* renderer = focusNode->renderer(); + if (renderer && (renderer->isTextField() || renderer->isTextArea())) { + bool ime = !shouldSuppressKeyboard(focusNode) + && !(static_cast(focusNode))->readOnly(); + if (ime) { +#if ENABLE(WEB_AUTOFILL) + if (renderer->isTextField()) { + EditorClientAndroid* editorC = static_cast(framePtr->page()->editorClient()); + WebAutoFill* autoFill = editorC->getAutoFill(); + autoFill->formFieldFocused(static_cast(focusNode)); + } +#endif + if (!fake) { + RenderTextControl* rtc + = static_cast (renderer); + requestKeyboardWithSelection(focusNode, rtc->selectionStart(), + rtc->selectionEnd()); + } + } else if (!fake) { + requestKeyboard(false); + } + } else if (!fake){ + // If the selection is contentEditable, show the keyboard so the + // user can type. Otherwise hide the keyboard because no text + // input is needed. + if (isContentEditable(focusNode)) { + requestKeyboard(true); + } else if (!nodeIsPlugin(focusNode)) { + clearTextEntry(); + } + } + } else if (!fake) { + // There is no focusNode, so the keyboard is not needed. + clearTextEntry(); + } + return handled; +} + +void WebViewCore::popupReply(int index) +{ + if (m_popupReply) { + m_popupReply->replyInt(index); + Release(m_popupReply); + m_popupReply = 0; + } +} + +void WebViewCore::popupReply(const int* array, int count) +{ + if (m_popupReply) { + m_popupReply->replyIntArray(array, count); + Release(m_popupReply); + m_popupReply = 0; + } +} + +void WebViewCore::formDidBlur(const WebCore::Node* node) +{ + // If the blur is on a text input, keep track of the node so we can + // hide the soft keyboard when the new focus is set, if it is not a + // text input. + if (isTextInput(node)) + m_blurringNodePointer = reinterpret_cast(node); +} + +void WebViewCore::focusNodeChanged(const WebCore::Node* newFocus) +{ + if (isTextInput(newFocus)) + m_shouldPaintCaret = true; + else if (m_blurringNodePointer) { + JNIEnv* env = JSC::Bindings::getJNIEnv(); + env->CallVoidMethod(m_javaGlue->object(env).get(), + m_javaGlue->m_formDidBlur, m_blurringNodePointer); + checkException(env); + m_blurringNodePointer = 0; + } +} + +void WebViewCore::addMessageToConsole(const WTF::String& message, unsigned int lineNumber, const WTF::String& sourceID, int msgLevel) { + JNIEnv* env = JSC::Bindings::getJNIEnv(); + jstring jMessageStr = wtfStringToJstring(env, message); + jstring jSourceIDStr = wtfStringToJstring(env, sourceID); + env->CallVoidMethod(m_javaGlue->object(env).get(), + m_javaGlue->m_addMessageToConsole, jMessageStr, lineNumber, + jSourceIDStr, msgLevel); + env->DeleteLocalRef(jMessageStr); + env->DeleteLocalRef(jSourceIDStr); + checkException(env); +} + +void WebViewCore::jsAlert(const WTF::String& url, const WTF::String& text) +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + jstring jInputStr = wtfStringToJstring(env, text); + jstring jUrlStr = wtfStringToJstring(env, url); + env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsAlert, jUrlStr, jInputStr); + env->DeleteLocalRef(jInputStr); + env->DeleteLocalRef(jUrlStr); + checkException(env); +} + +void WebViewCore::exceededDatabaseQuota(const WTF::String& url, const WTF::String& databaseIdentifier, const unsigned long long currentQuota, unsigned long long estimatedSize) +{ +#if ENABLE(DATABASE) + JNIEnv* env = JSC::Bindings::getJNIEnv(); + jstring jDatabaseIdentifierStr = wtfStringToJstring(env, databaseIdentifier); + jstring jUrlStr = wtfStringToJstring(env, url); + env->CallVoidMethod(m_javaGlue->object(env).get(), + m_javaGlue->m_exceededDatabaseQuota, jUrlStr, + jDatabaseIdentifierStr, currentQuota, estimatedSize); + env->DeleteLocalRef(jDatabaseIdentifierStr); + env->DeleteLocalRef(jUrlStr); + checkException(env); +#endif +} + +void WebViewCore::reachedMaxAppCacheSize(const unsigned long long spaceNeeded) +{ +#if ENABLE(OFFLINE_WEB_APPLICATIONS) + JNIEnv* env = JSC::Bindings::getJNIEnv(); + env->CallVoidMethod(m_javaGlue->object(env).get(), + m_javaGlue->m_reachedMaxAppCacheSize, spaceNeeded); + checkException(env); +#endif +} + +void WebViewCore::populateVisitedLinks(WebCore::PageGroup* group) +{ + m_groupForVisitedLinks = group; + JNIEnv* env = JSC::Bindings::getJNIEnv(); + env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_populateVisitedLinks); + checkException(env); +} + +void WebViewCore::geolocationPermissionsShowPrompt(const WTF::String& origin) +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + jstring originString = wtfStringToJstring(env, origin); + env->CallVoidMethod(m_javaGlue->object(env).get(), + m_javaGlue->m_geolocationPermissionsShowPrompt, + originString); + env->DeleteLocalRef(originString); + checkException(env); +} + +void WebViewCore::geolocationPermissionsHidePrompt() +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + env->CallVoidMethod(m_javaGlue->object(env).get(), + m_javaGlue->m_geolocationPermissionsHidePrompt); + checkException(env); +} + +jobject WebViewCore::getDeviceMotionService() +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + jobject object = env->CallObjectMethod(m_javaGlue->object(env).get(), + m_javaGlue->m_getDeviceMotionService); + checkException(env); + return object; +} + +jobject WebViewCore::getDeviceOrientationService() +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + jobject object = env->CallObjectMethod(m_javaGlue->object(env).get(), + m_javaGlue->m_getDeviceOrientationService); + checkException(env); + return object; +} + +bool WebViewCore::jsConfirm(const WTF::String& url, const WTF::String& text) +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + jstring jInputStr = wtfStringToJstring(env, text); + jstring jUrlStr = wtfStringToJstring(env, url); + jboolean result = env->CallBooleanMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsConfirm, jUrlStr, jInputStr); + env->DeleteLocalRef(jInputStr); + env->DeleteLocalRef(jUrlStr); + checkException(env); + return result; +} + +bool WebViewCore::jsPrompt(const WTF::String& url, const WTF::String& text, const WTF::String& defaultValue, WTF::String& result) +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + jstring jUrlStr = wtfStringToJstring(env, url); + jstring jInputStr = wtfStringToJstring(env, text); + jstring jDefaultStr = wtfStringToJstring(env, defaultValue); + jstring returnVal = static_cast(env->CallObjectMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsPrompt, jUrlStr, jInputStr, jDefaultStr)); + env->DeleteLocalRef(jUrlStr); + env->DeleteLocalRef(jInputStr); + env->DeleteLocalRef(jDefaultStr); + checkException(env); + + // If returnVal is null, it means that the user cancelled the dialog. + if (!returnVal) + return false; + + result = jstringToWtfString(env, returnVal); + env->DeleteLocalRef(returnVal); + return true; +} + +bool WebViewCore::jsUnload(const WTF::String& url, const WTF::String& message) +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + jstring jInputStr = wtfStringToJstring(env, message); + jstring jUrlStr = wtfStringToJstring(env, url); + jboolean result = env->CallBooleanMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsUnload, jUrlStr, jInputStr); + env->DeleteLocalRef(jInputStr); + env->DeleteLocalRef(jUrlStr); + checkException(env); + return result; +} + +bool WebViewCore::jsInterrupt() +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + jboolean result = env->CallBooleanMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsInterrupt); + checkException(env); + return result; +} + +AutoJObject +WebViewCore::getJavaObject() +{ + return m_javaGlue->object(JSC::Bindings::getJNIEnv()); +} + +jobject +WebViewCore::getWebViewJavaObject() +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + return env->GetObjectField(m_javaGlue->object(env).get(), gWebViewCoreFields.m_webView); +} + +void WebViewCore::updateTextSelection() { + WebCore::Node* focusNode = currentFocus(); + if (!focusNode) + return; + RenderObject* renderer = focusNode->renderer(); + if (!renderer || (!renderer->isTextArea() && !renderer->isTextField())) + return; + RenderTextControl* rtc = static_cast(renderer); + JNIEnv* env = JSC::Bindings::getJNIEnv(); + env->CallVoidMethod(m_javaGlue->object(env).get(), + m_javaGlue->m_updateTextSelection, reinterpret_cast(focusNode), + rtc->selectionStart(), rtc->selectionEnd(), m_textGeneration); + checkException(env); +} + +void WebViewCore::updateTextfield(WebCore::Node* ptr, bool changeToPassword, + const WTF::String& text) +{ + if (m_blockTextfieldUpdates) + return; + JNIEnv* env = JSC::Bindings::getJNIEnv(); + if (changeToPassword) { + env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_updateTextfield, + (int) ptr, true, 0, m_textGeneration); + checkException(env); + return; + } + jstring string = wtfStringToJstring(env, text); + env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_updateTextfield, + (int) ptr, false, string, m_textGeneration); + env->DeleteLocalRef(string); + checkException(env); +} + +void WebViewCore::clearTextEntry() +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + env->CallVoidMethod(m_javaGlue->object(env).get(), + m_javaGlue->m_clearTextEntry); +} + +void WebViewCore::setBackgroundColor(SkColor c) +{ + WebCore::FrameView* view = m_mainFrame->view(); + if (!view) + return; + + // need (int) cast to find the right constructor + WebCore::Color bcolor((int)SkColorGetR(c), (int)SkColorGetG(c), + (int)SkColorGetB(c), (int)SkColorGetA(c)); + view->setBaseBackgroundColor(bcolor); + + // Background color of 0 indicates we want a transparent background + if (c == 0) + view->setTransparent(true); +} + +jclass WebViewCore::getPluginClass(const WTF::String& libName, const char* className) +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + + jstring libString = wtfStringToJstring(env, libName); + jstring classString = env->NewStringUTF(className); + jobject pluginClass = env->CallObjectMethod(m_javaGlue->object(env).get(), + m_javaGlue->m_getPluginClass, + libString, classString); + checkException(env); + + // cleanup unneeded local JNI references + env->DeleteLocalRef(libString); + env->DeleteLocalRef(classString); + + if (pluginClass != NULL) { + return static_cast(pluginClass); + } else { + return NULL; + } +} + +void WebViewCore::showFullScreenPlugin(jobject childView, NPP npp) +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + AutoJObject obj = m_javaGlue->object(env); + + env->CallVoidMethod(obj.get(), + m_javaGlue->m_showFullScreenPlugin, childView, (int)npp); + checkException(env); +} + +void WebViewCore::hideFullScreenPlugin() +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + env->CallVoidMethod(m_javaGlue->object(env).get(), + m_javaGlue->m_hideFullScreenPlugin); + checkException(env); +} + +jobject WebViewCore::createSurface(jobject view) +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + jobject result = env->CallObjectMethod(m_javaGlue->object(env).get(), + m_javaGlue->m_createSurface, view); + checkException(env); + return result; +} + +jobject WebViewCore::addSurface(jobject view, int x, int y, int width, int height) +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + jobject result = env->CallObjectMethod(m_javaGlue->object(env).get(), + m_javaGlue->m_addSurface, + view, x, y, width, height); + checkException(env); + return result; +} + +void WebViewCore::updateSurface(jobject childView, int x, int y, int width, int height) +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + env->CallVoidMethod(m_javaGlue->object(env).get(), + m_javaGlue->m_updateSurface, childView, + x, y, width, height); + checkException(env); +} + +void WebViewCore::destroySurface(jobject childView) +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_destroySurface, childView); + checkException(env); +} + +jobject WebViewCore::getContext() +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + AutoJObject obj = m_javaGlue->object(env); + + jobject result = env->CallObjectMethod(obj.get(), m_javaGlue->m_getContext); + checkException(env); + return result; +} + +void WebViewCore::keepScreenOn(bool screenOn) { + if ((screenOn && m_screenOnCounter == 0) || (!screenOn && m_screenOnCounter == 1)) { + JNIEnv* env = JSC::Bindings::getJNIEnv(); + env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_keepScreenOn, screenOn); + checkException(env); + } + + // update the counter + if (screenOn) + m_screenOnCounter++; + else if (m_screenOnCounter > 0) + m_screenOnCounter--; +} + +bool WebViewCore::validNodeAndBounds(Frame* frame, Node* node, + const IntRect& originalAbsoluteBounds) +{ + bool valid = CacheBuilder::validNode(m_mainFrame, frame, node); + if (!valid) + return false; + RenderObject* renderer = node->renderer(); + if (!renderer) + return false; + IntRect absBounds = node->hasTagName(HTMLNames::areaTag) + ? CacheBuilder::getAreaRect(static_cast(node)) + : renderer->absoluteBoundingBoxRect(); + return absBounds == originalAbsoluteBounds; +} + +void WebViewCore::showRect(int left, int top, int width, int height, + int contentWidth, int contentHeight, float xPercentInDoc, + float xPercentInView, float yPercentInDoc, float yPercentInView) +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_showRect, + left, top, width, height, contentWidth, contentHeight, + xPercentInDoc, xPercentInView, yPercentInDoc, yPercentInView); + checkException(env); +} + +void WebViewCore::centerFitRect(int x, int y, int width, int height) +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + env->CallVoidMethod(m_javaGlue->object(env).get(), + m_javaGlue->m_centerFitRect, x, y, width, height); + checkException(env); +} + + +void WebViewCore::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode verticalMode) +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_setScrollbarModes, + horizontalMode, verticalMode); + checkException(env); +} + +void WebViewCore::notifyWebAppCanBeInstalled() +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_setInstallableWebApp); + checkException(env); +} + +#if ENABLE(VIDEO) +void WebViewCore::enterFullscreenForVideoLayer(int layerId, const WTF::String& url) +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + jstring jUrlStr = wtfStringToJstring(env, url); + env->CallVoidMethod(m_javaGlue->object(env).get(), + m_javaGlue->m_enterFullscreenForVideoLayer, layerId, jUrlStr); + checkException(env); +} +#endif + +void WebViewCore::setWebTextViewAutoFillable(int queryId, const string16& previewSummary) +{ +#if ENABLE(WEB_AUTOFILL) + JNIEnv* env = JSC::Bindings::getJNIEnv(); + jstring preview = env->NewString(previewSummary.data(), previewSummary.length()); + env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_setWebTextViewAutoFillable, queryId, preview); + env->DeleteLocalRef(preview); +#endif +} + +bool WebViewCore::drawIsPaused() const +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + return env->GetBooleanField(m_javaGlue->object(env).get(), + gWebViewCoreFields.m_drawIsPaused); +} + +#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 + if (m_webRequestContext) + m_webRequestContext->setUserAgent(WebFrame::getWebFrame(m_mainFrame)->userAgentForURL(0)); // URL not used +} + +void WebViewCore::setWebRequestContextCacheMode(int cacheMode) +{ + m_cacheMode = cacheMode; + // We cannot create a WebRequestContext, because we might not know it this is a private tab or not yet + if (!m_webRequestContext) + return; + + m_webRequestContext->setCacheMode(cacheMode); +} + +WebRequestContext* WebViewCore::webRequestContext() +{ + if (!m_webRequestContext) { + Settings* settings = mainFrame()->settings(); + m_webRequestContext = new WebRequestContext(settings && settings->privateBrowsingEnabled()); + setWebRequestContextUserAgent(); + setWebRequestContextCacheMode(m_cacheMode); + } + return m_webRequestContext.get(); +} +#endif + +void WebViewCore::scrollRenderLayer(int layer, const SkRect& rect) +{ +#if USE(ACCELERATED_COMPOSITING) + GraphicsLayerAndroid* root = graphicsRootLayer(); + if (!root) + return; + + LayerAndroid* layerAndroid = root->platformLayer(); + if (!layerAndroid) + return; + + LayerAndroid* target = layerAndroid->findById(layer); + if (!target) + return; + + RenderLayer* owner = target->owningLayer(); + if (!owner) + return; + + if (owner->stackingContext()) + owner->scrollToOffset(rect.fLeft, rect.fTop, true, false); +#endif +} + +//---------------------------------------------------------------------- +// Native JNI methods +//---------------------------------------------------------------------- +static void RevealSelection(JNIEnv *env, jobject obj) +{ + GET_NATIVE_VIEW(env, obj)->revealSelection(); +} + +static jstring RequestLabel(JNIEnv *env, jobject obj, int framePointer, + int nodePointer) +{ + return wtfStringToJstring(env, GET_NATIVE_VIEW(env, obj)->requestLabel( + (WebCore::Frame*) framePointer, (WebCore::Node*) nodePointer)); +} + +static void ClearContent(JNIEnv *env, jobject obj) +{ +#ifdef ANDROID_INSTRUMENT + TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); +#endif + WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); + viewImpl->clearContent(); +} + +static void UpdateFrameCacheIfLoading(JNIEnv *env, jobject obj) +{ + GET_NATIVE_VIEW(env, obj)->updateFrameCacheIfLoading(); +} + +static void SetSize(JNIEnv *env, jobject obj, jint width, jint height, + jint textWrapWidth, jfloat scale, jint screenWidth, jint screenHeight, + jint anchorX, jint anchorY, jboolean ignoreHeight) +{ +#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"); + 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) +{ +#ifdef ANDROID_INSTRUMENT + TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); +#endif + WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); + LOG_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) +{ +#ifdef ANDROID_INSTRUMENT + TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); +#endif + WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); + LOG_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) +{ +#ifdef ANDROID_INSTRUMENT + TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); +#endif + return GET_NATIVE_VIEW(env, obj)->key(PlatformKeyboardEvent(keyCode, + unichar, repeatCount, isDown, isShift, isAlt, isSym)); +} + +static void Click(JNIEnv *env, jobject obj, 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"); + + viewImpl->click(reinterpret_cast(framePtr), + reinterpret_cast(nodePtr), fake); +} + +static void ContentInvalidateAll(JNIEnv *env, jobject obj) +{ + GET_NATIVE_VIEW(env, obj)->contentInvalidateAll(); +} + +static void DeleteSelection(JNIEnv *env, jobject obj, jint start, jint end, + jint textGeneration) +{ +#ifdef ANDROID_INSTRUMENT + TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); +#endif + WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); + viewImpl->deleteSelection(start, end, textGeneration); +} + +static void SetSelection(JNIEnv *env, jobject obj, jint start, jint end) +{ +#ifdef ANDROID_INSTRUMENT + TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); +#endif + WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); + viewImpl->setSelection(start, end); +} + +static jstring ModifySelection(JNIEnv *env, jobject obj, jint direction, jint granularity) +{ +#ifdef ANDROID_INSTRUMENT + TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); +#endif + WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); + String selectionString = viewImpl->modifySelection(direction, granularity); + return wtfStringToJstring(env, selectionString); +} + +static void ReplaceTextfieldText(JNIEnv *env, jobject obj, + 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); + WTF::String webcoreString = jstringToWtfString(env, replace); + viewImpl->replaceTextfieldText(oldStart, + oldEnd, webcoreString, start, end, textGeneration); +} + +static void PassToJs(JNIEnv *env, jobject obj, + 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, + PlatformKeyboardEvent(keyCode, keyValue, 0, down, cap, fn, sym)); +} + +static void ScrollFocusedTextInput(JNIEnv *env, jobject obj, jfloat xPercent, + jint y) +{ +#ifdef ANDROID_INSTRUMENT + TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); +#endif + WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); + viewImpl->scrollFocusedTextInput(xPercent, y); +} + +static void SetFocusControllerActive(JNIEnv *env, jobject obj, 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"); + viewImpl->setFocusControllerActive(active); +} + +static void SaveDocumentState(JNIEnv *env, jobject obj, 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"); + viewImpl->saveDocumentState((WebCore::Frame*) frame); +} + +void WebViewCore::addVisitedLink(const UChar* string, int length) +{ + if (m_groupForVisitedLinks) + m_groupForVisitedLinks->addVisitedLink(string, length); +} + +static jint UpdateLayers(JNIEnv *env, jobject obj, jobject region) +{ + WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); + BaseLayerAndroid* result = viewImpl->createBaseLayer(); + SkRegion* nativeRegion = GraphicsJNI::getNativeRegion(env, region); + if (result) { + SkIRect bounds; + LayerAndroid* root = static_cast(result->getChild(0)); + if (root) { + root->bounds().roundOut(&bounds); + nativeRegion->setRect(bounds); + } + } + return reinterpret_cast(result); +} + +static jint RecordContent(JNIEnv *env, jobject obj, jobject region, jobject pt) +{ +#ifdef ANDROID_INSTRUMENT + TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); +#endif + WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); + SkRegion* nativeRegion = GraphicsJNI::getNativeRegion(env, region); + SkIPoint nativePt; + BaseLayerAndroid* result = viewImpl->recordContent(nativeRegion, &nativePt); + GraphicsJNI::ipoint_to_jpoint(nativePt, env, pt); + return reinterpret_cast(result); +} + +static void SplitContent(JNIEnv *env, jobject obj, jint content) +{ +#ifdef ANDROID_INSTRUMENT + TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); +#endif + WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); + viewImpl->splitContent(reinterpret_cast(content)); +} + +static void SendListBoxChoice(JNIEnv* env, jobject obj, 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"); + viewImpl->popupReply(choice); +} + +// Set aside a predetermined amount of space in which to place the listbox +// choices, to avoid unnecessary allocations. +// The size here is arbitrary. We want the size to be at least as great as the +// 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) +{ +#ifdef ANDROID_INSTRUMENT + TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); +#endif + WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); + LOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoices"); + jboolean* ptrArray = env->GetBooleanArrayElements(jArray, 0); + SkAutoSTMalloc storage(size); + int* array = storage.get(); + int count = 0; + for (int i = 0; i < size; i++) { + if (ptrArray[i]) { + array[count++] = i; + } + } + env->ReleaseBooleanArrayElements(jArray, ptrArray, JNI_ABORT); + viewImpl->popupReply(array, count); +} + +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; + jstring ret = 0; + if (success) + ret = env->NewString(addrChars + start, end - start); + env->ReleaseStringChars(addr, addrChars); + return ret; +} + +static jboolean HandleTouchEvent(JNIEnv *env, jobject obj, 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__); + jint* ptrIdArray = env->GetIntArrayElements(idArray, 0); + jint* ptrXArray = env->GetIntArrayElements(xArray, 0); + jint* ptrYArray = env->GetIntArrayElements(yArray, 0); + Vector ids(count); + Vector points(count); + for (int c = 0; c < count; c++) { + ids[c] = ptrIdArray[c]; + points[c].setX(ptrXArray[c]); + points[c].setY(ptrYArray[c]); + } + env->ReleaseIntArrayElements(idArray, ptrIdArray, JNI_ABORT); + env->ReleaseIntArrayElements(xArray, ptrXArray, JNI_ABORT); + env->ReleaseIntArrayElements(yArray, ptrYArray, JNI_ABORT); + + 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) +{ +#ifdef ANDROID_INSTRUMENT + TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); +#endif + WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); + LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); + viewImpl->touchUp(touchGeneration, + (WebCore::Frame*) frame, (WebCore::Node*) node, x, y); +} + +static jstring RetrieveHref(JNIEnv *env, jobject obj, 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__); + 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) +{ +#ifdef ANDROID_INSTRUMENT + TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); +#endif + WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); + LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); + WTF::String result = viewImpl->retrieveAnchorText(x, y); + if (!result.isEmpty()) + return wtfStringToJstring(env, result); + return 0; +} + +static jstring RetrieveImageSource(JNIEnv *env, jobject obj, jint x, jint y) +{ + WTF::String result = GET_NATIVE_VIEW(env, obj)->retrieveImageSource(x, y); + return !result.isEmpty() ? wtfStringToJstring(env, result) : 0; +} + +static void StopPaintingCaret(JNIEnv *env, jobject obj) +{ + GET_NATIVE_VIEW(env, obj)->setShouldPaintCaret(false); +} + +static void MoveFocus(JNIEnv *env, jobject obj, jint framePtr, jint nodePtr) +{ +#ifdef ANDROID_INSTRUMENT + TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); +#endif + WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); + LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); + viewImpl->moveFocus((WebCore::Frame*) framePtr, (WebCore::Node*) nodePtr); +} + +static void MoveMouse(JNIEnv *env, jobject obj, jint frame, + jint x, jint y) +{ +#ifdef ANDROID_INSTRUMENT + TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); +#endif + WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); + LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); + viewImpl->moveMouse((WebCore::Frame*) frame, x, y); +} + +static void MoveMouseIfLatest(JNIEnv *env, jobject obj, jint moveGeneration, + jint frame, jint x, jint y) +{ +#ifdef ANDROID_INSTRUMENT + TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); +#endif + WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); + LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); + viewImpl->moveMouseIfLatest(moveGeneration, + (WebCore::Frame*) frame, x, y); +} + +static void UpdateFrameCache(JNIEnv *env, jobject obj) +{ +#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) +{ +#ifdef ANDROID_INSTRUMENT + TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); +#endif + WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); + LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); + + WebCore::Frame* frame = viewImpl->mainFrame(); + if (frame) { + WebCore::Document* document = frame->document(); + if (document) { + WebCore::RenderObject* renderer = document->renderer(); + if (renderer && renderer->isRenderView()) { + return renderer->minPreferredLogicalWidth(); + } + } + } + return 0; +} + +static void SetViewportSettingsFromNative(JNIEnv *env, jobject obj) +{ +#ifdef ANDROID_INSTRUMENT + TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); +#endif + WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); + LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); + + WebCore::Settings* s = viewImpl->mainFrame()->page()->settings(); + if (!s) + return; + +#ifdef ANDROID_META_SUPPORT + env->SetIntField(obj, gWebViewCoreFields.m_viewportWidth, s->viewportWidth()); + env->SetIntField(obj, gWebViewCoreFields.m_viewportHeight, s->viewportHeight()); + env->SetIntField(obj, gWebViewCoreFields.m_viewportInitialScale, s->viewportInitialScale()); + env->SetIntField(obj, gWebViewCoreFields.m_viewportMinimumScale, s->viewportMinimumScale()); + env->SetIntField(obj, gWebViewCoreFields.m_viewportMaximumScale, s->viewportMaximumScale()); + env->SetBooleanField(obj, gWebViewCoreFields.m_viewportUserScalable, s->viewportUserScalable()); + env->SetIntField(obj, gWebViewCoreFields.m_viewportDensityDpi, s->viewportTargetDensityDpi()); +#endif +} + +static void SetBackgroundColor(JNIEnv *env, jobject obj, 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__); + + viewImpl->setBackgroundColor((SkColor) color); +} + +static void DumpDomTree(JNIEnv *env, jobject obj, jboolean useFile) +{ + WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); + LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); + + viewImpl->dumpDomTree(useFile); +} + +static void DumpRenderTree(JNIEnv *env, jobject obj, jboolean useFile) +{ + WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); + LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); + + viewImpl->dumpRenderTree(useFile); +} + +static void DumpNavTree(JNIEnv *env, jobject obj) +{ + WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); + LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); + + viewImpl->dumpNavTree(); +} + +static void DumpV8Counters(JNIEnv*, jobject) +{ +#if USE(V8) +#ifdef ANDROID_INSTRUMENT + V8Counters::dumpCounters(); +#endif +#endif +} + +static void SetJsFlags(JNIEnv *env, jobject obj, jstring flags) +{ +#if USE(V8) + WTF::String flagsString = jstringToWtfString(env, flags); + WTF::CString utf8String = flagsString.utf8(); + WebCore::ScriptController::setFlags(utf8String.data(), utf8String.length()); +#endif +} + + +// Called from the Java side to set a new quota for the origin or new appcache +// max size in response to a notification that the original quota was exceeded or +// that the appcache has reached its maximum size. +static void SetNewStorageLimit(JNIEnv* env, jobject obj, jlong quota) { +#if ENABLE(DATABASE) || ENABLE(OFFLINE_WEB_APPLICATIONS) + WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); + Frame* frame = viewImpl->mainFrame(); + + // The main thread is blocked awaiting this response, so now we can wake it + // up. + ChromeClientAndroid* chromeC = static_cast(frame->page()->chrome()->client()); + chromeC->wakeUpMainThreadWithNewQuota(quota); +#endif +} + +// 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); + Frame* frame = viewImpl->mainFrame(); + + ChromeClientAndroid* chromeClient = static_cast(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 + WebCore::SchemeRegistry::registerURLSchemeAsLocal(jstringToWtfString(env, scheme)); +} + +static bool FocusBoundsChanged(JNIEnv* env, jobject obj) +{ + return GET_NATIVE_VIEW(env, obj)->focusBoundsChanged(); +} + +static void Pause(JNIEnv* env, jobject obj) +{ + // 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(); + ChromeClientAndroid* chromeClientAndroid = static_cast(chromeClient); + chromeClientAndroid->storeGeolocationPermissions(); + + Frame* mainFrame = GET_NATIVE_VIEW(env, obj)->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(); + + ANPEvent event; + SkANP::InitEvent(&event, kLifecycle_ANPEventType); + event.data.lifecycle.action = kPause_ANPLifecycleAction; + GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event); + + GET_NATIVE_VIEW(env, obj)->setIsPaused(true); +} + +static void Resume(JNIEnv* env, jobject obj) +{ + Frame* mainFrame = GET_NATIVE_VIEW(env, obj)->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(); + + ANPEvent event; + SkANP::InitEvent(&event, kLifecycle_ANPEventType); + event.data.lifecycle.action = kResume_ANPLifecycleAction; + GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event); + + GET_NATIVE_VIEW(env, obj)->setIsPaused(false); +} + +static void FreeMemory(JNIEnv* env, jobject obj) +{ + ANPEvent event; + SkANP::InitEvent(&event, kLifecycle_ANPEventType); + event.data.lifecycle.action = kFreeMemory_ANPLifecycleAction; + GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event); +} + +static void ProvideVisitedHistory(JNIEnv *env, jobject obj, jobject hist) +{ + WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); + LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); + + jobjectArray array = static_cast(hist); + + jsize len = env->GetArrayLength(array); + for (jsize i = 0; i < len; i++) { + jstring item = static_cast(env->GetObjectArrayElement(array, i)); + const UChar* str = static_cast(env->GetStringChars(item, 0)); + jsize len = env->GetStringLength(item); + viewImpl->addVisitedLink(str, len); + env->ReleaseStringChars(item, str); + env->DeleteLocalRef(item); + } +} + +// Notification from the UI thread that the plugin's full-screen surface has been discarded +static void FullScreenPluginHidden(JNIEnv* env, jobject obj, jint npp) +{ + WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); + PluginWidgetAndroid* plugin = viewImpl->getPluginWidget((NPP)npp); + if (plugin) + plugin->exitFullScreen(false); +} + +static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj) +{ + int L, T, R, B; + GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B); + return WebCore::IntRect(L, T, R - L, B - T); +} + +static bool ValidNodeAndBounds(JNIEnv *env, jobject obj, int frame, int node, + jobject rect) +{ + IntRect nativeRect = jrect_to_webrect(env, rect); + return GET_NATIVE_VIEW(env, obj)->validNodeAndBounds( + reinterpret_cast(frame), + reinterpret_cast(node), nativeRect); +} + +static jobject GetTouchHighlightRects(JNIEnv* env, jobject obj, jint x, jint y, jint slop) +{ + WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); + if (!viewImpl) + return 0; + Vector 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, "", "(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, "", "(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].right(), rects[i].bottom()); + if (rect) { + env->CallBooleanMethod(array, add, rect); + env->DeleteLocalRef(rect); + } + } + + env->DeleteLocalRef(rectClass); + env->DeleteLocalRef(arrayClass); + return array; +} + +static void AutoFillForm(JNIEnv* env, jobject obj, jint queryId) +{ +#if ENABLE(WEB_AUTOFILL) + WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); + if (!viewImpl) + return; + + WebCore::Frame* frame = viewImpl->mainFrame(); + if (frame) { + EditorClientAndroid* editorC = static_cast(frame->page()->editorClient()); + WebAutoFill* autoFill = editorC->getAutoFill(); + autoFill->fillFormFields(queryId); + } +#endif +} + +static void ScrollRenderLayer(JNIEnv* env, jobject obj, jint layer, jobject jRect) +{ + SkRect rect; + GraphicsJNI::jrect_to_rect(env, jRect, &rect); + GET_NATIVE_VIEW(env, obj)->scrollRenderLayer(layer, rect); +} + +// ---------------------------------------------------------------------------- + +/* + * JNI registration. + */ +static JNINativeMethod gJavaWebViewCoreMethods[] = { + { "nativeClearContent", "()V", + (void*) ClearContent }, + { "nativeFocusBoundsChanged", "()Z", + (void*) FocusBoundsChanged } , + { "nativeKey", "(IIIZZZZ)Z", + (void*) Key }, + { "nativeClick", "(IIZ)V", + (void*) Click }, + { "nativeContentInvalidateAll", "()V", + (void*) ContentInvalidateAll }, + { "nativeSendListBoxChoices", "([ZI)V", + (void*) SendListBoxChoices }, + { "nativeSendListBoxChoice", "(I)V", + (void*) SendListBoxChoice }, + { "nativeSetSize", "(IIIFIIIIZ)V", + (void*) SetSize }, + { "nativeSetScrollOffset", "(IZII)V", + (void*) SetScrollOffset }, + { "nativeSetGlobalBounds", "(IIII)V", + (void*) SetGlobalBounds }, + { "nativeSetSelection", "(II)V", + (void*) SetSelection } , + { "nativeModifySelection", "(II)Ljava/lang/String;", + (void*) ModifySelection }, + { "nativeDeleteSelection", "(III)V", + (void*) DeleteSelection } , + { "nativeReplaceTextfieldText", "(IILjava/lang/String;III)V", + (void*) ReplaceTextfieldText } , + { "nativeMoveFocus", "(II)V", + (void*) MoveFocus }, + { "nativeMoveMouse", "(III)V", + (void*) MoveMouse }, + { "nativeMoveMouseIfLatest", "(IIII)V", + (void*) MoveMouseIfLatest }, + { "passToJs", "(ILjava/lang/String;IIZZZZ)V", + (void*) PassToJs }, + { "nativeScrollFocusedTextInput", "(FI)V", + (void*) ScrollFocusedTextInput }, + { "nativeSetFocusControllerActive", "(Z)V", + (void*) SetFocusControllerActive }, + { "nativeSaveDocumentState", "(I)V", + (void*) SaveDocumentState }, + { "nativeFindAddress", "(Ljava/lang/String;Z)Ljava/lang/String;", + (void*) FindAddress }, + { "nativeHandleTouchEvent", "(I[I[I[IIII)Z", + (void*) HandleTouchEvent }, + { "nativeTouchUp", "(IIIII)V", + (void*) TouchUp }, + { "nativeRetrieveHref", "(II)Ljava/lang/String;", + (void*) RetrieveHref }, + { "nativeRetrieveAnchorText", "(II)Ljava/lang/String;", + (void*) RetrieveAnchorText }, + { "nativeRetrieveImageSource", "(II)Ljava/lang/String;", + (void*) RetrieveImageSource }, + { "nativeStopPaintingCaret", "()V", + (void*) StopPaintingCaret }, + { "nativeUpdateFrameCache", "()V", + (void*) UpdateFrameCache }, + { "nativeGetContentMinPrefWidth", "()I", + (void*) GetContentMinPrefWidth }, + { "nativeUpdateLayers", "(Landroid/graphics/Region;)I", + (void*) UpdateLayers }, + { "nativeRecordContent", "(Landroid/graphics/Region;Landroid/graphics/Point;)I", + (void*) RecordContent }, + { "setViewportSettingsFromNative", "()V", + (void*) SetViewportSettingsFromNative }, + { "nativeSplitContent", "(I)V", + (void*) SplitContent }, + { "nativeSetBackgroundColor", "(I)V", + (void*) SetBackgroundColor }, + { "nativeRegisterURLSchemeAsLocal", "(Ljava/lang/String;)V", + (void*) RegisterURLSchemeAsLocal }, + { "nativeDumpDomTree", "(Z)V", + (void*) DumpDomTree }, + { "nativeDumpRenderTree", "(Z)V", + (void*) DumpRenderTree }, + { "nativeDumpNavTree", "()V", + (void*) DumpNavTree }, + { "nativeDumpV8Counters", "()V", + (void*) DumpV8Counters }, + { "nativeSetNewStorageLimit", "(J)V", + (void*) SetNewStorageLimit }, + { "nativeGeolocationPermissionsProvide", "(Ljava/lang/String;ZZ)V", + (void*) GeolocationPermissionsProvide }, + { "nativePause", "()V", (void*) Pause }, + { "nativeResume", "()V", (void*) Resume }, + { "nativeFreeMemory", "()V", (void*) FreeMemory }, + { "nativeSetJsFlags", "(Ljava/lang/String;)V", (void*) SetJsFlags }, + { "nativeRequestLabel", "(II)Ljava/lang/String;", + (void*) RequestLabel }, + { "nativeRevealSelection", "()V", (void*) RevealSelection }, + { "nativeUpdateFrameCacheIfLoading", "()V", + (void*) UpdateFrameCacheIfLoading }, + { "nativeProvideVisitedHistory", "([Ljava/lang/String;)V", + (void*) ProvideVisitedHistory }, + { "nativeFullScreenPluginHidden", "(I)V", + (void*) FullScreenPluginHidden }, + { "nativeValidNodeAndBounds", "(IILandroid/graphics/Rect;)Z", + (void*) ValidNodeAndBounds }, + { "nativeGetTouchHighlightRects", "(III)Ljava/util/ArrayList;", + (void*) GetTouchHighlightRects }, + { "nativeAutoFillForm", "(I)V", + (void*) AutoFillForm }, + { "nativeScrollLayer", "(ILandroid/graphics/Rect;)V", + (void*) ScrollRenderLayer }, +}; + +int registerWebViewCore(JNIEnv* env) +{ + jclass widget = env->FindClass("android/webkit/WebViewCore"); + LOG_ASSERT(widget, + "Unable to find class android/webkit/WebViewCore"); + gWebViewCoreFields.m_nativeClass = env->GetFieldID(widget, "mNativeClass", + "I"); + LOG_ASSERT(gWebViewCoreFields.m_nativeClass, + "Unable to find android/webkit/WebViewCore.mNativeClass"); + gWebViewCoreFields.m_viewportWidth = env->GetFieldID(widget, + "mViewportWidth", "I"); + LOG_ASSERT(gWebViewCoreFields.m_viewportWidth, + "Unable to find android/webkit/WebViewCore.mViewportWidth"); + gWebViewCoreFields.m_viewportHeight = env->GetFieldID(widget, + "mViewportHeight", "I"); + LOG_ASSERT(gWebViewCoreFields.m_viewportHeight, + "Unable to find android/webkit/WebViewCore.mViewportHeight"); + gWebViewCoreFields.m_viewportInitialScale = env->GetFieldID(widget, + "mViewportInitialScale", "I"); + LOG_ASSERT(gWebViewCoreFields.m_viewportInitialScale, + "Unable to find android/webkit/WebViewCore.mViewportInitialScale"); + gWebViewCoreFields.m_viewportMinimumScale = env->GetFieldID(widget, + "mViewportMinimumScale", "I"); + LOG_ASSERT(gWebViewCoreFields.m_viewportMinimumScale, + "Unable to find android/webkit/WebViewCore.mViewportMinimumScale"); + gWebViewCoreFields.m_viewportMaximumScale = env->GetFieldID(widget, + "mViewportMaximumScale", "I"); + LOG_ASSERT(gWebViewCoreFields.m_viewportMaximumScale, + "Unable to find android/webkit/WebViewCore.mViewportMaximumScale"); + gWebViewCoreFields.m_viewportUserScalable = env->GetFieldID(widget, + "mViewportUserScalable", "Z"); + LOG_ASSERT(gWebViewCoreFields.m_viewportUserScalable, + "Unable to find android/webkit/WebViewCore.mViewportUserScalable"); + gWebViewCoreFields.m_viewportDensityDpi = env->GetFieldID(widget, + "mViewportDensityDpi", "I"); + LOG_ASSERT(gWebViewCoreFields.m_viewportDensityDpi, + "Unable to find android/webkit/WebViewCore.mViewportDensityDpi"); + gWebViewCoreFields.m_webView = env->GetFieldID(widget, + "mWebView", "Landroid/webkit/WebView;"); + LOG_ASSERT(gWebViewCoreFields.m_webView, + "Unable to find android/webkit/WebViewCore.mWebView"); + gWebViewCoreFields.m_drawIsPaused = env->GetFieldID(widget, + "mDrawIsPaused", "Z"); + LOG_ASSERT(gWebViewCoreFields.m_drawIsPaused, + "Unable to find android/webkit/WebViewCore.mDrawIsPaused"); + gWebViewCoreFields.m_lowMemoryUsageMb = env->GetFieldID(widget, "mLowMemoryUsageThresholdMb", "I"); + gWebViewCoreFields.m_highMemoryUsageMb = env->GetFieldID(widget, "mHighMemoryUsageThresholdMb", "I"); + gWebViewCoreFields.m_highUsageDeltaMb = env->GetFieldID(widget, "mHighUsageDeltaMb", "I"); + + gWebViewCoreStaticMethods.m_isSupportedMediaMimeType = + env->GetStaticMethodID(widget, "isSupportedMediaMimeType", "(Ljava/lang/String;)Z"); + LOG_FATAL_IF(!gWebViewCoreStaticMethods.m_isSupportedMediaMimeType, + "Could not find static method isSupportedMediaMimeType from WebViewCore"); + + env->DeleteLocalRef(widget); + + return jniRegisterNativeMethods(env, "android/webkit/WebViewCore", + gJavaWebViewCoreMethods, NELEM(gJavaWebViewCoreMethods)); +} + +} /* namespace android */ diff --git a/Source/WebKit/android/jni/WebViewCore.h b/Source/WebKit/android/jni/WebViewCore.h new file mode 100644 index 0000000..8d8f303 --- /dev/null +++ b/Source/WebKit/android/jni/WebViewCore.h @@ -0,0 +1,714 @@ +/* + * 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 WEBVIEWCORE_H +#define WEBVIEWCORE_H + +#include "CacheBuilder.h" +#include "CachedHistory.h" +#include "DeviceMotionAndOrientationManager.h" +#include "DOMSelection.h" +#include "FileChooser.h" +#include "PictureSet.h" +#include "PlatformGraphicsContext.h" +#include "SkColor.h" +#include "SkTDArray.h" +#include "SkRegion.h" +#include "Timer.h" +#include "WebCoreRefObject.h" +#include "WebCoreJni.h" +#include "WebRequestContext.h" +#include "android_npapi.h" + +#include +#include +#include + +namespace WebCore { + class Color; + class FrameView; + class HTMLAnchorElement; + class HTMLElement; + class HTMLImageElement; + class HTMLSelectElement; + class RenderPart; + class RenderText; + class Node; + class PlatformKeyboardEvent; + class QualifiedName; + class RenderTextControl; + class ScrollView; + class TimerBase; + class PageGroup; +} + +#if USE(ACCELERATED_COMPOSITING) +namespace WebCore { + class GraphicsLayerAndroid; +} +#endif + +namespace WebCore { + class BaseLayerAndroid; +} + +struct PluginWidgetAndroid; +class SkPicture; +class SkIRect; + +namespace android { + + enum Direction { + DIRECTION_BACKWARD = 0, + DIRECTION_FORWARD = 1 + }; + + enum NavigationAxis { + AXIS_CHARACTER = 0, + AXIS_WORD = 1, + AXIS_SENTENCE = 2, + AXIS_HEADING = 3, + AXIS_SIBLING = 4, + AXIS_PARENT_FIRST_CHILD = 5, + AXIS_DOCUMENT = 6 + }; + + class CachedFrame; + class CachedNode; + class CachedRoot; + class ListBoxReply; + + class WebCoreReply : public WebCoreRefObject { + public: + virtual ~WebCoreReply() {} + + virtual void replyInt(int value) { + SkDEBUGF(("WebCoreReply::replyInt(%d) not handled\n", value)); + } + + virtual void replyIntArray(const int* array, int count) { + SkDEBUGF(("WebCoreReply::replyIntArray() not handled\n")); + } + // add more replyFoo signatures as needed + }; + + // one instance of WebViewCore per page for calling into Java's WebViewCore + class WebViewCore : public WebCoreRefObject { + public: + /** + * Initialize the native WebViewCore with a JNI environment, a Java + * WebViewCore object and the main frame. + */ + WebViewCore(JNIEnv* env, jobject javaView, WebCore::Frame* mainframe); + ~WebViewCore(); + + // helper function + static WebViewCore* getWebViewCore(const WebCore::FrameView* view); + static WebViewCore* getWebViewCore(const WebCore::ScrollView* view); + + // Followings are called from native WebCore to Java + + /** + * Notification that a form was blurred. Pass a message to hide the + * keyboard if it was showing for that Node. + * @param Node The Node that blurred. + */ + void formDidBlur(const WebCore::Node*); + void focusNodeChanged(const WebCore::Node*); + + /** + * Scroll to an absolute position. + * @param x The x coordinate. + * @param y The y coordinate. + * @param animate If it is true, animate to the new scroll position + * + * This method calls Java to trigger a gradual scroll event. + */ + void scrollTo(int x, int y, bool animate = false); + + /** + * Record the invalid rectangle + */ + void contentInvalidate(const WebCore::IntRect &rect); + void contentInvalidateAll(); + + /** + * Satisfy any outstanding invalidates, so that the current state + * of the DOM is drawn. + */ + void contentDraw(); + + /** + * copy the layers to the UI side + */ + void layersDraw(); + +#if USE(ACCELERATED_COMPOSITING) + GraphicsLayerAndroid* graphicsRootLayer() const; +#endif + + /** Invalidate the view/screen, NOT the content/DOM, but expressed in + * content/DOM coordinates (i.e. they need to eventually be scaled, + * by webview into view.java coordinates + */ + void viewInvalidate(const WebCore::IntRect& rect); + + /** + * Invalidate part of the content that may be offscreen at the moment + */ + void offInvalidate(const WebCore::IntRect &rect); + + /** + * Called by webcore when the progress indicator is done + * used to rebuild and display any changes in focus + */ + void notifyProgressFinished(); + + /** + * Notify the view that WebCore did its first layout. + */ + void didFirstLayout(); + + /** + * Notify the view to update the viewport. + */ + void updateViewport(); + + /** + * Notify the view to restore the screen width, which in turn restores + * the scale. Also restore the scale for the text wrap. + */ + void restoreScale(float scale, float textWrapScale); + + /** + * Tell the java side to update the focused textfield + * @param pointer Pointer to the node for the input field. + * @param changeToPassword If true, we are changing the textfield to + * a password field, and ignore the String + * @param text If changeToPassword is false, this is the new text that + * should go into the textfield. + */ + void updateTextfield(WebCore::Node* pointer, + bool changeToPassword, const WTF::String& text); + + /** + * Tell the java side to update the current selection in the focused + * textfield to the WebTextView. This function finds the currently + * focused textinput, and passes its selection to java. + * If there is no focus, or it is not a text input, this does nothing. + */ + void updateTextSelection(); + + void clearTextEntry(); + // JavaScript support + void jsAlert(const WTF::String& url, const WTF::String& text); + bool jsConfirm(const WTF::String& url, const WTF::String& text); + bool jsPrompt(const WTF::String& url, const WTF::String& message, + const WTF::String& defaultValue, WTF::String& result); + bool jsUnload(const WTF::String& url, const WTF::String& message); + bool jsInterrupt(); + + /** + * Tell the Java side that the origin has exceeded its database quota. + * @param url The URL of the page that caused the quota overflow + * @param databaseIdentifier the id of the database that caused the + * quota overflow. + * @param currentQuota The current quota for the origin + * @param estimatedSize The estimated size of the database + */ + void exceededDatabaseQuota(const WTF::String& url, + const WTF::String& databaseIdentifier, + const unsigned long long currentQuota, + const unsigned long long estimatedSize); + + /** + * Tell the Java side that the appcache has exceeded its max size. + * @param spaceNeeded is the amount of disk space that would be needed + * in order for the last appcache operation to succeed. + */ + void reachedMaxAppCacheSize(const unsigned long long spaceNeeded); + + /** + * Set up the PageGroup's idea of which links have been visited, + * with the browser history. + * @param group the object to deliver the links to. + */ + void populateVisitedLinks(WebCore::PageGroup*); + + /** + * Instruct the browser to show a Geolocation permission prompt for the + * specified origin. + * @param origin The origin of the frame requesting Geolocation + * permissions. + */ + void geolocationPermissionsShowPrompt(const WTF::String& origin); + /** + * Instruct the browser to hide the Geolocation permission prompt. + */ + void geolocationPermissionsHidePrompt(); + + jobject getDeviceMotionService(); + jobject getDeviceOrientationService(); + + void addMessageToConsole(const String& message, unsigned int lineNumber, const String& sourceID, int msgLevel); + + /** + * Tell the Java side of the scrollbar mode + */ + void setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode verticalMode); + + // + // Followings support calls from Java to native WebCore + // + + WTF::String retrieveHref(int x, int y); + WTF::String retrieveAnchorText(int x, int y); + WTF::String retrieveImageSource(int x, int y); + WTF::String requestLabel(WebCore::Frame* , WebCore::Node* ); + + // If the focus is a textfield (), textarea, or contentEditable, + // scroll the selection on screen (if necessary). + void revealSelection(); + // Create a single picture to represent the drawn DOM (used by navcache) + void recordPicture(SkPicture* picture); + + void moveFocus(WebCore::Frame* frame, WebCore::Node* node); + void moveMouse(WebCore::Frame* frame, int x, int y); + void moveMouseIfLatest(int moveGeneration, + WebCore::Frame* frame, int x, int y); + + // set the scroll amount that webview.java is currently showing + void setScrollOffset(int moveGeneration, bool sendScrollEvent, int dx, int dy); + + void setGlobalBounds(int x, int y, int h, int v); + + void setSizeScreenWidthAndScale(int width, int height, int screenWidth, + float scale, int realScreenWidth, int screenHeight, int anchorX, + int anchorY, bool ignoreHeight); + + /** + * Handle key events from Java. + * @return Whether keyCode was handled by this class. + */ + bool key(const WebCore::PlatformKeyboardEvent& event); + + /** + * Handle (trackball) click event / dpad center press from Java. + * Also used when typing into an unfocused textfield, in which case 'fake' + * will be true. + */ + void click(WebCore::Frame* frame, WebCore::Node* node, bool fake); + + /** + * Handle touch event + */ + bool handleTouchEvent(int action, Vector& ids, Vector& points, int actionIndex, int metaState); + + /** + * Handle motionUp event from the UI thread (called touchUp in the + * WebCore thread). + * @param touchGeneration Generation number for touches so we can ignore + * touches when a newer one has been generated. + * @param frame Pointer to Frame containing the node that was touched. + * @param node Pointer to Node that was touched. + * @param x x-position of the touch. + * @param y y-position of the touch. + */ + void touchUp(int touchGeneration, WebCore::Frame* frame, + WebCore::Node* node, int x, int y); + + /** + * Sets the index of the label from a popup + */ + void popupReply(int index); + void popupReply(const int* array, int count); + + /** + * Delete text from start to end in the focused textfield. + * If start == end, set the selection, but perform no deletion. + * If there is no focus, silently fail. + * If start and end are out of order, swap them. + */ + void deleteSelection(int start, int end, int textGeneration); + + /** + * Set the selection of the currently focused textfield to (start, end). + * If start and end are out of order, swap them. + */ + void setSelection(int start, int end); + + /** + * Modifies the current selection. + * + * Note: Accessibility support. + * + * direction - The direction in which to alter the selection. + * granularity - The granularity of the selection modification. + * + * returns - The selected HTML as a string. This is not a well formed + * HTML, rather the selection annotated with the tags of all + * intermediary elements it crosses. + */ + String modifySelection(const int direction, const int granularity); + + /** + * Moves the selection to the given node in a given frame i.e. selects that node. + * + * Note: Accessibility support. + * + * frame - The frame in which to select is the node to be selected. + * node - The node to be selected. + * + * returns - The selected HTML as a string. This is not a well formed + * HTML, rather the selection annotated with the tags of all + * intermediary elements it crosses. + */ + String moveSelection(WebCore::Frame* frame, WebCore::Node* node); + + /** + * In the currently focused textfield, replace the characters from oldStart to oldEnd + * (if oldStart == oldEnd, this will be an insert at that position) with replace, + * and set the selection to (start, end). + */ + void replaceTextfieldText(int oldStart, + int oldEnd, const WTF::String& replace, int start, int end, + int textGeneration); + void passToJs(int generation, + const WTF::String& , const WebCore::PlatformKeyboardEvent& ); + /** + * Scroll the focused textfield to (x, y) in document space + */ + void scrollFocusedTextInput(float x, int y); + /** + * Set the FocusController's active and focused states, so that + * the caret will draw (true) or not. + */ + void setFocusControllerActive(bool active); + + void saveDocumentState(WebCore::Frame* frame); + + void addVisitedLink(const UChar*, int); + + // TODO: I don't like this hack but I need to access the java object in + // order to send it as a parameter to java + AutoJObject getJavaObject(); + + // Return the parent WebView Java object associated with this + // WebViewCore. + 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 + pageflipping bitmap. + */ + void addPlugin(PluginWidgetAndroid*); + void removePlugin(PluginWidgetAndroid*); + // returns true if the pluginwidgit is in our active list + bool isPlugin(PluginWidgetAndroid*) const; + void invalPlugin(PluginWidgetAndroid*); + void drawPlugins(); + + // send the current screen size/zoom to all of the plugins in our list + void sendPluginVisibleScreen(); + + // send onLoad event to plugins who are descendents of the given frame + void notifyPluginsOnFrameLoad(const Frame*); + + // gets a rect representing the current on-screen portion of the document + void getVisibleScreen(ANPRectI&); + + // send this event to all of the plugins in our list + void sendPluginEvent(const ANPEvent&); + + // 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); + + void requestKeyboardWithSelection(const WebCore::Node*, int selStart, int selEnd); + // Notify the Java side that webkit is requesting a keyboard + void requestKeyboard(bool showKeyboard); + + // Generates a class loader that contains classes from the plugin's apk + jclass getPluginClass(const WTF::String& libName, const char* className); + + // Creates a full screen surface for a plugin + void showFullScreenPlugin(jobject webkitPlugin, NPP npp); + + // Instructs the UI thread to discard the plugin's full-screen surface + void hideFullScreenPlugin(); + + // Creates a childView for the plugin but does not attach to the view hierarchy + jobject createSurface(jobject view); + + // Adds the plugin's view (aka surface) to the view hierarchy + jobject addSurface(jobject view, int x, int y, int width, int height); + + // Updates a Surface coordinates and dimensions for a plugin + void updateSurface(jobject childView, int x, int y, int width, int height); + + // Destroys a SurfaceView for a plugin + void destroySurface(jobject childView); + + // Returns the context (android.content.Context) of the WebView + jobject getContext(); + + // Manages requests to keep the screen on while the WebView is visible + void keepScreenOn(bool screenOn); + + bool validNodeAndBounds(Frame* , Node* , const IntRect& ); + + // Make the rect (left, top, width, height) visible. If it can be fully + // fit, center it on the screen. Otherwise make sure the point specified + // by (left + xPercentInDoc * width, top + yPercentInDoc * height) + // pinned at the screen position (xPercentInView, yPercentInView). + void showRect(int left, int top, int width, int height, int contentWidth, + int contentHeight, float xPercentInDoc, float xPercentInView, + float yPercentInDoc, float yPercentInView); + + // Scale the rect (x, y, width, height) to make it just fit and centered + // in the current view. + 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 getTouchHighlightRects(int x, int y, int slop); + + // Open a file chooser for selecting a file to upload + void openFileChooser(PassRefPtr ); + + // reset the picture set to empty + void clearContent(); + + bool focusBoundsChanged(); + + // record the inval area, and the picture size + BaseLayerAndroid* recordContent(SkRegion* , SkIPoint* ); + + // This creates a new BaseLayerAndroid by copying the current m_content + // and doing a copy of the layers. The layers' content may be updated + // as we are calling layersSync(). + BaseLayerAndroid* createBaseLayer(); + + int textWrapWidth() const { return m_textWrapWidth; } + float scale() const { return m_scale; } + float textWrapScale() const { return m_screenWidth * m_scale / m_textWrapWidth; } + WebCore::Frame* mainFrame() const { return m_mainFrame; } + void updateCursorBounds(const CachedRoot* root, + const CachedFrame* cachedFrame, const CachedNode* cachedNode); + void updateFrameCacheIfLoading(); + + // utility to split slow parts of the picture set + void splitContent(PictureSet*); + + void notifyWebAppCanBeInstalled(); + +#if ENABLE(VIDEO) + void enterFullscreenForVideoLayer(int layerId, const WTF::String& url); +#endif + + void setWebTextViewAutoFillable(int queryId, const string16& previewSummary); + + DeviceMotionAndOrientationManager* deviceMotionAndOrientationManager() { return &m_deviceMotionAndOrientationManager; } + + 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); + // call only from webkit thread (like add/remove), return true if inst + // is still alive + static bool isInstance(WebViewCore*); + // if there exists at least one WebViewCore instance then we return the + // application context, otherwise NULL is returned. + static jobject getApplicationContext(); + // Check whether a media mimeType is supported in Android media framework. + static bool isSupportedMediaMimeType(const WTF::String& mimeType); + + // 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; + // These two fields go together: we use the mutex to protect access to + // m_buttons, so that we, and webview.cpp can look/modify the m_buttons + // field safely from our respective threads + static Mutex gButtonMutex; + WTF::Vector m_buttons; + // end of shared members + + // internal functions + private: + CacheBuilder& cacheBuilder(); + WebCore::Node* currentFocus(); + // Compare the new set of buttons to the old one. All of the new + // buttons either replace our old ones or should be added to our list. + // Then check the old buttons to see if any are no longer needed. + void updateButtonList(WTF::Vector* buttons); + void reset(bool fromConstructor); + // 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); + + friend class ListBoxReply; + struct JavaGlue; + struct JavaGlue* m_javaGlue; + WebCore::Frame* m_mainFrame; + WebCoreReply* m_popupReply; + WebCore::Node* m_lastFocused; + WebCore::IntRect m_lastFocusedBounds; + int m_blurringNodePointer; + int m_lastFocusedSelStart; + int m_lastFocusedSelEnd; + PictureSet m_content; // the set of pictures to draw + SkRegion m_addInval; // the accumulated inval region (not yet drawn) + SkRegion m_rebuildInval; // the accumulated region for rebuilt pictures + // Used in passToJS to avoid updating the UI text field until after the + // key event has been processed. + bool m_blockTextfieldUpdates; + bool m_focusBoundsChanged; + bool m_skipContentDraw; + // Passed in with key events to know when they were generated. Store it + // with the cache so that we can ignore stale text changes. + int m_textGeneration; + CachedRoot* m_temp; + SkPicture* m_tempPict; + int m_maxXScroll; + int m_maxYScroll; + int m_scrollOffsetX; // webview.java's current scroll in X + int m_scrollOffsetY; // webview.java's current scroll in Y + WebCore::IntPoint m_mousePos; + bool m_frameCacheOutOfDate; + bool m_progressDone; + int m_lastPassed; + int m_lastVelocity; + 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; + float m_scale; + unsigned m_domtree_version; + bool m_check_domtree_version; + PageGroup* m_groupForVisitedLinks; + bool m_isPaused; + int m_cacheMode; + bool m_shouldPaintCaret; + + SkTDArray m_plugins; + WebCore::Timer m_pluginInvalTimer; + void pluginInvalTimerFired(WebCore::Timer*) { + this->drawPlugins(); + } + int m_screenOnCounter; + + void doMaxScroll(CacheBuilder::Direction dir); + SkPicture* rebuildPicture(const SkIRect& inval); + void rebuildPictureSet(PictureSet* ); + void sendNotifyProgressFinished(); + /* + * Handle a mouse click, either from a touch or trackball press. + * @param frame Pointer to the Frame containing the node that was clicked on. + * @param node Pointer to the Node that was clicked on. + * @param fake This is a fake mouse click, used to put a textfield into focus. Do not + * open the IME. + */ + bool handleMouseClick(WebCore::Frame*, WebCore::Node*, bool fake); + WebCore::HTMLAnchorElement* retrieveAnchorElement(int x, int y); + WebCore::HTMLElement* retrieveElement(int x, int y, + const WebCore::QualifiedName& ); + WebCore::HTMLImageElement* retrieveImageElement(int x, int y); + // below are members responsible for accessibility support + String modifySelectionTextNavigationAxis(DOMSelection* selection, int direction, int granularity); + String modifySelectionDomNavigationAxis(DOMSelection* selection, int direction, int granularity); + Text* traverseNextContentTextNode(Node* fromNode, Node* toNode ,int direction); + bool isVisible(Node* node); + bool isHeading(Node* node); + String formatMarkup(DOMSelection* selection); + void selectAt(int x, int y); + Node* m_currentNodeDomNavigationAxis; + void scrollNodeIntoView(Frame* frame, Node* node); + bool isContentTextNode(Node* node); + Node* getIntermediaryInputElement(Node* fromNode, Node* toNode, int direction); + bool isContentInputElement(Node* node); + bool isDescendantOf(Node* parent, Node* node); + void advanceAnchorNode(DOMSelection* selection, int direction, String& markup, bool ignoreFirstNode, ExceptionCode& ec); + Node* getNextAnchorNode(Node* anchorNode, bool skipFirstHack, int direction); + Node* getImplicitBoundaryNode(Node* node, unsigned offset, int direction); + +#if ENABLE(TOUCH_EVENTS) + bool m_forwardingTouchEvents; +#endif +#if DEBUG_NAV_UI + uint32_t m_now; +#endif + DeviceMotionAndOrientationManager m_deviceMotionAndOrientationManager; +#if USE(CHROME_NETWORK_STACK) + scoped_refptr m_webRequestContext; +#endif + + // called from constructor, to add this to a global list + static void addInstance(WebViewCore*); + // called from destructor, to remove this from a global list + static void removeInstance(WebViewCore*); + }; + +} // namespace android + +#endif // WEBVIEWCORE_H diff --git a/Source/WebKit/android/nav/CacheBuilder.cpp b/Source/WebKit/android/nav/CacheBuilder.cpp new file mode 100644 index 0000000..dc10f21 --- /dev/null +++ b/Source/WebKit/android/nav/CacheBuilder.cpp @@ -0,0 +1,3201 @@ +/* + * 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 + +#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(), false, false); +} + +#if DUMP_NAV_CACHE + +static bool hasEventListener(Node* node, const AtomicString& eventType) { + if (!node->isElementNode()) + return false; + Element* element = static_cast(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(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(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(node); + wideString(anchor->href()); + } else if (node->hasTagName(HTMLNames::imgTag)) { + HTMLImageElement* image = static_cast(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(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(renderer); + if (renderer->isRenderBlock() && renderBlock->hasColumns()) { + const RenderBox* box = static_cast(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 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(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& 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 tracker(1); // sentinel + { + FocusTracker* baseTracker = tracker.data(); + bzero(baseTracker, sizeof(FocusTracker)); + baseTracker->mCachedNodeIndex = -1; + } + WTF::Vector layerTracker(1); // sentinel + bzero(layerTracker.data(), sizeof(LayerTracker)); + WTF::Vector clipTracker(1); // sentinel + bzero(clipTracker.data(), sizeof(ClipColumnTracker)); + WTF::Vector tabIndexTracker(1); // sentinel + bzero(tabIndexTracker.data(), sizeof(TabIndexTracker)); + WTF::Vector 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(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 (node->hasTagName(HTMLNames::canvasTag)) + mPictureSetDisabled = true; + if (checkForPluginViewThatWantsFocus(nodeRenderer)) { + bounds = absBounds; + isUnclipped = true; + takesFocus = true; + type = PLUGIN_CACHEDNODETYPE; + goto keepNode; + } + // Only use the root contentEditable element + if (node->isContentEditable() && !node->parentOrHostNode()->isContentEditable()) { + 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(node); + if (input->isTextField()) { + if (input->readOnly()) + continue; + type = TEXT_INPUT_CACHEDNODETYPE; + cachedInput.init(); + cachedInput.setAutoComplete(input->autoComplete()); + 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(node); + if (area->readOnly()) + continue; + cachedInput.init(); + type = TEXT_INPUT_CACHEDNODETYPE; + cachedInput.setFormPointer(area->form()); + cachedInput.setIsTextArea(true); + 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(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(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.setNavableRects(); + 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(); + lastCached->setNavableRects(); + 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(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->getRect(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(renderer)->widget(); + if (widget == NULL) + return NULL; + if (widget->isFrameView() == false) + return NULL; + return static_cast(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(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(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(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(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 (layer->width() == 0 || layer->height() == 0) + 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->width(), layer->height()); + 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, + 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, false, false); +#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(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* result, IntRect* focusBounds) +{ + if (bounds.isEmpty()) + return true; + bounds.move(x, y); + if (bounds.right() <= 0 || bounds.bottom() <= 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* result, + int* imageCountPtr) +{ + WTF::Vector 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 + int left = bounds.x() + ((RenderBox*)renderer)->paddingLeft() + + ((RenderBox*)renderer)->borderLeft(); + int top = bounds.y() + ((RenderBox*)renderer)->paddingTop() + + ((RenderBox*)renderer)->borderTop(); + int right = bounds.right() - ((RenderBox*)renderer)->paddingRight() + - ((RenderBox*)renderer)->borderRight(); + int bottom = bounds.bottom() - ((RenderBox*)renderer)->paddingBottom() + - ((RenderBox*)renderer)->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* 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* 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 new file mode 100644 index 0000000..d48a045 --- /dev/null +++ b/Source/WebKit/android/nav/CacheBuilder.h @@ -0,0 +1,297 @@ +/* + * 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 +#include + +#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* 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 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* 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* result); + static bool ConstructTextRects(Text* node, int start, + Text* last, int end, int x, int y, IntRect* focusBounds, + const IntRect& clip, WTF::Vector* 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, + 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 new file mode 100644 index 0000000..c610022 --- /dev/null +++ b/Source/WebKit/android/nav/CachedColor.cpp @@ -0,0 +1,58 @@ +/* + * 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 new file mode 100644 index 0000000..4b39810 --- /dev/null +++ b/Source/WebKit/android/nav/CachedColor.h @@ -0,0 +1,87 @@ +/* + * 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 new file mode 100644 index 0000000..3d9e012 --- /dev/null +++ b/Source/WebKit/android/nav/CachedDebug.h @@ -0,0 +1,72 @@ +/* + * 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 +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 new file mode 100644 index 0000000..b26e24b --- /dev/null +++ b/Source/WebKit/android/nav/CachedFrame.cpp @@ -0,0 +1,1494 @@ +/* + * 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.bottom() : prior.bottom(); + 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.right(); + int testRight = bestRect.right(); + if (right < testRight) + right = testRight; + width = right - left; + } else { + left = direction == LEFT ? bestRect.right() : prior.right(); + 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.bottom(); + int testBottom = bestRect.bottom(); + 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(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.right(), rect.bottom(), + testRect.x(), testRect.y(), testRect.right(), testRect.bottom()); + 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.right(), + cursorRect.bottom()); + 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->right() - testBounds.x(); break; + case RIGHT: distance = testBounds.right() - clip->x(); break; + case UP: distance = clip->bottom() - testBounds.y(); break; + case DOWN: distance = testBounds.bottom() - clip->y(); break; +#endif + default: + distance = 0; ASSERT(0); + } + 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(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(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.bottom(); + int testX = mNodeBounds.x(); + int testRight = mNodeBounds.right(); + setNavOverlap(navBounds.width(), navBounds.right() - 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.bottom() - mNodeBounds.bottom(); + setNavInclusion(testRight - navBounds.right(), 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.right(); + int testY = mNodeBounds.y(); + int testBottom = mNodeBounds.bottom(); + setNavOverlap(navBounds.height(), navBounds.bottom() - testY, + testBottom - navBounds.y()); + if (canBeReachedByAnotherDirection()) { + mNode->setCondition(CachedNode::BEST_DIRECTION); + return REJECT_TEST; + } + int inNavRight = navBounds.right() - mNodeBounds.right(); + 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.bottom()); + 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.right(); + int testY = mNodeBounds.y(); + int testBottom = mNodeBounds.bottom(); + setNavOverlap(navBounds.height(), navBounds.bottom() - 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.right() - mNodeBounds.right(); + setNavInclusion(testBottom - navBounds.bottom(), 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.bottom(); + int testX = mNodeBounds.x(); + int testRight = mNodeBounds.right(); + setNavOverlap(navBounds.width(), navBounds.right() - testX, + testRight - navBounds.x()); + if (canBeReachedByAnotherDirection()) { + mNode->setCondition(CachedNode::BEST_DIRECTION); + return REJECT_TEST; + } + int inNavBottom = navBounds.bottom() - mNodeBounds.bottom(); + 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.right()); + 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 new file mode 100644 index 0000000..039a0ee --- /dev/null +++ b/Source/WebKit/android/nav/CachedFrame.h @@ -0,0 +1,285 @@ +/* + * 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 CachedFrame_H +#define CachedFrame_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(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().bottom(); } + 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().right(); } + 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 mCachedColors; + WTF::Vector mCachedNodes; + WTF::Vector mCachedFrames; + WTF::Vector mCachedTextInputs; +#if USE(ACCELERATED_COMPOSITING) + WTF::Vector 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 diff --git a/Source/WebKit/android/nav/CachedHistory.cpp b/Source/WebKit/android/nav/CachedHistory.cpp new file mode 100644 index 0000000..9066412 --- /dev/null +++ b/Source/WebKit/android/nav/CachedHistory.cpp @@ -0,0 +1,187 @@ +/* + * 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.bottom()) + mMinWorkingHorizontal = viewBounds.y(); + if (mMaxWorkingHorizontal > viewBounds.bottom() || + mMaxWorkingHorizontal <= viewBounds.y()) + mMaxWorkingHorizontal = viewBounds.bottom(); + if (mMinWorkingVertical < viewBounds.x() || + mMinWorkingVertical >= viewBounds.right()) + mMinWorkingVertical = viewBounds.x(); + if (mMaxWorkingVertical > viewBounds.right() || + mMaxWorkingVertical <= viewBounds.x()) + mMaxWorkingVertical = viewBounds.right(); +} + +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->bottom(); + } + if (lastAxis != CachedFrame::UP && navBounds->width() > 0) { + mMinWorkingVertical = navBounds->x(); + mMaxWorkingVertical = navBounds->right(); + } + } + 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 new file mode 100644 index 0000000..e8c1ad9 --- /dev/null +++ b/Source/WebKit/android/nav/CachedHistory.h @@ -0,0 +1,89 @@ +/* + * 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 new file mode 100644 index 0000000..a6a57ef --- /dev/null +++ b/Source/WebKit/android/nav/CachedInput.cpp @@ -0,0 +1,100 @@ +/* + * 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 new file mode 100644 index 0000000..f7f9eea --- /dev/null +++ b/Source/WebKit/android/nav/CachedInput.h @@ -0,0 +1,112 @@ +/* + * 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 setTextSize(float textSize) { mTextSize = textSize; } + 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 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 new file mode 100644 index 0000000..299f2d1 --- /dev/null +++ b/Source/WebKit/android/nav/CachedLayer.cpp @@ -0,0 +1,221 @@ +/* + * 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(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(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 SkLayer* 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 new file mode 100644 index 0000000..3d963e0 --- /dev/null +++ b/Source/WebKit/android/nav/CachedLayer.h @@ -0,0 +1,86 @@ +/* + * 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 new file mode 100644 index 0000000..e3ba34d --- /dev/null +++ b/Source/WebKit/android/nav/CachedNode.cpp @@ -0,0 +1,432 @@ +/* + * 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(parent->hasFrame(this)); + child->clearCursor(); + } + mIsCursor = false; +} + +bool CachedNode::Clip(const WebCore::IntRect& outer, WebCore::IntRect* inner, + WTF::Vector* 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* 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 = mNavableRects; + ASSERT(partMax > 0); + WebCore::IntRect bounds = mCursorRing[0]; + for (int partIndex = 1; 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 (mNavableRects <= 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->bottom(); + int unitLeft = unitBoundsPtr->x(); + int unitRight = unitBoundsPtr->right(); + WebCore::IntRect* testBoundsPtr = mCursorRing.begin() - 1; + while (++testBoundsPtr < unitBoundsEnd) { + if (unitBoundsPtr == testBoundsPtr) + continue; + int testTop = testBoundsPtr->y(); + int testBottom = testBoundsPtr->bottom(); + int testLeft = testBoundsPtr->x(); + int testRight = testBoundsPtr->right(); + 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->bottom()) + candidateTop = checkBoundsPtr->bottom(); + else if (candidateTop < checkBoundsPtr->y() && + candidateBottom <= checkBoundsPtr->bottom()) + candidateBottom = checkBoundsPtr->y(); + else + goto nextCheck; + } else { + if (candidateLeft >= checkBoundsPtr->x() && + candidateRight > checkBoundsPtr->right()) + candidateLeft = checkBoundsPtr->right(); + else if (candidateLeft < checkBoundsPtr->x() && + candidateRight <= checkBoundsPtr->right()) + 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(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* 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 = mNavableRects; + int innerMax = other->mNavableRects; + 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* 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 mNavableRects=%d;\n", b->mNavableRects); + 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 new file mode 100644 index 0000000..f9bcbed --- /dev/null +++ b/Source/WebKit/android/nav/CachedNode.h @@ -0,0 +1,247 @@ +/* + * 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 +#include + +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* 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* ) 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* ) 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 mNavableRects; } + 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& 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 setNavableRects() { mNavableRects = mCursorRing.size(); } + 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 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 mNavableRects; // FIXME: could be bitfield once I limit max number of rects + 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 new file mode 100644 index 0000000..8bc9328 --- /dev/null +++ b/Source/WebKit/android/nav/CachedNodeType.h @@ -0,0 +1,56 @@ +/* + * 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 new file mode 100644 index 0000000..73a5c2c --- /dev/null +++ b/Source/WebKit/android/nav/CachedPrefix.h @@ -0,0 +1,53 @@ +/* + * 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 +#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 new file mode 100644 index 0000000..64bf19a --- /dev/null +++ b/Source/WebKit/android/nav/CachedRoot.cpp @@ -0,0 +1,1813 @@ +/* + * 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& 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->right(), r->bottom()}; + 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 mLayers; + Vector 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(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(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(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(mBounder).startText(paint); + INHERITED::drawPosTextH(text, byteLength, xpos, constY, paint); + } + + virtual int save(SaveFlags flags) + { + RingCheck& bounder = static_cast(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(mBounder); + bounder.push(CommonCheck::kPushLayer_Type, getTotalClip().getBounds()); + return INHERITED::save(flags); + } + + virtual void restore() + { + RingCheck& bounder = static_cast(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.right(), + contentBounds.bottom(), + overBounds.x(), overBounds.y(), overBounds.right(), overBounds.bottom(), + mScrolledBounds.x(), mScrolledBounds.y(), mScrolledBounds.right(), + mScrolledBounds.bottom(), + mViewBounds.x(), mViewBounds.y(), mViewBounds.right(), + mViewBounds.bottom(), + bitBounds->x(), bitBounds->y(), bitBounds->right(), + bitBounds->bottom()); +} + + +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& 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.right(), bitBounds.bottom(), + nodeBounds.x(), nodeBounds.y(), nodeBounds.right(), nodeBounds.bottom(), + testBounds.x(), testBounds.y(), testBounds.right(), testBounds.bottom(), + 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 (mRootLayer) CachedLayer::Debug::printRootLayerAndroid(mRootLayer); +#endif + int best = INT_MAX; + bool inside = false; + (const_cast(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.right()); + setupScrolledBounds(); + // (line up) + mScrolledBounds.setHeight(mScrolledBounds.height() + mMaxYScroll); + int testTop = mScrolledBounds.y(); + int viewBottom = mViewBounds.bottom(); + const WebCore::IntRect& navBounds = mHistory->mNavBounds; + if (navBounds.isEmpty() == false && + navBounds.bottom() > viewBottom && viewBottom < mContents.height()) + return false; + if (navBounds.isEmpty() == false) { + int navTop = navBounds.y(); + int scrollBottom; + if (testTop < navTop && navTop < (scrollBottom = mScrolledBounds.bottom())) { + 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.bottom()); + setupScrolledBounds(); + mScrolledBounds.setX(mScrolledBounds.x() - mMaxXScroll); + mScrolledBounds.setWidth(mScrolledBounds.width() + mMaxXScroll); + int testRight = mScrolledBounds.right(); + 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.right(); + 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.right(), + 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.bottom(), 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.right() < newBounds.right()) + offsetX = mViewBounds.right() - mHistory->mNavBounds.right(); + if (mViewBounds.y() > newBounds.y()) + offsetY = mViewBounds.y() - mHistory->mNavBounds.y(); + else if (mViewBounds.bottom() < newBounds.bottom()) + offsetY = mViewBounds.bottom() - mHistory->mNavBounds.bottom(); + mHistory->mNavBounds.move(offsetX, offsetY); + } + mHistory->setDidFirstLayout(false); +} + +bool CachedRoot::innerRight(const CachedNode* test, BestData* bestData) const +{ + ASSERT(minWorkingHorizontal() >= mViewBounds.y()); + ASSERT(maxWorkingHorizontal() <= mViewBounds.bottom()); + setupScrolledBounds(); + // (align) + mScrolledBounds.setWidth(mScrolledBounds.width() + mMaxXScroll); + int testLeft = mScrolledBounds.x(); + int viewRight = mViewBounds.right(); + const WebCore::IntRect& navBounds = mHistory->mNavBounds; + if (navBounds.isEmpty() == false && + navBounds.right() > viewRight && viewRight < mContents.width()) + return false; + if (navBounds.isEmpty() == false) { + int navLeft = navBounds.x(); + int scrollRight; + if (testLeft < navLeft && navLeft < (scrollRight = mScrolledBounds.right())) { + 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.right()); + setupScrolledBounds(); + mScrolledBounds.setY(mScrolledBounds.y() - mMaxYScroll); + mScrolledBounds.setHeight(mScrolledBounds.height() + mMaxYScroll); + int testBottom = mScrolledBounds.bottom(); + 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.bottom(); + 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 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(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 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(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.right() <= mViewBounds.right(); + case UP: + *delta = -mMaxYScroll; + return newOutset.y() >= mViewBounds.y(); + case DOWN: + *delta = mMaxYScroll; + return newOutset.bottom() <= mViewBounds.bottom(); + 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 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 new file mode 100644 index 0000000..1f8b851 --- /dev/null +++ b/Source/WebKit/android/nav/CachedRoot.h @@ -0,0 +1,142 @@ +/* + * 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; } + const 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.h b/Source/WebKit/android/nav/DrawExtra.h new file mode 100644 index 0000000..6716a65 --- /dev/null +++ b/Source/WebKit/android/nav/DrawExtra.h @@ -0,0 +1,48 @@ +/* + * 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 DrawExtra_h +#define DrawExtra_h + +class SkCanvas; + +namespace WebCore { + class IntRect; + class LayerAndroid; +} + +using namespace WebCore; + +namespace android { + +class DrawExtra { +public: + virtual ~DrawExtra() {} + virtual void draw(SkCanvas* , LayerAndroid* , IntRect* ) = 0; +}; + +} + +#endif diff --git a/Source/WebKit/android/nav/FindCanvas.cpp b/Source/WebKit/android/nav/FindCanvas.cpp new file mode 100644 index 0000000..2d310b3 --- /dev/null +++ b/Source/WebKit/android/nav/FindCanvas.cpp @@ -0,0 +1,699 @@ +/* + * 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 + +#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(); + 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 (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]; + // FIXME: this should test if the match in the layer is visible + if (info.isInLayer()) + return noBounds; + 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(); +} + +// 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* 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 new file mode 100644 index 0000000..76ee1e2 --- /dev/null +++ b/Source/WebKit/android/nav/FindCanvas.h @@ -0,0 +1,255 @@ +/* + * 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 +#include + +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. + bool isInLayer() const { return m_layerId >= 0; } + int layerId() const { return m_layerId; } + void set(const SkRegion& region, SkPicture* pic, int 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* detachMatches() { + WTF::Vector* 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* mMatches; + const UChar* mLowerText; + const UChar* mUpperText; + Vector mLowerReversed; + Vector mUpperReversed; + size_t mLength; + FindBounder mBounder; + int mNumFound; + SkScalar mOutset; + SkTDArray 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() { delete m_matches; } + void clearCurrentLocation() { m_hasCurrentLocation = false; } + IntRect currentMatchBounds() const; + int currentMatchIndex() const { return m_findIndex; } + bool currentMatchIsInLayer() const; + virtual void draw(SkCanvas* , LayerAndroid* , IntRect* ); + void findNext(bool forward); + bool isCurrentLocationValid() { return m_hasCurrentLocation; } + void setMatches(WTF::Vector* matches); +private: + void drawMatch(const SkRegion& region, SkCanvas* canvas, bool focused); + void setUpFindPaint(); + void storeCurrentMatchLocation(); + WTF::Vector* 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/ParseCanvas.h b/Source/WebKit/android/nav/ParseCanvas.h new file mode 100644 index 0000000..9b7a889 --- /dev/null +++ b/Source/WebKit/android/nav/ParseCanvas.h @@ -0,0 +1,52 @@ +/* + * 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 PARSE_CANVAS_H +#define PARSE_CANVAS_H + +#include "SkCanvas.h" + +namespace android { + +class ParseCanvas : public SkCanvas { +protected: + virtual ~ParseCanvas() { + setBounder(0); + } + + // Pictures parsed for content never want to create offscreen bitmaps. + // Instead, just save and restore the canvas state -- this also keeps + // the picture contents at their original coordinates. + virtual int saveLayer(const SkRect* , const SkPaint* , SaveFlags flags) { + return INHERITED::save(flags); + } +private: + typedef SkCanvas INHERITED; +}; + +} + +#endif + diff --git a/Source/WebKit/android/nav/SelectText.cpp b/Source/WebKit/android/nav/SelectText.cpp new file mode 100644 index 0000000..f8ea799 --- /dev/null +++ b/Source/WebKit/android/nav/SelectText.cpp @@ -0,0 +1,1983 @@ +/* + * 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 "CachedPrefix.h" +#include "BidiResolver.h" +#include "CachedRoot.h" +#include "LayerAndroid.h" +#include "ParseCanvas.h" +#include "SelectText.h" +#include "SkBitmap.h" +#include "SkBounder.h" +#include "SkGradientShader.h" +#include "SkMatrix.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 +#include +#endif + +#define VERBOSE_LOGGING 0 +// #define EXTRA_NOISY_LOGGING 1 + +// TextRunIterator has been copied verbatim from GraphicsContext.cpp +namespace WebCore { + +class TextRunIterator { +public: + TextRunIterator() + : m_textRun(0) + , m_offset(0) + { + } + + TextRunIterator(const TextRun* textRun, unsigned offset) + : m_textRun(textRun) + , m_offset(offset) + { + } + + TextRunIterator(const TextRunIterator& other) + : m_textRun(other.m_textRun) + , m_offset(other.m_offset) + { + } + + unsigned offset() const { return m_offset; } + void increment() { m_offset++; } + bool atEnd() const { return !m_textRun || m_offset >= m_textRun->length(); } + UChar current() const { return (*m_textRun)[m_offset]; } + WTF::Unicode::Direction direction() const { return atEnd() ? WTF::Unicode::OtherNeutral : WTF::Unicode::direction(current()); } + + bool operator==(const TextRunIterator& other) + { + return m_offset == other.m_offset && m_textRun == other.m_textRun; + } + + bool operator!=(const TextRunIterator& other) { return !operator==(other); } + +private: + const TextRun* m_textRun; + int m_offset; +}; + +// ReverseBidi is a trimmed-down version of GraphicsContext::drawBidiText() +void ReverseBidi(UChar* chars, int len) { + using namespace WTF::Unicode; + WTF::Vector result; + result.reserveCapacity(len); + TextRun run(chars, len); + BidiResolver bidiResolver; + bidiResolver.setStatus(BidiStatus(LeftToRight, LeftToRight, LeftToRight, + BidiContext::create(0, LeftToRight, false))); + bidiResolver.setPosition(TextRunIterator(&run, 0)); + bidiResolver.createBidiRunsForLine(TextRunIterator(&run, len)); + if (!bidiResolver.runCount()) + return; + BidiCharacterRun* bidiRun = bidiResolver.firstRun(); + while (bidiRun) { + int bidiStart = bidiRun->start(); + int bidiStop = bidiRun->stop(); + int size = result.size(); + int bidiCount = bidiStop - bidiStart; + result.append(chars + bidiStart, bidiCount); + if (bidiRun->level() % 2) { + UChar* start = &result[size]; + UChar* end = start + bidiCount; + // reverse the order of any RTL substrings + while (start < end) { + UChar temp = *start; + *start++ = *--end; + *end = temp; + } + start = &result[size]; + end = start + bidiCount - 1; + // if the RTL substring had a surrogate pair, restore its order + while (start < end) { + UChar trail = *start++; + if (!U16_IS_SURROGATE(trail)) + continue; + start[-1] = *start; // lead + *start++ = trail; + } + } + bidiRun = bidiRun->next(); + } + bidiResolver.deleteRuns(); + memcpy(chars, &result[0], len * sizeof(UChar)); +} + +} + +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(-1); + mLastCandidate.fGlyphID = static_cast(-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(-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(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 mParagraphs; + SkTDArray 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 sortedBounds; + SkTDArray 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 mSelectBounds; + SkTDArray mSelectEnd; + SkTDArray mSelectStart; + int mSelectStartIndex; + SkTDArray 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(picture)); + bool flipped = builder.flipped(); + if (flipped) { + TextCanvas checker(&builder); + checker.drawPicture(const_cast(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(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(picture)); + return finder.bestBounds(base); +} + +static WTF::String text(const SkPicture& picture, const SkIRect& area, + const SkIRect& start, int startBase, const SkIRect& end, + int endBase, bool flipped) +{ + TextExtractor extractor(start, startBase, end, endBase, area, flipped); + TextCanvas checker(&extractor); + checker.drawPicture(const_cast(picture)); + return extractor.text(); +} + +#define CONTROL_NOTCH 16 +#define CONTROL_HEIGHT 35 +#define CONTROL_WIDTH 21 +#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 + +#define SLOP 35 + +SelectText::SelectText() +{ + 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::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 + canvas->save(); + canvas->translate(m_selStart.fLeft, m_selStart.fBottom); + canvas->drawPicture(m_startControl); + canvas->restore(); + canvas->save(); + canvas->translate(m_selEnd.fRight, m_selEnd.fBottom); + canvas->drawPicture(m_endControl); + canvas->restore(); + 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(picture)); + lineCheck.finish(m_selRegion); + check.setLines(&lineCheck); + TextCanvas checker(&check); + checker.drawPicture(const_cast(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(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, cy); + test.inset(-SLOP, -SLOP); + return test.contains(x, y); +} + +bool SelectText::hitSelection(int x, int y) const +{ + x -= m_startOffset.fX; + y -= m_startOffset.fY; + int left = m_selStart.fLeft - CONTROL_WIDTH / 2; + int top = m_selStart.fBottom + CONTROL_HEIGHT / 2; + if (hitCorner(left, top, x, y)) + return true; + int right = m_selEnd.fRight + CONTROL_WIDTH / 2; + int bottom = m_selEnd.fBottom + CONTROL_HEIGHT / 2; + if (hitCorner(right, bottom, x, y)) + return true; + return m_selRegion.contains(x, y); +} + +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; + } + int left = m_selStart.fLeft - CONTROL_WIDTH / 2; + int top = m_selStart.fBottom + CONTROL_HEIGHT / 2; + m_hitTopLeft = hitCorner(left, top, x, y); + int right = m_selEnd.fRight + CONTROL_WIDTH / 2; + int bottom = m_selEnd.fBottom + CONTROL_HEIGHT / 2; + bool hitBottomRight = hitCorner(right, bottom, 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 && (!hitBottomRight || y - top < bottom - y)) { + 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; +} + +/* selects the word at (x, y) +* a word is normally delimited by spaces +* a string of digits (even with inside spaces) is a word (for phone numbers) +* FIXME: digit find isn't implemented yet +* returns true if a word was selected +*/ +bool SelectText::wordSelection(const CachedRoot* root, const IntRect& vis, + int x, int y) +{ + IntRect tapArea = IntRect(x - TOUCH_SLOP, y - TOUCH_SLOP, TOUCH_SLOP * 2, + TOUCH_SLOP * 2); + if (!startSelection(root, tapArea, x, y)) + return false; + extendSelection(tapArea, x, y); + if (m_selStart.isEmpty()) + return false; + setDrawPointer(false); + setVisibleRect(vis); + SkIRect ivisBounds = m_visibleRect; + ivisBounds.join(m_selStart); + ivisBounds.join(m_selEnd); + DBG_NAV_LOGD("m_selStart=(%d,%d,r=%d,b=%d) m_selEnd=(%d,%d,r=%d,b=%d)" + " ivisBounds=(%d,%d,r=%d,b=%d)", + m_selStart.fLeft, m_selStart.fTop, m_selStart.fRight, m_selStart.fBottom, + m_selEnd.fLeft, m_selEnd.fTop, m_selEnd.fRight, m_selEnd.fBottom, + ivisBounds.fLeft, ivisBounds.fTop, ivisBounds.fRight, ivisBounds.fBottom); + m_selRegion.setEmpty(); + buildSelection(*m_picture, ivisBounds, m_selStart, m_startBase, + m_selEnd, m_endBase, &m_selRegion); + x = m_selStart.fLeft; + y = (m_selStart.fTop + m_selStart.fBottom) >> 1; + SkIRect clipRect = m_visibleRect; + clipRect.fLeft -= m_visibleRect.width() >> 1; + clipRect.fLeft = std::max(clipRect.fLeft, 0); + int base; + SkIRect left = findLeft(*m_picture, clipRect, x, y, &base); + if (!left.isEmpty()) { + m_startBase = base; + m_selStart = left; + } + x = m_selEnd.fRight; + y = (m_selEnd.fTop + m_selEnd.fBottom) >> 1; + clipRect = m_visibleRect; + clipRect.fRight += m_visibleRect.width() >> 1; + SkIRect right = findRight(*m_picture, clipRect, x, y, &base); + if (!right.isEmpty()) { + m_endBase = base; + m_selEnd = right; + } + DBG_NAV_LOGD("m_selStart=(%d, %d, %d, %d) m_selEnd=(%d, %d, %d, %d)", + m_selStart.fLeft, m_selStart.fTop, m_selStart.fRight, m_selStart.fBottom, + m_selEnd.fLeft, m_selEnd.fTop, m_selEnd.fRight, m_selEnd.fBottom); + if (!left.isEmpty() || !right.isEmpty()) { + m_wordBounds = m_selStart; + m_wordBounds.join(m_selEnd); + m_extendSelection = m_wordSelection = true; + m_outsideWord = false; + return true; + } + return false; +} + +void SelectText::swapAsNeeded() +{ + if (m_selStart.fTop >= (m_selEnd.fTop + m_selEnd.fBottom) >> 1 + || (m_selEnd.fTop < (m_selStart.fTop + m_selStart.fBottom) >> 1 + && m_selStart.fRight > m_selEnd.fLeft)) + { + SkTSwap(m_startBase, m_endBase); + SkTSwap(m_selStart, m_selEnd); + m_hitTopLeft ^= true; + DBG_NAV_LOGD("m_hitTopLeft=%s", m_hitTopLeft ? "true" : "false"); + } +} + +} diff --git a/Source/WebKit/android/nav/SelectText.h b/Source/WebKit/android/nav/SelectText.h new file mode 100644 index 0000000..42239cf --- /dev/null +++ b/Source/WebKit/android/nav/SelectText.h @@ -0,0 +1,116 @@ +/* + * 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 SELECT_TEXT_H +#define SELECT_TEXT_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); +public: + float m_inverseScale; // inverse scale, x, y used for drawing select path + int m_selectX; + int m_selectY; +private: + 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; + 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; +}; + +} + +namespace WebCore { + +void ReverseBidi(UChar* chars, int len); + +} + +#endif diff --git a/Source/WebKit/android/nav/WebView.cpp b/Source/WebKit/android/nav/WebView.cpp new file mode 100644 index 0000000..ff5d73d --- /dev/null +++ b/Source/WebKit/android/nav/WebView.cpp @@ -0,0 +1,2673 @@ +/* + * 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. + */ + +#define LOG_TAG "webviewglue" + +#include "config.h" + +#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" +#include "IntPoint.h" +#include "IntRect.h" +#include "LayerAndroid.h" +#include "Node.h" +#include "utils/Functor.h" +#include "private/hwui/DrawGlInfo.h" +#include "PlatformGraphicsContext.h" +#include "PlatformString.h" +#include "ScrollableLayerAndroid.h" +#include "SelectText.h" +#include "SkCanvas.h" +#include "SkDumpCanvas.h" +#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" +#include "WebViewCore.h" +#include "android_graphics.h" + +#ifdef GET_NATIVE_VIEW +#undef GET_NATIVE_VIEW +#endif + +#define GET_NATIVE_VIEW(env, obj) ((WebView*)env->GetIntField(obj, gWebViewField)) + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace android { + +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); + return m; +} + +//------------------------------------- +// This class provides JNI for making calls into native code from the UI side +// of the multi-threaded WebView. +class WebView +{ +public: +enum FrameCachePermission { + DontAllowNewer, + AllowNewer, + AllowNewest +}; + +enum DrawExtras { // keep this in sync with WebView.java + DrawExtrasNone = 0, + DrawExtrasFind = 1, + DrawExtrasSelection = 2, + DrawExtrasCursorRing = 3 +}; + +struct JavaGlue { + jweak m_obj; + jmethodID m_calcOurContentVisibleRectF; + jmethodID m_overrideLoading; + jmethodID m_scrollBy; + jmethodID m_sendMoveFocus; + jmethodID m_sendMoveMouse; + jmethodID m_sendMoveMouseIfLatest; + jmethodID m_sendMotionUp; + jmethodID m_domChangedFocus; + jmethodID m_getScaledMaxXScroll; + jmethodID m_getScaledMaxYScroll; + jmethodID m_getVisibleRect; + jmethodID m_rebuildWebTextView; + jmethodID m_viewInvalidate; + jmethodID m_viewInvalidateRect; + jmethodID m_postInvalidateDelayed; + jmethodID m_inFullScreenMode; + jfieldID m_rectLeft; + jfieldID m_rectTop; + jmethodID m_rectWidth; + jmethodID m_rectHeight; + jfieldID m_rectFLeft; + jfieldID m_rectFTop; + jmethodID m_rectFWidth; + jmethodID m_rectFHeight; + AutoJObject object(JNIEnv* env) { + return getRealObject(env, m_obj); + } +} m_javaGlue; + +WebView(JNIEnv* env, jobject javaWebView, int viewImpl, WTF::String drawableDir, AssetManager* am) : + m_ring((WebViewCore*) viewImpl) +{ + jclass clazz = env->FindClass("android/webkit/WebView"); + // m_javaGlue = new JavaGlue; + m_javaGlue.m_obj = env->NewWeakGlobalRef(javaWebView); + m_javaGlue.m_scrollBy = GetJMethod(env, clazz, "setContentScrollBy", "(IIZ)Z"); + m_javaGlue.m_calcOurContentVisibleRectF = GetJMethod(env, clazz, "calcOurContentVisibleRectF", "(Landroid/graphics/RectF;)V"); + m_javaGlue.m_overrideLoading = GetJMethod(env, clazz, "overrideLoading", "(Ljava/lang/String;)V"); + m_javaGlue.m_sendMoveFocus = GetJMethod(env, clazz, "sendMoveFocus", "(II)V"); + m_javaGlue.m_sendMoveMouse = GetJMethod(env, clazz, "sendMoveMouse", "(IIII)V"); + m_javaGlue.m_sendMoveMouseIfLatest = GetJMethod(env, clazz, "sendMoveMouseIfLatest", "(ZZ)V"); + m_javaGlue.m_sendMotionUp = GetJMethod(env, clazz, "sendMotionUp", "(IIIII)V"); + m_javaGlue.m_domChangedFocus = GetJMethod(env, clazz, "domChangedFocus", "()V"); + m_javaGlue.m_getScaledMaxXScroll = GetJMethod(env, clazz, "getScaledMaxXScroll", "()I"); + m_javaGlue.m_getScaledMaxYScroll = GetJMethod(env, clazz, "getScaledMaxYScroll", "()I"); + m_javaGlue.m_getVisibleRect = GetJMethod(env, clazz, "sendOurVisibleRect", "()Landroid/graphics/Rect;"); + m_javaGlue.m_rebuildWebTextView = GetJMethod(env, clazz, "rebuildWebTextView", "()V"); + m_javaGlue.m_viewInvalidate = GetJMethod(env, clazz, "viewInvalidate", "()V"); + m_javaGlue.m_viewInvalidateRect = GetJMethod(env, clazz, "viewInvalidate", "(IIII)V"); + m_javaGlue.m_postInvalidateDelayed = GetJMethod(env, clazz, + "viewInvalidateDelayed", "(JIIII)V"); + m_javaGlue.m_inFullScreenMode = GetJMethod(env, clazz, "inFullScreenMode", "()Z"); + env->DeleteLocalRef(clazz); + + jclass rectClass = env->FindClass("android/graphics/Rect"); + LOG_ASSERT(rectClass, "Could not find Rect class"); + m_javaGlue.m_rectLeft = env->GetFieldID(rectClass, "left", "I"); + m_javaGlue.m_rectTop = env->GetFieldID(rectClass, "top", "I"); + m_javaGlue.m_rectWidth = GetJMethod(env, rectClass, "width", "()I"); + m_javaGlue.m_rectHeight = GetJMethod(env, rectClass, "height", "()I"); + env->DeleteLocalRef(rectClass); + + jclass rectClassF = env->FindClass("android/graphics/RectF"); + LOG_ASSERT(rectClassF, "Could not find RectF class"); + m_javaGlue.m_rectFLeft = env->GetFieldID(rectClassF, "left", "F"); + m_javaGlue.m_rectFTop = env->GetFieldID(rectClassF, "top", "F"); + m_javaGlue.m_rectFWidth = GetJMethod(env, rectClassF, "width", "()F"); + m_javaGlue.m_rectFHeight = GetJMethod(env, rectClassF, "height", "()F"); + env->DeleteLocalRef(rectClassF); + + 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; + if (drawableDir.isEmpty()) + m_buttonSkin = 0; + else + m_buttonSkin = new RenderSkinButton(am, drawableDir); +#if USE(ACCELERATED_COMPOSITING) + m_glWebViewState = 0; +#endif +} + +~WebView() +{ + if (m_javaGlue.m_obj) + { + JNIEnv* env = JSC::Bindings::getJNIEnv(); + env->DeleteWeakGlobalRef(m_javaGlue.m_obj); + m_javaGlue.m_obj = 0; + } +#if USE(ACCELERATED_COMPOSITING) + // We must remove the m_glWebViewState prior to deleting m_baseLayer. If we + // do not remove it here, we risk having BaseTiles trying to paint using a + // deallocated base layer. + stopGL(); +#endif + delete m_frameCacheUI; + delete m_navPictureUI; + SkSafeUnref(m_baseLayer); + delete m_glDrawFunctor; + delete m_buttonSkin; +} + +void stopGL() +{ +#if USE(ACCELERATED_COMPOSITING) + delete m_glWebViewState; + m_glWebViewState = 0; +#endif +} + +WebViewCore* getWebViewCore() const { + return m_viewImpl; +} + +// 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); +} + +void hideCursor(CachedRoot* root) +{ + DBG_NAV_LOG("inner"); + m_viewImpl->m_hasCursorBounds = false; + root->hideCursor(); + viewInvalidate(); +} + +#if DUMP_NAV_CACHE +void debugDump() +{ + CachedRoot* root = getFrameCache(DontAllowNewer); + if (root) + root->mDebug.print(); +} +#endif + +// Traverse our stored array of buttons that are in our picture, and update +// their subpictures according to their current state. +// Called from the UI thread. This is the one place in the UI thread where we +// access the buttons stored in the WebCore thread. +// hasFocus keeps track of whether the WebView has focus && windowFocus. +// If not, we do not want to draw the button in a selected or pressed state +void nativeRecordButtons(bool hasFocus, bool pressed, bool invalidate) +{ + bool cursorIsOnButton = false; + const CachedFrame* cachedFrame; + const CachedNode* cachedCursor = 0; + // Lock the mutex, since we now share with the WebCore thread. + m_viewImpl->gButtonMutex.lock(); + if (m_viewImpl->m_buttons.size() && m_buttonSkin) { + // FIXME: In a future change, we should keep track of whether the selection + // has changed to short circuit (note that we would still need to update + // if we received new buttons from the WebCore thread). + WebCore::Node* cursor = 0; + CachedRoot* root = getFrameCache(DontAllowNewer); + if (root) { + cachedCursor = root->currentCursor(&cachedFrame); + if (cachedCursor) + cursor = (WebCore::Node*) cachedCursor->nodePointer(); + } + + // Traverse the array, and update each button, depending on whether it + // is selected. + Container* end = m_viewImpl->m_buttons.end(); + for (Container* ptr = m_viewImpl->m_buttons.begin(); ptr != end; ptr++) { + RenderSkinAndroid::State state = RenderSkinAndroid::kNormal; + if (ptr->matches(cursor)) { + cursorIsOnButton = true; + // If the WebView is out of focus/window focus, set the state to + // normal, but still keep track of the fact that the selected is a + // button + if (hasFocus) { + if (pressed || m_ring.m_isPressed) + state = RenderSkinAndroid::kPressed; + else if (SkTime::GetMSecs() < m_ringAnimationEnd) + state = RenderSkinAndroid::kFocused; + } + } + ptr->updateFocusState(state, m_buttonSkin); + } + } + m_viewImpl->gButtonMutex.unlock(); + if (invalidate && cachedCursor && cursorIsOnButton) { + const WebCore::IntRect& b = cachedCursor->bounds(cachedFrame); + viewInvalidateRect(b.x(), b.y(), b.right(), b.bottom()); + } +} + +// The caller has already determined that the desired document rect corresponds +// to the main picture, and not a layer +void scrollRectOnScreen(const IntRect& rect) +{ + if (rect.isEmpty()) + return; + SkRect visible; + calcOurContentVisibleRect(&visible); + int dx = 0; + int left = rect.x(); + int right = rect.right(); + if (left < visible.fLeft) { + dx = left - visible.fLeft; + // Only scroll right if the entire width can fit on screen. + } else if (right > visible.fRight && right - left < visible.width()) { + dx = right - visible.fRight; + } + int dy = 0; + int top = rect.y(); + int bottom = rect.bottom(); + if (top < visible.fTop) { + dy = top - visible.fTop; + // Only scroll down if the entire height can fit on screen + } else if (bottom > visible.fBottom && bottom - top < visible.height()) { + dy = bottom - visible.fBottom; + } + if ((dx|dy) == 0 || !scrollBy(dx, dy)) + return; + viewInvalidate(); +} + +void calcOurContentVisibleRect(SkRect* r) +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + jclass rectClass = env->FindClass("android/graphics/RectF"); + jmethodID init = env->GetMethodID(rectClass, "", "(FFFF)V"); + jobject jRect = env->NewObject(rectClass, init, 0, 0, 0, 0); + env->CallVoidMethod(m_javaGlue.object(env).get(), + m_javaGlue.m_calcOurContentVisibleRectF, jRect); + r->fLeft = env->GetFloatField(jRect, m_javaGlue.m_rectFLeft); + r->fTop = env->GetFloatField(jRect, m_javaGlue.m_rectFTop); + r->fRight = r->fLeft + env->CallFloatMethod(jRect, m_javaGlue.m_rectFWidth); + r->fBottom = r->fTop + env->CallFloatMethod(jRect, m_javaGlue.m_rectFHeight); + env->DeleteLocalRef(rectClass); + env->DeleteLocalRef(jRect); + checkException(env); +} + +void resetCursorRing() +{ + m_ringAnimationEnd = 0; + m_viewImpl->m_hasCursorBounds = false; +} + +bool drawCursorPreamble(CachedRoot* root) +{ + 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 = const_cast(root->rootLayer()); + SkRect visible; + calcOurContentVisibleRect(&visible); + layer->updateFixedLayersPositions(visible); + 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(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()) + return false; + + if (!m_glWebViewState) { + m_glWebViewState = new GLWebViewState(&m_viewImpl->gButtonMutex); + 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, false); + } + } + + CachedRoot* root = getFrameCache(AllowNewer); + if (!root) { + DBG_NAV_LOG("!root"); + if (extras == DrawExtrasCursorRing) + resetCursorRing(); + return false; + } + DrawExtra* extra = 0; + switch (extras) { + case DrawExtrasFind: + extra = &m_findOnPage; + break; + case DrawExtrasSelection: + extra = &m_selectText; + break; + case DrawExtrasCursorRing: + if (drawCursorPreamble(root) && m_ring.setup()) { + if (!m_ring.m_isButton) + extra = &m_ring; + drawCursorPostamble(); + } + break; + default: + ; + } + + unsigned int pic = m_glWebViewState->currentPictureCounter(); + + SkPicture picture; + IntRect rect(0, 0, 0, 0); + bool allowSame = false; + m_glWebViewState->resetRings(); + if (extra) { + if (extra == &m_ring) { + m_glWebViewState->setRings(m_ring.rings(), m_ring.m_isPressed); + } else { + LayerAndroid mainPicture(m_navPictureUI); + PictureSet* content = m_baseLayer->content(); + SkCanvas* canvas = picture.beginRecording(content->width(), + content->height()); + extra->draw(canvas, &mainPicture, &rect); + picture.endRecording(); + } + } else if (extras == DrawExtrasCursorRing && m_ring.m_isButton) { + const CachedFrame* cachedFrame; + const CachedNode* cachedCursor = root->currentCursor(&cachedFrame); + if (cachedCursor) { + rect = cachedCursor->bounds(cachedFrame); + allowSame = true; + } + } + m_glWebViewState->setExtra(m_baseLayer, picture, rect, allowSame); + + LayerAndroid* compositeLayer = compositeRoot(); + if (compositeLayer) + compositeLayer->setExtra(extra); + + SkRect visibleRect; + calcOurContentVisibleRect(&visibleRect); + bool ret = m_glWebViewState->drawGL(viewRect, visibleRect, invalRect, + webViewRect, titleBarHeight, clip, scale); + if (ret || m_glWebViewState->currentPictureCounter() != pic) + return true; +#endif + return false; +} + +PictureSet* draw(SkCanvas* canvas, SkColor bgColor, int extras, bool split) +{ + PictureSet* ret = 0; + if (!m_baseLayer) { + canvas->drawColor(bgColor); + return ret; + } + + // draw the content of the base layer first + PictureSet* content = m_baseLayer->content(); + int sc = canvas->save(SkCanvas::kClip_SaveFlag); + canvas->clipRect(SkRect::MakeLTRB(0, 0, content->width(), + content->height()), SkRegion::kDifference_Op); + canvas->drawColor(bgColor); + canvas->restoreToCount(sc); + if (content->draw(canvas)) + ret = split ? new PictureSet(*content) : 0; + + CachedRoot* root = getFrameCache(AllowNewer); + if (!root) { + DBG_NAV_LOG("!root"); + if (extras == DrawExtrasCursorRing) + resetCursorRing(); + return ret; + } + LayerAndroid mainPicture(m_navPictureUI); + DrawExtra* extra = 0; + switch (extras) { + case DrawExtrasFind: + extra = &m_findOnPage; + break; + case DrawExtrasSelection: + extra = &m_selectText; + break; + case DrawExtrasCursorRing: + if (drawCursorPreamble(root) && m_ring.setup()) { + if (!m_ring.m_isButton) + extra = &m_ring; + drawCursorPostamble(); + } + break; + default: + ; + } + if (extra) { + IntRect dummy; // inval area, unused for now + extra->draw(canvas, &mainPicture, &dummy); + } +#if USE(ACCELERATED_COMPOSITING) + LayerAndroid* compositeLayer = compositeRoot(); + if (!compositeLayer) + return ret; + compositeLayer->setExtra(extra); + SkRect visible; + calcOurContentVisibleRect(&visible); + // call this to be sure we've adjusted for any scrolling or animations + // before we actually draw + compositeLayer->updateFixedLayersPositions(visible); + compositeLayer->updatePositions(); + // We have to set the canvas' matrix on the base layer + // (to have fixed layers work as intended) + SkAutoCanvasRestore restore(canvas, true); + m_baseLayer->setMatrix(canvas->getTotalMatrix()); + canvas->resetMatrix(); + m_baseLayer->draw(canvas); +#endif + 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.right() - newBounds.right()) > 4) + return; + if (abs(bounds.bottom() - newBounds.bottom()) > 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(frame), + const_cast(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) { + SkRect visible; + calcOurContentVisibleRect(&visible); + LayerAndroid* layer = const_cast( + m_frameCacheUI->rootLayer()); + if (layer) { + layer->updateFixedLayersPositions(visible); + layer->updatePositions(); + } + } +#endif + fixCursor(); + if (oldFocusIsTextInput) { + const CachedNode* newFocus = m_frameCacheUI->currentFocus(); + if (newFocus && oldFocusNodePointer != newFocus->nodePointer() + && newFocus->isTextInput() + && newFocus != m_frameCacheUI->currentCursor()) { + // The focus has changed. We may need to update things. + LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); + JNIEnv* env = JSC::Bindings::getJNIEnv(); + env->CallVoidMethod(m_javaGlue.object(env).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; +} + +int getScaledMaxXScroll() +{ + LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); + JNIEnv* env = JSC::Bindings::getJNIEnv(); + int result = env->CallIntMethod(m_javaGlue.object(env).get(), m_javaGlue.m_getScaledMaxXScroll); + checkException(env); + return result; +} + +int getScaledMaxYScroll() +{ + LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); + JNIEnv* env = JSC::Bindings::getJNIEnv(); + int result = env->CallIntMethod(m_javaGlue.object(env).get(), m_javaGlue.m_getScaledMaxYScroll); + checkException(env); + return result; +} + +IntRect getVisibleRect() +{ + IntRect rect; + LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); + JNIEnv* env = JSC::Bindings::getJNIEnv(); + jobject jRect = env->CallObjectMethod(m_javaGlue.object(env).get(), m_javaGlue.m_getVisibleRect); + checkException(env); + rect.setX(env->GetIntField(jRect, m_javaGlue.m_rectLeft)); + checkException(env); + rect.setY(env->GetIntField(jRect, m_javaGlue.m_rectTop)); + checkException(env); + rect.setWidth(env->CallIntMethod(jRect, m_javaGlue.m_rectWidth)); + checkException(env); + rect.setHeight(env->CallIntMethod(jRect, m_javaGlue.m_rectHeight)); + checkException(env); + env->DeleteLocalRef(jRect); + checkException(env); + return rect; +} + +static CachedFrame::Direction KeyToDirection(int32_t keyCode) +{ + switch (keyCode) { + case AKEYCODE_DPAD_RIGHT: + DBG_NAV_LOGD("keyCode=%s", "right"); + return CachedFrame::RIGHT; + case AKEYCODE_DPAD_LEFT: + DBG_NAV_LOGD("keyCode=%s", "left"); + return CachedFrame::LEFT; + case AKEYCODE_DPAD_DOWN: + DBG_NAV_LOGD("keyCode=%s", "down"); + return CachedFrame::DOWN; + case AKEYCODE_DPAD_UP: + DBG_NAV_LOGD("keyCode=%s", "up"); + return CachedFrame::UP; + default: + DBG_NAV_LOGD("bad key %d sent", keyCode); + return CachedFrame::UNINITIALIZED; + } +} + +WTF::String imageURI(int x, int y) +{ + const CachedRoot* root = getFrameCache(DontAllowNewer); + return root ? root->imageURI(x, y) : WTF::String(); +} + +bool cursorWantsKeyEvents() +{ + const CachedRoot* root = getFrameCache(DontAllowNewer); + if (root) { + const CachedNode* focus = root->currentCursor(); + if (focus) + return focus->wantsKeyEvents(); + } + return false; +} + + +/* returns true if the key had no effect (neither scrolled nor changed cursor) */ +bool moveCursor(int keyCode, int count, bool ignoreScroll) +{ + CachedRoot* root = getFrameCache(AllowNewer); + if (!root) { + DBG_NAV_LOG("!root"); + return true; + } + + m_viewImpl->m_moveGeneration++; + CachedFrame::Direction direction = KeyToDirection(keyCode); + const CachedFrame* cachedFrame, * oldFrame = 0; + const CachedNode* cursor = root->currentCursor(&oldFrame); + WebCore::IntPoint cursorLocation = root->cursorLocation(); + DBG_NAV_LOGD("old cursor %d (nativeNode=%p) cursorLocation={%d, %d}", + cursor ? cursor->index() : 0, + cursor ? cursor->nodePointer() : 0, cursorLocation.x(), cursorLocation.y()); + WebCore::IntRect visibleRect = setVisibleRect(root); + int xMax = getScaledMaxXScroll(); + int yMax = getScaledMaxYScroll(); + root->setMaxScroll(xMax, yMax); + const CachedNode* cachedNode = 0; + int dx = 0; + int dy = 0; + int counter = count; + while (--counter >= 0) { + WebCore::IntPoint scroll = WebCore::IntPoint(0, 0); + cachedNode = root->moveCursor(direction, &cachedFrame, &scroll); + dx += scroll.x(); + dy += scroll.y(); + } + DBG_NAV_LOGD("new cursor %d (nativeNode=%p) cursorLocation={%d, %d}" + "bounds={%d,%d,w=%d,h=%d}", cachedNode ? cachedNode->index() : 0, + cachedNode ? cachedNode->nodePointer() : 0, + root->cursorLocation().x(), root->cursorLocation().y(), + cachedNode ? cachedNode->bounds(cachedFrame).x() : 0, + cachedNode ? cachedNode->bounds(cachedFrame).y() : 0, + cachedNode ? cachedNode->bounds(cachedFrame).width() : 0, + cachedNode ? cachedNode->bounds(cachedFrame).height() : 0); + // If !m_heightCanMeasure (such as in the browser), we want to scroll no + // matter what + if (!ignoreScroll && (!m_heightCanMeasure || + !cachedNode || + (cursor && cursor->nodePointer() == cachedNode->nodePointer()))) + { + if (count == 1 && dx != 0 && dy == 0 && -m_lastDx == dx && + SkTime::GetMSecs() - m_lastDxTime < 1000) + root->checkForJiggle(&dx); + DBG_NAV_LOGD("scrollBy %d,%d", dx, dy); + if ((dx | dy)) + this->scrollBy(dx, dy); + m_lastDx = dx; + m_lastDxTime = SkTime::GetMSecs(); + } + bool result = false; + if (cachedNode) { + showCursorUntimed(); + m_viewImpl->updateCursorBounds(root, cachedFrame, cachedNode); + root->setCursor(const_cast(cachedFrame), + const_cast(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.bottom() + dy > docHeight) + dy = docHeight - visibleRect.bottom(); + else if (visibleRect.y() + dy < 0) + dy = -visibleRect.y(); + if (visibleRect.right() + dx > docWidth) + dx = docWidth - visibleRect.right(); + 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(frame), + const_cast(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(frame), + const_cast(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) +static const ScrollableLayerAndroid* findScrollableLayer( + const LayerAndroid* parent, int x, int y, SkIRect* foundBounds) { + SkRect bounds; + parent->bounds(&bounds); + // Check the parent bounds first; this will clip to within a masking layer's + // bounds. + if (parent->masksToBounds() && !bounds.contains(x, y)) + return 0; + // Move the hit test local to parent. + x -= bounds.fLeft; + y -= bounds.fTop; + int count = parent->countChildren(); + while (count--) { + const LayerAndroid* child = parent->getChild(count); + const ScrollableLayerAndroid* result = findScrollableLayer(child, x, y, + foundBounds); + if (result) { + foundBounds->offset(bounds.fLeft, bounds.fTop); + if (parent->masksToBounds()) { + if (bounds.width() < foundBounds->width()) + foundBounds->fRight = foundBounds->fLeft + bounds.width(); + if (bounds.height() < foundBounds->height()) + foundBounds->fBottom = foundBounds->fTop + bounds.height(); + } + return result; + } + } + if (parent->contentIsScrollable()) { + foundBounds->set(0, 0, bounds.width(), bounds.height()); + return static_cast(parent); + } + return 0; +} +#endif + +int scrollableLayer(int x, int y, SkIRect* layerRect, SkIRect* bounds) +{ +#if USE(ACCELERATED_COMPOSITING) + const LayerAndroid* layerRoot = compositeRoot(); + if (!layerRoot) + return 0; + const ScrollableLayerAndroid* result = findScrollableLayer(layerRoot, x, y, + bounds); + if (result) { + result->getScrollRect(layerRect); + return result->uniqueId(); + } +#endif + return 0; +} + +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(); + jstring jName = wtfStringToJstring(env, url); + env->CallVoidMethod(m_javaGlue.object(env).get(), + m_javaGlue.m_overrideLoading, jName); + env->DeleteLocalRef(jName); +} + +void setFindIsUp(bool up) +{ + DBG_NAV_LOGD("up=%d", up); + m_viewImpl->m_findIsUp = up; +} + +void setFindIsEmpty() +{ + DBG_NAV_LOG(""); + m_findOnPage.clearCurrentLocation(); +} + +void showCursorTimed() +{ + DBG_NAV_LOG(""); + m_ringAnimationEnd = SkTime::GetMSecs() + 500; + viewInvalidate(); +} + +void showCursorUntimed() +{ + DBG_NAV_LOG(""); + m_ring.m_isPressed = false; + m_ringAnimationEnd = UINT_MAX; + viewInvalidate(); +} + +void setHeightCanMeasure(bool measure) +{ + m_heightCanMeasure = 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; + return m_selectText.startSelection(root, getVisibleRect(), x, y); +} + +bool wordSelection(int x, int y) +{ + const CachedRoot* root = getFrameCache(DontAllowNewer); + if (!root) + return false; + 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) +{ + return m_selectText.hitSelection(x, y); +} + +void setExtendSelection() +{ + m_selectText.setExtendSelection(true); +} + +void setSelectionPointer(bool set, float scale, int x, int y) +{ + m_selectText.setDrawPointer(set); + if (!set) + return; + m_selectText.m_inverseScale = scale; + m_selectText.m_selectX = x; + m_selectText.m_selectY = y; +} + +void sendMoveFocus(WebCore::Frame* framePtr, WebCore::Node* nodePtr) +{ + DBG_NAV_LOGD("framePtr=%p nodePtr=%p", framePtr, nodePtr); + JNIEnv* env = JSC::Bindings::getJNIEnv(); + env->CallVoidMethod(m_javaGlue.object(env).get(), + m_javaGlue.m_sendMoveFocus, (jint) framePtr, (jint) nodePtr); + checkException(env); +} + +void sendMoveMouse(WebCore::Frame* framePtr, WebCore::Node* nodePtr, int x, int y) +{ + DBG_NAV_LOGD("framePtr=%p nodePtr=%p x=%d y=%d", framePtr, nodePtr, x, y); + JNIEnv* env = JSC::Bindings::getJNIEnv(); + env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_sendMoveMouse, + (jint) framePtr, (jint) nodePtr, x, y); + checkException(env); +} + +void sendMoveMouseIfLatest(bool clearTextEntry, bool stopPaintingCaret) +{ + LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); + JNIEnv* env = JSC::Bindings::getJNIEnv(); + env->CallVoidMethod(m_javaGlue.object(env).get(), + m_javaGlue.m_sendMoveMouseIfLatest, clearTextEntry, stopPaintingCaret); + checkException(env); +} + +void sendMotionUp( + WebCore::Frame* framePtr, WebCore::Node* nodePtr, int x, int y) +{ + m_viewImpl->m_touchGeneration = ++m_generation; + DBG_NAV_LOGD("m_generation=%d framePtr=%p nodePtr=%p x=%d y=%d", + m_generation, framePtr, nodePtr, x, y); + LOG_ASSERT(m_javaGlue.m_obj, "A WebView was not associated with this WebViewNative!"); + JNIEnv* env = JSC::Bindings::getJNIEnv(); + env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_sendMotionUp, + m_generation, (jint) framePtr, (jint) nodePtr, x, y); + checkException(env); +} + +void findNext(bool forward) +{ + m_findOnPage.findNext(forward); + if (!m_findOnPage.currentMatchIsInLayer()) + scrollRectOnScreen(m_findOnPage.currentMatchBounds()); + viewInvalidate(); +} + +// With this call, WebView takes ownership of matches, and is responsible for +// deleting it. +void setMatches(WTF::Vector* 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; + if (sameAsLastSearch && m_findOnPage.isCurrentLocationValid()) { + oldLocation = m_findOnPage.currentMatchBounds(); + checkAgainstOldLocation = true; + } else + checkAgainstOldLocation = false; + + m_findOnPage.setMatches(matches); + + if (!checkAgainstOldLocation + || oldLocation != m_findOnPage.currentMatchBounds()) { + // FIXME: Need to scroll if the match is in a layer. + if (!m_findOnPage.currentMatchIsInLayer()) + scrollRectOnScreen(m_findOnPage.currentMatchBounds()); + } + 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!"); + + JNIEnv* env = JSC::Bindings::getJNIEnv(); + bool result = env->CallBooleanMethod(m_javaGlue.object(env).get(), + m_javaGlue.m_scrollBy, dx, dy, true); + checkException(env); + return result; +} + +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(); + env->CallVoidMethod(m_javaGlue.object(env).get(), + m_javaGlue.m_rebuildWebTextView); + checkException(env); +} + +void viewInvalidate() +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_viewInvalidate); + checkException(env); +} + +void viewInvalidateRect(int l, int t, int r, int b) +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_viewInvalidateRect, l, r, t, b); + checkException(env); +} + +void postInvalidateDelayed(int64_t delay, const WebCore::IntRect& bounds) +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_postInvalidateDelayed, + delay, bounds.x(), bounds.y(), bounds.right(), bounds.bottom()); + checkException(env); +} + +bool inFullScreenMode() +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + jboolean result = env->CallBooleanMethod(m_javaGlue.object(env).get(), + m_javaGlue.m_inFullScreenMode); + checkException(env); + return result; +} + +int moveGeneration() +{ + return m_viewImpl->m_moveGeneration; +} + +LayerAndroid* compositeRoot() const +{ + LOG_ASSERT(!m_baseLayer || m_baseLayer->countChildren() == 1, + "base layer can't have more than one child %s", __FUNCTION__); + if (m_baseLayer && m_baseLayer->countChildren() == 1) + return static_cast(m_baseLayer->getChild(0)); + else + return 0; +} + +#if ENABLE(ANDROID_OVERFLOW_SCROLL) +static void copyScrollPositionRecursive(const LayerAndroid* from, + LayerAndroid* root) +{ + if (!from || !root) + return; + for (int i = 0; i < from->countChildren(); i++) { + const LayerAndroid* l = from->getChild(i); + if (l->contentIsScrollable()) { + const SkPoint& pos = l->getPosition(); + LayerAndroid* match = root->findById(l->uniqueId()); + if (match && match->contentIsScrollable()) + match->setPosition(pos.fX, pos.fY); + } + copyScrollPositionRecursive(l, root); + } +} +#endif + +void setBaseLayer(BaseLayerAndroid* layer, SkRegion& inval, bool showVisualIndicator, + bool isPictureAfterFirstLayout) +{ +#if USE(ACCELERATED_COMPOSITING) + if (m_glWebViewState) + m_glWebViewState->setBaseLayer(layer, inval, showVisualIndicator, + isPictureAfterFirstLayout); +#endif + +#if ENABLE(ANDROID_OVERFLOW_SCROLL) + if (layer) { + LayerAndroid* newCompositeRoot = static_cast(layer->getChild(0)); + copyScrollPositionRecursive(compositeRoot(), newCompositeRoot); + } +#endif + SkSafeUnref(m_baseLayer); + m_baseLayer = layer; + CachedRoot* root = getFrameCache(DontAllowNewer); + if (!root) + return; + root->resetLayers(); + root->setRootLayer(compositeRoot()); +} + +void replaceBaseContent(PictureSet* set) +{ + if (!m_baseLayer) + return; + m_baseLayer->setContent(*set); + delete set; +} + +void copyBaseContentToPicture(SkPicture* picture) +{ + if (!m_baseLayer) + return; + PictureSet* content = m_baseLayer->content(); + m_baseLayer->drawCanvas(picture->beginRecording(content->width(), content->height(), + SkPicture::kUsePathBoundsForClip_RecordingFlag)); + picture->endRecording(); +} + +bool hasContent() { + if (!m_baseLayer) + return false; + return !m_baseLayer->content()->isEmpty(); +} + +void setFunctor(Functor* functor) { + delete m_glDrawFunctor; + m_glDrawFunctor = functor; +} + +Functor* getFunctor() { + return m_glDrawFunctor; +} + +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; + BaseLayerAndroid* m_baseLayer; + Functor* m_glDrawFunctor; +#if USE(ACCELERATED_COMPOSITING) + GLWebViewState* m_glWebViewState; +#endif + const RenderSkinButton* m_buttonSkin; +}; // end of WebView class + + +/** + * This class holds a function pointer and parameters for calling drawGL into a specific + * viewport. The pointer to the Functor will be put on a framework display list to be called + * when the display list is replayed. + */ +class GLDrawFunctor : Functor { + public: + GLDrawFunctor(WebView* _wvInstance, + bool(WebView::*_funcPtr)(WebCore::IntRect&, WebCore::IntRect*, WebCore::IntRect&, int, WebCore::IntRect&, jfloat, jint), + WebCore::IntRect _viewRect, float _scale, int _extras) { + wvInstance = _wvInstance; + funcPtr = _funcPtr; + viewRect = _viewRect; + scale = _scale; + extras = _extras; + }; + status_t operator()(int messageId, void* data) { + if (viewRect.isEmpty()) { + // NOOP operation if viewport is empty + return 0; + } + + WebCore::IntRect inval; + int titlebarHeight = webViewRect.height() - viewRect.height(); + + uirenderer::DrawGlInfo* info = reinterpret_cast(data); + WebCore::IntRect localViewRect = viewRect; + if (info->isLayer) + localViewRect.move(-1 * localViewRect.x(), -1 * localViewRect.y()); + + WebCore::IntRect clip(info->clipLeft, info->clipTop, + info->clipRight - info->clipLeft, + info->clipBottom - info->clipTop); + + bool retVal = (*wvInstance.*funcPtr)(localViewRect, &inval, webViewRect, titlebarHeight, clip, scale, extras); + if (retVal) { + IntRect finalInval; + if (inval.isEmpty()) { + finalInval = webViewRect; + retVal = true; + } else { + finalInval.setX(webViewRect.x() + inval.x()); + finalInval.setY(webViewRect.y() + titlebarHeight + inval.y()); + finalInval.setWidth(inval.width()); + finalInval.setHeight(inval.height()); + } + info->dirtyLeft = finalInval.x(); + info->dirtyTop = finalInval.y(); + info->dirtyRight = finalInval.right(); + info->dirtyBottom = finalInval.bottom(); + } + // return 1 if invalidation needed, 0 otherwise + return retVal ? 1 : 0; + } + void updateRect(WebCore::IntRect& _viewRect) { + viewRect = _viewRect; + } + void updateViewRect(WebCore::IntRect& _viewRect) { + webViewRect = _viewRect; + } + private: + WebView* wvInstance; + bool (WebView::*funcPtr)(WebCore::IntRect&, WebCore::IntRect*, WebCore::IntRect&, int, WebCore::IntRect&, float, int); + WebCore::IntRect viewRect; + WebCore::IntRect webViewRect; + jfloat scale; + jint extras; +}; + +/* + * Native JNI methods + */ +static int nativeCacheHitFramePointer(JNIEnv *env, jobject obj) +{ + return reinterpret_cast(GET_NATIVE_VIEW(env, obj) + ->m_cacheHitFrame->framePointer()); +} + +static jobject nativeCacheHitNodeBounds(JNIEnv *env, jobject obj) +{ + WebCore::IntRect bounds = GET_NATIVE_VIEW(env, obj) + ->m_cacheHitNode->originalAbsoluteBounds(); + jclass rectClass = env->FindClass("android/graphics/Rect"); + jmethodID init = env->GetMethodID(rectClass, "", "(IIII)V"); + jobject rect = env->NewObject(rectClass, init, bounds.x(), + bounds.y(), bounds.right(), bounds.bottom()); + env->DeleteLocalRef(rectClass); + return rect; +} + +static int nativeCacheHitNodePointer(JNIEnv *env, jobject obj) +{ + return reinterpret_cast(GET_NATIVE_VIEW(env, obj) + ->m_cacheHitNode->nodePointer()); +} + +static bool nativeCacheHitIsPlugin(JNIEnv *env, jobject obj) +{ + return GET_NATIVE_VIEW(env, obj)->m_cacheHitNode->isPlugin(); +} + +static void nativeClearCursor(JNIEnv *env, jobject obj) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + LOG_ASSERT(view, "view not set in %s", __FUNCTION__); + view->clearCursor(); +} + +static void nativeCreate(JNIEnv *env, jobject obj, int viewImpl, jstring drawableDir, + jobject jAssetManager) +{ + AssetManager* am = assetManagerForJavaObject(env, jAssetManager); + WTF::String dir = jstringToWtfString(env, drawableDir); + WebView* webview = new WebView(env, obj, viewImpl, dir, am); + // 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(frame ? frame->framePointer() : 0); +} + +static const CachedNode* getCursorNode(JNIEnv *env, jobject obj) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); + return root ? root->currentCursor() : 0; +} + +static const CachedNode* getCursorNode(JNIEnv *env, jobject obj, + const CachedFrame** frame) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); + return root ? root->currentCursor(frame) : 0; +} + +static const CachedNode* getFocusCandidate(JNIEnv *env, jobject obj, + const CachedFrame** frame) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); + if (!root) + return 0; + const CachedNode* cursor = root->currentCursor(frame); + if (cursor && cursor->wantsKeyEvents()) + return cursor; + return root->currentFocus(frame); +} + +static bool focusCandidateHasNextTextfield(JNIEnv *env, jobject obj) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); + if (!root) + return false; + const CachedNode* cursor = root->currentCursor(); + if (!cursor || !cursor->isTextInput()) + cursor = root->currentFocus(); + if (!cursor || !cursor->isTextInput()) return false; + return root->nextTextField(cursor, 0); +} + +static const CachedNode* getFocusNode(JNIEnv *env, jobject obj) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); + return root ? root->currentFocus() : 0; +} + +static const CachedNode* getFocusNode(JNIEnv *env, jobject obj, + const CachedFrame** frame) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); + return root ? root->currentFocus(frame) : 0; +} + +static const CachedInput* getInputCandidate(JNIEnv *env, jobject obj) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); + if (!root) + return 0; + const CachedFrame* frame; + const CachedNode* cursor = root->currentCursor(&frame); + if (!cursor || !cursor->wantsKeyEvents()) + cursor = root->currentFocus(&frame); + return cursor ? frame->textInput(cursor) : 0; +} + +static jboolean nativePageShouldHandleShiftAndArrows(JNIEnv *env, jobject obj) +{ + const CachedNode* focus = getFocusNode(env, obj); + if (!focus) return false; + // Plugins handle shift and arrows whether or not they have focus. + if (focus->isPlugin()) return true; + const CachedNode* cursor = getCursorNode(env, obj); + // ContentEditable nodes should only receive shift and arrows if they have + // both the cursor and the focus. + return cursor && cursor->nodePointer() == focus->nodePointer() + && cursor->isContentEditable(); +} + +static jobject nativeCursorNodeBounds(JNIEnv *env, jobject obj) +{ + const CachedFrame* frame; + const CachedNode* node = getCursorNode(env, obj, &frame); + WebCore::IntRect bounds = node ? node->bounds(frame) + : WebCore::IntRect(0, 0, 0, 0); + jclass rectClass = env->FindClass("android/graphics/Rect"); + jmethodID init = env->GetMethodID(rectClass, "", "(IIII)V"); + jobject rect = env->NewObject(rectClass, init, bounds.x(), + bounds.y(), bounds.right(), bounds.bottom()); + env->DeleteLocalRef(rectClass); + return rect; +} + +static jint nativeCursorNodePointer(JNIEnv *env, jobject obj) +{ + const CachedNode* node = getCursorNode(env, obj); + return reinterpret_cast(node ? node->nodePointer() : 0); +} + +static jobject nativeCursorPosition(JNIEnv *env, jobject obj) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + const CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); + WebCore::IntPoint pos = WebCore::IntPoint(0, 0); + if (root) + root->getSimulatedMousePosition(&pos); + jclass pointClass = env->FindClass("android/graphics/Point"); + jmethodID init = env->GetMethodID(pointClass, "", "(II)V"); + jobject point = env->NewObject(pointClass, init, pos.x(), pos.y()); + env->DeleteLocalRef(pointClass); + return point; +} + +static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj) +{ + int L, T, R, B; + GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B); + return WebCore::IntRect(L, T, R - L, B - T); +} + +static bool nativeCursorIntersects(JNIEnv *env, jobject obj, jobject visRect) +{ + const CachedFrame* frame; + const CachedNode* node = getCursorNode(env, obj, &frame); + return node ? node->bounds(frame).intersects( + jrect_to_webrect(env, visRect)) : false; +} + +static bool nativeCursorIsAnchor(JNIEnv *env, jobject obj) +{ + const CachedNode* node = getCursorNode(env, obj); + return node ? node->isAnchor() : false; +} + +static bool nativeCursorIsTextInput(JNIEnv *env, jobject obj) +{ + const CachedNode* node = getCursorNode(env, obj); + return node ? node->isTextInput() : false; +} + +static jobject nativeCursorText(JNIEnv *env, jobject obj) +{ + const CachedNode* node = getCursorNode(env, obj); + if (!node) + return 0; + WTF::String value = node->getExport(); + return wtfStringToJstring(env, value); +} + +static void nativeDebugDump(JNIEnv *env, jobject obj) +{ +#if DUMP_NAV_CACHE + WebView* view = GET_NATIVE_VIEW(env, obj); + LOG_ASSERT(view, "view not set in %s", __FUNCTION__); + view->debugDump(); +#endif +} + +static jint nativeDraw(JNIEnv *env, jobject obj, jobject canv, jint color, + jint extras, jboolean split) { + SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv); + return reinterpret_cast(GET_NATIVE_VIEW(env, obj)->draw(canvas, color, extras, split)); +} + +static jint nativeGetDrawGLFunction(JNIEnv *env, jobject obj, jobject jrect, jobject jviewrect, + jfloat scale, jint extras) { + WebCore::IntRect viewRect; + if (jrect == NULL) { + viewRect = WebCore::IntRect(); + } else { + viewRect = jrect_to_webrect(env, jrect); + } + WebView *wvInstance = GET_NATIVE_VIEW(env, obj); + GLDrawFunctor* functor = new GLDrawFunctor(wvInstance, &android::WebView::drawGL, + viewRect, scale, extras); + wvInstance->setFunctor((Functor*) functor); + + WebCore::IntRect webViewRect; + if (jviewrect == NULL) { + webViewRect = WebCore::IntRect(); + } else { + webViewRect = jrect_to_webrect(env, jviewrect); + } + functor->updateViewRect(webViewRect); + + return (jint)functor; +} + +static void nativeUpdateDrawGLFunction(JNIEnv *env, jobject obj, jobject jrect, jobject jviewrect) { + WebView *wvInstance = GET_NATIVE_VIEW(env, obj); + if (wvInstance != NULL) { + GLDrawFunctor* functor = (GLDrawFunctor*) wvInstance->getFunctor(); + if (functor != NULL) { + WebCore::IntRect viewRect; + if (jrect == NULL) { + viewRect = WebCore::IntRect(); + } else { + viewRect = jrect_to_webrect(env, jrect); + } + functor->updateRect(viewRect); + + WebCore::IntRect webViewRect; + if (jviewrect == NULL) { + webViewRect = WebCore::IntRect(); + } else { + webViewRect = jrect_to_webrect(env, jviewrect); + } + functor->updateViewRect(webViewRect); + } + } +} + +static bool nativeEvaluateLayersAnimations(JNIEnv *env, jobject obj) +{ +#if USE(ACCELERATED_COMPOSITING) + LayerAndroid* root = GET_NATIVE_VIEW(env, obj)->compositeRoot(); + if (root) + return root->evaluateAnimations(); +#endif + return false; +} + +static void nativeSetBaseLayer(JNIEnv *env, jobject obj, jint layer, jobject inval, + jboolean showVisualIndicator, + jboolean isPictureAfterFirstLayout) +{ + BaseLayerAndroid* layerImpl = reinterpret_cast(layer); + SkRegion invalRegion; + if (inval) + invalRegion = *GraphicsJNI::getNativeRegion(env, inval); + GET_NATIVE_VIEW(env, obj)->setBaseLayer(layerImpl, invalRegion, showVisualIndicator, + isPictureAfterFirstLayout); +} + +static void nativeReplaceBaseContent(JNIEnv *env, jobject obj, jint content) +{ + PictureSet* set = reinterpret_cast(content); + GET_NATIVE_VIEW(env, obj)->replaceBaseContent(set); +} + +static void nativeCopyBaseContentToPicture(JNIEnv *env, jobject obj, jobject pict) +{ + SkPicture* picture = GraphicsJNI::getNativePicture(env, pict); + GET_NATIVE_VIEW(env, obj)->copyBaseContentToPicture(picture); +} + +static bool nativeHasContent(JNIEnv *env, jobject obj) +{ + return GET_NATIVE_VIEW(env, obj)->hasContent(); +} + +static jobject nativeImageURI(JNIEnv *env, jobject obj, jint x, jint y) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + LOG_ASSERT(view, "view not set in %s", __FUNCTION__); + WTF::String uri = view->imageURI(x, y); + return wtfStringToJstring(env, uri); +} + +static jint nativeFocusCandidateFramePointer(JNIEnv *env, jobject obj) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); + if (!root) + return 0; + const CachedFrame* frame = 0; + const CachedNode* cursor = root->currentCursor(&frame); + if (!cursor || !cursor->wantsKeyEvents()) + (void) root->currentFocus(&frame); + return reinterpret_cast(frame ? frame->framePointer() : 0); +} + +static bool nativeFocusCandidateIsPassword(JNIEnv *env, jobject obj) +{ + const CachedInput* input = getInputCandidate(env, obj); + return input && input->getType() == CachedInput::PASSWORD; +} + +static bool nativeFocusCandidateIsRtlText(JNIEnv *env, jobject obj) +{ + const CachedInput* input = getInputCandidate(env, obj); + return input ? input->isRtlText() : false; +} + +static bool nativeFocusCandidateIsTextInput(JNIEnv *env, jobject obj) +{ + const CachedNode* node = getFocusCandidate(env, obj, 0); + return node ? node->isTextInput() : false; +} + +static jint nativeFocusCandidateMaxLength(JNIEnv *env, jobject obj) +{ + const CachedInput* input = getInputCandidate(env, obj); + return input ? input->maxLength() : false; +} + +static jint nativeFocusCandidateIsAutoComplete(JNIEnv *env, jobject obj) +{ + const CachedInput* input = getInputCandidate(env, obj); + return input ? input->autoComplete() : false; +} + +static jobject nativeFocusCandidateName(JNIEnv *env, jobject obj) +{ + const CachedInput* input = getInputCandidate(env, obj); + if (!input) + return 0; + const WTF::String& name = input->name(); + return wtfStringToJstring(env, name); +} + +static jobject createJavaRect(JNIEnv* env, int x, int y, int right, int bottom) +{ + jclass rectClass = env->FindClass("android/graphics/Rect"); + jmethodID init = env->GetMethodID(rectClass, "", "(IIII)V"); + jobject rect = env->NewObject(rectClass, init, x, y, right, bottom); + env->DeleteLocalRef(rectClass); + return rect; +} + +static jobject nativeFocusCandidateNodeBounds(JNIEnv *env, jobject obj) +{ + const CachedFrame* frame; + const CachedNode* node = getFocusCandidate(env, obj, &frame); + WebCore::IntRect bounds = node ? node->bounds(frame) + : WebCore::IntRect(0, 0, 0, 0); + return createJavaRect(env, bounds.x(), bounds.y(), bounds.right(), bounds.bottom()); +} + +static jobject nativeFocusCandidatePaddingRect(JNIEnv *env, jobject obj) +{ + const CachedInput* input = getInputCandidate(env, obj); + if (!input) + return 0; + // Note that the Java Rect is being used to pass four integers, rather than + // being used as an actual rectangle. + return createJavaRect(env, input->paddingLeft(), input->paddingTop(), + input->paddingRight(), input->paddingBottom()); +} + +static jint nativeFocusCandidatePointer(JNIEnv *env, jobject obj) +{ + const CachedNode* node = getFocusCandidate(env, obj, 0); + return reinterpret_cast(node ? node->nodePointer() : 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); +} + +static int nativeFocusCandidateLineHeight(JNIEnv *env, jobject obj) +{ + const CachedInput* input = getInputCandidate(env, obj); + return input ? input->lineHeight() : 0; +} + +static jfloat nativeFocusCandidateTextSize(JNIEnv *env, jobject obj) +{ + const CachedInput* input = getInputCandidate(env, obj); + return input ? input->textSize() : 0.f; +} + +static int nativeFocusCandidateType(JNIEnv *env, jobject obj) +{ + const CachedInput* input = getInputCandidate(env, obj); + if (!input) + return CachedInput::NONE; + + if (input->isTextArea()) + return CachedInput::TEXT_AREA; + + return input->getType(); +} + +static bool nativeFocusIsPlugin(JNIEnv *env, jobject obj) +{ + const CachedNode* node = getFocusNode(env, obj); + return node ? node->isPlugin() : false; +} + +static jobject nativeFocusNodeBounds(JNIEnv *env, jobject obj) +{ + const CachedFrame* frame; + const CachedNode* node = getFocusNode(env, obj, &frame); + WebCore::IntRect bounds = node ? node->bounds(frame) + : WebCore::IntRect(0, 0, 0, 0); + jclass rectClass = env->FindClass("android/graphics/Rect"); + jmethodID init = env->GetMethodID(rectClass, "", "(IIII)V"); + jobject rect = env->NewObject(rectClass, init, bounds.x(), + bounds.y(), bounds.right(), bounds.bottom()); + env->DeleteLocalRef(rectClass); + return rect; +} + +static jint nativeFocusNodePointer(JNIEnv *env, jobject obj) +{ + const CachedNode* node = getFocusNode(env, obj); + return node ? reinterpret_cast(node->nodePointer()) : 0; +} + +static bool nativeCursorWantsKeyEvents(JNIEnv* env, jobject jwebview) { + WebView* view = GET_NATIVE_VIEW(env, jwebview); + LOG_ASSERT(view, "view not set in %s", __FUNCTION__); + return view->cursorWantsKeyEvents(); +} + +static void nativeHideCursor(JNIEnv *env, jobject obj) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + LOG_ASSERT(view, "view not set in %s", __FUNCTION__); + view->hideCursor(); +} + +static void nativeInstrumentReport(JNIEnv *env, jobject obj) +{ +#ifdef ANDROID_INSTRUMENT + TimeCounter::reportNow(); +#endif +} + +static void nativeSelectBestAt(JNIEnv *env, jobject obj, jobject jrect) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + LOG_ASSERT(view, "view not set in %s", __FUNCTION__); + WebCore::IntRect rect = jrect_to_webrect(env, jrect); + view->selectBestAt(rect); +} + +static void nativeSelectAt(JNIEnv *env, jobject obj, jint x, jint y) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + LOG_ASSERT(view, "view not set in %s", __FUNCTION__); + WebCore::IntRect rect = IntRect(x, y , 1, 1); + view->selectBestAt(rect); + if (view->hasCursorNode()) + view->showCursorUntimed(); +} + +static jobject nativeLayerBounds(JNIEnv* env, jobject obj, jint jlayer) +{ + SkRect r; +#if USE(ACCELERATED_COMPOSITING) + LayerAndroid* layer = (LayerAndroid*) jlayer; + r = layer->bounds(); +#else + r.setEmpty(); +#endif + SkIRect irect; + r.round(&irect); + jclass rectClass = env->FindClass("android/graphics/Rect"); + jmethodID init = env->GetMethodID(rectClass, "", "(IIII)V"); + jobject rect = env->NewObject(rectClass, init, irect.fLeft, irect.fTop, + irect.fRight, irect.fBottom); + env->DeleteLocalRef(rectClass); + return rect; +} + +static jobject nativeSubtractLayers(JNIEnv* env, jobject obj, jobject jrect) +{ + SkIRect irect = jrect_to_webrect(env, jrect); +#if USE(ACCELERATED_COMPOSITING) + LayerAndroid* root = GET_NATIVE_VIEW(env, obj)->compositeRoot(); + if (root) { + SkRect rect; + rect.set(irect); + rect = root->subtractLayers(rect); + rect.round(&irect); + } +#endif + jclass rectClass = env->FindClass("android/graphics/Rect"); + jmethodID init = env->GetMethodID(rectClass, "", "(IIII)V"); + jobject rect = env->NewObject(rectClass, init, irect.fLeft, irect.fTop, + irect.fRight, irect.fBottom); + env->DeleteLocalRef(rectClass); + return rect; +} + +static jint nativeTextGeneration(JNIEnv *env, jobject obj) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); + return root ? root->textGeneration() : 0; +} + +static bool nativePointInNavCache(JNIEnv *env, jobject obj, + int x, int y, int slop) +{ + return GET_NATIVE_VIEW(env, obj)->pointInNavCache(x, y, slop); +} + +static bool nativeMotionUp(JNIEnv *env, jobject obj, + int x, int y, int slop) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + LOG_ASSERT(view, "view not set in %s", __FUNCTION__); + return view->motionUp(x, y, slop); +} + +static bool nativeHasCursorNode(JNIEnv *env, jobject obj) +{ + return GET_NATIVE_VIEW(env, obj)->hasCursorNode(); +} + +static bool nativeHasFocusNode(JNIEnv *env, jobject obj) +{ + return GET_NATIVE_VIEW(env, obj)->hasFocusNode(); +} + +static bool nativeMoveCursor(JNIEnv *env, jobject obj, + int key, int count, bool ignoreScroll) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + DBG_NAV_LOGD("env=%p obj=%p view=%p", env, obj, view); + LOG_ASSERT(view, "view not set in %s", __FUNCTION__); + return view->moveCursor(key, count, ignoreScroll); +} + +static void nativeRecordButtons(JNIEnv* env, jobject obj, bool hasFocus, + bool pressed, bool invalidate) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + LOG_ASSERT(view, "view not set in %s", __FUNCTION__); + view->nativeRecordButtons(hasFocus, pressed, invalidate); +} + +static void nativeSetFindIsUp(JNIEnv *env, jobject obj, jboolean isUp) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + LOG_ASSERT(view, "view not set in %s", __FUNCTION__); + view->setFindIsUp(isUp); +} + +static void nativeSetFindIsEmpty(JNIEnv *env, jobject obj) +{ + GET_NATIVE_VIEW(env, obj)->setFindIsEmpty(); +} + +static void nativeShowCursorTimed(JNIEnv *env, jobject obj) +{ + GET_NATIVE_VIEW(env, obj)->showCursorTimed(); +} + +static void nativeSetHeightCanMeasure(JNIEnv *env, jobject obj, bool measure) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + LOG_ASSERT(view, "view not set in nativeSetHeightCanMeasure"); + 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, "", "(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.right(), webRect.bottom()); + 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* 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(); +} + +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(cachedFocusNode))->setExport(webcoreString); + root->setTextGeneration(generation); + checkException(env); +} + +static jint nativeGetBlockLeftEdge(JNIEnv *env, jobject obj, jint x, jint y, + jfloat scale) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + LOG_ASSERT(view, "view not set in %s", __FUNCTION__); + if (!view) + return -1; + return view->getBlockLeftEdge(x, y, scale); +} + +static void nativeDestroy(JNIEnv *env, jobject obj) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + LOGD("nativeDestroy view: %p", view); + LOG_ASSERT(view, "view not set in nativeDestroy"); + delete view; +} + +static void nativeStopGL(JNIEnv *env, jobject obj) +{ + GET_NATIVE_VIEW(env, obj)->stopGL(); +} + +static bool nativeMoveCursorToNextTextInput(JNIEnv *env, jobject obj) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); + if (!root) + return false; + const CachedNode* current = root->currentCursor(); + if (!current || !current->isTextInput()) + current = root->currentFocus(); + if (!current || !current->isTextInput()) + return false; + const CachedFrame* frame; + const CachedNode* next = root->nextTextField(current, &frame); + if (!next) + return false; + const WebCore::IntRect& bounds = next->bounds(frame); + root->rootHistory()->setMouseBounds(bounds); + view->getWebViewCore()->updateCursorBounds(root, frame, next); + view->showCursorUntimed(); + root->setCursor(const_cast(frame), + const_cast(next)); + view->sendMoveFocus(static_cast(frame->framePointer()), + static_cast(next->nodePointer())); + if (!next->isInLayer()) + view->scrollRectOnScreen(bounds); + view->getWebViewCore()->m_moveGeneration++; + return true; +} + +static int nativeMoveGeneration(JNIEnv *env, jobject obj) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + if (!view) + return 0; + return view->moveGeneration(); +} + +static void nativeMoveSelection(JNIEnv *env, jobject obj, int x, int y) +{ + GET_NATIVE_VIEW(env, obj)->moveSelection(x, y); +} + +static void nativeResetSelection(JNIEnv *env, jobject obj) +{ + return GET_NATIVE_VIEW(env, obj)->resetSelection(); +} + +static jobject nativeSelectableText(JNIEnv* env, jobject obj) +{ + IntPoint pos = GET_NATIVE_VIEW(env, obj)->selectableText(); + jclass pointClass = env->FindClass("android/graphics/Point"); + jmethodID init = env->GetMethodID(pointClass, "", "(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__); + 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, jboolean set, + jfloat scale, jint x, jint y) +{ + GET_NATIVE_VIEW(env, obj)->setSelectionPointer(set, scale, x, y); +} + +#ifdef ANDROID_DUMP_DISPLAY_TREE +static void dumpToFile(const char text[], void* file) { + fwrite(text, 1, strlen(text), reinterpret_cast(file)); + fwrite("\n", 1, 1, reinterpret_cast(file)); +} +#endif + +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__); + + if (view && view->getWebViewCore()) { + FILE* file = fopen(DISPLAY_TREE_LOG_FILE, "w"); + if (file) { + SkFormatDumper dumper(dumpToFile, file); + // dump the URL + if (jurl) { + const char* str = env->GetStringUTFChars(jurl, 0); + SkDebugf("Dumping %s to %s\n", str, DISPLAY_TREE_LOG_FILE); + dumpToFile(str, file); + env->ReleaseStringUTFChars(jurl, str); + } + // now dump the display tree + 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); + // we're done with the file now + fwrite("\n", 1, 1, file); + fclose(file); + } +#if USE(ACCELERATED_COMPOSITING) + const LayerAndroid* rootLayer = view->compositeRoot(); + if (rootLayer) { + FILE* file = fopen(LAYERS_TREE_LOG_FILE,"w"); + if (file) { + rootLayer->dumpLayers(file, 0); + fclose(file); + } + } +#endif + } +#endif +} + +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__); + SkIRect nativeRect, nativeBounds; + int id = view->scrollableLayer(x, y, &nativeRect, &nativeBounds); + if (rect) + GraphicsJNI::irect_to_jrect(nativeRect, env, rect); + if (bounds) + GraphicsJNI::irect_to_jrect(nativeBounds, env, bounds); + return id; +} + +static bool nativeScrollLayer(JNIEnv* env, jobject obj, jint layerId, jint x, + jint y) +{ +#if ENABLE(ANDROID_OVERFLOW_SCROLL) + WebView* view = GET_NATIVE_VIEW(env, obj); + LayerAndroid* root = view->compositeRoot(); + if (!root) + return false; + LayerAndroid* layer = root->findById(layerId); + if (!layer || !layer->contentIsScrollable()) + return false; + return static_cast(layer)->scrollTo(x, y); +#endif + return false; +} + +static void nativeSetExpandedTileBounds(JNIEnv*, jobject, jboolean enabled) +{ + TilesManager::instance()->setExpandedTileBounds(enabled); +} + +/* + * JNI registration + */ +static JNINativeMethod gJavaWebViewMethods[] = { + { "nativeCacheHitFramePointer", "()I", + (void*) nativeCacheHitFramePointer }, + { "nativeCacheHitIsPlugin", "()Z", + (void*) nativeCacheHitIsPlugin }, + { "nativeCacheHitNodeBounds", "()Landroid/graphics/Rect;", + (void*) nativeCacheHitNodeBounds }, + { "nativeCacheHitNodePointer", "()I", + (void*) nativeCacheHitNodePointer }, + { "nativeClearCursor", "()V", + (void*) nativeClearCursor }, + { "nativeCreate", "(ILjava/lang/String;Landroid/content/res/AssetManager;)V", + (void*) nativeCreate }, + { "nativeCursorFramePointer", "()I", + (void*) nativeCursorFramePointer }, + { "nativePageShouldHandleShiftAndArrows", "()Z", + (void*) nativePageShouldHandleShiftAndArrows }, + { "nativeCursorNodeBounds", "()Landroid/graphics/Rect;", + (void*) nativeCursorNodeBounds }, + { "nativeCursorNodePointer", "()I", + (void*) nativeCursorNodePointer }, + { "nativeCursorIntersects", "(Landroid/graphics/Rect;)Z", + (void*) nativeCursorIntersects }, + { "nativeCursorIsAnchor", "()Z", + (void*) nativeCursorIsAnchor }, + { "nativeCursorIsTextInput", "()Z", + (void*) nativeCursorIsTextInput }, + { "nativeCursorPosition", "()Landroid/graphics/Point;", + (void*) nativeCursorPosition }, + { "nativeCursorText", "()Ljava/lang/String;", + (void*) nativeCursorText }, + { "nativeCursorWantsKeyEvents", "()Z", + (void*)nativeCursorWantsKeyEvents }, + { "nativeDebugDump", "()V", + (void*) nativeDebugDump }, + { "nativeDestroy", "()V", + (void*) nativeDestroy }, + { "nativeDraw", "(Landroid/graphics/Canvas;IIZ)I", + (void*) nativeDraw }, + { "nativeGetDrawGLFunction", "(Landroid/graphics/Rect;Landroid/graphics/Rect;FI)I", + (void*) nativeGetDrawGLFunction }, + { "nativeUpdateDrawGLFunction", "(Landroid/graphics/Rect;Landroid/graphics/Rect;)V", + (void*) nativeUpdateDrawGLFunction }, + { "nativeDumpDisplayTree", "(Ljava/lang/String;)V", + (void*) nativeDumpDisplayTree }, + { "nativeEvaluateLayersAnimations", "()Z", + (void*) nativeEvaluateLayersAnimations }, + { "nativeExtendSelection", "(II)V", + (void*) nativeExtendSelection }, + { "nativeFindAll", "(Ljava/lang/String;Ljava/lang/String;Z)I", + (void*) nativeFindAll }, + { "nativeFindNext", "(Z)V", + (void*) nativeFindNext }, + { "nativeFindIndex", "()I", + (void*) nativeFindIndex}, + { "nativeFocusCandidateFramePointer", "()I", + (void*) nativeFocusCandidateFramePointer }, + { "nativeFocusCandidateHasNextTextfield", "()Z", + (void*) focusCandidateHasNextTextfield }, + { "nativeFocusCandidateIsPassword", "()Z", + (void*) nativeFocusCandidateIsPassword }, + { "nativeFocusCandidateIsRtlText", "()Z", + (void*) nativeFocusCandidateIsRtlText }, + { "nativeFocusCandidateIsTextInput", "()Z", + (void*) nativeFocusCandidateIsTextInput }, + { "nativeFocusCandidateLineHeight", "()I", + (void*) nativeFocusCandidateLineHeight }, + { "nativeFocusCandidateMaxLength", "()I", + (void*) nativeFocusCandidateMaxLength }, + { "nativeFocusCandidateIsAutoComplete", "()Z", + (void*) nativeFocusCandidateIsAutoComplete }, + { "nativeFocusCandidateName", "()Ljava/lang/String;", + (void*) nativeFocusCandidateName }, + { "nativeFocusCandidateNodeBounds", "()Landroid/graphics/Rect;", + (void*) nativeFocusCandidateNodeBounds }, + { "nativeFocusCandidatePaddingRect", "()Landroid/graphics/Rect;", + (void*) nativeFocusCandidatePaddingRect }, + { "nativeFocusCandidatePointer", "()I", + (void*) nativeFocusCandidatePointer }, + { "nativeFocusCandidateText", "()Ljava/lang/String;", + (void*) nativeFocusCandidateText }, + { "nativeFocusCandidateTextSize", "()F", + (void*) nativeFocusCandidateTextSize }, + { "nativeFocusCandidateType", "()I", + (void*) nativeFocusCandidateType }, + { "nativeFocusIsPlugin", "()Z", + (void*) nativeFocusIsPlugin }, + { "nativeFocusNodeBounds", "()Landroid/graphics/Rect;", + (void*) nativeFocusNodeBounds }, + { "nativeFocusNodePointer", "()I", + (void*) nativeFocusNodePointer }, + { "nativeGetCursorRingBounds", "()Landroid/graphics/Rect;", + (void*) nativeGetCursorRingBounds }, + { "nativeGetSelection", "()Ljava/lang/String;", + (void*) nativeGetSelection }, + { "nativeHasCursorNode", "()Z", + (void*) nativeHasCursorNode }, + { "nativeHasFocusNode", "()Z", + (void*) nativeHasFocusNode }, + { "nativeHideCursor", "()V", + (void*) nativeHideCursor }, + { "nativeHitSelection", "(II)Z", + (void*) nativeHitSelection }, + { "nativeImageURI", "(II)Ljava/lang/String;", + (void*) nativeImageURI }, + { "nativeInstrumentReport", "()V", + (void*) nativeInstrumentReport }, + { "nativeLayerBounds", "(I)Landroid/graphics/Rect;", + (void*) nativeLayerBounds }, + { "nativeMotionUp", "(III)Z", + (void*) nativeMotionUp }, + { "nativeMoveCursor", "(IIZ)Z", + (void*) nativeMoveCursor }, + { "nativeMoveCursorToNextTextInput", "()Z", + (void*) nativeMoveCursorToNextTextInput }, + { "nativeMoveGeneration", "()I", + (void*) nativeMoveGeneration }, + { "nativeMoveSelection", "(II)V", + (void*) nativeMoveSelection }, + { "nativePointInNavCache", "(III)Z", + (void*) nativePointInNavCache }, + { "nativeRecordButtons", "(ZZZ)V", + (void*) nativeRecordButtons }, + { "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;ZZ)V", + (void*) nativeSetBaseLayer }, + { "nativeReplaceBaseContent", "(I)V", + (void*) nativeReplaceBaseContent }, + { "nativeCopyBaseContentToPicture", "(Landroid/graphics/Picture;)V", + (void*) nativeCopyBaseContentToPicture }, + { "nativeHasContent", "()Z", + (void*) nativeHasContent }, + { "nativeSetSelectionPointer", "(ZFII)V", + (void*) nativeSetSelectionPointer }, + { "nativeShowCursorTimed", "()V", + (void*) nativeShowCursorTimed }, + { "nativeStartSelection", "(II)Z", + (void*) nativeStartSelection }, + { "nativeStopGL", "()V", + (void*) nativeStopGL }, + { "nativeSubtractLayers", "(Landroid/graphics/Rect;)Landroid/graphics/Rect;", + (void*) nativeSubtractLayers }, + { "nativeTextGeneration", "()I", + (void*) nativeTextGeneration }, + { "nativeUpdateCachedTextfield", "(Ljava/lang/String;I)V", + (void*) nativeUpdateCachedTextfield }, + { "nativeWordSelection", "(II)Z", + (void*) nativeWordSelection }, + { "nativeGetBlockLeftEdge", "(IIF)I", + (void*) nativeGetBlockLeftEdge }, + { "nativeScrollableLayer", "(IILandroid/graphics/Rect;Landroid/graphics/Rect;)I", + (void*) nativeScrollableLayer }, + { "nativeScrollLayer", "(III)Z", + (void*) nativeScrollLayer }, + { "nativeSetExpandedTileBounds", "(Z)V", + (void*) nativeSetExpandedTileBounds }, +}; + +int registerWebView(JNIEnv* env) +{ + jclass clazz = env->FindClass("android/webkit/WebView"); + LOG_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"); + env->DeleteLocalRef(clazz); + + return jniRegisterNativeMethods(env, "android/webkit/WebView", gJavaWebViewMethods, NELEM(gJavaWebViewMethods)); +} + +} // namespace android diff --git a/Source/WebKit/android/plugins/ANPBitmapInterface.cpp b/Source/WebKit/android/plugins/ANPBitmapInterface.cpp new file mode 100644 index 0000000..4c6ad7c --- /dev/null +++ b/Source/WebKit/android/plugins/ANPBitmapInterface.cpp @@ -0,0 +1,71 @@ +/* + * 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. + */ + +// must include config.h first for webkit to fiddle with new/delete +#include "config.h" +#include "SkANP.h" +#include "SkColorPriv.h" + +static bool anp_getPixelPacking(ANPBitmapFormat fmt, ANPPixelPacking* packing) { + switch (fmt) { + case kRGBA_8888_ANPBitmapFormat: + if (packing) { + packing->AShift = SK_A32_SHIFT; + packing->ABits = SK_A32_BITS; + packing->RShift = SK_R32_SHIFT; + packing->RBits = SK_R32_BITS; + packing->GShift = SK_G32_SHIFT; + packing->GBits = SK_G32_BITS; + packing->BShift = SK_B32_SHIFT; + packing->BBits = SK_B32_BITS; + } + return true; + case kRGB_565_ANPBitmapFormat: + if (packing) { + packing->AShift = 0; + packing->ABits = 0; + packing->RShift = SK_R16_SHIFT; + packing->RBits = SK_R16_BITS; + packing->GShift = SK_G16_SHIFT; + packing->GBits = SK_G16_BITS; + packing->BShift = SK_B16_SHIFT; + packing->BBits = SK_B16_BITS; + } + return true; + default: + break; + } + return false; +} + +/////////////////////////////////////////////////////////////////////////////// + +#define ASSIGN(obj, name) (obj)->name = anp_##name + +void ANPBitmapInterfaceV0_Init(ANPInterface* value) { + ANPBitmapInterfaceV0* i = reinterpret_cast(value); + + ASSIGN(i, getPixelPacking); +} diff --git a/Source/WebKit/android/plugins/ANPCanvasInterface.cpp b/Source/WebKit/android/plugins/ANPCanvasInterface.cpp new file mode 100644 index 0000000..d6d89ff --- /dev/null +++ b/Source/WebKit/android/plugins/ANPCanvasInterface.cpp @@ -0,0 +1,197 @@ +/* + * 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. + */ + +// must include config.h first for webkit to fiddle with new/delete +#include "config.h" +#include "SkANP.h" + +static ANPCanvas* anp_newCanvas(const ANPBitmap* bitmap) { + SkBitmap bm; + return new ANPCanvas(*SkANP::SetBitmap(&bm, *bitmap)); +} + +static void anp_deleteCanvas(ANPCanvas* canvas) { + delete canvas; +} + +static void anp_save(ANPCanvas* canvas) { + canvas->skcanvas->save(); +} + +static void anp_restore(ANPCanvas* canvas) { + canvas->skcanvas->restore(); +} + +static void anp_translate(ANPCanvas* canvas, float tx, float ty) { + canvas->skcanvas->translate(SkFloatToScalar(tx), SkFloatToScalar(ty)); +} + +static void anp_scale(ANPCanvas* canvas, float sx, float sy) { + canvas->skcanvas->scale(SkFloatToScalar(sx), SkFloatToScalar(sy)); +} + +static void anp_rotate(ANPCanvas* canvas, float degrees) { + canvas->skcanvas->rotate(SkFloatToScalar(degrees)); +} + +static void anp_skew(ANPCanvas* canvas, float kx, float ky) { + canvas->skcanvas->skew(SkFloatToScalar(kx), SkFloatToScalar(ky)); +} + +static void anp_clipRect(ANPCanvas* canvas, const ANPRectF* rect) { + SkRect r; + canvas->skcanvas->clipRect(*SkANP::SetRect(&r, *rect)); +} + +static void anp_clipPath(ANPCanvas* canvas, const ANPPath* path) { + canvas->skcanvas->clipPath(*path); +} +static void anp_concat(ANPCanvas* canvas, const ANPMatrix* matrix) { + canvas->skcanvas->concat(*matrix); +} + +static void anp_getTotalMatrix(ANPCanvas* canvas, ANPMatrix* matrix) { + const SkMatrix& src = canvas->skcanvas->getTotalMatrix(); + *matrix = *reinterpret_cast(&src); +} + +static bool anp_getLocalClipBounds(ANPCanvas* canvas, ANPRectF* r, + bool antialias) { + SkRect bounds; + if (canvas->skcanvas->getClipBounds(&bounds, + antialias ? SkCanvas::kAA_EdgeType : SkCanvas::kBW_EdgeType)) { + SkANP::SetRect(r, bounds); + return true; + } + return false; +} + +static bool anp_getDeviceClipBounds(ANPCanvas* canvas, ANPRectI* r) { + const SkRegion& clip = canvas->skcanvas->getTotalClip(); + if (!clip.isEmpty()) { + SkANP::SetRect(r, clip.getBounds()); + return true; + } + return false; +} + +static void anp_drawColor(ANPCanvas* canvas, ANPColor color) { + canvas->skcanvas->drawColor(color); +} + +static void anp_drawPaint(ANPCanvas* canvas, const ANPPaint* paint) { + canvas->skcanvas->drawPaint(*paint); +} + +static void anp_drawLine(ANPCanvas* canvas, float x0, float y0, + float x1, float y1, const ANPPaint* paint) { + canvas->skcanvas->drawLine(SkFloatToScalar(x0), SkFloatToScalar(y0), + SkFloatToScalar(x1), SkFloatToScalar(y1), *paint); +} + +static void anp_drawRect(ANPCanvas* canvas, const ANPRectF* rect, + const ANPPaint* paint) { + SkRect r; + canvas->skcanvas->drawRect(*SkANP::SetRect(&r, *rect), *paint); +} + +static void anp_drawOval(ANPCanvas* canvas, const ANPRectF* rect, + const ANPPaint* paint) { + SkRect r; + canvas->skcanvas->drawOval(*SkANP::SetRect(&r, *rect), *paint); +} + +static void anp_drawPath(ANPCanvas* canvas, const ANPPath* path, + const ANPPaint* paint) { + canvas->skcanvas->drawPath(*path, *paint); +} + +static void anp_drawText(ANPCanvas* canvas, const void* text, uint32_t length, + float x, float y, const ANPPaint* paint) { + canvas->skcanvas->drawText(text, length, + SkFloatToScalar(x), SkFloatToScalar(y), + *paint); +} + +static void anp_drawPosText(ANPCanvas* canvas, const void* text, + uint32_t byteLength, const float xy[], const ANPPaint* paint) { + canvas->skcanvas->drawPosText(text, byteLength, + reinterpret_cast(xy), *paint); +} + +static void anp_drawBitmap(ANPCanvas* canvas, const ANPBitmap* bitmap, + float x, float y, const ANPPaint* paint) { + SkBitmap bm; + canvas->skcanvas->drawBitmap(*SkANP::SetBitmap(&bm, *bitmap), + SkFloatToScalar(x), SkFloatToScalar(y), + paint); +} + +static void anp_drawBitmapRect(ANPCanvas* canvas, const ANPBitmap* bitmap, + const ANPRectI* src, const ANPRectF* dst, + const ANPPaint* paint) { + SkBitmap bm; + SkRect dstR; + SkIRect srcR, *srcPtr = NULL; + + if (src) { + srcPtr = SkANP::SetRect(&srcR, *src); + } + canvas->skcanvas->drawBitmapRect(*SkANP::SetBitmap(&bm, *bitmap), srcPtr, + *SkANP::SetRect(&dstR, *dst), paint); +} + +/////////////////////////////////////////////////////////////////////////////// + +#define ASSIGN(obj, name) (obj)->name = anp_##name + +void ANPCanvasInterfaceV0_Init(ANPInterface* value) { + ANPCanvasInterfaceV0* i = reinterpret_cast(value); + + ASSIGN(i, newCanvas); + ASSIGN(i, deleteCanvas); + ASSIGN(i, save); + ASSIGN(i, restore); + ASSIGN(i, translate); + ASSIGN(i, scale); + ASSIGN(i, rotate); + ASSIGN(i, skew); + ASSIGN(i, clipRect); + ASSIGN(i, clipPath); + ASSIGN(i, concat); + ASSIGN(i, getTotalMatrix); + ASSIGN(i, getLocalClipBounds); + ASSIGN(i, getDeviceClipBounds); + ASSIGN(i, drawColor); + ASSIGN(i, drawPaint); + ASSIGN(i, drawLine); + ASSIGN(i, drawRect); + ASSIGN(i, drawOval); + ASSIGN(i, drawPath); + ASSIGN(i, drawText); + ASSIGN(i, drawPosText); + ASSIGN(i, drawBitmap); + ASSIGN(i, drawBitmapRect); +} diff --git a/Source/WebKit/android/plugins/ANPEventInterface.cpp b/Source/WebKit/android/plugins/ANPEventInterface.cpp new file mode 100644 index 0000000..2fdf159 --- /dev/null +++ b/Source/WebKit/android/plugins/ANPEventInterface.cpp @@ -0,0 +1,84 @@ +/* + * 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. + */ + +// must include config.h first for webkit to fiddle with new/delete +#include "config.h" +#include "SkANP.h" +#include "WebViewCore.h" +#include "PluginView.h" +#include "PluginWidgetAndroid.h" + +#include "JavaSharedClient.h" + +using namespace android; + +struct WrappedANPEvent { + WebViewCore* fWVC; + PluginWidgetAndroid* fPWA; + ANPEvent fEvent; +}; + +/* Its possible we may be called after the plugin that initiated the event + has been torn-down. Thus we check that the assicated webviewcore and + pluginwidget are still active before dispatching the event. + */ +static void send_anpevent(void* data) { + WrappedANPEvent* wrapper = static_cast(data); + WebViewCore* core = wrapper->fWVC; + PluginWidgetAndroid* widget = wrapper->fPWA; + + // be sure we're still alive before delivering the event + if (WebViewCore::isInstance(core) && core->isPlugin(widget)) { + widget->sendEvent(wrapper->fEvent); + } + delete wrapper; +} + +static void anp_postEvent(NPP instance, const ANPEvent* event) { + if (instance && instance->ndata && event) { + PluginView* pluginView = static_cast(instance->ndata); + PluginWidgetAndroid* pluginWidget = pluginView->platformPluginWidget(); + WebViewCore* wvc = pluginWidget->webViewCore(); + + WrappedANPEvent* wrapper = new WrappedANPEvent; + // recored these, and recheck that they are valid before delivery + // in send_anpevent + wrapper->fWVC = pluginWidget->webViewCore(); + wrapper->fPWA = pluginWidget; + // make a copy of the event + wrapper->fEvent = *event; + JavaSharedClient::EnqueueFunctionPtr(send_anpevent, wrapper); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +#define ASSIGN(obj, name) (obj)->name = anp_##name + +void ANPEventInterfaceV0_Init(ANPInterface* value) { + ANPEventInterfaceV0* i = reinterpret_cast(value); + + ASSIGN(i, postEvent); +} diff --git a/Source/WebKit/android/plugins/ANPKeyCodes.h b/Source/WebKit/android/plugins/ANPKeyCodes.h new file mode 100644 index 0000000..969679f --- /dev/null +++ b/Source/WebKit/android/plugins/ANPKeyCodes.h @@ -0,0 +1,229 @@ +/* + * 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 ANPKeyCodes_DEFINED +#define ANPKeyCodes_DEFINED + +/* List the key codes that are set to a plugin in the ANPKeyEvent. + + These exactly match the values in android/view/KeyEvent.java and the + corresponding .h file android/keycodes.h. +*/ +enum ANPKeyCodes { + kUnknown_ANPKeyCode = 0, + + kSoftLeft_ANPKeyCode = 1, + kSoftRight_ANPKeyCode = 2, + kHome_ANPKeyCode = 3, + kBack_ANPKeyCode = 4, + kCall_ANPKeyCode = 5, + kEndCall_ANPKeyCode = 6, + k0_ANPKeyCode = 7, + k1_ANPKeyCode = 8, + k2_ANPKeyCode = 9, + k3_ANPKeyCode = 10, + k4_ANPKeyCode = 11, + k5_ANPKeyCode = 12, + k6_ANPKeyCode = 13, + k7_ANPKeyCode = 14, + k8_ANPKeyCode = 15, + k9_ANPKeyCode = 16, + kStar_ANPKeyCode = 17, + kPound_ANPKeyCode = 18, + kDpadUp_ANPKeyCode = 19, + kDpadDown_ANPKeyCode = 20, + kDpadLeft_ANPKeyCode = 21, + kDpadRight_ANPKeyCode = 22, + kDpadCenter_ANPKeyCode = 23, + kVolumeUp_ANPKeyCode = 24, + kVolumeDown_ANPKeyCode = 25, + kPower_ANPKeyCode = 26, + kCamera_ANPKeyCode = 27, + kClear_ANPKeyCode = 28, + kA_ANPKeyCode = 29, + kB_ANPKeyCode = 30, + kC_ANPKeyCode = 31, + kD_ANPKeyCode = 32, + kE_ANPKeyCode = 33, + kF_ANPKeyCode = 34, + kG_ANPKeyCode = 35, + kH_ANPKeyCode = 36, + kI_ANPKeyCode = 37, + kJ_ANPKeyCode = 38, + kK_ANPKeyCode = 39, + kL_ANPKeyCode = 40, + kM_ANPKeyCode = 41, + kN_ANPKeyCode = 42, + kO_ANPKeyCode = 43, + kP_ANPKeyCode = 44, + kQ_ANPKeyCode = 45, + kR_ANPKeyCode = 46, + kS_ANPKeyCode = 47, + kT_ANPKeyCode = 48, + kU_ANPKeyCode = 49, + kV_ANPKeyCode = 50, + kW_ANPKeyCode = 51, + kX_ANPKeyCode = 52, + kY_ANPKeyCode = 53, + kZ_ANPKeyCode = 54, + kComma_ANPKeyCode = 55, + kPeriod_ANPKeyCode = 56, + kAltLeft_ANPKeyCode = 57, + kAltRight_ANPKeyCode = 58, + kShiftLeft_ANPKeyCode = 59, + kShiftRight_ANPKeyCode = 60, + kTab_ANPKeyCode = 61, + kSpace_ANPKeyCode = 62, + kSym_ANPKeyCode = 63, + kExplorer_ANPKeyCode = 64, + kEnvelope_ANPKeyCode = 65, + kNewline_ANPKeyCode = 66, + kDel_ANPKeyCode = 67, + kGrave_ANPKeyCode = 68, + kMinus_ANPKeyCode = 69, + kEquals_ANPKeyCode = 70, + kLeftBracket_ANPKeyCode = 71, + kRightBracket_ANPKeyCode = 72, + kBackslash_ANPKeyCode = 73, + kSemicolon_ANPKeyCode = 74, + kApostrophe_ANPKeyCode = 75, + kSlash_ANPKeyCode = 76, + kAt_ANPKeyCode = 77, + kNum_ANPKeyCode = 78, + kHeadSetHook_ANPKeyCode = 79, + kFocus_ANPKeyCode = 80, + kPlus_ANPKeyCode = 81, + kMenu_ANPKeyCode = 82, + kNotification_ANPKeyCode = 83, + kSearch_ANPKeyCode = 84, + kMediaPlayPause_ANPKeyCode = 85, + kMediaStop_ANPKeyCode = 86, + kMediaNext_ANPKeyCode = 87, + kMediaPrevious_ANPKeyCode = 88, + kMediaRewind_ANPKeyCode = 89, + kMediaFastForward_ANPKeyCode = 90, + kMute_ANPKeyCode = 91, + kPageUp_ANPKeyCode = 92, + kPageDown_ANPKeyCode = 93, + kPictsymbols_ANPKeyCode = 94, + kSwitchCharset_ANPKeyCode = 95, + kButtonA_ANPKeyCode = 96, + kButtonB_ANPKeyCode = 97, + kButtonC_ANPKeyCode = 98, + kButtonX_ANPKeyCode = 99, + kButtonY_ANPKeyCode = 100, + kButtonZ_ANPKeyCode = 101, + kButtonL1_ANPKeyCode = 102, + kButtonR1_ANPKeyCode = 103, + kButtonL2_ANPKeyCode = 104, + kButtonR2_ANPKeyCode = 105, + kButtonThumbL_ANPKeyCode = 106, + kButtonThumbR_ANPKeyCode = 107, + kButtonStart_ANPKeyCode = 108, + kButtonSelect_ANPKeyCode = 109, + kButtonMode_ANPKeyCode = 110, + kEscape_ANPKeyCode = 111, + kForwardDel_ANPKeyCode = 112, + kCtrlLeft_ANPKeyCode = 113, + kCtrlRight_ANPKeyCode = 114, + kCapsLock_ANPKeyCode = 115, + kScrollLock_ANPKeyCode = 116, + kMetaLeft_ANPKeyCode = 117, + kMetaRight_ANPKeyCode = 118, + kFunction_ANPKeyCode = 119, + kSysRq_ANPKeyCode = 120, + kBreak_ANPKeyCode = 121, + kMoveHome_ANPKeyCode = 122, + kMoveEnd_ANPKeyCode = 123, + kInsert_ANPKeyCode = 124, + kForward_ANPKeyCode = 125, + kMediaPlay_ANPKeyCode = 126, + kMediaPause_ANPKeyCode = 127, + kMediaClose_ANPKeyCode = 128, + kMediaEject_ANPKeyCode = 129, + kMediaRecord_ANPKeyCode = 130, + kF1_ANPKeyCode = 131, + kF2_ANPKeyCode = 132, + kF3_ANPKeyCode = 133, + kF4_ANPKeyCode = 134, + kF5_ANPKeyCode = 135, + kF6_ANPKeyCode = 136, + kF7_ANPKeyCode = 137, + kF8_ANPKeyCode = 138, + kF9_ANPKeyCode = 139, + kF10_ANPKeyCode = 140, + kF11_ANPKeyCode = 141, + kF12_ANPKeyCode = 142, + kNumLock_ANPKeyCode = 143, + kNumPad0_ANPKeyCode = 144, + kNumPad1_ANPKeyCode = 145, + kNumPad2_ANPKeyCode = 146, + kNumPad3_ANPKeyCode = 147, + kNumPad4_ANPKeyCode = 148, + kNumPad5_ANPKeyCode = 149, + kNumPad6_ANPKeyCode = 150, + kNumPad7_ANPKeyCode = 151, + kNumPad8_ANPKeyCode = 152, + kNumPad9_ANPKeyCode = 153, + kNumPadDivide_ANPKeyCode = 154, + kNumPadMultiply_ANPKeyCode = 155, + kNumPadSubtract_ANPKeyCode = 156, + kNumPadAdd_ANPKeyCode = 157, + kNumPadDot_ANPKeyCode = 158, + kNumPadComma_ANPKeyCode = 159, + kNumPadEnter_ANPKeyCode = 160, + kNumPadEquals_ANPKeyCode = 161, + kNumPadLeftParen_ANPKeyCode = 162, + kNumPadRightParen_ANPKeyCode = 163, + kVolumeMute_ANPKeyCode = 164, + kInfo_ANPKeyCode = 165, + kChannelUp_ANPKeyCode = 166, + kChannelDown_ANPKeyCode = 167, + kZoomIn_ANPKeyCode = 168, + kZoomOut_ANPKeyCode = 169, + kTv_ANPKeyCode = 170, + kWindow_ANPKeyCode = 171, + kGuide_ANPKeyCode = 172, + kDvr_ANPKeyCode = 173, + kBookmark_ANPKeyCode = 174, + kCaptions_ANPKeyCode = 175, + kSettings_ANPKeyCode = 176, + kTvPower_ANPKeyCode = 177, + kTvInput_ANPKeyCode = 178, + kStbPower_ANPKeyCode = 179, + kStbInput_ANPKeyCode = 180, + kAvrPower_ANPKeyCode = 181, + kAvrInput_ANPKeyCode = 182, + kProgRed_ANPKeyCode = 183, + kProgGreen_ANPKeyCode = 184, + kProgYellow_ANPKeyCode = 185, + kProgBlue_ANPKeyCode = 186, + kAppSwitch_ANPKeyCode = 187, + + // NOTE: If you add a new keycode here you must also add it to several other files. + // Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list. +}; + +#endif diff --git a/Source/WebKit/android/plugins/ANPLogInterface.cpp b/Source/WebKit/android/plugins/ANPLogInterface.cpp new file mode 100644 index 0000000..23a4ed6 --- /dev/null +++ b/Source/WebKit/android/plugins/ANPLogInterface.cpp @@ -0,0 +1,60 @@ +/* + * 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 "webkitPlugin" + +#include "utils/Log.h" +#include "android_npapi.h" +#include + +static void anp_log(ANPLogType logType, const char format[], ...) { + va_list args; + va_start(args, format); + + android_LogPriority priority; + switch (logType) { + case kError_ANPLogType: + priority = ANDROID_LOG_ERROR; + break; + case kWarning_ANPLogType: + priority = ANDROID_LOG_WARN; + break; + case kDebug_ANPLogType: + priority = ANDROID_LOG_DEBUG; + break; + default: + priority = ANDROID_LOG_UNKNOWN; + break; + } + LOG_PRI_VA(priority, "plugin", format, args); + + va_end(args); +} + +void ANPLogInterfaceV0_Init(ANPInterface* value) { + ANPLogInterfaceV0* i = reinterpret_cast(value); + + i->log = anp_log; +} diff --git a/Source/WebKit/android/plugins/ANPMatrixInterface.cpp b/Source/WebKit/android/plugins/ANPMatrixInterface.cpp new file mode 100644 index 0000000..f322315 --- /dev/null +++ b/Source/WebKit/android/plugins/ANPMatrixInterface.cpp @@ -0,0 +1,167 @@ +/* + * 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. + */ + +// must include config.h first for webkit to fiddle with new/delete +#include "config.h" +#include "SkANP.h" + +#ifdef SK_SCALAR_IS_FIXED +static void fromFloat(SkScalar dst[], const float src[], int n) { + for (int i = 0; i < n; i++) { + dst[i] = SkFloatToScalar(src[i]); + } +} + +static void toFloat(float dst[], const SkScalar src[], int n) { + for (int i = 0; i < n; i++) { + dst[i] = SkScalarToFloat(src[i]); + } +} +#endif + +static ANPMatrix* anp_newMatrix() { + return new ANPMatrix; +} + +static void anp_deleteMatrix(ANPMatrix* matrix) { + delete matrix; +} + +static ANPMatrixFlag anp_getFlags(const ANPMatrix* matrix) { + return matrix->getType(); +} + +static void anp_copy(ANPMatrix* dst, const ANPMatrix* src) { + *dst = *src; +} + +static void anp_get3x3(const ANPMatrix* matrix, float dst[9]) { + for (int i = 0; i < 9; i++) { + dst[i] = SkScalarToFloat(matrix->get(i)); + } +} + +static void anp_set3x3(ANPMatrix* matrix, const float src[9]) { + for (int i = 0; i < 9; i++) { + matrix->set(i, SkFloatToScalar(src[i])); + } +} + +static void anp_setIdentity(ANPMatrix* matrix) { + matrix->reset(); +} + +static void anp_preTranslate(ANPMatrix* matrix, float tx, float ty) { + matrix->preTranslate(SkFloatToScalar(tx), SkFloatToScalar(ty)); +} + +static void anp_postTranslate(ANPMatrix* matrix, float tx, float ty) { + matrix->postTranslate(SkFloatToScalar(tx), SkFloatToScalar(ty)); +} + +static void anp_preScale(ANPMatrix* matrix, float sx, float sy) { + matrix->preScale(SkFloatToScalar(sx), SkFloatToScalar(sy)); +} + +static void anp_postScale(ANPMatrix* matrix, float sx, float sy) { + matrix->postScale(SkFloatToScalar(sx), SkFloatToScalar(sy)); +} + +static void anp_preSkew(ANPMatrix* matrix, float kx, float ky) { + matrix->preSkew(SkFloatToScalar(kx), SkFloatToScalar(ky)); +} + +static void anp_postSkew(ANPMatrix* matrix, float kx, float ky) { + matrix->postSkew(SkFloatToScalar(kx), SkFloatToScalar(ky)); +} + +static void anp_preRotate(ANPMatrix* matrix, float degrees) { + matrix->preRotate(SkFloatToScalar(degrees)); +} + +static void anp_postRotate(ANPMatrix* matrix, float degrees) { + matrix->postRotate(SkFloatToScalar(degrees)); +} + +static void anp_preConcat(ANPMatrix* matrix, const ANPMatrix* other) { + matrix->preConcat(*other); +} + +static void anp_postConcat(ANPMatrix* matrix, const ANPMatrix* other) { + matrix->postConcat(*other); +} + +static bool anp_invert(ANPMatrix* dst, const ANPMatrix* src) { + return src->invert(dst); +} + +static void anp_mapPoints(ANPMatrix* matrix, float dst[], const float src[], + int32_t count) { +#ifdef SK_SCALAR_IS_FLOAT + matrix->mapPoints(reinterpret_cast(dst), + reinterpret_cast(src), count); +#else + const int N = 64; + SkPoint tmp[N]; + do { + int n = count; + if (n > N) { + n = N; + } + fromFloat(&tmp[0].fX, src, n*2); + matrix->mapPoints(tmp, n); + toFloat(dst, &tmp[0].fX, n*2); + count -= n; + } while (count > 0); +#endif +} + +/////////////////////////////////////////////////////////////////////////////// + +#define ASSIGN(obj, name) (obj)->name = anp_##name + +void ANPMatrixInterfaceV0_Init(ANPInterface* value) { + ANPMatrixInterfaceV0* i = reinterpret_cast(value); + + ASSIGN(i, newMatrix); + ASSIGN(i, deleteMatrix); + ASSIGN(i, getFlags); + ASSIGN(i, copy); + ASSIGN(i, get3x3); + ASSIGN(i, set3x3); + ASSIGN(i, setIdentity); + ASSIGN(i, preTranslate); + ASSIGN(i, postTranslate); + ASSIGN(i, preScale); + ASSIGN(i, postScale); + ASSIGN(i, preSkew); + ASSIGN(i, postSkew); + ASSIGN(i, preRotate); + ASSIGN(i, postRotate); + ASSIGN(i, preConcat); + ASSIGN(i, postConcat); + ASSIGN(i, invert); + ASSIGN(i, mapPoints); +} diff --git a/Source/WebKit/android/plugins/ANPOpenGLInterface.cpp b/Source/WebKit/android/plugins/ANPOpenGLInterface.cpp new file mode 100644 index 0000000..839ec17 --- /dev/null +++ b/Source/WebKit/android/plugins/ANPOpenGLInterface.cpp @@ -0,0 +1,121 @@ +/* + * 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. + */ + +// must include config.h first for webkit to fiddle with new/delete +#include "config.h" + +#include "ANPOpenGL_npapi.h" +#include "PluginView.h" +#include "PluginWidgetAndroid.h" +#include "MediaLayer.h" +#include "WebViewCore.h" +#include "Frame.h" +#include "Page.h" +#include "Chrome.h" +#include "ChromeClient.h" + +using namespace android; + +static WebCore::PluginView* pluginViewForInstance(NPP instance) { + if (instance && instance->ndata) + return static_cast(instance->ndata); + return WebCore::PluginView::currentPluginView(); +} + +static EGLContext anp_acquireContext(NPP instance) { + WebCore::PluginView* pluginView = pluginViewForInstance(instance); + PluginWidgetAndroid* pluginWidget = pluginView->platformPluginWidget(); + WebCore::MediaLayer* mediaLayer = pluginWidget->getLayer(); + + if (!mediaLayer) + return EGL_NO_CONTEXT; + + return mediaLayer->getTexture()->producerAcquireContext(); +} + +static ANPTextureInfo anp_lockTexture(NPP instance) { + WebCore::PluginView* pluginView = pluginViewForInstance(instance); + PluginWidgetAndroid* pluginWidget = pluginView->platformPluginWidget(); + WebCore::MediaLayer* mediaLayer = pluginWidget->getLayer(); + WebCore::DoubleBufferedTexture* texture = mediaLayer->getTexture(); + + // lock the texture and cache the internal info + WebCore::TextureInfo* info = texture->producerLock(); + mediaLayer->setCurrentTextureInfo(info); + + ANPTextureInfo anpInfo; + anpInfo.textureId = info->m_textureId; + anpInfo.width = (int32_t) info->m_width; + anpInfo.height = (int32_t) info->m_height; + anpInfo.internalFormat = info->m_internalFormat; + return anpInfo; +} + +static void anp_releaseTexture(NPP instance, const ANPTextureInfo* textureInfo) { + WebCore::PluginView* pluginView = pluginViewForInstance(instance); + PluginWidgetAndroid* pluginWidget = pluginView->platformPluginWidget(); + WebCore::MediaLayer* mediaLayer = pluginWidget->getLayer(); + WebCore::DoubleBufferedTexture* texture = mediaLayer->getTexture(); + + //copy the info into our internal structure + WebCore::TextureInfo* info = mediaLayer->getCurrentTextureInfo(); + info->m_textureId = textureInfo->textureId; + info->m_width = textureInfo->width; + info->m_height = textureInfo->height; + info->m_internalFormat = textureInfo->internalFormat; + + texture->producerReleaseAndSwap(); + + // invalidate the java view so that this content is drawn + pluginWidget->viewInvalidate(); +} + +static void anp_invertPluginContent(NPP instance, bool isContentInverted) { + WebCore::PluginView* pluginView = pluginViewForInstance(instance); + PluginWidgetAndroid* pluginWidget = pluginView->platformPluginWidget(); + WebCore::MediaLayer* mediaLayer = pluginWidget->getLayer(); + + mediaLayer->invertContents(isContentInverted); + + //force the layer to sync to the UI thread + WebViewCore* wvc = pluginWidget->webViewCore(); + if (wvc) + wvc->mainFrame()->page()->chrome()->client()->scheduleCompositingLayerSync(); +} + + + +/////////////////////////////////////////////////////////////////////////////// + +#define ASSIGN(obj, name) (obj)->name = anp_##name + +void ANPOpenGLInterfaceV0_Init(ANPInterface* v) { + ANPOpenGLInterfaceV0* i = reinterpret_cast(v); + + ASSIGN(i, acquireContext); + ASSIGN(i, lockTexture); + ASSIGN(i, releaseTexture); + ASSIGN(i, invertPluginContent); +} diff --git a/Source/WebKit/android/plugins/ANPOpenGL_npapi.h b/Source/WebKit/android/plugins/ANPOpenGL_npapi.h new file mode 100644 index 0000000..5aabbc4 --- /dev/null +++ b/Source/WebKit/android/plugins/ANPOpenGL_npapi.h @@ -0,0 +1,63 @@ +/* + * 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 ANPOpenGL_npapi_H +#define ANPOpenGL_npapi_H + +#include "android_npapi.h" +#include +#include + +/** + * TODO should we not use EGL and GL data types for ABI safety? + */ +struct ANPTextureInfo { + GLuint textureId; + uint32_t width; + uint32_t height; + GLenum internalFormat; +}; + +struct ANPOpenGLInterfaceV0 : ANPInterface { + /** + */ + EGLContext (*acquireContext)(NPP instance); + + /** + */ + ANPTextureInfo (*lockTexture)(NPP instance); + + /** + */ + void (*releaseTexture)(NPP instance, const ANPTextureInfo*); + + /** + * Invert the contents of the plugin on the y-axis. + * default is to not be inverted (i.e. use OpenGL coordinates) + */ + void (*invertPluginContent)(NPP instance, bool isContentInverted); +}; + +#endif //ANPOpenGL_npapi_H diff --git a/Source/WebKit/android/plugins/ANPPaintInterface.cpp b/Source/WebKit/android/plugins/ANPPaintInterface.cpp new file mode 100644 index 0000000..5c59df9 --- /dev/null +++ b/Source/WebKit/android/plugins/ANPPaintInterface.cpp @@ -0,0 +1,212 @@ +/* + * 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. + */ + +// must include config.h first for webkit to fiddle with new/delete +#include "config.h" +#include "SkANP.h" +#include "SkTypeface.h" + +static ANPPaint* anp_newPaint() { + return new ANPPaint; +} + +static void anp_deletePaint(ANPPaint* paint) { + delete paint; +} + +static ANPPaintFlags anp_getFlags(const ANPPaint* paint) { + return paint->getFlags(); +} + +static void anp_setFlags(ANPPaint* paint, ANPPaintFlags flags) { + paint->setFlags(flags); +} + +static ANPColor anp_getColor(const ANPPaint* paint) { + return paint->getColor(); +} + +static void anp_setColor(ANPPaint* paint, ANPColor color) { + paint->setColor(color); +} + +static ANPPaintStyle anp_getStyle(const ANPPaint* paint) { + return paint->getStyle(); +} + +static void anp_setStyle(ANPPaint* paint, ANPPaintStyle style) { + paint->setStyle(static_cast(style)); +} + +static float anp_getStrokeWidth(const ANPPaint* paint) { + return SkScalarToFloat(paint->getStrokeWidth()); +} + +static float anp_getStrokeMiter(const ANPPaint* paint) { + return SkScalarToFloat(paint->getStrokeMiter()); +} + +static ANPPaintCap anp_getStrokeCap(const ANPPaint* paint) { + return paint->getStrokeCap(); +} + +static ANPPaintJoin anp_getStrokeJoin(const ANPPaint* paint) { + return paint->getStrokeJoin(); +} + +static void anp_setStrokeWidth(ANPPaint* paint, float width) { + paint->setStrokeWidth(SkFloatToScalar(width)); +} + +static void anp_setStrokeMiter(ANPPaint* paint, float miter) { + paint->setStrokeMiter(SkFloatToScalar(miter)); +} + +static void anp_setStrokeCap(ANPPaint* paint, ANPPaintCap cap) { + paint->setStrokeCap(static_cast(cap)); +} + +static void anp_setStrokeJoin(ANPPaint* paint, ANPPaintJoin join) { + paint->setStrokeJoin(static_cast(join)); +} + +static ANPTextEncoding anp_getTextEncoding(const ANPPaint* paint) { + return paint->getTextEncoding(); +} + +static ANPPaintAlign anp_getTextAlign(const ANPPaint* paint) { + return paint->getTextAlign(); +} + +static float anp_getTextSize(const ANPPaint* paint) { + return SkScalarToFloat(paint->getTextSize()); +} + +static float anp_getTextScaleX(const ANPPaint* paint) { + return SkScalarToFloat(paint->getTextScaleX()); +} + +static float anp_getTextSkewX(const ANPPaint* paint) { + return SkScalarToFloat(paint->getTextSkewX()); +} + +static ANPTypeface* anp_getTypeface(const ANPPaint* paint) { + return reinterpret_cast(paint->getTypeface()); +} + +static void anp_setTextEncoding(ANPPaint* paint, ANPTextEncoding encoding) { + paint->setTextEncoding(static_cast(encoding)); +} + +static void anp_setTextAlign(ANPPaint* paint, ANPPaintAlign align) { + paint->setTextAlign(static_cast(align)); +} + +static void anp_setTextSize(ANPPaint* paint, float textSize) { + paint->setTextSize(SkFloatToScalar(textSize)); +} + +static void anp_setTextScaleX(ANPPaint* paint, float scaleX) { + paint->setTextScaleX(SkFloatToScalar(scaleX)); +} + +static void anp_setTextSkewX(ANPPaint* paint, float skewX) { + paint->setTextSkewX(SkFloatToScalar(skewX)); +} + +static void anp_setTypeface(ANPPaint* paint, ANPTypeface* tf) { + paint->setTypeface(tf); +} + +static float anp_measureText(ANPPaint* paint, const void* text, + uint32_t byteLength, ANPRectF* bounds) { + SkScalar w = paint->measureText(text, byteLength, + reinterpret_cast(bounds)); + return SkScalarToFloat(w); +} + +/** Return the number of unichars specifed by the text. + If widths is not null, returns the array of advance widths for each + unichar. + If bounds is not null, returns the array of bounds for each unichar. + */ +static int anp_getTextWidths(ANPPaint* paint, const void* text, + uint32_t byteLength, float widths[], ANPRectF bounds[]) { + return paint->getTextWidths(text, byteLength, widths, + reinterpret_cast(bounds)); +} + +static float anp_getFontMetrics(ANPPaint* paint, ANPFontMetrics* metrics) { + SkPaint::FontMetrics fm; + SkScalar spacing = paint->getFontMetrics(&fm); + if (metrics) { + metrics->fTop = SkScalarToFloat(fm.fTop); + metrics->fAscent = SkScalarToFloat(fm.fAscent); + metrics->fDescent = SkScalarToFloat(fm.fDescent); + metrics->fBottom = SkScalarToFloat(fm.fBottom); + metrics->fLeading = SkScalarToFloat(fm.fLeading); + } + return SkScalarToFloat(spacing); +} + +/////////////////////////////////////////////////////////////////////////////// + +#define ASSIGN(obj, name) (obj)->name = anp_##name + +void ANPPaintInterfaceV0_Init(ANPInterface* value) { + ANPPaintInterfaceV0* i = reinterpret_cast(value); + + ASSIGN(i, newPaint); + ASSIGN(i, deletePaint); + ASSIGN(i, getFlags); + ASSIGN(i, setFlags); + ASSIGN(i, getColor); + ASSIGN(i, setColor); + ASSIGN(i, getStyle); + ASSIGN(i, setStyle); + ASSIGN(i, getStrokeWidth); + ASSIGN(i, getStrokeMiter); + ASSIGN(i, getStrokeCap); + ASSIGN(i, getStrokeJoin); + ASSIGN(i, setStrokeWidth); + ASSIGN(i, setStrokeMiter); + ASSIGN(i, setStrokeCap); + ASSIGN(i, setStrokeJoin); + ASSIGN(i, getTextEncoding); + ASSIGN(i, getTextAlign); + ASSIGN(i, getTextSize); + ASSIGN(i, getTextScaleX); + ASSIGN(i, getTextSkewX); + ASSIGN(i, getTypeface); + ASSIGN(i, setTextEncoding); + ASSIGN(i, setTextAlign); + ASSIGN(i, setTextSize); + ASSIGN(i, setTextScaleX); + ASSIGN(i, setTextSkewX); + ASSIGN(i, setTypeface); + ASSIGN(i, measureText); + ASSIGN(i, getTextWidths); + ASSIGN(i, getFontMetrics); +} diff --git a/Source/WebKit/android/plugins/ANPPathInterface.cpp b/Source/WebKit/android/plugins/ANPPathInterface.cpp new file mode 100644 index 0000000..69cabcf --- /dev/null +++ b/Source/WebKit/android/plugins/ANPPathInterface.cpp @@ -0,0 +1,112 @@ +/* + * 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. + */ + +// must include config.h first for webkit to fiddle with new/delete +#include "config.h" +#include "SkANP.h" + +static ANPPath* anp_newPath() { + return new ANPPath; +} + +static void anp_deletePath(ANPPath* path) { + delete path; +} + +static void anp_copy(ANPPath* dst, const ANPPath* src) { + *dst = *src; +} + +static bool anp_equal(const ANPPath* p0, const ANPPath* p1) { + return *p0 == *p1; +} + +static void anp_reset(ANPPath* path) { + path->reset(); +} + +static bool anp_isEmpty(const ANPPath* path) { + return path->isEmpty(); +} + +static void anp_getBounds(const ANPPath* path, ANPRectF* bounds) { + SkANP::SetRect(bounds, path->getBounds()); +} + +static void anp_moveTo(ANPPath* path, float x, float y) { + path->moveTo(SkFloatToScalar(x), SkFloatToScalar(y)); +} + +static void anp_lineTo(ANPPath* path, float x, float y) { + path->lineTo(SkFloatToScalar(x), SkFloatToScalar(y)); +} + +static void anp_quadTo(ANPPath* path, float x0, float y0, float x1, float y1) { + path->quadTo(SkFloatToScalar(x0), SkFloatToScalar(y0), + SkFloatToScalar(x1), SkFloatToScalar(y1)); +} + +static void anp_cubicTo(ANPPath* path, float x0, float y0, + float x1, float y1, float x2, float y2) { + path->cubicTo(SkFloatToScalar(x0), SkFloatToScalar(y0), + SkFloatToScalar(x1), SkFloatToScalar(y1), + SkFloatToScalar(x2), SkFloatToScalar(y2)); +} + +static void anp_close(ANPPath* path) { + path->close(); +} + +static void anp_offset(ANPPath* path, float dx, float dy, ANPPath* dst) { + path->offset(SkFloatToScalar(dx), SkFloatToScalar(dy), dst); +} + +static void anp_transform(ANPPath* src, const ANPMatrix* matrix, + ANPPath* dst) { + src->transform(*matrix, dst); +} + +/////////////////////////////////////////////////////////////////////////////// + +#define ASSIGN(obj, name) (obj)->name = anp_##name + +void ANPPathInterfaceV0_Init(ANPInterface* value) { + ANPPathInterfaceV0* i = reinterpret_cast(value); + + ASSIGN(i, newPath); + ASSIGN(i, deletePath); + ASSIGN(i, copy); + ASSIGN(i, equal); + ASSIGN(i, reset); + ASSIGN(i, isEmpty); + ASSIGN(i, getBounds); + ASSIGN(i, moveTo); + ASSIGN(i, lineTo); + ASSIGN(i, quadTo); + ASSIGN(i, cubicTo); + ASSIGN(i, close); + ASSIGN(i, offset); + ASSIGN(i, transform); +} diff --git a/Source/WebKit/android/plugins/ANPSoundInterface.cpp b/Source/WebKit/android/plugins/ANPSoundInterface.cpp new file mode 100644 index 0000000..c238872 --- /dev/null +++ b/Source/WebKit/android/plugins/ANPSoundInterface.cpp @@ -0,0 +1,163 @@ +/* + * 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. + */ + +// must include config.h first for webkit to fiddle with new/delete +#include "config.h" +#include "android_npapi.h" + +#include "SkTypes.h" +#include "media/AudioTrack.h" + +#include + +struct ANPAudioTrack { + void* mUser; + ANPAudioCallbackProc mProc; + android::AudioTrack* mTrack; +}; + +static ANPSampleFormat toANPFormat(int fm) { + switch (fm) { + case AUDIO_FORMAT_PCM_16_BIT: + return kPCM16Bit_ANPSampleFormat; + case AUDIO_FORMAT_PCM_8_BIT: + return kPCM8Bit_ANPSampleFormat; + default: + return kUnknown_ANPSamleFormat; + } +} + +static int fromANPFormat(ANPSampleFormat fm) { + switch (fm) { + case kPCM16Bit_ANPSampleFormat: + return AUDIO_FORMAT_PCM_16_BIT; + case kPCM8Bit_ANPSampleFormat: + return AUDIO_FORMAT_PCM_8_BIT; + default: + return AUDIO_FORMAT_INVALID; + } +} + +static void callbackProc(int event, void* user, void* info) { + ANPAudioTrack* track = reinterpret_cast(user); + + switch (event) { + case android::AudioTrack::EVENT_MORE_DATA: { + ANPAudioBuffer dst; + android::AudioTrack::Buffer* src; + + src = reinterpret_cast(info); + dst.bufferData = src->raw; + dst.channelCount = src->channelCount; + dst.format = toANPFormat(src->format); + dst.size = src->size; + track->mProc(kMoreData_ANPAudioEvent, track->mUser, &dst); + // return the updated size field + src->size = dst.size; + break; + } + case android::AudioTrack::EVENT_UNDERRUN: + track->mProc(kUnderRun_ANPAudioEvent, track->mUser, NULL); + break; + default: + SkDebugf("------ unknown audio event for plugin %d\n", event); + break; + } +} + +static ANPAudioTrack* ANPCreateTrack(uint32_t sampleRate, + ANPSampleFormat format, + int channelCount, + ANPAudioCallbackProc proc, + void* user) { + + ANPAudioTrack* track = new ANPAudioTrack; + + track->mUser = user; + track->mProc = proc; + track->mTrack = new android::AudioTrack(AUDIO_STREAM_MUSIC, + sampleRate, + fromANPFormat(format), + (channelCount > 1) ? AUDIO_CHANNEL_OUT_STEREO : AUDIO_CHANNEL_OUT_MONO, + 0, // frameCount + 0, // flags + callbackProc, + track, + 0); + + if (track->mTrack->initCheck() != 0) { // failure + delete track->mTrack; + delete track; + track = NULL; + } + return track; +} + +static void ANPDeleteTrack(ANPAudioTrack* track) { + if (track) { + delete track->mTrack; + delete track; + } +} + +static void ANPTrackStart(ANPAudioTrack* track) { + track->mTrack->start(); +} + +static void ANPTrackPause(ANPAudioTrack* track) { + track->mTrack->pause(); +} + +static void ANPTrackStop(ANPAudioTrack* track) { + track->mTrack->stop(); +} + +static bool ANPTrackIsStopped(ANPAudioTrack* track) { + return track->mTrack->stopped(); +} + +static uint32_t ANPTrackLatency(ANPAudioTrack* track) { + return track->mTrack->latency(); +} + +/////////////////////////////////////////////////////////////////////////////// + +void ANPAudioTrackInterfaceV0_Init(ANPInterface* value) { + ANPAudioTrackInterfaceV0* si = reinterpret_cast(value); + si->newTrack = ANPCreateTrack; + si->deleteTrack = ANPDeleteTrack; + si->start = ANPTrackStart; + si->pause = ANPTrackPause; + si->stop = ANPTrackStop; + si->isStopped = ANPTrackIsStopped; +} + +void ANPAudioTrackInterfaceV1_Init(ANPInterface* value) { + // initialize the functions from the previous interface + ANPAudioTrackInterfaceV0_Init(value); + // add any new functions or override existing functions + ANPAudioTrackInterfaceV1* si = reinterpret_cast(value); + si->trackLatency = ANPTrackLatency; +} diff --git a/Source/WebKit/android/plugins/ANPSurfaceInterface.cpp b/Source/WebKit/android/plugins/ANPSurfaceInterface.cpp new file mode 100644 index 0000000..4b99b31 --- /dev/null +++ b/Source/WebKit/android/plugins/ANPSurfaceInterface.cpp @@ -0,0 +1,174 @@ +/* + * 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. + */ + +// must include config.h first for webkit to fiddle with new/delete +#include "config.h" +#include "ANPSurface_npapi.h" + +#include "PluginView.h" +#include "PluginWidgetAndroid.h" +#include "SkANP.h" +#include "android_graphics.h" +#include +#include +#include +#include +#include + +using namespace android; + +// used to cache JNI method and field IDs for Surface Objects +static struct ANPSurfaceInterfaceJavaGlue { + bool initialized; + jmethodID getSurfaceHolder; + jmethodID getSurface; + jfieldID surfacePointer; +} gSurfaceJavaGlue; + +static inline sp getSurface(JNIEnv* env, jobject view) { + if (!env || !view) { + return NULL; + } + + if (!gSurfaceJavaGlue.initialized) { + + jclass surfaceViewClass = env->FindClass("android/view/SurfaceView"); + gSurfaceJavaGlue.getSurfaceHolder = env->GetMethodID(surfaceViewClass, "getHolder", + "()Landroid/view/SurfaceHolder;"); + + jclass surfaceHolderClass = env->FindClass("android/view/SurfaceHolder"); + gSurfaceJavaGlue.getSurface = env->GetMethodID(surfaceHolderClass, "getSurface", + "()Landroid/view/Surface;"); + + jclass surfaceClass = env->FindClass("android/view/Surface"); + gSurfaceJavaGlue.surfacePointer = env->GetFieldID(surfaceClass, + ANDROID_VIEW_SURFACE_JNI_ID, "I"); + + env->DeleteLocalRef(surfaceClass); + env->DeleteLocalRef(surfaceViewClass); + env->DeleteLocalRef(surfaceHolderClass); + + gSurfaceJavaGlue.initialized = true; + } + + jobject holder = env->CallObjectMethod(view, gSurfaceJavaGlue.getSurfaceHolder); + jobject surface = env->CallObjectMethod(holder, gSurfaceJavaGlue.getSurface); + jint surfacePointer = env->GetIntField(surface, gSurfaceJavaGlue.surfacePointer); + + env->DeleteLocalRef(holder); + env->DeleteLocalRef(surface); + + return sp((Surface*) surfacePointer); +} + +static inline ANPBitmapFormat convertPixelFormat(PixelFormat format) { + switch (format) { + case PIXEL_FORMAT_RGBA_8888: return kRGBA_8888_ANPBitmapFormat; + case PIXEL_FORMAT_RGB_565: return kRGB_565_ANPBitmapFormat; + default: return kUnknown_ANPBitmapFormat; + } +} + +static bool anp_lock(JNIEnv* env, jobject surfaceView, ANPBitmap* bitmap, ANPRectI* dirtyRect) { + if (!bitmap || !surfaceView) { + return false; + } + + sp surface = getSurface(env, surfaceView); + + if (!bitmap || !Surface::isValid(surface)) { + return false; + } + + Region dirtyRegion; + if (dirtyRect) { + Rect rect(dirtyRect->left, dirtyRect->top, dirtyRect->right, dirtyRect->bottom); + if (!rect.isEmpty()) { + dirtyRegion.set(rect); + } + } else { + dirtyRegion.set(Rect(0x3FFF, 0x3FFF)); + } + + Surface::SurfaceInfo info; + status_t err = surface->lock(&info, &dirtyRegion); + if (err < 0) { + return false; + } + + // the surface may have expanded the dirty region so we must to pass that + // information back to the plugin. + if (dirtyRect) { + Rect dirtyBounds = dirtyRegion.getBounds(); + dirtyRect->left = dirtyBounds.left; + dirtyRect->right = dirtyBounds.right; + dirtyRect->top = dirtyBounds.top; + dirtyRect->bottom = dirtyBounds.bottom; + } + + ssize_t bpr = info.s * bytesPerPixel(info.format); + + bitmap->format = convertPixelFormat(info.format); + bitmap->width = info.w; + bitmap->height = info.h; + bitmap->rowBytes = bpr; + + if (info.w > 0 && info.h > 0) { + bitmap->baseAddr = info.bits; + } else { + bitmap->baseAddr = NULL; + return false; + } + + return true; +} + +static void anp_unlock(JNIEnv* env, jobject surfaceView) { + if (!surfaceView) { + return; + } + + sp surface = getSurface(env, surfaceView); + + if (!Surface::isValid(surface)) { + return; + } + + surface->unlockAndPost(); +} + +/////////////////////////////////////////////////////////////////////////////// + +#define ASSIGN(obj, name) (obj)->name = anp_##name + +void ANPSurfaceInterfaceV0_Init(ANPInterface* value) { + ANPSurfaceInterfaceV0* i = reinterpret_cast(value); + + ASSIGN(i, lock); + ASSIGN(i, unlock); + + // setup the java glue struct + gSurfaceJavaGlue.initialized = false; +} diff --git a/Source/WebKit/android/plugins/ANPSurface_npapi.h b/Source/WebKit/android/plugins/ANPSurface_npapi.h new file mode 100644 index 0000000..910a948 --- /dev/null +++ b/Source/WebKit/android/plugins/ANPSurface_npapi.h @@ -0,0 +1,48 @@ +/* + * 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 ANPSurface_npapi_H +#define ANPSurface_npapi_H + +#include "android_npapi.h" +#include + +struct ANPSurfaceInterfaceV0 : ANPInterface { + /** Locks the surface from manipulation by other threads and provides a bitmap + to be written to. The dirtyRect param specifies which portion of the + bitmap will be written to. If the dirtyRect is NULL then the entire + surface will be considered dirty. If the lock was successful the function + will return true and the bitmap will be set to point to a valid bitmap. + If not the function will return false and the bitmap will be set to NULL. + */ + bool (*lock)(JNIEnv* env, jobject surface, ANPBitmap* bitmap, ANPRectI* dirtyRect); + /** Given a locked surface handle (i.e. result of a successful call to lock) + the surface is unlocked and the contents of the bitmap, specifically + those inside the dirtyRect are written to the screen. + */ + void (*unlock)(JNIEnv* env, jobject surface); +}; + +#endif //ANPSurface_npapi_H diff --git a/Source/WebKit/android/plugins/ANPSystemInterface.cpp b/Source/WebKit/android/plugins/ANPSystemInterface.cpp new file mode 100644 index 0000000..7199635 --- /dev/null +++ b/Source/WebKit/android/plugins/ANPSystemInterface.cpp @@ -0,0 +1,222 @@ +/* + * 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. + */ + +// must include config.h first for webkit to fiddle with new/delete +#include "config.h" + +#include "ANPSystem_npapi.h" +#include "Frame.h" +#include "JavaSharedClient.h" +#include "PluginClient.h" +#include "PluginPackage.h" +#include "PluginView.h" +#include "PluginWidgetAndroid.h" +#include "Settings.h" +#include "SkString.h" +#include "WebViewCore.h" +#include + +#include + +//#define PLUGIN_DEBUG_LOCAL // controls the printing of log messages +#include "PluginDebugAndroid.h" + +static const char* gApplicationDataDir = NULL; +static const char* gApplicationDataDirIncognito = NULL; + +using namespace android; + +static WebCore::PluginView* pluginViewForInstance(NPP instance) { + if (instance && instance->ndata) + return static_cast(instance->ndata); + return WebCore::PluginView::currentPluginView(); +} + +static const char* anp_getApplicationDataDirectory() { + if (NULL == gApplicationDataDir) { + PluginClient* client = JavaSharedClient::GetPluginClient(); + if (!client) + return NULL; + + WTF::String path = client->getPluginSharedDataDirectory(); + int length = path.length(); + if (length == 0) + return NULL; + + char* storage = (char*) malloc(length + 1); + if (NULL == storage) + return NULL; + + memcpy(storage, path.utf8().data(), length); + storage[length] = '\0'; + + static const char incognitoPath[] = "/incognito_plugins"; + char* incognitoStorage = (char*) malloc(length + strlen(incognitoPath) + 1); + + strcpy(incognitoStorage, storage); + strcat(incognitoStorage, incognitoPath); + + // save this assignment for last, so that if multiple threads call us + // (which should never happen), we never return an incomplete global. + // At worst, we would allocate storage for the path twice. + gApplicationDataDir = storage; + gApplicationDataDirIncognito = incognitoStorage; + } + + return gApplicationDataDir; +} + +static const char* anp_getApplicationDataDirectoryV2(NPP instance) { + WebCore::PluginView* pluginView = pluginViewForInstance(instance); + PluginWidgetAndroid* pluginWidget = pluginView->platformPluginWidget(); + + if (NULL == gApplicationDataDir) { + anp_getApplicationDataDirectory(); + } + + WebCore::Settings* settings = pluginWidget->webViewCore()->mainFrame()->settings(); + if (settings && settings->privateBrowsingEnabled()) { + // if this is an incognito view then check the path to see if it exists + // and if it is a directory, otherwise if it does not exist create it. + struct stat st; + if (stat(gApplicationDataDirIncognito, &st) == 0) { + if (!S_ISDIR(st.st_mode)) { + return NULL; + } + } else { + if (mkdir(gApplicationDataDirIncognito, S_IRWXU) != 0) { + return NULL; + } + } + + return gApplicationDataDirIncognito; + } + + return gApplicationDataDir; +} + +static jclass anp_loadJavaClass(NPP instance, const char* className) { + WebCore::PluginView* pluginView = pluginViewForInstance(instance); + PluginWidgetAndroid* pluginWidget = pluginView->platformPluginWidget(); + + jclass result; + result = pluginWidget->webViewCore()->getPluginClass(pluginView->plugin()->path(), + className); + return result; +} + +static void anp_setPowerState(NPP instance, ANPPowerState powerState) { + WebCore::PluginView* pluginView = pluginViewForInstance(instance); + PluginWidgetAndroid* pluginWidget = pluginView->platformPluginWidget(); + + pluginWidget->setPowerState(powerState); +} + +/////////////////////////////////////////////////////////////////////////////// + +#define ASSIGN(obj, name) (obj)->name = anp_##name + +void ANPSystemInterfaceV0_Init(ANPInterface* v) { + ANPSystemInterfaceV0* i = reinterpret_cast(v); + + ASSIGN(i, getApplicationDataDirectory); + ASSIGN(i, loadJavaClass); +} + +void ANPSystemInterfaceV1_Init(ANPInterface* v) { + // initialize the functions from the previous interface + ANPSystemInterfaceV0_Init(v); + // add any new functions or override existing functions + ANPSystemInterfaceV1* i = reinterpret_cast(v); + ASSIGN(i, setPowerState); +} + +void ANPSystemInterfaceV2_Init(ANPInterface* v) { + // initialize the functions from the previous interface + ANPSystemInterfaceV1_Init(v); + // add any new functions or override existing functions + ANPSystemInterfaceV2* i = reinterpret_cast(v); + i->getApplicationDataDirectory = anp_getApplicationDataDirectoryV2; +} + +/////////////////////////////////////////////////////////////////////////////// + +static bool isDirectory(const char* path) { + struct stat st; + return stat(path, &st) == 0 && S_ISDIR(st.st_mode); +} + +static void removeDirectory(const char* path) { + // create a pointer to a directory + DIR *dir = NULL; + dir = opendir(path); + if (!dir) + return; + + struct dirent* entry = 0; + while ((entry = readdir(dir))) { // while there is still something in the directory to list + if (!entry) + return; + + if (!strcmp(".", entry->d_name) || !strcmp("..", entry->d_name)) { + PLUGIN_LOG(". file: %s", entry->d_name); + continue; + } + + // concatenate the strings to get the complete path + static const char separator[] = "/"; + char* file = (char*) malloc(strlen(path) + strlen(separator) + strlen(entry->d_name) + 1); + strcpy(file, path); + strcat(file, separator); + strcat(file, entry->d_name); + + if (isDirectory(file) == true) { + PLUGIN_LOG("remove dir: %s", file); + removeDirectory(file); + } else { // it's a file, we can use remove + PLUGIN_LOG("remove file: %s", file); + remove(file); + } + + free(file); + } + + // clean up + closedir (dir); // close the directory + rmdir(path); // delete the directory +} + +void ANPSystemInterface_CleanupIncognito() { + PLUGIN_LOG("cleanup incognito plugin directory"); + + if (gApplicationDataDirIncognito == NULL) + anp_getApplicationDataDirectory(); + if (gApplicationDataDirIncognito == NULL) + return; + + // check to see if the directory exists and if so delete it + if (isDirectory(gApplicationDataDirIncognito)) + removeDirectory(gApplicationDataDirIncognito); +} diff --git a/Source/WebKit/android/plugins/ANPSystem_npapi.h b/Source/WebKit/android/plugins/ANPSystem_npapi.h new file mode 100644 index 0000000..835bc7c --- /dev/null +++ b/Source/WebKit/android/plugins/ANPSystem_npapi.h @@ -0,0 +1,72 @@ +/* + * 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 ANPSystem_npapi_H +#define ANPSystem_npapi_H + +#include "android_npapi.h" +#include + +struct ANPSystemInterfaceV0 : ANPInterface { + /** Return the path name for the current Application's plugin data directory, + or NULL if not supported + */ + const char* (*getApplicationDataDirectory)(); + + /** A helper function to load java classes from the plugin's apk. The + function looks for a class given the fully qualified and null terminated + string representing the className. For example, + + const char* className = "com.android.mypackage.MyClass"; + + If the class cannot be found or there is a problem loading the class + NULL will be returned. + */ + jclass (*loadJavaClass)(NPP instance, const char* className); +}; + +enum ANPPowerStates { + kDefault_ANPPowerState = 0, + kScreenOn_ANPPowerState = 1 +}; +typedef int32_t ANPPowerState; + +struct ANPSystemInterfaceV1 : ANPSystemInterfaceV0 { + void (*setPowerState)(NPP instance, ANPPowerState powerState); +}; + +struct ANPSystemInterfaceV2 : ANPInterface { + /** Return the path name for the current Application's plugin data directory, + or NULL if not supported. This directory will change depending on whether + or not the plugin is found within an incognito tab. + */ + const char* (*getApplicationDataDirectory)(NPP instance); + + // redeclaration of existing features + jclass (*loadJavaClass)(NPP instance, const char* className); + void (*setPowerState)(NPP instance, ANPPowerState powerState); +}; + +#endif //ANPSystem_npapi_H diff --git a/Source/WebKit/android/plugins/ANPTypefaceInterface.cpp b/Source/WebKit/android/plugins/ANPTypefaceInterface.cpp new file mode 100644 index 0000000..99734a7 --- /dev/null +++ b/Source/WebKit/android/plugins/ANPTypefaceInterface.cpp @@ -0,0 +1,104 @@ +/* + * 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. + */ + +// must include config.h first for webkit to fiddle with new/delete +#include "config.h" +#include "SkANP.h" +#include "SkFontHost.h" + +static ANPTypeface* anp_createFromName(const char name[], ANPTypefaceStyle s) { + SkTypeface* tf = SkTypeface::CreateFromName(name, + static_cast(s)); + return reinterpret_cast(tf); +} + +static ANPTypeface* anp_createFromTypeface(const ANPTypeface* family, + ANPTypefaceStyle s) { + SkTypeface* tf = SkTypeface::CreateFromTypeface(family, + static_cast(s)); + return reinterpret_cast(tf); +} + +static int32_t anp_getRefCount(const ANPTypeface* tf) { + return tf ? tf->getRefCnt() : 0; +} + +static void anp_ref(ANPTypeface* tf) { + SkSafeRef(tf); +} + +static void anp_unref(ANPTypeface* tf) { + SkSafeUnref(tf); +} + +static ANPTypefaceStyle anp_getStyle(const ANPTypeface* tf) { + SkTypeface::Style s = tf ? tf->style() : SkTypeface::kNormal; + return static_cast(s); +} + +static int32_t anp_getFontPath(const ANPTypeface* tf, char fileName[], + int32_t length, int32_t* index) { + size_t size = SkFontHost::GetFileName(SkTypeface::UniqueID(tf), fileName, + length, index); + return static_cast(size); +} + +static const char* gFontDir; +#define FONT_DIR_SUFFIX "/fonts/" + +static const char* anp_getFontDirectoryPath() { + if (NULL == gFontDir) { + const char* root = getenv("ANDROID_ROOT"); + size_t len = strlen(root); + char* storage = (char*)malloc(len + sizeof(FONT_DIR_SUFFIX)); + if (NULL == storage) { + return NULL; + } + memcpy(storage, root, len); + memcpy(storage + len, FONT_DIR_SUFFIX, sizeof(FONT_DIR_SUFFIX)); + // save this assignment for last, so that if multiple threads call us + // (which should never happen), we never return an incomplete global. + // At worst, we would allocate storage for the path twice. + gFontDir = storage; + } + return gFontDir; +} + +/////////////////////////////////////////////////////////////////////////////// + +#define ASSIGN(obj, name) (obj)->name = anp_##name + +void ANPTypefaceInterfaceV0_Init(ANPInterface* v) { + ANPTypefaceInterfaceV0* i = reinterpret_cast(v); + + ASSIGN(i, createFromName); + ASSIGN(i, createFromTypeface); + ASSIGN(i, getRefCount); + ASSIGN(i, ref); + ASSIGN(i, unref); + ASSIGN(i, getStyle); + ASSIGN(i, getFontPath); + ASSIGN(i, getFontDirectoryPath); +} diff --git a/Source/WebKit/android/plugins/ANPVideoInterface.cpp b/Source/WebKit/android/plugins/ANPVideoInterface.cpp new file mode 100644 index 0000000..8eb9846 --- /dev/null +++ b/Source/WebKit/android/plugins/ANPVideoInterface.cpp @@ -0,0 +1,83 @@ +/* + * 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. + */ + +// must include config.h first for webkit to fiddle with new/delete +#include "config.h" +#include "ANPVideo_npapi.h" +#include "SkANP.h" + +#include "PluginView.h" +#include "PluginWidgetAndroid.h" +#include "MediaLayer.h" + +static WebCore::PluginView* pluginViewForInstance(NPP instance) { + if (instance && instance->ndata) + return static_cast(instance->ndata); + return WebCore::PluginView::currentPluginView(); +} + +static WebCore::MediaLayer* mediaLayerForInstance(NPP instance) { + WebCore::PluginView* pluginView = pluginViewForInstance(instance); + PluginWidgetAndroid* pluginWidget = pluginView->platformPluginWidget(); + return pluginWidget->getLayer(); +} + +static ANativeWindow* anp_acquireNativeWindow(NPP instance) { + WebCore::MediaLayer* mediaLayer = mediaLayerForInstance(instance); + + return mediaLayer->acquireNativeWindowForVideo(); +} + +static void anp_setWindowDimensions(NPP instance, const ANativeWindow* window, + const ANPRectF* dimensions) { + + WebCore::MediaLayer* mediaLayer = mediaLayerForInstance(instance); + if (!mediaLayer) + return; + + SkRect rect; + mediaLayer->setWindowDimensionsForVideo(window, *SkANP::SetRect(&rect, *dimensions)); +} + + +static void anp_releaseNativeWindow(NPP instance, ANativeWindow* window) { + WebCore::MediaLayer* mediaLayer = mediaLayerForInstance(instance); + if (!mediaLayer) + return; + + mediaLayer->releaseNativeWindowForVideo(window); +} + +/////////////////////////////////////////////////////////////////////////////// + +#define ASSIGN(obj, name) (obj)->name = anp_##name + +void ANPVideoInterfaceV0_Init(ANPInterface* value) { + ANPVideoInterfaceV0* i = reinterpret_cast(value); + + ASSIGN(i, acquireNativeWindow); + ASSIGN(i, setWindowDimensions); + ASSIGN(i, releaseNativeWindow); +} diff --git a/Source/WebKit/android/plugins/ANPVideo_npapi.h b/Source/WebKit/android/plugins/ANPVideo_npapi.h new file mode 100644 index 0000000..18e0231 --- /dev/null +++ b/Source/WebKit/android/plugins/ANPVideo_npapi.h @@ -0,0 +1,61 @@ +/* + * 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 ANPVideo_npapi_H +#define ANPVideo_npapi_H + +#include "android_npapi.h" +#include + +struct ANPVideoInterfaceV0 : ANPInterface { + + /** + * Constructs a new native window to be used for rendering video content. + * + * Subsequent calls will produce new windows, but may also return NULL after + * n attempts if the browser has reached it's limit. Further, if the browser + * is unable to acquire the window quickly it may also return NULL in order + * to not prevent the plugin from executing. A subsequent call will then + * return the window if it is avaiable. + * + * NOTE: The hardware may fail if you try to decode more than the allowable + * number of videos supported on that device. + */ + ANativeWindow* (*acquireNativeWindow)(NPP instance); + + /** + * Sets the rectangle that specifies where the video content is to be drawn. + * The dimensions are in document space. Further, if the rect is NULL the + * browser will not attempt to draw the window, therefore do not set the + * dimensions until you queue the first buffer in the window. + */ + void (*setWindowDimensions)(NPP instance, const ANativeWindow* window, const ANPRectF* dimensions); + + /** + */ + void (*releaseNativeWindow)(NPP instance, ANativeWindow* window); +}; + +#endif //ANPVideo_npapi_H diff --git a/Source/WebKit/android/plugins/ANPWindowInterface.cpp b/Source/WebKit/android/plugins/ANPWindowInterface.cpp new file mode 100644 index 0000000..a74616c --- /dev/null +++ b/Source/WebKit/android/plugins/ANPWindowInterface.cpp @@ -0,0 +1,103 @@ +/* + * 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. + */ + +// must include config.h first for webkit to fiddle with new/delete +#include "config.h" +#include "SkANP.h" +#include "WebViewCore.h" +#include "PluginView.h" +#include "PluginWidgetAndroid.h" + +static PluginView* pluginViewForInstance(NPP instance) { + if (instance && instance->ndata) + return static_cast(instance->ndata); + return PluginView::currentPluginView(); +} + +static void anp_setVisibleRects(NPP instance, const ANPRectI rects[], int32_t count) { + PluginView* pluginView = pluginViewForInstance(instance); + PluginWidgetAndroid* pluginWidget = pluginView->platformPluginWidget(); + pluginWidget->setVisibleRects(rects, count); +} + +static void anp_clearVisibleRects(NPP instance) { + anp_setVisibleRects(instance, NULL, 0); +} + +static void anp_showKeyboard(NPP instance, bool value) { + PluginView* pluginView = pluginViewForInstance(instance); + PluginWidgetAndroid* pluginWidget = pluginView->platformPluginWidget(); + if(pluginWidget->hasFocus()) + pluginWidget->webViewCore()->requestKeyboard(value); +} + +static void anp_requestFullScreen(NPP instance) { + PluginView* pluginView = pluginViewForInstance(instance); + // call focusPluginElement() so that the pluginView receives keyboard events + pluginView->focusPluginElement(); + PluginWidgetAndroid* pluginWidget = pluginView->platformPluginWidget(); + pluginWidget->requestFullScreen(); +} + +static void anp_exitFullScreen(NPP instance) { + PluginView* pluginView = pluginViewForInstance(instance); + PluginWidgetAndroid* pluginWidget = pluginView->platformPluginWidget(); + pluginWidget->exitFullScreen(true); +} + +static void anp_requestCenterFitZoom(NPP instance) { + PluginView* pluginView = pluginViewForInstance(instance); + PluginWidgetAndroid* pluginWidget = pluginView->platformPluginWidget(); + pluginWidget->requestCenterFitZoom(); +} + +static ANPRectI anp_visibleRect(NPP instance) { + PluginView* pluginView = pluginViewForInstance(instance); + PluginWidgetAndroid* pluginWidget = pluginView->platformPluginWidget(); + return pluginWidget->visibleRect(); +} + +/////////////////////////////////////////////////////////////////////////////// + +#define ASSIGN(obj, name) (obj)->name = anp_##name + +void ANPWindowInterfaceV0_Init(ANPInterface* value) { + ANPWindowInterfaceV0* i = reinterpret_cast(value); + + ASSIGN(i, setVisibleRects); + ASSIGN(i, clearVisibleRects); + ASSIGN(i, showKeyboard); + ASSIGN(i, requestFullScreen); + ASSIGN(i, exitFullScreen); + ASSIGN(i, requestCenterFitZoom); +} + +void ANPWindowInterfaceV1_Init(ANPInterface* value) { + // initialize the functions from the previous interface + ANPWindowInterfaceV0_Init(value); + // add any new functions or override existing functions + ANPWindowInterfaceV1* i = reinterpret_cast(value); + ASSIGN(i, visibleRect); +} diff --git a/Source/WebKit/android/plugins/PluginDebugAndroid.cpp b/Source/WebKit/android/plugins/PluginDebugAndroid.cpp new file mode 100644 index 0000000..3958714 --- /dev/null +++ b/Source/WebKit/android/plugins/PluginDebugAndroid.cpp @@ -0,0 +1,137 @@ +/* + * 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 "PluginDebugAndroid.h" +#include "utils/Log.h" +#include "utils/SystemClock.h" +#include + +#define ARRAY_COUNT(array) static_cast(sizeof(array) / sizeof(array[0])) + +// used for key, mouse, and touch inputs +static const char* const inputActions[] = { + "down", + "up", + "move", /* touch only */ + "cancel", /* touch only */ + "longPress", /* touch only */ + "doubleTap" /* touch only */ +}; + +static const char* const lifecycleActions[] = { + "kPause_ANPLifecycleAction", + "kResume_ANPLifecycleAction", + "kGainFocus_ANPLifecycleAction", + "kLoseFocus_ANPLifecycleAction", + "kFreeMemory_ANPLifecycleAction", + "kOnLoad_ANPLifecycleAction", + "kEnterFullScreen_ANPLifecycleAction", + "kExitFullScreen_ANPLifecycleAction", + "kOnScreen_ANPLifecycleAction", + "kOffScreen_ANPLifecycleAction" +}; + +void anp_logPlugin(const char format[], ...) { + va_list args; + va_start(args, format); + LOG_PRI_VA(ANDROID_LOG_DEBUG, "webkit_plugin", format, args); + va_end(args); +} + +void anp_logPluginEvent(void* npp, const ANPEvent* evt, int16_t returnVal, int elapsedTime) { + + switch(evt->eventType) { + + case kNull_ANPEventType: + PLUGIN_LOG("%p EVENT::NULL", npp); + break; + + case kKey_ANPEventType: + if(evt->data.key.action < ARRAY_COUNT(inputActions)) { + anp_logPlugin("%p EVENT::KEY[%d] time=%d action=%s code=%d vcode=%d unichar=%d repeat=%d mods=%x", + npp, returnVal, elapsedTime, inputActions[evt->data.key.action], + evt->data.key.nativeCode, evt->data.key.virtualCode, + evt->data.key.unichar, evt->data.key.repeatCount, + evt->data.key.modifiers); + } else { + PLUGIN_LOG("%p EVENT::KEY[%d] unknown action", npp, returnVal); + } + break; + + case kMouse_ANPEventType: + if(evt->data.mouse.action < ARRAY_COUNT(inputActions)) { + anp_logPlugin("%p EVENT::MOUSE[%d] time=%d action=%s [%d %d]", npp, + returnVal, elapsedTime, inputActions[evt->data.mouse.action], + evt->data.touch.x, evt->data.touch.y); + } else { + anp_logPlugin("%p EVENT::MOUSE[%d] unknown action", npp, returnVal); + } + break; + + case kTouch_ANPEventType: + if(evt->data.touch.action < ARRAY_COUNT(inputActions)) { + + anp_logPlugin("%p EVENT::TOUCH[%d] time=%d action=%s [%d %d]", + npp, returnVal, elapsedTime, + inputActions[evt->data.touch.action], evt->data.touch.x, + evt->data.touch.y); + } else { + anp_logPlugin("%p EVENT::TOUCH[%d] unknown action", npp, returnVal); + } + break; + + case kDraw_ANPEventType: + if (evt->data.draw.model == kBitmap_ANPDrawingModel) { + anp_logPlugin("%p EVENT::DRAW bitmap time=%d format=%d clip=[%d,%d,%d,%d]", + npp, elapsedTime, evt->data.draw.data.bitmap.format, + evt->data.draw.clip.left, evt->data.draw.clip.top, + evt->data.draw.clip.right, evt->data.draw.clip.bottom); + } else if (evt->data.draw.model == kOpenGL_ANPDrawingModel) { + anp_logPlugin("%p EVENT::DRAW openGL time=%d dimensions=[%d,%d]", + npp, elapsedTime, evt->data.draw.data.surface.width, + evt->data.draw.data.surface.height); + } else { + anp_logPlugin("%p EVENT::DRAW unknown drawing model", npp); + } + break; + + case kLifecycle_ANPEventType: + if(evt->data.lifecycle.action < ARRAY_COUNT(lifecycleActions)) { + anp_logPlugin("%p EVENT::LIFECYCLE time=%d action=%s", npp, elapsedTime, + lifecycleActions[evt->data.lifecycle.action]); + } else { + anp_logPlugin("%p EVENT::LIFECYCLE unknown action", npp); + } + break; + + case kCustom_ANPEventType: + anp_logPlugin("%p EVENT::CUSTOM time=%d", npp, elapsedTime); + break; + + default: + anp_logPlugin("%p EVENT::UNKNOWN", npp); + break; + } +} diff --git a/Source/WebKit/android/plugins/PluginDebugAndroid.h b/Source/WebKit/android/plugins/PluginDebugAndroid.h new file mode 100644 index 0000000..5002882 --- /dev/null +++ b/Source/WebKit/android/plugins/PluginDebugAndroid.h @@ -0,0 +1,58 @@ +/* + * 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 PLUGIN_DEBUG_ANDROID_H__ +#define PLUGIN_DEBUG_ANDROID_H__ + +#include "android_npapi.h" + +// Define PLUGIN_DEBUG_LOCAL in an individual C++ file to enable for +// that file only. + +// Define PLUGIN_DEBUG_GLOBAL to 1 to turn plug-in debug for all +// Android plug-in code in this directory. +#define PLUGIN_DEBUG_GLOBAL 0 + +#if PLUGIN_DEBUG_GLOBAL || defined(PLUGIN_DEBUG_LOCAL) +# define PLUGIN_LOG(FORMAT, ARGS...) do { anp_logPlugin(FORMAT, ## ARGS); } while(0) +# define PLUGIN_LOG_EVENT(NPP, EVT, RET, TIME) do { anp_logPluginEvent(NPP, EVT, RET, TIME); } while(0) + +/* Logs the given character array and optional arguments. All log entries use + the DEBUG priority and use the same "webkit_plugin" log tag. + */ +void anp_logPlugin(const char format[], ...); +/* Logs a user readable description of a plugin event. The relevant contents of + each event are logged, as well as the value returned by the plugin instance + and how long the instance took to process the event (in milliseconds). + */ +void anp_logPluginEvent(void* npp, const ANPEvent* event, int16_t returnVal, int elapsedTime); + +#else +# define PLUGIN_LOG(A, B...) do { } while(0) +# define PLUGIN_LOG_EVENT(NPP, EVT, RET, TIME) do { } while(0) + +#endif + +#endif // defined(PLUGIN_DEBUG_ANDROID_H__) diff --git a/Source/WebKit/android/plugins/PluginTimer.cpp b/Source/WebKit/android/plugins/PluginTimer.cpp new file mode 100644 index 0000000..dfa7272 --- /dev/null +++ b/Source/WebKit/android/plugins/PluginTimer.cpp @@ -0,0 +1,135 @@ +/* + * Copyright 2009, The Android Open Source Project + * Copyright (C) 2008 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. + * + * 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 "PluginTimer.h" +#include "RefPtr.h" + +namespace WebCore { + + static uint32_t gTimerID; + + PluginTimer::PluginTimer(PluginTimer** list, NPP instance, bool repeat, + void (*timerFunc)(NPP npp, uint32_t timerID)) + : m_list(list), + m_instance(instance), + m_timerFunc(timerFunc), + m_repeat(repeat), + m_unscheduled(false) + { + m_timerID = ++gTimerID; + + m_next = *list; + if (m_next) { + m_next->m_prev = this; + } + m_prev = 0; + *list = this; + relaxAdoptionRequirement(); + } + + PluginTimer::~PluginTimer() + { + if (m_next) { + m_next->m_prev = m_prev; + } + if (m_prev) { + m_prev->m_next = m_next; + } else { + *m_list = m_next; + } + } + + void PluginTimer::fired() + { + // ensure the timer cannot be deleted until this method completes + RefPtr protector(this); + + if (!m_unscheduled) + m_timerFunc(m_instance, m_timerID); + + // remove the timer if it is a one-shot timer (!m_repeat) or if is a + // repeating timer that has been unscheduled. In either case we must + // ensure that the refcount is 2 or greater since the PluginTimerList + // could have been deleted by the timerFunc and we must ensure that we + // do not double delete. + if ((!m_repeat || m_unscheduled) && refCount() > 1) + deref(); // mark the timer for deletion as it is no longer needed + } + + // may return null if timerID is not found + PluginTimer* PluginTimer::Find(PluginTimer* list, uint32_t timerID) + { + PluginTimer* curr = list; + while (curr) { + if (curr->m_timerID == timerID) { + break; + } + curr = curr->m_next; + } + return curr; + } + + /////////////////////////////////////////////////////////////////////////// + + PluginTimerList::~PluginTimerList() + { + PluginTimer* curr = m_list; + PluginTimer* next; + while (curr) { + next = curr->next(); + curr->deref(); + curr = next; + } + } + + uint32_t PluginTimerList::schedule(NPP instance, uint32_t interval, bool repeat, + void (*proc)(NPP npp, uint32_t timerID)) + { + PluginTimer* timer = new PluginTimer(&m_list, instance, repeat, proc); + + double dinterval = interval * 0.001; // milliseconds to seconds + if (repeat) { + timer->startRepeating(dinterval); + } else { + timer->startOneShot(dinterval); + } + return timer->timerID(); + } + + void PluginTimerList::unschedule(NPP instance, uint32_t timerID) + { + // Although it looks like simply deleting the timer would work here + // (stop() will be executed by the dtor), we cannot do this, as + // the plugin can call us while we are in the fired() method, + // (when we execute the timerFunc callback). Deleting the object + // we are in would then be a rather bad move... + PluginTimer* timer = PluginTimer::Find(m_list, timerID); + if (timer) + timer->unschedule(); + } + +} // namespace WebCore diff --git a/Source/WebKit/android/plugins/PluginTimer.h b/Source/WebKit/android/plugins/PluginTimer.h new file mode 100644 index 0000000..20c0816 --- /dev/null +++ b/Source/WebKit/android/plugins/PluginTimer.h @@ -0,0 +1,82 @@ +/* + * Copyright 2009, The Android Open Source Project + * Copyright (C) 2008 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. + * + * 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 PluginTimer_H +#define PluginTimer_H + +#include "RefCounted.h" +#include "Timer.h" +#include "npapi.h" + +namespace WebCore { + + class PluginTimerList; + + class PluginTimer : public TimerBase, public RefCounted { + public: + PluginTimer(PluginTimer** list, NPP instance, bool repeat, + void (*proc)(NPP npp, uint32_t timerID)); + virtual ~PluginTimer(); + + uint32_t timerID() const { return m_timerID; } + + void unschedule() { m_unscheduled = true; } + + static PluginTimer* Find(PluginTimer* list, uint32_t timerID); + + private: + // override from TimerBase + virtual void fired(); + + PluginTimer* next() const { return m_next; } + friend class PluginTimerList; + + PluginTimer** m_list; + PluginTimer* m_prev; + PluginTimer* m_next; + NPP m_instance; + void (*m_timerFunc)(NPP, uint32_t); + uint32_t m_timerID; + bool m_repeat; + bool m_unscheduled; + }; + + class PluginTimerList { + public: + PluginTimerList() : m_list(0) {} + ~PluginTimerList(); + + uint32_t schedule(NPP instance, uint32_t interval, bool repeat, + void (*proc)(NPP npp, uint32_t timerID)); + void unschedule(NPP instance, uint32_t timerID); + + private: + PluginTimer* m_list; + }; + +} // namespace WebCore + +#endif diff --git a/Source/WebKit/android/plugins/PluginViewBridgeAndroid.cpp b/Source/WebKit/android/plugins/PluginViewBridgeAndroid.cpp new file mode 100644 index 0000000..2be9dc3 --- /dev/null +++ b/Source/WebKit/android/plugins/PluginViewBridgeAndroid.cpp @@ -0,0 +1,38 @@ +/* + * 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. + */ + +#include "config.h" +#include "PluginViewBridgeAndroid.h" + +namespace WebCore { + + void PluginViewBridgeAndroid::draw(GraphicsContext* gc, + const IntRect& rect) {} + + bool PluginViewBridgeAndroid::forPluginView() const { + return true; + } + +} diff --git a/Source/WebKit/android/plugins/PluginViewBridgeAndroid.h b/Source/WebKit/android/plugins/PluginViewBridgeAndroid.h new file mode 100644 index 0000000..5d16f46 --- /dev/null +++ b/Source/WebKit/android/plugins/PluginViewBridgeAndroid.h @@ -0,0 +1,48 @@ +/* + * Copyright 2009, The Android Open Source Project + * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008 Collabora Ltd. 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. + * + * 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 PluginViewBridgeAndroid_H +#define PluginViewBridgeAndroid_H + +#include "PluginView.h" +#include "WebCoreViewBridge.h" + +namespace WebCore { + + // (Dummy for now) WebCoreViewBridge associated with a PluginView Widget. + class PluginViewBridgeAndroid : public WebCoreViewBridge { + public: + PluginViewBridgeAndroid() {} + + // overrides + virtual void draw(GraphicsContext* gc, const IntRect& rect); + virtual bool forPluginView() const; + }; + +} // namespace WebCore + +#endif diff --git a/Source/WebKit/android/plugins/PluginWidgetAndroid.cpp b/Source/WebKit/android/plugins/PluginWidgetAndroid.cpp new file mode 100644 index 0000000..b8a10cc --- /dev/null +++ b/Source/WebKit/android/plugins/PluginWidgetAndroid.cpp @@ -0,0 +1,690 @@ +/* + * 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. + */ + +#include "config.h" +#include "PluginWidgetAndroid.h" + +#if ENABLE(TOUCH_EVENTS) +#include "ChromeClient.h" +#endif +#include "Document.h" +#include "Element.h" +#include "Frame.h" +#include "Page.h" +#include "PluginPackage.h" +#include "PluginView.h" +#include "PluginWidgetAndroid.h" +#include "ScrollView.h" +#include "SkANP.h" +#include "SkFlipPixelRef.h" +#include "SkString.h" +#include "SkTime.h" +#include "WebViewCore.h" +#include "android_graphics.h" +#include + +// #define PLUGIN_DEBUG_LOCAL // controls the printing of log messages +#define DEBUG_EVENTS 0 // logs event contents, return value, and processing time +#define DEBUG_VISIBLE_RECTS 0 // temporary debug printfs and fixes + +// this include statement must follow the declaration of PLUGIN_DEBUG_LOCAL +#include "PluginDebugAndroid.h" + +PluginWidgetAndroid::PluginWidgetAndroid(WebCore::PluginView* view) + : m_pluginView(view) { + m_flipPixelRef = NULL; + m_core = NULL; + m_drawingModel = kBitmap_ANPDrawingModel; + m_eventFlags = 0; + m_pluginWindow = NULL; + m_requestedVisibleRectCount = 0; + m_requestedVisibleRect.setEmpty(); + m_visibleDocRect.setEmpty(); + m_pluginBounds.setEmpty(); + m_hasFocus = false; + m_isFullScreen = false; + m_visible = false; + m_cachedZoomLevel = 0; + m_embeddedView = NULL; + m_embeddedViewAttached = false; + m_acceptEvents = false; + m_isSurfaceClippedOut = false; + m_layer = 0; + m_powerState = kDefault_ANPPowerState; +} + +PluginWidgetAndroid::~PluginWidgetAndroid() { + PLUGIN_LOG("%p Deleting Plugin", m_pluginView->instance()); + m_acceptEvents = false; + if (m_core) { + setPowerState(kDefault_ANPPowerState); + m_core->removePlugin(this); + if (m_isFullScreen) { + exitFullScreen(true); + } + if (m_embeddedView) { + m_core->destroySurface(m_embeddedView); + } + } + + // cleanup any remaining JNI References + JNIEnv* env = JSC::Bindings::getJNIEnv(); + if (m_embeddedView) { + env->DeleteGlobalRef(m_embeddedView); + } + + SkSafeUnref(m_flipPixelRef); + + if (m_layer) + m_layer->unref(); +} + +void PluginWidgetAndroid::init(android::WebViewCore* core) { + m_core = core; + m_core->addPlugin(this); + m_acceptEvents = true; + PLUGIN_LOG("%p Initialized Plugin", m_pluginView->instance()); +} + +static SkBitmap::Config computeConfig(bool isTransparent) { + return isTransparent ? SkBitmap::kARGB_8888_Config + : SkBitmap::kRGB_565_Config; +} + +void PluginWidgetAndroid::setWindow(NPWindow* window, bool isTransparent) { + + // store the reference locally for easy lookup + m_pluginWindow = window; + + // make a copy of the previous bounds + SkIRect oldPluginBounds = m_pluginBounds; + + // keep a local copy of the plugin bounds because the m_pluginWindow pointer + // gets updated values prior to this method being called + m_pluginBounds.set(m_pluginWindow->x, m_pluginWindow->y, + m_pluginWindow->x + m_pluginWindow->width, + m_pluginWindow->y + m_pluginWindow->height); + + PLUGIN_LOG("%p PluginBounds (%d,%d,%d,%d)", m_pluginView->instance(), + m_pluginBounds.fLeft, m_pluginBounds.fTop, + m_pluginBounds.fRight, m_pluginBounds.fBottom); + + const bool boundsChanged = m_pluginBounds != oldPluginBounds; + + //TODO hack to ensure that we grab the most recent screen dimensions and scale + ANPRectI screenCoords; + m_core->getVisibleScreen(screenCoords); + float scale = m_core->scale(); + bool scaleChanged = m_cachedZoomLevel != scale; + setVisibleScreen(screenCoords, scale); + + // if the scale changed then setVisibleScreen will call this function and + // this call will potentially fire a duplicate draw event + if (!scaleChanged) { + sendSizeAndVisibilityEvents(boundsChanged); + } + layoutSurface(boundsChanged); + + if (m_drawingModel != kSurface_ANPDrawingModel) { + SkSafeUnref(m_flipPixelRef); + m_flipPixelRef = new SkFlipPixelRef(computeConfig(isTransparent), + window->width, window->height); + } +} + +bool PluginWidgetAndroid::setDrawingModel(ANPDrawingModel model) { + + if (model == kOpenGL_ANPDrawingModel && m_layer == 0) { + JNIEnv* env = JSC::Bindings::getJNIEnv(); + jobject webview = m_core->getWebViewJavaObject(); + jobject weakWebViewRef = 0; + if (webview) + weakWebViewRef = env->NewWeakGlobalRef(webview); + m_layer = new WebCore::MediaLayer(weakWebViewRef); + } + else if (model != kOpenGL_ANPDrawingModel && m_layer != 0) { + m_layer->unref(); + m_layer = 0; + } + + if (m_drawingModel != model) { + // Trigger layer computation in RenderLayerCompositor + m_pluginView->getElement()->setNeedsStyleRecalc(SyntheticStyleChange); + } + + m_drawingModel = model; + return true; +} + +// returned rect is in the page coordinate +bool PluginWidgetAndroid::isDirty(SkIRect* rect) const { + // nothing to report if we haven't had setWindow() called yet + if (NULL == m_flipPixelRef) { + return false; + } + + const SkRegion& dirty = m_flipPixelRef->dirtyRgn(); + if (dirty.isEmpty()) { + return false; + } else { + if (rect) { + *rect = dirty.getBounds(); + rect->offset(m_pluginWindow->x, m_pluginWindow->y); + } + return true; + } +} + +void PluginWidgetAndroid::inval(const WebCore::IntRect& rect, + bool signalRedraw) { + // nothing to do if we haven't had setWindow() called yet. m_flipPixelRef + // will also be null if this is a Surface model. + if (NULL == m_flipPixelRef) { + return; + } + + m_flipPixelRef->inval(rect); + + if (signalRedraw && m_flipPixelRef->isDirty()) { + m_core->invalPlugin(this); + } +} + +void PluginWidgetAndroid::viewInvalidate() { + WebCore::IntRect rect(m_pluginBounds.fLeft, m_pluginBounds.fTop, + m_pluginBounds.width(), m_pluginBounds.height()); + m_core->viewInvalidate(rect); +} + +void PluginWidgetAndroid::draw(SkCanvas* canvas) { + if (NULL == m_flipPixelRef || !m_flipPixelRef->isDirty()) { + return; + } + + SkAutoFlipUpdate update(m_flipPixelRef); + const SkBitmap& bitmap = update.bitmap(); + const SkRegion& dirty = update.dirty(); + + ANPEvent event; + SkANP::InitEvent(&event, kDraw_ANPEventType); + + event.data.draw.model = m_drawingModel; + SkANP::SetRect(&event.data.draw.clip, dirty.getBounds()); + + switch (m_drawingModel) { + case kBitmap_ANPDrawingModel: { + WebCore::PluginPackage* pkg = m_pluginView->plugin(); + NPP instance = m_pluginView->instance(); + + if (SkANP::SetBitmap(&event.data.draw.data.bitmap, + bitmap) && + pkg->pluginFuncs()->event(instance, &event)) { + + if (canvas && m_pluginWindow) { + SkBitmap bm(bitmap); + bm.setPixelRef(m_flipPixelRef); + canvas->drawBitmap(bm, 0, 0); + } + } + break; + } + default: + break; + } +} + +void PluginWidgetAndroid::setSurfaceClip(const SkIRect& clip) { + + if (m_drawingModel != kSurface_ANPDrawingModel) + return; + + /* don't display surfaces that are either entirely clipped or only 1x1 in + size. It appears that when an element is absolutely positioned and has + been completely clipped in CSS that webkit still sends a clip of 1x1. + */ + bool clippedOut = (clip.width() <= 1 && clip.height() <= 1); + if(clippedOut != m_isSurfaceClippedOut) { + m_isSurfaceClippedOut = clippedOut; + layoutSurface(); + } +} + +void PluginWidgetAndroid::layoutSurface(bool pluginBoundsChanged) { + + if (m_drawingModel != kSurface_ANPDrawingModel) + return; + if (!m_pluginWindow) + return; + + + bool displayPlugin = m_pluginView->isVisible() && !m_isSurfaceClippedOut; + PLUGIN_LOG("%p DisplayPlugin[%d] visible=[%d] clipped=[%d]", + m_pluginView->instance(), displayPlugin, + m_pluginView->isVisible(), m_isSurfaceClippedOut); + + // if the surface does not exist then create a new surface + if (!m_embeddedView && displayPlugin) { + + WebCore::PluginPackage* pkg = m_pluginView->plugin(); + NPP instance = m_pluginView->instance(); + + jobject pluginSurface; + pkg->pluginFuncs()->getvalue(instance, kJavaSurface_ANPGetValue, + static_cast(&pluginSurface)); + + jobject tempObj = m_core->addSurface(pluginSurface, + m_pluginWindow->x, m_pluginWindow->y, + m_pluginWindow->width, m_pluginWindow->height); + + if (tempObj) { + JNIEnv* env = JSC::Bindings::getJNIEnv(); + m_embeddedView = env->NewGlobalRef(tempObj); + m_embeddedViewAttached = true; + } + // if the view is unattached but visible then attach it + } else if (m_embeddedView && !m_embeddedViewAttached && displayPlugin && !m_isFullScreen) { + m_core->updateSurface(m_embeddedView, m_pluginWindow->x, m_pluginWindow->y, + m_pluginWindow->width, m_pluginWindow->height); + m_embeddedViewAttached = true; + // if the view is attached but invisible then remove it + } else if (m_embeddedView && m_embeddedViewAttached && !displayPlugin) { + m_core->destroySurface(m_embeddedView); + m_embeddedViewAttached = false; + // if the plugin's bounds have changed and it's visible then update it + } else if (pluginBoundsChanged && displayPlugin && !m_isFullScreen) { + m_core->updateSurface(m_embeddedView, m_pluginWindow->x, m_pluginWindow->y, + m_pluginWindow->width, m_pluginWindow->height); + + } +} + +int16_t PluginWidgetAndroid::sendEvent(const ANPEvent& evt) { + if (!m_acceptEvents) + return 0; + WebCore::PluginPackage* pkg = m_pluginView->plugin(); + NPP instance = m_pluginView->instance(); + // "missing" plugins won't have these + if (pkg && instance) { + + // if the plugin is gaining focus then update our state now to allow + // the plugin's event handler to perform actions that require focus + if (evt.eventType == kLifecycle_ANPEventType && + evt.data.lifecycle.action == kGainFocus_ANPLifecycleAction) { + m_hasFocus = true; + } + +#if DEBUG_EVENTS + SkMSec startTime = SkTime::GetMSecs(); +#endif + + // make a localCopy since the actual plugin may not respect its constness, + // and so we don't want our caller to have its param modified + ANPEvent localCopy = evt; + int16_t result = pkg->pluginFuncs()->event(instance, &localCopy); + +#if DEBUG_EVENTS + SkMSec endTime = SkTime::GetMSecs(); + PLUGIN_LOG_EVENT(instance, &evt, result, endTime - startTime); +#endif + + // if the plugin is losing focus then delay the update of our state + // until after we notify the plugin and allow them to perform actions + // that may require focus + if (evt.eventType == kLifecycle_ANPEventType && + evt.data.lifecycle.action == kLoseFocus_ANPLifecycleAction) { + m_hasFocus = false; + } + + return result; + } + return 0; +} + +void PluginWidgetAndroid::updateEventFlags(ANPEventFlags flags) { + + // if there are no differences then immediately return + if (m_eventFlags == flags) { + return; + } + + Document* doc = m_pluginView->parentFrame()->document(); +#if ENABLE(TOUCH_EVENTS) + if((m_eventFlags ^ flags) & kTouch_ANPEventFlag) { + if (flags & kTouch_ANPEventFlag) + doc->addListenerTypeIfNeeded(eventNames().touchstartEvent); + } +#endif + + m_eventFlags = flags; +} + +bool PluginWidgetAndroid::isAcceptingEvent(ANPEventFlag flag) { + return m_eventFlags & flag; +} + +void PluginWidgetAndroid::sendSizeAndVisibilityEvents(const bool updateDimensions) { + // TODO update the bitmap size based on the zoom? (for kBitmap_ANPDrawingModel) + + const float zoomLevel = m_core->scale(); + + // notify the plugin of the new size + if (m_drawingModel == kOpenGL_ANPDrawingModel && updateDimensions && m_pluginWindow) { + PLUGIN_LOG("%s (%d,%d)[%f]", __FUNCTION__, m_pluginWindow->width, + m_pluginWindow->height, zoomLevel); + ANPEvent event; + SkANP::InitEvent(&event, kDraw_ANPEventType); + event.data.draw.model = kOpenGL_ANPDrawingModel; + event.data.draw.data.surface.width = m_pluginWindow->width * zoomLevel; + event.data.draw.data.surface.height = m_pluginWindow->height * zoomLevel; + sendEvent(event); + } + + bool visible = SkIRect::Intersects(m_visibleDocRect, m_pluginBounds); + if(m_visible != visible) { + +#if DEBUG_VISIBLE_RECTS + PLUGIN_LOG("%p changeVisiblity[%d] pluginBounds(%d,%d,%d,%d)", + m_pluginView->instance(), visible, + m_pluginBounds.fLeft, m_pluginBounds.fTop, + m_pluginBounds.fRight, m_pluginBounds.fBottom); +#endif + + // change the visibility + m_visible = visible; + // send the event + ANPEvent event; + SkANP::InitEvent(&event, kLifecycle_ANPEventType); + event.data.lifecycle.action = visible ? kOnScreen_ANPLifecycleAction + : kOffScreen_ANPLifecycleAction; + sendEvent(event); + } +} + +void PluginWidgetAndroid::setVisibleScreen(const ANPRectI& visibleDocRect, float zoom) { +#if DEBUG_VISIBLE_RECTS + PLUGIN_LOG("%s (%d,%d,%d,%d)[%f]", __FUNCTION__, visibleDocRect.left, + visibleDocRect.top, visibleDocRect.right, + visibleDocRect.bottom, zoom); +#endif + int oldScreenW = m_visibleDocRect.width(); + int oldScreenH = m_visibleDocRect.height(); + + const bool zoomChanged = m_cachedZoomLevel != zoom; + + // make local copies of the parameters + m_cachedZoomLevel = zoom; + m_visibleDocRect.set(visibleDocRect.left, + visibleDocRect.top, + visibleDocRect.right, + visibleDocRect.bottom); + + int newScreenW = m_visibleDocRect.width(); + int newScreenH = m_visibleDocRect.height(); + + // if the screen dimensions have changed by more than 5 pixels in either + // direction then recompute the plugin's visible rectangle + if (abs(oldScreenW - newScreenW) > 5 || abs(oldScreenH - newScreenH) > 5) { + PLUGIN_LOG("%s VisibleDoc old=[%d,%d] new=[%d,%d] ", __FUNCTION__, + oldScreenW, oldScreenH, newScreenW, newScreenH); + computeVisiblePluginRect(); + } + + sendSizeAndVisibilityEvents(zoomChanged); +} + +ANPRectI PluginWidgetAndroid::visibleRect() { + + SkIRect visibleRect; + visibleRect.setEmpty(); + + // compute the interesection of the visible screen and the plugin + bool visible = visibleRect.intersect(m_visibleDocRect, m_pluginBounds); + if (visible) { + // convert from absolute coordinates to the plugin's relative coordinates + visibleRect.offset(-m_pluginBounds.fLeft, -m_pluginBounds.fTop); + } + + // convert from SkRect to ANPRect + ANPRectI result; + memcpy(&result, &visibleRect, sizeof(ANPRectI)); + return result; +} + +void PluginWidgetAndroid::setVisibleRects(const ANPRectI rects[], int32_t count) { +#if DEBUG_VISIBLE_RECTS + PLUGIN_LOG("%s count=%d", __FUNCTION__, count); +#endif + // ensure the count does not exceed our allocated space + if (count > MAX_REQUESTED_RECTS) + count = MAX_REQUESTED_RECTS; + + // store the values in member variables + m_requestedVisibleRectCount = count; + memcpy(m_requestedVisibleRects, rects, count * sizeof(rects[0])); + +#if DEBUG_VISIBLE_RECTS // FIXME: this fixes bad data from the plugin + // take it out once plugin supplies better data + for (int index = 0; index < count; index++) { + PLUGIN_LOG("%s [%d](%d,%d,%d,%d)", __FUNCTION__, index, + m_requestedVisibleRects[index].left, + m_requestedVisibleRects[index].top, + m_requestedVisibleRects[index].right, + m_requestedVisibleRects[index].bottom); + if (m_requestedVisibleRects[index].left == + m_requestedVisibleRects[index].right) { + m_requestedVisibleRects[index].right += 1; + } + if (m_requestedVisibleRects[index].top == + m_requestedVisibleRects[index].bottom) { + m_requestedVisibleRects[index].bottom += 1; + } + } +#endif + computeVisiblePluginRect(); +} + +void PluginWidgetAndroid::computeVisiblePluginRect() { + + // ensure the visibleDocRect has been set (i.e. not equal to zero) + if (m_visibleDocRect.isEmpty() || !m_pluginWindow || m_requestedVisibleRectCount < 1) + return; + + // create a rect that will contain as many of the rects that will fit on screen + SkIRect visibleRect; + visibleRect.setEmpty(); + + for (int counter = 0; counter < m_requestedVisibleRectCount; counter++) { + + ANPRectI* rect = &m_requestedVisibleRects[counter]; + + // create skia rect for easier manipulation and convert it to page coordinates + SkIRect pluginRect; + pluginRect.set(rect->left, rect->top, rect->right, rect->bottom); + pluginRect.offset(m_pluginWindow->x, m_pluginWindow->y); + + // ensure the rect falls within the plugin's bounds + if (!m_pluginBounds.contains(pluginRect)) { +#if DEBUG_VISIBLE_RECTS + PLUGIN_LOG("%s (%d,%d,%d,%d) !contain (%d,%d,%d,%d)", __FUNCTION__, + m_pluginBounds.fLeft, m_pluginBounds.fTop, + m_pluginBounds.fRight, m_pluginBounds.fBottom, + pluginRect.fLeft, pluginRect.fTop, + pluginRect.fRight, pluginRect.fBottom); + // assume that the desired outcome is to clamp to the container + if (pluginRect.intersect(m_pluginBounds)) { + visibleRect = pluginRect; + } +#endif + continue; + } + + // combine this new rect with the higher priority rects + pluginRect.join(visibleRect); + + // check to see if the new rect could be made to fit within the screen + // bounds. If this is the highest priority rect then attempt to center + // even if it doesn't fit on the screen. + if (counter > 0 && (m_visibleDocRect.width() < pluginRect.width() || + m_visibleDocRect.height() < pluginRect.height())) + break; + + // set the new visible rect + visibleRect = pluginRect; + } + + m_requestedVisibleRect = visibleRect; + scrollToVisiblePluginRect(); +} + +void PluginWidgetAndroid::scrollToVisiblePluginRect() { + + if (!m_hasFocus || m_requestedVisibleRect.isEmpty() || m_visibleDocRect.isEmpty()) { +#if DEBUG_VISIBLE_RECTS + PLUGIN_LOG("%s call m_hasFocus=%d m_requestedVisibleRect.isEmpty()=%d" + " m_visibleDocRect.isEmpty()=%d", __FUNCTION__, m_hasFocus, + m_requestedVisibleRect.isEmpty(), m_visibleDocRect.isEmpty()); +#endif + return; + } + // if the entire rect is already visible then we don't need to scroll + if (m_visibleDocRect.contains(m_requestedVisibleRect)) + return; + + // find the center of the visibleRect in document coordinates + int rectCenterX = m_requestedVisibleRect.fLeft + m_requestedVisibleRect.width()/2; + int rectCenterY = m_requestedVisibleRect.fTop + m_requestedVisibleRect.height()/2; + + // find document coordinates for center of the visible screen + int visibleDocCenterX = m_visibleDocRect.fLeft + m_visibleDocRect.width()/2; + int visibleDocCenterY = m_visibleDocRect.fTop + m_visibleDocRect.height()/2; + + //compute the delta of the two points and scale to screen coordinates + int deltaX = rectCenterX - visibleDocCenterX; + int deltaY = rectCenterY - visibleDocCenterY; + + ScrollView* scrollView = m_pluginView->parent(); + android::WebViewCore* core = android::WebViewCore::getWebViewCore(scrollView); +#if DEBUG_VISIBLE_RECTS + PLUGIN_LOG("%s call scrollBy (%d,%d)", __FUNCTION__, deltaX, deltaY); +#endif + core->scrollTo(rectCenterX, rectCenterY, true); +} + +void PluginWidgetAndroid::requestFullScreen() { + if (m_isFullScreen) { + return; + } + + if (!m_embeddedView && m_drawingModel == kOpenGL_ANPDrawingModel) { + WebCore::PluginPackage* pkg = m_pluginView->plugin(); + NPP instance = m_pluginView->instance(); + + jobject pluginSurface; + pkg->pluginFuncs()->getvalue(instance, kJavaSurface_ANPGetValue, + static_cast(&pluginSurface)); + + // create the surface, but do not add it to the view hierarchy + jobject tempObj = m_core->createSurface(pluginSurface); + + if (tempObj) { + JNIEnv* env = JSC::Bindings::getJNIEnv(); + m_embeddedView = env->NewGlobalRef(tempObj); + m_embeddedViewAttached = false; + } + } + + if (!m_embeddedView) { + return; + } + + // send event to notify plugin of full screen change + ANPEvent event; + SkANP::InitEvent(&event, kLifecycle_ANPEventType); + event.data.lifecycle.action = kEnterFullScreen_ANPLifecycleAction; + sendEvent(event); + + // remove the embedded surface from the view hierarchy + if (m_drawingModel != kOpenGL_ANPDrawingModel) + m_core->destroySurface(m_embeddedView); + + // add the full screen view + m_core->showFullScreenPlugin(m_embeddedView, m_pluginView->instance()); + m_isFullScreen = true; +} + +void PluginWidgetAndroid::exitFullScreen(bool pluginInitiated) { + if (!m_isFullScreen || !m_embeddedView) { + return; + } + + // remove the full screen surface from the view hierarchy + if (pluginInitiated) { + m_core->hideFullScreenPlugin(); + } + + // add the embedded view back + if (m_drawingModel != kOpenGL_ANPDrawingModel) + m_core->updateSurface(m_embeddedView, m_pluginWindow->x, m_pluginWindow->y, + m_pluginWindow->width, m_pluginWindow->height); + + // send event to notify plugin of full screen change + ANPEvent event; + SkANP::InitEvent(&event, kLifecycle_ANPEventType); + event.data.lifecycle.action = kExitFullScreen_ANPLifecycleAction; + sendEvent(event); + + m_isFullScreen = false; +} + +void PluginWidgetAndroid::requestCenterFitZoom() { + m_core->centerFitRect(m_pluginWindow->x, m_pluginWindow->y, + m_pluginWindow->width, m_pluginWindow->height); +} + +void PluginWidgetAndroid::setPowerState(ANPPowerState powerState) { + if(m_powerState == powerState) + return; + + // cleanup the old power state + switch (m_powerState) { + case kDefault_ANPPowerState: + break; + case kScreenOn_ANPPowerState: + m_core->keepScreenOn(false); + break; + } + + // setup the new power state + switch (powerState) { + case kDefault_ANPPowerState: + break; + case kScreenOn_ANPPowerState: + m_core->keepScreenOn(true); + break; + } + + m_powerState = powerState; +} + diff --git a/Source/WebKit/android/plugins/PluginWidgetAndroid.h b/Source/WebKit/android/plugins/PluginWidgetAndroid.h new file mode 100644 index 0000000..5d586b1 --- /dev/null +++ b/Source/WebKit/android/plugins/PluginWidgetAndroid.h @@ -0,0 +1,219 @@ +/* + * 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 PluginWidgetAndroid_H +#define PluginWidgetAndroid_H + +#include "android_npapi.h" +#include "ANPSystem_npapi.h" +#include "IntPoint.h" +#include "IntRect.h" +#include "MediaLayer.h" +#include "SkRect.h" +#include + +namespace WebCore { + class PluginView; +} + +namespace android { + class PluginSurface; + class WebViewCore; +} + +class SkCanvas; +class SkFlipPixelRef; + +/* + This is our extended state in a PluginView. This object is created and + kept insync with the PluginView, but is also available to WebViewCore + to allow its draw() method to be called from outside of the PluginView. + */ +struct PluginWidgetAndroid { + // initialize with our host pluginview. This will delete us when it is + // destroyed. + PluginWidgetAndroid(WebCore::PluginView* view); + ~PluginWidgetAndroid(); + + WebCore::PluginView* pluginView() const { return m_pluginView; } + + // Needed by PluginSurface to manage the java SurfaceView. + android::WebViewCore* webViewCore() const { return m_core; } + + /* Can't determine our core at construction time, so PluginView calls this + as soon as it has a parent. + */ + void init(android::WebViewCore*); + /* Called each time the PluginView gets a new size or position. + */ + void setWindow(NPWindow* window, bool isTransparent); + + /* Called whenever the plugin itself requests a new drawing model. If the + hardware does not support the requested model then false is returned, + otherwise true is returned. + */ + bool setDrawingModel(ANPDrawingModel); + + /* Called to check if the plugin is running in "windowed" mode (i.e. surface + view). + */ + bool isSurfaceDrawingModel() const { return kSurface_ANPDrawingModel == m_drawingModel; } + + bool isOpenGLDrawingModel() const { return kOpenGL_ANPDrawingModel == m_drawingModel; } + + /* Returns true (and optionally updates rect with the dirty bounds in the + page coordinate) if the plugin has invalidate us. + */ + bool isDirty(SkIRect* dirtyBounds = NULL) const; + /* Called by PluginView to invalidate a portion of the plugin area (in + local plugin coordinates). If signalRedraw is true, this also triggers + a subsequent call to draw(NULL). + */ + void inval(const WebCore::IntRect&, bool signalRedraw); + + /* Called to draw into the plugin's bitmap. If canvas is non-null, the + bitmap itself is then drawn into the canvas. + */ + void draw(SkCanvas* canvas = NULL); + + /* Send this event to the plugin instance. A non-zero value will be + returned if the plugin handled the event. + */ + int16_t sendEvent(const ANPEvent&); + + /* Update the plugins event flags. If a flag is set to true then the plugin + wants to be notified of events of this type. + */ + void updateEventFlags(ANPEventFlags); + + /* Called to check if a plugin wants to accept a given event type. It + returns true if the plugin wants the events and false otherwise. + */ + bool isAcceptingEvent(ANPEventFlag); + + /* Notify the plugin of the currently visible screen coordinates (document + space) and the current zoom level. + */ + void setVisibleScreen(const ANPRectI& visibleScreenRect, float zoom); + + /** Returns a rectangle representing the visible area of the plugin on + screen. The coordinates are relative to the size of the plugin in the + document and will not be negative or exceed the plugin's size. + */ + ANPRectI visibleRect(); + + /** Registers a set of rectangles that the plugin would like to keep on + screen. The rectangles are listed in order of priority with the highest + priority rectangle in location rects[0]. The browser will attempt to keep + as many of the rectangles on screen as possible and will scroll them into + view in response to the invocation of this method and other various events. + The count specifies how many rectangles are in the array. If the count is + zero it signals the plugin that any existing rectangles should be cleared + and no rectangles will be tracked. + */ + void setVisibleRects(const ANPRectI rects[], int32_t count); + + /** Called when a plugin wishes to enter into full screen mode. It invokes + the plugin's Java class (defined in the plugin's apk manifest), which is + called asynchronously and provides a View to be displayed full screen. + */ + void requestFullScreen(); + + /** Called when a plugin wishes to exit from full screen mode. As a result, + the plugin's full-screen view is discarded by the view system. It is also + called in order to notify the native code that the browser has discarded + the view. + */ + void exitFullScreen(bool pluginInitiated); + + bool inFullScreen() { return m_isFullScreen; } + + /** Called to check if a plugin currently has document focus, which is + required for certain operations (e.g. show/hide keyboard). It returns + true if the plugin currently has focus and false otherwise. + */ + bool hasFocus() const { return m_hasFocus; } + + /** Called to ensure the surface is being correctly displayed within the + view hierarchy. For instance, if the visibility of the plugin has + changed then we need to ensure the surface is added or removed from the + view system. + */ + void layoutSurface(bool pluginBoundsChanged = false); + + /** send the surface the currently visible portion of the plugin. This is not + the portion of the plugin visible on the screen but rather the portion of + the plugin that is not obscured by other HTML content. + */ + void setSurfaceClip(const SkIRect& clip); + + /** Called when a plugin wishes to be zoomed and centered in the current view. + */ + void requestCenterFitZoom(); + + WebCore::MediaLayer* getLayer() const { return m_layer; } + + void setPowerState(ANPPowerState powerState); + + void viewInvalidate(); + +private: + void computeVisiblePluginRect(); + void scrollToVisiblePluginRect(); + void sendSizeAndVisibilityEvents(const bool updateDimensions); + + WebCore::MediaLayer* m_layer; + + WebCore::PluginView* m_pluginView; + android::WebViewCore* m_core; + SkFlipPixelRef* m_flipPixelRef; + ANPDrawingModel m_drawingModel; + ANPEventFlags m_eventFlags; + NPWindow* m_pluginWindow; + SkIRect m_pluginBounds; // relative to the page + SkIRect m_visibleDocRect; // relative to the page + SkIRect m_requestedVisibleRect; // relative to the page + bool m_hasFocus; + bool m_isFullScreen; + bool m_visible; + float m_cachedZoomLevel; // used for comparison only + jobject m_embeddedView; + bool m_embeddedViewAttached; + bool m_acceptEvents; + bool m_isSurfaceClippedOut; + ANPPowerState m_powerState; + + /* We limit the number of rectangles to minimize storage and ensure adequate + speed. + */ + enum { + MAX_REQUESTED_RECTS = 5, + }; + + ANPRectI m_requestedVisibleRects[MAX_REQUESTED_RECTS]; + int32_t m_requestedVisibleRectCount; +}; + +#endif diff --git a/Source/WebKit/android/plugins/SkANP.cpp b/Source/WebKit/android/plugins/SkANP.cpp new file mode 100644 index 0000000..720387d --- /dev/null +++ b/Source/WebKit/android/plugins/SkANP.cpp @@ -0,0 +1,106 @@ +/* + * 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. + */ + +// must include config.h first for webkit to fiddle with new/delete +#include "config.h" +#include "SkANP.h" +#include + +SkRect* SkANP::SetRect(SkRect* dst, const ANPRectF& src) { + dst->set(SkFloatToScalar(src.left), + SkFloatToScalar(src.top), + SkFloatToScalar(src.right), + SkFloatToScalar(src.bottom)); + return dst; +} + +SkIRect* SkANP::SetRect(SkIRect* dst, const ANPRectI& src) { + dst->set(src.left, src.top, src.right, src.bottom); + return dst; +} + +ANPRectI* SkANP::SetRect(ANPRectI* dst, const SkIRect& src) { + dst->left = src.fLeft; + dst->top = src.fTop; + dst->right = src.fRight; + dst->bottom = src.fBottom; + return dst; +} + +ANPRectF* SkANP::SetRect(ANPRectF* dst, const SkRect& src) { + dst->left = SkScalarToFloat(src.fLeft); + dst->top = SkScalarToFloat(src.fTop); + dst->right = SkScalarToFloat(src.fRight); + dst->bottom = SkScalarToFloat(src.fBottom); + return dst; +} + +SkBitmap* SkANP::SetBitmap(SkBitmap* dst, const ANPBitmap& src) { + SkBitmap::Config config = SkBitmap::kNo_Config; + + switch (src.format) { + case kRGBA_8888_ANPBitmapFormat: + config = SkBitmap::kARGB_8888_Config; + break; + case kRGB_565_ANPBitmapFormat: + config = SkBitmap::kRGB_565_Config; + break; + default: + break; + } + + dst->setConfig(config, src.width, src.height, src.rowBytes); + dst->setPixels(src.baseAddr); + return dst; +} + +bool SkANP::SetBitmap(ANPBitmap* dst, const SkBitmap& src) { + if (!(dst->baseAddr = src.getPixels())) { + SkDebugf("SkANP::SetBitmap - getPixels() returned null\n"); + return false; + } + + switch (src.config()) { + case SkBitmap::kARGB_8888_Config: + dst->format = kRGBA_8888_ANPBitmapFormat; + break; + case SkBitmap::kRGB_565_Config: + dst->format = kRGB_565_ANPBitmapFormat; + break; + default: + SkDebugf("SkANP::SetBitmap - unsupported src.config %d\n", src.config()); + return false; + } + + dst->width = src.width(); + dst->height = src.height(); + dst->rowBytes = src.rowBytes(); + return true; +} + +void SkANP::InitEvent(ANPEvent* event, ANPEventType et) { + event->inSize = sizeof(ANPEvent); + event->eventType = et; +} diff --git a/Source/WebKit/android/plugins/SkANP.h b/Source/WebKit/android/plugins/SkANP.h new file mode 100644 index 0000000..5c2a936 --- /dev/null +++ b/Source/WebKit/android/plugins/SkANP.h @@ -0,0 +1,79 @@ +/* + * 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 SkANP_DEFINED +#define SkANP_DEFINED + +#include "android_npapi.h" +#include "SkCanvas.h" +#include "SkMatrix.h" +#include "SkPaint.h" +#include "SkPath.h" +#include "SkTypeface.h" + +struct ANPMatrix : SkMatrix { +}; + +struct ANPPath : SkPath { +}; + +struct ANPPaint : SkPaint { +}; + +struct ANPTypeface : SkTypeface { +}; + +struct ANPCanvas { + SkCanvas* skcanvas; + + // draw into the specified bitmap + explicit ANPCanvas(const SkBitmap& bm) { + skcanvas = new SkCanvas(bm); + } + + // redirect all drawing to the specific SkCanvas + explicit ANPCanvas(SkCanvas* other) { + skcanvas = other; + skcanvas->ref(); + } + + ~ANPCanvas() { + skcanvas->unref(); + } +}; + +class SkANP { +public: + static SkRect* SetRect(SkRect* dst, const ANPRectF& src); + static SkIRect* SetRect(SkIRect* dst, const ANPRectI& src); + static ANPRectI* SetRect(ANPRectI* dst, const SkIRect& src); + static ANPRectF* SetRect(ANPRectF* dst, const SkRect& src); + static SkBitmap* SetBitmap(SkBitmap* dst, const ANPBitmap& src); + static bool SetBitmap(ANPBitmap* dst, const SkBitmap& src); + + static void InitEvent(ANPEvent* event, ANPEventType et); +}; + +#endif diff --git a/Source/WebKit/android/plugins/SurfaceCallback.h b/Source/WebKit/android/plugins/SurfaceCallback.h new file mode 100644 index 0000000..945fc3f --- /dev/null +++ b/Source/WebKit/android/plugins/SurfaceCallback.h @@ -0,0 +1,42 @@ +/* + * Copyright 2009, The Android Open Source Project + * Copyright (C) 2008 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. + * + * 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 SurfaceCallback_H +#define SurfaceCallback_H + +namespace android { + + class SurfaceCallback { + public: + virtual ~SurfaceCallback() {} + virtual void surfaceCreated() = 0; + virtual void surfaceChanged(int format, int width, int height) = 0; + virtual void surfaceDestroyed() = 0; + }; + +} // namespace android + +#endif diff --git a/Source/WebKit/android/plugins/android_npapi.h b/Source/WebKit/android/plugins/android_npapi.h new file mode 100644 index 0000000..b0c3765 --- /dev/null +++ b/Source/WebKit/android/plugins/android_npapi.h @@ -0,0 +1,987 @@ +/* + * 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. + */ + +/* Defines the android-specific types and functions as part of npapi + + In particular, defines the window and event types that are passed to + NPN_GetValue, NPP_SetWindow and NPP_HandleEvent. + + To minimize what native libraries the plugin links against, some + functionality is provided via function-ptrs (e.g. time, sound) + */ + +#ifndef android_npapi_H +#define android_npapi_H + +#include + +#include "npapi.h" + +/////////////////////////////////////////////////////////////////////////////// +// General types + +enum ANPBitmapFormats { + kUnknown_ANPBitmapFormat = 0, + kRGBA_8888_ANPBitmapFormat = 1, + kRGB_565_ANPBitmapFormat = 2 +}; +typedef int32_t ANPBitmapFormat; + +struct ANPPixelPacking { + uint8_t AShift; + uint8_t ABits; + uint8_t RShift; + uint8_t RBits; + uint8_t GShift; + uint8_t GBits; + uint8_t BShift; + uint8_t BBits; +}; + +struct ANPBitmap { + void* baseAddr; + ANPBitmapFormat format; + int32_t width; + int32_t height; + int32_t rowBytes; +}; + +struct ANPRectF { + float left; + float top; + float right; + float bottom; +}; + +struct ANPRectI { + int32_t left; + int32_t top; + int32_t right; + int32_t bottom; +}; + +struct ANPCanvas; +struct ANPMatrix; +struct ANPPaint; +struct ANPPath; +struct ANPRegion; +struct ANPTypeface; + +enum ANPMatrixFlags { + kIdentity_ANPMatrixFlag = 0, + kTranslate_ANPMatrixFlag = 0x01, + kScale_ANPMatrixFlag = 0x02, + kAffine_ANPMatrixFlag = 0x04, + kPerspective_ANPMatrixFlag = 0x08, +}; +typedef uint32_t ANPMatrixFlag; + +/////////////////////////////////////////////////////////////////////////////// +// NPN_GetValue + +/** queries for a specific ANPInterface. + + Maybe called with NULL for the NPP instance + + NPN_GetValue(inst, interface_enum, ANPInterface*) + */ +#define kLogInterfaceV0_ANPGetValue ((NPNVariable)1000) +#define kAudioTrackInterfaceV0_ANPGetValue ((NPNVariable)1001) +#define kCanvasInterfaceV0_ANPGetValue ((NPNVariable)1002) +#define kMatrixInterfaceV0_ANPGetValue ((NPNVariable)1003) +#define kPaintInterfaceV0_ANPGetValue ((NPNVariable)1004) +#define kPathInterfaceV0_ANPGetValue ((NPNVariable)1005) +#define kTypefaceInterfaceV0_ANPGetValue ((NPNVariable)1006) +#define kWindowInterfaceV0_ANPGetValue ((NPNVariable)1007) +#define kBitmapInterfaceV0_ANPGetValue ((NPNVariable)1008) +#define kSurfaceInterfaceV0_ANPGetValue ((NPNVariable)1009) +#define kSystemInterfaceV0_ANPGetValue ((NPNVariable)1010) +#define kEventInterfaceV0_ANPGetValue ((NPNVariable)1011) + +#define kAudioTrackInterfaceV1_ANPGetValue ((NPNVariable)1012) +#define kOpenGLInterfaceV0_ANPGetValue ((NPNVariable)1013) +#define kWindowInterfaceV1_ANPGetValue ((NPNVariable)1014) +#define kVideoInterfaceV0_ANPGetValue ((NPNVariable)1015) +#define kSystemInterfaceV1_ANPGetValue ((NPNVariable)1016) + +#define kSystemInterfaceV2_ANPGetValue ((NPNVariable)1017) + +/** queries for the drawing models supported on this device. + + NPN_GetValue(inst, kSupportedDrawingModel_ANPGetValue, uint32_t* bits) + */ +#define kSupportedDrawingModel_ANPGetValue ((NPNVariable)2000) + +/** queries for the context (android.content.Context) of the plugin. If no + instance is specified the application's context is returned. If the instance + is given then the context returned is identical to the context used to + create the webview in which that instance resides. + + NOTE: Holding onto a non-application context after your instance has been + destroyed will cause a memory leak. Refer to the android documentation to + determine what context is best suited for your particular scenario. + + NPN_GetValue(inst, kJavaContext_ANPGetValue, jobject context) + */ +#define kJavaContext_ANPGetValue ((NPNVariable)2001) + +/////////////////////////////////////////////////////////////////////////////// +// NPN_SetValue + +/** Request to set the drawing model. SetValue will return false if the drawing + model is not supported or has insufficient information for configuration. + + NPN_SetValue(inst, kRequestDrawingModel_ANPSetValue, (void*)foo_ANPDrawingModel) + */ +#define kRequestDrawingModel_ANPSetValue ((NPPVariable)1000) + +/** These are used as bitfields in ANPSupportedDrawingModels_EnumValue, + and as-is in ANPRequestDrawingModel_EnumValue. The drawing model determines + how to interpret the ANPDrawingContext provided in the Draw event and how + to interpret the NPWindow->window field. + */ +enum ANPDrawingModels { + /** Draw into a bitmap from the browser thread in response to a Draw event. + NPWindow->window is reserved (ignore) + */ + kBitmap_ANPDrawingModel = 1 << 0, + /** Draw into a surface (e.g. raster, openGL, etc.) using the Java surface + interface. When this model is used the browser will invoke the Java + class specified in the plugin's apk manifest. From that class the browser + will invoke the appropriate method to return an an instance of a android + Java View. The instance is then embedded in the html. The plugin can then + manipulate the view as it would any normal Java View in android. + + Unlike the bitmap model, a surface model is opaque so no html content + behind the plugin will be visible. Unless the plugin needs to be + transparent the surface model should be chosen over the bitmap model as + it will have better performance. + + Further, a plugin can manipulate some surfaces in native code using the + ANPSurfaceInterface. This interface can be used to manipulate Java + objects that extend Surface.class by allowing them to access the + surface's underlying bitmap in native code. For instance, if a raster + surface is used the plugin can lock, draw directly into the bitmap, and + unlock the surface in native code without making JNI calls to the Java + surface object. + */ + kSurface_ANPDrawingModel = 1 << 1, + kOpenGL_ANPDrawingModel = 1 << 2, +}; +typedef int32_t ANPDrawingModel; + +/** Request to receive/disable events. If the pointer is NULL then all flags will + be disabled. Otherwise, the event type will be enabled iff its corresponding + bit in the EventFlags bit field is set. + + NPN_SetValue(inst, ANPAcceptEvents, (void*)EventFlags) + */ +#define kAcceptEvents_ANPSetValue ((NPPVariable)1001) + +/** The EventFlags are a set of bits used to determine which types of events the + plugin wishes to receive. For example, if the value is 0x03 then both key + and touch events will be provided to the plugin. + */ +enum ANPEventFlag { + kKey_ANPEventFlag = 0x01, + kTouch_ANPEventFlag = 0x02, +}; +typedef uint32_t ANPEventFlags; + +/////////////////////////////////////////////////////////////////////////////// +// NPP_GetValue + +/** Requests that the plugin return a java surface to be displayed. This will + only be used if the plugin has choosen the kSurface_ANPDrawingModel. + + NPP_GetValue(inst, kJavaSurface_ANPGetValue, jobject surface) + */ +#define kJavaSurface_ANPGetValue ((NPPVariable)2000) + + +/////////////////////////////////////////////////////////////////////////////// +// ANDROID INTERFACE DEFINITIONS + +/** Interfaces provide additional functionality to the plugin via function ptrs. + Once an interface is retrieved, it is valid for the lifetime of the plugin + (just like browserfuncs). + + All ANPInterfaces begin with an inSize field, which must be set by the + caller (plugin) with the number of bytes allocated for the interface. + e.g. SomeInterface si; si.inSize = sizeof(si); browser->getvalue(..., &si); + */ +struct ANPInterface { + uint32_t inSize; // size (in bytes) of this struct +}; + +enum ANPLogTypes { + kError_ANPLogType = 0, // error + kWarning_ANPLogType = 1, // warning + kDebug_ANPLogType = 2 // debug only (informational) +}; +typedef int32_t ANPLogType; + +struct ANPLogInterfaceV0 : ANPInterface { + /** dumps printf messages to the log file + e.g. interface->log(instance, kWarning_ANPLogType, "value is %d", value); + */ + void (*log)(ANPLogType, const char format[], ...); +}; + +struct ANPBitmapInterfaceV0 : ANPInterface { + /** Returns true if the specified bitmap format is supported, and if packing + is non-null, sets it to the packing info for that format. + */ + bool (*getPixelPacking)(ANPBitmapFormat, ANPPixelPacking* packing); +}; + +struct ANPMatrixInterfaceV0 : ANPInterface { + /** Return a new identity matrix + */ + ANPMatrix* (*newMatrix)(); + /** Delete a matrix previously allocated by newMatrix() + */ + void (*deleteMatrix)(ANPMatrix*); + + ANPMatrixFlag (*getFlags)(const ANPMatrix*); + + void (*copy)(ANPMatrix* dst, const ANPMatrix* src); + + /** Return the matrix values in a float array (allcoated by the caller), + where the values are treated as follows: + w = x * [6] + y * [7] + [8]; + x' = (x * [0] + y * [1] + [2]) / w; + y' = (x * [3] + y * [4] + [5]) / w; + */ + void (*get3x3)(const ANPMatrix*, float[9]); + /** Initialize the matrix from values in a float array, + where the values are treated as follows: + w = x * [6] + y * [7] + [8]; + x' = (x * [0] + y * [1] + [2]) / w; + y' = (x * [3] + y * [4] + [5]) / w; + */ + void (*set3x3)(ANPMatrix*, const float[9]); + + void (*setIdentity)(ANPMatrix*); + void (*preTranslate)(ANPMatrix*, float tx, float ty); + void (*postTranslate)(ANPMatrix*, float tx, float ty); + void (*preScale)(ANPMatrix*, float sx, float sy); + void (*postScale)(ANPMatrix*, float sx, float sy); + void (*preSkew)(ANPMatrix*, float kx, float ky); + void (*postSkew)(ANPMatrix*, float kx, float ky); + void (*preRotate)(ANPMatrix*, float degrees); + void (*postRotate)(ANPMatrix*, float degrees); + void (*preConcat)(ANPMatrix*, const ANPMatrix*); + void (*postConcat)(ANPMatrix*, const ANPMatrix*); + + /** Return true if src is invertible, and if so, return its inverse in dst. + If src is not invertible, return false and ignore dst. + */ + bool (*invert)(ANPMatrix* dst, const ANPMatrix* src); + + /** Transform the x,y pairs in src[] by this matrix, and store the results + in dst[]. The count parameter is treated as the number of pairs in the + array. It is legal for src and dst to point to the same memory, but + illegal for the two arrays to partially overlap. + */ + void (*mapPoints)(ANPMatrix*, float dst[], const float src[], + int32_t count); +}; + +struct ANPPathInterfaceV0 : ANPInterface { + /** Return a new path */ + ANPPath* (*newPath)(); + + /** Delete a path previously allocated by ANPPath() */ + void (*deletePath)(ANPPath*); + + /** Make a deep copy of the src path, into the dst path (already allocated + by the caller). + */ + void (*copy)(ANPPath* dst, const ANPPath* src); + + /** Returns true if the two paths are the same (i.e. have the same points) + */ + bool (*equal)(const ANPPath* path0, const ANPPath* path1); + + /** Remove any previous points, initializing the path back to empty. */ + void (*reset)(ANPPath*); + + /** Return true if the path is empty (has no lines, quads or cubics). */ + bool (*isEmpty)(const ANPPath*); + + /** Return the path's bounds in bounds. */ + void (*getBounds)(const ANPPath*, ANPRectF* bounds); + + void (*moveTo)(ANPPath*, float x, float y); + void (*lineTo)(ANPPath*, float x, float y); + void (*quadTo)(ANPPath*, float x0, float y0, float x1, float y1); + void (*cubicTo)(ANPPath*, float x0, float y0, float x1, float y1, + float x2, float y2); + void (*close)(ANPPath*); + + /** Offset the src path by [dx, dy]. If dst is null, apply the + change directly to the src path. If dst is not null, write the + changed path into dst, and leave the src path unchanged. In that case + dst must have been previously allocated by the caller. + */ + void (*offset)(ANPPath* src, float dx, float dy, ANPPath* dst); + + /** Transform the path by the matrix. If dst is null, apply the + change directly to the src path. If dst is not null, write the + changed path into dst, and leave the src path unchanged. In that case + dst must have been previously allocated by the caller. + */ + void (*transform)(ANPPath* src, const ANPMatrix*, ANPPath* dst); +}; + +/** ANPColor is always defined to have the same packing on all platforms, and + it is always unpremultiplied. + + This is in contrast to 32bit format(s) in bitmaps, which are premultiplied, + and their packing may vary depending on the platform, hence the need for + ANPBitmapInterface::getPixelPacking() + */ +typedef uint32_t ANPColor; +#define ANPColor_ASHIFT 24 +#define ANPColor_RSHIFT 16 +#define ANPColor_GSHIFT 8 +#define ANPColor_BSHIFT 0 +#define ANP_MAKE_COLOR(a, r, g, b) \ + (((a) << ANPColor_ASHIFT) | \ + ((r) << ANPColor_RSHIFT) | \ + ((g) << ANPColor_GSHIFT) | \ + ((b) << ANPColor_BSHIFT)) + +enum ANPPaintFlag { + kAntiAlias_ANPPaintFlag = 1 << 0, + kFilterBitmap_ANPPaintFlag = 1 << 1, + kDither_ANPPaintFlag = 1 << 2, + kUnderlineText_ANPPaintFlag = 1 << 3, + kStrikeThruText_ANPPaintFlag = 1 << 4, + kFakeBoldText_ANPPaintFlag = 1 << 5, +}; +typedef uint32_t ANPPaintFlags; + +enum ANPPaintStyles { + kFill_ANPPaintStyle = 0, + kStroke_ANPPaintStyle = 1, + kFillAndStroke_ANPPaintStyle = 2 +}; +typedef int32_t ANPPaintStyle; + +enum ANPPaintCaps { + kButt_ANPPaintCap = 0, + kRound_ANPPaintCap = 1, + kSquare_ANPPaintCap = 2 +}; +typedef int32_t ANPPaintCap; + +enum ANPPaintJoins { + kMiter_ANPPaintJoin = 0, + kRound_ANPPaintJoin = 1, + kBevel_ANPPaintJoin = 2 +}; +typedef int32_t ANPPaintJoin; + +enum ANPPaintAligns { + kLeft_ANPPaintAlign = 0, + kCenter_ANPPaintAlign = 1, + kRight_ANPPaintAlign = 2 +}; +typedef int32_t ANPPaintAlign; + +enum ANPTextEncodings { + kUTF8_ANPTextEncoding = 0, + kUTF16_ANPTextEncoding = 1, +}; +typedef int32_t ANPTextEncoding; + +enum ANPTypefaceStyles { + kBold_ANPTypefaceStyle = 1 << 0, + kItalic_ANPTypefaceStyle = 1 << 1 +}; +typedef uint32_t ANPTypefaceStyle; + +typedef uint32_t ANPFontTableTag; + +struct ANPFontMetrics { + /** The greatest distance above the baseline for any glyph (will be <= 0) */ + float fTop; + /** The recommended distance above the baseline (will be <= 0) */ + float fAscent; + /** The recommended distance below the baseline (will be >= 0) */ + float fDescent; + /** The greatest distance below the baseline for any glyph (will be >= 0) */ + float fBottom; + /** The recommended distance to add between lines of text (will be >= 0) */ + float fLeading; +}; + +struct ANPTypefaceInterfaceV0 : ANPInterface { + /** Return a new reference to the typeface that most closely matches the + requested name and style. Pass null as the name to return + the default font for the requested style. Will never return null + + The 5 generic font names "serif", "sans-serif", "monospace", "cursive", + "fantasy" are recognized, and will be mapped to their logical font + automatically by this call. + + @param name May be NULL. The name of the font family. + @param style The style (normal, bold, italic) of the typeface. + @return reference to the closest-matching typeface. Caller must call + unref() when they are done with the typeface. + */ + ANPTypeface* (*createFromName)(const char name[], ANPTypefaceStyle); + + /** Return a new reference to the typeface that most closely matches the + requested typeface and specified Style. Use this call if you want to + pick a new style from the same family of the existing typeface. + If family is NULL, this selects from the default font's family. + + @param family May be NULL. The name of the existing type face. + @param s The style (normal, bold, italic) of the type face. + @return reference to the closest-matching typeface. Call must call + unref() when they are done. + */ + ANPTypeface* (*createFromTypeface)(const ANPTypeface* family, + ANPTypefaceStyle); + + /** Return the owner count of the typeface. A newly created typeface has an + owner count of 1. When the owner count is reaches 0, the typeface is + deleted. + */ + int32_t (*getRefCount)(const ANPTypeface*); + + /** Increment the owner count on the typeface + */ + void (*ref)(ANPTypeface*); + + /** Decrement the owner count on the typeface. When the count goes to 0, + the typeface is deleted. + */ + void (*unref)(ANPTypeface*); + + /** Return the style bits for the specified typeface + */ + ANPTypefaceStyle (*getStyle)(const ANPTypeface*); + + /** Some fonts are stored in files. If that is true for the fontID, then + this returns the byte length of the full file path. If path is not null, + then the full path is copied into path (allocated by the caller), up to + length bytes. If index is not null, then it is set to the truetype + collection index for this font, or 0 if the font is not in a collection. + + Note: getFontPath does not assume that path is a null-terminated string, + so when it succeeds, it only copies the bytes of the file name and + nothing else (i.e. it copies exactly the number of bytes returned by the + function. If the caller wants to treat path[] as a C string, it must be + sure that it is allocated at least 1 byte larger than the returned size, + and it must copy in the terminating 0. + + If the fontID does not correspond to a file, then the function returns + 0, and the path and index parameters are ignored. + + @param fontID The font whose file name is being queried + @param path Either NULL, or storage for receiving up to length bytes + of the font's file name. Allocated by the caller. + @param length The maximum space allocated in path (by the caller). + Ignored if path is NULL. + @param index Either NULL, or receives the TTC index for this font. + If the font is not a TTC, then will be set to 0. + @return The byte length of th font's file name, or 0 if the font is not + baked by a file. + */ + int32_t (*getFontPath)(const ANPTypeface*, char path[], int32_t length, + int32_t* index); + + /** Return a UTF8 encoded path name for the font directory, or NULL if not + supported. If returned, this string address will be valid for the life + of the plugin instance. It will always end with a '/' character. + */ + const char* (*getFontDirectoryPath)(); +}; + +struct ANPPaintInterfaceV0 : ANPInterface { + /** Return a new paint object, which holds all of the color and style + attributes that affect how things (geometry, text, bitmaps) are drawn + in a ANPCanvas. + + The paint that is returned is not tied to any particular plugin + instance, but it must only be accessed from one thread at a time. + */ + ANPPaint* (*newPaint)(); + void (*deletePaint)(ANPPaint*); + + ANPPaintFlags (*getFlags)(const ANPPaint*); + void (*setFlags)(ANPPaint*, ANPPaintFlags); + + ANPColor (*getColor)(const ANPPaint*); + void (*setColor)(ANPPaint*, ANPColor); + + ANPPaintStyle (*getStyle)(const ANPPaint*); + void (*setStyle)(ANPPaint*, ANPPaintStyle); + + float (*getStrokeWidth)(const ANPPaint*); + float (*getStrokeMiter)(const ANPPaint*); + ANPPaintCap (*getStrokeCap)(const ANPPaint*); + ANPPaintJoin (*getStrokeJoin)(const ANPPaint*); + void (*setStrokeWidth)(ANPPaint*, float); + void (*setStrokeMiter)(ANPPaint*, float); + void (*setStrokeCap)(ANPPaint*, ANPPaintCap); + void (*setStrokeJoin)(ANPPaint*, ANPPaintJoin); + + ANPTextEncoding (*getTextEncoding)(const ANPPaint*); + ANPPaintAlign (*getTextAlign)(const ANPPaint*); + float (*getTextSize)(const ANPPaint*); + float (*getTextScaleX)(const ANPPaint*); + float (*getTextSkewX)(const ANPPaint*); + void (*setTextEncoding)(ANPPaint*, ANPTextEncoding); + void (*setTextAlign)(ANPPaint*, ANPPaintAlign); + void (*setTextSize)(ANPPaint*, float); + void (*setTextScaleX)(ANPPaint*, float); + void (*setTextSkewX)(ANPPaint*, float); + + /** Return the typeface ine paint, or null if there is none. This does not + modify the owner count of the returned typeface. + */ + ANPTypeface* (*getTypeface)(const ANPPaint*); + + /** Set the paint's typeface. If the paint already had a non-null typeface, + its owner count is decremented. If the new typeface is non-null, its + owner count is incremented. + */ + void (*setTypeface)(ANPPaint*, ANPTypeface*); + + /** Return the width of the text. If bounds is not null, return the bounds + of the text in that rectangle. + */ + float (*measureText)(ANPPaint*, const void* text, uint32_t byteLength, + ANPRectF* bounds); + + /** Return the number of unichars specifed by the text. + If widths is not null, returns the array of advance widths for each + unichar. + If bounds is not null, returns the array of bounds for each unichar. + */ + int (*getTextWidths)(ANPPaint*, const void* text, uint32_t byteLength, + float widths[], ANPRectF bounds[]); + + /** Return in metrics the spacing values for text, respecting the paint's + typeface and pointsize, and return the spacing between lines + (descent - ascent + leading). If metrics is NULL, it will be ignored. + */ + float (*getFontMetrics)(ANPPaint*, ANPFontMetrics* metrics); +}; + +struct ANPCanvasInterfaceV0 : ANPInterface { + /** Return a canvas that will draw into the specified bitmap. Note: the + canvas copies the fields of the bitmap, so it need not persist after + this call, but the canvas DOES point to the same pixel memory that the + bitmap did, so the canvas should not be used after that pixel memory + goes out of scope. In the case of creating a canvas to draw into the + pixels provided by kDraw_ANPEventType, those pixels are only while + handling that event. + + The canvas that is returned is not tied to any particular plugin + instance, but it must only be accessed from one thread at a time. + */ + ANPCanvas* (*newCanvas)(const ANPBitmap*); + void (*deleteCanvas)(ANPCanvas*); + + void (*save)(ANPCanvas*); + void (*restore)(ANPCanvas*); + void (*translate)(ANPCanvas*, float tx, float ty); + void (*scale)(ANPCanvas*, float sx, float sy); + void (*rotate)(ANPCanvas*, float degrees); + void (*skew)(ANPCanvas*, float kx, float ky); + void (*concat)(ANPCanvas*, const ANPMatrix*); + void (*clipRect)(ANPCanvas*, const ANPRectF*); + void (*clipPath)(ANPCanvas*, const ANPPath*); + + /** Return the current matrix on the canvas + */ + void (*getTotalMatrix)(ANPCanvas*, ANPMatrix*); + /** Return the current clip bounds in local coordinates, expanding it to + account for antialiasing edge effects if aa is true. If the + current clip is empty, return false and ignore the bounds argument. + */ + bool (*getLocalClipBounds)(ANPCanvas*, ANPRectF* bounds, bool aa); + /** Return the current clip bounds in device coordinates in bounds. If the + current clip is empty, return false and ignore the bounds argument. + */ + bool (*getDeviceClipBounds)(ANPCanvas*, ANPRectI* bounds); + + void (*drawColor)(ANPCanvas*, ANPColor); + void (*drawPaint)(ANPCanvas*, const ANPPaint*); + void (*drawLine)(ANPCanvas*, float x0, float y0, float x1, float y1, + const ANPPaint*); + void (*drawRect)(ANPCanvas*, const ANPRectF*, const ANPPaint*); + void (*drawOval)(ANPCanvas*, const ANPRectF*, const ANPPaint*); + void (*drawPath)(ANPCanvas*, const ANPPath*, const ANPPaint*); + void (*drawText)(ANPCanvas*, const void* text, uint32_t byteLength, + float x, float y, const ANPPaint*); + void (*drawPosText)(ANPCanvas*, const void* text, uint32_t byteLength, + const float xy[], const ANPPaint*); + void (*drawBitmap)(ANPCanvas*, const ANPBitmap*, float x, float y, + const ANPPaint*); + void (*drawBitmapRect)(ANPCanvas*, const ANPBitmap*, + const ANPRectI* src, const ANPRectF* dst, + const ANPPaint*); +}; + +struct ANPWindowInterfaceV0 : ANPInterface { + /** Registers a set of rectangles that the plugin would like to keep on + screen. The rectangles are listed in order of priority with the highest + priority rectangle in location rects[0]. The browser will attempt to keep + as many of the rectangles on screen as possible and will scroll them into + view in response to the invocation of this method and other various events. + The count specifies how many rectangles are in the array. If the count is + zero it signals the browser that any existing rectangles should be cleared + and no rectangles will be tracked. + */ + void (*setVisibleRects)(NPP instance, const ANPRectI rects[], int32_t count); + /** Clears any rectangles that are being tracked as a result of a call to + setVisibleRects. This call is equivalent to setVisibleRect(inst, NULL, 0). + */ + void (*clearVisibleRects)(NPP instance); + /** Given a boolean value of true the device will be requested to provide + a keyboard. A value of false will result in a request to hide the + keyboard. Further, the on-screen keyboard will not be displayed if a + physical keyboard is active. + */ + void (*showKeyboard)(NPP instance, bool value); + /** Called when a plugin wishes to enter into full screen mode. The plugin's + Java class (defined in the plugin's apk manifest) will be called + asynchronously to provide a View object to be displayed full screen. + */ + void (*requestFullScreen)(NPP instance); + /** Called when a plugin wishes to exit from full screen mode. As a result, + the plugin's full screen view will be discarded by the view system. + */ + void (*exitFullScreen)(NPP instance); + /** Called when a plugin wishes to be zoomed and centered in the current view. + */ + void (*requestCenterFitZoom)(NPP instance); +}; + +struct ANPWindowInterfaceV1 : ANPWindowInterfaceV0 { + /** Returns a rectangle representing the visible area of the plugin on + screen. The coordinates are relative to the size of the plugin in the + document and therefore will never be negative or exceed the plugin's size. + */ + ANPRectI (*visibleRect)(NPP instance); +}; + +/////////////////////////////////////////////////////////////////////////////// + +enum ANPSampleFormats { + kUnknown_ANPSamleFormat = 0, + kPCM16Bit_ANPSampleFormat = 1, + kPCM8Bit_ANPSampleFormat = 2 +}; +typedef int32_t ANPSampleFormat; + +/** The audio buffer is passed to the callback proc to request more samples. + It is owned by the system, and the callback may read it, but should not + maintain a pointer to it outside of the scope of the callback proc. + */ +struct ANPAudioBuffer { + // RO - repeat what was specified in newTrack() + int32_t channelCount; + // RO - repeat what was specified in newTrack() + ANPSampleFormat format; + /** This buffer is owned by the caller. Inside the callback proc, up to + "size" bytes of sample data should be written into this buffer. The + address is only valid for the scope of a single invocation of the + callback proc. + */ + void* bufferData; + /** On input, specifies the maximum number of bytes that can be written + to "bufferData". On output, specifies the actual number of bytes that + the callback proc wrote into "bufferData". + */ + uint32_t size; +}; + +enum ANPAudioEvents { + /** This event is passed to the callback proc when the audio-track needs + more sample data written to the provided buffer parameter. + */ + kMoreData_ANPAudioEvent = 0, + /** This event is passed to the callback proc if the audio system runs out + of sample data. In this event, no buffer parameter will be specified + (i.e. NULL will be passed to the 3rd parameter). + */ + kUnderRun_ANPAudioEvent = 1 +}; +typedef int32_t ANPAudioEvent; + +/** Called to feed sample data to the track. This will be called in a separate + thread. However, you may call trackStop() from the callback (but you + cannot delete the track). + + For example, when you have written the last chunk of sample data, you can + immediately call trackStop(). This will take effect after the current + buffer has been played. + + The "user" parameter is the same value that was passed to newTrack() + */ +typedef void (*ANPAudioCallbackProc)(ANPAudioEvent event, void* user, + ANPAudioBuffer* buffer); + +struct ANPAudioTrack; // abstract type for audio tracks + +struct ANPAudioTrackInterfaceV0 : ANPInterface { + /** Create a new audio track, or NULL on failure. The track is initially in + the stopped state and therefore ANPAudioCallbackProc will not be called + until the track is started. + */ + ANPAudioTrack* (*newTrack)(uint32_t sampleRate, // sampling rate in Hz + ANPSampleFormat, + int channelCount, // MONO=1, STEREO=2 + ANPAudioCallbackProc, + void* user); + /** Deletes a track that was created using newTrack. The track can be + deleted in any state and it waits for the ANPAudioCallbackProc thread + to exit before returning. + */ + void (*deleteTrack)(ANPAudioTrack*); + + void (*start)(ANPAudioTrack*); + void (*pause)(ANPAudioTrack*); + void (*stop)(ANPAudioTrack*); + /** Returns true if the track is not playing (e.g. pause or stop was called, + or start was never called. + */ + bool (*isStopped)(ANPAudioTrack*); +}; + +struct ANPAudioTrackInterfaceV1 : ANPAudioTrackInterfaceV0 { + /** Returns the track's latency in milliseconds. */ + uint32_t (*trackLatency)(ANPAudioTrack*); +}; + +/////////////////////////////////////////////////////////////////////////////// +// DEFINITION OF VALUES PASSED THROUGH NPP_HandleEvent + +enum ANPEventTypes { + kNull_ANPEventType = 0, + kKey_ANPEventType = 1, + /** Mouse events are triggered by either clicking with the navigational pad + or by tapping the touchscreen (if the kDown_ANPTouchAction is handled by + the plugin then no mouse event is generated). The kKey_ANPEventFlag has + to be set to true in order to receive these events. + */ + kMouse_ANPEventType = 2, + /** Touch events are generated when the user touches on the screen. The + kTouch_ANPEventFlag has to be set to true in order to receive these + events. + */ + kTouch_ANPEventType = 3, + /** Only triggered by a plugin using the kBitmap_ANPDrawingModel. This event + signals that the plugin needs to redraw itself into the provided bitmap. + */ + kDraw_ANPEventType = 4, + kLifecycle_ANPEventType = 5, + + /** This event type is completely defined by the plugin. + When creating an event, the caller must always set the first + two fields, the remaining data is optional. + ANPEvent evt; + evt.inSize = sizeof(ANPEvent); + evt.eventType = kCustom_ANPEventType + // other data slots are optional + evt.other[] = ...; + To post a copy of the event, call + eventInterface->postEvent(myNPPInstance, &evt); + That call makes a copy of the event struct, and post that on the event + queue for the plugin. + */ + kCustom_ANPEventType = 6, + /** MultiTouch events are generated when the user touches on the screen. The + kTouch_ANPEventFlag has to be set to true in order to receive these + events. This type is a replacement for the older kTouch_ANPEventType. + */ + kMultiTouch_ANPEventType = 7, +}; +typedef int32_t ANPEventType; + +enum ANPKeyActions { + kDown_ANPKeyAction = 0, + kUp_ANPKeyAction = 1, +}; +typedef int32_t ANPKeyAction; + +#include "ANPKeyCodes.h" +typedef int32_t ANPKeyCode; + +enum ANPKeyModifiers { + kAlt_ANPKeyModifier = 1 << 0, + kShift_ANPKeyModifier = 1 << 1, +}; +// bit-field containing some number of ANPKeyModifier bits +typedef uint32_t ANPKeyModifier; + +enum ANPMouseActions { + kDown_ANPMouseAction = 0, + kUp_ANPMouseAction = 1, +}; +typedef int32_t ANPMouseAction; + +enum ANPTouchActions { + /** This occurs when the user first touches on the screen. As such, this + action will always occur prior to any of the other touch actions. If + the plugin chooses to not handle this action then no other events + related to that particular touch gesture will be generated. + */ + kDown_ANPTouchAction = 0, + kUp_ANPTouchAction = 1, + kMove_ANPTouchAction = 2, + kCancel_ANPTouchAction = 3, + // The web view will ignore the return value from the following actions + kLongPress_ANPTouchAction = 4, + kDoubleTap_ANPTouchAction = 5, +}; +typedef int32_t ANPTouchAction; + +enum ANPLifecycleActions { + /** The web view containing this plugin has been paused. See documentation + on the android activity lifecycle for more information. + */ + kPause_ANPLifecycleAction = 0, + /** The web view containing this plugin has been resumed. See documentation + on the android activity lifecycle for more information. + */ + kResume_ANPLifecycleAction = 1, + /** The plugin has focus and is now the recipient of input events (e.g. key, + touch, etc.) + */ + kGainFocus_ANPLifecycleAction = 2, + /** The plugin has lost focus and will not receive any input events until it + regains focus. This event is always preceded by a GainFocus action. + */ + kLoseFocus_ANPLifecycleAction = 3, + /** The browser is running low on available memory and is requesting that + the plugin free any unused/inactive resources to prevent a performance + degradation. + */ + kFreeMemory_ANPLifecycleAction = 4, + /** The page has finished loading. This happens when the page's top level + frame reports that it has completed loading. + */ + kOnLoad_ANPLifecycleAction = 5, + /** The browser is honoring the plugin's request to go full screen. Upon + returning from this event the browser will resize the plugin's java + surface to full-screen coordinates. + */ + kEnterFullScreen_ANPLifecycleAction = 6, + /** The browser has exited from full screen mode. Immediately prior to + sending this event the browser has resized the plugin's java surface to + its original coordinates. + */ + kExitFullScreen_ANPLifecycleAction = 7, + /** The plugin is visible to the user on the screen. This event will always + occur after a kOffScreen_ANPLifecycleAction event. + */ + kOnScreen_ANPLifecycleAction = 8, + /** The plugin is no longer visible to the user on the screen. This event + will always occur prior to an kOnScreen_ANPLifecycleAction event. + */ + kOffScreen_ANPLifecycleAction = 9, +}; +typedef uint32_t ANPLifecycleAction; + +struct TouchPoint { + int32_t id; + float x; // relative to your "window" (0...width) + float y; // relative to your "window" (0...height) + float pressure; + float size; // normalized to a value between 0...1 +}; + +/* This is what is passed to NPP_HandleEvent() */ +struct ANPEvent { + uint32_t inSize; // size of this struct in bytes + ANPEventType eventType; + // use based on the value in eventType + union { + struct { + ANPKeyAction action; + ANPKeyCode nativeCode; + int32_t virtualCode; // windows virtual key code + ANPKeyModifier modifiers; + int32_t repeatCount; // 0 for initial down (or up) + int32_t unichar; // 0 if there is no value + } key; + struct { + ANPMouseAction action; + int32_t x; // relative to your "window" (0...width) + int32_t y; // relative to your "window" (0...height) + } mouse; + struct { + ANPTouchAction action; + ANPKeyModifier modifiers; + int32_t x; // relative to your "window" (0...width) + int32_t y; // relative to your "window" (0...height) + } touch; + struct { + ANPLifecycleAction action; + } lifecycle; + struct { + ANPDrawingModel model; + // relative to (0,0) in top-left of your plugin + ANPRectI clip; + // use based on the value in model + union { + ANPBitmap bitmap; + struct { + int32_t width; + int32_t height; + } surface; + } data; + } draw; + struct { + int64_t timestamp; + int32_t id; + ANPTouchAction action; + int32_t pointerCount; + TouchPoint* touchPoint; + } multiTouch; + int32_t other[8]; + } data; +}; + +struct ANPEventInterfaceV0 : ANPInterface { + /** Post a copy of the specified event to the plugin. The event will be + delivered to the plugin in its main thread (the thread that receives + other ANPEvents). If, after posting before delivery, the NPP instance + is torn down, the event will be discarded. + */ + void (*postEvent)(NPP inst, const ANPEvent* event); +}; + + +#endif diff --git a/Source/WebKit/android/smoke/MessageThread.cpp b/Source/WebKit/android/smoke/MessageThread.cpp new file mode 100644 index 0000000..48f2222 --- /dev/null +++ b/Source/WebKit/android/smoke/MessageThread.cpp @@ -0,0 +1,146 @@ +/* + * 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. + */ + +#define LOG_TAG "MessageThread" + +#include "config.h" + +#include +#include + +#include "MessageThread.h" +#include "ScriptController.h" + +#include + +namespace android { + +static bool compareMessages(const Message& msg1, + const Message& msg2, + bool memberIsNull) { + return (msg1.object() == msg2.object() && + (memberIsNull || msg1.member() == msg2.member())); +} + +bool MessageQueue::hasMessages(const Message& message) { + AutoMutex lock(m_mutex); + + static const Message::GenericMemberFunction nullMember = NULL; + const bool memberIsNull = message.member() == nullMember; + + for (list::iterator it = m_messages.begin(); + it != m_messages.end(); ++it) { + Message* m = *it; + if (compareMessages(message, *m, memberIsNull)) + return true; + } + return false; +} + +void MessageQueue::remove(const Message& message) { + AutoMutex lock(m_mutex); + + static const Message::GenericMemberFunction nullMember = NULL; + const bool memberIsNull = message.member() == nullMember; + + for (list::iterator it = m_messages.begin(); + it != m_messages.end(); ++it) { + Message* m = *it; + if (compareMessages(message, *m, memberIsNull)) { + it = m_messages.erase(it); + delete m; + } + } +} + +void MessageQueue::post(Message* message) { + AutoMutex lock(m_mutex); + + double when = message->m_when; + LOG_ASSERT(when > 0, "Message time may not be 0"); + + list::iterator it; + for (it = m_messages.begin(); it != m_messages.end(); ++it) { + Message* m = *it; + if (when < m->m_when) { + break; + } + } + m_messages.insert(it, message); + m_condition.signal(); +} + +void MessageQueue::postAtFront(Message* message) { + AutoMutex lock(m_mutex); + message->m_when = 0; + m_messages.push_front(message); +} + +Message* MessageQueue::next() { + AutoMutex lock(m_mutex); + while (true) { + if (m_messages.empty()) { + // No messages, wait until another arrives + m_condition.wait(m_mutex); + } + Message* next = m_messages.front(); + double now = WTF::currentTimeMS(); + double diff = next->m_when - now; + if (diff > 0) { + // Not time for this message yet, wait the difference in nanos + m_condition.waitRelative(m_mutex, + static_cast(diff * 1000000) /* nanos */); + } else { + // Time for this message to run. + m_messages.pop_front(); + return next; + } + } +} + +bool MessageThread::threadLoop() { + WebCore::ScriptController::initializeThreading(); + + while (true) { + Message* message = m_queue.next(); + if (message != NULL) { + message->run(); + } + } + return false; +} + +// Global thread object obtained by messageThread(). +static sp gMessageThread; + +MessageThread* messageThread() { + if (gMessageThread == NULL) { + gMessageThread = new MessageThread(); + gMessageThread->run("WebCoreThread"); + } + return gMessageThread.get(); +} + +} // namespace android diff --git a/Source/WebKit/android/smoke/MessageThread.h b/Source/WebKit/android/smoke/MessageThread.h new file mode 100644 index 0000000..ca0115b --- /dev/null +++ b/Source/WebKit/android/smoke/MessageThread.h @@ -0,0 +1,108 @@ +/* + * 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 ANDROID_WEBKIT_MESSAGETHREAD_H +#define ANDROID_WEBKIT_MESSAGETHREAD_H + +#include + +#include "MessageTypes.h" + +#include + +using std::list; + +namespace android { + +class MessageQueue { +public: + MessageQueue() {} + + // Return true if the queue has messages with the given object and member + // function. If member is null, return true if the message has the same + // object. + template + bool hasMessages(T* object, void (T::*member)(void)); + + // Remove all messages with the given object and member function. If + // member is null, remove all messages with the given object. + template + void remove(T* object, void (T::*member)(void)); + + // Post a new message to the queue. + void post(Message* closure); + + // Post a new message at the front of the queue. + void postAtFront(Message* closure); + + // Obtain the next message. Blocks until either a new message arrives or + // we reach the time of the next message. + Message* next(); + +private: + bool hasMessages(const Message& message); + void remove(const Message& message); + + list m_messages; + Mutex m_mutex; + Condition m_condition; +}; + +template +bool MessageQueue::hasMessages(T* object, void (T::*member)(void)) { + MemberFunctionMessage message(object, member); + return hasMessages(message); +} + +template +void MessageQueue::remove(T* object, void (T::*member)(void)) { + MemberFunctionMessage message(object, member); + remove(message); +} + +class MessageThread : public Thread { +public: + MessageQueue& queue() { return m_queue; } + +private: + MessageThread() : Thread(true /* canCallJava */) {} + + virtual bool threadLoop(); + + MessageQueue m_queue; + // Used for thread initialization + Mutex m_mutex; + Condition m_condition; + + friend MessageThread* messageThread(); +}; + +// Get (possibly creating) the global MessageThread object used to pass +// messages to WebCore. +MessageThread* messageThread(); + +} // namespace android + +#endif // ANDROID_WEBKIT_MESSAGETHREAD_H diff --git a/Source/WebKit/android/smoke/MessageTypes.h b/Source/WebKit/android/smoke/MessageTypes.h new file mode 100644 index 0000000..7da6cb8 --- /dev/null +++ b/Source/WebKit/android/smoke/MessageTypes.h @@ -0,0 +1,159 @@ +/* + * 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 ANDROID_WEBKIT_MESSAGETYPES_H_ +#define ANDROID_WEBKIT_MESSAGETYPES_H_ + +#include + +// TODO(phanna): autogenerate these types! + +namespace android { + +// Forward declared for friendship! +class MessageQueue; + +// Removes the reference from the typename so we store the actual value in the +// closure. +template struct remove_reference { typedef T type; }; +template struct remove_reference { typedef T type; }; + +// Prevent the compiler from inferring the type. +template struct identity { typedef T type; }; + +// Message base class. Defines the public run() method and contains generic +// object and member function variables for use in MessageQueue. +// +// Note: The template subclass MemberFunctionMessage casts its object and +// member function to the generic void* and Message::* types. During run(), +// each template specialization downcasts to the original type and invokes the +// correct function. This may seem dangerous but the compiler enforces +// correctness in NewMessage and in the template constructor. +class Message { +public: + typedef void (Message::*GenericMemberFunction)(void); + + virtual ~Message() {} + virtual void run() = 0; + + // The wall time that the message is supposed to run. + double m_when; + + void* object() const { return m_object; } + GenericMemberFunction member() const { return m_member; } + +protected: + Message(void* object, GenericMemberFunction member, long delay = 0) + : m_object(object) + , m_member(member) { + m_when = WTF::currentTimeMS() + delay; + } + + // Downcast back to the original template params in run(). Also accessed + // by MessageQueue to compare messages. + void* m_object; + GenericMemberFunction m_member; + +private: + // Disallow copy + Message(const Message&); +}; + +// Forward declaration for partial specialization. +template +class MemberFunctionMessage; + +template +class MemberFunctionMessage : public Message { +private: + typedef void (T::*MemberSignature)(); + +public: + inline MemberFunctionMessage(T* object, + MemberSignature member, + long delay = 0) + : Message(reinterpret_cast(object), + reinterpret_cast(member), + delay) {} + + virtual void run() { + MemberSignature member = reinterpret_cast(m_member); + (reinterpret_cast(m_object)->*member)(); + delete this; + } +}; + +template +inline Message* NewMessage(T* object, void (T::*member)()) { + return new MemberFunctionMessage(object, member); +} + +template +inline Message* NewDelayedMessage(T* object, void (T::*member)(), long delay) { + return new MemberFunctionMessage(object, member, delay); +} + +template +class MemberFunctionMessage : public Message { +private: + typedef void (T::*MemberSignature)(A1); + +public: + inline MemberFunctionMessage(T* object, + MemberSignature member, + A1 arg1, + long delay = 0) + : Message(reinterpret_cast(object), + reinterpret_cast(member), + delay) + , m_arg1(arg1) {} + + virtual void run() { + MemberSignature member = reinterpret_cast(m_member); + (reinterpret_cast(m_object)->*member)(m_arg1); + delete this; + } + +private: + typename remove_reference::type m_arg1; +}; + +template +inline Message* NewMessage(T* object, void (T::*member)(A1), + typename identity::type arg1) { + return new MemberFunctionMessage( + object, member, arg1); +} + +template +inline Message* NewDelayedMessage(T* object, void (T::*member)(A1), + typename identity::type arg1, long delay) { + return new MemberFunctionMessage(object, member, arg1, delay); +} + +} // namespace android + + +#endif // ANDROID_WEBKIT_MESSAGETYPES_H_ diff --git a/Source/WebKit/android/wds/Command.cpp b/Source/WebKit/android/wds/Command.cpp new file mode 100644 index 0000000..bd8536f --- /dev/null +++ b/Source/WebKit/android/wds/Command.cpp @@ -0,0 +1,154 @@ +/* + * 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 "wds" +#include "config.h" + +#include "AndroidLog.h" +#include "Command.h" +#include "Connection.h" +#include "DebugServer.h" +#include "Frame.h" +#include "RenderTreeAsText.h" +#include "RenderView.h" +#include "WebViewCore.h" +#include +#include + +#if ENABLE(WDS) + +using namespace WebCore; + +namespace android { + +namespace WDS { + +//------------------------------------------------------------------------------ +// Actual commands -- XXX should be moved somewhere else +//------------------------------------------------------------------------------ +static bool callDumpRenderTree(const Frame* frame, const Connection* conn) { + CString str = externalRepresentation(frame->contentRenderer()).latin1(); + conn->write(str.data(), str.length()); + return true; +} + +static bool callDumpDomTree(const Frame* frame, const Connection* conn) { + WebViewCore::getWebViewCore(frame->view())->dumpDomTree(true); + + FILE* f = fopen(DOM_TREE_LOG_FILE, "r"); + if (!f) { + conn->write("Dom tree written to logcat\n"); + } else { + char buf[512]; + while (true) { + int nread = fread(buf, 1, sizeof(buf), f); + if (nread <= 0) + break; + conn->write(buf, nread); + } + fclose(f); + } + return true; +} + +class WebCoreHandler : public Handler { +public: + virtual void post(TargetThreadFunction func, void* v) const { + callOnMainThread(func, v); + } +}; +static WebCoreHandler s_webcoreHandler; + +//------------------------------------------------------------------------------ +// End command section +//------------------------------------------------------------------------------ + +class InternalCommand : public Command { +public: + InternalCommand(const Command* comm, const Frame* frame, + const Connection* connection) + : Command(*comm) + , m_frame(frame) + , m_connection(connection) {} + virtual ~InternalCommand() { delete m_connection; } + + void doCommand() const { + LOGD("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); + } + +private: + const Frame* m_frame; + const Connection* m_connection; +}; + +static void commandDispatcher(void* v) { + InternalCommand* c = static_cast(v); + c->doCommand(); + delete c; +} + +void Command::dispatch() { + m_handler.post(commandDispatcher, this); +} + +Vector* Command::s_commands; + +void Command::Init() { + // Do not initialize twice. + if (s_commands) + return; + // XXX: Move this somewhere else. + s_commands = new Vector(); + s_commands->append(new Command("DDOM", "Dump Dom Tree", + callDumpDomTree, s_webcoreHandler)); + s_commands->append(new Command("DDRT", "Dump Render Tree", + callDumpRenderTree, s_webcoreHandler)); +} + +Command* Command::Find(const Connection* conn) { + char buf[COMMAND_LENGTH]; + if (conn->read(buf, sizeof(buf)) != COMMAND_LENGTH) + return NULL; + + // Linear search of commands. TODO: binary search when more commands are + // added. + Vector::const_iterator i = s_commands->begin(); + Vector::const_iterator end = s_commands->end(); + while (i != end) { + if (strncmp(buf, (*i)->name(), sizeof(buf)) == 0) + return new InternalCommand(*i, server()->getFrame(0), conn); + i++; + } + return NULL; +} + +} // end namespace WDS + +} // end namespace android + +#endif diff --git a/Source/WebKit/android/wds/Command.h b/Source/WebKit/android/wds/Command.h new file mode 100644 index 0000000..90861d4 --- /dev/null +++ b/Source/WebKit/android/wds/Command.h @@ -0,0 +1,108 @@ +/* + * 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 WDS_COMMAND_H +#define WDS_COMMAND_H + +#include "wtf/MainThread.h" +#include "wtf/Vector.h" + +namespace WebCore { +class Frame; +} + +using namespace WTF; +using namespace WebCore; + +namespace android { + +// WebCore Debug Server +namespace WDS { + +class Connection; + +// Command identifier length +#define COMMAND_LENGTH 4 + +// The dispatcher function called with a Frame for context and the established +// connection to the client. The connection can be used to read and write to the +// client application. Return true on successful completion of the command, +// return false to indicate failure. +typedef bool (*DispatchFunction)(const Frame*, const Connection*); + +// Note: Although the type is named MainThreadFunction, it may not always be +// the main thread. The type is generic enough to reuse here but named +// something more appropriate. +typedef MainThreadFunction TargetThreadFunction; + +// Helper class to dipatch functions on a particular thread. +class Handler { +public: + virtual ~Handler() {} + virtual void post(TargetThreadFunction, void*) const = 0; +}; + +// Class for containing information about particular commands. +class Command { +public: + Command(const char* name, const char* desc, const DispatchFunction func, + const Handler& handler) + : m_name(name) + , m_description(desc) + , m_dispatch(func) + , m_handler(handler) {} + Command(const Command& comm) + : m_name(comm.m_name) + , m_description(comm.m_description) + , m_dispatch(comm.m_dispatch) + , m_handler(comm.m_handler) {} + virtual ~Command() {} + + // Initialize the debug server commands + static void Init(); + + // Find the command specified by the client request. + static Command* Find(const Connection* conn); + + // Dispatch this command + void dispatch(); + + const char* name() const { return m_name; } + +protected: + const char* m_name; + const char* m_description; + const DispatchFunction m_dispatch; + +private: + const Handler& m_handler; + static Vector* s_commands; +}; + +} // end namespace WDS + +} // end namespace android + +#endif diff --git a/Source/WebKit/android/wds/Connection.cpp b/Source/WebKit/android/wds/Connection.cpp new file mode 100644 index 0000000..d7e55ac --- /dev/null +++ b/Source/WebKit/android/wds/Connection.cpp @@ -0,0 +1,93 @@ +/* + * 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 "wds" +#include "config.h" + +#include "DebugServer.h" // used for ENABLE_WDS +#include "Connection.h" +#include +#include +#include + +#if ENABLE(WDS) + +#define MAX_CONNECTION_QUEUE 5 +#define log_errno(x) LOGE("%s: %d", x, strerror(errno)) + +namespace android { + +namespace WDS { + +bool Socket::open() { + m_fd = socket(PF_INET, SOCK_STREAM, 0); + if (m_fd < 0) { + log_errno("Failed to create file descriptor"); + return false; + } + return true; +} + +bool ConnectionServer::connect(short port) { + if (!m_socket.open()) + return false; + int fd = m_socket.fd(); + + // Build our sockaddr_in structure use to listen to incoming connections + sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_ANY); + addr.sin_port = htons(port); + + // Try to bind to the given port + if (bind(fd, (sockaddr*) &addr, sizeof(addr)) < 0) { + log_errno("Failed to bind to local host"); + return false; + } + + // Try to listen + if (listen(fd, MAX_CONNECTION_QUEUE) < 0) { + log_errno("Failed to listen"); + return false; + } + + return true; +} + +Connection* ConnectionServer::accept() const { + int conn = ::accept(m_socket.fd(), NULL, NULL); + if (conn < 0) { + log_errno("Accept failed"); + return NULL; + } + return new Connection(conn); +} + +} // end namespace WDS + +} // end namespace android + +#endif diff --git a/Source/WebKit/android/wds/Connection.h b/Source/WebKit/android/wds/Connection.h new file mode 100644 index 0000000..d67179e --- /dev/null +++ b/Source/WebKit/android/wds/Connection.h @@ -0,0 +1,86 @@ +/* + * 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 WDS_CONNECTION_H +#define WDS_CONNECTION_H + +#include +#include + +namespace android { + +namespace WDS { + +class Socket { +public: + Socket(): m_fd(-1) {} + Socket(int fd): m_fd(fd) {} + ~Socket() { + if (m_fd != -1) { + shutdown(m_fd, SHUT_RDWR); + close(m_fd); + } + } + // Open a new socket using PF_INET and SOCK_STREAM + bool open(); + int fd() const { return m_fd; } +private: + int m_fd; +}; + +class Connection { +public: + Connection(int conn): m_socket(conn) {} + int read(char buf[], size_t length) const { + return recv(m_socket.fd(), buf, length, 0); + } + int write(const char buf[], size_t length) const { + return send(m_socket.fd(), buf, length, 0); + } + int write(const char buf[]) const { + return write(buf, strlen(buf)); + } +private: + Socket m_socket; +}; + +class ConnectionServer { +public: + ConnectionServer() {} + + // Establish a connection to the local host on the given port. + bool connect(short port); + + // Blocks on the established socket until a new connection arrives. + Connection* accept() const; +private: + Socket m_socket; +}; + +} // end namespace WDS + +} // end namespace android + +#endif diff --git a/Source/WebKit/android/wds/DebugServer.cpp b/Source/WebKit/android/wds/DebugServer.cpp new file mode 100644 index 0000000..f33a65b --- /dev/null +++ b/Source/WebKit/android/wds/DebugServer.cpp @@ -0,0 +1,116 @@ +/* + * 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 "wds" +#include "config.h" + +#include "Command.h" +#include "Connection.h" +#include "DebugServer.h" +#include "wtf/MainThread.h" +#include "wtf/Threading.h" +#include +#include +#include +#include +#include +#include +#include + +#if ENABLE(WDS) + +#define DEFAULT_PORT 9999 +#define log_errno(x) LOGE("%s: %d", x, strerror(errno)) + +namespace android { + +namespace WDS { + +static DebugServer* s_server = NULL; + +// Main thread function for createThread +static void* mainThread(void* v) { + DebugServer* server = static_cast(v); + server->start(); + delete server; + s_server = NULL; + return NULL; +} + +DebugServer* server() { + if (s_server == NULL) + s_server = new DebugServer(); + return s_server; +} + +DebugServer::DebugServer() { + // Read webcore.wds.enable to determine if the debug server should run + char buf[PROPERTY_VALUE_MAX]; + int ret = property_get("webcore.wds.enable", buf, NULL); + if (ret != -1 && strcmp(buf, "1") == 0) { + LOGD("WDS Enabled"); + m_threadId = createThread(mainThread, this, "WDS"); + } + // Initialize the available commands. + Command::Init(); +} + +void DebugServer::start() { + LOGD("DebugServer thread started"); + + ConnectionServer cs; + if (!cs.connect(DEFAULT_PORT)) { + LOGE("Failed to start the server socket connection"); + return; + } + + while (true ) { + LOGD("Waiting for incoming connections..."); + Connection* conn = cs.accept(); + if (!conn) { + log_errno("Failed to accept new connections"); + return; + } + LOGD("...Connection established"); + + Command* c = Command::Find(conn); + if (!c) { + LOGE("Could not find matching command"); + delete conn; + } else { + // Dispatch the command, it will handle cleaning up the connection + // when finished. + c->dispatch(); + } + } + + LOGD("DebugServer thread finished"); +} + +} // end namespace WDS + +} // end namespace android + +#endif diff --git a/Source/WebKit/android/wds/DebugServer.h b/Source/WebKit/android/wds/DebugServer.h new file mode 100644 index 0000000..92edad9 --- /dev/null +++ b/Source/WebKit/android/wds/DebugServer.h @@ -0,0 +1,77 @@ +/* + * 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 DEBUGSERVER_H +#define DEBUGSERVER_H + +// Turn on the wds feature in webkit +#define ENABLE_WDS 0 + +#include "wtf/Threading.h" +#include "wtf/Vector.h" + +// Forward declarations. +namespace WebCore { + class Frame; +} + +using namespace WTF; +using namespace WebCore; + +namespace android { + +// WebCore Debug Server +namespace WDS { + +class DebugServer : WTFNoncopyable::Noncopyable { +public: + void start(); + void addFrame(Frame* frame) { + m_frames.append(frame); + } + void removeFrame(Frame* frame) { + size_t i = m_frames.find(frame); + if (i != notFound) + m_frames.remove(i); + } + Frame* getFrame(unsigned idx) { + if (idx < m_frames.size()) + return m_frames.at(idx); + return NULL; + } +private: + DebugServer(); + WTF::Vector m_frames; + ThreadIdentifier m_threadId; + friend DebugServer* server(); +}; + +DebugServer* server(); + +} // end namespace WDS + +} // end namespace android + +#endif diff --git a/Source/WebKit/android/wds/client/AdbConnection.cpp b/Source/WebKit/android/wds/client/AdbConnection.cpp new file mode 100644 index 0000000..465f9c3 --- /dev/null +++ b/Source/WebKit/android/wds/client/AdbConnection.cpp @@ -0,0 +1,237 @@ +/* + * 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 "wdsclient" + +#include "AdbConnection.h" +#include "ClientUtils.h" +#include "Device.h" +#include +#include +#include +#include +#include +#include + +void AdbConnection::close() { + if (m_fd != -1) { + shutdown(m_fd, SHUT_RDWR); + ::close(m_fd); + m_fd = -1; + } +} + +// Default adb port +#define ADB_PORT 5037 + +bool AdbConnection::connect() { + // Some commands (host:devices for example) close the connection so we call + // connect after the response. + close(); + + m_fd = socket(PF_INET, SOCK_STREAM, 0); + if (m_fd < 0) { + log_errno("Failed to create socket for connecting to adb"); + return false; + } + + // Create the socket address struct + sockaddr_in adb; + createTcpSocket(adb, ADB_PORT); + + // Connect to adb + if (::connect(m_fd, (sockaddr*) &adb, sizeof(adb)) < 0) { + log_errno("Failed to connect to adb"); + return false; + } + + // Connected + return true; +} + +// Adb protocol stuff +#define MAX_COMMAND_LENGTH 1024 +#define PAYLOAD_LENGTH 4 +#define PAYLOAD_FORMAT "%04X" + +bool AdbConnection::sendRequest(const char* fmt, ...) const { + if (m_fd == -1) { + LOGE("Connection is closed"); + return false; + } + + // Build the command (service) + char buf[MAX_COMMAND_LENGTH]; + va_list args; + va_start(args, fmt); + int res = vsnprintf(buf, MAX_COMMAND_LENGTH, fmt, args); + va_end(args); + + LOGV("Sending command: %04X%.*s", res, res, buf); + + // Construct the payload length + char payloadLen[PAYLOAD_LENGTH + 1]; + snprintf(payloadLen, sizeof(payloadLen), PAYLOAD_FORMAT, res); + + // First, send the payload length + if (send(m_fd, payloadLen, PAYLOAD_LENGTH, 0) < 0) { + log_errno("Failure when sending payload"); + return false; + } + + // Send the actual command + if (send(m_fd, buf, res, 0) < 0) { + log_errno("Failure when sending command"); + return false; + } + + // Check for the OKAY from adb + return checkOkayResponse(); +} + +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"); + lenStr[PAYLOAD_LENGTH] = 0; + + // Parse the hex payload + payloadLen = strtol(lenStr, NULL, 16); + if (payloadLen < 0) + return; + + // Grab the message + char* msg = new char[payloadLen + 1]; // include null-terminator + int res = recv(fd, msg, payloadLen, 0); + if (res < 0) { + log_errno("Failure reading failure message from adb"); + return; + } else if (res != payloadLen) { + LOGE("Incorrect payload length %d - expected %d", res, payloadLen); + return; + } + msg[res] = 0; + + // Tell somebody about it + LOGE("Received failure from adb: %s", msg); + + // Cleanup + delete[] msg; +} + +#define ADB_RESPONSE_LENGTH 4 + +bool AdbConnection::checkOkayResponse() const { + LOG_ASSERT(m_fd != -1, "Connection has been closed!"); + + char buf[ADB_RESPONSE_LENGTH]; + int res = recv(m_fd, buf, sizeof(buf), 0); + if (res < 0) { + log_errno("Failure reading response from adb"); + return false; + } + + // Check for a response other than OKAY/FAIL + if ((res == ADB_RESPONSE_LENGTH) && (strncmp(buf, "OKAY", res) == 0)) { + LOGV("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); + return false; +} + +void AdbConnection::clearDevices() { + for (unsigned i = 0; i < m_devices.size(); i++) + delete m_devices.editItemAt(i); + m_devices.clear(); +} + +const DeviceList& AdbConnection::getDeviceList() { + // Clear the current device list + clearDevices(); + + if (m_fd == -1) { + LOGE("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"); + return m_devices; + } + + // Get the payload length + char lenStr[PAYLOAD_LENGTH + 1]; + int res = recv(m_fd, lenStr, sizeof(lenStr) - 1, 0); + if (res < 0) { + log_errno("Failure to read payload size of device list"); + return m_devices; + } + lenStr[PAYLOAD_LENGTH] = 0; + + // Parse the hex payload + int payloadLen = strtol(lenStr, NULL, 16); + if (payloadLen < 0) + return m_devices; + + // Grab the list of devices. The format is as follows: + // + char* msg = new char[payloadLen + 1]; + res = recv(m_fd, msg, payloadLen, 0); + if (res < 0) { + log_errno("Failure reading the device list"); + return m_devices; + } else if (res != payloadLen) { + LOGE("Incorrect payload length %d - expected %d", res, payloadLen); + return m_devices; + } + msg[res] = 0; + + char serial[32]; + char state[32]; + int numRead; + char* ptr = msg; + while (sscanf(ptr, "%31s\t%31s\n%n", serial, state, &numRead) > 1) { + Device::DeviceType t = Device::DEVICE; + static const char emulator[] = "emulator-"; + if (strncmp(serial, emulator, sizeof(emulator) - 1) == 0) + t = Device::EMULATOR; + LOGV("Adding device %s (%s)", serial, state); + m_devices.add(new Device(serial, t, this)); + + // Reset for the next line + ptr += numRead; + } + // Cleanup + delete[] msg; + + return m_devices; +} diff --git a/Source/WebKit/android/wds/client/AdbConnection.h b/Source/WebKit/android/wds/client/AdbConnection.h new file mode 100644 index 0000000..58bad67 --- /dev/null +++ b/Source/WebKit/android/wds/client/AdbConnection.h @@ -0,0 +1,47 @@ +/* + * 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 WDS_ADB_CONNECTION_H +#define WDS_ADB_CONNECTION_H + +#include "DeviceList.h" + +class AdbConnection { +public: + AdbConnection() : m_fd(-1) {} + ~AdbConnection() { clearDevices(); } + void close(); + bool connect(); + bool sendRequest(const char* fmt, ...) const; + const DeviceList& getDeviceList(); + +private: + bool checkOkayResponse() const; + void clearDevices(); + DeviceList m_devices; + int m_fd; +}; + +#endif diff --git a/Source/WebKit/android/wds/client/Android.mk b/Source/WebKit/android/wds/client/Android.mk new file mode 100644 index 0000000..db79dd4 --- /dev/null +++ b/Source/WebKit/android/wds/client/Android.mk @@ -0,0 +1,39 @@ +## +## 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. +## + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + AdbConnection.cpp \ + ClientUtils.cpp \ + Device.cpp \ + main.cpp + +LOCAL_STATIC_LIBRARIES := liblog libutils libcutils + +LOCAL_MODULE:= wdsclient + +include $(BUILD_HOST_EXECUTABLE) diff --git a/Source/WebKit/android/wds/client/ClientUtils.cpp b/Source/WebKit/android/wds/client/ClientUtils.cpp new file mode 100644 index 0000000..f8ca889 --- /dev/null +++ b/Source/WebKit/android/wds/client/ClientUtils.cpp @@ -0,0 +1,35 @@ +/* + * 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 "ClientUtils.h" +#include +#include + +void createTcpSocket(sockaddr_in& addr, short port) { + memset(&addr, 0, sizeof(sockaddr_in)); + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr); +} diff --git a/Source/WebKit/android/wds/client/ClientUtils.h b/Source/WebKit/android/wds/client/ClientUtils.h new file mode 100644 index 0000000..5da1624 --- /dev/null +++ b/Source/WebKit/android/wds/client/ClientUtils.h @@ -0,0 +1,46 @@ +/* + * 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 WDS_CLIENT_UTILS_H +#define WDS_CLIENT_UTILS_H + +#include + +/* + * included for sockaddr_in structure, AF_INET definiton and etc. + */ +#ifdef __FreeBSD__ +#include +#include +#endif + +// Callers need to include Log.h and errno.h to use this macro +#define log_errno(str) LOGE("%s: %s", str, strerror(errno)) + +// Fill in the sockaddr_in structure for binding to the localhost on the given +// port +void createTcpSocket(sockaddr_in& addr, short port); + +#endif diff --git a/Source/WebKit/android/wds/client/Device.cpp b/Source/WebKit/android/wds/client/Device.cpp new file mode 100644 index 0000000..789a89d --- /dev/null +++ b/Source/WebKit/android/wds/client/Device.cpp @@ -0,0 +1,31 @@ +/* + * 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 "AdbConnection.h" +#include "Device.h" + +bool Device::sendRequest(const char* req) const { + return m_connection->sendRequest("host-serial:%s:%s", m_name, req); +} diff --git a/Source/WebKit/android/wds/client/Device.h b/Source/WebKit/android/wds/client/Device.h new file mode 100644 index 0000000..39d4b12 --- /dev/null +++ b/Source/WebKit/android/wds/client/Device.h @@ -0,0 +1,62 @@ +/* + * 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 WDS_DEVICE_H +#define WDS_DEVICE_H + +#include + +class AdbConnection; + +class Device { +public: + // Type of device. + // TODO: Add simulator support + enum DeviceType { + NONE = -1, + EMULATOR, + DEVICE + }; + + // Takes ownership of name + Device(char* name, DeviceType type, const AdbConnection* conn) + : m_connection(conn) + , m_name(strdup(name)) + , m_type(type) {} + ~Device() { free(m_name); } + + const char* name() const { return m_name; } + DeviceType type() const { return m_type; } + + // Send a request to this device. + bool sendRequest(const char* req) const; + +private: + const AdbConnection* m_connection; + char* m_name; + DeviceType m_type; +}; + +#endif diff --git a/Source/WebKit/android/wds/client/DeviceList.h b/Source/WebKit/android/wds/client/DeviceList.h new file mode 100644 index 0000000..45bfb87 --- /dev/null +++ b/Source/WebKit/android/wds/client/DeviceList.h @@ -0,0 +1,35 @@ +/* + * 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 WDS_DEVICE_LIST_H +#define WDS_DEVICE_LIST_H + +#include + +class Device; + +typedef android::Vector DeviceList; + +#endif diff --git a/Source/WebKit/android/wds/client/main.cpp b/Source/WebKit/android/wds/client/main.cpp new file mode 100644 index 0000000..1c7d856 --- /dev/null +++ b/Source/WebKit/android/wds/client/main.cpp @@ -0,0 +1,173 @@ +/* + * 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 "wdsclient" + +#include "AdbConnection.h" +#include "ClientUtils.h" +#include "Device.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEFAULT_WDS_PORT 9999 +#define STR(x) #x +#define XSTR(x) STR(x) +#define PORT_STR XSTR(DEFAULT_WDS_PORT) + +int wds_open() { + // Create the structure for connecting to the forwarded 9999 port + sockaddr_in addr; + createTcpSocket(addr, DEFAULT_WDS_PORT); + + // Create our socket + int fd = socket(PF_INET, SOCK_STREAM, 0); + if (fd < 0) { + log_errno("Failed to create file descriptor"); + return -1; + } + // Connect to the remote wds server thread + if (connect(fd, (sockaddr*)&addr, sizeof(addr)) < 0) { + log_errno("Failed to connect to remote debug server"); + return -1; + } + return fd; +} + +// Clean up the file descriptor and connections +void wds_close(int fd) { + if (fd != -1) { + shutdown(fd, SHUT_RDWR); + close(fd); + } +} + +int main(int argc, char** argv) { + + Device::DeviceType type = Device::NONE; + + if (argc <= 1) { + LOGE("wdsclient takes at least 1 argument"); + return 1; + } else { + // Parse the options, look for -e or -d to choose a device. + while (true) { + int c = getopt(argc, argv, "ed"); + if (c == -1) + break; + switch (c) { + case 'e': + type = Device::EMULATOR; + break; + case 'd': + type = Device::DEVICE; + break; + default: + break; + } + } + if (optind == argc) { + LOGE("No command specified"); + return 1; + } + } + + // Do the initial connection. + AdbConnection conn; + conn.connect(); + + const DeviceList& devices = conn.getDeviceList(); + // host:devices closes the connection, reconnect + conn.connect(); + + // 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"); + return 1; + } else if (devices.size() == 0) { + LOGE("No devices connected"); + return 1; + } + + // Find the correct device + const Device* device = NULL; + if (type == Device::NONE) + device = devices[0]; // grab the only one + else { + // Search for a matching device type + for (unsigned i = 0; i < devices.size(); i++) { + if (devices[i]->type() == type) { + device = devices[i]; + break; + } + } + } + + if (!device) { + LOGE("No device found!"); + return 1; + } + + // Forward tcp:9999 + if (!device->sendRequest("forward:tcp:" PORT_STR ";tcp:" PORT_STR)) { + LOGE("Failed to send forwarding request"); + return 1; + } + + LOGV("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); + return 1; + } + + // Open the wds connection + int wdsFd = wds_open(); + if (wdsFd == -1) + return 1; + + // Send the command specified + send(wdsFd, command, WDS_COMMAND_LENGTH, 0); // commands are 4 bytes + + // Read and display the response + char response[256]; + int res = 0; + while ((res = recv(wdsFd, response, sizeof(response), 0)) > 0) + printf("%.*s", res, response); + printf("\n\n"); + + // Shutdown + wds_close(wdsFd); + + return 0; +} diff --git a/WebKit/Android.mk b/WebKit/Android.mk deleted file mode 100644 index 5998227..0000000 --- a/WebKit/Android.mk +++ /dev/null @@ -1,132 +0,0 @@ -## -## -## Copyright 2008, The Android Open Source Project -## -## Licensed under the Apache License, Version 2.0 (the "License"); -## you may not use this file except in compliance with the License. -## You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## - -LOCAL_SRC_FILES := \ - android/WebCoreSupport/CachedFramePlatformDataAndroid.cpp \ - android/WebCoreSupport/ChromeClientAndroid.cpp \ - android/WebCoreSupport/ContextMenuClientAndroid.cpp \ - android/WebCoreSupport/DeviceMotionClientAndroid.cpp \ - android/WebCoreSupport/DeviceOrientationClientAndroid.cpp \ - android/WebCoreSupport/DragClientAndroid.cpp \ - android/WebCoreSupport/EditorClientAndroid.cpp \ - android/WebCoreSupport/FrameLoaderClientAndroid.cpp \ - android/WebCoreSupport/FrameNetworkingContextAndroid.cpp \ - android/WebCoreSupport/GeolocationPermissions.cpp \ - android/WebCoreSupport/MediaPlayerPrivateAndroid.cpp \ - android/WebCoreSupport/MemoryUsage.cpp \ - android/WebCoreSupport/PlatformBridge.cpp \ - android/WebCoreSupport/ResourceLoaderAndroid.cpp \ - android/WebCoreSupport/UrlInterceptResponse.cpp \ - android/WebCoreSupport/V8Counters.cpp - -ifeq ($(HTTP_STACK),chrome) -LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \ - android/WebCoreSupport/ChromiumInit.cpp \ - android/WebCoreSupport/CacheResult.cpp \ - android/WebCoreSupport/WebCache.cpp \ - android/WebCoreSupport/WebCookieJar.cpp \ - android/WebCoreSupport/WebUrlLoader.cpp \ - android/WebCoreSupport/WebUrlLoaderClient.cpp \ - android/WebCoreSupport/WebRequest.cpp \ - android/WebCoreSupport/WebRequestContext.cpp \ - android/WebCoreSupport/WebResourceRequest.cpp \ - android/WebCoreSupport/WebResponse.cpp \ - android/WebCoreSupport/WebViewClientError.cpp -endif # HTTP_STACK == chrome - -LOCAL_SRC_FILES := $(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/jni/CacheManager.cpp \ - android/jni/CookieManager.cpp \ - android/jni/DeviceMotionAndOrientationManager.cpp \ - android/jni/DeviceMotionClientImpl.cpp \ - android/jni/DeviceOrientationClientImpl.cpp \ - 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 \ - android/jni/WebStorage.cpp \ - android/jni/WebSettings.cpp \ - android/jni/WebViewCore.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/SelectText.cpp \ - android/nav/WebView.cpp \ - \ - android/plugins/ANPBitmapInterface.cpp \ - android/plugins/ANPCanvasInterface.cpp \ - android/plugins/ANPEventInterface.cpp \ - android/plugins/ANPLogInterface.cpp \ - android/plugins/ANPMatrixInterface.cpp \ - android/plugins/ANPOpenGLInterface.cpp \ - android/plugins/ANPPaintInterface.cpp \ - android/plugins/ANPPathInterface.cpp \ - android/plugins/ANPSoundInterface.cpp \ - android/plugins/ANPSurfaceInterface.cpp \ - android/plugins/ANPSystemInterface.cpp \ - android/plugins/ANPTypefaceInterface.cpp \ - android/plugins/ANPVideoInterface.cpp \ - android/plugins/ANPWindowInterface.cpp \ - android/plugins/PluginDebugAndroid.cpp \ - android/plugins/PluginTimer.cpp \ - android/plugins/PluginViewBridgeAndroid.cpp \ - android/plugins/PluginWidgetAndroid.cpp \ - android/plugins/SkANP.cpp \ - \ - android/wds/Command.cpp \ - android/wds/Connection.cpp \ - android/wds/DebugServer.cpp - -# Needed for autofill. -ifeq ($(ENABLE_AUTOFILL),true) -LOCAL_CFLAGS += -DENABLE_WEB_AUTOFILL - -LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \ - android/WebCoreSupport/autofill/AutoFillHostAndroid.cpp \ - android/WebCoreSupport/autofill/FormFieldAndroid.cpp \ - android/WebCoreSupport/autofill/FormManagerAndroid.cpp \ - android/WebCoreSupport/autofill/WebAutoFill.cpp -endif # ENABLE_AUTOFILL == true diff --git a/WebKit/android/AndroidLog.h b/WebKit/android/AndroidLog.h deleted file mode 100644 index a69dce6..0000000 --- a/WebKit/android/AndroidLog.h +++ /dev/null @@ -1,48 +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 ANDROIDLOG_H_ -#define ANDROIDLOG_H_ - -#ifdef ANDROID_DOM_LOGGING -#include -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__); } - -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__); } -#else -#define DUMP_DOM_LOGD(...) ((void)0) -#define DUMP_RENDER_LOGD(...) ((void)0) -#endif /* ANDROID_DOM_LOGGING */ - -#define DISPLAY_TREE_LOG_FILE "/sdcard/displayTree.txt" -#define LAYERS_TREE_LOG_FILE "/sdcard/layersTree.plist" - -#endif /* ANDROIDLOG_H_ */ diff --git a/WebKit/android/JavaVM/jni.h b/WebKit/android/JavaVM/jni.h deleted file mode 100644 index da02603..0000000 --- a/WebKit/android/JavaVM/jni.h +++ /dev/null @@ -1,32 +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 _JNI_COVER_H_ -#define _JNI_COVER_H_ - -#include "nativehelper/jni.h" -#define AttachCurrentThread(a, b) AttachCurrentThread((JNIEnv**) a, b) - -#endif diff --git a/WebKit/android/RenderSkinAndroid.cpp b/WebKit/android/RenderSkinAndroid.cpp deleted file mode 100644 index 9383a9c..0000000 --- a/WebKit/android/RenderSkinAndroid.cpp +++ /dev/null @@ -1,73 +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 "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" - -namespace WebCore { - -RenderSkinAndroid::~RenderSkinAndroid() -{ - delete m_button; -} -RenderSkinAndroid::RenderSkinAndroid(android::AssetManager* am, String drawableDirectory) -{ - m_button = new RenderSkinButton(am, drawableDirectory); - RenderSkinCombo::Init(am, drawableDirectory); - RenderSkinMediaButton::Init(am, drawableDirectory); - RenderSkinRadio::Init(am, drawableDirectory); -} - -bool RenderSkinAndroid::DecodeBitmap(android::AssetManager* am, const char* fileName, SkBitmap* bitmap) -{ - android::Asset* asset = am->open(fileName, android::Asset::ACCESS_BUFFER); - if (!asset) { - asset = am->openNonAsset(fileName, android::Asset::ACCESS_BUFFER); - if (!asset) { - LOGD("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); - } - - delete asset; - return success; -} - -} // namespace WebCore diff --git a/WebKit/android/RenderSkinAndroid.h b/WebKit/android/RenderSkinAndroid.h deleted file mode 100644 index 73773ea..0000000 --- a/WebKit/android/RenderSkinAndroid.h +++ /dev/null @@ -1,74 +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 RenderSkinAndroid_h -#define RenderSkinAndroid_h - -#include "PlatformString.h" - -namespace android { - class AssetManager; -} - -class SkBitmap; - -namespace WebCore { -class Node; -class RenderSkinButton; - -class RenderSkinAndroid -{ -public: - enum State { - kDisabled, - kNormal, - kFocused, - kPressed, - - kNumStates - }; - - /** - * Initialize the Android skinning system. The AssetManager may be used to find resources used - * in rendering. - */ - RenderSkinAndroid(android::AssetManager*, String drawableDirectory); - ~RenderSkinAndroid(); - - /* DecodeBitmap determines which file to use, with the given fileName of the form - * "images/bitmap.png", and uses the asset manager to select the exact one. It - * returns true if it successfully decoded the bitmap, false otherwise. - */ - static bool DecodeBitmap(android::AssetManager* am, const char* fileName, SkBitmap* bitmap); - - const RenderSkinButton* renderSkinButton() const { return m_button; } - -private: - RenderSkinButton* m_button; -}; - -} // WebCore - -#endif diff --git a/WebKit/android/RenderSkinButton.cpp b/WebKit/android/RenderSkinButton.cpp deleted file mode 100644 index 6a0ae54..0000000 --- a/WebKit/android/RenderSkinButton.cpp +++ /dev/null @@ -1,90 +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 -#include -#include -#include -#include -#include - -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(android::AssetManager* am, String drawableDirectory) -{ - m_decoded = true; - for (size_t i = 0; i < 4; i++) { - String path = String(drawableDirectory.impl()); - path.append(String(gFiles[i])); - if (!RenderSkinNinePatch::decodeAsset(am, path.utf8().data(), &m_buttons[i])) { - m_decoded = false; - LOGE("RenderSkinButton::Init: button assets failed to decode\n\tBrowser buttons will not draw"); - return; - } - } - - // 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::draw(SkCanvas* canvas, const IntRect& r, - RenderSkinAndroid::State newState) const -{ - // 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(newState) < - static_cast(RenderSkinAndroid::kNumStates)); - - RenderSkinNinePatch::DrawNinePatch(canvas, SkRect(r), m_buttons[newState]); -} - -} //WebCore diff --git a/WebKit/android/RenderSkinButton.h b/WebKit/android/RenderSkinButton.h deleted file mode 100644 index e9db74c..0000000 --- a/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: - /** - * Initialize the class before use. Uses the AssetManager to initialize any - * bitmaps the class may use. - */ - RenderSkinButton(android::AssetManager*, 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) const; -private: - bool m_decoded; - NinePatch m_buttons[4]; -}; - -} // WebCore -#endif diff --git a/WebKit/android/RenderSkinCombo.cpp b/WebKit/android/RenderSkinCombo.cpp deleted file mode 100644 index b30dc29..0000000 --- a/WebKit/android/RenderSkinCombo.cpp +++ /dev/null @@ -1,146 +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 - -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 -}; - -// There are 2.5 different concepts of a 'border' here, which results -// in rather a lot of magic constants. In each case, there are 2 -// numbers, one for medium res and one for high-res. All sizes are in pixels. - -// 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[2] = {22, 34}; -const int RenderSkinCombo::padMargin[2] = {2, 5}; - -// 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. -static const int stretchMargin[2] = {3, 5}; // border width for the bottom and left of the 9-patch -static const int stretchTop[2] = {15, 23}; // border width for the top of the 9-patch - -// 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. -static const int arrowWidth[2] = {22, 31}; - -RenderSkinCombo::Resolution RenderSkinCombo::resolution = MedRes; - -const SkIRect RenderSkinCombo::margin[2][2] = {{{ stretchMargin[MedRes], stretchTop[MedRes], - RenderSkinCombo::arrowMargin[MedRes] + stretchMargin[MedRes], stretchMargin[MedRes] }, - {0, stretchTop[MedRes], 0, stretchMargin[MedRes]}}, - {{ stretchMargin[HighRes], stretchTop[HighRes], - RenderSkinCombo::arrowMargin[HighRes] + stretchMargin[HighRes], stretchMargin[HighRes] }, - {0, stretchTop[HighRes], 0, stretchMargin[HighRes]}}}; -static SkBitmap bitmaps[2][2]; // Collection of assets for a combo box -static bool isDecoded; // True if all assets were decoded - -void RenderSkinCombo::Init(android::AssetManager* am, String drawableDirectory) -{ - if (isDecoded) - return; - - if (drawableDirectory[drawableDirectory.length() - 5] == 'h') - resolution = HighRes; - - 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[resolution], 0, width, height); - bitmaps[kNormal][FullAsset].extractSubset(&bitmaps[kNormal][NoBorder], subset); - bitmaps[kDisabled][FullAsset].extractSubset(&bitmaps[kDisabled][NoBorder], subset); -} - - -bool RenderSkinCombo::Draw(SkCanvas* canvas, Node* element, int x, int y, int width, int height) -{ - if (!isDecoded) - return true; - - State state = (element->isElementNode() && static_cast(element)->isEnabledFormControl()) ? kNormal : kDisabled; - height = std::max(height, (stretchMargin[resolution]<<1) + 1); - - 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; - } - SkNinePatch::DrawNine(canvas, bounds, bitmaps[state][drawBorder], margin[resolution][drawBorder]); - return false; -} - -} //WebCore diff --git a/WebKit/android/RenderSkinCombo.h b/WebKit/android/RenderSkinCombo.h deleted file mode 100644 index 38cd048..0000000 --- a/WebKit/android/RenderSkinCombo.h +++ /dev/null @@ -1,69 +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: - /** - * Initialize the class before use. Uses the AssetManager to initialize any bitmaps the class may use. - */ - static void Init(android::AssetManager*, String drawableDirectory); - - /** - * 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[resolution]; } - static int padding() { return padMargin[resolution]; } - - enum Resolution { - MedRes, - HighRes - }; -private: - static Resolution resolution; - const static int arrowMargin[2]; - const static int padMargin[2]; - const static SkIRect margin[2][2]; -}; - -} // WebCore - -#endif diff --git a/WebKit/android/RenderSkinMediaButton.cpp b/WebKit/android/RenderSkinMediaButton.cpp deleted file mode 100644 index 090d55e..0000000 --- a/WebKit/android/RenderSkinMediaButton.cpp +++ /dev/null @@ -1,215 +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. - */ - -#define LOG_TAG "WebCore" - -#include "config.h" -#include "android_graphics.h" -#include "Document.h" -#include "IntRect.h" -#include "Node.h" -#include "RenderObject.h" -#include "RenderSkinMediaButton.h" -#include "RenderSlider.h" -#include "SkCanvas.h" -#include "SkNinePatch.h" -#include "SkRect.h" -#include -#include -#include - -struct PatchData { - const char* name; - int8_t outset, margin; -}; - -static const PatchData gFiles[] = - { - { "scrubber_primary_holo.9.png", 0, 0 }, // SLIDER_TRACK, left of the SLIDER_THUMB - { "ic_media_pause.png", 0, 0}, // PAUSE - { "ic_media_play.png", 0, 0 }, // PLAY - { "ic_media_pause.png", 0, 0 }, // MUTE - { "ic_media_rew.png", 0, 0 }, // REWIND - { "ic_media_ff.png", 0, 0 }, // FORWARD - { "ic_media_fullscreen.png", 0, 0 }, // FULLSCREEN - { "spinner_76_outer_holo.png", 0, 0 }, // SPINNER_OUTER - { "spinner_76_inner_holo.png", 0, 0 }, // SPINNER_INNER - { "ic_media_video_poster.png", 0, 0 }, // VIDEO - { "btn_media_player_disabled.9.png", 0, 0 }, // BACKGROUND_SLIDER - { "scrubber_track_holo_dark.9.png", 0, 0 }, // SLIDER_TRACK - { "scrubber_control_holo.png", 0, 0 } // SLIDER_THUMB - }; - -static SkBitmap gButton[sizeof(gFiles)/sizeof(gFiles[0])]; -static bool gDecoded; -static bool gHighRes; - -namespace WebCore { - -void RenderSkinMediaButton::Init(android::AssetManager* am, String drawableDirectory) -{ - static bool gInited; - if (gInited) - return; - - gInited = true; - gDecoded = true; - gHighRes = drawableDirectory[drawableDirectory.length() - 5] == 'h'; - for (size_t i = 0; i < sizeof(gFiles)/sizeof(gFiles[0]); i++) { - String path = drawableDirectory + gFiles[i].name; - if (!RenderSkinAndroid::DecodeBitmap(am, path.utf8().data(), &gButton[i])) { - gDecoded = false; - LOGD("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) -{ - // 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 (!gDecoded) { - return; - } - - bool drawsNinePatch = false; - bool drawsImage = true; - bool drawsBackgroundColor = true; - - int ninePatchIndex = 0; - int imageIndex = 0; - - SkRect bounds(r); - SkScalar imageMargin = 8; - SkPaint paint; - - int alpha = 255; - if (translucent) - alpha = 190; - - SkColor backgroundColor = SkColorSetARGB(alpha, 34, 34, 34); - SkColor trackBackgroundColor = SkColorSetARGB(255, 100, 100, 100); - paint.setColor(backgroundColor); - paint.setFlags(SkPaint::kFilterBitmap_Flag); - - switch (buttonType) { - case PAUSE: - case PLAY: - case MUTE: - case REWIND: - case FORWARD: - case FULLSCREEN: - { - imageIndex = buttonType + 1; - paint.setColor(backgroundColor); - break; - } - case SPINNER_OUTER: - case SPINNER_INNER: - case VIDEO: - { - drawsBackgroundColor = false; - imageIndex = buttonType + 1; - break; - } - case BACKGROUND_SLIDER: - { - drawsBackgroundColor = false; - drawsImage = false; - break; - } - case SLIDER_TRACK: - { - drawsNinePatch = true; - drawsImage = false; - ninePatchIndex = buttonType + 1; - break; - } - case SLIDER_THUMB: - { - drawsBackgroundColor = false; - imageMargin = 0; - imageIndex = buttonType + 1; - break; - } - default: - return; - } - - if (drawsBackgroundColor) { - canvas->drawRect(r, paint); - } - - if (drawsNinePatch) { - const PatchData& pd = gFiles[ninePatchIndex]; - int marginValue = pd.margin + pd.outset; - - SkIRect margin; - margin.set(marginValue, marginValue, marginValue, marginValue); - if (buttonType == SLIDER_TRACK) { - // Cut the height in half (with some extra slop determined by trial - // and error to get the placement just right. - SkScalar quarterHeight = SkScalarHalf(SkScalarHalf(bounds.height())); - bounds.fTop += quarterHeight + SkScalarHalf(3); - bounds.fBottom += -quarterHeight + SK_ScalarHalf; - if (o && o->isSlider()) { - RenderSlider* slider = toRenderSlider(o); - IntRect thumb = slider->thumbRect(); - // Inset the track by half the width of the thumb, so the track - // does not appear to go beyond the space where the thumb can - // be. - SkScalar thumbHalfWidth = SkIntToScalar(thumb.width()/2); - bounds.fLeft += thumbHalfWidth; - bounds.fRight -= thumbHalfWidth; - if (thumb.x() > 0) { - // The video is past the starting point. Show the area to - // left of the thumb as having been played. - SkScalar alreadyPlayed = SkIntToScalar(thumb.center().x() + r.x()); - SkRect playedRect(bounds); - playedRect.fRight = alreadyPlayed; - SkNinePatch::DrawNine(canvas, playedRect, gButton[0], margin); - bounds.fLeft = alreadyPlayed; - } - - } - } - SkNinePatch::DrawNine(canvas, bounds, gButton[ninePatchIndex], margin); - } - - if (drawsImage) { - SkScalar SIZE = gButton[imageIndex].width(); - SkScalar width = r.width(); - SkScalar scale = SkScalarDiv(width - 2*imageMargin, SIZE); - int saveScaleCount = canvas->save(); - canvas->translate(bounds.fLeft + imageMargin, bounds.fTop + imageMargin); - canvas->scale(scale, scale); - canvas->drawBitmap(gButton[imageIndex], 0, 0, &paint); - canvas->restoreToCount(saveScaleCount); - } -} - -} // WebCore diff --git a/WebKit/android/RenderSkinMediaButton.h b/WebKit/android/RenderSkinMediaButton.h deleted file mode 100644 index 6aa9c4e..0000000 --- a/WebKit/android/RenderSkinMediaButton.h +++ /dev/null @@ -1,63 +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 RenderSkinMediaButton_h -#define RenderSkinMediaButton_h - -#include "RenderSkinAndroid.h" - -class SkCanvas; - -namespace WebCore { -class IntRect; -class RenderObject; - -class RenderSkinMediaButton { -public: - /** - * Initialize the class before use. Uses the AssetManager to initialize any - * bitmaps the class may use. - */ - static void Init(android::AssetManager*, 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. - */ - static void Draw(SkCanvas* , const IntRect& , int buttonType, bool translucent = false, - RenderObject* o = 0); - /** - * Button types - */ - enum { PAUSE, PLAY, MUTE, REWIND, FORWARD, FULLSCREEN, SPINNER_OUTER, SPINNER_INNER , VIDEO, BACKGROUND_SLIDER, SLIDER_TRACK, SLIDER_THUMB }; - /** - * Slider dimensions - */ - static int sliderThumbWidth() { return 32; } - static int sliderThumbHeight() { return 32; } - -}; - -} // WebCore -#endif // RenderSkinMediaButton_h diff --git a/WebKit/android/RenderSkinNinePatch.cpp b/WebKit/android/RenderSkinNinePatch.cpp deleted file mode 100644 index 0c915c0..0000000 --- a/WebKit/android/RenderSkinNinePatch.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "config.h" - -#include "RenderSkinNinePatch.h" -#include "NinePatchPeeker.h" -#include "SkCanvas.h" -#include "SkImageDecoder.h" -#include "SkRect.h" -#include "SkStream.h" -#include "SkTemplates.h" -#include -#include -#include -#include - -class SkPaint; -class SkRegion; - -using namespace android; - -extern void NinePatch_Draw(SkCanvas* canvas, const SkRect& bounds, - const SkBitmap& bitmap, const Res_png_9patch& chunk, - const SkPaint* paint, SkRegion** outRegion); - -bool RenderSkinNinePatch::decodeAsset(AssetManager* am, const char* filename, NinePatch* ninepatch) { - Asset* asset = am->open(filename, android::Asset::ACCESS_BUFFER); - if (!asset) { - asset = am->openNonAsset(filename, android::Asset::ACCESS_BUFFER); - if (!asset) { - return false; - } - } - - SkImageDecoder::Mode mode = SkImageDecoder::kDecodePixels_Mode; - SkBitmap::Config prefConfig = SkBitmap::kNo_Config; - SkStream* stream = new SkMemoryStream(asset->getBuffer(false), asset->getLength()); - SkImageDecoder* decoder = SkImageDecoder::Factory(stream); - if (!decoder) { - asset->close(); - LOGE("RenderSkinNinePatch::Failed to create an image decoder"); - return false; - } - - decoder->setSampleSize(1); - decoder->setDitherImage(true); - decoder->setPreferQualityOverSpeed(false); - - NinePatchPeeker peeker(decoder); - - SkAutoTDelete add(decoder); - - decoder->setPeeker(&peeker); - if (!decoder->decode(stream, &ninepatch->m_bitmap, prefConfig, mode, true)) { - asset->close(); - LOGE("RenderSkinNinePatch::Failed to decode nine patch asset"); - return false; - } - - asset->close(); - if (!peeker.fPatchIsValid) { - LOGE("RenderSkinNinePatch::Patch data not valid"); - return false; - } - void** data = &ninepatch->m_serializedPatchData; - *data = malloc(peeker.fPatch->serializedSize()); - peeker.fPatch->serialize(*data); - return true; -} - -void RenderSkinNinePatch::DrawNinePatch(SkCanvas* canvas, const SkRect& bounds, - const NinePatch& patch) { - Res_png_9patch* data = Res_png_9patch::deserialize(patch.m_serializedPatchData); - NinePatch_Draw(canvas, bounds, patch.m_bitmap, *data, 0, 0); -} diff --git a/WebKit/android/RenderSkinNinePatch.h b/WebKit/android/RenderSkinNinePatch.h deleted file mode 100644 index e4db260..0000000 --- a/WebKit/android/RenderSkinNinePatch.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef RenderSkinNinePatch_h -#define RenderSkinNinePatch_h - -#include "SkBitmap.h" -#include "utils/Asset.h" - -namespace android { - class AssetManager; -} - -class SkCanvas; -class SkRect; - -struct NinePatch { - SkBitmap m_bitmap; - void* m_serializedPatchData; - NinePatch() { - m_serializedPatchData = 0; - } - ~NinePatch() { - if (m_serializedPatchData) - free(m_serializedPatchData); - } -}; - -class RenderSkinNinePatch { -public: - static bool decodeAsset(android::AssetManager*, const char* fileName, NinePatch*); - static void DrawNinePatch(SkCanvas*, const SkRect&, const NinePatch&); -}; - -#endif // RenderSkinNinePatch_h diff --git a/WebKit/android/RenderSkinRadio.cpp b/WebKit/android/RenderSkinRadio.cpp deleted file mode 100644 index 5dfee4a..0000000 --- a/WebKit/android/RenderSkinRadio.cpp +++ /dev/null @@ -1,100 +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 - -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 SIZE; - -namespace WebCore { - -static SkBitmap s_bitmap[4]; -static bool s_decoded; - -void RenderSkinRadio::Init(android::AssetManager* am, String drawableDirectory) -{ - if (s_decoded) - return; - String path = drawableDirectory + checks[0]; - s_decoded = RenderSkinAndroid::DecodeBitmap(am, path.utf8().data(), &s_bitmap[0]); - path = drawableDirectory + checks[1]; - s_decoded = RenderSkinAndroid::DecodeBitmap(am, path.utf8().data(), &s_bitmap[1]) && s_decoded; - path = drawableDirectory + checks[2]; - s_decoded = RenderSkinAndroid::DecodeBitmap(am, path.utf8().data(), &s_bitmap[2]) && s_decoded; - path = drawableDirectory + checks[3]; - s_decoded = RenderSkinAndroid::DecodeBitmap(am, path.utf8().data(), &s_bitmap[3]) && s_decoded; - SIZE = SkIntToScalar(s_bitmap[0].width()); -} - -void RenderSkinRadio::Draw(SkCanvas* canvas, Node* element, const IntRect& ir, - bool isCheckBox) -{ - if (!s_decoded || !element) { - 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)->isEnabledFormControl()) { - paint.setAlpha(0x80); - } - SkScalar width = r.width(); - SkScalar scale = SkScalarDiv(width, SIZE); - saveScaleCount = canvas->save(); - canvas->translate(r.fLeft, r.fTop); - canvas->scale(scale, scale); - - bool checked = false; - if (InputElement* inputElement = toInputElement(static_cast(element))) { - checked = inputElement->isChecked(); - } - - canvas->drawBitmap(s_bitmap[checked + 2*(!isCheckBox)], - 0, 0, &paint); - canvas->restoreToCount(saveScaleCount); -} - -} //WebCore diff --git a/WebKit/android/RenderSkinRadio.h b/WebKit/android/RenderSkinRadio.h deleted file mode 100644 index f77e1be..0000000 --- a/WebKit/android/RenderSkinRadio.h +++ /dev/null @@ -1,61 +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 RenderSkinRadio_h -#define RenderSkinRadio_h - -#include "PlatformString.h" - -class SkCanvas; - -namespace android { - class AssetManager; -} - -namespace WebCore { - -class Node; -class IntRect; - -/* RenderSkin for a radio button or a checkbox - */ -class RenderSkinRadio -{ -public: - /** - * Initialize the class before use. Uses the AssetManager to initialize any bitmaps the class may use. - */ - static void Init(android::AssetManager*, String drawableDirectory); - - /** - * 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); -}; - -} // WebCore -#endif diff --git a/WebKit/android/TimeCounter.cpp b/WebKit/android/TimeCounter.cpp deleted file mode 100644 index 2393f8a..0000000 --- a/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 -#include -#include -#include -#include - -#if USE(JSC) -#include "JSDOMWindow.h" -#include -#include -#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((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((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/WebKit/android/TimeCounter.h b/WebKit/android/TimeCounter.h deleted file mode 100644 index 64908d1..0000000 --- a/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 TIME_COUNTER_H -#define TIME_COUNTER_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/WebKit/android/TimerClient.h b/WebKit/android/TimerClient.h deleted file mode 100644 index 0c3c84c..0000000 --- a/WebKit/android/TimerClient.h +++ /dev/null @@ -1,42 +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 TIMER_CLIENT_H -#define TIMER_CLIENT_H - -namespace android { - - class TimerClient - { - public: - virtual ~TimerClient() {} - virtual void setSharedTimerCallback(void(*f)()) = 0; - virtual void setSharedTimer(long long timemillis) = 0; - virtual void stopSharedTimer() = 0; - virtual void signalServiceFuncPtrQueue() = 0; - }; - -} -#endif diff --git a/WebKit/android/WebCoreSupport/CacheResult.cpp b/WebKit/android/WebCoreSupport/CacheResult.cpp deleted file mode 100644 index 5309c66..0000000 --- a/WebKit/android/WebCoreSupport/CacheResult.cpp +++ /dev/null @@ -1,251 +0,0 @@ -/* - * 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 "CacheResult.h" - -#include "WebResponse.h" -#include "WebUrlLoaderClient.h" -#include -#include - -using namespace base; -using namespace disk_cache; -using namespace net; -using namespace std; - -namespace android { - -// All public methods are called on a UI thread but we do work on the -// Chromium thread. However, because we block the WebCore thread while this -// work completes, we can never receive new public method calls while the -// Chromium thread work is in progress. - -// Copied from HttpCache -enum { - kResponseInfoIndex = 0, - kResponseContentIndex -}; - -CacheResult::CacheResult(disk_cache::Entry* entry, String url) - : m_entry(entry) - , m_onResponseHeadersDoneCallback(this, &CacheResult::onResponseHeadersDone) - , m_onReadNextChunkDoneCallback(this, &CacheResult::onReadNextChunkDone) - , m_url(url) -{ - ASSERT(m_entry); -} - -CacheResult::~CacheResult() -{ - m_entry->Close(); - // TODO: Should we also call DoneReadingFromEntry() on the cache for our - // entry? -} - -int64 CacheResult::contentSize() const -{ - // The android stack does not take the content length from the HTTP response - // headers but calculates it when writing the content to disk. It can never - // overflow a long because we limit the cache size. - return m_entry->GetDataSize(kResponseContentIndex); -} - -bool CacheResult::firstResponseHeader(const char* name, String* result, bool allowEmptyString) const -{ - string value; - if (responseHeaders() && responseHeaders()->EnumerateHeader(NULL, name, &value) && (!value.empty() || allowEmptyString)) { - *result = String(value.c_str()); - return true; - } - return false; -} - -String CacheResult::mimeType() const -{ - string mimeType; - if (responseHeaders()) - responseHeaders()->GetMimeType(&mimeType); - if (!mimeType.length() && m_url.length()) - mimeType = WebResponse::resolveMimeType(std::string(m_url.utf8().data(), m_url.length()), ""); - return String(mimeType.c_str()); -} - -int64 CacheResult::expires() const -{ - // We have to do this manually, rather than using HttpResponseHeaders::GetExpiresValue(), - // to handle the "-1" and "0" special cases. - string expiresString; - if (responseHeaders() && responseHeaders()->EnumerateHeader(NULL, "expires", &expiresString)) { - wstring expiresStringWide(expiresString.begin(), expiresString.end()); // inflate ascii - // We require the time expressed as ms since the epoch. - Time time; - if (Time::FromString(expiresStringWide.c_str(), &time)) { - // Will not overflow for a very long time! - return static_cast(1000.0 * time.ToDoubleT()); - } - - if (expiresString == "-1" || expiresString == "0") - return 0; - } - - // TODO - // The Android stack applies a heuristic to set an expiry date if the - // expires header is not set or can't be parsed. I'm not sure whether the Chromium cache - // does this, and if so, it may not be possible for us to get hold of it - // anyway to set it on the result. - return -1; -} - -int CacheResult::responseCode() const -{ - return responseHeaders() ? responseHeaders()->response_code() : 0; -} - -bool CacheResult::writeToFile(const String& filePath) const -{ - // Getting the headers is potentially async, so post to the Chromium thread - // and block here. - MutexLocker lock(m_mutex); - - base::Thread* thread = WebUrlLoaderClient::ioThread(); - if (!thread) - return false; - - CacheResult* me = const_cast(this); - thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(me, &CacheResult::writeToFileImpl)); - - m_filePath = filePath.threadsafeCopy(); - m_isAsyncOperationInProgress = true; - while (m_isAsyncOperationInProgress) - m_condition.wait(m_mutex); - - return m_wasWriteToFileSuccessful; -} - -void CacheResult::writeToFileImpl() -{ - m_bufferSize = m_entry->GetDataSize(kResponseContentIndex); - m_readOffset = 0; - m_wasWriteToFileSuccessful = false; - readNextChunk(); -} - -void CacheResult::readNextChunk() -{ - m_buffer = new IOBuffer(m_bufferSize); - int rv = m_entry->ReadData(kResponseInfoIndex, m_readOffset, m_buffer, m_bufferSize, &m_onReadNextChunkDoneCallback); - if (rv == ERR_IO_PENDING) - return; - - onReadNextChunkDone(rv); -}; - -void CacheResult::onReadNextChunkDone(int size) -{ - if (size > 0) { - // Still more reading to be done. - if (writeChunkToFile()) { - // TODO: I assume that we need to clear and resize the buffer for the next read? - m_readOffset += size; - m_bufferSize -= size; - readNextChunk(); - } else - onWriteToFileDone(); - return; - } - - if (!size) { - // Reached end of file. - if (writeChunkToFile()) - m_wasWriteToFileSuccessful = true; - } - onWriteToFileDone(); -} - -bool CacheResult::writeChunkToFile() -{ - PlatformFileHandle file; - file = openFile(m_filePath, OpenForWrite); - if (!isHandleValid(file)) - return false; - return WebCore::writeToFile(file, m_buffer->data(), m_bufferSize) == m_bufferSize; -} - -void CacheResult::onWriteToFileDone() -{ - MutexLocker lock(m_mutex); - m_isAsyncOperationInProgress = false; - m_condition.signal(); -} - -HttpResponseHeaders* CacheResult::responseHeaders() const -{ - MutexLocker lock(m_mutex); - if (m_responseHeaders) - return m_responseHeaders; - - // Getting the headers is potentially async, so post to the Chromium thread - // and block here. - base::Thread* thread = WebUrlLoaderClient::ioThread(); - if (!thread) - return 0; - - CacheResult* me = const_cast(this); - thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(me, &CacheResult::responseHeadersImpl)); - - m_isAsyncOperationInProgress = true; - while (m_isAsyncOperationInProgress) - m_condition.wait(m_mutex); - - return m_responseHeaders; -} - -void CacheResult::responseHeadersImpl() -{ - m_bufferSize = m_entry->GetDataSize(kResponseInfoIndex); - m_buffer = new IOBuffer(m_bufferSize); - - int rv = m_entry->ReadData(kResponseInfoIndex, 0, m_buffer, m_bufferSize, &m_onResponseHeadersDoneCallback); - if (rv == ERR_IO_PENDING) - return; - - onResponseHeadersDone(rv); -}; - -void CacheResult::onResponseHeadersDone(int size) -{ - MutexLocker lock(m_mutex); - // It's OK to throw away the HttpResponseInfo object as we hold our own ref - // to the headers. - HttpResponseInfo response; - bool truncated = false; // TODO: Waht is this param for? - if (size == m_bufferSize && HttpCache::ParseResponseInfo(m_buffer->data(), m_bufferSize, &response, &truncated)) - m_responseHeaders = response.headers; - m_isAsyncOperationInProgress = false; - m_condition.signal(); -} - -} // namespace android diff --git a/WebKit/android/WebCoreSupport/CacheResult.h b/WebKit/android/WebCoreSupport/CacheResult.h deleted file mode 100644 index c39570c..0000000 --- a/WebKit/android/WebCoreSupport/CacheResult.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * 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 CacheResult_h -#define CacheResult_h - -#include "ChromiumIncludes.h" - -#include -#include -#include - -namespace android { - -// A wrapper around a disk_cache::Entry. Provides fields appropriate for constructing a Java CacheResult object. -class CacheResult : public base::RefCountedThreadSafe { -public: - // Takes ownership of the Entry passed to the constructor. - CacheResult(disk_cache::Entry*, String url); - ~CacheResult(); - - int64 contentSize() const; - bool firstResponseHeader(const char* name, WTF::String* result, bool allowEmptyString) const; - // The Android stack uses the empty string if no Content-Type headers are - // found, so we use the same default here. - WTF::String mimeType() const; - // Returns the value of the expires header as milliseconds since the epoch. - int64 expires() const; - int responseCode() const; - bool writeToFile(const WTF::String& filePath) const; -private: - net::HttpResponseHeaders* responseHeaders() const; - void responseHeadersImpl(); - void onResponseHeadersDone(int size); - - void writeToFileImpl(); - void readNextChunk(); - void onReadNextChunkDone(int size); - bool writeChunkToFile(); - void onWriteToFileDone(); - - disk_cache::Entry* m_entry; - - scoped_refptr m_responseHeaders; - - int m_readOffset; - bool m_wasWriteToFileSuccessful; - mutable String m_filePath; - - int m_bufferSize; - scoped_refptr m_buffer; - mutable bool m_isAsyncOperationInProgress; - mutable WTF::Mutex m_mutex; - mutable WTF::ThreadCondition m_condition; - - net::CompletionCallbackImpl m_onResponseHeadersDoneCallback; - net::CompletionCallbackImpl m_onReadNextChunkDoneCallback; - - String m_url; -}; - -} // namespace android - -#endif diff --git a/WebKit/android/WebCoreSupport/CachedFramePlatformDataAndroid.cpp b/WebKit/android/WebCoreSupport/CachedFramePlatformDataAndroid.cpp deleted file mode 100644 index 30f374f..0000000 --- a/WebKit/android/WebCoreSupport/CachedFramePlatformDataAndroid.cpp +++ /dev/null @@ -1,66 +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 "config.h" - -#include "CachedFramePlatformDataAndroid.h" -#include "Settings.h" - -namespace android { - -CachedFramePlatformDataAndroid::CachedFramePlatformDataAndroid(WebCore::Settings* settings) -{ -#ifdef ANDROID_META_SUPPORT - m_viewport_width = settings->viewportWidth(); - m_viewport_height = settings->viewportHeight(); - m_viewport_initial_scale = settings->viewportInitialScale(); - m_viewport_minimum_scale = settings->viewportMinimumScale(); - m_viewport_maximum_scale = settings->viewportMaximumScale(); - m_viewport_target_densitydpi = settings->viewportTargetDensityDpi(); - m_viewport_user_scalable = settings->viewportUserScalable(); - m_format_detection_address = settings->formatDetectionAddress(); - m_format_detection_email = settings->formatDetectionEmail(); - m_format_detection_telephone = settings->formatDetectionTelephone(); -#endif - -} - -#ifdef ANDROID_META_SUPPORT -void CachedFramePlatformDataAndroid::restoreMetadata(WebCore::Settings* settings) -{ - settings->setViewportWidth(m_viewport_width); - settings->setViewportHeight(m_viewport_height); - settings->setViewportInitialScale(m_viewport_initial_scale); - settings->setViewportMinimumScale(m_viewport_minimum_scale); - settings->setViewportMaximumScale(m_viewport_maximum_scale); - settings->setViewportTargetDensityDpi(m_viewport_target_densitydpi); - settings->setViewportUserScalable(m_viewport_user_scalable); - settings->setFormatDetectionAddress(m_format_detection_address); - settings->setFormatDetectionEmail(m_format_detection_email); - settings->setFormatDetectionTelephone(m_format_detection_telephone); -} -#endif - -} diff --git a/WebKit/android/WebCoreSupport/CachedFramePlatformDataAndroid.h b/WebKit/android/WebCoreSupport/CachedFramePlatformDataAndroid.h deleted file mode 100644 index 20c7be4..0000000 --- a/WebKit/android/WebCoreSupport/CachedFramePlatformDataAndroid.h +++ /dev/null @@ -1,63 +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 CachedFramePlatformDatatAndroid_h -#define CachedFramePlatformDatatAndroid_h - -#include "CachedFramePlatformData.h" - -namespace WebCore { - class Settings; -} - -namespace android { - -class CachedFramePlatformDataAndroid : public WebCore::CachedFramePlatformData { -public: - CachedFramePlatformDataAndroid(WebCore::Settings* settings); - -#ifdef ANDROID_META_SUPPORT - void restoreMetadata(WebCore::Settings* settings); -#endif - -private: -#ifdef ANDROID_META_SUPPORT - // meta data of the frame - int m_viewport_width; - int m_viewport_height; - int m_viewport_initial_scale; - int m_viewport_minimum_scale; - int m_viewport_maximum_scale; - int m_viewport_target_densitydpi; - bool m_viewport_user_scalable : 1; - bool m_format_detection_address : 1; - bool m_format_detection_email : 1; - bool m_format_detection_telephone : 1; -#endif -}; - -} - -#endif diff --git a/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp b/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp deleted file mode 100644 index 6f872b8..0000000 --- a/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp +++ /dev/null @@ -1,605 +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. - */ - -#define LOG_TAG "WebCore" - -#include "config.h" - -#include "ApplicationCacheStorage.h" -#include "ChromeClientAndroid.h" -#include "DatabaseTracker.h" -#include "Document.h" -#include "PlatformString.h" -#include "FloatRect.h" -#include "Frame.h" -#include "FrameLoader.h" -#include "FrameView.h" -#include "Geolocation.h" -#include "HTMLMediaElement.h" -#include "HTMLNames.h" -#include "Icon.h" -#include "LayerAndroid.h" -#include "Page.h" -#include "PopupMenuAndroid.h" -#include "ScriptController.h" -#include "SearchPopupMenuAndroid.h" -#include "WebCoreFrameBridge.h" -#include "WebCoreViewBridge.h" -#include "WebViewCore.h" -#include "WindowFeatures.h" -#include "Settings.h" -#include "UserGestureIndicator.h" -#include - -namespace android { - -#if ENABLE(DATABASE) -static unsigned long long tryToReclaimDatabaseQuota(SecurityOrigin* originNeedingQuota); -#endif - -#if USE(ACCELERATED_COMPOSITING) - -WebCore::GraphicsLayer* ChromeClientAndroid::layersSync() -{ - if (m_rootGraphicsLayer && m_needsLayerSync && m_webFrame) { - if (FrameView* frameView = m_webFrame->page()->mainFrame()->view()) - frameView->syncCompositingStateRecursive(); - } - m_needsLayerSync = false; - return m_rootGraphicsLayer; -} - -void ChromeClientAndroid::scheduleCompositingLayerSync() -{ - if (m_needsLayerSync) - return; - m_needsLayerSync = true; - WebViewCore* webViewCore = WebViewCore::getWebViewCore(m_webFrame->page()->mainFrame()->view()); - if (webViewCore) - webViewCore->layersDraw(); -} - -void ChromeClientAndroid::setNeedsOneShotDrawingSynchronization() -{ - // This should not be needed -} - -void ChromeClientAndroid::attachRootGraphicsLayer(WebCore::Frame*, WebCore::GraphicsLayer* layer) -{ - // frame is not used in Android as we should only get root graphics layer for the main frame - m_rootGraphicsLayer = layer; - if (!layer) - return; - scheduleCompositingLayerSync(); -} - -#endif - -void ChromeClientAndroid::setWebFrame(android::WebFrame* webframe) -{ - Release(m_webFrame); - m_webFrame = webframe; - Retain(m_webFrame); -} - -void ChromeClientAndroid::chromeDestroyed() -{ - Release(m_webFrame); - delete this; -} - -void ChromeClientAndroid::setWindowRect(const FloatRect&) { notImplemented(); } - -FloatRect ChromeClientAndroid::windowRect() { - ASSERT(m_webFrame); - if (!m_webFrame) - return FloatRect(); - FrameView* frameView = m_webFrame->page()->mainFrame()->view(); - if (!frameView) - return FloatRect(); - const WebCoreViewBridge* bridge = frameView->platformWidget(); - const IntRect& rect = bridge->getWindowBounds(); - FloatRect fRect(rect.x(), rect.y(), rect.width(), rect.height()); - return fRect; -} - -FloatRect ChromeClientAndroid::pageRect() { notImplemented(); return FloatRect(); } - -float ChromeClientAndroid::scaleFactor() -{ - ASSERT(m_webFrame); - return m_webFrame->density(); -} - -void ChromeClientAndroid::focus() -{ - ASSERT(m_webFrame); - bool isUserGesture = UserGestureIndicator::processingUserGesture(); - - // Ask the application to focus this WebView if the action is intiated by the user - if (isUserGesture) - m_webFrame->requestFocus(); -} -void ChromeClientAndroid::unfocus() { notImplemented(); } - -bool ChromeClientAndroid::canTakeFocus(FocusDirection) { notImplemented(); return false; } -void ChromeClientAndroid::takeFocus(FocusDirection) { notImplemented(); } - -void ChromeClientAndroid::focusedNodeChanged(Node* node) -{ - android::WebViewCore::getWebViewCore(m_webFrame->page()->mainFrame()->view())->focusNodeChanged(node); -} - -void ChromeClientAndroid::focusedFrameChanged(Frame*) { notImplemented(); } - -Page* ChromeClientAndroid::createWindow(Frame* frame, const FrameLoadRequest&, - const WindowFeatures& features, const NavigationAction&) -{ - ASSERT(frame); -#ifdef ANDROID_MULTIPLE_WINDOWS - if (frame->settings() && !(frame->settings()->supportMultipleWindows())) - // If the client doesn't support multiple windows, just return the current page - return frame->page(); -#endif - - const WebCoreViewBridge* bridge = frame->view()->platformWidget(); - bool dialog = features.dialog || !features.resizable - || (features.heightSet && features.height < bridge->height() - && features.widthSet && features.width < bridge->width()) - || (!features.menuBarVisible && !features.statusBarVisible - && !features.toolBarVisible && !features.locationBarVisible - && !features.scrollbarsVisible); - // fullscreen definitely means no dialog - if (features.fullscreen) - dialog = false; - WebCore::Frame* newFrame = m_webFrame->createWindow(dialog, - ScriptController::processingUserGesture()); - if (newFrame) { - WebCore::Page* page = newFrame->page(); - page->setGroupName(frame->page()->groupName()); - return page; - } - return NULL; -} - -void ChromeClientAndroid::show() { notImplemented(); } - -bool ChromeClientAndroid::canRunModal() { notImplemented(); return false; } -void ChromeClientAndroid::runModal() { notImplemented(); } - -void ChromeClientAndroid::setToolbarsVisible(bool) { notImplemented(); } -bool ChromeClientAndroid::toolbarsVisible() { notImplemented(); return false; } - -void ChromeClientAndroid::setStatusbarVisible(bool) { notImplemented(); } -bool ChromeClientAndroid::statusbarVisible() { notImplemented(); return false; } - -void ChromeClientAndroid::setScrollbarsVisible(bool) { notImplemented(); } -bool ChromeClientAndroid::scrollbarsVisible() { notImplemented(); return false; } - -void ChromeClientAndroid::setMenubarVisible(bool) { notImplemented(); } -bool ChromeClientAndroid::menubarVisible() { notImplemented(); return false; } - -void ChromeClientAndroid::setResizable(bool) { notImplemented(); } - -#if ENABLE(CONTEXT_MENUS) -void ChromeClientAndroid::showContextMenu() { notImplemented(); } -#endif - -// This function is called by the JavaScript bindings to print usually an error to -// a message console. Pass the message to the java side so that the client can -// handle it as it sees fit. -void ChromeClientAndroid::addMessageToConsole(MessageSource, MessageType, MessageLevel msgLevel, const String& message, unsigned int lineNumber, const String& sourceID) { - android::WebViewCore::getWebViewCore(m_webFrame->page()->mainFrame()->view())->addMessageToConsole(message, lineNumber, sourceID, msgLevel); -} - -void ChromeClientAndroid::formDidBlur(const WebCore::Node* node) -{ - android::WebViewCore::getWebViewCore(m_webFrame->page()->mainFrame()->view())->formDidBlur(node); -} - -bool ChromeClientAndroid::canRunBeforeUnloadConfirmPanel() { return true; } -bool ChromeClientAndroid::runBeforeUnloadConfirmPanel(const String& message, Frame* frame) { - String url = frame->document()->documentURI(); - return android::WebViewCore::getWebViewCore(frame->view())->jsUnload(url, message); -} - -void ChromeClientAndroid::closeWindowSoon() -{ - ASSERT(m_webFrame); - Page* page = m_webFrame->page(); - Frame* mainFrame = page->mainFrame(); - // This will prevent javascript cross-scripting during unload - page->setGroupName(String()); - // Stop loading but do not send the unload event - mainFrame->loader()->stopLoading(UnloadEventPolicyNone); - // Cancel all pending loaders - mainFrame->loader()->stopAllLoaders(); - // Remove all event listeners so that no javascript can execute as a result - // of mouse/keyboard events. - mainFrame->document()->removeAllEventListeners(); - // Close the window. - m_webFrame->closeWindow(android::WebViewCore::getWebViewCore(mainFrame->view())); -} - -void ChromeClientAndroid::runJavaScriptAlert(Frame* frame, const String& message) -{ - String url = frame->document()->documentURI(); - - android::WebViewCore::getWebViewCore(frame->view())->jsAlert(url, message); -} - -bool ChromeClientAndroid::runJavaScriptConfirm(Frame* frame, const String& message) -{ - String url = frame->document()->documentURI(); - - return android::WebViewCore::getWebViewCore(frame->view())->jsConfirm(url, message); -} - -/* This function is called for the javascript method Window.prompt(). A dialog should be shown on - * the screen with an input put box. First param is the text, the second is the default value for - * the input box, third is return param. If the function returns true, the value set in the third parameter - * is provided to javascript, else null is returned to the script. - */ -bool ChromeClientAndroid::runJavaScriptPrompt(Frame* frame, const String& message, const String& defaultValue, String& result) -{ - String url = frame->document()->documentURI(); - return android::WebViewCore::getWebViewCore(frame->view())->jsPrompt(url, message, defaultValue, result); -} -void ChromeClientAndroid::setStatusbarText(const String&) { notImplemented(); } - -// This is called by the JavaScript interpreter when a script has been running for a long -// time. A dialog should be shown to the user asking them if they would like to cancel the -// Javascript. If true is returned, the script is cancelled. -// To make a device more responsive, we default to return true to disallow long running script. -// This implies that some of scripts will not be completed. -bool ChromeClientAndroid::shouldInterruptJavaScript() { - FrameView* frameView = m_webFrame->page()->mainFrame()->view(); - return android::WebViewCore::getWebViewCore(frameView)->jsInterrupt(); -} - -bool ChromeClientAndroid::tabsToLinks() const { return false; } - -IntRect ChromeClientAndroid::windowResizerRect() const { return IntRect(0, 0, 0, 0); } - -void ChromeClientAndroid::invalidateWindow(const IntRect&, bool) -{ - notImplemented(); -} - -void ChromeClientAndroid::invalidateContentsAndWindow(const IntRect& updateRect, bool /*immediate*/) -{ - notImplemented(); -} - -void ChromeClientAndroid::invalidateContentsForSlowScroll(const IntRect& updateRect, bool immediate) -{ - notImplemented(); -} - -// new to change 38068 (Nov 6, 2008) -void ChromeClientAndroid::scroll(const IntSize& scrollDelta, - const IntRect& rectToScroll, const IntRect& clipRect) { - notImplemented(); -} - -// new to change 38068 (Nov 6, 2008) -IntPoint ChromeClientAndroid::screenToWindow(const IntPoint&) const { - notImplemented(); - return IntPoint(); -} - -// new to change 38068 (Nov 6, 2008) -IntRect ChromeClientAndroid::windowToScreen(const IntRect&) const { - notImplemented(); - return IntRect(); -} - -PlatformPageClient ChromeClientAndroid::platformPageClient() const { - Page* page = m_webFrame->page(); - Frame* mainFrame = page->mainFrame(); - FrameView* view = mainFrame->view(); - PlatformWidget viewBridge = view->platformWidget(); - return viewBridge; -} - -void ChromeClientAndroid::contentsSizeChanged(Frame*, const IntSize&) const -{ - notImplemented(); -} - -void ChromeClientAndroid::scrollRectIntoView(const IntRect&, const ScrollView*) const -{ - notImplemented(); -} - -void ChromeClientAndroid::formStateDidChange(const Node*) -{ - notImplemented(); -} - -void ChromeClientAndroid::scrollbarsModeDidChange() const -{ - notImplemented(); -} - -void ChromeClientAndroid::mouseDidMoveOverElement(const HitTestResult&, unsigned int) {} -void ChromeClientAndroid::setToolTip(const String&, TextDirection) {} -void ChromeClientAndroid::print(Frame*) {} - -/* - * This function is called on the main (webcore) thread by SQLTransaction::deliverQuotaIncreaseCallback. - * The way that the callback mechanism is designed inside SQLTransaction means that there must be a new quota - * (which may be equal to the old quota if the user did not allow more quota) when this function returns. As - * we call into the browser thread to ask what to do with the quota, we block here and get woken up when the - * browser calls the native WebViewCore::SetDatabaseQuota method with the new quota value. - */ -#if ENABLE(DATABASE) -void ChromeClientAndroid::exceededDatabaseQuota(Frame* frame, const String& name) -{ - SecurityOrigin* origin = frame->document()->securityOrigin(); - DatabaseTracker& tracker = WebCore::DatabaseTracker::tracker(); - - // We want to wait on a new quota from the UI thread. Reset the m_newQuota variable to represent we haven't received a new quota. - m_newQuota = -1; - - // This origin is being tracked and has exceeded it's quota. Call into - // the Java side of things to inform the user. - unsigned long long currentQuota = 0; - if (tracker.hasEntryForOrigin(origin)) - currentQuota = tracker.quotaForOrigin(origin); - - unsigned long long estimatedSize = 0; - - // Only update estimatedSize if we are trying to create a a new database, i.e. the usage for the database is 0. - if (tracker.usageForDatabase(name, origin) == 0) - estimatedSize = tracker.detailsForNameAndOrigin(name, origin).expectedUsage(); - - android::WebViewCore::getWebViewCore(frame->view())->exceededDatabaseQuota(frame->document()->documentURI(), name, currentQuota, estimatedSize); - - // We've sent notification to the browser so now wait for it to come back. - m_quotaThreadLock.lock(); - while (m_newQuota == -1) { - m_quotaThreadCondition.wait(m_quotaThreadLock); - } - m_quotaThreadLock.unlock(); - - // If new quota is unavailable, we may be able to resolve the situation by shrinking the quota of an origin that asked for a lot but is only using a little. - // If we find such a site, shrink it's quota and ask Java to try again. - - if ((unsigned long long) m_newQuota == currentQuota && !m_triedToReclaimDBQuota) { - m_triedToReclaimDBQuota = true; // we should only try this once per quota overflow. - unsigned long long reclaimedQuotaBytes = tryToReclaimDatabaseQuota(origin); - - // If we were able to free up enough space, try asking Java again. - // Otherwise, give up and deny the new database. :( - if (reclaimedQuotaBytes >= estimatedSize) { - exceededDatabaseQuota(frame, name); - return; - } - } - - // Update the DatabaseTracker with the new quota value (if the user declined - // new quota, this may equal the old quota) - tracker.setQuota(origin, m_newQuota); - m_triedToReclaimDBQuota = false; -} - -static unsigned long long tryToReclaimDatabaseQuota(SecurityOrigin* originNeedingQuota) { - DatabaseTracker& tracker = WebCore::DatabaseTracker::tracker(); - Vector > origins; - tracker.origins(origins); - unsigned long long reclaimedQuotaBytes = 0; - for (unsigned i = 0; i < origins.size(); i++) { - SecurityOrigin* originToReclaimFrom = origins[i].get(); - - // Don't try to reclaim from the origin that has exceeded its quota. - if (originToReclaimFrom->equal(originNeedingQuota)) - continue; - - unsigned long long originUsage = tracker.usageForOrigin(originToReclaimFrom); - unsigned long long originQuota = tracker.quotaForOrigin(originToReclaimFrom); - // If the origin has a quota that is more than it's current usage +1MB, shrink it. - static const int ONE_MB = 1 * 1024 * 1024; - if (originUsage + ONE_MB < originQuota) { - unsigned long long newQuota = originUsage + ONE_MB; - tracker.setQuota(originToReclaimFrom, newQuota); - reclaimedQuotaBytes += originQuota - newQuota; - } - } - return reclaimedQuotaBytes; -} -#endif - -#if ENABLE(OFFLINE_WEB_APPLICATIONS) -void ChromeClientAndroid::reachedMaxAppCacheSize(int64_t spaceNeeded) -{ - // Set m_newQuota before calling into the Java side. If we do this after, - // we could overwrite the result passed from the Java side and deadlock in the - // wait call below. - m_newQuota = -1; - Page* page = m_webFrame->page(); - Frame* mainFrame = page->mainFrame(); - FrameView* view = mainFrame->view(); - android::WebViewCore::getWebViewCore(view)->reachedMaxAppCacheSize(spaceNeeded); - - // We've sent notification to the browser so now wait for it to come back. - m_quotaThreadLock.lock(); - while (m_newQuota == -1) { - m_quotaThreadCondition.wait(m_quotaThreadLock); - } - m_quotaThreadLock.unlock(); - if (m_newQuota > 0) { - WebCore::cacheStorage().setMaximumSize(m_newQuota); - // Now the app cache will retry the saving the previously failed cache. - } -} -#endif - -void ChromeClientAndroid::populateVisitedLinks() -{ - Page* page = m_webFrame->page(); - Frame* mainFrame = page->mainFrame(); - FrameView* view = mainFrame->view(); - android::WebViewCore::getWebViewCore(view)->populateVisitedLinks(&page->group()); -} - -void ChromeClientAndroid::requestGeolocationPermissionForFrame(Frame* frame, Geolocation* geolocation) -{ - ASSERT(geolocation); - if (!m_geolocationPermissions) { - m_geolocationPermissions = new GeolocationPermissions(android::WebViewCore::getWebViewCore(frame->view()), - m_webFrame->page()->mainFrame()); - } - m_geolocationPermissions->queryPermissionState(frame); -} - -void ChromeClientAndroid::cancelGeolocationPermissionRequestForFrame(Frame* frame, WebCore::Geolocation*) -{ - if (m_geolocationPermissions) - m_geolocationPermissions->cancelPermissionStateQuery(frame); -} - -void ChromeClientAndroid::provideGeolocationPermissions(const String &origin, bool allow, bool remember) -{ - ASSERT(m_geolocationPermissions); - m_geolocationPermissions->providePermissionState(origin, allow, remember); -} - -void ChromeClientAndroid::storeGeolocationPermissions() -{ - GeolocationPermissions::maybeStorePermanentPermissions(); -} - -void ChromeClientAndroid::onMainFrameLoadStarted() -{ - if (m_geolocationPermissions.get()) - m_geolocationPermissions->resetTemporaryPermissionStates(); -} - -void ChromeClientAndroid::runOpenPanel(Frame* frame, - PassRefPtr chooser) -{ - android::WebViewCore* core = android::WebViewCore::getWebViewCore( - frame->view()); - core->openFileChooser(chooser); -} - -void ChromeClientAndroid::chooseIconForFiles(const Vector&, FileChooser*) -{ - notImplemented(); -} - -void ChromeClientAndroid::setCursor(const Cursor&) -{ - notImplemented(); -} - -void ChromeClientAndroid::wakeUpMainThreadWithNewQuota(long newQuota) { - MutexLocker locker(m_quotaThreadLock); - m_newQuota = newQuota; - m_quotaThreadCondition.signal(); -} - -#if ENABLE(TOUCH_EVENTS) -void ChromeClientAndroid::needTouchEvents(bool needTouchEvents) -{ - FrameView* frameView = m_webFrame->page()->mainFrame()->view(); - android::WebViewCore* core = android::WebViewCore::getWebViewCore(frameView); - if (core) - core->needTouchEvents(needTouchEvents); -} -#endif - -bool ChromeClientAndroid::selectItemWritingDirectionIsNatural() -{ - return false; -} - -PassRefPtr ChromeClientAndroid::createPopupMenu(PopupMenuClient* client) const -{ - return adoptRef(new PopupMenuAndroid(static_cast(client))); -} - -PassRefPtr ChromeClientAndroid::createSearchPopupMenu(PopupMenuClient*) const -{ - return adoptRef(new SearchPopupMenuAndroid); -} - -void ChromeClientAndroid::reachedApplicationCacheOriginQuota(SecurityOrigin*) -{ - notImplemented(); -} - -#if ENABLE(ANDROID_INSTALLABLE_WEB_APPS) -void ChromeClientAndroid::webAppCanBeInstalled() -{ - FrameView* frameView = m_webFrame->page()->mainFrame()->view(); - android::WebViewCore* core = android::WebViewCore::getWebViewCore(frameView); - if (core) - core->notifyWebAppCanBeInstalled(); -} -#endif - -#if ENABLE(VIDEO) -bool ChromeClientAndroid::supportsFullscreenForNode(const Node* node) -{ - return node->hasTagName(HTMLNames::videoTag); -} - -void ChromeClientAndroid::enterFullscreenForNode(Node* node) -{ - if (!node->hasTagName(HTMLNames::videoTag)) - return; - - HTMLMediaElement* videoElement = static_cast(node); - String url = videoElement->currentSrc(); - LayerAndroid* layer = videoElement->platformLayer(); - if (!layer) - return; - - FrameView* frameView = m_webFrame->page()->mainFrame()->view(); - android::WebViewCore* core = android::WebViewCore::getWebViewCore(frameView); - m_webFrame->page()->mainFrame()->document()->webkitWillEnterFullScreenForElement(videoElement); - if (core) - core->enterFullscreenForVideoLayer(layer->uniqueId(), url); -} - -void ChromeClientAndroid::exitFullscreenForNode(Node* node) -{ -} -#endif - -#if ENABLE(FULLSCREEN_API) -void ChromeClientAndroid::exitFullScreenForElement(Element* element) -{ - if (!element) - return; - - HTMLMediaElement* videoElement = static_cast(element); - videoElement->exitFullscreen(); -} -#endif - -} diff --git a/WebKit/android/WebCoreSupport/ChromeClientAndroid.h b/WebKit/android/WebCoreSupport/ChromeClientAndroid.h deleted file mode 100644 index d49cec8..0000000 --- a/WebKit/android/WebCoreSupport/ChromeClientAndroid.h +++ /dev/null @@ -1,216 +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 ChromeClientAndroid_h -#define ChromeClientAndroid_h - -#include "ChromeClient.h" - -#include "GeolocationPermissions.h" -#include "PopupMenu.h" -#include "SearchPopupMenu.h" -#include "Timer.h" -#include -#include - -namespace WebCore { -class PopupMenuClient; -class Geolocation; -} - -using namespace WebCore; - -namespace android { - class WebFrame; - - class ChromeClientAndroid : public ChromeClient { - public: - ChromeClientAndroid() : m_webFrame(0), m_geolocationPermissions(0) -#if USE(ACCELERATED_COMPOSITING) - , m_rootGraphicsLayer(0) - , m_needsLayerSync(false) -#endif - , m_triedToReclaimDBQuota(false) - { } - virtual void chromeDestroyed(); - - virtual void setWindowRect(const FloatRect&); - virtual FloatRect windowRect(); - - virtual FloatRect pageRect(); - - virtual float scaleFactor(); - - virtual void focus(); - virtual void unfocus(); - virtual void formDidBlur(const WebCore::Node*); - virtual bool canTakeFocus(FocusDirection); - virtual void takeFocus(FocusDirection); - - virtual void focusedNodeChanged(Node*); - virtual void focusedFrameChanged(Frame*); - - // The Frame pointer provides the ChromeClient with context about which - // Frame wants to create the new Page. Also, the newly created window - // should not be shown to the user until the ChromeClient of the newly - // created Page has its show method called. - virtual Page* createWindow(Frame*, const FrameLoadRequest&, const WindowFeatures&, const NavigationAction&); - virtual void show(); - - virtual bool canRunModal(); - virtual void runModal(); - - virtual void setToolbarsVisible(bool); - virtual bool toolbarsVisible(); - - virtual void setStatusbarVisible(bool); - virtual bool statusbarVisible(); - - virtual void setScrollbarsVisible(bool); - virtual bool scrollbarsVisible(); - - virtual void setMenubarVisible(bool); - virtual bool menubarVisible(); - - virtual void setResizable(bool); - - virtual void addMessageToConsole(MessageSource, MessageType, MessageLevel, const String& message, unsigned int lineNumber, const String& sourceID); - - virtual bool canRunBeforeUnloadConfirmPanel(); - virtual bool runBeforeUnloadConfirmPanel(const String& message, Frame* frame); - - virtual void closeWindowSoon(); - - virtual void runJavaScriptAlert(Frame*, const String&); - virtual bool runJavaScriptConfirm(Frame*, const String&); - virtual bool runJavaScriptPrompt(Frame*, const String& message, const String& defaultValue, String& result); - virtual void setStatusbarText(const String&); - virtual bool shouldInterruptJavaScript(); - virtual bool tabsToLinks() const; - - virtual IntRect windowResizerRect() const; - - // Methods used by HostWindow. - virtual void invalidateWindow(const WebCore::IntRect&, bool); - virtual void invalidateContentsAndWindow(const WebCore::IntRect&, bool); - virtual void invalidateContentsForSlowScroll(const WebCore::IntRect&, bool); - virtual void scroll(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect); - virtual IntPoint screenToWindow(const IntPoint&) const; - virtual IntRect windowToScreen(const IntRect&) const; - virtual PlatformPageClient platformPageClient() const; - virtual void contentsSizeChanged(Frame*, const IntSize&) const; - virtual void scrollRectIntoView(const IntRect&, const ScrollView*) const; - // End methods used by HostWindow. - - virtual void scrollbarsModeDidChange() const; - virtual void mouseDidMoveOverElement(const HitTestResult&, unsigned int); - - virtual void setToolTip(const String&, TextDirection); - - virtual void print(Frame*); -#if ENABLE(DATABASE) - virtual void exceededDatabaseQuota(Frame*, const String&); -#endif -#if ENABLE(OFFLINE_WEB_APPLICATIONS) - virtual void reachedMaxAppCacheSize(int64_t spaceNeeded); - virtual void reachedApplicationCacheOriginQuota(SecurityOrigin*); -#endif - - virtual void populateVisitedLinks(); - -#if ENABLE(TOUCH_EVENTS) - virtual void needTouchEvents(bool); -#endif - - // Methods used to request and provide Geolocation permissions. - virtual void requestGeolocationPermissionForFrame(Frame*, Geolocation*); - virtual void cancelGeolocationPermissionRequestForFrame(WebCore::Frame*, WebCore::Geolocation*); - // Android-specific - void provideGeolocationPermissions(const String &origin, bool allow, bool remember); - void storeGeolocationPermissions(); - void onMainFrameLoadStarted(); - - virtual void runOpenPanel(Frame*, PassRefPtr); - virtual void setCursor(const Cursor&); - virtual void chooseIconForFiles(const WTF::Vector&, FileChooser*); - - // Notification that the given form element has changed. This function - // will be called frequently, so handling should be very fast. - virtual void formStateDidChange(const Node*); - - virtual PassOwnPtr createHTMLParserQuirks() { return 0; } - - // Android-specific - void setWebFrame(android::WebFrame* webframe); - android::WebFrame* webFrame() { return m_webFrame; } - void wakeUpMainThreadWithNewQuota(long newQuota); - -#if USE(ACCELERATED_COMPOSITING) - virtual void attachRootGraphicsLayer(WebCore::Frame*, WebCore::GraphicsLayer* g); - virtual void setNeedsOneShotDrawingSynchronization(); - virtual void scheduleCompositingLayerSync(); - virtual bool allowsAcceleratedCompositing() const { return true; } - WebCore::GraphicsLayer* layersSync(); -#endif - - virtual bool selectItemWritingDirectionIsNatural(); - virtual PassRefPtr createPopupMenu(WebCore::PopupMenuClient*) const; - virtual PassRefPtr createSearchPopupMenu(WebCore::PopupMenuClient*) const; - -#if ENABLE(CONTEXT_MENUS) - virtual void showContextMenu(); -#endif - -#if ENABLE(ANDROID_INSTALLABLE_WEB_APPS) - virtual void webAppCanBeInstalled(); -#endif - -#if ENABLE(FULLSCREEN_API) - virtual void exitFullScreenForElement(Element*); -#endif - -#if ENABLE(VIDEO) - virtual bool supportsFullscreenForNode(const WebCore::Node*); - virtual void enterFullscreenForNode(WebCore::Node*); - virtual void exitFullscreenForNode(WebCore::Node*); -#endif - - private: - android::WebFrame* m_webFrame; - // The Geolocation permissions manager. - OwnPtr m_geolocationPermissions; -#if USE(ACCELERATED_COMPOSITING) - WebCore::GraphicsLayer* m_rootGraphicsLayer; - bool m_needsLayerSync; -#endif - WTF::ThreadCondition m_quotaThreadCondition; - WTF::Mutex m_quotaThreadLock; - long m_newQuota; - bool m_triedToReclaimDBQuota; - }; - -} - -#endif diff --git a/WebKit/android/WebCoreSupport/ChromiumIncludes.h b/WebKit/android/WebCoreSupport/ChromiumIncludes.h deleted file mode 100644 index 8166eb7..0000000 --- a/WebKit/android/WebCoreSupport/ChromiumIncludes.h +++ /dev/null @@ -1,104 +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 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). - -#ifdef LOG -#define LOG_WAS_DEFINED LOG -#undef LOG -#endif - -#ifdef LOG_ASSERT -#define LOG_ASSERT_WAS_DEFINED LOG_ASSERT -#undef LOG_ASSERT -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if ENABLE(WEB_AUTOFILL) -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#endif - -#undef LOG -#if defined(LOG_WAS_DEFINED) && defined(LOG_PRI) -#define LOG(priority, tag, ...) LOG_PRI(ANDROID_##priority, tag, __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/WebKit/android/WebCoreSupport/ChromiumInit.cpp b/WebKit/android/WebCoreSupport/ChromiumInit.cpp deleted file mode 100644 index 1872fb9..0000000 --- a/WebKit/android/WebCoreSupport/ChromiumInit.cpp +++ /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. - */ - -#include "config.h" -#include "ChromiumInit.h" - -#include "ChromiumIncludes.h" - -#include -#include - -namespace android { - -bool logMessageHandler(int severity, const char* file, int line, size_t message_start, const std::string& str) { - int androidSeverity = ANDROID_LOG_VERBOSE; - switch(severity) { - case logging::LOG_FATAL: - androidSeverity = ANDROID_LOG_FATAL; - break; - case logging::LOG_ERROR_REPORT: - case logging::LOG_ERROR: - androidSeverity = ANDROID_LOG_ERROR; - break; - case logging::LOG_WARNING: - androidSeverity = ANDROID_LOG_WARN; - break; - default: - androidSeverity = ANDROID_LOG_VERBOSE; - break; - } - android_printLog(androidSeverity, "chromium", "%s:%d: %s", file, line, str.c_str()); - return false; -} - -namespace { - scoped_ptr networkChangeNotifier; -} - -void initChromium() -{ - static Lock lock; - AutoLock aLock(lock); - static bool initCalled = false; - if (!initCalled) { - logging::SetLogMessageHandler(logMessageHandler); - networkChangeNotifier.reset(net::NetworkChangeNotifier::Create()); - net::HttpNetworkLayer::EnableSpdy("npn"); - initCalled = true; - } -} - -} // namespace android diff --git a/WebKit/android/WebCoreSupport/ChromiumInit.h b/WebKit/android/WebCoreSupport/ChromiumInit.h deleted file mode 100644 index 235c3dc..0000000 --- a/WebKit/android/WebCoreSupport/ChromiumInit.h +++ /dev/null @@ -1,38 +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 ChromiumLogging_h -#define ChromiumLogging_h - -namespace android { - -// Sends chromium logs to logcat -// -// This only calls into chromium once, but can be called multiple times. -// It should be called before any other calls into external/chromium. -void initChromium(); -} - -#endif diff --git a/WebKit/android/WebCoreSupport/ContextMenuClientAndroid.cpp b/WebKit/android/WebCoreSupport/ContextMenuClientAndroid.cpp deleted file mode 100644 index 3dc4b00..0000000 --- a/WebKit/android/WebCoreSupport/ContextMenuClientAndroid.cpp +++ /dev/null @@ -1,51 +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 "config.h" -#include "ContextMenuClientAndroid.h" - -#include "NotImplemented.h" -#include - -namespace WebCore { - -void ContextMenuClientAndroid::contextMenuDestroyed() { delete this; } - -PlatformMenuDescription ContextMenuClientAndroid::getCustomMenuFromDefaultItems(ContextMenu*) { notImplemented(); return 0; } -void ContextMenuClientAndroid::contextMenuItemSelected(ContextMenuItem*, const ContextMenu*) { notImplemented(); } - -void ContextMenuClientAndroid::downloadURL(const KURL& url) { notImplemented(); } -void ContextMenuClientAndroid::copyImageToClipboard(const HitTestResult&) { notImplemented(); } -void ContextMenuClientAndroid::searchWithGoogle(const Frame*) { notImplemented(); } -void ContextMenuClientAndroid::lookUpInDictionary(Frame*) { notImplemented(); } -void ContextMenuClientAndroid::speak(const String&) { notImplemented(); } -void ContextMenuClientAndroid::stopSpeaking() { notImplemented(); } -bool ContextMenuClientAndroid::isSpeaking() -{ - notImplemented(); - return false; -} - -} diff --git a/WebKit/android/WebCoreSupport/ContextMenuClientAndroid.h b/WebKit/android/WebCoreSupport/ContextMenuClientAndroid.h deleted file mode 100644 index 4563829..0000000 --- a/WebKit/android/WebCoreSupport/ContextMenuClientAndroid.h +++ /dev/null @@ -1,51 +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 ContextMenuClientAndroid_h -#define ContextMenuClientAndroid_h - -#include "ContextMenuClient.h" - -namespace WebCore { - -class ContextMenuClientAndroid : public ContextMenuClient { -public: - virtual void contextMenuDestroyed(); - - virtual PlatformMenuDescription getCustomMenuFromDefaultItems(ContextMenu*); - virtual void contextMenuItemSelected(ContextMenuItem*, const ContextMenu*); - - virtual void downloadURL(const KURL& url); - virtual void copyImageToClipboard(const HitTestResult&); - virtual void searchWithGoogle(const Frame*); - virtual void lookUpInDictionary(Frame*); - virtual void speak(const String&); - virtual void stopSpeaking(); - virtual bool isSpeaking(); -}; - -} // namespace WebCore - -#endif // ContextMenuClientAndroid_h diff --git a/WebKit/android/WebCoreSupport/CookieClient.h b/WebKit/android/WebCoreSupport/CookieClient.h deleted file mode 100644 index 56d9382..0000000 --- a/WebKit/android/WebCoreSupport/CookieClient.h +++ /dev/null @@ -1,46 +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 COOKIE_CLIENT_H -#define COOKIE_CLIENT_H - -#include -#include - -using namespace WebCore; - -namespace android { - -class CookieClient { - -public: - virtual ~CookieClient() {} - virtual void setCookies(const KURL& url, const String& value) = 0; - virtual String cookies(const KURL& url) = 0; - virtual bool cookiesEnabled() = 0; -}; - -} -#endif diff --git a/WebKit/android/WebCoreSupport/DeviceMotionClientAndroid.cpp b/WebKit/android/WebCoreSupport/DeviceMotionClientAndroid.cpp deleted file mode 100644 index f8de733..0000000 --- a/WebKit/android/WebCoreSupport/DeviceMotionClientAndroid.cpp +++ /dev/null @@ -1,84 +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 "DeviceMotionClientAndroid.h" - -#include "WebViewCore.h" - -using namespace WebCore; - -namespace android { - -DeviceMotionClientAndroid::DeviceMotionClientAndroid() - : m_client(0) -{ -} - -void DeviceMotionClientAndroid::setWebViewCore(WebViewCore* webViewCore) -{ - m_webViewCore = webViewCore; - ASSERT(m_webViewCore); -} - -void DeviceMotionClientAndroid::setController(DeviceMotionController* controller) -{ - // This will be called by the Page constructor before the WebViewCore - // has been configured regarding the mock. We cache the controller for - // later use. - m_controller = controller; - ASSERT(m_controller); -} - -void DeviceMotionClientAndroid::startUpdating() -{ - client()->startUpdating(); -} - -void DeviceMotionClientAndroid::stopUpdating() -{ - client()->stopUpdating(); -} - -DeviceMotionData* DeviceMotionClientAndroid::currentDeviceMotion() const -{ - return client()->currentDeviceMotion(); -} - -void DeviceMotionClientAndroid::deviceMotionControllerDestroyed() -{ - delete this; -} - -DeviceMotionClient* DeviceMotionClientAndroid::client() const -{ - if (!m_client) { - m_client = m_webViewCore->deviceMotionAndOrientationManager()->motionClient(); - m_client->setController(m_controller); - } - return m_client; -} - -} // namespace android diff --git a/WebKit/android/WebCoreSupport/DeviceMotionClientAndroid.h b/WebKit/android/WebCoreSupport/DeviceMotionClientAndroid.h deleted file mode 100644 index 98d4709..0000000 --- a/WebKit/android/WebCoreSupport/DeviceMotionClientAndroid.h +++ /dev/null @@ -1,65 +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 DeviceMotionClientAndroid_h -#define DeviceMotionClientAndroid_h - -#include - -namespace WebCore { -class DeviceMotionController; -} - -namespace android { - -class WebViewCore; - -// The Android implementation of DeviceMotionClient. Acts as a proxy to -// the real or mock impl, which is owned by the WebViewCore. -class DeviceMotionClientAndroid : public WebCore::DeviceMotionClient { -public: - DeviceMotionClientAndroid(); - - void setWebViewCore(WebViewCore*); - - // DeviceMotionClient methods - virtual void setController(WebCore::DeviceMotionController*); - virtual void startUpdating(); - virtual void stopUpdating(); - virtual WebCore::DeviceMotionData* currentDeviceMotion() const; - virtual void deviceMotionControllerDestroyed(); - -private: - WebCore::DeviceMotionClient* client() const; - - WebViewCore* m_webViewCore; - WebCore::DeviceMotionController* m_controller; - // Lazily obtained cache of the client owned by the WebViewCore. - mutable WebCore::DeviceMotionClient* m_client; -}; - -} // namespace android - -#endif // DeviceMotionClientAndroid_h diff --git a/WebKit/android/WebCoreSupport/DeviceOrientationClientAndroid.cpp b/WebKit/android/WebCoreSupport/DeviceOrientationClientAndroid.cpp deleted file mode 100644 index 9d7145c..0000000 --- a/WebKit/android/WebCoreSupport/DeviceOrientationClientAndroid.cpp +++ /dev/null @@ -1,84 +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 "DeviceOrientationClientAndroid.h" - -#include "WebViewCore.h" - -using namespace WebCore; - -namespace android { - -DeviceOrientationClientAndroid::DeviceOrientationClientAndroid() - : m_client(0) -{ -} - -void DeviceOrientationClientAndroid::setWebViewCore(WebViewCore* webViewCore) -{ - m_webViewCore = webViewCore; - ASSERT(m_webViewCore); -} - -void DeviceOrientationClientAndroid::setController(DeviceOrientationController* controller) -{ - // This will be called by the Page constructor before the WebViewCore - // has been configured regarding the mock. We cache the controller for - // later use. - m_controller = controller; - ASSERT(m_controller); -} - -void DeviceOrientationClientAndroid::startUpdating() -{ - client()->startUpdating(); -} - -void DeviceOrientationClientAndroid::stopUpdating() -{ - client()->stopUpdating(); -} - -DeviceOrientation* DeviceOrientationClientAndroid::lastOrientation() const -{ - return client()->lastOrientation(); -} - -void DeviceOrientationClientAndroid::deviceOrientationControllerDestroyed() -{ - delete this; -} - -DeviceOrientationClient* DeviceOrientationClientAndroid::client() const -{ - if (!m_client) { - m_client = m_webViewCore->deviceMotionAndOrientationManager()->orientationClient(); - m_client->setController(m_controller); - } - return m_client; -} - -} // namespace android diff --git a/WebKit/android/WebCoreSupport/DeviceOrientationClientAndroid.h b/WebKit/android/WebCoreSupport/DeviceOrientationClientAndroid.h deleted file mode 100644 index 7842b95..0000000 --- a/WebKit/android/WebCoreSupport/DeviceOrientationClientAndroid.h +++ /dev/null @@ -1,65 +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 DeviceOrientationClientAndroid_h -#define DeviceOrientationClientAndroid_h - -#include - -namespace WebCore { -class DeviceOrientationController; -} - -namespace android { - -class WebViewCore; - -// The Android implementation of DeviceOrientationClient. Acts as a proxy to -// the real or mock impl, which is owned by the WebViewCore. -class DeviceOrientationClientAndroid : public WebCore::DeviceOrientationClient { -public: - DeviceOrientationClientAndroid(); - - void setWebViewCore(WebViewCore*); - - // DeviceOrientationClient methods - virtual void setController(WebCore::DeviceOrientationController*); - virtual void startUpdating(); - virtual void stopUpdating(); - virtual WebCore::DeviceOrientation* lastOrientation() const; - virtual void deviceOrientationControllerDestroyed(); - -private: - WebCore::DeviceOrientationClient* client() const; - - WebViewCore* m_webViewCore; - WebCore::DeviceOrientationController* m_controller; - // Lazily obtained cache of the client owned by the WebViewCore. - mutable WebCore::DeviceOrientationClient* m_client; -}; - -} // namespace android - -#endif // DeviceOrientationClientAndroid_h diff --git a/WebKit/android/WebCoreSupport/DragClientAndroid.cpp b/WebKit/android/WebCoreSupport/DragClientAndroid.cpp deleted file mode 100644 index f64b80c..0000000 --- a/WebKit/android/WebCoreSupport/DragClientAndroid.cpp +++ /dev/null @@ -1,46 +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. - */ - -#define LOG_TAG "WebCore" - -#include "config.h" -#include "DragClientAndroid.h" -#include "NotImplemented.h" - -namespace android { - -void DragClientAndroid::dragControllerDestroyed() { notImplemented(); delete this; } - -void DragClientAndroid::willPerformDragDestinationAction(DragDestinationAction, DragData*) { notImplemented(); } - -DragDestinationAction DragClientAndroid::actionMaskForDrag(DragData*) { notImplemented(); return DragDestinationActionNone; } - -DragSourceAction DragClientAndroid::dragSourceActionMaskForPoint(const IntPoint&) { notImplemented(); return DragSourceActionNone; } - -void* DragClientAndroid::createDragImageForLink(KURL&, String const&, Frame*) { return NULL; } -void DragClientAndroid::willPerformDragSourceAction(DragSourceAction, IntPoint const&, Clipboard*) {} -void DragClientAndroid::startDrag(void*, IntPoint const&, IntPoint const&, Clipboard*, Frame*, bool) {} - -} diff --git a/WebKit/android/WebCoreSupport/DragClientAndroid.h b/WebKit/android/WebCoreSupport/DragClientAndroid.h deleted file mode 100644 index 020e1f1..0000000 --- a/WebKit/android/WebCoreSupport/DragClientAndroid.h +++ /dev/null @@ -1,51 +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 DragClientAndroid_h -#define DragClientAndroid_h - -#include "DragClient.h" - -using namespace WebCore; - -namespace android { - - class DragClientAndroid : public DragClient { - public: - virtual void willPerformDragDestinationAction(DragDestinationAction, DragData*); - virtual void willPerformDragSourceAction(DragSourceAction, const IntPoint&, Clipboard*); - virtual DragDestinationAction actionMaskForDrag(DragData*); - //We work in window rather than view coordinates here - virtual DragSourceAction dragSourceActionMaskForPoint(const IntPoint&); - - virtual void startDrag(DragImageRef dragImage, const IntPoint& dragImageOrigin, const IntPoint& eventPos, Clipboard*, Frame*, bool linkDrag = false); - virtual DragImageRef createDragImageForLink(KURL&, const String& label, Frame*); - - virtual void dragControllerDestroyed(); - }; - -} - -#endif diff --git a/WebKit/android/WebCoreSupport/EditorClientAndroid.cpp b/WebKit/android/WebCoreSupport/EditorClientAndroid.cpp deleted file mode 100644 index 250fdbf..0000000 --- a/WebKit/android/WebCoreSupport/EditorClientAndroid.cpp +++ /dev/null @@ -1,280 +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. - */ - -#define LOG_TAG "WebCore" - -#include "config.h" -#include "Editor.h" -#include "EditorClientAndroid.h" -#include "Event.h" -#include "EventNames.h" -#include "FocusController.h" -#include "Frame.h" -#include "HTMLNames.h" -#include "KeyboardEvent.h" -#include "NotImplemented.h" -#include "PlatformKeyboardEvent.h" -#include "PlatformString.h" -#include "WebViewCore.h" -#include "WindowsKeyboardCodes.h" - -using namespace WebCore::HTMLNames; - -namespace android { - -void EditorClientAndroid::pageDestroyed() { - delete this; -} - -bool EditorClientAndroid::shouldDeleteRange(Range*) { return true; } -bool EditorClientAndroid::shouldShowDeleteInterface(HTMLElement*) { notImplemented(); return false; } -bool EditorClientAndroid::smartInsertDeleteEnabled() { notImplemented(); return false; } -bool EditorClientAndroid::isSelectTrailingWhitespaceEnabled(){ notImplemented(); return false; } -bool EditorClientAndroid::isContinuousSpellCheckingEnabled() { notImplemented(); return false; } -void EditorClientAndroid::toggleContinuousSpellChecking() { notImplemented(); } -bool EditorClientAndroid::isGrammarCheckingEnabled() { notImplemented(); return false; } -void EditorClientAndroid::toggleGrammarChecking() { notImplemented(); } -int EditorClientAndroid::spellCheckerDocumentTag() { notImplemented(); return -1; } - -bool EditorClientAndroid::isEditable() { /* notImplemented(); */ return false; } - -// Following Qt's implementation. For shouldBeginEditing and shouldEndEditing. -// Returning true for these fixes issue http://b/issue?id=735185 -bool EditorClientAndroid::shouldBeginEditing(Range*) -{ - return true; -} - -bool EditorClientAndroid::shouldEndEditing(Range*) -{ - return true; -} - -bool EditorClientAndroid::shouldInsertNode(Node*, Range*, EditorInsertAction) { notImplemented(); return true; } -bool EditorClientAndroid::shouldInsertText(const String&, Range*, EditorInsertAction) { return true; } -bool EditorClientAndroid::shouldApplyStyle(CSSStyleDeclaration*, Range*) { notImplemented(); return true; } - -void EditorClientAndroid::didBeginEditing() { notImplemented(); } - -// This function is called so that the platform can handle changes to content. It is called -// after the contents have been edited or unedited (ie undo) -void EditorClientAndroid::respondToChangedContents() { notImplemented(); } - -void EditorClientAndroid::didEndEditing() { notImplemented(); } -void EditorClientAndroid::didWriteSelectionToPasteboard() { notImplemented(); } -void EditorClientAndroid::didSetSelectionTypesForPasteboard() { notImplemented(); } - -// Copied from the Window's port of WebKit. -static const unsigned AltKey = 1 << 0; -static const unsigned ShiftKey = 1 << 1; - -struct KeyDownEntry { - unsigned virtualKey; - unsigned modifiers; - const char* name; -}; - -struct KeyPressEntry { - unsigned charCode; - unsigned modifiers; - const char* name; -}; - -static const KeyDownEntry keyDownEntries[] = { - { VK_LEFT, 0, "MoveLeft" }, - { VK_LEFT, ShiftKey, "MoveLeftAndModifySelection" }, - { VK_LEFT, AltKey, "MoveWordLeft" }, - { VK_LEFT, AltKey | ShiftKey, "MoveWordLeftAndModifySelection" }, - { VK_RIGHT, 0, "MoveRight" }, - { VK_RIGHT, ShiftKey, "MoveRightAndModifySelection" }, - { VK_RIGHT, AltKey, "MoveWordRight" }, - { VK_RIGHT, AltKey | ShiftKey, "MoveWordRightAndModifySelection" }, - { VK_UP, 0, "MoveUp" }, - { VK_UP, ShiftKey, "MoveUpAndModifySelection" }, - { VK_DOWN, 0, "MoveDown" }, - { VK_DOWN, ShiftKey, "MoveDownAndModifySelection" }, - - { VK_BACK, 0, "BackwardDelete" }, - { VK_BACK, ShiftKey, "ForwardDelete" }, - { VK_BACK, AltKey, "DeleteWordBackward" }, - { VK_BACK, AltKey | ShiftKey, "DeleteWordForward" }, - - { VK_ESCAPE, 0, "Cancel" }, - { VK_TAB, 0, "InsertTab" }, - { VK_TAB, ShiftKey, "InsertBacktab" }, - { VK_RETURN, 0, "InsertNewline" }, - { VK_RETURN, AltKey, "InsertNewline" }, - { VK_RETURN, AltKey | ShiftKey, "InsertNewline" } -}; - -static const KeyPressEntry keyPressEntries[] = { - { '\t', 0, "InsertTab" }, - { '\t', ShiftKey, "InsertBackTab" }, - { '\r', 0, "InsertNewline" }, - { '\r', AltKey, "InsertNewline" }, - { '\r', AltKey | ShiftKey, "InsertNewline" } -}; - -static const char* interpretKeyEvent(const KeyboardEvent* evt) -{ - const PlatformKeyboardEvent* keyEvent = evt->keyEvent(); - - static HashMap* keyDownCommandsMap = 0; - static HashMap* keyPressCommandsMap = 0; - - if (!keyDownCommandsMap) { - keyDownCommandsMap = new HashMap; - keyPressCommandsMap = new HashMap; - - for (unsigned i = 0; i < sizeof(keyDownEntries)/sizeof(KeyDownEntry); i++) - keyDownCommandsMap->set(keyDownEntries[i].modifiers << 16 | keyDownEntries[i].virtualKey, keyDownEntries[i].name); - - for (unsigned i = 0; i < sizeof(keyPressEntries)/sizeof(KeyPressEntry); i++) - keyPressCommandsMap->set(keyPressEntries[i].modifiers << 16 | keyPressEntries[i].charCode, keyPressEntries[i].name); - } - - unsigned modifiers = 0; - if (keyEvent->shiftKey()) - modifiers |= ShiftKey; - if (keyEvent->altKey()) - modifiers |= AltKey; - - if (evt->type() == eventNames().keydownEvent) { - int mapKey = modifiers << 16 | evt->keyCode(); - return mapKey ? keyDownCommandsMap->get(mapKey) : 0; - } - - int mapKey = modifiers << 16 | evt->charCode(); - return mapKey ? keyPressCommandsMap->get(mapKey) : 0; -} - -void EditorClientAndroid::handleKeyboardEvent(KeyboardEvent* event) { - ASSERT(m_page); - Frame* frame = m_page->focusController()->focusedOrMainFrame(); - if (!frame) - return; - - const PlatformKeyboardEvent* keyEvent = event->keyEvent(); - // TODO: If the event is not coming from Android Java, e.g. from JavaScript, - // PlatformKeyboardEvent is null. We should support this later. - if (!keyEvent) - return; - - Editor::Command command = frame->editor()->command(interpretKeyEvent(event)); - if (keyEvent->type() == PlatformKeyboardEvent::RawKeyDown) { - if (!command.isTextInsertion() && command.execute(event)) { - // This function mimics the Windows version. However, calling event->setDefaultHandled() - // prevents the javascript key events for the delete key from happening. - // Update: Safari doesn't send delete key events to javascript so - // we will mimic that behavior. - event->setDefaultHandled(); - } - return; - } - - if (command.execute(event)) { - event->setDefaultHandled(); - return; - } - - // Don't insert null or control characters as they can result in unexpected behaviour - if (event->charCode() < ' ') - return; - - if (frame->editor()->insertText(keyEvent->text(), event)) - event->setDefaultHandled(); -} - -//////////////////////////////////////////////////////////////////////////////////////////////// -// we just don't support Undo/Redo at the moment - -void EditorClientAndroid::registerCommandForUndo(PassRefPtr) {} -void EditorClientAndroid::registerCommandForRedo(PassRefPtr) {} -void EditorClientAndroid::clearUndoRedoOperations() {} -bool EditorClientAndroid::canUndo() const { return false; } -bool EditorClientAndroid::canRedo() const { return false; } -void EditorClientAndroid::undo() {} -void EditorClientAndroid::redo() {} - -// functions new to Jun-07 tip of tree merge: -void EditorClientAndroid::showSpellingUI(bool) {} -void EditorClientAndroid::getGuessesForWord(String const&, const String&, WTF::Vector&) {} -bool EditorClientAndroid::spellingUIIsShowing() { return false; } -void EditorClientAndroid::checkGrammarOfString(unsigned short const*, int, WTF::Vector&, int*, int*) {} -void EditorClientAndroid::checkSpellingOfString(unsigned short const*, int, int*, int*) {} -String EditorClientAndroid::getAutoCorrectSuggestionForMisspelledWord(const String&) { return String(); } -void EditorClientAndroid::textFieldDidEndEditing(Element*) {} -void EditorClientAndroid::textDidChangeInTextArea(Element*) {} -void EditorClientAndroid::textDidChangeInTextField(Element*) {} -void EditorClientAndroid::textFieldDidBeginEditing(Element*) {} -void EditorClientAndroid::ignoreWordInSpellDocument(String const&) {} - -// We need to pass the selection up to the WebTextView -void EditorClientAndroid::respondToChangedSelection() { - if (m_uiGeneratedSelectionChange) - return; - Frame* frame = m_page->focusController()->focusedOrMainFrame(); - if (!frame || !frame->view()) - return; - WebViewCore* webViewCore = WebViewCore::getWebViewCore(frame->view()); - webViewCore->updateTextSelection(); -} - -bool EditorClientAndroid::shouldChangeSelectedRange(Range*, Range*, EAffinity, - bool) { - return m_shouldChangeSelectedRange; -} - -bool EditorClientAndroid::doTextFieldCommandFromEvent(Element*, KeyboardEvent*) { return false; } -void EditorClientAndroid::textWillBeDeletedInTextField(Element*) {} -void EditorClientAndroid::updateSpellingUIWithGrammarString(String const&, GrammarDetail const&) {} -void EditorClientAndroid::updateSpellingUIWithMisspelledWord(String const&) {} -void EditorClientAndroid::learnWord(String const&) {} - -// functions new to the Nov-16-08 tip of tree merge: -bool EditorClientAndroid::shouldMoveRangeAfterDelete(Range*, Range*) { return true; } -void EditorClientAndroid::setInputMethodState(bool) {} - -// functions new to Feb-19 tip of tree merge: -void EditorClientAndroid::handleInputMethodKeydown(KeyboardEvent*) {} - -void EditorClientAndroid::willSetInputMethodState() -{ - notImplemented(); -} - -void EditorClientAndroid::requestCheckingOfString(SpellChecker*, int, const String&) {} - -#if ENABLE(WEB_AUTOFILL) -WebAutoFill* EditorClientAndroid::getAutoFill() -{ - if (!m_autoFill) - m_autoFill.set(new WebAutoFill()); - - return m_autoFill.get(); -} -#endif - -} diff --git a/WebKit/android/WebCoreSupport/EditorClientAndroid.h b/WebKit/android/WebCoreSupport/EditorClientAndroid.h deleted file mode 100644 index 94a6518..0000000 --- a/WebKit/android/WebCoreSupport/EditorClientAndroid.h +++ /dev/null @@ -1,135 +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 EditorClientAndroid_h -#define EditorClientAndroid_h - -#include "config.h" - - -#include "EditorClient.h" -#include "Page.h" -#include "autofill/WebAutoFill.h" - -#include - -using namespace WebCore; - -namespace android { - -class EditorClientAndroid : public EditorClient { -public: - EditorClientAndroid() { - m_shouldChangeSelectedRange = true; - m_uiGeneratedSelectionChange = false; - } - virtual void pageDestroyed(); - - virtual bool shouldDeleteRange(Range*); - virtual bool shouldShowDeleteInterface(HTMLElement*); - virtual bool smartInsertDeleteEnabled(); - virtual bool isSelectTrailingWhitespaceEnabled(); - virtual bool isContinuousSpellCheckingEnabled(); - virtual void toggleContinuousSpellChecking(); - virtual bool isGrammarCheckingEnabled(); - virtual void toggleGrammarChecking(); - virtual int spellCheckerDocumentTag(); - - virtual bool isEditable(); - - virtual bool shouldBeginEditing(Range*); - virtual bool shouldEndEditing(Range*); - virtual bool shouldInsertNode(Node*, Range*, EditorInsertAction); - virtual bool shouldInsertText(const String&, Range*, EditorInsertAction); - virtual bool shouldChangeSelectedRange(Range* fromRange, Range* toRange, EAffinity, bool stillSelecting); - - virtual bool shouldApplyStyle(CSSStyleDeclaration*, Range*); -// virtual bool shouldChangeTypingStyle(CSSStyleDeclaration* fromStyle, CSSStyleDeclaration* toStyle); -// virtual bool doCommandBySelector(SEL selector); - virtual bool shouldMoveRangeAfterDelete(Range*, Range*); - - virtual void didBeginEditing(); - virtual void respondToChangedContents(); - virtual void respondToChangedSelection(); - virtual void didEndEditing(); - virtual void didWriteSelectionToPasteboard(); - virtual void didSetSelectionTypesForPasteboard(); -// virtual void didChangeTypingStyle:(NSNotification *)notification; -// virtual void didChangeSelection:(NSNotification *)notification; -// virtual NSUndoManager* undoManager:(WebView *)webView; - - virtual void registerCommandForUndo(PassRefPtr); - virtual void registerCommandForRedo(PassRefPtr); - virtual void clearUndoRedoOperations(); - - virtual bool canUndo() const; - virtual bool canRedo() const; - - virtual void undo(); - virtual void redo(); - - virtual void handleKeyboardEvent(KeyboardEvent*); - virtual void handleInputMethodKeydown(KeyboardEvent*); - - virtual void textFieldDidBeginEditing(Element*); - virtual void textFieldDidEndEditing(Element*); - virtual void textDidChangeInTextField(Element*); - virtual bool doTextFieldCommandFromEvent(Element*, KeyboardEvent*); - virtual void textWillBeDeletedInTextField(Element*); - virtual void textDidChangeInTextArea(Element*); - - virtual void ignoreWordInSpellDocument(const String&); - virtual void learnWord(const String&); - virtual void checkSpellingOfString(const UChar*, int length, int* misspellingLocation, int* misspellingLength); - virtual String getAutoCorrectSuggestionForMisspelledWord(const String& misspelledWorld); - virtual void checkGrammarOfString(const UChar*, int length, WTF::Vector&, int* badGrammarLocation, int* badGrammarLength); - virtual void updateSpellingUIWithGrammarString(const String&, const GrammarDetail& detail); - virtual void updateSpellingUIWithMisspelledWord(const String&); - virtual void showSpellingUI(bool show); - virtual bool spellingUIIsShowing(); - virtual void getGuessesForWord(const String&, const String& context, WTF::Vector& guesses); - virtual void willSetInputMethodState(); - virtual void setInputMethodState(bool); - virtual void requestCheckingOfString(SpellChecker*, int, const String&); - - // Android specific: - void setPage(Page* page) { m_page = page; } - void setShouldChangeSelectedRange(bool shouldChangeSelectedRange) { m_shouldChangeSelectedRange = shouldChangeSelectedRange; } - void setUiGeneratedSelectionChange(bool uiGenerated) { m_uiGeneratedSelectionChange = uiGenerated; } -#if ENABLE(WEB_AUTOFILL) - WebAutoFill* getAutoFill(); -#endif -private: - Page* m_page; - bool m_shouldChangeSelectedRange; - bool m_uiGeneratedSelectionChange; -#if ENABLE(WEB_AUTOFILL) - OwnPtr m_autoFill; -#endif -}; - -} - -#endif diff --git a/WebKit/android/WebCoreSupport/FileSystemClient.h b/WebKit/android/WebCoreSupport/FileSystemClient.h deleted file mode 100644 index 5bde18a..0000000 --- a/WebKit/android/WebCoreSupport/FileSystemClient.h +++ /dev/null @@ -1,41 +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 FILESYSTEM_CLIENT_H -#define FILESYSTEM_CLIENT_H - -#include "PlatformString.h" - -using namespace WebCore; - -namespace android { - -class FileSystemClient { -public: - virtual ~FileSystemClient() { } - virtual String resolveFilePathForContentUri(const String&) = 0; -}; -} -#endif diff --git a/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp b/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp deleted file mode 100644 index 946a4a7..0000000 --- a/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp +++ /dev/null @@ -1,1351 +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. - */ - -#define LOG_TAG "WebCore" - -#include "config.h" -#include "FrameLoaderClientAndroid.h" - -#include "BackForwardList.h" -#include "CachedFrame.h" -#include "CachedFramePlatformDataAndroid.h" -#include "Chrome.h" -#include "ChromeClientAndroid.h" -#include "DOMImplementation.h" -#include "Document.h" -#include "DocumentLoader.h" -#include "EditorClientAndroid.h" -#include "Frame.h" -#include "FrameLoader.h" -#include "FrameNetworkingContextAndroid.h" -#include "FrameTree.h" -#include "FrameView.h" -#include "GraphicsContext.h" -#include "HTMLFrameOwnerElement.h" -#include "HTMLPlugInElement.h" -#include "HistoryItem.h" -#include "IconDatabase.h" -#include "MIMETypeRegistry.h" -#include "NotImplemented.h" -#include "PackageNotifier.h" -#include "Page.h" -#include "PlatformBridge.h" -#include "PlatformGraphicsContext.h" -#include "PlatformString.h" -#include "PluginDatabase.h" -#include "PluginView.h" -#include "PluginViewBase.h" -#include "ProgressTracker.h" -#include "RenderPart.h" -#include "RenderView.h" -#include "RenderWidget.h" -#include "ResourceError.h" -#include "ResourceHandle.h" -#include "ResourceHandleInternal.h" -#include "SelectionController.h" -#include "Settings.h" -#include "SkCanvas.h" -#include "SkRect.h" -#include "TextEncoding.h" -#include "WebCoreFrameBridge.h" -#include "WebCoreResourceLoader.h" -#include "WebHistory.h" -#include "WebIconDatabase.h" -#include "WebFrameView.h" -#include "WebViewClientError.h" -#include "WebViewCore.h" -#include "autofill/WebAutoFill.h" -#include "android_graphics.h" - -#include -#include - -extern android::AssetManager* globalAssetManager(); - -namespace android { - -static const int EXTRA_LAYOUT_DELAY = 1000; - -FrameLoaderClientAndroid::FrameLoaderClientAndroid(WebFrame* webframe) - : m_frame(NULL) - , m_webFrame(webframe) - , m_manualLoader(NULL) - , m_hasSentResponseToPlugin(false) - , m_onDemandPluginsEnabled(false) { - Retain(m_webFrame); -} - -FrameLoaderClientAndroid* FrameLoaderClientAndroid::get(const WebCore::Frame* frame) -{ - return static_cast (frame->loader()->client()); -} - -void FrameLoaderClientAndroid::frameLoaderDestroyed() { - registerForIconNotification(false); - m_frame = 0; - Release(m_webFrame); - delete this; -} - -bool FrameLoaderClientAndroid::hasWebView() const { - // FIXME, - // there is one web view per page, or top frame. - // as android's view is created from Java side, it is always there. - return true; -} - -void FrameLoaderClientAndroid::makeRepresentation(DocumentLoader*) { - m_onDemandPluginsEnabled = false; - // don't use representation - verifiedOk(); -} - -void FrameLoaderClientAndroid::forceLayout() { - ASSERT(m_frame); - m_frame->view()->forceLayout(); - // FIXME, should we adjust view size here? - m_frame->view()->adjustViewSize(); -} - -void FrameLoaderClientAndroid::forceLayoutForNonHTML() { - notImplemented(); -} - -void FrameLoaderClientAndroid::setCopiesOnScroll() { - // this is a hint about whether we need to force redraws, or can - // just copy the scrolled content. Since we always force a redraw - // anyways, we can ignore this call. - verifiedOk(); -} - -void FrameLoaderClientAndroid::detachedFromParent2() { - // FIXME, ready to detach frame from view -} - -void FrameLoaderClientAndroid::detachedFromParent3() { - // FIXME, ready to release view - notImplemented(); -} - -// This function is responsible for associating the "id" with a given -// subresource load. The following functions that accept an "id" are -// called for each subresource, so they should not be dispatched to the m_frame. -void FrameLoaderClientAndroid::assignIdentifierToInitialRequest(unsigned long id, - DocumentLoader*, const ResourceRequest&) { - lowPriority_notImplemented(); -} - -void FrameLoaderClientAndroid::dispatchWillSendRequest(DocumentLoader*, unsigned long id, - ResourceRequest&, const ResourceResponse&) { - lowPriority_notImplemented(); -} - -bool FrameLoaderClientAndroid::shouldUseCredentialStorage(DocumentLoader*, unsigned long identifier) -{ - notImplemented(); - return false; -} - -void FrameLoaderClientAndroid::dispatchDidReceiveAuthenticationChallenge(DocumentLoader*, - unsigned long id, const AuthenticationChallenge&) { - lowPriority_notImplemented(); -} - -void FrameLoaderClientAndroid::dispatchDidCancelAuthenticationChallenge(DocumentLoader*, - unsigned long id, const AuthenticationChallenge&) { - lowPriority_notImplemented(); -} - -void FrameLoaderClientAndroid::dispatchDidReceiveResponse(DocumentLoader*, - unsigned long id, const ResourceResponse&) { - lowPriority_notImplemented(); -} - -void FrameLoaderClientAndroid::dispatchDidReceiveContentLength(DocumentLoader*, - unsigned long id, int lengthReceived) { - lowPriority_notImplemented(); -} - -void FrameLoaderClientAndroid::dispatchDidFinishLoading(DocumentLoader*, - unsigned long id) { - lowPriority_notImplemented(); -} - -void FrameLoaderClientAndroid::dispatchDidFailLoading(DocumentLoader* docLoader, - unsigned long id, const ResourceError&) { - lowPriority_notImplemented(); -} - -bool FrameLoaderClientAndroid::dispatchDidLoadResourceFromMemoryCache(DocumentLoader*, - const ResourceRequest&, const ResourceResponse&, int length) { - notImplemented(); - return false; -} - -void FrameLoaderClientAndroid::dispatchDidHandleOnloadEvents() { -} - -void FrameLoaderClientAndroid::dispatchDidReceiveServerRedirectForProvisionalLoad() { - ASSERT(m_frame); - // Tell the load it was a redirect. - m_webFrame->loadStarted(m_frame); -} - -void FrameLoaderClientAndroid::dispatchDidCancelClientRedirect() { - notImplemented(); -} - -void FrameLoaderClientAndroid::dispatchWillPerformClientRedirect(const KURL&, - double interval, double fireDate) { - notImplemented(); -} - -void FrameLoaderClientAndroid::dispatchDidChangeLocationWithinPage() { - notImplemented(); -} - -void FrameLoaderClientAndroid::dispatchDidPushStateWithinPage() -{ - notImplemented(); -} - -void FrameLoaderClientAndroid::dispatchDidReplaceStateWithinPage() -{ - notImplemented(); -} - -void FrameLoaderClientAndroid::dispatchDidPopStateWithinPage() -{ - notImplemented(); -} - -void FrameLoaderClientAndroid::dispatchWillClose() { - notImplemented(); -} - -void FrameLoaderClientAndroid::dispatchDidReceiveIcon() { - ASSERT(m_frame); - if (m_frame->tree() && m_frame->tree()->parent()) - return; - WTF::String url(m_frame->loader()->url().string()); - // Try to obtain the icon image. - WebCore::Image* icon = WebCore::iconDatabase()->iconForPageURL( - url, WebCore::IntSize(16, 16)); - // If the request fails, try the original request url. - if (!icon) { - DocumentLoader* docLoader = m_frame->loader()->activeDocumentLoader(); - KURL originalURL = docLoader->originalRequest().url(); - icon = WebCore::iconDatabase()->iconForPageURL( - originalURL, WebCore::IntSize(16, 16)); - } - // 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, - url.utf8().data()); - m_webFrame->didReceiveIcon(icon); - } else { - LOGV("Icon data for %s unavailable, registering for notification...", - url.utf8().data()); - registerForIconNotification(); - } -} - -void FrameLoaderClientAndroid::dispatchDidReceiveTouchIconURL(const String& url, bool precomposed) { - ASSERT(m_frame); - // Do not report sub frame touch icons - if (m_frame->tree() && m_frame->tree()->parent()) - return; - m_webFrame->didReceiveTouchIconURL(url, precomposed); -} - -void FrameLoaderClientAndroid::dispatchDidStartProvisionalLoad() { - notImplemented(); -} - -void FrameLoaderClientAndroid::dispatchDidReceiveTitle(const String& title) { - ASSERT(m_frame); - // Used to check for FrameLoadTypeStandard but we only want to send the title for - // the top frame and not sub-frames. - if (!m_frame->tree() || !m_frame->tree()->parent()) { - m_webFrame->setTitle(title); - } -} - -void FrameLoaderClientAndroid::dispatchDidCommitLoad() { -#if ENABLE(WEB_AUTOFILL) - if (m_frame == m_frame->page()->mainFrame()) { - EditorClientAndroid* editorC = static_cast(m_frame->page()->editorClient()); - WebAutoFill* autoFill = editorC->getAutoFill(); - autoFill->reset(); - } -#endif - verifiedOk(); -} - -static void loadDataIntoFrame(Frame* frame, KURL baseUrl, const String& url, - const String& data) { - if (baseUrl.isEmpty()) { - baseUrl = blankURL(); - } - ResourceRequest request(baseUrl); - CString cstr = data.utf8(); - RefPtr buf = WebCore::SharedBuffer::create(cstr.data(), cstr.length()); - SubstituteData subData(buf, String("text/html"), String("utf-8"), - KURL(KURL(), url)); - frame->loader()->load(request, subData, false); -} - -void FrameLoaderClientAndroid::dispatchDidFailProvisionalLoad(const ResourceError& error) { - ASSERT(m_frame); - // Ignore ErrorInterrupted since it is due to a policy interruption. This - // is caused by a decision to download the main resource rather than - // display it. - if (error.errorCode() == InternalErrorInterrupted - || error.errorCode() == InternalErrorCancelled) { - // If we decided to download the main resource or if the user cancelled - // it, make sure we report that the load is done. - didFinishLoad(); - return; - } - - AssetManager* am = globalAssetManager(); - - // Check to see if the error code was not generated internally - WebCore::PlatformBridge::rawResId id = WebCore::PlatformBridge::NoDomain; - if ((error.errorCode() == ErrorFile || - error.errorCode() == ErrorFileNotFound) && - (!error.localizedDescription().isEmpty())) { - id = WebCore::PlatformBridge::LoadError; - } - String filename = m_webFrame->getRawResourceFilename(id); - if (filename.isEmpty()) - return; - - // Grab the error page from the asset manager - Asset* a = am->openNonAsset( - filename.utf8().data(), Asset::ACCESS_BUFFER); - if (!a) - return; - - // Take the failing url and encode html entities so javascript urls are not - // executed. - CString failingUrl = error.failingURL().utf8(); - WTF::Vector url; - int len = failingUrl.length(); - const char* data = failingUrl.data(); - for (int i = 0; i < len; i++) { - char c = data[i]; - if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') - || (c >= '0' && c <= '9')) - url.append(c); - else { - char buf[16]; - int res = sprintf(buf, "&#%d;", c); - buf[res] = 0; - url.append(buf, res); - } - } - - // Replace all occurances of %s with the failing url. - String s = UTF8Encoding().decode((const char*)a->getBuffer(false), a->getLength()); - s = s.replace("%s", String(url.data(), url.size())); - - // Replace all occurances of %e with the error text - s = s.replace("%e", error.localizedDescription()); - - // Create the request and the substitute data and tell the FrameLoader to - // load with the replacement data. - // use KURL(const char*) as KURL(const String& url) can trigger ASSERT for - // invalidate URL string. - loadDataIntoFrame(m_frame, KURL(ParsedURLString, data), error.failingURL(), s); - - // Delete the asset. - delete a; - - // Report that the load is finished, since it failed. - didFinishLoad(); -} - -void FrameLoaderClientAndroid::dispatchDidFailLoad(const ResourceError&) { - // called when page is completed with error - didFinishLoad(); -} - -void FrameLoaderClientAndroid::dispatchDidFinishDocumentLoad() { - // called when finishedParsing - lowPriority_notImplemented(); -} - -void FrameLoaderClientAndroid::dispatchDidFinishLoad() { - didFinishLoad(); -} - -void FrameLoaderClientAndroid::dispatchDidFirstLayout() { - ASSERT(m_frame); - // set EXTRA_LAYOUT_DELAY if the loader is not completed yet - if (!m_frame->loader()->isComplete()) - m_frame->document()->setExtraLayoutDelay(EXTRA_LAYOUT_DELAY); - // we need to do this here instead of dispatchDidFirstVisuallyNonEmptyLayout - // so that about:blank will update the screen. - if (!m_frame->tree()->parent()) { - // Only need to notify Java side for the top frame - WebViewCore::getWebViewCore(m_frame->view())->didFirstLayout(); - } -} - -void FrameLoaderClientAndroid::dispatchDidFirstVisuallyNonEmptyLayout() -{ - notImplemented(); -} - -Frame* FrameLoaderClientAndroid::dispatchCreatePage(const NavigationAction&) { - ASSERT(m_frame); -#ifdef ANDROID_MULTIPLE_WINDOWS - if (m_frame->settings() && m_frame->settings()->supportMultipleWindows()) - // Always a user gesture since window.open maps to - // ChromeClientAndroid::createWindow - return m_webFrame->createWindow(false, true); - else -#endif - // If the client doesn't support multiple windows, just replace the - // current frame's contents. - return m_frame; -} - -void FrameLoaderClientAndroid::dispatchShow() { - ASSERT(m_frame); - m_frame->view()->invalidate(); -} - - -static bool TreatAsAttachment(const String& content_disposition) { - // Some broken sites just send - // Content-Disposition: ; filename="file" - // screen those out here. - if (content_disposition.startsWith(";")) - return false; - - if (content_disposition.startsWith("inline", false)) - return false; - - // Some broken sites just send - // Content-Disposition: filename="file" - // without a disposition token... screen those out. - if (content_disposition.startsWith("filename", false)) - return false; - - // Also in use is Content-Disposition: name="file" - if (content_disposition.startsWith("name", false)) - return false; - - // We have a content-disposition of "attachment" or unknown. - // RFC 2183, section 2.8 says that an unknown disposition - // value should be treated as "attachment" - return true; -} - -void FrameLoaderClientAndroid::dispatchDecidePolicyForMIMEType(FramePolicyFunction func, - const String& MIMEType, const ResourceRequest& request) { - ASSERT(m_frame); - ASSERT(func); - if (!func) - return; - - PolicyChecker* policy = m_frame->loader()->policyChecker(); - - if (request.isNull()) { - (policy->*func)(PolicyIgnore); - return; - } - // Default to Use (display internally). - PolicyAction action = PolicyUse; - // Check if we should Download instead. - const ResourceResponse& response = m_frame->loader()->activeDocumentLoader()->response(); - const String& content_disposition = response.httpHeaderField("Content-Disposition"); - if (!content_disposition.isEmpty() && - TreatAsAttachment(content_disposition)) { - // Server wants to override our normal policy. - // Check to see if we are a sub frame (main frame has no owner element) - if (m_frame->ownerElement() != 0) - action = PolicyIgnore; - else - action = PolicyDownload; - (policy->*func)(action); - return; - } - - // Ask if it can be handled internally. - if (!canShowMIMEType(MIMEType)) { - // Check to see if we are a sub frame (main frame has no owner element) - if (m_frame->ownerElement() != 0) - action = PolicyIgnore; - else - action = PolicyDownload; - (policy->*func)(action); - return; - } - // A status code of 204 indicates no content change. Ignore the result. - WebCore::DocumentLoader* docLoader = m_frame->loader()->activeDocumentLoader(); - if (docLoader->response().httpStatusCode() == 204) - action = PolicyIgnore; - (policy->*func)(action); -} - -void FrameLoaderClientAndroid::dispatchDecidePolicyForNewWindowAction(FramePolicyFunction func, - const NavigationAction& action, const ResourceRequest& request, - PassRefPtr formState, const String& frameName) { - ASSERT(m_frame); - ASSERT(func); - if (!func) - return; - - if (request.isNull()) { - (m_frame->loader()->policyChecker()->*func)(PolicyIgnore); - return; - } - - if (action.type() == NavigationTypeFormSubmitted || action.type() == NavigationTypeFormResubmitted) - m_frame->loader()->resetMultipleFormSubmissionProtection(); - - // If we get to this point it means that a link has a target that was not - // found by the frame tree. Instead of creating a new frame, return the - // current frame in dispatchCreatePage. - if (canHandleRequest(request)) - (m_frame->loader()->policyChecker()->*func)(PolicyUse); - else - (m_frame->loader()->policyChecker()->*func)(PolicyIgnore); -} - -void FrameLoaderClientAndroid::cancelPolicyCheck() { - lowPriority_notImplemented(); -} - -void FrameLoaderClientAndroid::dispatchUnableToImplementPolicy(const ResourceError&) { - notImplemented(); -} - -void FrameLoaderClientAndroid::dispatchDecidePolicyForNavigationAction(FramePolicyFunction func, - const NavigationAction& action, const ResourceRequest& request, - PassRefPtr formState) { - ASSERT(m_frame); - ASSERT(func); - if (!func) - return; - if (request.isNull()) { - (m_frame->loader()->policyChecker()->*func)(PolicyIgnore); - return; - } - - // Reset multiple form submission protection. If this is a resubmission, we check with the - // user and reset the protection if they choose to resubmit the form (see WebCoreFrameBridge.cpp) - if (action.type() == NavigationTypeFormSubmitted) - m_frame->loader()->resetMultipleFormSubmissionProtection(); - - if (action.type() == NavigationTypeFormResubmitted) { - m_webFrame->decidePolicyForFormResubmission(func); - return; - } else - (m_frame->loader()->policyChecker()->*func)(PolicyUse); -} - -void FrameLoaderClientAndroid::dispatchWillSubmitForm(FramePolicyFunction func, PassRefPtr) { - ASSERT(m_frame); - ASSERT(func); - (m_frame->loader()->policyChecker()->*func)(PolicyUse); -} - -void FrameLoaderClientAndroid::dispatchWillSendSubmitEvent(HTMLFormElement* form) -{ - if (m_webFrame->shouldSaveFormData()) - m_webFrame->saveFormData(form); -} - -void FrameLoaderClientAndroid::dispatchDidLoadMainResource(DocumentLoader*) { - notImplemented(); -} - -void FrameLoaderClientAndroid::revertToProvisionalState(DocumentLoader*) { - notImplemented(); -} - -void FrameLoaderClientAndroid::setMainDocumentError(DocumentLoader* docLoader, const ResourceError& error) { - ASSERT(m_frame); - if (m_manualLoader) { - m_manualLoader->didFail(error); - m_manualLoader = NULL; - m_hasSentResponseToPlugin = false; - } else { - if (!error.isNull() && error.errorCode() >= InternalErrorLast && error.errorCode() != ERROR_OK) - m_webFrame->reportError(error.errorCode(), - error.localizedDescription(), error.failingURL()); - } -} - -// This function is called right before the progress is updated. -void FrameLoaderClientAndroid::willChangeEstimatedProgress() { - verifiedOk(); -} - -// This function is called after the progress has been updated. The bad part -// about this is that when a page is completed, this function is called after -// the progress has been reset to 0. -void FrameLoaderClientAndroid::didChangeEstimatedProgress() { - verifiedOk(); -} - -// This will give us the initial estimate when the page first starts to load. -void FrameLoaderClientAndroid::postProgressStartedNotification() { - ASSERT(m_frame); - if (m_frame->page()) - m_webFrame->setProgress(m_frame->page()->progress()->estimatedProgress()); -} - -// This will give us any updated progress including the final progress. -void FrameLoaderClientAndroid::postProgressEstimateChangedNotification() { - ASSERT(m_frame); - if (m_frame->page()) - m_webFrame->setProgress(m_frame->page()->progress()->estimatedProgress()); -} - -// This is just a notification that the progress has finished. Don't call -// setProgress(1) because postProgressEstimateChangedNotification will do so. -void FrameLoaderClientAndroid::postProgressFinishedNotification() { - WebViewCore* core = WebViewCore::getWebViewCore(m_frame->view()); - if (!m_frame->tree()->parent()) { - // only need to notify Java for the top frame - core->notifyProgressFinished(); - } - // notify plugins that the frame has loaded - core->notifyPluginsOnFrameLoad(m_frame); -} - -void FrameLoaderClientAndroid::setMainFrameDocumentReady(bool) { - // this is only interesting once we provide an external API for the DOM - notImplemented(); -} - -void FrameLoaderClientAndroid::startDownload(const ResourceRequest&) { - notImplemented(); -} - -void FrameLoaderClientAndroid::willChangeTitle(DocumentLoader*) { - verifiedOk(); -} - -void FrameLoaderClientAndroid::didChangeTitle(DocumentLoader* loader) { - verifiedOk(); -} - -void FrameLoaderClientAndroid::finishedLoading(DocumentLoader* docLoader) { - // Telling the frame we received some data and passing 0 as the data is our - // way to get work done that is normally done when the first bit of data is - // received, even for the case of a document with no data (like about:blank) - if (!m_manualLoader) { - committedLoad(docLoader, 0, 0); - return; - } - - m_manualLoader->didFinishLoading(); - m_manualLoader = NULL; - m_hasSentResponseToPlugin = false; -} - -void FrameLoaderClientAndroid::updateGlobalHistory() { - ASSERT(m_frame); - - DocumentLoader* docLoader = m_frame->loader()->documentLoader(); - ASSERT(docLoader); - - // Code copied from FrameLoader.cpp:createHistoryItem - // Only add this URL to the database if it is a valid page - if (docLoader->unreachableURL().isEmpty() - && docLoader->response().httpStatusCode() < 400) { - m_webFrame->updateVisitedHistory(docLoader->urlForHistory(), false); - if (!docLoader->serverRedirectSourceForHistory().isNull()) - m_webFrame->updateVisitedHistory(KURL(ParsedURLString, docLoader->serverRedirectDestinationForHistory()), false); - } -} - -void FrameLoaderClientAndroid::updateGlobalHistoryRedirectLinks() { - // Note, do we need to do anything where there is no HistoryItem? If we call - // updateGlobalHistory(), we will add bunch of "data:xxx" urls for gmail.com - // which is not what we want. Opt to do nothing now. -} - -bool FrameLoaderClientAndroid::shouldGoToHistoryItem(HistoryItem* item) const { - // hmmm, seems like we might do a more thoughtful check - ASSERT(m_frame); - return item != NULL; -} - -void FrameLoaderClientAndroid::didDisplayInsecureContent() -{ - notImplemented(); -} - -void FrameLoaderClientAndroid::didRunInsecureContent(SecurityOrigin*) -{ - notImplemented(); -} - -void FrameLoaderClientAndroid::committedLoad(DocumentLoader* loader, const char* data, int length) { - if (!m_manualLoader) - loader->commitData(data, length); - - // commit data may have created a manual plugin loader - if (m_manualLoader) { - if (!m_hasSentResponseToPlugin) { - m_manualLoader->didReceiveResponse(loader->response()); - // Failure could cause the main document to have an error causing - // the manual loader to be reset. - if (!m_manualLoader) - return; - m_hasSentResponseToPlugin = true; - } - m_manualLoader->didReceiveData(data, length); - } -} - -ResourceError FrameLoaderClientAndroid::cancelledError(const ResourceRequest& request) { - return ResourceError(String(), InternalErrorCancelled, request.url(), String()); -} - -ResourceError FrameLoaderClientAndroid::cannotShowURLError(const ResourceRequest& request) { - return ResourceError(String(), InternalErrorCannotShowUrl, request.url(), String()); -} - -ResourceError FrameLoaderClientAndroid::interruptForPolicyChangeError(const ResourceRequest& request) { - return ResourceError(String(), InternalErrorInterrupted, request.url(), String()); -} - -ResourceError FrameLoaderClientAndroid::cannotShowMIMETypeError(const ResourceResponse& request) { - return ResourceError(String(), InternalErrorCannotShowMimeType, request.url(), String()); -} - -ResourceError FrameLoaderClientAndroid::fileDoesNotExistError(const ResourceResponse& request) { - return ResourceError(String(), InternalErrorFileDoesNotExist, request.url(), String()); -} - -ResourceError FrameLoaderClientAndroid::pluginWillHandleLoadError(const ResourceResponse& request) { - return ResourceError(String(), InternalErrorPluginWillHandleLoadError, request.url(), String()); -} - -bool FrameLoaderClientAndroid::shouldFallBack(const ResourceError&) { - notImplemented(); - return false; -} - -bool FrameLoaderClientAndroid::canHandleRequest(const ResourceRequest& request) const { - ASSERT(m_frame); - // Don't allow hijacking of intrapage navigation - if (WebCore::equalIgnoringFragmentIdentifier(request.url(), m_frame->loader()->url())) - return true; - - // Don't allow hijacking of iframe urls that are http or https - if (request.url().protocol().startsWith("http", false) && - m_frame->tree() && m_frame->tree()->parent()) - return true; - - return m_webFrame->canHandleRequest(request); -} - -bool FrameLoaderClientAndroid::canShowMIMEType(const String& mimeType) const { - // FIXME: This looks like it has to do with whether or not a type can be - // shown "internally" (i.e. inside the browser) regardless of whether - // or not the browser is doing the rendering, e.g. a full page plugin. - if (MIMETypeRegistry::isSupportedImageResourceMIMEType(mimeType) || - MIMETypeRegistry::isSupportedNonImageMIMEType(mimeType) || - MIMETypeRegistry::isSupportedJavaScriptMIMEType(mimeType) || - (m_frame && m_frame->settings() - && m_frame->settings()->arePluginsEnabled() - && PluginDatabase::installedPlugins()->isMIMETypeRegistered( - mimeType)) || - (DOMImplementation::isTextMIMEType(mimeType) && - !mimeType.startsWith("text/vnd")) || - DOMImplementation::isXMLMIMEType(mimeType)) - return true; - return false; -} - -bool FrameLoaderClientAndroid::canShowMIMETypeAsHTML(const String& mimeType) const { - return false; -} - -bool FrameLoaderClientAndroid::representationExistsForURLScheme(const String&) const { - // don't use representation - verifiedOk(); - return false; -} - -String FrameLoaderClientAndroid::generatedMIMETypeForURLScheme(const String& URLScheme) const { - // FIXME, copy from Apple's port - String mimetype("x-apple-web-kit/"); - mimetype.append(URLScheme.lower()); - return mimetype; -} - -void FrameLoaderClientAndroid::frameLoadCompleted() { - // copied from Apple port, without this back with sub-frame will trigger ASSERT - ASSERT(m_frame); -} - -void FrameLoaderClientAndroid::saveViewStateToItem(HistoryItem* item) { - ASSERT(m_frame); - ASSERT(item); - // store the current scale (only) for the top frame - if (!m_frame->tree()->parent()) { - // We should have added a bridge when the child item was added to its - // parent. - AndroidWebHistoryBridge* bridge = item->bridge(); - ASSERT(bridge); - WebViewCore* webViewCore = WebViewCore::getWebViewCore(m_frame->view()); - bridge->setScale(webViewCore->scale()); - bridge->setTextWrapScale(webViewCore->textWrapScale()); - } - - WebCore::notifyHistoryItemChanged(item); -} - -void FrameLoaderClientAndroid::restoreViewState() { - WebViewCore* webViewCore = WebViewCore::getWebViewCore(m_frame->view()); - HistoryItem* item = m_frame->loader()->history()->currentItem(); - AndroidWebHistoryBridge* bridge = item->bridge(); - // restore the scale (only) for the top frame - if (!m_frame->tree()->parent()) { - webViewCore->restoreScale(bridge->scale(), bridge->textWrapScale()); - } -} - -void FrameLoaderClientAndroid::dispatchDidAddBackForwardItem(HistoryItem* item) const { - ASSERT(m_frame); - m_webFrame->addHistoryItem(item); -} - -void FrameLoaderClientAndroid::dispatchDidRemoveBackForwardItem(HistoryItem* item) const { - ASSERT(m_frame); - m_webFrame->removeHistoryItem(0); -} - -void FrameLoaderClientAndroid::dispatchDidChangeBackForwardIndex() const { - ASSERT(m_frame); - BackForwardList* list = m_frame->page()->backForwardList(); - ASSERT(list); - m_webFrame->updateHistoryIndex(list->backListCount()); -} - -void FrameLoaderClientAndroid::provisionalLoadStarted() { - ASSERT(m_frame); - m_webFrame->loadStarted(m_frame); -} - -void FrameLoaderClientAndroid::didFinishLoad() { - ASSERT(m_frame); - m_frame->document()->setExtraLayoutDelay(0); - m_webFrame->didFinishLoad(m_frame); -} - -void FrameLoaderClientAndroid::prepareForDataSourceReplacement() { - verifiedOk(); -} - -PassRefPtr FrameLoaderClientAndroid::createDocumentLoader( - const ResourceRequest& request, const SubstituteData& data) { - RefPtr loader = DocumentLoader::create(request, data); - return loader.release(); -} - -void FrameLoaderClientAndroid::setTitle(const String& title, const KURL& url) { - // Not needed. dispatchDidReceiveTitle is called immediately after this. - // url is used to update the Apple port history items. - verifiedOk(); -} - -String FrameLoaderClientAndroid::userAgent(const KURL& u) { - return m_webFrame->userAgentForURL(&u); -} - -void FrameLoaderClientAndroid::savePlatformDataToCachedFrame(WebCore::CachedFrame* cachedFrame) { - CachedFramePlatformDataAndroid* platformData = new CachedFramePlatformDataAndroid(m_frame->settings()); - cachedFrame->setCachedFramePlatformData(platformData); -} - -void FrameLoaderClientAndroid::transitionToCommittedFromCachedFrame(WebCore::CachedFrame* cachedFrame) { - CachedFramePlatformDataAndroid* platformData = reinterpret_cast(cachedFrame->cachedFramePlatformData()); -#ifdef ANDROID_META_SUPPORT - platformData->restoreMetadata(m_frame->settings()); -#endif - m_webFrame->transitionToCommitted(m_frame); -} - -void FrameLoaderClientAndroid::transitionToCommittedForNewPage() { - ASSERT(m_frame); - -#ifdef ANDROID_META_SUPPORT - // reset metadata settings for the main frame as they are not preserved cross page - if (m_frame == m_frame->page()->mainFrame() && m_frame->settings()) - m_frame->settings()->resetMetadataSettings(); -#endif - - // Save the old WebViewCore before creating a new FrameView. There is one - // WebViewCore per page. Each frame, including the main frame and sub frame, - // has a 1:1 FrameView and WebFrameView. - WebViewCore* webViewCore = WebViewCore::getWebViewCore(m_frame->view()); - Retain(webViewCore); - - // Save the old WebFrameView's bounds and apply them to the new WebFrameView - WebFrameView* oldWebFrameView = static_cast (m_frame->view()->platformWidget()); - IntRect bounds = oldWebFrameView->getBounds(); - IntRect visBounds = oldWebFrameView->getVisibleBounds(); - IntRect windowBounds = oldWebFrameView->getWindowBounds(); - WebCore::FrameView* oldFrameView = oldWebFrameView->view(); - const float oldZoomFactor = oldFrameView->frame()->textZoomFactor(); - m_frame->createView(bounds.size(), oldFrameView->baseBackgroundColor(), oldFrameView->isTransparent(), - oldFrameView->fixedLayoutSize(), oldFrameView->useFixedLayout()); - if (oldZoomFactor != 1.0f && oldZoomFactor != m_frame->textZoomFactor()) { - m_frame->setTextZoomFactor(oldZoomFactor); - } - - // Create a new WebFrameView for the new FrameView - WebFrameView* newFrameView = new WebFrameView(m_frame->view(), webViewCore); - newFrameView->setLocation(bounds.x(), bounds.y()); - newFrameView->setSize(bounds.width(), bounds.height()); - newFrameView->setVisibleSize(visBounds.width(), visBounds.height()); - newFrameView->setWindowBounds(windowBounds.x(), windowBounds.y(), windowBounds.width(), windowBounds.height()); - // newFrameView attaches itself to FrameView which Retains the reference, so - // call Release for newFrameView - Release(newFrameView); - // WebFrameView Retains webViewCore, so call Release for webViewCore - Release(webViewCore); - - m_webFrame->transitionToCommitted(m_frame); -} - -void FrameLoaderClientAndroid::dispatchDidBecomeFrameset(bool) -{ -} - -bool FrameLoaderClientAndroid::canCachePage() const { - return true; -} - -void FrameLoaderClientAndroid::download(ResourceHandle* handle, const ResourceRequest&, - const ResourceRequest&, const ResourceResponse&) { - // Get the C++ side of the load listener and tell it to handle the download - handle->getInternal()->m_loader->downloadFile(); -} - -WTF::PassRefPtr FrameLoaderClientAndroid::createFrame(const KURL& url, const String& name, - HTMLFrameOwnerElement* ownerElement, const String& referrer, - bool allowsScrolling, int marginWidth, int marginHeight) -{ - Frame* parent = ownerElement->document()->frame(); - FrameLoaderClientAndroid* loaderC = new FrameLoaderClientAndroid(m_webFrame); - RefPtr pFrame = Frame::create(parent->page(), ownerElement, loaderC); - Frame* newFrame = pFrame.get(); - loaderC->setFrame(newFrame); - // Append the subframe to the parent and set the name of the subframe. The name must be set after - // appending the child so that the name becomes unique. - parent->tree()->appendChild(newFrame); - newFrame->tree()->setName(name); - // Create a new FrameView and WebFrameView for the child frame to draw into. - RefPtr frameView = FrameView::create(newFrame); - WebFrameView* webFrameView = new WebFrameView(frameView.get(), - WebViewCore::getWebViewCore(parent->view())); - // frameView Retains webFrameView, so call Release for webFrameView - Release(webFrameView); - // Attach the frameView to the newFrame. - newFrame->setView(frameView); - newFrame->init(); - newFrame->selection()->setFocused(true); - LOGV("::WebCore:: createSubFrame returning %p", newFrame); - - // The creation of the frame may have run arbitrary JavaScript that removed it from the page already. - if (!pFrame->page()) - return 0; - - parent->loader()->loadURLIntoChildFrame(url, referrer, pFrame.get()); - - // onLoad may cuase the frame to be removed from the document. Allow the RefPtr to delete the child frame. - if (!pFrame->tree()->parent()) - return NULL; - - return pFrame.release(); -} - -// YouTube flash url path starts with /v/ -static const char slash_v_slash[] = { '/', 'v', '/' }; -static const char slash_e_slash[] = { '/', 'e', '/' }; - -static bool isValidYouTubeVideo(const String& path) -{ - if (!charactersAreAllASCII(path.characters(), path.length())) - return false; - unsigned int len = path.length(); - if (len <= sizeof(slash_v_slash)) // check for more than just /v/ - return false; - CString str = path.lower().utf8(); - const char* data = str.data(); - // Youtube flash url can start with /v/ or /e/ - if (memcmp(data, slash_v_slash, sizeof(slash_v_slash)) != 0) - if (memcmp(data, slash_e_slash, sizeof(slash_e_slash)) != 0) - return false; - // Start after /v/ - for (unsigned int i = sizeof(slash_v_slash); i < len; i++) { - char c = data[i]; - // Check for alpha-numeric characters only. - if (WTF::isASCIIAlphanumeric(c) || c == '_' || c == '-') - continue; - // The url can have more parameters such as &hl=en after the video id. - // Once we start seeing extra parameters we can return true. - return c == '&' && i > sizeof(slash_v_slash); - } - return true; -} - -static bool isYouTubeUrl(const KURL& url, const String& mimeType) -{ - String host = url.host(); - bool youtube = host.endsWith("youtube.com") - || host.endsWith("youtube-nocookie.com"); - return youtube && isValidYouTubeVideo(url.path()) - && equalIgnoringCase(mimeType, "application/x-shockwave-flash"); -} - -static bool isYouTubeInstalled() { - return WebCore::packageNotifier().isPackageInstalled("com.google.android.youtube"); -} - -// Use PluginViewBase rather than an Android specific sub class as we do not require any -// Android specific functionality; this just renders a placeholder which will later -// activate the real plugin. -class PluginToggleWidget : public PluginViewBase { -public: - PluginToggleWidget(Frame* parent, const IntSize& size, - HTMLPlugInElement* elem, const KURL& url, - const WTF::Vector& paramNames, - const WTF::Vector& paramValues, const String& mimeType, - bool loadManually) - : PluginViewBase(0) - , m_parent(parent) - , m_size(size) - , m_element(elem) - , m_url(url) - , m_paramNames(paramNames) - , m_paramValues(paramValues) - , m_mimeType(mimeType) - , m_loadManually(loadManually) - { - resize(size); - } - - virtual void paint(GraphicsContext* ctx, const IntRect& rect) - { - // Most of this code is copied from PluginView::paintMissingPluginIcon - // with slight modification. - - static RefPtr image; - if (!image) { - image = Image::loadPlatformResource("togglePlugin"); - } - - IntRect imageRect(x(), y(), image->width(), image->height()); - - int xOffset = (width() - imageRect.width()) >> 1; - int yOffset = (height() - imageRect.height()) >> 1; - - imageRect.move(xOffset, yOffset); - - if (!rect.intersects(imageRect)) - return; - - // FIXME: We need to clip similarly to paintMissingPluginIcon but it is - // way screwed up right now. It has something to do with how we tell - // webkit the scroll position and it causes the placeholder to get - // clipped very badly. http://b/issue?id=2533303 - - ctx->save(); - ctx->clip(frameRect()); - - ctx->setFillColor(Color::white, ColorSpaceDeviceRGB); - ctx->fillRect(frameRect()); - if (frameRect().contains(imageRect)) { - // Leave a 2 pixel padding. - const int pixelWidth = 2; - IntRect innerRect = frameRect(); - innerRect.inflate(-pixelWidth); - // Draw a 2 pixel light gray border. - ctx->setStrokeColor(Color::lightGray, ColorSpaceDeviceRGB); - ctx->strokeRect(innerRect, pixelWidth); - } - - // Draw the image in the center - ctx->drawImage(image.get(), ColorSpaceDeviceRGB, imageRect.location()); - ctx->restore(); - } - - virtual void handleEvent(Event* event) - { - if (event->type() != eventNames().clickEvent) - return; - - Frame* frame = m_parent->page()->mainFrame(); - while (frame) { - RenderView* view = frame->contentRenderer(); - const HashSet widgets = view->widgets(); - HashSet::const_iterator it = widgets.begin(); - HashSet::const_iterator end = widgets.end(); - for (; it != end; ++it) { - Widget* widget = (*it)->widget(); - // PluginWidget is used only with PluginToggleWidget - if (widget && widget->isPluginViewBase()) { - PluginToggleWidget* ptw = - static_cast(widget); - ptw->swapPlugin(*it); - } - } - frame = frame->tree()->traverseNext(); - } - } - - void swapPlugin(RenderWidget* renderer) { - typedef FrameLoaderClientAndroid FLCA; - FLCA* client = static_cast(m_parent->loader()->client()); - client->enableOnDemandPlugins(); - WTF::PassRefPtr prpWidget = - PluginView::create(m_parent.get(), - m_size, - m_element, - m_url, - m_paramNames, - m_paramValues, - m_mimeType, - m_loadManually); - RefPtr myProtector(this); - prpWidget->focusPluginElement(); - renderer->setWidget(prpWidget); - } - -private: - void invalidateRect(const IntRect& rect) { } - - RefPtr m_parent; - IntSize m_size; - HTMLPlugInElement* m_element; - KURL m_url; - WTF::Vector m_paramNames; - WTF::Vector m_paramValues; - String m_mimeType; - bool m_loadManually; -}; - -WTF::PassRefPtr FrameLoaderClientAndroid::createPlugin( - const IntSize& size, - HTMLPlugInElement* element, - const KURL& url, - const WTF::Vector& names, - const WTF::Vector& values, - const String& mimeType, - bool loadManually) { - WTF::PassRefPtr prpWidget = 0; -#ifdef ANDROID_PLUGINS - // This is copied from PluginView.cpp. We need to determine if a plugin - // will be found before doing some of the work in PluginView. - String mimeTypeCopy = mimeType; - PluginPackage* plugin = - PluginDatabase::installedPlugins()->findPlugin(url, mimeTypeCopy); - if (!plugin && PluginDatabase::installedPlugins()->refresh()) { - mimeTypeCopy = mimeType; - plugin = PluginDatabase::installedPlugins()->findPlugin(url, - mimeTypeCopy); - } - Settings* settings = m_frame->settings(); - // Do the placeholder if plugins are on-demand and there is a plugin for the - // given mime type. - if (settings && settings->arePluginsOnDemand() && plugin && - !m_onDemandPluginsEnabled) { - return adoptRef(new PluginToggleWidget(m_frame, size, element, url, - names, values, mimeType, loadManually)); - } - prpWidget = PluginView::create(m_frame, - size, - element, - url, - names, - values, - mimeType, - loadManually); - // Return the plugin if it was loaded successfully. Otherwise, fallback to - // the youtube placeholder if possible. No need to check prpWidget as - // PluginView::create will create a PluginView for missing plugins. - // Note: this check really only checks if the plugin was found and not if - // the plugin was loaded. - if (prpWidget->status() == PluginStatusLoadedSuccessfully) - return prpWidget; -#endif - // Create an iframe for youtube urls. - if (isYouTubeUrl(url, mimeType) && isYouTubeInstalled()) { - WTF::RefPtr frame = createFrame(blankURL(), String(), element, - String(), false, 0, 0); - if (frame) { - // grab everything after /v/ - String videoId = url.path().substring(sizeof(slash_v_slash)); - // Extract just the video id - unsigned videoIdEnd = 0; - for (; videoIdEnd < videoId.length(); videoIdEnd++) { - if (videoId[videoIdEnd] == '&') { - videoId = videoId.left(videoIdEnd); - break; - } - } - AssetManager* am = globalAssetManager(); - Asset* a = am->open("webkit/youtube.html", - Asset::ACCESS_BUFFER); - if (!a) - return NULL; - String s = String((const char*)a->getBuffer(false), a->getLength()); - s = s.replace("VIDEO_ID", videoId); - delete a; - loadDataIntoFrame(frame.get(), - KURL(ParsedURLString, "file:///android_asset/webkit/"), String(), s); - // Transfer ownership to a local refptr. - WTF::RefPtr widget(frame->view()); - return widget.release(); - } - } - return prpWidget; -} - -void FrameLoaderClientAndroid::redirectDataToPlugin(Widget* pluginWidget) { - // Do not redirect data if the Widget is our plugin placeholder. - if (pluginWidget->isPluginView()) { - m_manualLoader = static_cast(pluginWidget); - } -} - -WTF::PassRefPtr FrameLoaderClientAndroid::createJavaAppletWidget(const IntSize&, HTMLAppletElement*, - const KURL& baseURL, const WTF::Vector& paramNames, - const WTF::Vector& paramValues) { - // don't support widget yet - notImplemented(); - return 0; -} - -void FrameLoaderClientAndroid::didTransferChildFrameToNewDocument(WebCore::Page*) -{ - ASSERT(m_frame); - // m_webFrame points to the WebFrame for the page that our frame previously - // belonged to. If the frame now belongs to a new page, we need to update - // m_webFrame to point to the WebFrame for the new page. - Page* newPage = m_frame->page(); - if (newPage != m_webFrame->page()) { - ChromeClientAndroid* chromeClient = static_cast(newPage->chrome()->client()); - Release(m_webFrame); - m_webFrame = chromeClient->webFrame(); - Retain(m_webFrame); - } -} - -void FrameLoaderClientAndroid::transferLoadingResourceFromPage(unsigned long, DocumentLoader*, const ResourceRequest&, Page*) -{ - notImplemented(); -} - -// This function is used by the element to determine the type of -// the contents and work out if it can render it. -ObjectContentType FrameLoaderClientAndroid::objectContentType(const KURL& url, - const String& mimeType) { - return FrameLoader::defaultObjectContentType(url, mimeType); -} - -// This function allows the application to set the correct CSS media -// style. Android could use it to set the media style 'handheld'. Safari -// may use it to set the media style to 'print' when the user wants to print -// a particular web page. -String FrameLoaderClientAndroid::overrideMediaType() const { - lowPriority_notImplemented(); - return String(); -} - -// This function is used to re-attach Javascript<->native code classes. -void FrameLoaderClientAndroid::dispatchDidClearWindowObjectInWorld(DOMWrapperWorld* world) -{ - if (world != mainThreadNormalWorld()) - return; - - ASSERT(m_frame); - LOGV("::WebCore:: windowObjectCleared called on frame %p for %s\n", - m_frame, m_frame->loader()->url().string().ascii().data()); - m_webFrame->windowObjectCleared(m_frame); -} - -void FrameLoaderClientAndroid::documentElementAvailable() { -} - -// functions new to Jun-07 tip of tree merge: -ResourceError FrameLoaderClientAndroid::blockedError(ResourceRequest const& request) { - return ResourceError(String(), InternalErrorFileDoesNotExist, String(), String()); -} - -// functions new to Nov-07 tip of tree merge: -void FrameLoaderClientAndroid::didPerformFirstNavigation() const { - // This seems to be just a notification that the UI can listen to, to - // know if the user has performed first navigation action. - // It is called from - // void FrameLoader::addBackForwardItemClippedAtTarget(bool doClip) - // "Navigation" here means a transition from one page to another that - // ends up in the back/forward list. -} - -void FrameLoaderClientAndroid::registerForIconNotification(bool listen) { - if (listen) - WebIconDatabase::RegisterForIconNotification(this); - else - WebIconDatabase::UnregisterForIconNotification(this); -} - -// This is the WebIconDatabaseClient method for receiving a notification when we -// get the icon for the page. -void FrameLoaderClientAndroid::didAddIconForPageUrl(const String& pageUrl) { - // This call must happen before dispatchDidReceiveIcon since that method - // may register for icon notifications again since the icon data may have - // to be read from disk. - registerForIconNotification(false); - KURL u(ParsedURLString, pageUrl); - if (equalIgnoringFragmentIdentifier(u, m_frame->loader()->url())) { - dispatchDidReceiveIcon(); - } -} - -void FrameLoaderClientAndroid::dispatchDidChangeIcons() { - notImplemented(); -} - -PassRefPtr FrameLoaderClientAndroid::createNetworkingContext() -{ - return FrameNetworkingContextAndroid::create(getFrame()); -} - -} diff --git a/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.h b/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.h deleted file mode 100644 index 25561a8..0000000 --- a/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.h +++ /dev/null @@ -1,271 +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 FrameLoaderClientAndroid_h -#define FrameLoaderClientAndroid_h - -#include "CacheBuilder.h" -#include "FrameLoaderClient.h" -#include "ResourceResponse.h" -#include "WebIconDatabase.h" -#include - -namespace WebCore { -class PluginManualLoader; -} - -using namespace WebCore; - -namespace android { - class WebFrame; - - class FrameLoaderClientAndroid : public FrameLoaderClient, - WebIconDatabaseClient { - public: - FrameLoaderClientAndroid(WebFrame* webframe); - - Frame* getFrame() { return m_frame; } - static FrameLoaderClientAndroid* get(const Frame* frame); - - void setFrame(Frame* frame) { m_frame = frame; } - WebFrame* webFrame() const { return m_webFrame; } - - virtual void frameLoaderDestroyed(); - - virtual bool hasWebView() const; // mainly for assertions - - virtual void makeRepresentation(DocumentLoader*); - virtual void forceLayout(); - virtual void forceLayoutForNonHTML(); - - virtual void setCopiesOnScroll(); - - virtual void detachedFromParent2(); - virtual void detachedFromParent3(); - - virtual void assignIdentifierToInitialRequest(unsigned long identifier, DocumentLoader*, const ResourceRequest&); - - virtual void dispatchWillSendRequest(DocumentLoader*, unsigned long identifier, ResourceRequest&, const ResourceResponse& redirectResponse); - virtual bool shouldUseCredentialStorage(DocumentLoader*, unsigned long identifier); - virtual void dispatchDidReceiveAuthenticationChallenge(DocumentLoader*, unsigned long identifier, const AuthenticationChallenge&); - virtual void dispatchDidCancelAuthenticationChallenge(DocumentLoader*, unsigned long identifier, const AuthenticationChallenge&); - virtual void dispatchDidReceiveResponse(DocumentLoader*, unsigned long identifier, const ResourceResponse&); - virtual void dispatchDidReceiveContentLength(DocumentLoader*, unsigned long identifier, int lengthReceived); - virtual void dispatchDidFinishLoading(DocumentLoader*, unsigned long identifier); - virtual void dispatchDidFailLoading(DocumentLoader*, unsigned long identifier, const ResourceError&); - virtual bool dispatchDidLoadResourceFromMemoryCache(DocumentLoader*, const ResourceRequest&, const ResourceResponse&, int length); - - virtual void dispatchDidHandleOnloadEvents(); - virtual void dispatchDidReceiveServerRedirectForProvisionalLoad(); - virtual void dispatchDidCancelClientRedirect(); - virtual void dispatchWillPerformClientRedirect(const KURL&, double interval, double fireDate); - virtual void dispatchDidChangeLocationWithinPage(); - virtual void dispatchDidPushStateWithinPage(); - virtual void dispatchDidReplaceStateWithinPage(); - virtual void dispatchDidPopStateWithinPage(); - virtual void dispatchWillClose(); - virtual void dispatchDidReceiveIcon(); - virtual void dispatchDidStartProvisionalLoad(); - virtual void dispatchDidReceiveTitle(const String& title); - virtual void dispatchDidCommitLoad(); - virtual void dispatchDidFailProvisionalLoad(const ResourceError&); - virtual void dispatchDidFailLoad(const ResourceError&); - virtual void dispatchDidFinishDocumentLoad(); - virtual void dispatchDidFinishLoad(); - virtual void dispatchDidFirstLayout(); - virtual void dispatchDidFirstVisuallyNonEmptyLayout(); - - virtual Frame* dispatchCreatePage(const NavigationAction&); - virtual void dispatchShow(); - - virtual void dispatchDecidePolicyForMIMEType(FramePolicyFunction, const String& MIMEType, const ResourceRequest&); - virtual void dispatchDecidePolicyForNewWindowAction(FramePolicyFunction, const NavigationAction&, const ResourceRequest&, PassRefPtr, const String& frameName); - virtual void dispatchDecidePolicyForNavigationAction(FramePolicyFunction, const NavigationAction&, const ResourceRequest&, PassRefPtr); - virtual void cancelPolicyCheck(); - - virtual void dispatchUnableToImplementPolicy(const ResourceError&); - - virtual void dispatchWillSubmitForm(FramePolicyFunction, PassRefPtr); - - virtual void dispatchDidLoadMainResource(DocumentLoader*); - virtual void revertToProvisionalState(DocumentLoader*); - virtual void setMainDocumentError(DocumentLoader*, const ResourceError&); - - virtual void willChangeEstimatedProgress(); - virtual void didChangeEstimatedProgress(); - virtual void postProgressStartedNotification(); - virtual void postProgressEstimateChangedNotification(); - virtual void postProgressFinishedNotification(); - - virtual void setMainFrameDocumentReady(bool); - - virtual void startDownload(const ResourceRequest&); - - virtual void willChangeTitle(DocumentLoader*); - virtual void didChangeTitle(DocumentLoader*); - - virtual void committedLoad(DocumentLoader*, const char*, int); - virtual void finishedLoading(DocumentLoader*); - - virtual void updateGlobalHistory(); - virtual void updateGlobalHistoryRedirectLinks(); - - virtual bool shouldGoToHistoryItem(HistoryItem*) const; - - virtual void didDisplayInsecureContent(); - virtual void didRunInsecureContent(SecurityOrigin*); - - virtual void dispatchDidAddBackForwardItem(HistoryItem*) const; - virtual void dispatchDidRemoveBackForwardItem(HistoryItem*) const; - virtual void dispatchDidChangeBackForwardIndex() const; - - virtual ResourceError cancelledError(const ResourceRequest&); - virtual ResourceError blockedError(const ResourceRequest&); - virtual ResourceError cannotShowURLError(const ResourceRequest&); - virtual ResourceError interruptForPolicyChangeError(const ResourceRequest&); - - virtual ResourceError cannotShowMIMETypeError(const ResourceResponse&); - virtual ResourceError fileDoesNotExistError(const ResourceResponse&); - virtual ResourceError pluginWillHandleLoadError(const ResourceResponse&); - - virtual bool shouldFallBack(const ResourceError&); - - virtual bool canHandleRequest(const ResourceRequest&) const; - virtual bool canShowMIMEType(const String& MIMEType) const; - virtual bool canShowMIMETypeAsHTML(const String& MIMEType) const; - virtual bool representationExistsForURLScheme(const String& URLScheme) const; - virtual String generatedMIMETypeForURLScheme(const String& URLScheme) const; - - virtual void frameLoadCompleted(); - virtual void saveViewStateToItem(HistoryItem*); - virtual void restoreViewState(); - virtual void provisionalLoadStarted(); - virtual void didFinishLoad(); - virtual void prepareForDataSourceReplacement(); - - virtual PassRefPtr createDocumentLoader(const ResourceRequest&, const SubstituteData&); - virtual void setTitle(const String& title, const KURL&); - - // This provides the userAgent to WebCore. It is used by WebCore to - // populate navigator.userAgent and to set the HTTP header in - // ResourceRequest objects. We also set a userAgent on WebRequestContext - // for the Chromium HTTP stack, which overrides the value on the - // ResourceRequest. - virtual String userAgent(const KURL&); - - virtual void savePlatformDataToCachedFrame(WebCore::CachedFrame*); - virtual void transitionToCommittedFromCachedFrame(WebCore::CachedFrame*); - virtual void transitionToCommittedForNewPage(); - - virtual void dispatchDidBecomeFrameset(bool isFrameSet); - - virtual bool canCachePage() const; - virtual void download(ResourceHandle*, const ResourceRequest&, const ResourceRequest&, const ResourceResponse&); - - virtual WTF::PassRefPtr createFrame(const KURL& url, const String& name, HTMLFrameOwnerElement* ownerElement, const String& referrer, bool allowsScrolling, int marginWidth, int marginHeight); - virtual void didTransferChildFrameToNewDocument(WebCore::Page*); - virtual void transferLoadingResourceFromPage(unsigned long identifier, DocumentLoader*, const ResourceRequest&, Page* oldPage); - virtual WTF::PassRefPtr createPlugin(const IntSize&, HTMLPlugInElement*, const KURL&, const WTF::Vector&, const WTF::Vector&, const String&, bool loadManually); - virtual void redirectDataToPlugin(Widget* pluginWidget); - - virtual WTF::PassRefPtr createJavaAppletWidget(const IntSize&, HTMLAppletElement*, const KURL& baseURL, const WTF::Vector& paramNames, const WTF::Vector& paramValues); - - virtual ObjectContentType objectContentType(const KURL& url, const String& mimeType); - virtual String overrideMediaType() const; - - virtual void dispatchDidClearWindowObjectInWorld(DOMWrapperWorld*); - virtual void documentElementAvailable(); - virtual void didPerformFirstNavigation() const; - -#if USE(V8) - // TODO(benm): Implement - virtual void didCreateScriptContextForFrame() { } - virtual void didDestroyScriptContextForFrame() { } - virtual void didCreateIsolatedScriptContext() { } - - virtual bool allowScriptExtension(const String& extensionName, int extensionGroup) { return false; } -#endif - - virtual void registerForIconNotification(bool listen = true); - - virtual void dispatchDidReceiveTouchIconURL(const String& url, bool precomposed); - - virtual PassRefPtr createNetworkingContext(); - - // 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(); - void dispatchWillSendSubmitEvent(HTMLFormElement*); - - virtual void didSaveToPageCache() { } - virtual void didRestoreFromPageCache() { } - private: - CacheBuilder m_cacheBuilder; - Frame* m_frame; - WebFrame* m_webFrame; - PluginManualLoader* m_manualLoader; - bool m_hasSentResponseToPlugin; - bool m_onDemandPluginsEnabled; - - enum ResourceErrors { - InternalErrorCancelled = -99, - InternalErrorCannotShowUrl, - InternalErrorInterrupted, - InternalErrorCannotShowMimeType, - InternalErrorFileDoesNotExist, - InternalErrorPluginWillHandleLoadError, - InternalErrorLast - }; - - /* XXX: These must match android.net.http.EventHandler */ - enum EventHandlerErrors { - Error = -1, - ErrorLookup = -2, - ErrorUnsupportedAuthScheme = -3, - ErrorAuth = -4, - ErrorProxyAuth = -5, - ErrorConnect = -6, - ErrorIO = -7, - ErrorTimeout = -8, - ErrorRedirectLoop = -9, - ErrorUnsupportedScheme = -10, - ErrorFailedSslHandshake = -11, - ErrorBadUrl = -12, - ErrorFile = -13, - ErrorFileNotFound = -14, - ErrorTooManyRequests = -15 - }; - friend class CacheBuilder; - }; - -} - -#endif diff --git a/WebKit/android/WebCoreSupport/FrameNetworkingContextAndroid.cpp b/WebKit/android/WebCoreSupport/FrameNetworkingContextAndroid.cpp deleted file mode 100644 index a5fe494..0000000 --- a/WebKit/android/WebCoreSupport/FrameNetworkingContextAndroid.cpp +++ /dev/null @@ -1,52 +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 "FrameNetworkingContextAndroid.h" - -#include "DocumentLoader.h" -#include "MainResourceLoader.h" -#include "Settings.h" - -using namespace WebCore; - -namespace android { - -FrameNetworkingContextAndroid::FrameNetworkingContextAndroid(WebCore::Frame* frame) - : WebCore::FrameNetworkingContext(frame) -{ -} - -MainResourceLoader* FrameNetworkingContextAndroid::mainResourceLoader() const -{ - return frame()->loader()->activeDocumentLoader()->mainResourceLoader(); -} - -FrameLoaderClient* FrameNetworkingContextAndroid::frameLoaderClient() const -{ - return frame()->loader()->client(); -} - -} // namespace android diff --git a/WebKit/android/WebCoreSupport/FrameNetworkingContextAndroid.h b/WebKit/android/WebCoreSupport/FrameNetworkingContextAndroid.h deleted file mode 100644 index d0ff979..0000000 --- a/WebKit/android/WebCoreSupport/FrameNetworkingContextAndroid.h +++ /dev/null @@ -1,54 +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 FrameNetworkingContextAndroid_h -#define FrameNetworkingContextAndroid_h - -#include "FrameNetworkingContext.h" - -namespace WebCore { -class MainResourceLoader; -class FrameLoaderClient; -} - -namespace android { - -class FrameNetworkingContextAndroid : public WebCore::FrameNetworkingContext { -public: - static PassRefPtr create(WebCore::Frame* frame) - { - return adoptRef(new FrameNetworkingContextAndroid(frame)); - } - -private: - FrameNetworkingContextAndroid(WebCore::Frame*); - - virtual WebCore::MainResourceLoader* mainResourceLoader() const; - virtual WebCore::FrameLoaderClient* frameLoaderClient() const; -}; - -} // namespace android - -#endif // FrameNetworkingContextAndroid_h diff --git a/WebKit/android/WebCoreSupport/GeolocationPermissions.cpp b/WebKit/android/WebCoreSupport/GeolocationPermissions.cpp deleted file mode 100755 index 36a9b61..0000000 --- a/WebKit/android/WebCoreSupport/GeolocationPermissions.cpp +++ /dev/null @@ -1,419 +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 "config.h" -#include "GeolocationPermissions.h" - -#include "DOMWindow.h" -#include "Frame.h" -#include "Geolocation.h" -#include "Navigator.h" -#include "SQLiteDatabase.h" -#include "SQLiteFileSystem.h" -#include "SQLiteStatement.h" -#include "SQLiteTransaction.h" -#include "WebViewCore.h" - -#include - -using namespace WebCore; - -namespace android { - -GeolocationPermissions::PermissionsMap GeolocationPermissions::s_permanentPermissions; -GeolocationPermissions::GeolocationPermissionsVector GeolocationPermissions::s_instances; -bool GeolocationPermissions::s_alwaysDeny = false; -bool GeolocationPermissions::s_permanentPermissionsLoaded = false; -bool GeolocationPermissions::s_permanentPermissionsModified = false; -String GeolocationPermissions::s_databasePath; - -static const char* databaseName = "GeolocationPermissions.db"; - -GeolocationPermissions::GeolocationPermissions(WebViewCore* webViewCore, Frame* mainFrame) - : m_webViewCore(webViewCore) - , m_mainFrame(mainFrame) - , m_timer(this, &GeolocationPermissions::timerFired) - -{ - ASSERT(m_webViewCore); - maybeLoadPermanentPermissions(); - s_instances.append(this); -} - -GeolocationPermissions::~GeolocationPermissions() -{ - size_t index = s_instances.find(this); - s_instances.remove(index); -} - -void GeolocationPermissions::queryPermissionState(Frame* frame) -{ - ASSERT(s_permanentPermissionsLoaded); - - // We use SecurityOrigin::toString to key the map. Note that testing - // the SecurityOrigin pointer for equality is insufficient. - String originString = frame->document()->securityOrigin()->toString(); - - // If we've been told to always deny requests, do so. - if (s_alwaysDeny) { - makeAsynchronousCallbackToGeolocation(originString, false); - return; - } - - // See if we have a record for this origin in the permanent permissions. - // These take precedence over temporary permissions so that changes made - // from the browser settings work as intended. - PermissionsMap::const_iterator iter = s_permanentPermissions.find(originString); - PermissionsMap::const_iterator end = s_permanentPermissions.end(); - if (iter != end) { - bool allow = iter->second; - makeAsynchronousCallbackToGeolocation(originString, allow); - return; - } - - // Check the temporary permisions. - iter = m_temporaryPermissions.find(originString); - end = m_temporaryPermissions.end(); - if (iter != end) { - bool allow = iter->second; - makeAsynchronousCallbackToGeolocation(originString, allow); - return; - } - - // If there's no pending request, prompt the user. - if (nextOriginInQueue().isEmpty()) { - // Although multiple tabs may request permissions for the same origin - // simultaneously, the routing in WebViewCore/CallbackProxy ensures that - // the result of the request will make it back to this object, so - // there's no need for a globally unique ID for the request. - m_webViewCore->geolocationPermissionsShowPrompt(originString); - } - - // Add this request to the queue so we can track which frames requested it. - if (m_queuedOrigins.find(originString) == WTF::notFound) { - m_queuedOrigins.append(originString); - FrameSet frameSet; - frameSet.add(frame); - m_queuedOriginsToFramesMap.add(originString, frameSet); - } else { - ASSERT(m_queuedOriginsToFramesMap.contains(originString)); - m_queuedOriginsToFramesMap.find(originString)->second.add(frame); - } -} - -void GeolocationPermissions::cancelPermissionStateQuery(WebCore::Frame* frame) -{ - // We cancel any queued request for the given frame. There can be at most - // one of these, since each frame maps to a single origin. We only cancel - // the request if this frame is the only one reqesting permission for this - // origin. - // - // We can use the origin string to avoid searching the map. - String originString = frame->document()->securityOrigin()->toString(); - size_t index = m_queuedOrigins.find(originString); - if (index == WTF::notFound) - return; - - ASSERT(m_queuedOriginsToFramesMap.contains(originString)); - OriginToFramesMap::iterator iter = m_queuedOriginsToFramesMap.find(originString); - ASSERT(iter->second.contains(frame)); - iter->second.remove(frame); - if (!iter->second.isEmpty()) - return; - - m_queuedOrigins.remove(index); - m_queuedOriginsToFramesMap.remove(iter); - - // If this is the origin currently being shown, cancel the prompt - // and show the next in the queue, if present. - if (index == 0) { - m_webViewCore->geolocationPermissionsHidePrompt(); - if (!nextOriginInQueue().isEmpty()) - m_webViewCore->geolocationPermissionsShowPrompt(nextOriginInQueue()); - } -} - -void GeolocationPermissions::makeAsynchronousCallbackToGeolocation(String origin, bool allow) -{ - m_callbackData.origin = origin; - m_callbackData.allow = allow; - m_timer.startOneShot(0); -} - -void GeolocationPermissions::providePermissionState(String origin, bool allow, bool remember) -{ - ASSERT(s_permanentPermissionsLoaded); - - // It's possible that this method is called with an origin that doesn't - // match m_originInProgress. This can occur if this object is reset - // while a permission result is in the process of being marshalled back to - // the WebCore thread from the browser. In this case, we simply ignore the - // call. - if (origin != nextOriginInQueue()) - return; - - maybeCallbackFrames(origin, allow); - recordPermissionState(origin, allow, remember); - - // If the permissions are set to be remembered, cancel any queued requests - // for this domain in other tabs. - if (remember) - cancelPendingRequestsInOtherTabs(origin); - - // Clear the origin from the queue. - ASSERT(!m_queuedOrigins.isEmpty()); - m_queuedOrigins.remove(0); - ASSERT(m_queuedOriginsToFramesMap.contains(origin)); - m_queuedOriginsToFramesMap.remove(origin); - - // If there are other requests queued, start the next one. - if (!nextOriginInQueue().isEmpty()) - m_webViewCore->geolocationPermissionsShowPrompt(nextOriginInQueue()); -} - -void GeolocationPermissions::recordPermissionState(String origin, bool allow, bool remember) -{ - if (remember) { - s_permanentPermissions.set(origin, allow); - s_permanentPermissionsModified = true; - } else { - // It's possible that another tab recorded a permanent permission for - // this origin while our request was in progress, but we record it - // anyway. - m_temporaryPermissions.set(origin, allow); - } -} - -void GeolocationPermissions::cancelPendingRequestsInOtherTabs(String origin) -{ - for (GeolocationPermissionsVector::const_iterator iter = s_instances.begin(); - iter != s_instances.end(); - ++iter) - (*iter)->cancelPendingRequests(origin); -} - -void GeolocationPermissions::cancelPendingRequests(String origin) -{ - size_t index = m_queuedOrigins.find(origin); - - // Don't cancel the request if it's currently being shown, in which case - // it's at index 0. - if (index == WTF::notFound || !index) - return; - - // Get the permission from the permanent list. - ASSERT(s_permanentPermissions.contains(origin)); - PermissionsMap::const_iterator iter = s_permanentPermissions.find(origin); - bool allow = iter->second; - - maybeCallbackFrames(origin, allow); - - m_queuedOrigins.remove(index); - ASSERT(m_queuedOriginsToFramesMap.contains(origin)); - m_queuedOriginsToFramesMap.remove(origin); -} - -void GeolocationPermissions::timerFired(Timer* timer) -{ - ASSERT_UNUSED(timer, timer == &m_timer); - maybeCallbackFrames(m_callbackData.origin, m_callbackData.allow); -} - -void GeolocationPermissions::resetTemporaryPermissionStates() -{ - ASSERT(s_permanentPermissionsLoaded); - m_queuedOrigins.clear(); - m_queuedOriginsToFramesMap.clear(); - m_temporaryPermissions.clear(); - // If any permission results are being marshalled back to this thread, this - // will render them inefective. - m_timer.stop(); - - m_webViewCore->geolocationPermissionsHidePrompt(); -} - -const WTF::String& GeolocationPermissions::nextOriginInQueue() -{ - static const String emptyString = ""; - return m_queuedOrigins.isEmpty() ? emptyString : m_queuedOrigins[0]; -} - -void GeolocationPermissions::maybeCallbackFrames(String origin, bool allow) -{ - // We can't track which frame issued the request, as frames can be deleted - // or have their contents replaced. Even uniqueChildName is not unique when - // frames are dynamically deleted and created. Instead, we simply call back - // to the Geolocation object in all frames from the correct origin. - for (Frame* frame = m_mainFrame; frame; frame = frame->tree()->traverseNext()) { - if (origin == frame->document()->securityOrigin()->toString()) { - // If the page has changed, it may no longer have a Geolocation - // object. - Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation(); - if (geolocation) - geolocation->setIsAllowed(allow); - } - } -} - -GeolocationPermissions::OriginSet GeolocationPermissions::getOrigins() -{ - maybeLoadPermanentPermissions(); - OriginSet origins; - PermissionsMap::const_iterator end = s_permanentPermissions.end(); - for (PermissionsMap::const_iterator iter = s_permanentPermissions.begin(); iter != end; ++iter) - origins.add(iter->first); - return origins; -} - -bool GeolocationPermissions::getAllowed(String origin) -{ - maybeLoadPermanentPermissions(); - bool allowed = false; - PermissionsMap::const_iterator iter = s_permanentPermissions.find(origin); - PermissionsMap::const_iterator end = s_permanentPermissions.end(); - if (iter != end) - allowed = iter->second; - return allowed; -} - -void GeolocationPermissions::clear(String origin) -{ - maybeLoadPermanentPermissions(); - PermissionsMap::iterator iter = s_permanentPermissions.find(origin); - if (iter != s_permanentPermissions.end()) { - s_permanentPermissions.remove(iter); - s_permanentPermissionsModified = true; - } -} - -void GeolocationPermissions::allow(String origin) -{ - maybeLoadPermanentPermissions(); - // We replace any existing permanent permission. - s_permanentPermissions.set(origin, true); - s_permanentPermissionsModified = true; -} - -void GeolocationPermissions::clearAll() -{ - maybeLoadPermanentPermissions(); - s_permanentPermissions.clear(); - s_permanentPermissionsModified = true; -} - -void GeolocationPermissions::maybeLoadPermanentPermissions() -{ - if (s_permanentPermissionsLoaded) - return; - s_permanentPermissionsLoaded = true; - - SQLiteDatabase database; - if (!openDatabase(&database)) - return; - - // Create the table here, such that even if we've just created the DB, the - // commands below should succeed. - if (!database.executeCommand("CREATE TABLE IF NOT EXISTS Permissions (origin TEXT UNIQUE NOT NULL, allow INTEGER NOT NULL)")) { - database.close(); - return; - } - - SQLiteStatement statement(database, "SELECT * FROM Permissions"); - if (statement.prepare() != SQLResultOk) { - database.close(); - return; - } - - ASSERT(s_permanentPermissions.size() == 0); - while (statement.step() == SQLResultRow) - s_permanentPermissions.set(statement.getColumnText(0), statement.getColumnInt64(1)); - - database.close(); -} - -void GeolocationPermissions::maybeStorePermanentPermissions() -{ - // If the permanent permissions haven't been modified, there's no need to - // save them to the DB. (If we haven't even loaded them, writing them now - // would overwrite the stored permissions with the empty set.) - if (!s_permanentPermissionsModified) - return; - - SQLiteDatabase database; - if (!openDatabase(&database)) - return; - - SQLiteTransaction transaction(database); - - // The number of entries should be small enough that it's not worth trying - // to perform a diff. Simply clear the table and repopulate it. - if (!database.executeCommand("DELETE FROM Permissions")) { - database.close(); - return; - } - - PermissionsMap::const_iterator end = s_permanentPermissions.end(); - for (PermissionsMap::const_iterator iter = s_permanentPermissions.begin(); iter != end; ++iter) { - SQLiteStatement statement(database, "INSERT INTO Permissions (origin, allow) VALUES (?, ?)"); - if (statement.prepare() != SQLResultOk) - continue; - statement.bindText(1, iter->first); - statement.bindInt64(2, iter->second); - statement.executeCommand(); - } - - transaction.commit(); - database.close(); - - s_permanentPermissionsModified = false; -} - -void GeolocationPermissions::setDatabasePath(String path) -{ - // Take the first non-empty value. - if (s_databasePath.length() > 0) - return; - s_databasePath = path; -} - -bool GeolocationPermissions::openDatabase(SQLiteDatabase* database) -{ - ASSERT(database); - String filename = SQLiteFileSystem::appendDatabaseFileNameToPath(s_databasePath, databaseName); - if (!database->open(filename)) - return false; - if (chmod(filename.utf8().data(), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)) { - database->close(); - return false; - } - return true; -} - -void GeolocationPermissions::setAlwaysDeny(bool deny) -{ - s_alwaysDeny = deny; -} - -} // namespace android diff --git a/WebKit/android/WebCoreSupport/GeolocationPermissions.h b/WebKit/android/WebCoreSupport/GeolocationPermissions.h deleted file mode 100644 index fb31dfe..0000000 --- a/WebKit/android/WebCoreSupport/GeolocationPermissions.h +++ /dev/null @@ -1,178 +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 GeolocationPermissions_h -#define GeolocationPermissions_h - -#include "PlatformString.h" -#include "Timer.h" - -#include -#include -#include -#include -#include - -namespace WebCore { - class Frame; - class Geolocation; - class SQLiteDatabase; -} - -namespace android { - - class WebViewCore; - - // The GeolocationPermissions class manages Geolocation permissions for the - // browser. Permissions are managed on a per-origin basis, as required by - // the Geolocation spec - http://dev.w3.org/geo/api/spec-source.html. An - // origin specifies the scheme, host and port of particular frame. An - // origin is represented here as a string, using the output of - // WebCore::SecurityOrigin::toString. - // - // Each instance handles permissions for a given main frame. The class - // enforces the following policy. - // - Non-remembered permissions last for the dureation of the main frame. - // - Remembered permissions last indefinitely. - // - All permissions are shared between child frames of a main frame. - // - Only remembered permissions are shared between main frames. - // - Remembered permissions are made available for use in the browser - // settings menu. - class GeolocationPermissions : public RefCounted { - public: - // Creates the GeolocationPermissions object to manage permissions for - // the specified main frame (i.e. tab). The WebViewCore is used to - // communicate with the browser to display UI. - GeolocationPermissions(WebViewCore* webViewCore, WebCore::Frame* mainFrame); - virtual ~GeolocationPermissions(); - - // Queries the permission state for the specified frame. If the - // permission state has not yet been set, prompts the user. Once the - // permission state has been determined, asynchronously calls back to - // the Geolocation objects in all frames in this WebView that are from - // the same origin as the requesting frame. - void queryPermissionState(WebCore::Frame* frame); - void cancelPermissionStateQuery(WebCore::Frame*); - - // Provides this object with a permission state set by the user. The - // permission is specified by 'allow' and applied to 'origin'. If - // 'remember' is set, the permission state is remembered permanently. - // The new permission state is recorded and will trigger callbacks to - // geolocation objects as described above. If any other permission - // requests are queued, the next is started. - void providePermissionState(WTF::String origin, bool allow, bool remember); - - // Clears the temporary permission state and any pending requests. Used - // when the main frame is refreshed or navigated to a new URL. - void resetTemporaryPermissionStates(); - - // Static methods for use from Java. These are used to interact with the - // browser settings menu and to update the permanent permissions when - // system settings are changed. - // Gets the list of all origins for which permanent permissions are - // recorded. - typedef HashSet OriginSet; - static OriginSet getOrigins(); - // Gets whether the specified origin is allowed. - static bool getAllowed(WTF::String origin); - // Clears the permission state for the specified origin. - static void clear(WTF::String origin); - // Sets the permission state for the specified origin to allowed. - static void allow(WTF::String origin); - // Clears the permission state for all origins. - static void clearAll(); - // Sets whether the GeolocationPermissions object should always deny - // permission requests, irrespective of previously recorded permission - // states. - static void setAlwaysDeny(bool deny); - - static void setDatabasePath(WTF::String path); - static bool openDatabase(WebCore::SQLiteDatabase*); - - // Saves the permanent permissions to the DB if required. - static void maybeStorePermanentPermissions(); - - private: - // Records the permission state for the specified origin and whether - // this should be remembered. - void recordPermissionState(WTF::String origin, bool allow, bool remember); - - // Used to make an asynchronous callback to the Geolocation objects. - void makeAsynchronousCallbackToGeolocation(WTF::String origin, bool allow); - void timerFired(WebCore::Timer* timer); - - // Calls back to the Geolocation objects in all frames from the - // specified origin. There may be no such objects, as the frames using - // Geolocation from the specified origin may no longer use Geolocation, - // or may have been navigated to a different origin.. - void maybeCallbackFrames(WTF::String origin, bool allow); - - // Cancels pending permission requests for the specified origin in - // other main frames (ie browser tabs). This is used when the user - // specifies permission to be remembered. - static void cancelPendingRequestsInOtherTabs(WTF::String origin); - void cancelPendingRequests(WTF::String origin); - - static void maybeLoadPermanentPermissions(); - - const WTF::String& nextOriginInQueue(); - - WebViewCore* m_webViewCore; - WebCore::Frame* m_mainFrame; - // A vector of the origins queued to make a permission request. - // The first in the vector is the origin currently making the request. - typedef Vector OriginVector; - OriginVector m_queuedOrigins; - // A map from a queued origin to the set of frames that have requested - // permission for that origin. - typedef HashSet FrameSet; - typedef HashMap OriginToFramesMap; - OriginToFramesMap m_queuedOriginsToFramesMap; - - typedef WTF::HashMap PermissionsMap; - PermissionsMap m_temporaryPermissions; - static PermissionsMap s_permanentPermissions; - - typedef WTF::Vector GeolocationPermissionsVector; - static GeolocationPermissionsVector s_instances; - - WebCore::Timer m_timer; - - struct CallbackData { - WTF::String origin; - bool allow; - }; - CallbackData m_callbackData; - - static bool s_alwaysDeny; - - static bool s_permanentPermissionsLoaded; - static bool s_permanentPermissionsModified; - static WTF::String s_databasePath; - }; - -} // namespace android - -#endif diff --git a/WebKit/android/WebCoreSupport/InspectorClientAndroid.h b/WebKit/android/WebCoreSupport/InspectorClientAndroid.h deleted file mode 100644 index 9d734e8..0000000 --- a/WebKit/android/WebCoreSupport/InspectorClientAndroid.h +++ /dev/null @@ -1,54 +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 InspectorClientAndroid_h -#define InspectorClientAndroid_h - -#include "InspectorClient.h" - -#include - -namespace android { - -class InspectorClientAndroid : public InspectorClient { -public: - virtual ~InspectorClientAndroid() { } - - virtual void inspectorDestroyed() { delete this; } - - virtual void openInspectorFrontend(WebCore::InspectorController*) {} - - virtual void highlight(Node*) {} - virtual void hideHighlight() {} - - virtual void populateSetting(const String& key, String* value) {} - virtual void storeSetting(const String& key, const String& value) {} - - virtual bool sendMessageToFrontend(const WTF::String&) { return false; } -}; - -} - -#endif diff --git a/WebKit/android/WebCoreSupport/KeyGeneratorClient.h b/WebKit/android/WebCoreSupport/KeyGeneratorClient.h deleted file mode 100644 index 1bcd8e8..0000000 --- a/WebKit/android/WebCoreSupport/KeyGeneratorClient.h +++ /dev/null @@ -1,46 +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 KEY_GENERATOR_CLIENT_H -#define KEY_GENERATOR_CLIENT_H - -#include "KURL.h" -#include "PlatformString.h" - -#include - -using namespace WebCore; - -namespace android { - -class KeyGeneratorClient { -public: - virtual ~KeyGeneratorClient() { } - virtual WTF::Vector getSupportedKeyStrengthList() = 0; - virtual String getSignedPublicKeyAndChallengeString(unsigned index, - const String& challenge, const KURL& url) = 0; - }; -} -#endif diff --git a/WebKit/android/WebCoreSupport/MediaPlayerPrivateAndroid.cpp b/WebKit/android/WebCoreSupport/MediaPlayerPrivateAndroid.cpp deleted file mode 100644 index e6a2710..0000000 --- a/WebKit/android/WebCoreSupport/MediaPlayerPrivateAndroid.cpp +++ /dev/null @@ -1,654 +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 "config.h" -#include "MediaPlayerPrivateAndroid.h" - -#if ENABLE(VIDEO) - -#include "BaseLayerAndroid.h" -#include "DocumentLoader.h" -#include "Frame.h" -#include "FrameLoader.h" -#include "FrameView.h" -#include "GraphicsContext.h" -#include "SkiaUtils.h" -#include "VideoLayerAndroid.h" -#include "WebCoreJni.h" -#include "WebViewCore.h" -#include -#include -#include -#include -#include - -using namespace android; -// Forward decl -namespace android { -sp SurfaceTexture_getSurfaceTexture(JNIEnv* env, jobject thiz); -}; - -namespace WebCore { - -static const char* g_ProxyJavaClass = "android/webkit/HTML5VideoViewProxy"; -static const char* g_ProxyJavaClassAudio = "android/webkit/HTML5Audio"; - -struct MediaPlayerPrivate::JavaGlue { - jobject m_javaProxy; - jmethodID m_play; - jmethodID m_teardown; - jmethodID m_seek; - jmethodID m_pause; - // Audio - jmethodID m_newInstance; - jmethodID m_setDataSource; - jmethodID m_getMaxTimeSeekable; - // Video - jmethodID m_getInstance; - jmethodID m_loadPoster; -}; - -MediaPlayerPrivate::~MediaPlayerPrivate() -{ - // m_videoLayer is reference counted, unref is enough here. - m_videoLayer->unref(); - if (m_glue->m_javaProxy) { - JNIEnv* env = JSC::Bindings::getJNIEnv(); - if (env) { - env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_teardown); - env->DeleteGlobalRef(m_glue->m_javaProxy); - } - } - delete m_glue; -} - -void MediaPlayerPrivate::registerMediaEngine(MediaEngineRegistrar registrar) -{ - registrar(create, getSupportedTypes, supportsType); -} - -MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String& type, const String& codecs) -{ - if (WebViewCore::isSupportedMediaMimeType(type)) - return MediaPlayer::MayBeSupported; - return MediaPlayer::IsNotSupported; -} - -void MediaPlayerPrivate::pause() -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - if (!env || !m_glue->m_javaProxy || !m_url.length()) - return; - - m_paused = true; - m_player->playbackStateChanged(); - env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_pause); - checkException(env); -} - -void MediaPlayerPrivate::setVisible(bool visible) -{ - m_isVisible = visible; - if (m_isVisible) - createJavaPlayerIfNeeded(); -} - -void MediaPlayerPrivate::seek(float time) -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - if (!env || !m_url.length()) - return; - - if (m_glue->m_javaProxy) { - env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_seek, static_cast(time * 1000.0f)); - m_currentTime = time; - } - checkException(env); -} - -void MediaPlayerPrivate::prepareToPlay() -{ - // We are about to start playing. Since our Java VideoView cannot - // buffer any data, we just simply transition to the HaveEnoughData - // state in here. This will allow the MediaPlayer to transition to - // the "play" state, at which point our VideoView will start downloading - // the content and start the playback. - m_networkState = MediaPlayer::Loaded; - m_player->networkStateChanged(); - m_readyState = MediaPlayer::HaveEnoughData; - m_player->readyStateChanged(); -} - -MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player) - : m_player(player), - m_glue(0), - m_duration(1), // keep this minimal to avoid initial seek problem - m_currentTime(0), - m_paused(true), - m_readyState(MediaPlayer::HaveNothing), - m_networkState(MediaPlayer::Empty), - m_poster(0), - m_naturalSize(100, 100), - m_naturalSizeUnknown(true), - m_isVisible(false), - m_videoLayer(new VideoLayerAndroid()) -{ -} - -void MediaPlayerPrivate::onEnded() -{ - m_currentTime = duration(); - m_player->timeChanged(); - m_paused = true; - m_player->playbackStateChanged(); - m_networkState = MediaPlayer::Idle; -} - -void MediaPlayerPrivate::onPaused() -{ - m_paused = true; - m_player->playbackStateChanged(); - m_networkState = MediaPlayer::Idle; - m_player->playbackStateChanged(); -} - -void MediaPlayerPrivate::onTimeupdate(int position) -{ - m_currentTime = position / 1000.0f; - m_player->timeChanged(); -} - -void MediaPlayerPrivate::onStopFullscreen() -{ - if (m_player && m_player->mediaPlayerClient() - && m_player->mediaPlayerClient()->mediaPlayerOwningDocument()) { - m_player->mediaPlayerClient()->mediaPlayerOwningDocument()->webkitCancelFullScreen(); - } -} - -class MediaPlayerVideoPrivate : public MediaPlayerPrivate { -public: - void load(const String& url) - { - m_url = url; - // Cheat a bit here to make sure Window.onLoad event can be triggered - // at the right time instead of real video play time, since only full - // screen video play is supported in Java's VideoView. - // See also comments in prepareToPlay function. - m_networkState = MediaPlayer::Loading; - m_player->networkStateChanged(); - m_readyState = MediaPlayer::HaveCurrentData; - m_player->readyStateChanged(); - } - - void play() - { - JNIEnv* env = JSC::Bindings::getJNIEnv(); - if (!env || !m_url.length() || !m_glue->m_javaProxy) - return; - - // We only play video fullscreen on Android, so stop sites playing fullscreen video in the onload handler. - Frame* frame = m_player->frameView()->frame(); - if (frame && !frame->loader()->documentLoader()->wasOnloadHandled()) - return; - - m_paused = false; - m_player->playbackStateChanged(); - - if (m_currentTime == duration()) - m_currentTime = 0; - - jstring jUrl = wtfStringToJstring(env, m_url); - env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_play, jUrl, - static_cast(m_currentTime * 1000.0f), - m_videoLayer->uniqueId()); - env->DeleteLocalRef(jUrl); - - checkException(env); - } - bool canLoadPoster() const { return true; } - void setPoster(const String& url) - { - if (m_posterUrl == url) - return; - - m_posterUrl = url; - JNIEnv* env = JSC::Bindings::getJNIEnv(); - if (!env || !m_glue->m_javaProxy || !m_posterUrl.length()) - return; - // Send the poster - jstring jUrl = wtfStringToJstring(env, m_posterUrl); - env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_loadPoster, jUrl); - env->DeleteLocalRef(jUrl); - } - void paint(GraphicsContext* ctxt, const IntRect& r) - { - if (ctxt->paintingDisabled()) - return; - - if (!m_isVisible) - return; - - if (!m_poster || (!m_poster->getPixels() && !m_poster->pixelRef())) - return; - - SkCanvas* canvas = ctxt->platformContext()->mCanvas; - // We paint with the following rules in mind: - // - only downscale the poster, never upscale - // - maintain the natural aspect ratio of the poster - // - the poster should be centered in the target rect - float originalRatio = static_cast(m_poster->width()) / static_cast(m_poster->height()); - int posterWidth = r.width() > m_poster->width() ? m_poster->width() : r.width(); - int posterHeight = posterWidth / originalRatio; - int posterX = ((r.width() - posterWidth) / 2) + r.x(); - int posterY = ((r.height() - posterHeight) / 2) + r.y(); - IntRect targetRect(posterX, posterY, posterWidth, posterHeight); - canvas->drawBitmapRect(*m_poster, 0, targetRect, 0); - } - - void onPosterFetched(SkBitmap* poster) - { - m_poster = poster; - if (m_naturalSizeUnknown) { - // We had to fake the size at startup, or else our paint - // method would not be called. If we haven't yet received - // the onPrepared event, update the intrinsic size to the size - // of the poster. That will be overriden when onPrepare comes. - // In case of an error, we should report the poster size, rather - // than our initial fake value. - m_naturalSize = IntSize(poster->width(), poster->height()); - m_player->sizeChanged(); - } - } - - void onPrepared(int duration, int width, int height) - { - m_duration = duration / 1000.0f; - m_naturalSize = IntSize(width, height); - m_naturalSizeUnknown = false; - m_player->durationChanged(); - m_player->sizeChanged(); - } - - virtual bool hasAudio() const { return false; } // do not display the audio UI - virtual bool hasVideo() const { return true; } - virtual bool supportsFullscreen() const { return true; } - - MediaPlayerVideoPrivate(MediaPlayer* player) : MediaPlayerPrivate(player) - { - JNIEnv* env = JSC::Bindings::getJNIEnv(); - if (!env) - return; - - jclass clazz = env->FindClass(g_ProxyJavaClass); - - if (!clazz) - return; - - m_glue = new JavaGlue; - m_glue->m_getInstance = env->GetStaticMethodID(clazz, "getInstance", "(Landroid/webkit/WebViewCore;I)Landroid/webkit/HTML5VideoViewProxy;"); - m_glue->m_loadPoster = env->GetMethodID(clazz, "loadPoster", "(Ljava/lang/String;)V"); - m_glue->m_play = env->GetMethodID(clazz, "play", "(Ljava/lang/String;II)V"); - - m_glue->m_teardown = env->GetMethodID(clazz, "teardown", "()V"); - m_glue->m_seek = env->GetMethodID(clazz, "seek", "(I)V"); - m_glue->m_pause = env->GetMethodID(clazz, "pause", "()V"); - m_glue->m_javaProxy = 0; - env->DeleteLocalRef(clazz); - // An exception is raised if any of the above fails. - checkException(env); - } - - void createJavaPlayerIfNeeded() - { - // Check if we have been already created. - if (m_glue->m_javaProxy) - return; - - JNIEnv* env = JSC::Bindings::getJNIEnv(); - if (!env) - return; - - jclass clazz = env->FindClass(g_ProxyJavaClass); - - if (!clazz) - return; - - jobject obj = 0; - - FrameView* frameView = m_player->frameView(); - if (!frameView) - return; - WebViewCore* webViewCore = WebViewCore::getWebViewCore(frameView); - ASSERT(webViewCore); - - // Get the HTML5VideoViewProxy instance - obj = env->CallStaticObjectMethod(clazz, m_glue->m_getInstance, webViewCore->getJavaObject().get(), this); - m_glue->m_javaProxy = env->NewGlobalRef(obj); - // Send the poster - jstring jUrl = 0; - if (m_posterUrl.length()) - jUrl = wtfStringToJstring(env, m_posterUrl); - // Sending a NULL jUrl allows the Java side to try to load the default poster. - env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_loadPoster, jUrl); - if (jUrl) - env->DeleteLocalRef(jUrl); - - // Clean up. - if (obj) - env->DeleteLocalRef(obj); - env->DeleteLocalRef(clazz); - checkException(env); - } - - float maxTimeSeekable() const - { - return m_duration; - } -}; - -class MediaPlayerAudioPrivate : public MediaPlayerPrivate { -public: - void load(const String& url) - { - m_url = url; - JNIEnv* env = JSC::Bindings::getJNIEnv(); - if (!env || !m_url.length()) - return; - - createJavaPlayerIfNeeded(); - - if (!m_glue->m_javaProxy) - return; - - jstring jUrl = wtfStringToJstring(env, m_url); - // start loading the data asynchronously - env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_setDataSource, jUrl); - env->DeleteLocalRef(jUrl); - checkException(env); - } - - void play() - { - JNIEnv* env = JSC::Bindings::getJNIEnv(); - if (!env || !m_url.length()) - return; - - createJavaPlayerIfNeeded(); - - if (!m_glue->m_javaProxy) - return; - - m_paused = false; - m_player->playbackStateChanged(); - env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_play); - checkException(env); - } - - virtual bool hasAudio() const { return true; } - virtual bool hasVideo() const { return false; } - virtual bool supportsFullscreen() const { return false; } - - float maxTimeSeekable() const - { - if (m_glue->m_javaProxy) { - JNIEnv* env = JSC::Bindings::getJNIEnv(); - if (env) { - float maxTime = env->CallFloatMethod(m_glue->m_javaProxy, - m_glue->m_getMaxTimeSeekable); - checkException(env); - return maxTime; - } - } - return 0; - } - - MediaPlayerAudioPrivate(MediaPlayer* player) : MediaPlayerPrivate(player) - { - JNIEnv* env = JSC::Bindings::getJNIEnv(); - if (!env) - return; - - jclass clazz = env->FindClass(g_ProxyJavaClassAudio); - - if (!clazz) - return; - - m_glue = new JavaGlue; - m_glue->m_newInstance = env->GetMethodID(clazz, "", "(I)V"); - m_glue->m_setDataSource = env->GetMethodID(clazz, "setDataSource", "(Ljava/lang/String;)V"); - m_glue->m_play = env->GetMethodID(clazz, "play", "()V"); - m_glue->m_getMaxTimeSeekable = env->GetMethodID(clazz, "getMaxTimeSeekable", "()F"); - m_glue->m_teardown = env->GetMethodID(clazz, "teardown", "()V"); - m_glue->m_seek = env->GetMethodID(clazz, "seek", "(I)V"); - m_glue->m_pause = env->GetMethodID(clazz, "pause", "()V"); - m_glue->m_javaProxy = 0; - env->DeleteLocalRef(clazz); - // An exception is raised if any of the above fails. - checkException(env); - } - - void createJavaPlayerIfNeeded() - { - // Check if we have been already created. - if (m_glue->m_javaProxy) - return; - - JNIEnv* env = JSC::Bindings::getJNIEnv(); - if (!env) - return; - - jclass clazz = env->FindClass(g_ProxyJavaClassAudio); - - if (!clazz) - return; - - jobject obj = 0; - - // Get the HTML5Audio instance - obj = env->NewObject(clazz, m_glue->m_newInstance, this); - m_glue->m_javaProxy = env->NewGlobalRef(obj); - - // Clean up. - if (obj) - env->DeleteLocalRef(obj); - env->DeleteLocalRef(clazz); - checkException(env); - } - - void onPrepared(int duration, int width, int height) - { - // Android media player gives us a duration of 0 for a live - // stream, so in that case set the real duration to infinity. - // We'll still be able to handle the case that we genuinely - // get an audio clip with a duration of 0s as we'll get the - // ended event when it stops playing. - if (duration > 0) { - m_duration = duration / 1000.0f; - } else { - m_duration = std::numeric_limits::infinity(); - } - m_player->durationChanged(); - m_player->sizeChanged(); - m_player->prepareToPlay(); - } -}; - -MediaPlayerPrivateInterface* MediaPlayerPrivate::create(MediaPlayer* player) -{ - if (player->mediaElementType() == MediaPlayer::Video) - return new MediaPlayerVideoPrivate(player); - return new MediaPlayerAudioPrivate(player); -} - -} - -namespace android { - -static void OnPrepared(JNIEnv* env, jobject obj, int duration, int width, int height, int pointer) -{ - if (pointer) { - WebCore::MediaPlayerPrivate* player = reinterpret_cast(pointer); - player->onPrepared(duration, width, height); - } -} - -static void OnEnded(JNIEnv* env, jobject obj, int pointer) -{ - if (pointer) { - WebCore::MediaPlayerPrivate* player = reinterpret_cast(pointer); - player->onEnded(); - } -} - -static void OnPaused(JNIEnv* env, jobject obj, int pointer) -{ - if (pointer) { - WebCore::MediaPlayerPrivate* player = reinterpret_cast(pointer); - player->onPaused(); - } -} - -static void OnPosterFetched(JNIEnv* env, jobject obj, jobject poster, int pointer) -{ - if (!pointer || !poster) - return; - - WebCore::MediaPlayerPrivate* player = reinterpret_cast(pointer); - SkBitmap* posterNative = GraphicsJNI::getNativeBitmap(env, poster); - if (!posterNative) - return; - player->onPosterFetched(posterNative); -} - -static void OnBuffering(JNIEnv* env, jobject obj, int percent, int pointer) -{ - if (pointer) { - WebCore::MediaPlayerPrivate* player = reinterpret_cast(pointer); - // TODO: player->onBuffering(percent); - } -} - -static void OnTimeupdate(JNIEnv* env, jobject obj, int position, int pointer) -{ - if (pointer) { - WebCore::MediaPlayerPrivate* player = reinterpret_cast(pointer); - player->onTimeupdate(position); - } -} - -// 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 -// video layers on the UI thread. Therefore, on the UI thread, we have to use -// the videoLayerId from Java side to find the exact video layer in the tree -// to set the surface texture. -// Every time a play call into Java side, the videoLayerId will be sent and -// saved in Java side. Then every time setBaseLayer call, the saved -// videoLayerId will be passed to this function to find the Video Layer. -// Return value: true when the video layer is found. -static bool SendSurfaceTexture(JNIEnv* env, jobject obj, jobject surfTex, - int baseLayer, int videoLayerId, - int textureName, int playerState) { - if (!surfTex) - return false; - - sp texture = android::SurfaceTexture_getSurfaceTexture(env, surfTex); - if (!texture.get()) - return false; - - BaseLayerAndroid* layerImpl = reinterpret_cast(baseLayer); - if (!layerImpl) - return false; - if (!layerImpl->countChildren()) - return false; - LayerAndroid* compositedRoot = static_cast(layerImpl->getChild(0)); - if (!compositedRoot) - return false; - - VideoLayerAndroid* videoLayer = - static_cast(compositedRoot->findById(videoLayerId)); - if (!videoLayer) - return false; - - // Set the SurfaceTexture to the layer we found - videoLayer->setSurfaceTexture(texture, textureName, static_cast(playerState)); - return true; -} - -static void OnStopFullscreen(JNIEnv* env, jobject obj, int pointer) -{ - if (pointer) { - WebCore::MediaPlayerPrivate* player = - reinterpret_cast(pointer); - player->onStopFullscreen(); - } -} - -/* - * JNI registration - */ -static JNINativeMethod g_MediaPlayerMethods[] = { - { "nativeOnPrepared", "(IIII)V", - (void*) OnPrepared }, - { "nativeOnEnded", "(I)V", - (void*) OnEnded }, - { "nativeOnStopFullscreen", "(I)V", - (void*) OnStopFullscreen }, - { "nativeOnPaused", "(I)V", - (void*) OnPaused }, - { "nativeOnPosterFetched", "(Landroid/graphics/Bitmap;I)V", - (void*) OnPosterFetched }, - { "nativeSendSurfaceTexture", "(Landroid/graphics/SurfaceTexture;IIII)Z", - (void*) SendSurfaceTexture }, - { "nativeOnTimeupdate", "(II)V", - (void*) OnTimeupdate }, -}; - -static JNINativeMethod g_MediaAudioPlayerMethods[] = { - { "nativeOnBuffering", "(II)V", - (void*) OnBuffering }, - { "nativeOnEnded", "(I)V", - (void*) OnEnded }, - { "nativeOnPrepared", "(IIII)V", - (void*) OnPrepared }, - { "nativeOnTimeupdate", "(II)V", - (void*) OnTimeupdate }, -}; - -int registerMediaPlayerVideo(JNIEnv* env) -{ - return jniRegisterNativeMethods(env, g_ProxyJavaClass, - g_MediaPlayerMethods, NELEM(g_MediaPlayerMethods)); -} - -int registerMediaPlayerAudio(JNIEnv* env) -{ - return jniRegisterNativeMethods(env, g_ProxyJavaClassAudio, - g_MediaAudioPlayerMethods, NELEM(g_MediaAudioPlayerMethods)); -} - -} -#endif // VIDEO diff --git a/WebKit/android/WebCoreSupport/MemoryUsage.cpp b/WebKit/android/WebCoreSupport/MemoryUsage.cpp deleted file mode 100644 index 32cdebf..0000000 --- a/WebKit/android/WebCoreSupport/MemoryUsage.cpp +++ /dev/null @@ -1,81 +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 "MemoryUsage.h" - -#include -#include - -#if USE(V8) -#include -#endif // USE(V8) - -using namespace WTF; - -class MemoryUsageCache { -public: - MemoryUsageCache() - : m_cachedMemoryUsage(0) - , m_cacheTime(0) - { - } - - int getCachedMemoryUsage(bool forceFresh); - -private: - unsigned m_cachedMemoryUsage; - double m_cacheTime; - static const int CACHE_VALIDITY_MS = 2000; -}; - -int MemoryUsageCache::getCachedMemoryUsage(bool forceFresh) -{ - if (!forceFresh && currentTimeMS() <= m_cacheTime + CACHE_VALIDITY_MS) - return m_cachedMemoryUsage; - - 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; -} - -int MemoryUsage::memoryUsageMb(bool forceFresh) -{ - static MemoryUsageCache cache; - return cache.getCachedMemoryUsage(forceFresh); -} - -int MemoryUsage::m_lowMemoryUsageMb = 0; -int MemoryUsage::m_highMemoryUsageMb = 0; -int MemoryUsage::m_highUsageDeltaMb = 0; diff --git a/WebKit/android/WebCoreSupport/MemoryUsage.h b/WebKit/android/WebCoreSupport/MemoryUsage.h deleted file mode 100644 index 2a3d7ed..0000000 --- a/WebKit/android/WebCoreSupport/MemoryUsage.h +++ /dev/null @@ -1,45 +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 MemoryUsage_h -#define MemoryUsage_h - -class MemoryUsage { -public: - static int memoryUsageMb(bool forceFresh); - static int lowMemoryUsageMb() { return m_lowMemoryUsageMb; } - static int highMemoryUsageMb() { return m_highMemoryUsageMb; } - static int highUsageDeltaMb() { return m_highUsageDeltaMb; } - static void setHighMemoryUsageMb(int highMemoryUsageMb) { m_highMemoryUsageMb = highMemoryUsageMb; } - static void setLowMemoryUsageMb(int lowMemoryUsageMb) { m_lowMemoryUsageMb = lowMemoryUsageMb; } - static void setHighUsageDeltaMb(int highUsageDeltaMb) { m_highUsageDeltaMb = highUsageDeltaMb; } - -private: - static int m_lowMemoryUsageMb; - static int m_highMemoryUsageMb; - static int m_highUsageDeltaMb; -}; - -#endif diff --git a/WebKit/android/WebCoreSupport/PlatformBridge.cpp b/WebKit/android/WebCoreSupport/PlatformBridge.cpp deleted file mode 100644 index 8d8d809..0000000 --- a/WebKit/android/WebCoreSupport/PlatformBridge.cpp +++ /dev/null @@ -1,261 +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 "config.h" -#include - -#include "CookieClient.h" -#include "Document.h" -#include "FileSystemClient.h" -#include "FrameView.h" -#include "JavaSharedClient.h" -#include "KeyGeneratorClient.h" -#include "MemoryUsage.h" -#include "PluginView.h" -#include "Settings.h" -#include "WebCookieJar.h" -#include "WebRequestContext.h" -#include "WebViewCore.h" -#include "npruntime.h" - -#include -#include -#include -#include -#include - -using namespace android; - -namespace WebCore { - -WTF::Vector PlatformBridge::getSupportedKeyStrengthList() -{ - KeyGeneratorClient* client = JavaSharedClient::GetKeyGeneratorClient(); - if (!client) - return WTF::Vector(); - - return client->getSupportedKeyStrengthList(); -} - -String PlatformBridge::getSignedPublicKeyAndChallengeString(unsigned index, const String& challenge, const KURL& url) -{ - KeyGeneratorClient* client = JavaSharedClient::GetKeyGeneratorClient(); - if (!client) - return String(); - - return client->getSignedPublicKeyAndChallengeString(index, challenge, url); -} - -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(widget); - return pluginView->getNPObject(); -#else - return 0; -#endif -} - -bool PlatformBridge::isWebViewPaused(const WebCore::FrameView* frameView) -{ - android::WebViewCore* webViewCore = android::WebViewCore::getWebViewCore(frameView); - return webViewCore->isPaused(); -} - -bool PlatformBridge::popupsAllowed(NPP) -{ - return false; -} - -String PlatformBridge::resolveFilePathForContentUri(const String& contentUri) -{ - FileSystemClient* client = JavaSharedClient::GetFileSystemClient(); - return client->resolveFilePathForContentUri(contentUri); -} - -int PlatformBridge::PlatformBridge::screenDepth() -{ - android::DisplayInfo info; - android::SurfaceComposerClient::getDisplayInfo(android::DisplayID(0), &info); - return info.pixelFormatInfo.bitsPerPixel; -} - -FloatRect PlatformBridge::screenRect() -{ - android::DisplayInfo info; - android::SurfaceComposerClient::getDisplayInfo(android::DisplayID(0), &info); - return FloatRect(0.0, 0.0, info.w, info.h); -} - -// The visible size on screen in document coordinate -int PlatformBridge::screenWidthInDocCoord(const WebCore::FrameView* frameView) -{ - android::WebViewCore* webViewCore = android::WebViewCore::getWebViewCore(frameView); - return webViewCore->screenWidth(); -} - -int PlatformBridge::screenHeightInDocCoord(const WebCore::FrameView* frameView) -{ - android::WebViewCore* webViewCore = android::WebViewCore::getWebViewCore(frameView); - return webViewCore->screenHeight(); -} - -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) -{ - android::WebViewCore* webViewCore = android::WebViewCore::getWebViewCore(frameView); - webViewCore->updateViewport(); -} - -void PlatformBridge::updateTextfield(FrameView* frameView, Node* nodePtr, bool changeToPassword, const WTF::String& text) -{ - android::WebViewCore* webViewCore = android::WebViewCore::getWebViewCore(frameView); - webViewCore->updateTextfield(nodePtr, changeToPassword, text); -} - -void PlatformBridge::setScrollPosition(ScrollView* scrollView, int x, int y) { - // Check to make sure the view is the main FrameView. - android::WebViewCore *webViewCore = android::WebViewCore::getWebViewCore(scrollView); - if (webViewCore->mainFrame()->view() == scrollView) - webViewCore->scrollTo(x, y); -} - -int PlatformBridge::lowMemoryUsageMB() -{ - return MemoryUsage::lowMemoryUsageMb(); -} - -int PlatformBridge::highMemoryUsageMB() -{ - return MemoryUsage::highMemoryUsageMb(); -} - -int PlatformBridge::highUsageDeltaMB() -{ - return MemoryUsage::highUsageDeltaMb(); -} - -int PlatformBridge::memoryUsageMB() -{ - return MemoryUsage::memoryUsageMb(false); -} - -int PlatformBridge::actualMemoryUsageMB() -{ - return MemoryUsage::memoryUsageMb(true); -} - -} // namespace WebCore - - -// This is the implementation of AndroidThreading, which is declared in -// JavaScriptCore/wtf/android/AndroidThreading.h. It is provided here, rather -// than in its own source file, to avoid linker problems. -// -// By default, when building a shared library, the linker strips from static -// libraries any compilation units which do not contain any code referenced from -// that static library. Since -// AndroidThreading::scheduleDispatchFunctionsOnMainThread is not referenced -// from libwebcore.a, implementing it in its own compilation unit results in it -// being stripped. This stripping can be avoided by using the linker option -// --whole-archive for libwebcore.a, but this adds considerably to the size of -// libwebcore.so. - -namespace WTF { - -// Callback in the main thread. -static void timeoutFired(void*) -{ - dispatchFunctionsFromMainThread(); -} - -void AndroidThreading::scheduleDispatchFunctionsOnMainThread() -{ - JavaSharedClient::EnqueueFunctionPtr(timeoutFired, 0); -} - -} // namespace WTF diff --git a/WebKit/android/WebCoreSupport/ResourceLoaderAndroid.cpp b/WebKit/android/WebCoreSupport/ResourceLoaderAndroid.cpp deleted file mode 100644 index 7f54810..0000000 --- a/WebKit/android/WebCoreSupport/ResourceLoaderAndroid.cpp +++ /dev/null @@ -1,71 +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 -#include - -#include "Frame.h" -#include "FrameLoaderClientAndroid.h" -#include "WebCoreFrameBridge.h" -#include "WebCoreResourceLoader.h" -#include "WebUrlLoader.h" -#include "WebViewCore.h" - -using namespace android; - -namespace WebCore { - -PassRefPtr ResourceLoaderAndroid::start( - ResourceHandle* handle, const ResourceRequest& request, FrameLoaderClient* client, bool isMainResource, bool isSync) -{ - // Called on main thread - FrameLoaderClientAndroid* clientAndroid = static_cast(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 - // out the cache entry by the time we fetch it. - // - // So, we always say yes here, to prevent the FrameLoader from initiating a - // 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/WebKit/android/WebCoreSupport/UrlInterceptResponse.cpp b/WebKit/android/WebCoreSupport/UrlInterceptResponse.cpp deleted file mode 100644 index 3779ba8..0000000 --- a/WebKit/android/WebCoreSupport/UrlInterceptResponse.cpp +++ /dev/null @@ -1,130 +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. - */ - -#define LOG_TAG "UrlInterceptResponse" -#include "config.h" - -#include "JNIUtility.h" -#include "UrlInterceptResponse.h" -#include "WebCoreJni.h" - -#include - -namespace android { - -class JavaInputStreamWrapper { -public: - JavaInputStreamWrapper(JNIEnv* env, jobject inputStream) - : m_inputStream(env->NewGlobalRef(inputStream)) - , m_buffer(0) { - LOG_ALWAYS_FATAL_IF(!inputStream); - jclass inputStreamClass = env->FindClass("java/io/InputStream"); - LOG_ALWAYS_FATAL_IF(!inputStreamClass); - m_read = env->GetMethodID(inputStreamClass, "read", "([B)I"); - LOG_ALWAYS_FATAL_IF(!m_read); - m_close = env->GetMethodID(inputStreamClass, "close", "()V"); - LOG_ALWAYS_FATAL_IF(!m_close); - } - - ~JavaInputStreamWrapper() { - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_inputStream, m_close); - checkException(env); - env->DeleteGlobalRef(m_inputStream); - // In case we never call read(). - if (m_buffer) - env->DeleteGlobalRef(m_buffer); - } - - void read(std::vector* out) { - JNIEnv* env = JSC::Bindings::getJNIEnv(); - // Initialize our read buffer to the capacity of out. - if (!m_buffer) { - m_buffer = env->NewByteArray(out->capacity()); - m_buffer = (jbyteArray) env->NewGlobalRef(m_buffer); - } - int size = (int) env->CallIntMethod(m_inputStream, m_read, m_buffer); - if (checkException(env) || size < 0) - return; - // Copy from m_buffer to out. - out->resize(size); - env->GetByteArrayRegion(m_buffer, 0, size, (jbyte*)&out->front()); - } - -private: - jobject m_inputStream; - jbyteArray m_buffer; - jmethodID m_read; - jmethodID m_close; -}; - -UrlInterceptResponse::UrlInterceptResponse(JNIEnv* env, jobject response) { - jclass javaResponse = env->FindClass("android/webkit/WebResourceResponse"); - LOG_ALWAYS_FATAL_IF(!javaResponse); - jfieldID mimeType = env->GetFieldID(javaResponse, "mMimeType", - "Ljava/lang/String;"); - LOG_ALWAYS_FATAL_IF(!mimeType); - jfieldID encoding = env->GetFieldID(javaResponse, "mEncoding", - "Ljava/lang/String;"); - LOG_ALWAYS_FATAL_IF(!encoding); - jfieldID inputStream = env->GetFieldID(javaResponse, "mInputStream", - "Ljava/io/InputStream;"); - LOG_ALWAYS_FATAL_IF(!inputStream); - - jobject stream = env->GetObjectField(response, inputStream); - if (stream) - m_inputStream.set(new JavaInputStreamWrapper(env, stream)); - - jstring mimeStr = (jstring) env->GetObjectField(response, mimeType); - jstring encodingStr = (jstring) env->GetObjectField(response, encoding); - - if (mimeStr) { - const char* s = env->GetStringUTFChars(mimeStr, NULL); - m_mimeType.assign(s, env->GetStringUTFLength(mimeStr)); - env->ReleaseStringUTFChars(mimeStr, s); - } - if (encodingStr) { - const char* s = env->GetStringUTFChars(encodingStr, NULL); - m_encoding.assign(s, env->GetStringUTFLength(encodingStr)); - env->ReleaseStringUTFChars(encodingStr, s); - } - - env->DeleteLocalRef(javaResponse); - env->DeleteLocalRef(mimeStr); - env->DeleteLocalRef(encodingStr); -} - -UrlInterceptResponse::~UrlInterceptResponse() { - // Cannot be inlined because of JavaInputStreamWrapper visibility. -} - -bool UrlInterceptResponse::readStream(std::vector* out) const { - if (!m_inputStream) - return false; - m_inputStream->read(out); - return true; -} - -} // namespace android diff --git a/WebKit/android/WebCoreSupport/UrlInterceptResponse.h b/WebKit/android/WebCoreSupport/UrlInterceptResponse.h deleted file mode 100644 index 64dad69..0000000 --- a/WebKit/android/WebCoreSupport/UrlInterceptResponse.h +++ /dev/null @@ -1,70 +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 UrlInterceptResponse_h -#define UrlInterceptResponse_h - -#include "PlatformString.h" -#include "wtf/Noncopyable.h" -#include "wtf/OwnPtr.h" - -#include -#include -#include - -namespace android { - -class JavaInputStreamWrapper; - -class UrlInterceptResponse : public Noncopyable { -public: - UrlInterceptResponse(JNIEnv* env, jobject response); - ~UrlInterceptResponse(); - - const std::string& mimeType() const { - return m_mimeType; - } - - const std::string& encoding() const { - return m_encoding; - } - - int status() const { - return m_inputStream ? 200 : 404; - } - - // Read from the input stream. Returns false if reading failed. - // A size of 0 indicates eof. - bool readStream(std::vector* out) const; - -private: - std::string m_mimeType; - std::string m_encoding; - OwnPtr m_inputStream; -}; - -} // namespace android - -#endif diff --git a/WebKit/android/WebCoreSupport/V8Counters.cpp b/WebKit/android/WebCoreSupport/V8Counters.cpp deleted file mode 100644 index d164f9a..0000000 --- a/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 -#include -#include - -#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 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(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::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/WebKit/android/WebCoreSupport/V8Counters.h b/WebKit/android/WebCoreSupport/V8Counters.h deleted file mode 100644 index 499b856..0000000 --- a/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 -#include -#include - -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 m_counters; -}; - -} - -#endif // ANDROID_INSTRUMENT -#endif // USE(V8) -#endif // V8Counters_h diff --git a/WebKit/android/WebCoreSupport/WebCache.cpp b/WebKit/android/WebCoreSupport/WebCache.cpp deleted file mode 100644 index be9a700..0000000 --- a/WebKit/android/WebCoreSupport/WebCache.cpp +++ /dev/null @@ -1,237 +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 "WebCache.h" - -#include "JNIUtility.h" -#include "WebCoreJni.h" -#include "WebRequestContext.h" -#include "WebUrlLoaderClient.h" - -#include - -using namespace WTF; -using namespace disk_cache; -using namespace net; -using namespace std; - -namespace android { - -static WTF::Mutex instanceMutex; - -static const string& rootDirectory() -{ - // This method may be called on any thread, as the Java method is - // synchronized. - static WTF::Mutex mutex; - MutexLocker lock(mutex); - static string cacheDirectory; - if (cacheDirectory.empty()) { - JNIEnv* env = JSC::Bindings::getJNIEnv(); - jclass bridgeClass = env->FindClass("android/webkit/JniUtil"); - jmethodID method = env->GetStaticMethodID(bridgeClass, "getCacheDirectory", "()Ljava/lang/String;"); - cacheDirectory = jstringToStdString(env, static_cast(env->CallStaticObjectMethod(bridgeClass, method))); - env->DeleteLocalRef(bridgeClass); - } - return cacheDirectory; -} - -static string storageDirectory() -{ - // Private cache is currently in memory only - static const char* const kDirectory = "/webviewCacheChromium"; - string storageDirectory = rootDirectory(); - storageDirectory.append(kDirectory); - return storageDirectory; -} - -static scoped_refptr* instance(bool isPrivateBrowsing) -{ - static scoped_refptr regularInstance; - static scoped_refptr privateInstance; - return isPrivateBrowsing ? &privateInstance : ®ularInstance; -} - -WebCache* WebCache::get(bool isPrivateBrowsing) -{ - MutexLocker lock(instanceMutex); - scoped_refptr* instancePtr = instance(isPrivateBrowsing); - if (!instancePtr->get()) - *instancePtr = new WebCache(isPrivateBrowsing); - return instancePtr->get(); -} - -void WebCache::cleanup(bool isPrivateBrowsing) -{ - MutexLocker lock(instanceMutex); - scoped_refptr* instancePtr = instance(isPrivateBrowsing); - *instancePtr = 0; -} - -WebCache::WebCache(bool isPrivateBrowsing) - : m_doomAllEntriesCallback(this, &WebCache::doomAllEntries) - , m_onClearDoneCallback(this, &WebCache::onClearDone) - , m_isClearInProgress(false) - , m_openEntryCallback(this, &WebCache::openEntry) - , m_onGetEntryDoneCallback(this, &WebCache::onGetEntryDone) - , m_isGetEntryInProgress(false) - , m_cacheBackend(0) -{ - base::Thread* ioThread = WebUrlLoaderClient::ioThread(); - scoped_refptr cacheMessageLoopProxy = ioThread->message_loop_proxy(); - - static const int kMaximumCacheSizeBytes = 20 * 1024 * 1024; - m_hostResolver = net::CreateSystemHostResolver(net::HostResolver::kDefaultParallelism, 0, 0); - - m_proxyConfigService = new ProxyConfigServiceAndroid(); - net::HttpCache::BackendFactory* backendFactory; - if (isPrivateBrowsing) - backendFactory = net::HttpCache::DefaultBackend::InMemory(kMaximumCacheSizeBytes / 2); - else { - FilePath directoryPath(storageDirectory().c_str()); - backendFactory = new net::HttpCache::DefaultBackend(net::DISK_CACHE, directoryPath, kMaximumCacheSizeBytes, cacheMessageLoopProxy); - } - - m_cache = new net::HttpCache(m_hostResolver.get(), - 0, // dnsrr_resolver - 0, // dns_cert_checker - net::ProxyService::CreateWithoutProxyResolver(m_proxyConfigService, 0 /* net_log */), - net::SSLConfigService::CreateSystemSSLConfigService(), - net::HttpAuthHandlerFactory::CreateDefault(m_hostResolver.get()), - 0, // network_delegate - 0, // net_log - backendFactory); -} - -void WebCache::clear() -{ - base::Thread* thread = WebUrlLoaderClient::ioThread(); - if (thread) - thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this, &WebCache::clearImpl)); -} - -void WebCache::clearImpl() -{ - if (m_isClearInProgress) - return; - m_isClearInProgress = true; - - if (!m_cacheBackend) { - int code = m_cache->GetBackend(&m_cacheBackend, &m_doomAllEntriesCallback); - // Code ERR_IO_PENDING indicates that the operation is still in progress and - // the supplied callback will be invoked when it completes. - if (code == ERR_IO_PENDING) - return; - else if (code != OK) { - onClearDone(0 /*unused*/); - return; - } - } - doomAllEntries(0 /*unused*/); -} - -void WebCache::doomAllEntries(int) -{ - if (!m_cacheBackend) { - onClearDone(0 /*unused*/); - return; - } - - // Code ERR_IO_PENDING indicates that the operation is still in progress and - // the supplied callback will be invoked when it completes. - if (m_cacheBackend->DoomAllEntries(&m_onClearDoneCallback) == ERR_IO_PENDING) - return; - onClearDone(0 /*unused*/); -} - -void WebCache::onClearDone(int) -{ - m_isClearInProgress = false; -} - -scoped_refptr WebCache::getCacheResult(String url) -{ - // This is called on the UI thread. - MutexLocker lock(m_getEntryMutex); - if (m_isGetEntryInProgress) - return 0; // TODO: OK? Or can we queue 'em up? - - // The Chromium methods are asynchronous, but we need this method to be - // synchronous. Do the work on the Chromium thread but block this thread - // here waiting for the work to complete. - base::Thread* thread = WebUrlLoaderClient::ioThread(); - if (!thread) - return 0; - - m_entry = 0; - m_isGetEntryInProgress = true; - m_entryUrl = url.threadsafeCopy(); - thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this, &WebCache::getEntryImpl)); - - while (m_isGetEntryInProgress) - m_getEntryCondition.wait(m_getEntryMutex); - - if (!m_entry) - return 0; - - return new CacheResult(m_entry, url); -} - -void WebCache::getEntryImpl() -{ - if (!m_cacheBackend) { - int code = m_cache->GetBackend(&m_cacheBackend, &m_openEntryCallback); - if (code == ERR_IO_PENDING) - return; - else if (code != OK) { - onGetEntryDone(0 /*unused*/); - return; - } - } - openEntry(0 /*unused*/); -} - -void WebCache::openEntry(int) -{ - if (!m_cacheBackend) { - onGetEntryDone(0 /*unused*/); - return; - } - - if (m_cacheBackend->OpenEntry(string(m_entryUrl.utf8().data()), &m_entry, &m_onGetEntryDoneCallback) == ERR_IO_PENDING) - return; - onGetEntryDone(0 /*unused*/); -} - -void WebCache::onGetEntryDone(int) -{ - // Unblock the UI thread in getEntry(); - MutexLocker lock(m_getEntryMutex); - m_isGetEntryInProgress = false; - m_getEntryCondition.signal(); -} - -} // namespace android diff --git a/WebKit/android/WebCoreSupport/WebCache.h b/WebKit/android/WebCoreSupport/WebCache.h deleted file mode 100644 index 7149fcc..0000000 --- a/WebKit/android/WebCoreSupport/WebCache.h +++ /dev/null @@ -1,88 +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 WebCache_h -#define WebCache_h - -#include "CacheResult.h" -#include "ChromiumIncludes.h" - -#include -#include -#include - -namespace android { - -// This class is not generally threadsafe. However, get() and cleanup() are -// threadsafe. -class WebCache : public base::RefCountedThreadSafe { -public: - static WebCache* get(bool isPrivateBrowsing); - static void cleanup(bool isPrivateBrowsing); - - void clear(); - scoped_refptr getCacheResult(WTF::String url); - net::HostResolver* hostResolver() { return m_hostResolver.get(); } - net::HttpCache* cache() { return m_cache.get(); } - net::ProxyConfigServiceAndroid* proxy() { return m_proxyConfigService; } - -private: - WebCache(bool isPrivateBrowsing); - - // For clear() - void clearImpl(); - void doomAllEntries(int); - void onClearDone(int); - - // For getEntry() - void getEntryImpl(); - void openEntry(int); - void onGetEntryDone(int); - - OwnPtr m_hostResolver; - OwnPtr m_cache; - // This is owned by the ProxyService, which is owned by the HttpNetworkLayer, - // which is owned by the HttpCache, which is owned by this class. - net::ProxyConfigServiceAndroid* m_proxyConfigService; - - // For clear() - net::CompletionCallbackImpl m_doomAllEntriesCallback; - net::CompletionCallbackImpl m_onClearDoneCallback; - bool m_isClearInProgress; - // For getEntry() - net::CompletionCallbackImpl m_openEntryCallback; - net::CompletionCallbackImpl m_onGetEntryDoneCallback; - bool m_isGetEntryInProgress; - String m_entryUrl; - disk_cache::Entry* m_entry; - WTF::Mutex m_getEntryMutex; - WTF::ThreadCondition m_getEntryCondition; - - disk_cache::Backend* m_cacheBackend; -}; - -} // namespace android - -#endif diff --git a/WebKit/android/WebCoreSupport/WebCookieJar.cpp b/WebKit/android/WebCoreSupport/WebCookieJar.cpp deleted file mode 100644 index 99de67e..0000000 --- a/WebKit/android/WebCoreSupport/WebCookieJar.cpp +++ /dev/null @@ -1,263 +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 "WebCookieJar.h" - -#include "JNIUtility.h" -#include "WebCoreJni.h" -#include "WebRequestContext.h" -#include "WebUrlLoaderClient.h" - -#include -#include - -#undef ASSERT -#define ASSERT(assertion, ...) do \ - if (!(assertion)) { \ - android_printLog(ANDROID_LOG_ERROR, __FILE__, __VA_ARGS__); \ - } \ -while (0) - -namespace android { - -static WTF::Mutex instanceMutex; -static bool isFirstInstanceCreated = false; -static bool fileSchemeCookiesEnabled = false; - -static const std::string& databaseDirectory() -{ - // This method may be called on any thread, as the Java method is - // synchronized. - static WTF::Mutex databaseDirectoryMutex; - MutexLocker lock(databaseDirectoryMutex); - static std::string databaseDirectory; - if (databaseDirectory.empty()) { - JNIEnv* env = JSC::Bindings::getJNIEnv(); - jclass bridgeClass = env->FindClass("android/webkit/JniUtil"); - jmethodID method = env->GetStaticMethodID(bridgeClass, "getDatabaseDirectory", "()Ljava/lang/String;"); - databaseDirectory = jstringToStdString(env, static_cast(env->CallStaticObjectMethod(bridgeClass, method))); - env->DeleteLocalRef(bridgeClass); - } - return databaseDirectory; -} - -static void removeFileOrDirectory(const char* filename) -{ - struct stat filetype; - if (stat(filename, &filetype) != 0) - return; - if (S_ISDIR(filetype.st_mode)) { - DIR* directory = opendir(filename); - if (directory) { - while (struct dirent* entry = readdir(directory)) { - if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) - continue; - std::string entryName(filename); - entryName.append("/"); - entryName.append(entry->d_name); - removeFileOrDirectory(entryName.c_str()); - } - closedir(directory); - rmdir(filename); - } - return; - } - unlink(filename); -} - -static std::string databaseDirectory(bool isPrivateBrowsing) -{ - static const char* const kDatabaseFilename = "/webviewCookiesChromium.db"; - static const char* const kDatabaseFilenamePrivateBrowsing = "/webviewCookiesChromiumPrivate.db"; - - std::string databaseFilePath = databaseDirectory(); - databaseFilePath.append(isPrivateBrowsing ? kDatabaseFilenamePrivateBrowsing : kDatabaseFilename); - return databaseFilePath; -} - -scoped_refptr* instance(bool isPrivateBrowsing) -{ - static scoped_refptr regularInstance; - static scoped_refptr privateInstance; - return isPrivateBrowsing ? &privateInstance : ®ularInstance; -} - -WebCookieJar* WebCookieJar::get(bool isPrivateBrowsing) -{ - MutexLocker lock(instanceMutex); - if (!isFirstInstanceCreated && fileSchemeCookiesEnabled) - net::CookieMonster::EnableFileScheme(); - isFirstInstanceCreated = true; - scoped_refptr* instancePtr = instance(isPrivateBrowsing); - if (!instancePtr->get()) - *instancePtr = new WebCookieJar(databaseDirectory(isPrivateBrowsing)); - return instancePtr->get(); -} - -void WebCookieJar::cleanup(bool isPrivateBrowsing) -{ - // This is called on the UI thread. - MutexLocker lock(instanceMutex); - scoped_refptr* instancePtr = instance(isPrivateBrowsing); - *instancePtr = 0; - removeFileOrDirectory(databaseDirectory(isPrivateBrowsing).c_str()); -} - -WebCookieJar::WebCookieJar(const std::string& databaseFilePath) - : m_allowCookies(true) -{ - // Setup the permissions for the file - const char* cDatabasePath = databaseFilePath.c_str(); - mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP; - if (access(cDatabasePath, F_OK) == 0) - chmod(cDatabasePath, mode); - else { - int fd = open(cDatabasePath, O_CREAT, mode); - if (fd >= 0) - close(fd); - } - - FilePath cookiePath(databaseFilePath.c_str()); - m_cookieDb = new SQLitePersistentCookieStore(cookiePath); - m_cookieStore = new net::CookieMonster(m_cookieDb.get(), 0); -} - -bool WebCookieJar::allowCookies() -{ - MutexLocker lock(m_allowCookiesMutex); - return m_allowCookies; -} - -void WebCookieJar::setAllowCookies(bool allow) -{ - MutexLocker lock(m_allowCookiesMutex); - 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&, net::CompletionCallback*) -{ - MutexLocker lock(m_allowCookiesMutex); - return m_allowCookies ? net::OK : net::ERR_ACCESS_DENIED; -} - -// From CookiePolicy in chromium -int WebCookieJar::CanSetCookie(const GURL&, const GURL&, const std::string&, net::CompletionCallback*) -{ - MutexLocker lock(m_allowCookiesMutex); - return m_allowCookies ? net::OK : net::ERR_ACCESS_DENIED; -} - -class FlushSemaphore : public base::RefCounted -{ -public: - FlushSemaphore() - : m_condition(&m_lock) - , m_count(0) - {} - - void SendFlushRequest(net::CookieMonster* monster) { - // FlushStore() needs to run on a Chrome thread (because it will need - // to post the callback, and it may want to do so on its own thread.) - // We use the IO thread for this purpose. - // - // TODO(husky): Our threads are hidden away in various files. Clean this - // up and consider integrating with Chrome's browser_thread.h. Might be - // a better idea to use the DB thread here rather than the IO thread. - - base::Thread* ioThread = WebUrlLoaderClient::ioThread(); - if (ioThread) { - Task* callback = NewRunnableMethod(this, &FlushSemaphore::Callback); - ioThread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod( - monster, &net::CookieMonster::FlushStore, callback)); - } else { - Callback(); - } - } - - // Block until the given number of callbacks has been made. - void Wait(int numCallbacks) { - AutoLock al(m_lock); - int lastCount = m_count; - while (m_count < numCallbacks) { - // TODO(husky): Maybe use TimedWait() here? But it's not obvious what - // to do if the flush fails. Might be okay just to let the OS kill us. - m_condition.Wait(); - ASSERT(lastCount != m_count, "Wait finished without incrementing m_count %d %d", m_count, lastCount); - lastCount = m_count; - } - m_count -= numCallbacks; - } - -private: - friend class base::RefCounted; - - void Callback() { - AutoLock al(m_lock); - m_count++; - m_condition.Broadcast(); - } - - Lock m_lock; - ConditionVariable m_condition; - volatile int m_count; -}; - -void WebCookieJar::flush() -{ - // Flush both cookie stores (private and non-private), wait for 2 callbacks. - static scoped_refptr semaphore(new FlushSemaphore()); - semaphore->SendFlushRequest(get(false)->cookieStore()->GetCookieMonster()); - semaphore->SendFlushRequest(get(true)->cookieStore()->GetCookieMonster()); - semaphore->Wait(2); -} - -bool WebCookieJar::acceptFileSchemeCookies() -{ - MutexLocker lock(instanceMutex); - return fileSchemeCookiesEnabled; -} - -void WebCookieJar::setAcceptFileSchemeCookies(bool accept) -{ - // The Chromium HTTP stack only reflects changes to this flag when creating - // a new CookieMonster instance. While we could track whether any - // CookieMonster instances currently exist, this would be complicated and is - // not required, so we only allow this flag to be changed before the first - // instance is created. - MutexLocker lock(instanceMutex); - if (!isFirstInstanceCreated) - fileSchemeCookiesEnabled = accept; -} - -} diff --git a/WebKit/android/WebCoreSupport/WebCookieJar.h b/WebKit/android/WebCoreSupport/WebCookieJar.h deleted file mode 100644 index 1f4266c..0000000 --- a/WebKit/android/WebCoreSupport/WebCookieJar.h +++ /dev/null @@ -1,78 +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 WebCookieJar_h -#define WebCookieJar_h - -#include "ChromiumIncludes.h" - -#include - -namespace android { - -// This class is threadsafe. It is used from the IO, WebCore and Chromium IO -// threads. -class WebCookieJar : public net::CookiePolicy, public base::RefCountedThreadSafe { -public: - static WebCookieJar* get(bool isPrivateBrowsing); - static void cleanup(bool isPrivateBrowsing); - - // Flush all cookies to disk. Synchronous. - static void flush(); - - // CookiePolicy implementation from external/chromium - virtual int CanGetCookies(const GURL& url, const GURL& first_party_for_cookies, net::CompletionCallback*); - virtual int CanSetCookie(const GURL& url, const GURL& first_party_for_cookies, const std::string& cookie_line, net::CompletionCallback*); - - bool allowCookies(); - void setAllowCookies(bool allow); - - // Getter and setter for whether we accept cookies for file scheme URLS. - // Defaults to false. Note that calls to the setter are ignored once the - // first instance of this class has been created. - static bool acceptFileSchemeCookies(); - static void setAcceptFileSchemeCookies(bool); - - // 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::CookiePolicy* cookiePolicy() { return this; } - - // Get the number of cookies that have actually been saved to flash. - // (This is used to implement CookieManager.hasCookies() in the Java framework.) - int getNumCookiesInDatabase(); - -private: - WebCookieJar(const std::string& databaseFilePath); - - scoped_refptr m_cookieDb; - scoped_refptr m_cookieStore; - bool m_allowCookies; - WTF::Mutex m_allowCookiesMutex; -}; - -} - -#endif diff --git a/WebKit/android/WebCoreSupport/WebRequest.cpp b/WebKit/android/WebCoreSupport/WebRequest.cpp deleted file mode 100644 index a7321da..0000000 --- a/WebKit/android/WebCoreSupport/WebRequest.cpp +++ /dev/null @@ -1,531 +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 "WebRequest.h" - -#include "JNIUtility.h" -#include "MainThread.h" -#include "UrlInterceptResponse.h" -#include "WebCoreFrameBridge.h" -#include "WebRequestContext.h" -#include "WebResourceRequest.h" -#include "WebUrlLoaderClient.h" -#include "jni.h" - -#include -#include -#include - -extern android::AssetManager* globalAssetManager(); - -// TODO: -// - Finish the file upload. Testcase is mobile buzz -// - Add network throttle needed by Android plugins - -// TODO: Turn off asserts crashing before release -// http://b/issue?id=2951985 -#undef ASSERT -#define ASSERT(assertion, ...) do \ - if (!(assertion)) { \ - android_printLog(ANDROID_LOG_ERROR, __FILE__, __VA_ARGS__); \ - } \ -while (0) - -namespace android { - -namespace { - const int kInitialReadBufSize = 32768; -} - -WebRequest::WebRequest(WebUrlLoaderClient* loader, const WebResourceRequest& webResourceRequest) - : m_urlLoader(loader) - , m_androidUrl(false) - , m_url(webResourceRequest.url()) - , m_userAgent(webResourceRequest.userAgent()) - , m_loadState(Created) - , m_authRequestCount(0) - , m_cacheMode(0) - , m_runnableFactory(this) - , m_wantToPause(false) - , m_isPaused(false) - , m_isSync(false) -{ - GURL gurl(m_url); - - m_request = new URLRequest(gurl, this); - - m_request->SetExtraRequestHeaders(webResourceRequest.requestHeaders()); - m_request->set_referrer(webResourceRequest.referrer()); - m_request->set_method(webResourceRequest.method()); - m_request->set_load_flags(webResourceRequest.loadFlags()); -} - -// This is a special URL for Android. Query the Java InputStream -// for data and send to WebCore -WebRequest::WebRequest(WebUrlLoaderClient* loader, const WebResourceRequest& webResourceRequest, UrlInterceptResponse* intercept) - : m_urlLoader(loader) - , m_interceptResponse(intercept) - , m_androidUrl(true) - , m_url(webResourceRequest.url()) - , m_userAgent(webResourceRequest.userAgent()) - , m_loadState(Created) - , m_authRequestCount(0) - , m_cacheMode(0) - , m_runnableFactory(this) - , m_wantToPause(false) - , m_isPaused(false) - , m_isSync(false) -{ -} - -WebRequest::~WebRequest() -{ - ASSERT(m_loadState == Finished, "dtor called on a WebRequest in a different state than finished (%d)", m_loadState); - - m_loadState = Deleted; -} - -const std::string& WebRequest::getUrl() const -{ - return m_url; -} - -const std::string& WebRequest::getUserAgent() const -{ - return m_userAgent; -} - -#ifdef LOG_REQUESTS -namespace { -int remaining = 0; -} -#endif - -void WebRequest::finish(bool success) -{ - m_runnableFactory.RevokeAll(); - ASSERT(m_loadState < Finished, "(%p) called finish on an already finished WebRequest (%d) (%s)", this, m_loadState, m_url.c_str()); - if (m_loadState >= Finished) - return; -#ifdef LOG_REQUESTS - time_t finish; - time(&finish); - finish = finish - m_startTime; - struct tm * timeinfo; - char buffer[80]; - timeinfo = localtime(&finish); - strftime(buffer, 80, "Time: %M:%S",timeinfo); - android_printLog(ANDROID_LOG_DEBUG, "KM", "(%p) finish (%d) (%s) (%d) (%s)", this, --remaining, buffer, success, m_url.c_str()); -#endif - - // Make sure WebUrlLoaderClient doesn't delete us in the middle of this method. - scoped_refptr guard(this); - - m_loadState = Finished; - if (success) { - m_urlLoader->maybeCallOnMainThread(NewRunnableMethod( - m_urlLoader.get(), &WebUrlLoaderClient::didFinishLoading)); - } else { - if (m_interceptResponse == NULL) { - OwnPtr webResponse(new WebResponse(m_request.get())); - m_urlLoader->maybeCallOnMainThread(NewRunnableMethod( - m_urlLoader.get(), &WebUrlLoaderClient::didFail, webResponse.release())); - } else { - OwnPtr webResponse(new WebResponse(m_url, m_interceptResponse->mimeType(), 0, - m_interceptResponse->encoding(), m_interceptResponse->status())); - m_urlLoader->maybeCallOnMainThread(NewRunnableMethod( - m_urlLoader.get(), &WebUrlLoaderClient::didFail, webResponse.release())); - } - } - m_networkBuffer = 0; - m_request = 0; - m_urlLoader = 0; -} - -void WebRequest::appendFileToUpload(const std::string& filename) -{ - // AppendFileToUpload is only valid before calling start - ASSERT(m_loadState == Created, "appendFileToUpload called on a WebRequest not in CREATED state: (%s)", m_url.c_str()); - FilePath filePath(filename); - m_request->AppendFileToUpload(filePath); -} - -void WebRequest::appendBytesToUpload(WTF::Vector* data) -{ - // AppendBytesToUpload is only valid before calling start - ASSERT(m_loadState == Created, "appendBytesToUpload called on a WebRequest not in CREATED state: (%s)", m_url.c_str()); - m_request->AppendBytesToUpload(data->data(), data->size()); - delete data; -} - -void WebRequest::setRequestContext(WebRequestContext* context) -{ - m_cacheMode = context->getCacheMode(); - if (m_request) - m_request->set_context(context); -} - -void WebRequest::updateLoadFlags(int& loadFlags) -{ - if (m_cacheMode == 1) { // LOAD_CACHE_ELSE_NETWORK - loadFlags |= net::LOAD_PREFERRING_CACHE; - loadFlags &= ~net::LOAD_VALIDATE_CACHE; - } - if (m_cacheMode == 2) // LOAD_NO_CACHE - loadFlags |= net::LOAD_BYPASS_CACHE; - if (m_cacheMode == 3) // LOAD_CACHE_ONLY - loadFlags |= net::LOAD_ONLY_FROM_CACHE; - - if (m_isSync) - loadFlags |= net::LOAD_IGNORE_LIMITS; -} - -void WebRequest::start() -{ - ASSERT(m_loadState == Created, "Start called on a WebRequest not in CREATED state: (%s)", m_url.c_str()); -#ifdef LOG_REQUESTS - android_printLog(ANDROID_LOG_DEBUG, "KM", "(%p) start (%d) (%s)", this, ++remaining, m_url.c_str()); - time(&m_startTime); -#endif - - m_loadState = Started; - - if (m_interceptResponse != NULL) - return handleInterceptedURL(); - - // Handle data urls before we send it off to the http stack - if (m_request->url().SchemeIs("data")) - return handleDataURL(m_request->url()); - - if (m_request->url().SchemeIs("browser")) - return handleBrowserURL(m_request->url()); - - // Update load flags with settings from WebSettings - int loadFlags = m_request->load_flags(); - updateLoadFlags(loadFlags); - m_request->set_load_flags(loadFlags); - - m_request->Start(); -} - -void WebRequest::cancel() -{ - ASSERT(m_loadState >= Started, "Cancel called on a not started WebRequest: (%s)", m_url.c_str()); - ASSERT(m_loadState != Cancelled, "Cancel called on an already cancelled WebRequest: (%s)", m_url.c_str()); - - // There is a possible race condition between the IO thread finishing the request and - // the WebCore thread cancelling it. If the request has already finished, do - // nothing to avoid sending duplicate finish messages to WebCore. - if (m_loadState > Cancelled) { - return; - } - ASSERT(m_request, "Request set to 0 before it is finished"); - - m_loadState = Cancelled; - - m_request->Cancel(); - finish(true); -} - -void WebRequest::pauseLoad(bool pause) -{ - ASSERT(m_loadState >= GotData, "PauseLoad in state other than RESPONSE and GOTDATA"); - if (pause) { - if (!m_isPaused) - m_wantToPause = true; - } else { - m_wantToPause = false; - if (m_isPaused) { - m_isPaused = false; - MessageLoop::current()->PostTask(FROM_HERE, m_runnableFactory.NewRunnableMethod(&WebRequest::startReading)); - } - } -} - -void WebRequest::handleInterceptedURL() -{ - m_loadState = Response; - - const std::string& mime = m_interceptResponse->mimeType(); - // Get the MIME type from the URL. "text/html" is a last resort, hopefully overridden. - std::string mimeType("text/html"); - if (mime == "") { - // Gmail appends the MIME to the end of the URL, with a ? separator. - size_t mimeTypeIndex = m_url.find_last_of('?'); - if (mimeTypeIndex != std::string::npos) { - mimeType.assign(m_url.begin() + mimeTypeIndex + 1, m_url.end()); - } else { - // Get the MIME type from the file extension, if any. - FilePath path(m_url); - net::GetMimeTypeFromFile(path, &mimeType); - } - } else { - // Set from the intercept response. - mimeType = mime; - } - - - OwnPtr webResponse(new WebResponse(m_url, mimeType, 0, m_interceptResponse->encoding(), m_interceptResponse->status())); - m_urlLoader->maybeCallOnMainThread(NewRunnableMethod( - m_urlLoader.get(), &WebUrlLoaderClient::didReceiveResponse, webResponse.release())); - - do { - // data is deleted in WebUrlLoaderClient::didReceiveAndroidFileData - // data is sent to the webcore thread - OwnPtr > data(new std::vector); - data->reserve(kInitialReadBufSize); - - // Read returns false on error and size of 0 on eof. - if (!m_interceptResponse->readStream(data.get()) || data->size() == 0) - break; - - m_loadState = GotData; - m_urlLoader->maybeCallOnMainThread(NewRunnableMethod( - m_urlLoader.get(), &WebUrlLoaderClient::didReceiveAndroidFileData, data.release())); - } while (true); - - finish(m_interceptResponse->status() == 200); -} - -void WebRequest::handleDataURL(GURL url) -{ - OwnPtr data(new std::string); - std::string mimeType; - std::string charset; - - if (net::DataURL::Parse(url, &mimeType, &charset, data.get())) { - // PopulateURLResponse from chrome implementation - // weburlloader_impl.cc - m_loadState = Response; - OwnPtr webResponse(new WebResponse(url.spec(), mimeType, data->size(), charset, 200)); - m_urlLoader->maybeCallOnMainThread(NewRunnableMethod( - m_urlLoader.get(), &WebUrlLoaderClient::didReceiveResponse, webResponse.release())); - - if (!data->empty()) { - m_loadState = GotData; - m_urlLoader->maybeCallOnMainThread(NewRunnableMethod( - m_urlLoader.get(), &WebUrlLoaderClient::didReceiveDataUrl, data.release())); - } - } else { - // handle the failed case - } - - finish(true); -} - -void WebRequest::handleBrowserURL(GURL url) -{ - std::string data("data:text/html;charset=utf-8,"); - if (url.spec() == "browser:incognito") { - AssetManager* assetManager = globalAssetManager(); - Asset* asset = assetManager->open("webkit/incognito_mode_start_page.html", Asset::ACCESS_BUFFER); - if (asset) { - data.append((const char*)asset->getBuffer(false), asset->getLength()); - delete asset; - } - } - GURL dataURL(data.c_str()); - handleDataURL(dataURL); -} - -// Called upon a server-initiated redirect. The delegate may call the -// request's Cancel method to prevent the redirect from being followed. -// Since there may be multiple chained redirects, there may also be more -// than one redirect call. -// -// When this function is called, the request will still contain the -// original URL, the destination of the redirect is provided in 'new_url'. -// If the delegate does not cancel the request and |*defer_redirect| is -// false, then the redirect will be followed, and the request's URL will be -// changed to the new URL. Otherwise if the delegate does not cancel the -// request and |*defer_redirect| is true, then the redirect will be -// followed once FollowDeferredRedirect is called on the URLRequest. -// -// The caller must set |*defer_redirect| to false, so that delegates do not -// need to set it if they are happy with the default behavior of not -// deferring redirect. -void WebRequest::OnReceivedRedirect(URLRequest* newRequest, const GURL& newUrl, bool* deferRedirect) -{ - ASSERT(m_loadState < Response, "Redirect after receiving response"); - ASSERT(newRequest && newRequest->status().is_success(), "Invalid redirect"); - - OwnPtr webResponse(new WebResponse(newRequest)); - webResponse->setUrl(newUrl.spec()); - m_urlLoader->maybeCallOnMainThread(NewRunnableMethod( - m_urlLoader.get(), &WebUrlLoaderClient::willSendRequest, webResponse.release())); - - // Defer the redirect until followDeferredRedirect() is called. - *deferRedirect = true; -} - -// Called when we receive an authentication failure. The delegate should -// call request->SetAuth() with the user's credentials once it obtains them, -// or request->CancelAuth() to cancel the login and display the error page. -// When it does so, the request will be reissued, restarting the sequence -// of On* callbacks. -void WebRequest::OnAuthRequired(URLRequest* request, net::AuthChallengeInfo* authInfo) -{ - ASSERT(m_loadState == Started, "OnAuthRequired called on a WebRequest not in STARTED state (state=%d)", m_loadState); - - scoped_refptr authInfoPtr(authInfo); - bool firstTime = (m_authRequestCount == 0); - ++m_authRequestCount; - - m_urlLoader->maybeCallOnMainThread(NewRunnableMethod( - m_urlLoader.get(), &WebUrlLoaderClient::authRequired, authInfoPtr, firstTime)); -} - -// Called when we received an SSL certificate error. The delegate will provide -// the user the options to proceed, cancel, or view certificates. -void WebRequest::OnSSLCertificateError(URLRequest* request, int cert_error, net::X509Certificate* cert) -{ - m_urlLoader->maybeCallOnMainThread(NewRunnableMethod( - m_urlLoader.get(), &WebUrlLoaderClient::reportSslCertError, cert_error, cert)); -} - -// After calling Start(), the delegate will receive an OnResponseStarted -// callback when the request has completed. If an error occurred, the -// request->status() will be set. On success, all redirects have been -// followed and the final response is beginning to arrive. At this point, -// meta data about the response is available, including for example HTTP -// response headers if this is a request for a HTTP resource. -void WebRequest::OnResponseStarted(URLRequest* request) -{ - ASSERT(m_loadState == Started, "Got response after receiving response"); - - m_loadState = Response; - if (request && request->status().is_success()) { - OwnPtr webResponse(new WebResponse(request)); - m_urlLoader->maybeCallOnMainThread(NewRunnableMethod( - m_urlLoader.get(), &WebUrlLoaderClient::didReceiveResponse, webResponse.release())); - - // Start reading the response - startReading(); - } else { - finish(false); - } -} - -void WebRequest::setAuth(const string16& username, const string16& password) -{ - ASSERT(m_loadState == Started, "setAuth called on a WebRequest not in STARTED state (state=%d)", m_loadState); - - m_request->SetAuth(username, password); -} - -void WebRequest::cancelAuth() -{ - ASSERT(m_loadState == Started, "cancelAuth called on a WebRequest not in STARTED state (state=%d)", m_loadState); - - m_request->CancelAuth(); -} - -void WebRequest::followDeferredRedirect() -{ - ASSERT(m_loadState < Response, "Redirect after receiving response"); - - m_request->FollowDeferredRedirect(); -} - -void WebRequest::proceedSslCertError() -{ - m_request->ContinueDespiteLastError(); -} - -void WebRequest::cancelSslCertError(int cert_error) -{ - m_request->SimulateError(cert_error); -} - -void WebRequest::startReading() -{ - ASSERT(m_networkBuffer == 0, "startReading called with a nonzero buffer"); - ASSERT(m_isPaused == 0, "startReading called in paused state"); - ASSERT(m_loadState == Response || m_loadState == GotData, "StartReading in state other than RESPONSE and GOTDATA"); - if (m_loadState > GotData) // We have been cancelled between reads - return; - - if (m_wantToPause) { - m_isPaused = true; - return; - } - - int bytesRead = 0; - - if (!read(&bytesRead)) { - if (m_request && m_request->status().is_io_pending()) - return; // Wait for OnReadCompleted() - return finish(false); - } - - // bytesRead == 0 indicates finished - if (!bytesRead) - return finish(true); - - m_loadState = GotData; - // Read ok, forward buffer to webcore - m_urlLoader->maybeCallOnMainThread(NewRunnableMethod(m_urlLoader.get(), &WebUrlLoaderClient::didReceiveData, m_networkBuffer, bytesRead)); - m_networkBuffer = 0; - MessageLoop::current()->PostTask(FROM_HERE, m_runnableFactory.NewRunnableMethod(&WebRequest::startReading)); -} - -bool WebRequest::read(int* bytesRead) -{ - ASSERT(m_loadState == Response || m_loadState == GotData, "read in state other than RESPONSE and GOTDATA"); - ASSERT(m_networkBuffer == 0, "Read called with a nonzero buffer"); - - // TODO: when asserts work, check that the buffer is 0 here - m_networkBuffer = new net::IOBuffer(kInitialReadBufSize); - return m_request->Read(m_networkBuffer, kInitialReadBufSize, bytesRead); -} - -// This is called when there is data available - -// Called when the a Read of the response body is completed after an -// IO_PENDING status from a Read() call. -// The data read is filled into the buffer which the caller passed -// to Read() previously. -// -// If an error occurred, request->status() will contain the error, -// and bytes read will be -1. -void WebRequest::OnReadCompleted(URLRequest* request, int bytesRead) -{ - ASSERT(m_loadState == Response || m_loadState == GotData, "OnReadCompleted in state other than RESPONSE and GOTDATA"); - - if (request->status().is_success()) { - m_loadState = GotData; - m_urlLoader->maybeCallOnMainThread(NewRunnableMethod( - m_urlLoader.get(), &WebUrlLoaderClient::didReceiveData, m_networkBuffer, bytesRead)); - m_networkBuffer = 0; - - // Get the rest of the data - startReading(); - } else { - finish(false); - } -} - -} // namespace android diff --git a/WebKit/android/WebCoreSupport/WebRequest.h b/WebKit/android/WebCoreSupport/WebRequest.h deleted file mode 100644 index 252267b..0000000 --- a/WebKit/android/WebCoreSupport/WebRequest.h +++ /dev/null @@ -1,125 +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 WebRequest_h -#define WebRequest_h - -#include "ChromiumIncludes.h" -#include - -class MessageLoop; - -namespace android { - -enum LoadState { - Created, - Started, - Response, - GotData, - Cancelled, - Finished, - Deleted -}; - -class UrlInterceptResponse; -class WebFrame; -class WebRequestContext; -class WebResourceRequest; -class WebUrlLoaderClient; - -// All methods in this class must be called on the io thread -class WebRequest : public URLRequest::Delegate, public base::RefCountedThreadSafe { -public: - WebRequest(WebUrlLoaderClient*, const WebResourceRequest&); - - // If this is an android specific url or the application wants to load - // custom data, we load the data through an input stream. - // Used for: - // - file:///android_asset - // - file:///android_res - // - content:// - WebRequest(WebUrlLoaderClient*, const WebResourceRequest&, UrlInterceptResponse* intercept); - - // Optional, but if used has to be called before start - void appendBytesToUpload(Vector* data); - void appendFileToUpload(const std::string& filename); - - void setRequestContext(WebRequestContext* context); - void start(); - void cancel(); - void pauseLoad(bool pause); - - // From URLRequest::Delegate - virtual void OnReceivedRedirect(URLRequest*, const GURL&, bool* deferRedirect); - virtual void OnResponseStarted(URLRequest*); - virtual void OnReadCompleted(URLRequest*, int bytesRead); - virtual void OnAuthRequired(URLRequest*, net::AuthChallengeInfo*); - virtual void OnSSLCertificateError(URLRequest* request, int cert_error, net::X509Certificate* cert); - - // Methods called during a request by the UI code (via WebUrlLoaderClient). - void setAuth(const string16& username, const string16& password); - void cancelAuth(); - void followDeferredRedirect(); - void proceedSslCertError(); - void cancelSslCertError(int cert_error); - - const std::string& getUrl() const; - const std::string& getUserAgent() const; - - void setSync(bool sync) { m_isSync = sync; } -private: - void startReading(); - bool read(int* bytesRead); - - friend class base::RefCountedThreadSafe; - virtual ~WebRequest(); - void handleDataURL(GURL); - void handleBrowserURL(GURL); - void handleInterceptedURL(); - void finish(bool success); - void updateLoadFlags(int& loadFlags); - - scoped_refptr m_urlLoader; - OwnPtr m_request; - scoped_refptr m_networkBuffer; - scoped_ptr m_interceptResponse; - bool m_androidUrl; - std::string m_url; - std::string m_userAgent; - LoadState m_loadState; - int m_authRequestCount; - int m_cacheMode; - ScopedRunnableMethodFactory m_runnableFactory; - bool m_wantToPause; - bool m_isPaused; - bool m_isSync; -#ifdef LOG_REQUESTS - time_t m_startTime; -#endif -}; - -} // namespace android - -#endif diff --git a/WebKit/android/WebCoreSupport/WebRequestContext.cpp b/WebKit/android/WebCoreSupport/WebRequestContext.cpp deleted file mode 100644 index 78c3501..0000000 --- a/WebKit/android/WebCoreSupport/WebRequestContext.cpp +++ /dev/null @@ -1,130 +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 "WebRequestContext.h" - -#include "ChromiumIncludes.h" -#include "ChromiumInit.h" -#include "WebCache.h" -#include "WebCookieJar.h" - -#include - -static std::string acceptLanguageStdString(""); -static WTF::String acceptLanguageWtfString(""); -static WTF::Mutex acceptLanguageMutex; - -static int numPrivateBrowsingInstances; - -extern void ANPSystemInterface_CleanupIncognito(); - -using namespace WTF; - -namespace android { - -WebRequestContext::WebRequestContext(bool isPrivateBrowsing) - : m_isPrivateBrowsing(isPrivateBrowsing) -{ - // Initialize chromium logging, needs to be done before any chromium code is called. - initChromium(); - - if (m_isPrivateBrowsing) { - // Delete the old files if this is the first private browsing instance - // They are probably leftovers from a power cycle - // We do not need to clear the cache as it is in memory only for private browsing - if (!numPrivateBrowsingInstances) - WebCookieJar::cleanup(true); - numPrivateBrowsingInstances++; - } - - WebCache* cache = WebCache::get(m_isPrivateBrowsing); - host_resolver_ = cache->hostResolver(); - http_transaction_factory_ = cache->cache(); - - WebCookieJar* cookieJar = WebCookieJar::get(m_isPrivateBrowsing); - cookie_store_ = cookieJar->cookieStore(); - cookie_policy_ = cookieJar; - - // Also hardcoded in FrameLoader.java - accept_charset_ = "utf-8, iso-8859-1, utf-16, *;q=0.7"; -} - -WebRequestContext::~WebRequestContext() -{ - if (m_isPrivateBrowsing) { - numPrivateBrowsingInstances--; - - // This is the last private browsing context, delete the cookies and cache - if (!numPrivateBrowsingInstances) { - WebCookieJar::cleanup(true); - WebCache::cleanup(true); - ANPSystemInterface_CleanupIncognito(); - } - } -} - -void WebRequestContext::setUserAgent(const String& string) -{ - MutexLocker lock(m_userAgentMutex); - m_userAgent = string.utf8().data(); -} - -void WebRequestContext::setCacheMode(int mode) -{ - m_cacheMode = mode; -} - -int WebRequestContext::getCacheMode() -{ - return m_cacheMode; -} - -const std::string& WebRequestContext::GetUserAgent(const GURL& url) const -{ - MutexLocker lock(m_userAgentMutex); - return m_userAgent; -} - -void WebRequestContext::setAcceptLanguage(const String& string) -{ - MutexLocker lock(acceptLanguageMutex); - acceptLanguageStdString = string.utf8().data(); - acceptLanguageWtfString = string; -} - -const std::string& WebRequestContext::GetAcceptLanguage() const -{ - MutexLocker lock(acceptLanguageMutex); - return acceptLanguageStdString; -} - -const String& WebRequestContext::acceptLanguage() -{ - MutexLocker lock(acceptLanguageMutex); - return acceptLanguageWtfString; -} - -} // namespace android diff --git a/WebKit/android/WebCoreSupport/WebRequestContext.h b/WebKit/android/WebCoreSupport/WebRequestContext.h deleted file mode 100644 index 51f0514..0000000 --- a/WebKit/android/WebCoreSupport/WebRequestContext.h +++ /dev/null @@ -1,64 +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 WebRequestContext_h -#define WebRequestContext_h - -#include "ChromiumIncludes.h" -#include "PlatformString.h" - -#include - -namespace android { - -// This class is generally not threadsafe. -class WebRequestContext : public URLRequestContext { -public: - // URLRequestContext overrides. - virtual const std::string& GetUserAgent(const GURL&) const; - virtual const std::string& GetAcceptLanguage() const; - - WebRequestContext(bool isPrivateBrowsing); - - // These methods are threadsafe. - void setUserAgent(const WTF::String&); - void setCacheMode(int); - int getCacheMode(); - static void setAcceptLanguage(const WTF::String&); - static const WTF::String& acceptLanguage(); - -private: - WebRequestContext(); - ~WebRequestContext(); - - std::string m_userAgent; - int m_cacheMode; - mutable WTF::Mutex m_userAgentMutex; - bool m_isPrivateBrowsing; -}; - -} // namespace android - -#endif diff --git a/WebKit/android/WebCoreSupport/WebResourceRequest.cpp b/WebKit/android/WebCoreSupport/WebResourceRequest.cpp deleted file mode 100644 index 9b70fce..0000000 --- a/WebKit/android/WebCoreSupport/WebResourceRequest.cpp +++ /dev/null @@ -1,96 +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 "WebResourceRequest.h" - -#include "ResourceRequest.h" - -#include - -using namespace WebCore; - -namespace android { - -WebResourceRequest::WebResourceRequest(const WebCore::ResourceRequest& resourceRequest) -{ - // Set the load flags based on the WebCore request. - m_loadFlags = net::LOAD_NORMAL; - switch (resourceRequest.cachePolicy()) { - case ReloadIgnoringCacheData: - m_loadFlags |= net::LOAD_VALIDATE_CACHE; - break; - case ReturnCacheDataElseLoad: - m_loadFlags |= net::LOAD_PREFERRING_CACHE; - break; - case ReturnCacheDataDontLoad: - m_loadFlags |= net::LOAD_ONLY_FROM_CACHE; - break; - case UseProtocolCachePolicy: - break; - } - - // TODO: We should consider setting these flags and net::LOAD_DO_NOT_SEND_AUTH_DATA - // when FrameLoaderClient::shouldUseCredentialStorage() is false. However, - // the required WebKit logic is not yet in place. See Chromium's - // FrameLoaderClientImpl::shouldUseCredentialStorage(). - if (!resourceRequest.allowCookies()) { - m_loadFlags |= net::LOAD_DO_NOT_SAVE_COOKIES; - m_loadFlags |= net::LOAD_DO_NOT_SEND_COOKIES; - } - - - // Set the request headers - const HTTPHeaderMap& map = resourceRequest.httpHeaderFields(); - for (HTTPHeaderMap::const_iterator it = map.begin(); it != map.end(); ++it) { - const std::string& nameUtf8 = it->first.string().utf8().data(); - const std::string& valueUtf8 = it->second.utf8().data(); - - // Skip over referrer headers found in the header map because we already - // pulled it out as a separate parameter. We likewise prune the UA since - // that will be added back by the network layer. - if (LowerCaseEqualsASCII(nameUtf8, "referer") || LowerCaseEqualsASCII(nameUtf8, "user-agent")) - continue; - - // Skip over "Cache-Control: max-age=0" header if the corresponding - // load flag is already specified. FrameLoader sets both the flag and - // the extra header -- the extra header is redundant since our network - // implementation will add the necessary headers based on load flags. - // See http://code.google.com/p/chromium/issues/detail?id=3434. - if ((m_loadFlags & net::LOAD_VALIDATE_CACHE) && - LowerCaseEqualsASCII(nameUtf8, "cache-control") && LowerCaseEqualsASCII(valueUtf8, "max-age=0")) - continue; - - m_requestHeaders.SetHeader(nameUtf8, valueUtf8); - } - - m_method = resourceRequest.httpMethod().utf8().data(); - m_referrer = resourceRequest.httpReferrer().utf8().data(); - m_userAgent = resourceRequest.httpUserAgent().utf8().data(); - - m_url = resourceRequest.url().string().utf8().data(); -} - -} // namespace android diff --git a/WebKit/android/WebCoreSupport/WebResourceRequest.h b/WebKit/android/WebCoreSupport/WebResourceRequest.h deleted file mode 100644 index 38f37b5..0000000 --- a/WebKit/android/WebCoreSupport/WebResourceRequest.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 WebResourceRequest_h -#define WebResourceRequest_h - -#include "ChromiumIncludes.h" - -#include - -namespace WebCore { -class ResourceRequest; -} - -namespace android { - -class WebResourceRequest { - -public: - WebResourceRequest(const WebCore::ResourceRequest&); - - const std::string& method() const - { - return m_method; - } - - const std::string& referrer() const - { - return m_referrer; - } - - const std::string& userAgent() const - { - return m_userAgent; - } - - const net::HttpRequestHeaders& requestHeaders() const - { - return m_requestHeaders; - } - - const std::string& url() const - { - return m_url; - } - - int loadFlags() const - { - return m_loadFlags; - } - -private: - std::string m_method; - std::string m_referrer; - std::string m_userAgent; - net::HttpRequestHeaders m_requestHeaders; - std::string m_url; - int m_loadFlags; -}; - -} // namespace android - - -#endif diff --git a/WebKit/android/WebCoreSupport/WebResponse.cpp b/WebKit/android/WebCoreSupport/WebResponse.cpp deleted file mode 100644 index 4d297d7..0000000 --- a/WebKit/android/WebCoreSupport/WebResponse.cpp +++ /dev/null @@ -1,167 +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 "WebResponse.h" - -#include "MIMETypeRegistry.h" -#include "PlatformString.h" -#include "ResourceResponse.h" -#include "ResourceError.h" - -#include - -using namespace std; - -namespace android { - -WebResponse::WebResponse(URLRequest* request) - : m_httpStatusCode(0) -{ - // The misleadingly-named os_error() is actually a net::Error enum constant. - m_error = net::Error(request->status().os_error()); - - m_url = request->url().spec(); - m_host = request->url().HostNoBrackets(); - request->GetMimeType(&m_mime); - - request->GetCharset(&m_encoding); - m_expectedSize = request->GetExpectedContentSize(); - - m_sslInfo = request->ssl_info(); - - net::HttpResponseHeaders* responseHeaders = request->response_headers(); - if (!responseHeaders) - return; - - m_httpStatusCode = responseHeaders->response_code(); - m_httpStatusText = responseHeaders->GetStatusText(); - - string value; - string name; - void* iter = 0; - while (responseHeaders->EnumerateHeaderLines(&iter, &name, &value)) - m_headerFields[name] = value; -} - -WebResponse::WebResponse(const string &url, const string &mimeType, long long expectedSize, const string &encoding, int httpStatusCode) - : m_error(net::OK) - , m_encoding(encoding) - , m_httpStatusCode(httpStatusCode) - , m_expectedSize(expectedSize) - , m_mime(mimeType) - , m_url(url) -{ -} - -WebCore::ResourceResponse WebResponse::createResourceResponse() -{ - WebCore::ResourceResponse resourceResponse(createKurl(), getMimeType().c_str(), m_expectedSize, m_encoding.c_str(), ""); - resourceResponse.setHTTPStatusCode(m_httpStatusCode); - resourceResponse.setHTTPStatusText(m_httpStatusText.c_str()); - - map::const_iterator it; - for (it = m_headerFields.begin(); it != m_headerFields.end(); ++it) - resourceResponse.setHTTPHeaderField(it->first.c_str(), it->second.c_str()); - - return resourceResponse; -} - -WebCore::ResourceError WebResponse::createResourceError() -{ - WebCore::ResourceError error(m_host.c_str(), ToWebViewClientError(m_error), m_url.c_str(), WTF::String()); - return error; -} - - -WebCore::KURL WebResponse::createKurl() -{ - WebCore::KURL kurl(WebCore::ParsedURLString, m_url.c_str()); - return kurl; -} - -const string& WebResponse::getUrl() const -{ - return m_url; -} - -void WebResponse::setUrl(const string& url) -{ - m_url = url; -} - -// Calls WebCore APIs so should only be called from the WebCore thread. -// TODO: can we return a WTF::String directly? Need to check all callsites. -const string& WebResponse::getMimeType() -{ - if (!m_url.length()) - return m_mime; - - if (!m_mime.length() || !m_mime.compare("text/plain") || !m_mime.compare("application/octet-stream")) - m_mime = resolveMimeType(m_url, m_mime); - - return m_mime; -} - -const string WebResponse::resolveMimeType(const string& url, const string& old_mime) -{ - // Use "text/html" as a default (matching the behaviour of the Apache - // HTTP stack -- see guessMimeType() in LoadListener.java). - string mimeType = old_mime.length() ? old_mime : "text/html"; - // Try to guess a better MIME type from the URL. We call - // getMIMETypeForExtension rather than getMIMETypeForPath because the - // latter defaults to "application/octet-stream" on failure. - WebCore::KURL kurl(WebCore::ParsedURLString, url.c_str()); - WTF::String path = kurl.path(); - size_t extensionPos = path.reverseFind('.'); - if (extensionPos != WTF::notFound) { - // We found a file extension. - path.remove(0, extensionPos + 1); - // TODO: Should use content-disposition instead of url if it is there - WTF::String mime = WebCore::MIMETypeRegistry::getMIMETypeForExtension(path); - if (!mime.isEmpty()) { - // Great, we found a MIME type. - mimeType = std::string(mime.utf8().data(), mime.length()); - } - } - return mimeType; -} - -bool WebResponse::getHeader(const string& header, string* result) const -{ - map::const_iterator iter = m_headerFields.find(header); - if (iter == m_headerFields.end()) - return false; - if (result) - *result = iter->second; - return true; -} - -long long WebResponse::getExpectedSize() const -{ - return m_expectedSize; -} - -} // namespace android diff --git a/WebKit/android/WebCoreSupport/WebResponse.h b/WebKit/android/WebCoreSupport/WebResponse.h deleted file mode 100644 index 88c8917..0000000 --- a/WebKit/android/WebCoreSupport/WebResponse.h +++ /dev/null @@ -1,91 +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 WebResponse_h -#define WebResponse_h - -#include "ChromiumIncludes.h" -#include "KURL.h" -#include "WebViewClientError.h" - -#include -#include - -namespace WebCore { -class ResourceResponse; -class ResourceError; -} - -namespace android { - -class WebResponse { - -public: - WebResponse() {} - WebResponse(URLRequest*); - WebResponse(const std::string &url, const std::string &mimeType, long long expectedSize, const std::string &encoding, int httpStatusCode); - - const std::string& getUrl() const; - void setUrl(const std::string&); - - const std::string& getMimeType(); // Use only on WebCore thread. - bool getHeader(const std::string& header, std::string* result) const; - long long getExpectedSize() const; - - const net::SSLInfo& getSslInfo() const { return m_sslInfo; } - - // The create() methods create WebCore objects. They must only be called on the WebKit thread. - WebCore::KURL createKurl(); - WebCore::ResourceResponse createResourceResponse(); - WebCore::ResourceError createResourceError(); - - static const std::string resolveMimeType(const std::string& url, const std::string& old_mime); - -private: - net::Error m_error; - std::string m_encoding; - int m_httpStatusCode; - std::string m_host; - std::string m_httpStatusText; - long long m_expectedSize; - std::string m_mime; - std::string m_url; - net::SSLInfo m_sslInfo; - - struct CaseInsensitiveLessThan { - bool operator()(const std::string& lhs, const std::string& rhs) const { - return strcasecmp(lhs.c_str(), rhs.c_str()) < 0; - } - }; - - // Header fields are case insensitive, so we use a case-insensitive map. - // See RFC 822, 3.4.7, "CASE INDEPENDENCE". - std::map m_headerFields; - -}; - -} // namespace android - -#endif diff --git a/WebKit/android/WebCoreSupport/WebUrlLoader.cpp b/WebKit/android/WebCoreSupport/WebUrlLoader.cpp deleted file mode 100644 index 0c90bc5..0000000 --- a/WebKit/android/WebCoreSupport/WebUrlLoader.cpp +++ /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. - */ - -#include "config.h" - -#include "WebUrlLoader.h" - -#include "FrameLoaderClientAndroid.h" -#include "WebCoreFrameBridge.h" -#include "WebUrlLoaderClient.h" - -namespace android { - -// on main thread -WebUrlLoader::WebUrlLoader(WebFrame* webFrame, WebCore::ResourceHandle* resourceHandle, const WebCore::ResourceRequest& resourceRequest) -{ - m_loaderClient = new WebUrlLoaderClient(webFrame, resourceHandle, resourceRequest); -} - -// on main thread -WebUrlLoader::~WebUrlLoader() -{ -} - -PassRefPtr WebUrlLoader::start(FrameLoaderClient* client, WebCore::ResourceHandle* resourceHandle, - const WebCore::ResourceRequest& resourceRequest, bool isMainResource, bool isMainFrame, bool isSync, WebRequestContext* context) -{ - FrameLoaderClientAndroid* androidClient = static_cast(client); - WebFrame* webFrame = androidClient->webFrame(); - - if (webFrame->blockNetworkLoads() && - (resourceRequest.url().protocolIs("http") || - resourceRequest.url().protocolIs("https"))) - return NULL; - - webFrame->maybeSavePassword(androidClient->getFrame(), resourceRequest); - - RefPtr loader = WebUrlLoader::create(webFrame, resourceHandle, resourceRequest); - loader->m_loaderClient->start(isMainResource, isMainFrame, isSync, context); - - return loader.release(); -} - -PassRefPtr WebUrlLoader::create(WebFrame* webFrame, WebCore::ResourceHandle* resourceHandle, const WebCore::ResourceRequest& resourceRequest) -{ - return adoptRef(new WebUrlLoader(webFrame, resourceHandle, resourceRequest)); -} - -// on main thread -void WebUrlLoader::cancel() -{ - m_loaderClient->cancel(); -} - -void WebUrlLoader::downloadFile() -{ - m_loaderClient->downloadFile(); -} - -void WebUrlLoader::pauseLoad(bool pause) -{ - m_loaderClient->pauseLoad(pause); -} - -} // namespace android diff --git a/WebKit/android/WebCoreSupport/WebUrlLoader.h b/WebKit/android/WebCoreSupport/WebUrlLoader.h deleted file mode 100644 index dd88e73..0000000 --- a/WebKit/android/WebCoreSupport/WebUrlLoader.h +++ /dev/null @@ -1,57 +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 WebUrlLoader_h -#define WebUrlLoader_h - -#include "ChromiumIncludes.h" -#include "ResourceLoaderAndroid.h" - -using namespace WebCore; - -namespace android { -class WebUrlLoaderClient; -class WebFrame; -class WebRequestContext; - -class WebUrlLoader : public ResourceLoaderAndroid { -public: - virtual ~WebUrlLoader(); - static PassRefPtr start(FrameLoaderClient* client, WebCore::ResourceHandle*, const WebCore::ResourceRequest&, bool isMainResource, bool isMainFrame, bool sync, WebRequestContext*); - - virtual void cancel(); - virtual void downloadFile(); - virtual void pauseLoad(bool pause); - -private: - WebUrlLoader(WebFrame*, WebCore::ResourceHandle*, const WebCore::ResourceRequest&); - static PassRefPtr create(WebFrame*, WebCore::ResourceHandle*, const WebCore::ResourceRequest&); - - scoped_refptr m_loaderClient; -}; - -} // namespace android - -#endif diff --git a/WebKit/android/WebCoreSupport/WebUrlLoaderClient.cpp b/WebKit/android/WebCoreSupport/WebUrlLoaderClient.cpp deleted file mode 100644 index cf218e7..0000000 --- a/WebKit/android/WebCoreSupport/WebUrlLoaderClient.cpp +++ /dev/null @@ -1,482 +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. - */ - -#define LOG_TAG "WebUrlLoaderClient" - -#include "config.h" -#include "WebUrlLoaderClient.h" - -#include "ChromiumIncludes.h" -#include "OwnPtr.h" -#include "ResourceHandle.h" -#include "ResourceHandleClient.h" -#include "ResourceResponse.h" -#include "WebCoreFrameBridge.h" -#include "WebRequest.h" -#include "WebResourceRequest.h" - -#include - -namespace android { - -base::Thread* WebUrlLoaderClient::ioThread() -{ - static base::Thread* networkThread = 0; - static Lock networkThreadLock; - - // Multiple threads appear to access the ioThread so we must ensure the - // critical section ordering. - AutoLock lock(networkThreadLock); - - if (!networkThread) - networkThread = new base::Thread("network"); - - if (!networkThread) - return 0; - - if (networkThread->IsRunning()) - return networkThread; - - base::Thread::Options options; - options.message_loop_type = MessageLoop::TYPE_IO; - if (!networkThread->StartWithOptions(options)) { - delete networkThread; - networkThread = 0; - } - - return networkThread; -} - -Lock* WebUrlLoaderClient::syncLock() { - static Lock s_syncLock; - return &s_syncLock; -} - -ConditionVariable* WebUrlLoaderClient::syncCondition() { - static ConditionVariable s_syncCondition(syncLock()); - return &s_syncCondition; -} - -WebUrlLoaderClient::~WebUrlLoaderClient() -{ -} - -bool WebUrlLoaderClient::isActive() const -{ - if (m_cancelling) - return false; - if (!m_resourceHandle) - return false; - if (!m_resourceHandle->client()) - return false; - if (m_finished) - return false; - - return true; -} - -WebUrlLoaderClient::WebUrlLoaderClient(WebFrame* webFrame, WebCore::ResourceHandle* resourceHandle, const WebCore::ResourceRequest& resourceRequest) - : m_webFrame(webFrame) - , m_resourceHandle(resourceHandle) - , m_isMainResource(false) - , m_isMainFrame(false) - , m_isCertMimeType(false) - , m_cancelling(false) - , m_sync(false) - , m_finished(false) -{ - WebResourceRequest webResourceRequest(resourceRequest); - UrlInterceptResponse* intercept = webFrame->shouldInterceptRequest(resourceRequest.url().string()); - if (intercept) { - m_request = new WebRequest(this, webResourceRequest, intercept); - return; - } - - m_request = new WebRequest(this, webResourceRequest); - - // Set uploads before start is called on the request - if (resourceRequest.httpBody() && !(webResourceRequest.method() == "GET" || webResourceRequest.method() == "HEAD")) { - Vector::iterator iter; - Vector elements = resourceRequest.httpBody()->elements(); - for (iter = elements.begin(); iter != elements.end(); iter++) { - FormDataElement element = *iter; - - switch (element.m_type) { - case FormDataElement::data: - if (!element.m_data.isEmpty()) { - // WebKit sometimes gives up empty data to append. These aren't - // necessary so we just optimize those out here. - base::Thread* thread = ioThread(); - if (thread) { - Vector* data = new Vector(element.m_data); - thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request.get(), &WebRequest::appendBytesToUpload, data)); - } - } - break; - case FormDataElement::encodedFile: - { - // Chromium check if it is a directory by checking - // element.m_fileLength, that doesn't work in Android - std::string filename = element.m_filename.utf8().data(); - if (filename.size()) { - // Change from a url string to a filename - if (filename.find("file://") == 0) // Found at pos 0 - filename.erase(0, 7); - base::Thread* thread = ioThread(); - if (thread) - thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request.get(), &WebRequest::appendFileToUpload, filename)); - } - } - break; -#if ENABLE(BLOB) - case FormDataElement::encodedBlob: - LOG_ASSERT(false, "Unexpected use of FormDataElement::encodedBlob"); - break; -#endif // ENABLE(BLOB) - default: - LOG_ASSERT(false, "Unexpected default case in WebUrlLoaderClient.cpp"); - break; - } - } - } -} - -bool WebUrlLoaderClient::start(bool isMainResource, bool isMainFrame, bool sync, WebRequestContext* context) -{ - base::Thread* thread = ioThread(); - if (!thread) { - return false; - } - - m_isMainResource = isMainResource; - m_isMainFrame = isMainFrame; - m_sync = sync; - if (m_sync) { - AutoLock autoLock(*syncLock()); - m_request->setSync(sync); - m_request->setRequestContext(context); - thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request.get(), &WebRequest::start)); - - // Run callbacks until the queue is exhausted and m_finished is true. - // Sometimes, a sync load can wait forever and lock up the WebCore thread, - // here we use TimedWait() with multiple tries to avoid locking. - const int kMaxNumTimeout = 3; - const int kCallbackWaitingTime = 10; - int num_timeout = 0; - while(!m_finished) { - while (!m_queue.empty()) { - OwnPtr task(m_queue.front()); - m_queue.pop_front(); - task->Run(); - } - if (m_finished) break; - - syncCondition()->TimedWait(base::TimeDelta::FromSeconds(kCallbackWaitingTime)); - if (m_queue.empty()) { - LOGE("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) { - cancel(); - m_resourceHandle = 0; - return false; - } - } - } - - // This may be the last reference to us, so we may be deleted now. - // Don't access any more member variables after releasing this reference. - m_resourceHandle = 0; - } else { - // Asynchronous start. - // Important to set this before the thread starts so it has a reference and can't be deleted - // before the task starts running on the IO thread. - m_request->setRequestContext(context); - thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request.get(), &WebRequest::start)); - } - return true; -} - -namespace { -// Check if the mime type is for certificate installation. -// The items must be consistent with the sCertificateTypeMap -// in frameworks/base/core/java/android/webkit/CertTool.java. -bool isMimeTypeForCert(const std::string& mimeType) -{ - static std::hash_set sCertificateTypeSet; - if (sCertificateTypeSet.empty()) { - sCertificateTypeSet.insert("application/x-x509-ca-cert"); - sCertificateTypeSet.insert("application/x-x509-user-cert"); - sCertificateTypeSet.insert("application/x-pkcs12"); - } - return sCertificateTypeSet.find(mimeType) != sCertificateTypeSet.end(); -} -} - -void WebUrlLoaderClient::downloadFile() -{ - if (m_response) { - std::string contentDisposition; - m_response->getHeader("content-disposition", &contentDisposition); - m_webFrame->downloadStart(m_response->getUrl(), m_request->getUserAgent(), contentDisposition, m_response->getMimeType(), m_response->getExpectedSize()); - - m_isCertMimeType = isMimeTypeForCert(m_response->getMimeType()); - // Currently, only certificate mime type needs to receive the data. - // Other mime type, e.g. wav, will send the url to other application - // which will load the data by url. - if (!m_isCertMimeType) - cancel(); - } else { - LOGE("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(); - } -} - -void WebUrlLoaderClient::cancel() -{ - if (!isActive()) - return; - - m_cancelling = true; - - base::Thread* thread = ioThread(); - if (thread) - thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request.get(), &WebRequest::cancel)); -} - -void WebUrlLoaderClient::pauseLoad(bool pause) -{ - if (!isActive()) - return; - - base::Thread* thread = ioThread(); - if (thread) - thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request.get(), &WebRequest::pauseLoad, pause)); -} - -void WebUrlLoaderClient::setAuth(const std::string& username, const std::string& password) -{ - if (!isActive()) - return; - - base::Thread* thread = ioThread(); - if (!thread) { - return; - } - string16 username16 = ASCIIToUTF16(username); - string16 password16 = ASCIIToUTF16(password); - thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request.get(), &WebRequest::setAuth, username16, password16)); -} - -void WebUrlLoaderClient::cancelAuth() -{ - if (!isActive()) - return; - - base::Thread* thread = ioThread(); - if (!thread) { - return; - } - thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request.get(), &WebRequest::cancelAuth)); -} - -void WebUrlLoaderClient::proceedSslCertError() -{ - base::Thread* thread = ioThread(); - if (isActive() && thread) - thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request.get(), &WebRequest::proceedSslCertError)); - this->Release(); -} - -void WebUrlLoaderClient::cancelSslCertError(int cert_error) -{ - base::Thread* thread = ioThread(); - if (isActive() && thread) - thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request.get(), &WebRequest::cancelSslCertError, cert_error)); - this->Release(); -} - - -void WebUrlLoaderClient::finish() -{ - m_finished = true; - if (!m_sync) { - // This is the last reference to us, so we will be deleted now. - // We only release the reference here if start() was called asynchronously! - m_resourceHandle = 0; - } - m_request = 0; -} - -namespace { -// Trampoline to wrap a Chromium Task* in a WebKit-style static function + void*. -static void RunTask(void* v) { - OwnPtr task(static_cast(v)); - task->Run(); -} -} - -// This is called from the IO thread, and dispatches the callback to the main thread. -void WebUrlLoaderClient::maybeCallOnMainThread(Task* task) -{ - if (m_sync) { - AutoLock autoLock(*syncLock()); - if (m_queue.empty()) { - syncCondition()->Broadcast(); - } - m_queue.push_back(task); - } else { - // Let WebKit handle it. - callOnMainThread(RunTask, task); - } -} - -// Response methods -void WebUrlLoaderClient::didReceiveResponse(PassOwnPtr webResponse) -{ - if (!isActive()) - return; - - m_response = webResponse; - m_resourceHandle->client()->didReceiveResponse(m_resourceHandle.get(), m_response->createResourceResponse()); - - // Set the main page's certificate to WebView. - if (m_isMainResource && m_isMainFrame) { - const net::SSLInfo& ssl_info = m_response->getSslInfo(); - if (ssl_info.is_valid()) { - std::vector chain_bytes; - ssl_info.cert->GetChainDEREncodedBytes(&chain_bytes); - m_webFrame->setCertificate(chain_bytes[0]); - } - - // Look for X-Auto-Login on the main resource to log in the user. - std::string login; - if (m_response->getHeader("x-auto-login", &login)) - m_webFrame->autoLogin(login); - } -} - -void WebUrlLoaderClient::didReceiveData(scoped_refptr buf, int size) -{ - if (m_isMainResource && m_isCertMimeType) { - m_webFrame->didReceiveData(buf->data(), size); - } - - if (!isActive() || !size) - return; - - // didReceiveData will take a copy of the data - if (m_resourceHandle && m_resourceHandle->client()) - m_resourceHandle->client()->didReceiveData(m_resourceHandle.get(), buf->data(), size, size); -} - -// For data url's -void WebUrlLoaderClient::didReceiveDataUrl(PassOwnPtr str) -{ - if (!isActive() || !str->size()) - return; - - // didReceiveData will take a copy of the data - m_resourceHandle->client()->didReceiveData(m_resourceHandle.get(), str->data(), str->size(), str->size()); -} - -// For special android files -void WebUrlLoaderClient::didReceiveAndroidFileData(PassOwnPtr > vector) -{ - if (!isActive() || !vector->size()) - return; - - // didReceiveData will take a copy of the data - m_resourceHandle->client()->didReceiveData(m_resourceHandle.get(), vector->begin(), vector->size(), vector->size()); -} - -void WebUrlLoaderClient::didFail(PassOwnPtr webResponse) -{ - if (isActive()) - m_resourceHandle->client()->didFail(m_resourceHandle.get(), webResponse->createResourceError()); - - // Always finish a request, if not it will leak - finish(); -} - -void WebUrlLoaderClient::willSendRequest(PassOwnPtr webResponse) -{ - if (!isActive()) - return; - - KURL url = webResponse->createKurl(); - OwnPtr resourceRequest(new WebCore::ResourceRequest(url)); - m_resourceHandle->client()->willSendRequest(m_resourceHandle.get(), *resourceRequest, webResponse->createResourceResponse()); - - // WebKit may have killed the request. - if (!isActive()) - return; - - // Like Chrome, we only follow the redirect if WebKit left the URL unmodified. - if (url == resourceRequest->url()) { - ioThread()->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request.get(), &WebRequest::followDeferredRedirect)); - } else { - cancel(); - } -} - -void WebUrlLoaderClient::didFinishLoading() -{ - if (isActive()) - m_resourceHandle->client()->didFinishLoading(m_resourceHandle.get(), 0); - - if (m_isMainResource && m_isCertMimeType) { - m_webFrame->didFinishLoading(); - } - - // Always finish a request, if not it will leak - finish(); -} - -void WebUrlLoaderClient::authRequired(scoped_refptr authChallengeInfo, bool firstTime) -{ - if (!isActive()) - return; - - std::string host = base::SysWideToUTF8(authChallengeInfo->host_and_port); - std::string realm = base::SysWideToUTF8(authChallengeInfo->realm); - - m_webFrame->didReceiveAuthenticationChallenge(this, host, realm, firstTime); -} - -void WebUrlLoaderClient::reportSslCertError(int cert_error, net::X509Certificate* cert) -{ - if (!isActive()) - return; - - std::vector chain_bytes; - cert->GetChainDEREncodedBytes(&chain_bytes); - this->AddRef(); - m_webFrame->reportSslCertError(this, cert_error, chain_bytes[0]); -} - -} // namespace android diff --git a/WebKit/android/WebCoreSupport/WebUrlLoaderClient.h b/WebKit/android/WebCoreSupport/WebUrlLoaderClient.h deleted file mode 100644 index dc101db..0000000 --- a/WebKit/android/WebCoreSupport/WebUrlLoaderClient.h +++ /dev/null @@ -1,130 +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 WebUrlLoaderClient_h -#define WebUrlLoaderClient_h - -#include "ChromiumIncludes.h" -#include "RefCounted.h" -#include "WebResponse.h" -#include "WebUrlLoader.h" - -#include -#include -#include -#include - -class Lock; -class ConditionVariable; - -namespace base { -class Thread; -} - -namespace net { -class IOBuffer; -class AuthChallengeInfo; -} - -namespace android { - -class WebFrame; -class WebRequest; -class WebRequestContext; - -// This class handles communication between the IO thread where loading happens -// and the webkit main thread. -// TODO: -// - Implement didFail -// - Implement sync requests -// - Implement downloadFile -// - Implement pauseLoad -class WebUrlLoaderClient : public base::RefCountedThreadSafe { -public: - WebUrlLoaderClient(WebFrame*, WebCore::ResourceHandle*, const WebCore::ResourceRequest&); - - // Called from WebCore, will be forwarded to the IO thread - bool start(bool isMainResource, bool isMainFrame, bool sync, WebRequestContext*); - void cancel(); - void downloadFile(); - void pauseLoad(bool pause); - void setAuth(const std::string& username, const std::string& password); - void cancelAuth(); - void proceedSslCertError(); - void cancelSslCertError(int cert_error); - - typedef void CallbackFunction(void*); - - // This is called from the IO thread, and dispatches the callback to the main thread. - // (For asynchronous calls, we just delegate to WebKit's callOnMainThread.) - void maybeCallOnMainThread(Task* task); - - // Called by WebRequest (using maybeCallOnMainThread), should be forwarded to WebCore. - void didReceiveResponse(PassOwnPtr); - void didReceiveData(scoped_refptr, int size); - void didReceiveDataUrl(PassOwnPtr); - void didReceiveAndroidFileData(PassOwnPtr >); - void didFinishLoading(); - void didFail(PassOwnPtr); - void willSendRequest(PassOwnPtr); - void authRequired(scoped_refptr, bool firstTime); - void reportSslCertError(int cert_error, net::X509Certificate* cert); - - // Handle to the chrome IO thread - static base::Thread* ioThread(); - -private: - friend class base::RefCountedThreadSafe; - virtual ~WebUrlLoaderClient(); - - void finish(); - - WebFrame* m_webFrame; - RefPtr m_resourceHandle; - bool m_isMainResource; - bool m_isMainFrame; - bool m_isCertMimeType; - bool m_cancelling; - bool m_sync; - volatile bool m_finished; - - scoped_refptr m_request; - OwnPtr m_response; // NULL until didReceiveResponse is called. - - // Check if a request is active - bool isActive() const; - - // Mutex and condition variable used for synchronous requests. - // Note that these are static. This works because there's only one main thread. - static Lock* syncLock(); - static ConditionVariable* syncCondition(); - - // Queue of callbacks to be executed by the main thread. Must only be accessed inside mutex. - std::deque m_queue; -}; - -} // namespace android - -#endif diff --git a/WebKit/android/WebCoreSupport/WebViewClientError.cpp b/WebKit/android/WebCoreSupport/WebViewClientError.cpp deleted file mode 100644 index 59542da..0000000 --- a/WebKit/android/WebCoreSupport/WebViewClientError.cpp +++ /dev/null @@ -1,132 +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 "WebViewClientError.h" - -using namespace net; - -namespace android { - -WebViewClientError ToWebViewClientError(net::Error error) { - // Note: many net::Error constants don't have an obvious mapping. - // These will be handled by the default case, ERROR_UNKNOWN. - switch(error) { - case ERR_UNSUPPORTED_AUTH_SCHEME: - return ERROR_UNSUPPORTED_AUTH_SCHEME; - - case ERR_INVALID_AUTH_CREDENTIALS: - case ERR_MISSING_AUTH_CREDENTIALS: - case ERR_MISCONFIGURED_AUTH_ENVIRONMENT: - return ERROR_AUTHENTICATION; - - case ERR_TOO_MANY_REDIRECTS: - return ERROR_REDIRECT_LOOP; - - case ERR_UPLOAD_FILE_CHANGED: - return ERROR_FILE_NOT_FOUND; - - case ERR_INVALID_URL: - return ERROR_BAD_URL; - - case ERR_DISALLOWED_URL_SCHEME: - case ERR_UNKNOWN_URL_SCHEME: - return ERROR_UNSUPPORTED_SCHEME; - - case ERR_IO_PENDING: - case ERR_NETWORK_IO_SUSPENDED: - return ERROR_IO; - - case ERR_CONNECTION_TIMED_OUT: - case ERR_TIMED_OUT: - return ERROR_TIMEOUT; - - case ERR_FILE_TOO_BIG: - return ERROR_FILE; - - case ERR_HOST_RESOLVER_QUEUE_TOO_LARGE: - case ERR_INSUFFICIENT_RESOURCES: - case ERR_OUT_OF_MEMORY: - return ERROR_TOO_MANY_REQUESTS; - - case ERR_CONNECTION_CLOSED: - case ERR_CONNECTION_RESET: - case ERR_CONNECTION_REFUSED: - case ERR_CONNECTION_ABORTED: - case ERR_CONNECTION_FAILED: - case ERR_SOCKET_NOT_CONNECTED: - return ERROR_CONNECT; - - case ERR_ADDRESS_INVALID: - case ERR_ADDRESS_UNREACHABLE: - case ERR_NAME_NOT_RESOLVED: - case ERR_NAME_RESOLUTION_FAILED: - return ERROR_HOST_LOOKUP; - - case ERR_SSL_PROTOCOL_ERROR: - case ERR_SSL_CLIENT_AUTH_CERT_NEEDED: - case ERR_TUNNEL_CONNECTION_FAILED: - case ERR_NO_SSL_VERSIONS_ENABLED: - case ERR_SSL_VERSION_OR_CIPHER_MISMATCH: - case ERR_SSL_RENEGOTIATION_REQUESTED: - case ERR_CERT_ERROR_IN_SSL_RENEGOTIATION: - case ERR_BAD_SSL_CLIENT_AUTH_CERT: - case ERR_SSL_NO_RENEGOTIATION: - case ERR_SSL_DECOMPRESSION_FAILURE_ALERT: - case ERR_SSL_BAD_RECORD_MAC_ALERT: - case ERR_SSL_UNSAFE_NEGOTIATION: - case ERR_SSL_WEAK_SERVER_EPHEMERAL_DH_KEY: - case ERR_SSL_SNAP_START_NPN_MISPREDICTION: - case ERR_SSL_CLIENT_AUTH_PRIVATE_KEY_ACCESS_DENIED: - case ERR_SSL_CLIENT_AUTH_CERT_NO_PRIVATE_KEY: - return ERROR_FAILED_SSL_HANDSHAKE; - - case ERR_PROXY_AUTH_UNSUPPORTED: - case ERR_PROXY_AUTH_REQUESTED: - case ERR_PROXY_CONNECTION_FAILED: - case ERR_UNEXPECTED_PROXY_AUTH: - return ERROR_PROXY_AUTHENTICATION; - - /* The certificate errors are handled by their own dialog - * and don't need to be reported to the framework again. - */ - case ERR_CERT_COMMON_NAME_INVALID: - case ERR_CERT_DATE_INVALID: - case ERR_CERT_AUTHORITY_INVALID: - case ERR_CERT_CONTAINS_ERRORS: - case ERR_CERT_NO_REVOCATION_MECHANISM: - case ERR_CERT_UNABLE_TO_CHECK_REVOCATION: - case ERR_CERT_REVOKED: - case ERR_CERT_INVALID: - case ERR_CERT_WEAK_SIGNATURE_ALGORITHM: - case ERR_CERT_NOT_IN_DNS: - return ERROR_OK; - - default: - return ERROR_UNKNOWN; - } -} - -} diff --git a/WebKit/android/WebCoreSupport/WebViewClientError.h b/WebKit/android/WebCoreSupport/WebViewClientError.h deleted file mode 100644 index d274dc7..0000000 --- a/WebKit/android/WebCoreSupport/WebViewClientError.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 WebViewClientError_h -#define WebViewClientError_h - -#include "ChromiumIncludes.h" - -namespace android { - -// This enum must be kept in sync with WebViewClient.java -enum WebViewClientError { - /** Success */ - ERROR_OK = 0, - /** Generic error */ - ERROR_UNKNOWN = -1, - /** Server or proxy hostname lookup failed */ - ERROR_HOST_LOOKUP = -2, - /** Unsupported authentication scheme (not basic or digest) */ - ERROR_UNSUPPORTED_AUTH_SCHEME = -3, - /** User authentication failed on server */ - ERROR_AUTHENTICATION = -4, - /** User authentication failed on proxy */ - ERROR_PROXY_AUTHENTICATION = -5, - /** Failed to connect to the server */ - ERROR_CONNECT = -6, - /** Failed to read or write to the server */ - ERROR_IO = -7, - /** Connection timed out */ - ERROR_TIMEOUT = -8, - /** Too many redirects */ - ERROR_REDIRECT_LOOP = -9, - /** Unsupported URI scheme */ - ERROR_UNSUPPORTED_SCHEME = -10, - /** Failed to perform SSL handshake */ - ERROR_FAILED_SSL_HANDSHAKE = -11, - /** Malformed URL */ - ERROR_BAD_URL = -12, - /** Generic file error */ - ERROR_FILE = -13, - /** File not found */ - ERROR_FILE_NOT_FOUND = -14, - /** Too many requests during this load */ - ERROR_TOO_MANY_REQUESTS = -15, -}; - -// Get the closest WebViewClient match to the given Chrome error code. -WebViewClientError ToWebViewClientError(net::Error); - -} // namespace android - -#endif // WebViewClientError_h diff --git a/WebKit/android/WebCoreSupport/autofill/AutoFillHostAndroid.cpp b/WebKit/android/WebCoreSupport/autofill/AutoFillHostAndroid.cpp deleted file mode 100644 index 5bc4c92..0000000 --- a/WebKit/android/WebCoreSupport/autofill/AutoFillHostAndroid.cpp +++ /dev/null @@ -1,51 +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 "AutoFillHostAndroid.h" - -#include "autofill/WebAutoFill.h" - -namespace android { - -AutoFillHostAndroid::AutoFillHostAndroid(WebAutoFill* autoFill) - : mAutoFill(autoFill) -{ -} - -void AutoFillHostAndroid::AutoFillSuggestionsReturned(const std::vector& names, const std::vector& labels, const std::vector& icons, const std::vector& uniqueIds) -{ - // TODO: what do we do with icons? - if (mAutoFill) - mAutoFill->querySuccessful(names[0], labels[0], uniqueIds[0]); -} - -void AutoFillHostAndroid::AutoFillFormDataFilled(int queryId, const webkit_glue::FormData& form) -{ - if (mAutoFill) - mAutoFill->fillFormInPage(queryId, form); -} - -} diff --git a/WebKit/android/WebCoreSupport/autofill/AutoFillHostAndroid.h b/WebKit/android/WebCoreSupport/autofill/AutoFillHostAndroid.h deleted file mode 100644 index 9677b46..0000000 --- a/WebKit/android/WebCoreSupport/autofill/AutoFillHostAndroid.h +++ /dev/null @@ -1,54 +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 AutoFillHostAndroid_h -#define AutoFillHostAndroid_h - -#include "ChromiumIncludes.h" - -#include - -namespace webkit_glue { -class FormData; -} - -namespace android { -class WebAutoFill; - -// This class receives the callbacks from the AutoFillManager in the Chromium code. -class AutoFillHostAndroid : public AutoFillHost { -public: - AutoFillHostAndroid(WebAutoFill* autoFill); - virtual ~AutoFillHostAndroid() { } - - virtual void AutoFillSuggestionsReturned(const std::vector& names, const std::vector& labels, const std::vector& icons, const std::vector& uniqueIds); - virtual void AutoFillFormDataFilled(int queryId, const webkit_glue::FormData&); - -private: - WebAutoFill* mAutoFill; -}; -} - -#endif diff --git a/WebKit/android/WebCoreSupport/autofill/FormFieldAndroid.cpp b/WebKit/android/WebCoreSupport/autofill/FormFieldAndroid.cpp deleted file mode 100644 index 6af0875..0000000 --- a/WebKit/android/WebCoreSupport/autofill/FormFieldAndroid.cpp +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (c) 2010 The Chromium Authors. All rights reserved. - * 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 "FormFieldAndroid.h" - -#include "ChromiumIncludes.h" -#include "Element.h" -#include "HTMLFormControlElement.h" -#include "HTMLInputElement.h" -#include "HTMLNames.h" -#include "HTMLOptionElement.h" -#include "HTMLSelectElement.h" -#include "StringUtils.h" -#include - -using WebCore::Element; -using WebCore::HTMLFormControlElement; -using WebCore::HTMLInputElement; -using WebCore::HTMLOptionElement; -using WebCore::HTMLSelectElement; - -using namespace WebCore::HTMLNames; - -// TODO: This file is taken from chromium/webkit/glue/form_field.cc and -// customised to use WebCore types rather than WebKit API types. It would -// be nice and would ease future merge pain if the two could be combined. - -namespace webkit_glue { - -FormField::FormField() - : max_length_(0), - is_autofilled_(false) { -} - -// TODO: This constructor should probably be deprecated and the -// functionality moved to FormManager. -FormField::FormField(const HTMLFormControlElement& element) - : max_length_(0), - is_autofilled_(false) { - name_ = nameForAutoFill(element); - - // TODO: Extract the field label. For now we just use the field - // name. - label_ = name_; - - form_control_type_ = formControlType(element); - if (form_control_type_ == kText) { - const HTMLInputElement& input_element = static_cast(element); - value_ = WTFStringToString16(input_element.value()); - max_length_ = input_element.size(); - is_autofilled_ = input_element.isAutofilled(); - } else if (form_control_type_ == kSelectOne) { - const HTMLSelectElement& const_select_element = static_cast(element); - HTMLSelectElement& select_element = const_cast(const_select_element); - value_ = WTFStringToString16(select_element.value()); - - // For select-one elements copy option strings. - WTF::Vector list_items = select_element.listItems(); - option_strings_.reserve(list_items.size()); - for (size_t i = 0; i < list_items.size(); ++i) { - if (list_items[i]->hasTagName(optionTag)) - option_strings_.push_back(WTFStringToString16(static_cast(list_items[i])->value())); - } - } - - TrimWhitespace(value_, TRIM_LEADING, &value_); -} - -FormField::FormField(const string16& label, const string16& name, const string16& value, const string16& form_control_type, int max_length, bool is_autofilled) - : label_(label), - name_(name), - value_(value), - form_control_type_(form_control_type), - max_length_(max_length), - is_autofilled_(is_autofilled) { -} - -FormField::~FormField() { -} - -bool FormField::operator==(const FormField& field) const { - // A FormField stores a value, but the value is not part of the identity of - // the field, so we don't want to compare the values. - return (label_ == field.label_ && - name_ == field.name_ && - form_control_type_ == field.form_control_type_ && - max_length_ == field.max_length_); -} - -bool FormField::operator!=(const FormField& field) const { - return !operator==(field); -} - -bool FormField::StrictlyEqualsHack(const FormField& field) const { - return (label_ == field.label_ && - name_ == field.name_ && - value_ == field.value_ && - form_control_type_ == field.form_control_type_ && - max_length_ == field.max_length_); -} - -std::ostream& operator<<(std::ostream& os, const FormField& field) { - return os - << UTF16ToUTF8(field.label()) - << " " - << UTF16ToUTF8(field.name()) - << " " - << UTF16ToUTF8(field.value()) - << " " - << UTF16ToUTF8(field.form_control_type()) - << " " - << field.max_length(); -} - -} // namespace webkit_glue diff --git a/WebKit/android/WebCoreSupport/autofill/FormFieldAndroid.h b/WebKit/android/WebCoreSupport/autofill/FormFieldAndroid.h deleted file mode 100644 index c5e3ecc..0000000 --- a/WebKit/android/WebCoreSupport/autofill/FormFieldAndroid.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (c) 2010 The Chromium Authors. All rights reserved. - * 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 FormFieldAndroid_h -#define FormFieldAndroid_h - -#include -#include - -// TODO: This file is taken from chromium/webkit/glue/form_field.h and -// customised to use WebCore types rather than WebKit API types. It would -// be nice and would ease future merge pain if the two could be combined. - -namespace WebCore { -class HTMLFormControlElement; -} - -namespace webkit_glue { - -// Stores information about a field in a form. -class FormField { -public: - FormField(); - explicit FormField(const WebCore::HTMLFormControlElement& element); - FormField(const string16& label, const string16& name, const string16& value, const string16& form_control_type, int max_length, bool is_autofilled); - virtual ~FormField(); - - const string16& label() const { return label_; } - const string16& name() const { return name_; } - const string16& value() const { return value_; } - const string16& form_control_type() const { return form_control_type_; } - int max_length() const { return max_length_; } - bool is_autofilled() const { return is_autofilled_; } - - // Returns option string for elements for which they make sense (select-one, - // for example) for the rest of elements return an empty array. - const std::vector& option_strings() const { return option_strings_; } - - void set_label(const string16& label) { label_ = label; } - void set_name(const string16& name) { name_ = name; } - void set_value(const string16& value) { value_ = value; } - void set_form_control_type(const string16& form_control_type) { form_control_type_ = form_control_type; } - void set_max_length(int max_length) { max_length_ = max_length; } - void set_autofilled(bool is_autofilled) { is_autofilled_ = is_autofilled; } - void set_option_strings(const std::vector& strings) { option_strings_ = strings; } - - // Equality tests for identity which does not include |value_| or |size_|. - // Use |StrictlyEqualsHack| method to test all members. - // TODO: These operators need to be revised when we implement field - // ids. - bool operator==(const FormField& field) const; - bool operator!=(const FormField& field) const; - - // Test equality of all data members. - // TODO: This will be removed when we implement field ids. - bool StrictlyEqualsHack(const FormField& field) const; - -private: - string16 label_; - string16 name_; - string16 value_; - string16 form_control_type_; - int max_length_; - bool is_autofilled_; - std::vector option_strings_; -}; - -// So we can compare FormFields with EXPECT_EQ(). -std::ostream& operator<<(std::ostream& os, const FormField& field); - -} // namespace webkit_glue - -#endif // WEBKIT_GLUE_FORM_FIELD_H_ diff --git a/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.cpp b/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.cpp deleted file mode 100644 index 9652794..0000000 --- a/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.cpp +++ /dev/null @@ -1,871 +0,0 @@ -/* - * Copyright (c) 2010 The Chromium Authors. All rights reserved. - * 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 "FormManagerAndroid.h" - -#include "DocumentLoader.h" -#include "Element.h" -#include "Frame.h" -#include "FrameLoader.h" -#include "HTMLCollection.h" -#include "HTMLFormControlElement.h" -#include "HTMLFormElement.h" -#include "HTMLInputElement.h" -#include "HTMLLabelElement.h" -#include "HTMLNames.h" -#include "HTMLOptionElement.h" -#include "HTMLSelectElement.h" -#include "Node.h" -#include "NodeList.h" -#include "HTMLCollection.h" -#include "FormAssociatedElement.h" -#include "FormFieldAndroid.h" -#include "QualifiedName.h" -#include "StringUtils.h" - -// TODO: This file is taken from chromium/chrome/renderer/form_manager.cc and -// customised to use WebCore types rather than WebKit API types. It would be -// nice and would ease future merge pain if the two could be combined. - -using webkit_glue::FormData; -using webkit_glue::FormField; -using WebCore::Element; -using WebCore::FormAssociatedElement; -using WebCore::HTMLCollection; -using WebCore::HTMLElement; -using WebCore::HTMLFormControlElement; -using WebCore::HTMLFormElement; -using WebCore::HTMLInputElement; -using WebCore::HTMLLabelElement; -using WebCore::HTMLOptionElement; -using WebCore::HTMLSelectElement; -using WebCore::Node; -using WebCore::NodeList; - -using namespace WebCore::HTMLNames; - -namespace { - -// The number of fields required by AutoFill. Ideally we could send the forms -// to AutoFill no matter how many fields are in the forms; however, finding the -// label for each field is a costly operation and we can't spare the cycles if -// it's not necessary. -// Note the on ANDROID we reduce this from Chromium's 3 as it allows us to -// autofill simple name/email forms for example. This improves the mobile -// device experience where form filling can be time consuming and frustrating. -const size_t kRequiredAutoFillFields = 2; - -// The maximum length allowed for form data. -const size_t kMaxDataLength = 1024; - -// This is a helper function for the FindChildText() function. -// Returns the aggregated values of the descendants or siblings of |node| that -// are non-empty text nodes. This is a faster alternative to |innerText()| for -// performance critical operations. It does a full depth-first search so -// can be used when the structure is not directly known. The text is -// accumulated after the whitespace has been stropped. Search depth is limited -// with the |depth| parameter. -string16 FindChildTextInner(Node* node, int depth) { - string16 element_text; - if (!node || depth <= 0) - return element_text; - - string16 node_text = WTFStringToString16(node->nodeValue()); - TrimWhitespace(node_text, TRIM_ALL, &node_text); - if (!node_text.empty()) - element_text = node_text; - - string16 child_text = FindChildTextInner(node->firstChild(), depth-1); - if (!child_text.empty()) - element_text = element_text + child_text; - - string16 sibling_text = FindChildTextInner(node->nextSibling(), depth-1); - if (!sibling_text.empty()) - element_text = element_text + sibling_text; - - return element_text; -} - -// Returns the node value of the first decendant of |element| that is a -// non-empty text node. "Non-empty" in this case means non-empty after the -// whitespace has been stripped. Search is limited to withing 10 siblings and/or -// descendants. -string16 FindChildText(Element* element) { - Node* child = element->firstChild(); - - const int kChildSearchDepth = 10; - return FindChildTextInner(child, kChildSearchDepth); -} - -string16 InferLabelFromPrevious(const HTMLFormControlElement& element) { - string16 inferred_label; - Node* previous = element.previousSibling(); - if (!previous) - return string16(); - - if (previous->isTextNode()) { - inferred_label = WTFStringToString16(previous->nodeValue()); - TrimWhitespace(inferred_label, TRIM_ALL, &inferred_label); - } - - // If we didn't find text, check for previous paragraph. - // Eg.

Some Text

- // Note the lack of whitespace between

and elements. - if (inferred_label.empty() && previous->isElementNode()) { - Element* element = static_cast(previous); - if (element->hasTagName(pTag)) - inferred_label = FindChildText(element); - } - - // If we didn't find paragraph, check for previous paragraph to this. - // Eg.

Some Text

- // Note the whitespace between

and elements. - if (inferred_label.empty()) { - Node* sibling = previous->previousSibling(); - if (sibling && sibling->isElementNode()) { - Element* element = static_cast(sibling); - if (element->hasTagName(pTag)) - inferred_label = FindChildText(element); - } - } - - // Look for text node prior to tag. - // Eg. Some Text - if (inferred_label.empty()) { - while (inferred_label.empty() && previous) { - if (previous->isTextNode()) { - inferred_label = WTFStringToString16(previous->nodeValue()); - TrimWhitespace(inferred_label, TRIM_ALL, &inferred_label); - } else if (previous->isElementNode()) { - Element* element = static_cast(previous); - if (!element->hasTagName(imgTag)) - break; - } else - break; - previous = previous->previousSibling(); - } - } - - // Look for label node prior to tag. - // Eg. - if (inferred_label.empty()) { - while (inferred_label.empty() && previous) { - if (previous->isTextNode()) { - inferred_label = WTFStringToString16(previous->nodeValue()); - TrimWhitespace(inferred_label, TRIM_ALL, &inferred_label); - } else if (previous->isElementNode()) { - Element* element = static_cast(previous); - if (element->hasTagName(labelTag)) { - inferred_label = FindChildText(element); - } else { - break; - } - } else { - break; - } - - previous = previous->previousSibling(); - } - } - - return inferred_label; -} - -// Helper for |InferLabelForElement()| that infers a label, if possible, from -// surrounding table structure. -// Eg. Some Text -// Eg. Some Text -string16 InferLabelFromTable(const HTMLFormControlElement& element) { - string16 inferred_label; - Node* parent = element.parentNode(); - while (parent && parent->isElementNode() && !static_cast(parent)->hasTagName(tdTag)) - parent = parent->parentNode(); - - // Check all previous siblings, skipping non-element nodes, until we find a - // non-empty text block. - Node* previous = parent; - while(previous) { - if (previous->isElementNode()) { - Element* e = static_cast(previous); - if (e->hasTagName(tdTag)) { - inferred_label = FindChildText(e); - if (!inferred_label.empty()) - break; - } - } - previous = previous->previousSibling(); - } - return inferred_label; -} - -// Helper for |InferLabelForElement()| that infers a label, if possible, from -// a surrounding div table. -// Eg.

Some Text
-string16 InferLabelFromDivTable(const HTMLFormControlElement& element) { - Node* parent = element.parentNode(); - while (parent && parent->isElementNode() && !static_cast(parent)->hasTagName(divTag)) - parent = parent->parentNode(); - - if (!parent || !parent->isElementNode()) - return string16(); - - Element* e = static_cast(parent); - if (!e || !e->hasTagName(divTag)) - return string16(); - - return FindChildText(e); -} - -// Helper for |InferLabelForElement()| that infers a label, if possible, from -// a surrounding definition list. -// Eg.
Some Text
-// Eg.
Some Text
-string16 InferLabelFromDefinitionList(const HTMLFormControlElement& element) { - string16 inferred_label; - Node* parent = element.parentNode(); - while (parent && parent->isElementNode() && !static_cast(parent)->hasTagName(ddTag)) - parent = parent->parentNode(); - - if (parent && parent->isElementNode()) { - Element* element = static_cast(parent); - if (element->hasTagName(ddTag)) { - Node* previous = parent->previousSibling(); - - // Skip by any intervening text nodes. - while (previous && previous->isTextNode()) - previous = previous->previousSibling(); - - if (previous && previous->isElementNode()) { - element = static_cast(previous); - if (element->hasTagName(dtTag)) - inferred_label = FindChildText(element); - } - } - } - return inferred_label; -} - -void GetOptionStringsFromElement(HTMLFormControlElement* element, std::vector* option_strings) { - DCHECK(element); - DCHECK(option_strings); - option_strings->clear(); - if (formControlType(*element) == kSelectOne) { - HTMLSelectElement* select_element = static_cast(element); - - // For select-one elements copy option strings. - WTF::Vector list_items = select_element->listItems(); - option_strings->reserve(list_items.size()); - for (size_t i = 0; i < list_items.size(); ++i) { - if (list_items[i]->hasTagName(optionTag)) - option_strings->push_back(WTFStringToString16(static_cast(list_items[i])->value())); - } - } -} - -} // namespace - -namespace android { - -struct FormManager::FormElement { - RefPtr form_element; - std::vector > control_elements; - std::vector control_values; -}; - -FormManager::FormManager() { -} - -FormManager::~FormManager() { - Reset(); -} - -// static -void FormManager::HTMLFormControlElementToFormField(HTMLFormControlElement* element, ExtractMask extract_mask, FormField* field) { - DCHECK(field); - - // The label is not officially part of a HTMLFormControlElement; however, the - // labels for all form control elements are scraped from the DOM and set in - // WebFormElementToFormData. - field->set_name(nameForAutoFill(*element)); - field->set_form_control_type(formControlType(*element)); - - if (extract_mask & EXTRACT_OPTIONS) { - std::vector option_strings; - GetOptionStringsFromElement(element, &option_strings); - field->set_option_strings(option_strings); - } - - if (formControlType(*element) == kText) { - HTMLInputElement* input_element = static_cast(element); - field->set_max_length(input_element->maxLength()); - field->set_autofilled(input_element->isAutofilled()); - } - - if (!(extract_mask & EXTRACT_VALUE)) - return; - - // TODO: In WebKit, move value() and setValue() to - // WebFormControlElement. - string16 value; - if (formControlType(*element) == kText || - formControlType(*element) == kHidden) { - HTMLInputElement* input_element = static_cast(element); - value = WTFStringToString16(input_element->value()); - } else if (formControlType(*element) == kSelectOne) { - HTMLSelectElement* select_element = static_cast(element); - value = WTFStringToString16(select_element->value()); - - // Convert the |select_element| value to text if requested. - if (extract_mask & EXTRACT_OPTION_TEXT) { - Vector list_items = select_element->listItems(); - for (size_t i = 0; i < list_items.size(); ++i) { - if (list_items[i]->hasTagName(optionTag) && - WTFStringToString16(static_cast(list_items[i])->value()) == value) { - value = WTFStringToString16(static_cast(list_items[i])->text()); - break; - } - } - } - } - - // TODO: This is a temporary stop-gap measure designed to prevent - // a malicious site from DOS'ing the browser with extremely large profile - // data. The correct solution is to parse this data asynchronously. - // See http://crbug.com/49332. - if (value.size() > kMaxDataLength) - value = value.substr(0, kMaxDataLength); - - field->set_value(value); -} - -// static -string16 FormManager::LabelForElement(const HTMLFormControlElement& element) { - // Don't scrape labels for hidden elements. - if (formControlType(element) == kHidden) - return string16(); - - RefPtr labels = element.document()->getElementsByTagName("label"); - for (unsigned i = 0; i < labels->length(); ++i) { - Node* e = labels->item(i); - if (e->hasTagName(labelTag)) { - HTMLLabelElement* label = static_cast(e); - if (label->control() == &element) - return FindChildText(label); - } - } - - // Infer the label from context if not found in label element. - return FormManager::InferLabelForElement(element); -} - -// static -bool FormManager::HTMLFormElementToFormData(HTMLFormElement* element, RequirementsMask requirements, ExtractMask extract_mask, FormData* form) { - DCHECK(form); - - Frame* frame = element->document()->frame(); - if (!frame) - return false; - - if (requirements & REQUIRE_AUTOCOMPLETE && !element->autoComplete()) - return false; - - form->name = WTFStringToString16(element->name()); - form->method = WTFStringToString16(element->method()); - form->origin = GURL(WTFStringToString16(frame->loader()->documentLoader()->url().string())); - form->action = GURL(WTFStringToString16(frame->document()->completeURL(element->action()))); - form->user_submitted = element->wasUserSubmitted(); - - // If the completed URL is not valid, just use the action we get from - // WebKit. - if (!form->action.is_valid()) - form->action = GURL(WTFStringToString16(element->action())); - - // A map from a FormField's name to the FormField itself. - std::map name_map; - - // The extracted FormFields. We use pointers so we can store them in - // |name_map|. - ScopedVector form_fields; - - WTF::Vector control_elements = element->associatedElements(); - - // A vector of bools that indicate whether each field in the form meets the - // requirements and thus will be in the resulting |form|. - std::vector fields_extracted(control_elements.size(), false); - - for (size_t i = 0; i < control_elements.size(); ++i) { - if (!control_elements[i]->isFormControlElement()) - continue; - - HTMLFormControlElement* control_element = static_cast(control_elements[i]); - if (!(control_element->hasTagName(inputTag) || control_element->hasTagName(selectTag))) - continue; - - if (requirements & REQUIRE_AUTOCOMPLETE && - formControlType(*control_element) == kText) { - const WebCore::HTMLInputElement* input_element = static_cast(control_element); - if (!input_element->autoComplete()) - continue; - } - - if (requirements & REQUIRE_ENABLED && !control_element->isEnabledFormControl()) - continue; - - // Create a new FormField, fill it out and map it to the field's name. - FormField* field = new FormField; - HTMLFormControlElementToFormField(control_element, extract_mask, field); - form_fields.push_back(field); - // TODO: A label element is mapped to a form control element's id. - // field->name() will contain the id only if the name does not exist. Add - // an id() method to HTMLFormControlElement and use that here. - name_map[field->name()] = field; - fields_extracted[i] = true; - } - - // Don't extract field labels if we have no fields. - if (form_fields.empty()) - return false; - - // Loop through the label elements inside the form element. For each label - // element, get the corresponding form control element, use the form control - // element's name as a key into the map to find the - // previously created FormField and set the FormField's label to the - // label.firstChild().nodeValue() of the label element. - RefPtr labels = element->getElementsByTagName("label"); - for (unsigned i = 0; i < labels->length(); ++i) { - HTMLLabelElement* label = static_cast(labels->item(i)); - HTMLFormControlElement* field_element = label->control(); - if (!field_element || field_element->type() == "hidden") - continue; - - std::map::iterator iter = - name_map.find(nameForAutoFill(*field_element)); - if (iter != name_map.end()) - iter->second->set_label(FindChildText(label)); - } - - // Loop through the form control elements, extracting the label text from the - // DOM. We use the |fields_extracted| vector to make sure we assign the - // extracted label to the correct field, as it's possible |form_fields| will - // not contain all of the elements in |control_elements|. - for (size_t i = 0, field_idx = 0; i < control_elements.size() && field_idx < form_fields.size(); ++i) { - // This field didn't meet the requirements, so don't try to find a label for - // it. - if (!fields_extracted[i]) - continue; - - if (!control_elements[i]->isFormControlElement()) - continue; - - const HTMLFormControlElement* control_element = static_cast(control_elements[i]); - if (form_fields[field_idx]->label().empty()) - form_fields[field_idx]->set_label(FormManager::InferLabelForElement(*control_element)); - - ++field_idx; - - } - // Copy the created FormFields into the resulting FormData object. - for (ScopedVector::const_iterator iter = form_fields.begin(); iter != form_fields.end(); ++iter) - form->fields.push_back(**iter); - - return true; -} - -void FormManager::ExtractForms(Frame* frame) { - - ResetFrame(frame); - - WTF::PassRefPtr web_forms = frame->document()->forms(); - - for (size_t i = 0; i < web_forms->length(); ++i) { - FormElement* form_element = new FormElement; - HTMLFormElement* html_form_element = static_cast(web_forms->item(i)); - form_element->form_element = html_form_element; - - WTF::Vector control_elements = html_form_element->associatedElements(); - for (size_t j = 0; j < control_elements.size(); ++j) { - if (!control_elements[j]->isFormControlElement()) - continue; - - HTMLFormControlElement* element = static_cast(control_elements[j]); - form_element->control_elements.push_back(element); - - // Save original values of "select-one" inputs so we can restore them - // when |ClearFormWithNode()| is invoked. - if (formControlType(*element) == kSelectOne) { - HTMLSelectElement* select_element = static_cast(element); - string16 value = WTFStringToString16(select_element->value()); - form_element->control_values.push_back(value); - } else - form_element->control_values.push_back(string16()); - } - - form_elements_.push_back(form_element); - } -} - -void FormManager::GetFormsInFrame(const Frame* frame, RequirementsMask requirements, std::vector* forms) { - DCHECK(frame); - DCHECK(forms); - - for (FormElementList::const_iterator form_iter = form_elements_.begin(); form_iter != form_elements_.end(); ++form_iter) { - FormElement* form_element = *form_iter; - - if (form_element->form_element->document()->frame() != frame) - continue; - - // We need at least |kRequiredAutoFillFields| fields before appending this - // form to |forms|. - if (form_element->control_elements.size() < kRequiredAutoFillFields) - continue; - - if (requirements & REQUIRE_AUTOCOMPLETE && !form_element->form_element->autoComplete()) - continue; - - FormData form; - HTMLFormElementToFormData(form_element->form_element.get(), requirements, EXTRACT_VALUE, &form); - if (form.fields.size() >= kRequiredAutoFillFields) - forms->push_back(form); - } -} - -bool FormManager::FindFormWithFormControlElement(HTMLFormControlElement* element, RequirementsMask requirements, FormData* form) { - DCHECK(form); - - const Frame* frame = element->document()->frame(); - if (!frame) - return false; - - for (FormElementList::const_iterator iter = form_elements_.begin(); iter != form_elements_.end(); ++iter) { - const FormElement* form_element = *iter; - - if (form_element->form_element->document()->frame() != frame) - continue; - - for (std::vector >::const_iterator iter = form_element->control_elements.begin(); iter != form_element->control_elements.end(); ++iter) { - HTMLFormControlElement* candidate = iter->get(); - if (nameForAutoFill(*candidate) == nameForAutoFill(*element)) { - ExtractMask extract_mask = static_cast(EXTRACT_VALUE | EXTRACT_OPTIONS); - return HTMLFormElementToFormData(form_element->form_element.get(), requirements, extract_mask, form); - } - } - } - return false; -} - -bool FormManager::FillForm(const FormData& form, Node* node) { - FormElement* form_element = NULL; - if (!FindCachedFormElement(form, &form_element)) - return false; - - RequirementsMask requirements = static_cast(REQUIRE_AUTOCOMPLETE | REQUIRE_ENABLED | REQUIRE_EMPTY); - ForEachMatchingFormField(form_element, node, requirements, form, NewCallback(this, &FormManager::FillFormField)); - - return true; -} - -bool FormManager::PreviewForm(const FormData& form, Node* node) { - FormElement* form_element = NULL; - if (!FindCachedFormElement(form, &form_element)) - return false; - - RequirementsMask requirements = static_cast(REQUIRE_AUTOCOMPLETE | REQUIRE_ENABLED | REQUIRE_EMPTY); - ForEachMatchingFormField(form_element, node, requirements, form, NewCallback(this, &FormManager::PreviewFormField)); - - return true; -} - -bool FormManager::ClearFormWithNode(Node* node) { - FormElement* form_element = NULL; - if (!FindCachedFormElementWithNode(node, &form_element)) - return false; - - for (size_t i = 0; i < form_element->control_elements.size(); ++i) { - HTMLFormControlElement* element = form_element->control_elements[i].get(); - if (formControlType(*element) == kText) { - HTMLInputElement* input_element = static_cast(element); - - // We don't modify the value of disabled fields. - if (!input_element->isEnabledFormControl()) - continue; - - input_element->setValue(""); - input_element->setAutofilled(false); - // Clearing the value in the focused node (above) can cause selection - // to be lost. We force selection range to restore the text cursor. - if (node == input_element) { - int length = input_element->value().length(); - input_element->setSelectionRange(length, length); - } - } else if (formControlType(*element) == kSelectOne) { - HTMLSelectElement* select_element = static_cast(element); - select_element->setValue(form_element->control_values[i].c_str()); - } - } - - return true; -} - -bool FormManager::ClearPreviewedFormWithNode(Node* node, bool was_autofilled) { - FormElement* form_element = NULL; - if (!FindCachedFormElementWithNode(node, &form_element)) - return false; - - for (size_t i = 0; i < form_element->control_elements.size(); ++i) { - HTMLFormControlElement* element = form_element->control_elements[i].get(); - - // Only input elements can be previewed. - if (formControlType(*element) != kText) - continue; - - // If the input element has not been auto-filled, FormManager has not - // previewed this field, so we have nothing to reset. - HTMLInputElement* input_element = static_cast(element); - if (!input_element->isAutofilled()) - continue; - - // There might be unrelated elements in this form which have already been - // auto-filled. For example, the user might have already filled the address - // part of a form and now be dealing with the credit card section. We only - // want to reset the auto-filled status for fields that were previewed. - if (input_element->suggestedValue().isEmpty()) - continue; - - // Clear the suggested value. For the initiating node, also restore the - // original value. - input_element->setSuggestedValue(""); - bool is_initiating_node = (node == input_element); - if (is_initiating_node) { - // Call |setValue()| to force the renderer to update the field's displayed - // value. - input_element->setValue(input_element->value()); - input_element->setAutofilled(was_autofilled); - } else { - input_element->setAutofilled(false); - } - - // Clearing the suggested value in the focused node (above) can cause - // selection to be lost. We force selection range to restore the text - // cursor. - if (is_initiating_node) { - int length = input_element->value().length(); - input_element->setSelectionRange(length, length); - } - } - - return true; -} - -void FormManager::Reset() { - STLDeleteElements(&form_elements_); -} - -void FormManager::ResetFrame(const Frame* frame) { - FormElementList::iterator iter = form_elements_.begin(); - while (iter != form_elements_.end()) { - if ((*iter)->form_element->document()->frame() == frame) { - delete *iter; - iter = form_elements_.erase(iter); - } else - ++iter; - } -} - -bool FormManager::FormWithNodeIsAutoFilled(Node* node) { - FormElement* form_element = NULL; - if (!FindCachedFormElementWithNode(node, &form_element)) - return false; - - for (size_t i = 0; i < form_element->control_elements.size(); ++i) { - HTMLFormControlElement* element = form_element->control_elements[i].get(); - if (formControlType(*element) != kText) - continue; - - HTMLInputElement* input_element = static_cast(element); - if (input_element->isAutofilled()) - return true; - } - - return false; -} - -// static -string16 FormManager::InferLabelForElement(const HTMLFormControlElement& element) { - // Don't scrape labels for hidden elements. - if (formControlType(element) == kHidden) - return string16(); - - string16 inferred_label = InferLabelFromPrevious(element); - - // If we didn't find a label, check for table cell case. - if (inferred_label.empty()) - inferred_label = InferLabelFromTable(element); - - // If we didn't find a label, check for div table case. - if (inferred_label.empty()) - inferred_label = InferLabelFromDivTable(element); - - // If we didn't find a label, check for definition list case. - if (inferred_label.empty()) - inferred_label = InferLabelFromDefinitionList(element); - - return inferred_label; -} - -bool FormManager::FindCachedFormElementWithNode(Node* node, - FormElement** form_element) { - for (FormElementList::const_iterator form_iter = form_elements_.begin(); form_iter != form_elements_.end(); ++form_iter) { - for (std::vector >::const_iterator iter = (*form_iter)->control_elements.begin(); iter != (*form_iter)->control_elements.end(); ++iter) { - if (iter->get() == node) { - *form_element = *form_iter; - return true; - } - } - } - - return false; -} - -bool FormManager::FindCachedFormElement(const FormData& form, FormElement** form_element) { - for (FormElementList::iterator form_iter = form_elements_.begin(); form_iter != form_elements_.end(); ++form_iter) { - // TODO: matching on form name here which is not guaranteed to - // be unique for the page, nor is it guaranteed to be non-empty. Need to - // find a way to uniquely identify the form cross-process. For now we'll - // check form name and form action for identity. - // http://crbug.com/37990 test file sample8.html. - // Also note that WebString() == WebString(string16()) does not seem to - // evaluate to |true| for some reason TBD, so forcing to string16. - string16 element_name(WTFStringToString16((*form_iter)->form_element->name())); - GURL action(WTFStringToString16((*form_iter)->form_element->document()->completeURL((*form_iter)->form_element->action()).string())); - if (element_name == form.name && action == form.action) { - *form_element = *form_iter; - return true; - } - } - - return false; -} - - -void FormManager::ForEachMatchingFormField(FormElement* form, Node* node, RequirementsMask requirements, const FormData& data, Callback* callback) { - // It's possible that the site has injected fields into the form after the - // page has loaded, so we can't assert that the size of the cached control - // elements is equal to the size of the fields in |form|. Fortunately, the - // one case in the wild where this happens, paypal.com signup form, the fields - // are appended to the end of the form and are not visible. - for (size_t i = 0, j = 0; i < form->control_elements.size() && j < data.fields.size(); ++i) { - HTMLFormControlElement* element = form->control_elements[i].get(); - string16 element_name = nameForAutoFill(*element); - - if (element_name.empty()) - continue; - - // Search forward in the |form| for a corresponding field. - size_t k = j; - while (k < data.fields.size() && element_name != data.fields[k].name()) - k++; - - if (k >= data.fields.size()) - continue; - - DCHECK_EQ(data.fields[k].name(), element_name); - - bool is_initiating_node = false; - - // More than likely |requirements| will contain REQUIRE_AUTOCOMPLETE and/or - // REQUIRE_EMPTY, which both require text form control elements, so special- - // case this type of element. - if (formControlType(*element) == kText) { - HTMLInputElement* input_element = static_cast(element); - - // TODO: WebKit currently doesn't handle the autocomplete - // attribute for select control elements, but it probably should. - if (requirements & REQUIRE_AUTOCOMPLETE && !input_element->autoComplete()) - continue; - - is_initiating_node = (input_element == node); - // Don't require the node that initiated the auto-fill process to be - // empty. The user is typing in this field and we should complete the - // value when the user selects a value to fill out. - if (requirements & REQUIRE_EMPTY && !is_initiating_node && !input_element->value().isEmpty()) - continue; - } - - if (requirements & REQUIRE_ENABLED && !element->isEnabledFormControl()) - continue; - - callback->Run(element, &data.fields[k], is_initiating_node); - - // We found a matching form field so move on to the next. - ++j; - } - - delete callback; -} - -void FormManager::FillFormField(HTMLFormControlElement* field, const FormField* data, bool is_initiating_node) { - // Nothing to fill. - if (data->value().empty()) - return; - - if (formControlType(*field) == kText) { - HTMLInputElement* input_element = static_cast(field); - - // If the maxlength attribute contains a negative value, maxLength() - // returns the default maxlength value. - input_element->setValue(data->value().substr(0, input_element->maxLength()).c_str()); - input_element->setAutofilled(true); - if (is_initiating_node) { - int length = input_element->value().length(); - input_element->setSelectionRange(length, length); - } - } else if (formControlType(*field) == kSelectOne) { - HTMLSelectElement* select_element = static_cast(field); - select_element->setValue(data->value().c_str()); - } -} - -void FormManager::PreviewFormField(HTMLFormControlElement* field, const FormField* data, bool is_initiating_node) { - // Nothing to preview. - if (data->value().empty()) - return; - - // Only preview input fields. - if (formControlType(*field) != kText) - return; - - HTMLInputElement* input_element = static_cast(field); - - // If the maxlength attribute contains a negative value, maxLength() - // returns the default maxlength value. - input_element->setSuggestedValue(data->value().substr(0, input_element->maxLength()).c_str()); - input_element->setAutofilled(true); - if (is_initiating_node) - input_element->setSelectionRange(0, input_element->suggestedValue().length()); -} - -} diff --git a/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.h b/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.h deleted file mode 100644 index e844981..0000000 --- a/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.h +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright (c) 2010 The Chromium Authors. All rights reserved. - * 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 FormManagerAndroid_h -#define FormManagerAndroid_h - -#include "ChromiumIncludes.h" - -#include -#include - -// TODO: This file is taken from chromium/chrome/renderer/form_manager.h and -// customised to use WebCore types rather than WebKit API types. It would be -// nice and would ease future merge pain if the two could be combined. - -namespace webkit_glue { -struct FormData; -class FormField; -} // namespace webkit_glue - -namespace WebCore { -class Frame; -class HTMLFormControlElement; -class HTMLFormElement; -class Node; -} - -using WebCore::Frame; -using WebCore::HTMLFormControlElement; -using WebCore::HTMLFormElement; -using WebCore::Node; - -namespace android { - -// Manages the forms in a Document. -class FormManager { -public: - // A bit field mask for form requirements. - enum RequirementsMask { - REQUIRE_NONE = 0, // No requirements. - REQUIRE_AUTOCOMPLETE = 1 << 0, // Require that autocomplete != off. - REQUIRE_ENABLED = 1 << 1, // Require that disabled attribute is off. - REQUIRE_EMPTY = 1 << 2, // Require that the fields are empty. - }; - - // A bit field mask to extract data from HTMLFormControlElement. - enum ExtractMask { - EXTRACT_NONE = 0, - EXTRACT_VALUE = 1 << 0, // Extract value from HTMLFormControlElement. - EXTRACT_OPTION_TEXT = 1 << 1, // Extract option text from HTMLFormSelectElement. Only valid when |EXTRACT_VALUE| is set. This is used for form submission where humand readable value is captured. - EXTRACT_OPTIONS = 1 << 2, // Extract options from HTMLFormControlElement. - }; - - FormManager(); - virtual ~FormManager(); - - // Fills out a FormField object from a given HTMLFormControlElement. - // |extract_mask|: See the enum ExtractMask above for details. - static void HTMLFormControlElementToFormField(HTMLFormControlElement* element, ExtractMask extract_mask, webkit_glue::FormField* field); - - // Returns the corresponding label for |element|. WARNING: This method can - // potentially be very slow. Do not use during any code paths where the page - // is loading. - static string16 LabelForElement(const HTMLFormControlElement& element); - - // Fills out a FormData object from a given WebFormElement. If |get_values| - // is true, the fields in |form| will have the values filled out. Returns - // true if |form| is filled out; it's possible that |element| won't meet the - // requirements in |requirements|. This also returns false if there are no - // fields in |form|. - // TODO: Remove the user of this in RenderView and move this to - // private. - static bool HTMLFormElementToFormData(HTMLFormElement* element, RequirementsMask requirements, ExtractMask extract_mask, webkit_glue::FormData* form); - - // Scans the DOM in |frame| extracting and storing forms. - void ExtractForms(Frame* frame); - - // Returns a vector of forms in |frame| that match |requirements|. - void GetFormsInFrame(const Frame* frame, RequirementsMask requirements, std::vector* forms); - - // Finds the form that contains |element| and returns it in |form|. Returns - // false if the form is not found. - bool FindFormWithFormControlElement(HTMLFormControlElement* element, RequirementsMask requirements, webkit_glue::FormData* form); - - // Fills the form represented by |form|. |form| should have the name set to - // the name of the form to fill out, and the number of elements and values - // must match the number of stored elements in the form. |node| is the form - // control element that initiated the auto-fill process. - // TODO: Is matching on name alone good enough? It's possible to - // store multiple forms with the same names from different frames. - bool FillForm(const webkit_glue::FormData& form, Node* node); - - // Previews the form represented by |form|. |node| is the form control element - // that initiated the preview process. Same conditions as FillForm. - bool PreviewForm(const webkit_glue::FormData& form, Node* node); - - // Clears the values of all input elements in the form that contains |node|. - // Returns false if the form is not found. - bool ClearFormWithNode(Node* node); - - // Clears the placeholder values and the auto-filled background for any fields - // in the form containing |node| that have been previewed. Resets the - // autofilled state of |node| to |was_autofilled|. Returns false if the form - // is not found. - bool ClearPreviewedFormWithNode(Node* node, bool was_autofilled); - - // Resets the stored set of forms. - void Reset(); - - // Resets the forms for the specified |frame|. - void ResetFrame(const Frame* frame); - - // Returns true if |form| has any auto-filled fields. - bool FormWithNodeIsAutoFilled(Node* node); - -private: - // Stores the HTMLFormElement and the form control elements for a form. - // Original form values are stored so when we clear a form we can reset - // "select-one" values to their original state. - struct FormElement; - - // Type for cache of FormElement objects. - typedef std::vector FormElementList; - - // The callback type used by ForEachMatchingFormField(). - typedef Callback3::Type Callback; - - // Infers corresponding label for |element| from surrounding context in the - // DOM. Contents of preceeding

tag or preceeding text element found in - // the form. - static string16 InferLabelForElement(const HTMLFormControlElement& element); - - // Finds the cached FormElement that contains |node|. - bool FindCachedFormElementWithNode(Node* node, FormElement** form_element); - - // Uses the data in |form| to find the cached FormElement. - bool FindCachedFormElement(const webkit_glue::FormData& form, FormElement** form_element); - - // For each field in |data| that matches the corresponding field in |form| - // and meets the |requirements|, |callback| is called with the actual - // WebFormControlElement and the FormField data from |form|. The field that - // matches |node| is not required to be empty if |requirements| includes - // REQUIRE_EMPTY. This method owns |callback|. - void ForEachMatchingFormField(FormElement* form, Node* node, RequirementsMask requirements, const webkit_glue::FormData& data, Callback* callback); - - // A ForEachMatchingFormField() callback that sets |field|'s value using the - // value in |data|. This method also sets the autofill attribute, causing the - // background to be yellow. - void FillFormField(HTMLFormControlElement* field, const webkit_glue::FormField* data, bool is_initiating_node); - - // A ForEachMatchingFormField() callback that sets |field|'s placeholder value - // using the value in |data|, causing the test to be greyed-out. This method - // also sets the autofill attribute, causing the background to be yellow. - void PreviewFormField(HTMLFormControlElement* field, const webkit_glue::FormField* data, bool is_initiaiting_node); - - // The cached FormElement objects. - FormElementList form_elements_; - - DISALLOW_COPY_AND_ASSIGN(FormManager); -}; - -} // namespace android - -#endif // FormManagerAndroid_h diff --git a/WebKit/android/WebCoreSupport/autofill/MainThreadProxy.cpp b/WebKit/android/WebCoreSupport/autofill/MainThreadProxy.cpp deleted file mode 100644 index 598b9c4..0000000 --- a/WebKit/android/WebCoreSupport/autofill/MainThreadProxy.cpp +++ /dev/null @@ -1,35 +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 "MainThreadProxy.h" - -#include - -void MainThreadProxy::CallOnMainThread(CallOnMainThreadFunction f, void* c) -{ - callOnMainThread(f, c); -} diff --git a/WebKit/android/WebCoreSupport/autofill/MainThreadProxy.h b/WebKit/android/WebCoreSupport/autofill/MainThreadProxy.h deleted file mode 100644 index d9310bb..0000000 --- a/WebKit/android/WebCoreSupport/autofill/MainThreadProxy.h +++ /dev/null @@ -1,37 +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 MAIN_THREAD_PROXY_H -#define MAIN_THREAD_PROXY_H - -typedef void CallOnMainThreadFunction(void*); - -class MainThreadProxy -{ -public: - static void CallOnMainThread(CallOnMainThreadFunction, void*); -}; - -#endif diff --git a/WebKit/android/WebCoreSupport/autofill/StringUtils.h b/WebKit/android/WebCoreSupport/autofill/StringUtils.h deleted file mode 100644 index aa408a5..0000000 --- a/WebKit/android/WebCoreSupport/autofill/StringUtils.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2010 The Android Open Source Project. 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. - * - * 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 AutoFillStringUtils_h_ -#define AutoFillStringUtils_h_ - -#include "ChromiumIncludes.h" -#include "HTMLFormControlElement.h" -#include - -using WebCore::HTMLFormControlElement; - -const string16 kText = ASCIIToUTF16("text"); -const string16 kHidden = ASCIIToUTF16("hidden"); -const string16 kSelectOne = ASCIIToUTF16("select-one"); - -inline string16 WTFStringToString16(const WTF::String& wtfString) -{ - WTF::String str = wtfString; - - if (str.charactersWithNullTermination()) - return string16(str.charactersWithNullTermination()); - else - return string16(); -} - -inline string16 nameForAutoFill(const HTMLFormControlElement& element) -{ - // Taken from WebKit/chromium/src/WebFormControlElement.cpp, ported - // to use WebCore types for accessing element properties. - String name = element.name(); - String trimmedName = name.stripWhiteSpace(); - if (!trimmedName.isEmpty()) - return WTFStringToString16(trimmedName); - name = element.getIdAttribute(); - trimmedName = name.stripWhiteSpace(); - if (!trimmedName.isEmpty()) - return WTFStringToString16(trimmedName); - return string16(); -} - -inline string16 formControlType(const HTMLFormControlElement& element) -{ - // Taken from WebKit/chromium/src/WebFormControlElement.cpp, ported - // to use WebCore types for accessing element properties. - return WTFStringToString16(element.type()); -} - -#endif - diff --git a/WebKit/android/WebCoreSupport/autofill/WebAutoFill.cpp b/WebKit/android/WebCoreSupport/autofill/WebAutoFill.cpp deleted file mode 100644 index a80636c..0000000 --- a/WebKit/android/WebCoreSupport/autofill/WebAutoFill.cpp +++ /dev/null @@ -1,296 +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 "WebAutoFill.h" - -#if ENABLE(WEB_AUTOFILL) - -#include "AutoFillHostAndroid.h" -#include "Frame.h" -#include "FormData.h" -#include "FormManagerAndroid.h" -#include "FrameLoader.h" -#include "HTMLFormControlElement.h" -#include "MainThreadProxy.h" -#include "Node.h" -#include "Page.h" -#include "Settings.h" -#include "WebFrame.h" -#include "WebRequestContext.h" -#include "WebUrlLoaderClient.h" -#include "WebViewCore.h" - -#define NO_PROFILE_SET 0 -#define FORM_NOT_AUTOFILLABLE -1 - -namespace android -{ -WebAutoFill::WebAutoFill() - : mQueryId(1) - , mWebViewCore(0) - , mLastSearchDomVersion(0) - , mParsingForms(false) -{ - mTabContents = new TabContents(); - setEmptyProfile(); -} - -void WebAutoFill::init() -{ - if (mAutoFillManager) - return; - - mFormManager = new FormManager(); - // We use the WebView's WebRequestContext, which may be a private browsing context. - ASSERT(mWebViewCore); - mAutoFillManager = new AutoFillManager(mTabContents.get()); - mAutoFillHost = new AutoFillHostAndroid(this); - mTabContents->SetProfileRequestContext(new AndroidURLRequestContextGetter(mWebViewCore->webRequestContext(), WebUrlLoaderClient::ioThread())); - mTabContents->SetAutoFillHost(mAutoFillHost.get()); -} - -WebAutoFill::~WebAutoFill() -{ - cleanUpQueryMap(); - mUniqueIdMap.clear(); -} - -void WebAutoFill::cleanUpQueryMap() -{ - for (AutoFillQueryFormDataMap::iterator it = mQueryMap.begin(); it != mQueryMap.end(); it++) - delete it->second; - mQueryMap.clear(); -} - -void WebAutoFill::searchDocument(WebCore::Frame* frame) -{ - if (!enabled()) - return; - - MutexLocker lock(mFormsSeenMutex); - - init(); - - cleanUpQueryMap(); - mUniqueIdMap.clear(); - mForms.clear(); - mQueryId = 1; - - ASSERT(mFormManager); - ASSERT(mAutoFillManager); - - mAutoFillManager->Reset(); - mFormManager->Reset(); - - mFormManager->ExtractForms(frame); - mFormManager->GetFormsInFrame(frame, FormManager::REQUIRE_AUTOCOMPLETE, &mForms); - - // Needs to be done on a Chrome thread as it will make a URL request to the AutoFill server. - // TODO: Use our own Autofill thread instead of the IO thread. - // TODO: For now, block here. Would like to make this properly async. - base::Thread* thread = WebUrlLoaderClient::ioThread(); - mParsingForms = true; - thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this, &WebAutoFill::formsSeenImpl)); - while (mParsingForms) - mFormsSeenCondition.wait(mFormsSeenMutex); -} - -// Called on the Chromium IO thread. -void WebAutoFill::formsSeenImpl() -{ - MutexLocker lock(mFormsSeenMutex); - mAutoFillManager->FormsSeen(mForms); - mParsingForms = false; - mFormsSeenCondition.signal(); -} - -void WebAutoFill::formFieldFocused(WebCore::HTMLFormControlElement* formFieldElement) -{ - ASSERT(formFieldElement); - - Document* doc = formFieldElement->document(); - Frame* frame = doc->frame(); - - // FIXME: AutoFill only works in main frame for now. Should consider - // child frames. - if (frame != frame->page()->mainFrame()) - return; - - unsigned domVersion = doc->domTreeVersion(); - ASSERT(domVersion > 0); - - if (mLastSearchDomVersion != domVersion) { - // Need to extract forms as DOM version has changed since the last time - // we searched. - searchDocument(formFieldElement->document()->frame()); - mLastSearchDomVersion = domVersion; - } - - if (!enabled()) { - // In case that we've just been disabled and the last time we got autofill - // suggestions and told Java about them, clear that bit Java side now - // we're disabled. - mWebViewCore->setWebTextViewAutoFillable(FORM_NOT_AUTOFILLABLE, string16()); - return; - } - - // Get the FormField from the Node. - webkit_glue::FormField* formField = new webkit_glue::FormField; - FormManager::HTMLFormControlElementToFormField(formFieldElement, FormManager::EXTRACT_NONE, formField); - formField->set_label(FormManager::LabelForElement(*formFieldElement)); - - webkit_glue::FormData* form = new webkit_glue::FormData; - mFormManager->FindFormWithFormControlElement(formFieldElement, FormManager::REQUIRE_AUTOCOMPLETE, form); - mQueryMap[mQueryId] = new FormDataAndField(form, formField); - - bool suggestions = mAutoFillManager->GetAutoFillSuggestions(*form, *formField); - - mQueryId++; - if (!suggestions) { - ASSERT(mWebViewCore); - // Tell Java no autofill suggestions for this form. - mWebViewCore->setWebTextViewAutoFillable(FORM_NOT_AUTOFILLABLE, string16()); - return; - } -} - -void WebAutoFill::querySuccessful(const string16& value, const string16& label, int uniqueId) -{ - if (!enabled()) - return; - - // Store the unique ID for the query and inform java that autofill suggestions for this form are available. - // Pass java the queryId so that it can pass it back if the user decides to use autofill. - mUniqueIdMap[mQueryId] = uniqueId; - - ASSERT(mWebViewCore); - mWebViewCore->setWebTextViewAutoFillable(mQueryId, mAutoFillProfile->Label()); -} - -void WebAutoFill::fillFormFields(int queryId) -{ - if (!enabled()) - return; - - webkit_glue::FormData* form = mQueryMap[queryId]->form(); - webkit_glue::FormField* field = mQueryMap[queryId]->field(); - ASSERT(form); - ASSERT(field); - - AutoFillQueryToUniqueIdMap::iterator iter = mUniqueIdMap.find(queryId); - if (iter == mUniqueIdMap.end()) { - // The user has most likely tried to AutoFill the form again without - // refocussing the form field. The UI should protect against this - // but stop here to be certain. - return; - } - mAutoFillManager->FillAutoFillFormData(queryId, *form, *field, iter->second); - mUniqueIdMap.erase(iter); -} - -void WebAutoFill::fillFormInPage(int queryId, const webkit_glue::FormData& form) -{ - if (!enabled()) - return; - - // FIXME: Pass a pointer to the Node that triggered the AutoFill flow here instead of 0. - // The consquence of passing 0 is that we should always fail the test in FormManader::ForEachMathcingFormField():169 - // that says "only overwrite an elements current value if the user triggered autofill through that element" - // for elements that have a value already. But by a quirk of Android text views we are OK. We should still - // fix this though. - mFormManager->FillForm(form, 0); -} - -bool WebAutoFill::enabled() const -{ - Page* page = mWebViewCore->mainFrame()->page(); - return page ? page->settings()->autoFillEnabled() : false; -} - -void WebAutoFill::setProfile(const string16& fullName, const string16& emailAddress, const string16& companyName, - const string16& addressLine1, const string16& addressLine2, const string16& city, - const string16& state, const string16& zipCode, const string16& country, const string16& phoneNumber) -{ - if (!mAutoFillProfile) - mAutoFillProfile.set(new AutoFillProfile()); - - // Update the profile. - // Constants for AutoFill field types are found in external/chromium/chrome/browser/autofill/field_types.h. - mAutoFillProfile->SetInfo(AutoFillType(NAME_FULL), fullName); - mAutoFillProfile->SetInfo(AutoFillType(EMAIL_ADDRESS), emailAddress); - mAutoFillProfile->SetInfo(AutoFillType(COMPANY_NAME), companyName); - mAutoFillProfile->SetInfo(AutoFillType(ADDRESS_HOME_LINE1), addressLine1); - mAutoFillProfile->SetInfo(AutoFillType(ADDRESS_HOME_LINE2), addressLine2); - mAutoFillProfile->SetInfo(AutoFillType(ADDRESS_HOME_CITY), city); - mAutoFillProfile->SetInfo(AutoFillType(ADDRESS_HOME_STATE), state); - mAutoFillProfile->SetInfo(AutoFillType(ADDRESS_HOME_ZIP), zipCode); - mAutoFillProfile->SetInfo(AutoFillType(ADDRESS_HOME_COUNTRY), country); - mAutoFillProfile->SetInfo(AutoFillType(PHONE_HOME_WHOLE_NUMBER), phoneNumber); - - std::vector profiles; - profiles.push_back(*mAutoFillProfile); - updateProfileLabel(); - mTabContents->profile()->GetPersonalDataManager()->SetProfiles(&profiles); -} - -bool WebAutoFill::updateProfileLabel() -{ - std::vector profiles; - profiles.push_back(mAutoFillProfile.get()); - return AutoFillProfile::AdjustInferredLabels(&profiles); -} - -void WebAutoFill::clearProfiles() -{ - if (!mAutoFillProfile) - return; - // For now Chromium only ever knows about one profile, so we can just - // remove it. If we support multiple profiles in the future - // we need to remove them all here. - std::string profileGuid = mAutoFillProfile->guid(); - mTabContents->profile()->GetPersonalDataManager()->RemoveProfile(profileGuid); - setEmptyProfile(); -} - -void WebAutoFill::setEmptyProfile() -{ - // Set an empty profile. This will ensure that when autofill is enabled, - // we will still search the document for autofillable forms and inform - // java of their presence so we can invite the user to set up - // their own profile. - - // Chromium code will strip the values sent into the profile so we need them to be - // at least one non-whitespace character long. We need to set all fields of the - // profile to a non-empty string so that any field type can trigger the autofill - // suggestion. AutoFill will not detect form fields if the profile value for that - // field is an empty string. - static const string16 empty = string16(ASCIIToUTF16("a")); - setProfile(empty, empty, empty, empty, empty, empty, empty, empty, empty, empty); -} - -} - -#endif diff --git a/WebKit/android/WebCoreSupport/autofill/WebAutoFill.h b/WebKit/android/WebCoreSupport/autofill/WebAutoFill.h deleted file mode 100644 index 97e478e..0000000 --- a/WebKit/android/WebCoreSupport/autofill/WebAutoFill.h +++ /dev/null @@ -1,127 +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 WebAutoFill_h -#define WebAutoFill_h - -#if ENABLE(WEB_AUTOFILL) - -#include "ChromiumIncludes.h" - -#include -#include -#include -#include -#include - -class AutoFillManager; -class AutoFillProfile; -class AutoFillHost; - -namespace WebCore { -class Frame; -class HTMLFormControlElement; -} - -namespace android -{ -class FormManager; -class WebViewCore; - -class FormDataAndField { -public: - FormDataAndField(webkit_glue::FormData* form, webkit_glue::FormField* field) - : mForm(form) - , mField(field) - { - } - - webkit_glue::FormData* form() { return mForm.get(); } - webkit_glue::FormField* field() { return mField.get(); } - -private: - OwnPtr mForm; - OwnPtr mField; -}; - -class WebAutoFill : public Noncopyable -{ -public: - WebAutoFill(); - virtual ~WebAutoFill(); - void formFieldFocused(WebCore::HTMLFormControlElement*); - void fillFormFields(int queryId); - void querySuccessful(const string16& value, const string16& label, int uniqueId); - void fillFormInPage(int queryId, const webkit_glue::FormData& form); - void setWebViewCore(WebViewCore* webViewCore) { mWebViewCore = webViewCore; } - bool enabled() const; - - void setProfile(const string16& fullName, const string16& emailAddress, const string16& companyName, - const string16& addressLine1, const string16& addressLine2, const string16& city, - const string16& state, const string16& zipCode, const string16& country, const string16& phoneNumber); - void clearProfiles(); - - bool updateProfileLabel(); - - void reset() { mLastSearchDomVersion = 0; } - -private: - void init(); - void searchDocument(WebCore::Frame*); - void setEmptyProfile(); - void formsSeenImpl(); - void cleanUpQueryMap(); - - OwnPtr mFormManager; - OwnPtr mAutoFillManager; - OwnPtr mAutoFillHost; - OwnPtr mTabContents; - OwnPtr mAutoFillProfile; - - typedef std::vector > FormList; - FormList mForms; - - typedef std::map AutoFillQueryFormDataMap; - AutoFillQueryFormDataMap mQueryMap; - - typedef std::map AutoFillQueryToUniqueIdMap; - AutoFillQueryToUniqueIdMap mUniqueIdMap; - int mQueryId; - - WebViewCore* mWebViewCore; - - unsigned mLastSearchDomVersion; - - WTF::Mutex mFormsSeenMutex; // Guards mFormsSeenCondition and mParsingForms. - WTF::ThreadCondition mFormsSeenCondition; - bool volatile mParsingForms; -}; - -} - -DISABLE_RUNNABLE_METHOD_REFCOUNT(android::WebAutoFill); - -#endif // ENABLE(WEB_AUTOFILL) -#endif // WebAutoFill_h diff --git a/WebKit/android/benchmark/Android.mk b/WebKit/android/benchmark/Android.mk deleted file mode 100644 index 5b189e1..0000000 --- a/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/WebKit/android/benchmark/Intercept.cpp b/WebKit/android/benchmark/Intercept.cpp deleted file mode 100644 index deffac2..0000000 --- a/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 -#include -#include -#include - -PassRefPtr MyResourceLoader::create( - ResourceHandle* handle, String url) -{ - return adoptRef( - 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 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 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 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 MyWebFrame::startLoadingResource( - ResourceHandle* handle, const ResourceRequest& req, bool ignore, - bool ignore2) -{ - RefPtr 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*) -{ - LOGD("Handling requests..."); - Vector > reqs; - reqs.swap(m_requests); - Vector >::iterator i = reqs.begin(); - Vector >::iterator end = reqs.end(); - for (; i != end; i++) - static_cast((*i).get())->handleRequest(); - - LOGD("...done"); -} diff --git a/WebKit/android/benchmark/Intercept.h b/WebKit/android/benchmark/Intercept.h deleted file mode 100644 index edd5123..0000000 --- a/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 -#include - -namespace WebCore { - class Page; - class ResourceHandle; - class ResourceRequest; -} - -using namespace android; -using namespace WebCore; -using namespace WTF; - -class MyResourceLoader : public WebCoreResourceLoader { -public: - static PassRefPtr 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 startLoadingResource( - ResourceHandle* handle, const ResourceRequest& req, bool, bool); - - virtual bool canHandleRequest(const ResourceRequest&) { return true; } - -private: - void timerFired(Timer*); - Vector > m_requests; - Timer m_timer; -}; - -#endif diff --git a/WebKit/android/benchmark/MyJavaVM.cpp b/WebKit/android/benchmark/MyJavaVM.cpp deleted file mode 100644 index 574c745..0000000 --- a/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 -#include - -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/WebKit/android/benchmark/MyJavaVM.h b/WebKit/android/benchmark/MyJavaVM.h deleted file mode 100644 index 36d478d..0000000 --- a/WebKit/android/benchmark/MyJavaVM.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2009, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef MY_JAVA_VM_H -#define MY_JAVA_VM_H - -// Make it 1 just to appease any assertions or checks for valid objects -#define MY_JOBJECT ((jobject) 1) - -void InitializeJavaVM(); - -#endif diff --git a/WebKit/android/benchmark/main.cpp b/WebKit/android/benchmark/main.cpp deleted file mode 100644 index fcb797d..0000000 --- a/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 -#include -#include -#include - -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/WebKit/android/icu/unicode/ucnv.cpp b/WebKit/android/icu/unicode/ucnv.cpp deleted file mode 100644 index 1b40573..0000000 --- a/WebKit/android/icu/unicode/ucnv.cpp +++ /dev/null @@ -1,50 +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. - */ - -// BEGIN android-added -// Add config.h to avoid compiler error in uobject.h -// ucnv.h includes uobject.h indirectly and uobjetcs.h defines new/delete. -// new/delete are also defined in WebCorePrefix.h which auto included in Android make. -// -// config.h has to be on top of the include list. -#include "config.h" -// END android-added - -#include "EmojiFont.h" -#include - -namespace android { - -U_STABLE UConverter* U_EXPORT2 -ucnv_open_emoji(const char *converterName, UErrorCode *err) { - if (EmojiFont::IsAvailable()) { - if (strcmp(converterName, "Shift_JIS") == 0) { - converterName = EmojiFont::GetShiftJisConverterName(); - } - } - return ucnv_open(converterName, err); -} - -} // end namespace android diff --git a/WebKit/android/icu/unicode/ucnv.h b/WebKit/android/icu/unicode/ucnv.h deleted file mode 100644 index 5ddaedb..0000000 --- a/WebKit/android/icu/unicode/ucnv.h +++ /dev/null @@ -1,47 +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 ANDROID_UCNV_H -#define ANDROID_UCNV_H - -// Include the real ucnv.h file from icu. Use a more exact reference so we do -// not conflict with this file. -#include - -namespace android { - -U_STABLE UConverter* U_EXPORT2 -ucnv_open_emoji(const char *converterName, UErrorCode *err); - -} - -// Redefine ucnv_open to android::ucnv_open_emoji. This relies heavily on the -// fact that this file will be included before any of the real icu headers. -// This is done in Android.mk by including WebKit/android/icu before the -// regular icu directory. -#undef ucnv_open -#define ucnv_open android::ucnv_open_emoji - -#endif diff --git a/WebKit/android/jni/CacheManager.cpp b/WebKit/android/jni/CacheManager.cpp deleted file mode 100644 index 144b62a..0000000 --- a/WebKit/android/jni/CacheManager.cpp +++ /dev/null @@ -1,143 +0,0 @@ -/* - * 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" - -#if USE(CHROME_NETWORK_STACK) - -#include "ChromiumIncludes.h" -#include "WebCache.h" -#include "WebCoreJni.h" - -#include -#include -#include -#include -#include - -using namespace WebCore; -using namespace base; -using namespace disk_cache; -using namespace net; -using namespace std; - -namespace android { - -// JNI for android.webkit.CacheManager -static const char* javaCacheManagerClass = "android/webkit/CacheManager"; - -static void setStringField(JNIEnv* env, const jobject& object, const jfieldID& field, const String& str) -{ - jstring jstr = wtfStringToJstring(env, str); - env->SetObjectField(object, field, jstr); - env->DeleteLocalRef(jstr); -} - -static void setFieldFromHeaderIfPresent(CacheResult* result, const char* header, JNIEnv* env, const jobject& object, const jfieldID& field, bool allowEmptyString) -{ - String value; - if (result->firstResponseHeader(header, &value, allowEmptyString)) - setStringField(env, object, field, value); -} - -static String getCacheFileBaseDir(JNIEnv* env) -{ - static String baseDir; - if (baseDir.isEmpty()) { - jclass cacheManagerClass = env->FindClass("android/webkit/CacheManager"); - jmethodID getCacheFileBaseDirMethod = env->GetStaticMethodID(cacheManagerClass, "getCacheFileBaseDir", "()Ljava/io/File;"); - jclass fileClass = env->FindClass("java/io/File"); - jmethodID getPathMethod = env->GetMethodID(fileClass, "getPath", "()Ljava/lang/String;"); - jobject fileObject = env->CallStaticObjectMethod(cacheManagerClass, getCacheFileBaseDirMethod); - baseDir = jstringToWtfString(env, static_cast(env->CallObjectMethod(fileObject, getPathMethod))); - } - return baseDir; -} - -static jobject getCacheResult(JNIEnv* env, jobject, jstring url) -{ - // This is called on the UI thread. - scoped_refptr result = WebCache::get(false /*privateBrowsing*/)->getCacheResult(jstringToWtfString(env, url)); - if (!result) - return 0; - - // We create and populate a file with the cache entry. This allows us to - // replicate the behaviour of the Android HTTP stack in the Java - // CacheManager, which opens the cache file and provides an input stream to - // the file as part of the Java CacheResult object! - String urlWtfString = jstringToWtfString(env, url); - Vector encodedUrl; - base64Encode(urlWtfString.utf8().data(), urlWtfString.length(), encodedUrl, false /*insertLFs*/); - String filePath = pathByAppendingComponent(getCacheFileBaseDir(env), encodedUrl.data()); - if (!result->writeToFile(filePath)) - return 0; - - jclass cacheResultClass = env->FindClass("android/webkit/CacheManager$CacheResult"); - jmethodID constructor = env->GetMethodID(cacheResultClass, "", "()V"); - // We only bother with the fields that are made accessible through the public API. - jfieldID contentdispositionField = env->GetFieldID(cacheResultClass, "contentdisposition", "Ljava/lang/String;"); - jfieldID contentLengthField = env->GetFieldID(cacheResultClass, "contentLength", "J"); - jfieldID etagField = env->GetFieldID(cacheResultClass, "etag", "Ljava/lang/String;"); - jfieldID encodingField = env->GetFieldID(cacheResultClass, "encoding", "Ljava/lang/String;"); - jfieldID expiresField = env->GetFieldID(cacheResultClass, "expires", "J"); - jfieldID expiresStringField = env->GetFieldID(cacheResultClass, "expiresString", "Ljava/lang/String;"); - jfieldID httpStatusCodeField = env->GetFieldID(cacheResultClass, "httpStatusCode", "I"); - jfieldID lastModifiedField = env->GetFieldID(cacheResultClass, "lastModified", "Ljava/lang/String;"); - jfieldID localPathField = env->GetFieldID(cacheResultClass, "localPath", "Ljava/lang/String;"); - jfieldID locationField = env->GetFieldID(cacheResultClass, "location", "Ljava/lang/String;"); - jfieldID mimeTypeField = env->GetFieldID(cacheResultClass, "mimeType", "Ljava/lang/String;"); - - jobject javaResult = env->NewObject(cacheResultClass, constructor); - setFieldFromHeaderIfPresent(result.get(), "content-disposition", env, javaResult, contentdispositionField, true); - env->SetLongField(javaResult, contentLengthField, result->contentSize()); - setFieldFromHeaderIfPresent(result.get(), "etag", env, javaResult, etagField, false); - setStringField(env, javaResult, encodingField, "TODO"); // TODO: Where does the Android stack set this? - env->SetLongField(javaResult, expiresField, result->expires()); - env->SetIntField(javaResult, httpStatusCodeField, result->responseCode()); - setFieldFromHeaderIfPresent(result.get(), "last-modified", env, javaResult, lastModifiedField, false); - setStringField(env, javaResult, localPathField, encodedUrl.data()); - setFieldFromHeaderIfPresent(result.get(), "location", env, javaResult, locationField, false); - setStringField(env, javaResult, mimeTypeField, result->mimeType()); - - return javaResult; -} - -static JNINativeMethod gCacheManagerMethods[] = { - { "nativeGetCacheResult", "(Ljava/lang/String;)Landroid/webkit/CacheManager$CacheResult;", (void*) getCacheResult }, -}; - -int registerCacheManager(JNIEnv* env) -{ -#ifndef NDEBUG - jclass cacheManager = env->FindClass(javaCacheManagerClass); - LOG_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/WebKit/android/jni/CookieManager.cpp b/WebKit/android/jni/CookieManager.cpp deleted file mode 100644 index 0bdf303..0000000 --- a/WebKit/android/jni/CookieManager.cpp +++ /dev/null @@ -1,201 +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 "WebCookieJar.h" -#include "WebCoreJni.h" -#include - -using namespace base; -using namespace net; - -namespace android { - -// JNI for android.webkit.CookieManager -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 - // for such contexts are cleared up when we're done with them. - // TODO: Consider adding an optimisation to not create the context if it - // doesn't already exist. - WebCookieJar::get(true)->cookieStore()->GetCookieMonster()->DeleteAll(true); - - // 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(); - CookieMonster::CookieList cookies = cookieMonster->GetAllCookies(); - for (CookieMonster::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[] = { - { "nativeAcceptCookie", "()Z", (void*) acceptCookie }, - { "nativeGetCookie", "(Ljava/lang/String;Z)Ljava/lang/String;", (void*) getCookie }, - { "nativeHasCookies", "(Z)Z", (void*) hasCookies }, - { "nativeRemoveAllCookie", "()V", (void*) removeAllCookie }, - { "nativeRemoveExpiredCookie", "()V", (void*) removeExpiredCookie }, - { "nativeRemoveSessionCookie", "()V", (void*) removeSessionCookie }, - { "nativeSetAcceptCookie", "(Z)V", (void*) setAcceptCookie }, - { "nativeSetCookie", "(Ljava/lang/String;Ljava/lang/String;Z)V", (void*) setCookie }, - { "nativeFlushCookieStore", "()V", (void*) flushCookieStore }, - { "nativeAcceptFileSchemeCookies", "()Z", (void*) acceptFileSchemeCookies }, - { "nativeSetAcceptFileSchemeCookies", "(Z)V", (void*) setAcceptFileSchemeCookies }, -}; - -int registerCookieManager(JNIEnv* env) -{ -#ifndef NDEBUG - jclass cookieManager = env->FindClass(javaCookieManagerClass); - LOG_ASSERT(cookieManager, "Unable to find class"); - env->DeleteLocalRef(cookieManager); -#endif - return jniRegisterNativeMethods(env, javaCookieManagerClass, gCookieManagerMethods, NELEM(gCookieManagerMethods)); -} - -} // namespace android diff --git a/WebKit/android/jni/DeviceMotionAndOrientationManager.cpp b/WebKit/android/jni/DeviceMotionAndOrientationManager.cpp deleted file mode 100644 index 8beb372..0000000 --- a/WebKit/android/jni/DeviceMotionAndOrientationManager.cpp +++ /dev/null @@ -1,171 +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 "DeviceMotionAndOrientationManager.h" - -#include "DeviceMotionClientImpl.h" -#include "DeviceOrientationClientImpl.h" -#include "DeviceOrientationController.h" -#include "WebViewCore.h" -#include "Frame.h" -#include "Page.h" - -#include -#include - -using namespace WebCore; - -namespace android { - -DeviceMotionAndOrientationManager::DeviceMotionAndOrientationManager(WebViewCore* webViewCore) - : m_useMock(false) - , m_webViewCore(webViewCore) -{ -} - -void DeviceMotionAndOrientationManager::useMock() -{ - m_useMock = true; -} - -void DeviceMotionAndOrientationManager::setMockMotion(PassRefPtr motion) -{ - // TODO: There is not yet a DeviceMotion mock. -} - -void DeviceMotionAndOrientationManager::onMotionChange(PassRefPtr motion) -{ - ASSERT(!m_useMock); - static_cast(m_motionClient.get())->onMotionChange(motion); -} - -void DeviceMotionAndOrientationManager::setMockOrientation(PassRefPtr orientation) -{ - if (m_useMock) - static_cast(orientationClient())->setOrientation(orientation); -} - -void DeviceMotionAndOrientationManager::onOrientationChange(PassRefPtr orientation) -{ - ASSERT(!m_useMock); - static_cast(m_orientationClient.get())->onOrientationChange(orientation); -} - -void DeviceMotionAndOrientationManager::maybeSuspendClients() -{ - if (!m_useMock) { - if (m_motionClient) - static_cast(m_motionClient.get())->suspend(); - if (m_orientationClient) - static_cast(m_orientationClient.get())->suspend(); - } -} - -void DeviceMotionAndOrientationManager::maybeResumeClients() -{ - if (!m_useMock) { - if (m_motionClient) - static_cast(m_motionClient.get())->resume(); - if (m_orientationClient) - static_cast(m_orientationClient.get())->resume(); - } -} - -DeviceMotionClient* DeviceMotionAndOrientationManager::motionClient() -{ - // TODO: There is not yet a DeviceMotion mock. - if (!m_motionClient) - m_motionClient.set(m_useMock ? 0 - : static_cast(new DeviceMotionClientImpl(m_webViewCore))); - ASSERT(m_motionClient); - return m_motionClient.get(); -} - -DeviceOrientationClient* DeviceMotionAndOrientationManager::orientationClient() -{ - if (!m_orientationClient) - m_orientationClient.set(m_useMock ? new DeviceOrientationClientMock - : static_cast(new DeviceOrientationClientImpl(m_webViewCore))); - ASSERT(m_orientationClient); - return m_orientationClient.get(); -} - -// JNI for android.webkit.DeviceMotionAndOrientationManager -static const char* javaDeviceMotionAndOrientationManagerClass = "android/webkit/DeviceMotionAndOrientationManager"; - -static WebViewCore* getWebViewCore(JNIEnv* env, jobject webViewCoreObject) -{ - jclass webViewCoreClass = env->FindClass("android/webkit/WebViewCore"); - jfieldID nativeClassField = env->GetFieldID(webViewCoreClass, "mNativeClass", "I"); - env->DeleteLocalRef(webViewCoreClass); - return reinterpret_cast(env->GetIntField(webViewCoreObject, nativeClassField)); -} - -static void useMock(JNIEnv* env, jobject, jobject webViewCoreObject) -{ - getWebViewCore(env, webViewCoreObject)->deviceMotionAndOrientationManager()->useMock(); -} - -static void onMotionChange(JNIEnv* env, jobject, jobject webViewCoreObject, bool canProvideX, double x, bool canProvideY, double y, bool canProvideZ, double z, double interval) -{ - // We only provide accelerationIncludingGravity. - RefPtr accelerationIncludingGravity = DeviceMotionData::Acceleration::create(canProvideX, x, canProvideY, y, canProvideZ, z); - bool canProvideInterval = canProvideX || canProvideY || canProvideZ; - RefPtr motion = DeviceMotionData::create(0, accelerationIncludingGravity.release(), 0, canProvideInterval, interval); - getWebViewCore(env, webViewCoreObject)->deviceMotionAndOrientationManager()->onMotionChange(motion.release()); -} - -static void setMockOrientation(JNIEnv* env, jobject, jobject webViewCoreObject, bool canProvideAlpha, double alpha, bool canProvideBeta, double beta, bool canProvideGamma, double gamma) -{ - RefPtr orientation = DeviceOrientation::create(canProvideAlpha, alpha, canProvideBeta, beta, canProvideGamma, gamma); - getWebViewCore(env, webViewCoreObject)->deviceMotionAndOrientationManager()->setMockOrientation(orientation.release()); -} - -static void onOrientationChange(JNIEnv* env, jobject, jobject webViewCoreObject, bool canProvideAlpha, double alpha, bool canProvideBeta, double beta, bool canProvideGamma, double gamma) -{ - RefPtr orientation = DeviceOrientation::create(canProvideAlpha, alpha, canProvideBeta, beta, canProvideGamma, gamma); - getWebViewCore(env, webViewCoreObject)->deviceMotionAndOrientationManager()->onOrientationChange(orientation.release()); -} - -static JNINativeMethod gDeviceMotionAndOrientationManagerMethods[] = { - { "nativeUseMock", "(Landroid/webkit/WebViewCore;)V", (void*) useMock }, - { "nativeOnMotionChange", "(Landroid/webkit/WebViewCore;ZDZDZDD)V", (void*) onMotionChange }, - { "nativeSetMockOrientation", "(Landroid/webkit/WebViewCore;ZDZDZD)V", (void*) setMockOrientation }, - { "nativeOnOrientationChange", "(Landroid/webkit/WebViewCore;ZDZDZD)V", (void*) onOrientationChange } -}; - -int registerDeviceMotionAndOrientationManager(JNIEnv* env) -{ -#ifndef NDEBUG - jclass deviceMotionAndOrientationManager = env->FindClass(javaDeviceMotionAndOrientationManagerClass); - LOG_ASSERT(deviceMotionAndOrientationManager, "Unable to find class"); - env->DeleteLocalRef(deviceMotionAndOrientationManager); -#endif - - return jniRegisterNativeMethods(env, javaDeviceMotionAndOrientationManagerClass, gDeviceMotionAndOrientationManagerMethods, NELEM(gDeviceMotionAndOrientationManagerMethods)); -} - -} // namespace android diff --git a/WebKit/android/jni/DeviceMotionAndOrientationManager.h b/WebKit/android/jni/DeviceMotionAndOrientationManager.h deleted file mode 100644 index 44463c1..0000000 --- a/WebKit/android/jni/DeviceMotionAndOrientationManager.h +++ /dev/null @@ -1,68 +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 DeviceMotionAndOrientationManager_h -#define DeviceMotionAndOrientationManager_h - -#include -#include -#include -#include -#include -#include -#include - -namespace android { - -class WebViewCore; - -// This class takes care of the fact that the clients used for DeviceMotion and -// DeviceOrientation may be either the real implementations or mocks. It also -// handles setting the data on both the real and mock clients. This class is -// owned by WebViewCore and exists to keep cruft out of that class. -class DeviceMotionAndOrientationManager { -public: - DeviceMotionAndOrientationManager(WebViewCore*); - - void useMock(); - void setMockMotion(PassRefPtr); - void onMotionChange(PassRefPtr); - void setMockOrientation(PassRefPtr); - void onOrientationChange(PassRefPtr); - void maybeSuspendClients(); - void maybeResumeClients(); - WebCore::DeviceMotionClient* motionClient(); - WebCore::DeviceOrientationClient* orientationClient(); - -private: - bool m_useMock; - WebViewCore* m_webViewCore; - OwnPtr m_motionClient; - OwnPtr m_orientationClient; -}; - -} // namespace android - -#endif // DeviceMotionAndOrientationManager_h diff --git a/WebKit/android/jni/DeviceMotionClientImpl.cpp b/WebKit/android/jni/DeviceMotionClientImpl.cpp deleted file mode 100644 index 82f3c35..0000000 --- a/WebKit/android/jni/DeviceMotionClientImpl.cpp +++ /dev/null @@ -1,130 +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 "DeviceMotionClientImpl.h" - -#include "WebViewCore.h" -#include -#include -#include - -namespace android { - -using JSC::Bindings::getJNIEnv; - -enum javaServiceClassMethods { - ServiceMethodStart = 0, - ServiceMethodStop, - ServiceMethodSuspend, - ServiceMethodResume, - ServiceMethodCount -}; -static jmethodID javaServiceClassMethodIDs[ServiceMethodCount]; - -DeviceMotionClientImpl::DeviceMotionClientImpl(WebViewCore* webViewCore) - : m_webViewCore(webViewCore) - , m_javaServiceObject(0) -{ - ASSERT(m_webViewCore); -} - -DeviceMotionClientImpl::~DeviceMotionClientImpl() -{ - releaseJavaInstance(); -} - -jobject DeviceMotionClientImpl::getJavaInstance() -{ - // Lazily get the Java object. We can't do this until the WebViewCore is all - // set up. - if (m_javaServiceObject) - return m_javaServiceObject; - - JNIEnv* env = getJNIEnv(); - - ASSERT(m_webViewCore); - jobject object = m_webViewCore->getDeviceMotionService(); - - // Get the Java DeviceMotionService class. - jclass javaServiceClass = env->GetObjectClass(object); - ASSERT(javaServiceClass); - - // Set up the methods we wish to call on the Java DeviceMotionService - // class. - javaServiceClassMethodIDs[ServiceMethodStart] = - env->GetMethodID(javaServiceClass, "start", "()V"); - javaServiceClassMethodIDs[ServiceMethodStop] = - env->GetMethodID(javaServiceClass, "stop", "()V"); - javaServiceClassMethodIDs[ServiceMethodSuspend] = - env->GetMethodID(javaServiceClass, "suspend", "()V"); - javaServiceClassMethodIDs[ServiceMethodResume] = - env->GetMethodID(javaServiceClass, "resume", "()V"); - env->DeleteLocalRef(javaServiceClass); - - m_javaServiceObject = getJNIEnv()->NewGlobalRef(object); - getJNIEnv()->DeleteLocalRef(object); - - ASSERT(m_javaServiceObject); - return m_javaServiceObject; -} - -void DeviceMotionClientImpl::releaseJavaInstance() -{ - ASSERT(m_javaServiceObject); - getJNIEnv()->DeleteGlobalRef(m_javaServiceObject); -} - -void DeviceMotionClientImpl::startUpdating() -{ - getJNIEnv()->CallVoidMethod(getJavaInstance(), - javaServiceClassMethodIDs[ServiceMethodStart]); -} - -void DeviceMotionClientImpl::stopUpdating() -{ - getJNIEnv()->CallVoidMethod(getJavaInstance(), - javaServiceClassMethodIDs[ServiceMethodStop]); -} - -void DeviceMotionClientImpl::onMotionChange(PassRefPtr motion) -{ - m_lastMotion = motion; - m_controller->didChangeDeviceMotion(m_lastMotion.get()); -} - -void DeviceMotionClientImpl::suspend() -{ - getJNIEnv()->CallVoidMethod(getJavaInstance(), - javaServiceClassMethodIDs[ServiceMethodSuspend]); -} - -void DeviceMotionClientImpl::resume() -{ - getJNIEnv()->CallVoidMethod(getJavaInstance(), - javaServiceClassMethodIDs[ServiceMethodResume]); -} - -} // namespace android diff --git a/WebKit/android/jni/DeviceMotionClientImpl.h b/WebKit/android/jni/DeviceMotionClientImpl.h deleted file mode 100644 index c979098..0000000 --- a/WebKit/android/jni/DeviceMotionClientImpl.h +++ /dev/null @@ -1,70 +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 DeviceMotionClientImpl_h -#define DeviceMotionClientImpl_h - -#include -#include -#include -#include -#include - -using namespace WebCore; - -namespace android { - -class DeviceMotionAndOrientationManager; -class WebViewCore; - -class DeviceMotionClientImpl : public DeviceMotionClient { -public: - DeviceMotionClientImpl(WebViewCore*); - virtual ~DeviceMotionClientImpl(); - - void onMotionChange(PassRefPtr); - void suspend(); - void resume(); - - // DeviceMotionClient methods - virtual void startUpdating(); - virtual void stopUpdating(); - virtual DeviceMotionData* currentDeviceMotion() const { return m_lastMotion.get(); } - virtual void setController(DeviceMotionController* controller) { m_controller = controller; } - virtual void deviceMotionControllerDestroyed() { } - -private: - jobject getJavaInstance(); - void releaseJavaInstance(); - - WebViewCore* m_webViewCore; - jobject m_javaServiceObject; - DeviceMotionController* m_controller; - RefPtr m_lastMotion; -}; - -} // namespace android - -#endif // DeviceMotionClientImpl_h diff --git a/WebKit/android/jni/DeviceOrientationClientImpl.cpp b/WebKit/android/jni/DeviceOrientationClientImpl.cpp deleted file mode 100644 index bf3b3c3..0000000 --- a/WebKit/android/jni/DeviceOrientationClientImpl.cpp +++ /dev/null @@ -1,130 +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 "DeviceOrientationClientImpl.h" - -#include "WebViewCore.h" -#include -#include -#include - -namespace android { - -using JSC::Bindings::getJNIEnv; - -enum javaDeviceOrientationServiceClassMethods { - DeviceOrientationServiceMethodStart = 0, - DeviceOrientationServiceMethodStop, - DeviceOrientationServiceMethodSuspend, - DeviceOrientationServiceMethodResume, - DeviceOrientationServiceMethodCount -}; -static jmethodID javaDeviceOrientationServiceClassMethodIDs[DeviceOrientationServiceMethodCount]; - -DeviceOrientationClientImpl::DeviceOrientationClientImpl(WebViewCore* webViewCore) - : m_webViewCore(webViewCore) - , m_javaDeviceOrientationServiceObject(0) -{ - ASSERT(m_webViewCore); -} - -DeviceOrientationClientImpl::~DeviceOrientationClientImpl() -{ - releaseJavaInstance(); -} - -jobject DeviceOrientationClientImpl::getJavaInstance() -{ - // Lazily get the Java object. We can't do this until the WebViewCore is all - // set up. - if (m_javaDeviceOrientationServiceObject) - return m_javaDeviceOrientationServiceObject; - - JNIEnv* env = getJNIEnv(); - - ASSERT(m_webViewCore); - jobject object = m_webViewCore->getDeviceOrientationService(); - - // Get the Java DeviceOrientationService class. - jclass javaDeviceOrientationServiceClass = env->GetObjectClass(object); - ASSERT(javaDeviceOrientationServiceClass); - - // Set up the methods we wish to call on the Java DeviceOrientationService - // class. - javaDeviceOrientationServiceClassMethodIDs[DeviceOrientationServiceMethodStart] = - env->GetMethodID(javaDeviceOrientationServiceClass, "start", "()V"); - javaDeviceOrientationServiceClassMethodIDs[DeviceOrientationServiceMethodStop] = - env->GetMethodID(javaDeviceOrientationServiceClass, "stop", "()V"); - javaDeviceOrientationServiceClassMethodIDs[DeviceOrientationServiceMethodSuspend] = - env->GetMethodID(javaDeviceOrientationServiceClass, "suspend", "()V"); - javaDeviceOrientationServiceClassMethodIDs[DeviceOrientationServiceMethodResume] = - env->GetMethodID(javaDeviceOrientationServiceClass, "resume", "()V"); - env->DeleteLocalRef(javaDeviceOrientationServiceClass); - - m_javaDeviceOrientationServiceObject = getJNIEnv()->NewGlobalRef(object); - getJNIEnv()->DeleteLocalRef(object); - - ASSERT(m_javaDeviceOrientationServiceObject); - return m_javaDeviceOrientationServiceObject; -} - -void DeviceOrientationClientImpl::releaseJavaInstance() -{ - ASSERT(m_javaDeviceOrientationServiceObject); - getJNIEnv()->DeleteGlobalRef(m_javaDeviceOrientationServiceObject); -} - -void DeviceOrientationClientImpl::startUpdating() -{ - getJNIEnv()->CallVoidMethod(getJavaInstance(), - javaDeviceOrientationServiceClassMethodIDs[DeviceOrientationServiceMethodStart]); -} - -void DeviceOrientationClientImpl::stopUpdating() -{ - getJNIEnv()->CallVoidMethod(getJavaInstance(), - javaDeviceOrientationServiceClassMethodIDs[DeviceOrientationServiceMethodStop]); -} - -void DeviceOrientationClientImpl::onOrientationChange(PassRefPtr orientation) -{ - m_lastOrientation = orientation; - m_controller->didChangeDeviceOrientation(m_lastOrientation.get()); -} - -void DeviceOrientationClientImpl::suspend() -{ - getJNIEnv()->CallVoidMethod(getJavaInstance(), - javaDeviceOrientationServiceClassMethodIDs[DeviceOrientationServiceMethodSuspend]); -} - -void DeviceOrientationClientImpl::resume() -{ - getJNIEnv()->CallVoidMethod(getJavaInstance(), - javaDeviceOrientationServiceClassMethodIDs[DeviceOrientationServiceMethodResume]); -} - -} // namespace android diff --git a/WebKit/android/jni/DeviceOrientationClientImpl.h b/WebKit/android/jni/DeviceOrientationClientImpl.h deleted file mode 100644 index 0e3f6b3..0000000 --- a/WebKit/android/jni/DeviceOrientationClientImpl.h +++ /dev/null @@ -1,70 +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 DeviceOrientationClientImpl_h -#define DeviceOrientationClientImpl_h - -#include -#include -#include -#include -#include - -using namespace WebCore; - -namespace android { - -class DeviceMotionAndOrientationManager; -class WebViewCore; - -class DeviceOrientationClientImpl : public DeviceOrientationClient { -public: - DeviceOrientationClientImpl(WebViewCore*); - virtual ~DeviceOrientationClientImpl(); - - void onOrientationChange(PassRefPtr); - void suspend(); - void resume(); - - // DeviceOrientationClient methods - virtual void startUpdating(); - virtual void stopUpdating(); - virtual DeviceOrientation* lastOrientation() const { return m_lastOrientation.get(); } - virtual void setController(DeviceOrientationController* controller) { m_controller = controller; } - virtual void deviceOrientationControllerDestroyed() { } - -private: - jobject getJavaInstance(); - void releaseJavaInstance(); - - WebViewCore* m_webViewCore; - jobject m_javaDeviceOrientationServiceObject; - DeviceOrientationController* m_controller; - RefPtr m_lastOrientation; -}; - -} // namespace android - -#endif // DeviceOrientationClientImpl_h diff --git a/WebKit/android/jni/GeolocationPermissionsBridge.cpp b/WebKit/android/jni/GeolocationPermissionsBridge.cpp deleted file mode 100755 index a366601..0000000 --- a/WebKit/android/jni/GeolocationPermissionsBridge.cpp +++ /dev/null @@ -1,113 +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 "config.h" - -#include // For jniRegisterNativeMethods -#include "GeolocationPermissions.h" -#include "WebCoreJni.h" // For jstringToWtfString - - -/** - * This file provides a set of functions to bridge between the Java and C++ - * GeolocationPermissions classes. The java GeolocationPermissions object calls - * the functions provided here, which in turn call static methods on the C++ - * GeolocationPermissions class. - */ - -namespace android { - -static jobject getOrigins(JNIEnv* env, jobject obj) -{ - GeolocationPermissions::OriginSet origins = GeolocationPermissions::getOrigins(); - - jclass setClass = env->FindClass("java/util/HashSet"); - jmethodID constructor = env->GetMethodID(setClass, "", "()V"); - jmethodID addMethod = env->GetMethodID(setClass, "add", "(Ljava/lang/Object;)Z"); - jobject set = env->NewObject(setClass, constructor); - env->DeleteLocalRef(setClass); - - GeolocationPermissions::OriginSet::const_iterator end = origins.end(); - for (GeolocationPermissions::OriginSet::const_iterator iter = origins.begin(); iter != end; ++iter) { - jstring originString = wtfStringToJstring(env, *iter); - env->CallBooleanMethod(set, addMethod, originString); - env->DeleteLocalRef(originString); - } - return set; -} - -static bool getAllowed(JNIEnv* env, jobject obj, jstring origin) -{ - WTF::String originString = jstringToWtfString(env, origin); - return GeolocationPermissions::getAllowed(originString); -} - -static void clear(JNIEnv* env, jobject obj, jstring origin) -{ - WTF::String originString = jstringToWtfString(env, origin); - GeolocationPermissions::clear(originString); -} - -static void allow(JNIEnv* env, jobject obj, jstring origin) -{ - WTF::String originString = jstringToWtfString(env, origin); - GeolocationPermissions::allow(originString); -} - -static void clearAll(JNIEnv* env, jobject obj) -{ - GeolocationPermissions::clearAll(); -} - -/* - * JNI registration - */ -static JNINativeMethod gGeolocationPermissionsMethods[] = { - { "nativeGetOrigins", "()Ljava/util/Set;", - (void*) getOrigins }, - { "nativeGetAllowed", "(Ljava/lang/String;)Z", - (void*) getAllowed }, - { "nativeClear", "(Ljava/lang/String;)V", - (void*) clear }, - { "nativeAllow", "(Ljava/lang/String;)V", - (void*) allow }, - { "nativeClearAll", "()V", - (void*) clearAll } -}; - -int registerGeolocationPermissions(JNIEnv* env) -{ - const char* kGeolocationPermissionsClass = "android/webkit/GeolocationPermissions"; -#ifndef NDEBUG - jclass geolocationPermissions = env->FindClass(kGeolocationPermissionsClass); - LOG_ASSERT(geolocationPermissions, "Unable to find class"); - env->DeleteLocalRef(geolocationPermissions); -#endif - - return jniRegisterNativeMethods(env, kGeolocationPermissionsClass, - gGeolocationPermissionsMethods, NELEM(gGeolocationPermissionsMethods)); -} - -} diff --git a/WebKit/android/jni/JavaBridge.cpp b/WebKit/android/jni/JavaBridge.cpp deleted file mode 100644 index 2fa12fc..0000000 --- a/WebKit/android/jni/JavaBridge.cpp +++ /dev/null @@ -1,514 +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 "MemoryCache.h" -#include "Connection.h" -#include "CookieClient.h" -#include "FileSystemClient.h" -#include "JavaSharedClient.h" -#include "KeyGeneratorClient.h" -#include "KURL.h" -#include "NetworkStateNotifier.h" -#include "PackageNotifier.h" -#include "Page.h" -#include "PluginClient.h" -#include "PluginDatabase.h" -#include "Timer.h" -#include "TimerClient.h" -#ifdef ANDROID_INSTRUMENT -#include "TimeCounter.h" -#endif -#include "WebCache.h" -#include "WebCoreJni.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace android { - -// ---------------------------------------------------------------------------- - -static jfieldID gJavaBridge_ObjectID; - -// ---------------------------------------------------------------------------- - -class JavaBridge : public TimerClient, public CookieClient, public PluginClient, public KeyGeneratorClient, public FileSystemClient -{ -public: - JavaBridge(JNIEnv* env, jobject obj); - virtual ~JavaBridge(); - - /* - * WebCore -> Java API - */ - virtual void setSharedTimer(long long timemillis); - virtual void stopSharedTimer(); - - virtual void setCookies(WebCore::KURL const& url, WTF::String const& value); - virtual WTF::String cookies(WebCore::KURL const& url); - virtual bool cookiesEnabled(); - - virtual WTF::Vector getPluginDirectories(); - virtual WTF::String getPluginSharedDataDirectory(); - - virtual WTF::Vector getSupportedKeyStrengthList(); - virtual WTF::String getSignedPublicKeyAndChallengeString(unsigned index, - const WTF::String& challenge, const WebCore::KURL& url); - virtual WTF::String resolveFilePathForContentUri(const WTF::String& uri); - - //////////////////////////////////////////// - - virtual void setSharedTimerCallback(void (*f)()); - - //////////////////////////////////////////// - - virtual void signalServiceFuncPtrQueue(); - - // jni functions - static void Constructor(JNIEnv* env, jobject obj); - static void Finalize(JNIEnv* env, jobject obj); - static void SharedTimerFired(JNIEnv* env, jobject); - static void SetCacheSize(JNIEnv* env, jobject obj, jint bytes); - static void SetNetworkOnLine(JNIEnv* env, jobject obj, jboolean online); - static void SetNetworkType(JNIEnv* env, jobject obj, jstring type, jstring subtype); - static void SetDeferringTimers(JNIEnv* env, jobject obj, jboolean defer); - static void ServiceFuncPtrQueue(JNIEnv*); - static void UpdatePluginDirectories(JNIEnv* env, jobject obj, jobjectArray array, jboolean reload); - static void AddPackageNames(JNIEnv* env, jobject obj, jobject packageNames); - static void AddPackageName(JNIEnv* env, jobject obj, jstring packageName); - static void RemovePackageName(JNIEnv* env, jobject obj, jstring packageName); - static void UpdateProxy(JNIEnv* env, jobject obj, jstring newProxy); - - -private: - jweak mJavaObject; - jmethodID mSetSharedTimer; - jmethodID mStopSharedTimer; - jmethodID mSetCookies; - jmethodID mCookies; - jmethodID mCookiesEnabled; - jmethodID mGetPluginDirectories; - jmethodID mGetPluginSharedDataDirectory; - jmethodID mSignalFuncPtrQueue; - jmethodID mGetKeyStrengthList; - jmethodID mGetSignedPublicKey; - jmethodID mResolveFilePathForContentUri; - AutoJObject javaObject(JNIEnv* env) { return getRealObject(env, mJavaObject); } -}; - -static void (*sSharedTimerFiredCallback)(); - -JavaBridge::JavaBridge(JNIEnv* env, jobject obj) -{ - mJavaObject = env->NewWeakGlobalRef(obj); - jclass clazz = env->GetObjectClass(obj); - - mSetSharedTimer = env->GetMethodID(clazz, "setSharedTimer", "(J)V"); - mStopSharedTimer = env->GetMethodID(clazz, "stopSharedTimer", "()V"); - mSetCookies = env->GetMethodID(clazz, "setCookies", "(Ljava/lang/String;Ljava/lang/String;)V"); - mCookies = env->GetMethodID(clazz, "cookies", "(Ljava/lang/String;)Ljava/lang/String;"); - mCookiesEnabled = env->GetMethodID(clazz, "cookiesEnabled", "()Z"); - mGetPluginDirectories = env->GetMethodID(clazz, "getPluginDirectories", "()[Ljava/lang/String;"); - mGetPluginSharedDataDirectory = env->GetMethodID(clazz, "getPluginSharedDataDirectory", "()Ljava/lang/String;"); - mSignalFuncPtrQueue = env->GetMethodID(clazz, "signalServiceFuncPtrQueue", "()V"); - mGetKeyStrengthList = env->GetMethodID(clazz, "getKeyStrengthList", "()[Ljava/lang/String;"); - mGetSignedPublicKey = env->GetMethodID(clazz, "getSignedPublicKey", "(ILjava/lang/String;Ljava/lang/String;)Ljava/lang/String;"); - 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"); - - JavaSharedClient::SetTimerClient(this); - JavaSharedClient::SetCookieClient(this); - JavaSharedClient::SetPluginClient(this); - JavaSharedClient::SetKeyGeneratorClient(this); - JavaSharedClient::SetFileSystemClient(this); -} - -JavaBridge::~JavaBridge() -{ - if (mJavaObject) { - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->DeleteWeakGlobalRef(mJavaObject); - mJavaObject = 0; - } - - JavaSharedClient::SetTimerClient(NULL); - JavaSharedClient::SetCookieClient(NULL); - JavaSharedClient::SetPluginClient(NULL); - JavaSharedClient::SetKeyGeneratorClient(NULL); - JavaSharedClient::SetFileSystemClient(NULL); -} - -void -JavaBridge::setSharedTimer(long long timemillis) -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - AutoJObject obj = javaObject(env); - env->CallVoidMethod(obj.get(), mSetSharedTimer, timemillis); -} - -void -JavaBridge::stopSharedTimer() -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - AutoJObject obj = javaObject(env); - env->CallVoidMethod(obj.get(), mStopSharedTimer); -} - -void -JavaBridge::setCookies(WebCore::KURL const& url, WTF::String const& value) -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - const WTF::String& urlStr = url.string(); - jstring jUrlStr = wtfStringToJstring(env, urlStr); - jstring jValueStr = wtfStringToJstring(env, value); - - AutoJObject obj = javaObject(env); - env->CallVoidMethod(obj.get(), mSetCookies, jUrlStr, jValueStr); - env->DeleteLocalRef(jUrlStr); - env->DeleteLocalRef(jValueStr); -} - -WTF::String -JavaBridge::cookies(WebCore::KURL const& url) -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - const WTF::String& urlStr = url.string(); - jstring jUrlStr = wtfStringToJstring(env, urlStr); - - AutoJObject obj = javaObject(env); - jstring string = (jstring)(env->CallObjectMethod(obj.get(), mCookies, jUrlStr)); - - WTF::String ret = jstringToWtfString(env, string); - env->DeleteLocalRef(jUrlStr); - env->DeleteLocalRef(string); - return ret; -} - -bool -JavaBridge::cookiesEnabled() -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - AutoJObject obj = javaObject(env); - jboolean ret = env->CallBooleanMethod(obj.get(), mCookiesEnabled); - return (ret != 0); -} - -WTF::Vector -JavaBridge::getPluginDirectories() -{ - WTF::Vector directories; - JNIEnv* env = JSC::Bindings::getJNIEnv(); - AutoJObject obj = javaObject(env); - jobjectArray array = (jobjectArray) - env->CallObjectMethod(obj.get(), mGetPluginDirectories); - int count = env->GetArrayLength(array); - for (int i = 0; i < count; i++) { - jstring dir = (jstring) env->GetObjectArrayElement(array, i); - directories.append(jstringToWtfString(env, dir)); - env->DeleteLocalRef(dir); - } - env->DeleteLocalRef(array); - checkException(env); - return directories; -} - -WTF::String -JavaBridge::getPluginSharedDataDirectory() -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - AutoJObject obj = javaObject(env); - jstring ret = (jstring)env->CallObjectMethod(obj.get(), mGetPluginSharedDataDirectory); - WTF::String path = jstringToWtfString(env, ret); - checkException(env); - return path; -} - -void -JavaBridge::setSharedTimerCallback(void (*f)()) -{ - LOG_ASSERT(!sSharedTimerFiredCallback || sSharedTimerFiredCallback==f, - "Shared timer callback may already be set or null!"); - - sSharedTimerFiredCallback = f; -} - -void JavaBridge::signalServiceFuncPtrQueue() -{ - // In order to signal the main thread we must go through JNI. This - // is the only usage on most threads, so we need to ensure a JNI - // environment is setup. - JNIEnv* env = JSC::Bindings::getJNIEnv(); - AutoJObject obj = javaObject(env); - env->CallVoidMethod(obj.get(), mSignalFuncPtrQueue); -} - -WTF::VectorJavaBridge::getSupportedKeyStrengthList() { - WTF::Vector list; - JNIEnv* env = JSC::Bindings::getJNIEnv(); - AutoJObject obj = javaObject(env); - jobjectArray array = (jobjectArray) env->CallObjectMethod(obj.get(), - mGetKeyStrengthList); - int count = env->GetArrayLength(array); - for (int i = 0; i < count; ++i) { - jstring keyStrength = (jstring) env->GetObjectArrayElement(array, i); - list.append(jstringToWtfString(env, keyStrength)); - env->DeleteLocalRef(keyStrength); - } - env->DeleteLocalRef(array); - checkException(env); - return list; -} - -WTF::String JavaBridge::getSignedPublicKeyAndChallengeString(unsigned index, - const WTF::String& challenge, const WebCore::KURL& url) { - JNIEnv* env = JSC::Bindings::getJNIEnv(); - jstring jChallenge = wtfStringToJstring(env, challenge); - const WTF::String& urlStr = url.string(); - jstring jUrl = wtfStringToJstring(env, urlStr); - AutoJObject obj = javaObject(env); - jstring key = (jstring) env->CallObjectMethod(obj.get(), - mGetSignedPublicKey, index, jChallenge, jUrl); - WTF::String ret = jstringToWtfString(env, key); - env->DeleteLocalRef(jChallenge); - env->DeleteLocalRef(jUrl); - env->DeleteLocalRef(key); - return ret; -} - -WTF::String JavaBridge::resolveFilePathForContentUri(const WTF::String& uri) { - JNIEnv* env = JSC::Bindings::getJNIEnv(); - jstring jUri = wtfStringToJstring(env, uri); - AutoJObject obj = javaObject(env); - jstring path = static_cast(env->CallObjectMethod(obj.get(), mResolveFilePathForContentUri, jUri)); - WTF::String ret = jstringToWtfString(env, path); - env->DeleteLocalRef(jUri); - env->DeleteLocalRef(path); - return ret; -} - -// ---------------------------------------------------------------------------- - -void JavaBridge::Constructor(JNIEnv* env, jobject obj) -{ - JavaBridge* javaBridge = new JavaBridge(env, obj); - env->SetIntField(obj, gJavaBridge_ObjectID, (jint)javaBridge); -} - -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); - delete javaBridge; - env->SetIntField(obj, gJavaBridge_ObjectID, 0); -} - -// we don't use the java bridge object, as we're just looking at a global -void JavaBridge::SharedTimerFired(JNIEnv* env, jobject) -{ - if (sSharedTimerFiredCallback) - { -#ifdef ANDROID_INSTRUMENT - TimeCounter::start(TimeCounter::SharedTimerTimeCounter); -#endif - SkAutoMemoryUsageProbe mup("JavaBridge::sharedTimerFired"); - sSharedTimerFiredCallback(); -#ifdef ANDROID_INSTRUMENT - TimeCounter::record(TimeCounter::SharedTimerTimeCounter, __FUNCTION__); -#endif - } -} - -void JavaBridge::SetCacheSize(JNIEnv* env, jobject obj, jint bytes) -{ - WebCore::cache()->setCapacities(0, bytes/2, bytes); -} - -void JavaBridge::SetNetworkOnLine(JNIEnv* env, jobject obj, jboolean online) -{ - WebCore::networkStateNotifier().networkStateChange(online); -} - -void JavaBridge::SetNetworkType(JNIEnv* env, jobject obj, jstring javatype, jstring javasubtype) -{ - DEFINE_STATIC_LOCAL(AtomicString, wifi, ("wifi")); - DEFINE_STATIC_LOCAL(AtomicString, mobile, ("mobile")); - DEFINE_STATIC_LOCAL(AtomicString, mobileSupl, ("mobile_supl")); - DEFINE_STATIC_LOCAL(AtomicString, gprs, ("gprs")); - DEFINE_STATIC_LOCAL(AtomicString, edge, ("edge")); - DEFINE_STATIC_LOCAL(AtomicString, umts, ("umts")); - - String type = jstringToWtfString(env, javatype); - String subtype = jstringToWtfString(env, javasubtype); - Connection::ConnectionType connectionType = Connection::UNKNOWN; - if (type == wifi) - connectionType = Connection::WIFI; - else if (type == mobile || type == mobileSupl) { - if (subtype == edge || subtype == gprs) - connectionType = Connection::CELL_2G; - else if (subtype == umts) - connectionType = Connection::CELL_3G; - } - WebCore::networkStateNotifier().networkTypeChange(connectionType); -} - -void JavaBridge::ServiceFuncPtrQueue(JNIEnv*) -{ - JavaSharedClient::ServiceFunctionPtrQueue(); -} - -void JavaBridge::UpdatePluginDirectories(JNIEnv* env, jobject obj, - jobjectArray array, jboolean reload) { - WTF::Vector directories; - int count = env->GetArrayLength(array); - for (int i = 0; i < count; i++) { - jstring dir = (jstring) env->GetObjectArrayElement(array, i); - directories.append(jstringToWtfString(env, dir)); - env->DeleteLocalRef(dir); - } - checkException(env); - WebCore::PluginDatabase *pluginDatabase = - WebCore::PluginDatabase::installedPlugins(); - pluginDatabase->setPluginDirectories(directories); - // refreshPlugins() should refresh both PluginDatabase and Page's PluginData - WebCore::Page::refreshPlugins(reload); -} - -void JavaBridge::AddPackageNames(JNIEnv* env, jobject obj, jobject packageNames) -{ - if (!packageNames) - return; - - // dalvikvm will raise exception if any of these fail - jclass setClass = env->FindClass("java/util/Set"); - jmethodID iterator = env->GetMethodID(setClass, "iterator", - "()Ljava/util/Iterator;"); - jobject iter = env->CallObjectMethod(packageNames, iterator); - - jclass iteratorClass = env->FindClass("java/util/Iterator"); - jmethodID hasNext = env->GetMethodID(iteratorClass, "hasNext", "()Z"); - jmethodID next = env->GetMethodID(iteratorClass, "next", "()Ljava/lang/Object;"); - - HashSet namesSet; - while (env->CallBooleanMethod(iter, hasNext)) { - jstring name = static_cast(env->CallObjectMethod(iter, next)); - namesSet.add(jstringToWtfString(env, name)); - env->DeleteLocalRef(name); - } - - packageNotifier().addPackageNames(namesSet); - - env->DeleteLocalRef(iteratorClass); - env->DeleteLocalRef(iter); - env->DeleteLocalRef(setClass); -} - -void JavaBridge::AddPackageName(JNIEnv* env, jobject obj, jstring packageName) -{ - packageNotifier().addPackageName(jstringToWtfString(env, packageName)); -} - -void JavaBridge::RemovePackageName(JNIEnv* env, jobject obj, jstring packageName) -{ - packageNotifier().removePackageName(jstringToWtfString(env, packageName)); -} - -void JavaBridge::UpdateProxy(JNIEnv* env, jobject obj, jstring newProxy) -{ -#if USE(CHROME_NETWORK_STACK) - std::string proxy = jstringToStdString(env, newProxy); - WebCache::get(false)->proxy()->UpdateProxySettings(proxy); - WebCache::get(true)->proxy()->UpdateProxySettings(proxy); -#endif -} - - -// ---------------------------------------------------------------------------- - -/* - * JNI registration. - */ -static JNINativeMethod gWebCoreJavaBridgeMethods[] = { - /* name, signature, funcPtr */ - { "nativeConstructor", "()V", - (void*) JavaBridge::Constructor }, - { "nativeFinalize", "()V", - (void*) JavaBridge::Finalize }, - { "sharedTimerFired", "()V", - (void*) JavaBridge::SharedTimerFired }, - { "setCacheSize", "(I)V", - (void*) JavaBridge::SetCacheSize }, - { "setNetworkOnLine", "(Z)V", - (void*) JavaBridge::SetNetworkOnLine }, - { "setNetworkType", "(Ljava/lang/String;Ljava/lang/String;)V", - (void*) JavaBridge::SetNetworkType }, - { "nativeServiceFuncPtrQueue", "()V", - (void*) JavaBridge::ServiceFuncPtrQueue }, - { "nativeUpdatePluginDirectories", "([Ljava/lang/String;Z)V", - (void*) JavaBridge::UpdatePluginDirectories }, - { "addPackageNames", "(Ljava/util/Set;)V", - (void*) JavaBridge::AddPackageNames }, - { "addPackageName", "(Ljava/lang/String;)V", - (void*) JavaBridge::AddPackageName }, - { "removePackageName", "(Ljava/lang/String;)V", - (void*) JavaBridge::RemovePackageName }, - { "updateProxy", "(Ljava/lang/String;)V", - (void*) JavaBridge::UpdateProxy } -}; - -int registerJavaBridge(JNIEnv* env) -{ - jclass javaBridge = env->FindClass("android/webkit/JWebCoreJavaBridge"); - LOG_FATAL_IF(javaBridge == NULL, "Unable to find class android/webkit/JWebCoreJavaBridge"); - gJavaBridge_ObjectID = env->GetFieldID(javaBridge, "mNativeBridge", "I"); - LOG_FATAL_IF(gJavaBridge_ObjectID == NULL, "Unable to find android/webkit/JWebCoreJavaBridge.mNativeBridge"); - env->DeleteLocalRef(javaBridge); - - return jniRegisterNativeMethods(env, "android/webkit/JWebCoreJavaBridge", - gWebCoreJavaBridgeMethods, NELEM(gWebCoreJavaBridgeMethods)); -} - -} /* namespace android */ diff --git a/WebKit/android/jni/JavaSharedClient.cpp b/WebKit/android/jni/JavaSharedClient.cpp deleted file mode 100644 index e884c99..0000000 --- a/WebKit/android/jni/JavaSharedClient.cpp +++ /dev/null @@ -1,137 +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 "config.h" -#include "FileSystemClient.h" -#include "JavaSharedClient.h" -#include "TimerClient.h" -#include "SkDeque.h" -#include "SkThread.h" - -namespace android { - TimerClient* JavaSharedClient::GetTimerClient() - { - return gTimerClient; - } - - CookieClient* JavaSharedClient::GetCookieClient() - { - return gCookieClient; - } - - PluginClient* JavaSharedClient::GetPluginClient() - { - return gPluginClient; - } - - KeyGeneratorClient* JavaSharedClient::GetKeyGeneratorClient() - { - return gKeyGeneratorClient; - } - - FileSystemClient* JavaSharedClient::GetFileSystemClient() - { - return gFileSystemClient; - } - - void JavaSharedClient::SetTimerClient(TimerClient* client) - { - gTimerClient = client; - } - - void JavaSharedClient::SetCookieClient(CookieClient* client) - { - gCookieClient = client; - } - - void JavaSharedClient::SetPluginClient(PluginClient* client) - { - gPluginClient = client; - } - - void JavaSharedClient::SetKeyGeneratorClient(KeyGeneratorClient* client) - { - gKeyGeneratorClient = client; - } - - void JavaSharedClient::SetFileSystemClient(FileSystemClient* client) - { - gFileSystemClient = client; - } - - TimerClient* JavaSharedClient::gTimerClient = NULL; - CookieClient* JavaSharedClient::gCookieClient = NULL; - PluginClient* JavaSharedClient::gPluginClient = NULL; - KeyGeneratorClient* JavaSharedClient::gKeyGeneratorClient = NULL; - FileSystemClient* JavaSharedClient::gFileSystemClient = NULL; - - /////////////////////////////////////////////////////////////////////////// - - struct FuncPtrRec { - void (*fProc)(void* payload); - void* fPayload; - }; - - static SkMutex gFuncPtrQMutex; - static SkDeque gFuncPtrQ(sizeof(FuncPtrRec)); - - void JavaSharedClient::EnqueueFunctionPtr(void (*proc)(void* payload), - void* payload) - { - gFuncPtrQMutex.acquire(); - - 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); - } - } -} diff --git a/WebKit/android/jni/JavaSharedClient.h b/WebKit/android/jni/JavaSharedClient.h deleted file mode 100644 index 9a09280..0000000 --- a/WebKit/android/jni/JavaSharedClient.h +++ /dev/null @@ -1,65 +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 JAVA_SHARED_CLIENT_H -#define JAVA_SHARED_CLIENT_H - -namespace android { - - class TimerClient; - class CookieClient; - class PluginClient; - class KeyGeneratorClient; - class FileSystemClient; - - class JavaSharedClient - { - public: - static TimerClient* GetTimerClient(); - static CookieClient* GetCookieClient(); - static PluginClient* GetPluginClient(); - static KeyGeneratorClient* GetKeyGeneratorClient(); - static FileSystemClient* GetFileSystemClient(); - - static void SetTimerClient(TimerClient* client); - static void SetCookieClient(CookieClient* client); - static void SetPluginClient(PluginClient* client); - static void SetKeyGeneratorClient(KeyGeneratorClient* client); - static void SetFileSystemClient(FileSystemClient* client); - - // can be called from any thread, to be executed in webkit thread - static void EnqueueFunctionPtr(void (*proc)(void*), void* payload); - // only call this from webkit thread - static void ServiceFunctionPtrQueue(); - - private: - static TimerClient* gTimerClient; - static CookieClient* gCookieClient; - static PluginClient* gPluginClient; - static KeyGeneratorClient* gKeyGeneratorClient; - static FileSystemClient* gFileSystemClient; - }; -} -#endif diff --git a/WebKit/android/jni/JniUtil.cpp b/WebKit/android/jni/JniUtil.cpp deleted file mode 100644 index ee1e3f9..0000000 --- a/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 - -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/WebKit/android/jni/MIMETypeRegistry.cpp b/WebKit/android/jni/MIMETypeRegistry.cpp deleted file mode 100644 index 40f8cef..0000000 --- a/WebKit/android/jni/MIMETypeRegistry.cpp +++ /dev/null @@ -1,67 +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. - */ - -#define LOG_TAG "WebCore" - -#include "config.h" -#include "MIMETypeRegistry.h" - -#include "PlatformString.h" -#include "WebCoreJni.h" - -#include -#include -#include - -using namespace android; - -namespace WebCore { - -String MIMETypeRegistry::getMIMETypeForExtension(const String& ext) -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - jclass mimeClass = env->FindClass("android/webkit/MimeTypeMap"); - LOG_ASSERT(mimeClass, "Could not find class MimeTypeMap"); - jmethodID mimeTypeFromExtension = env->GetStaticMethodID(mimeClass, - "mimeTypeFromExtension", - "(Ljava/lang/String;)Ljava/lang/String;"); - LOG_ASSERT(mimeTypeFromExtension, - "Could not find method mimeTypeFromExtension"); - jstring extString = wtfStringToJstring(env, ext); - jobject mimeType = env->CallStaticObjectMethod(mimeClass, - mimeTypeFromExtension, extString); - String result = android::jstringToWtfString(env, (jstring) mimeType); - env->DeleteLocalRef(mimeClass); - env->DeleteLocalRef(extString); - env->DeleteLocalRef(mimeType); - return result; -} - -bool MIMETypeRegistry::isApplicationPluginMIMEType(const String&) -{ - return false; -} - -} diff --git a/WebKit/android/jni/MockGeolocation.cpp b/WebKit/android/jni/MockGeolocation.cpp deleted file mode 100755 index 1370715..0000000 --- a/WebKit/android/jni/MockGeolocation.cpp +++ /dev/null @@ -1,84 +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. - */ - -// The functions in this file are used to configure the mock GeolocationService -// for the LayoutTests. - -#include "config.h" - -#include "Coordinates.h" -#include "GeolocationServiceMock.h" -#include "Geoposition.h" -#include "JavaSharedClient.h" -#include "PositionError.h" -#include "WebCoreJni.h" -#include -#include -#include - -using namespace WebCore; - -namespace android { - -static const char* javaMockGeolocationClass = "android/webkit/MockGeolocation"; - -static void setPosition(JNIEnv* env, jobject, double latitude, double longitude, double accuracy) -{ - RefPtr coordinates = Coordinates::create(latitude, - longitude, - false, 0.0, // altitude, - accuracy, - false, 0.0, // altitudeAccuracy, - false, 0.0, // heading - false, 0.0); // speed - RefPtr position = Geoposition::create(coordinates.release(), WTF::currentTimeMS()); - GeolocationServiceMock::setPosition(position.release()); -} - -static void setError(JNIEnv* env, jobject, int code, jstring message) -{ - PositionError::ErrorCode codeEnum = static_cast(code); - String messageString = jstringToWtfString(env, message); - RefPtr error = PositionError::create(codeEnum, messageString); - GeolocationServiceMock::setError(error.release()); -} - -static JNINativeMethod gMockGeolocationMethods[] = { - { "nativeSetPosition", "(DDD)V", (void*) setPosition }, - { "nativeSetError", "(ILjava/lang/String;)V", (void*) setError } -}; - -int registerMockGeolocation(JNIEnv* env) -{ -#ifndef NDEBUG - jclass mockGeolocation = env->FindClass(javaMockGeolocationClass); - LOG_ASSERT(mockGeolocation, "Unable to find class"); - env->DeleteLocalRef(mockGeolocation); -#endif - - return jniRegisterNativeMethods(env, javaMockGeolocationClass, gMockGeolocationMethods, NELEM(gMockGeolocationMethods)); -} - -} diff --git a/WebKit/android/jni/PictureSet.cpp b/WebKit/android/jni/PictureSet.cpp deleted file mode 100644 index 6dafd26..0000000 --- a/WebKit/android/jni/PictureSet.cpp +++ /dev/null @@ -1,676 +0,0 @@ -/* - * Copyright 2008, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#define LOG_NDEBUG 0 -#define LOG_TAG "pictureset" - -//#include -#include "CachedPrefix.h" -#include "android_graphics.h" -#include "PictureSet.h" -#include "SkBounder.h" -#include "SkCanvas.h" -#include "SkPicture.h" -#include "SkRect.h" -#include "SkRegion.h" -#include "SkStream.h" -#include "TimeCounter.h" - -#define MAX_DRAW_TIME 100 -#define MIN_SPLITTABLE 400 - -#if PICTURE_SET_DEBUG -class MeasureStream : public SkWStream { -public: - MeasureStream() : mTotal(0) {} - virtual bool write(const void* , size_t size) { - mTotal += size; - return true; - } - size_t mTotal; -}; -#endif - -namespace android { - -PictureSet::PictureSet() -{ - mWidth = mHeight = 0; -} - -PictureSet::~PictureSet() -{ - clear(); -} - -void PictureSet::add(const Pictures* temp) -{ - Pictures pictureAndBounds = *temp; - SkSafeRef(pictureAndBounds.mPicture); - pictureAndBounds.mWroteElapsed = false; - mPictures.append(pictureAndBounds); -} - -void PictureSet::add(const SkRegion& area, SkPicture* picture, - uint32_t elapsed, bool split, bool empty) -{ - DBG_SET_LOGD("%p area={%d,%d,r=%d,b=%d} pict=%p elapsed=%d split=%d", this, - area.getBounds().fLeft, area.getBounds().fTop, - area.getBounds().fRight, area.getBounds().fBottom, picture, - elapsed, split); - SkSafeRef(picture); - /* if nothing is drawn beneath part of the new picture, mark it as a base */ - SkRegion diff = SkRegion(area); - Pictures* last = mPictures.end(); - for (Pictures* working = mPictures.begin(); working != last; working++) - diff.op(working->mArea, SkRegion::kDifference_Op); - Pictures pictureAndBounds = {area, picture, area.getBounds(), - elapsed, split, false, diff.isEmpty() == false, empty}; - mPictures.append(pictureAndBounds); -} - -/* -Pictures are discarded when they are fully drawn over. -When a picture is partially drawn over, it is discarded if it is not a base, and -its rectangular bounds is reduced if it is a base. -*/ -bool PictureSet::build() -{ - bool rebuild = false; - DBG_SET_LOGD("%p", this); - // walk pictures back to front, removing or trimming obscured ones - SkRegion drawn; - SkRegion inval; - Pictures* first = mPictures.begin(); - Pictures* last = mPictures.end(); - Pictures* working; - bool checkForNewBases = false; - for (working = last; working != first; ) { - --working; - SkRegion& area = working->mArea; - SkRegion visibleArea(area); - visibleArea.op(drawn, SkRegion::kDifference_Op); -#if PICTURE_SET_DEBUG - const SkIRect& a = area.getBounds(); - const SkIRect& d = drawn.getBounds(); - const SkIRect& i = inval.getBounds(); - const SkIRect& v = visibleArea.getBounds(); - DBG_SET_LOGD("%p [%d] area={%d,%d,r=%d,b=%d} drawn={%d,%d,r=%d,b=%d}" - " inval={%d,%d,r=%d,b=%d} vis={%d,%d,r=%d,b=%d}", - this, working - first, - a.fLeft, a.fTop, a.fRight, a.fBottom, - d.fLeft, d.fTop, d.fRight, d.fBottom, - i.fLeft, i.fTop, i.fRight, i.fBottom, - v.fLeft, v.fTop, v.fRight, v.fBottom); -#endif - bool tossPicture = false; - if (working->mBase == false) { - if (area != visibleArea) { - if (visibleArea.isEmpty() == false) { - DBG_SET_LOGD("[%d] partially overdrawn", working - first); - inval.op(visibleArea, SkRegion::kUnion_Op); - } else - DBG_SET_LOGD("[%d] fully hidden", working - first); - area.setEmpty(); - tossPicture = true; - } - } else { - const SkIRect& visibleBounds = visibleArea.getBounds(); - const SkIRect& areaBounds = area.getBounds(); - if (visibleBounds != areaBounds) { - DBG_SET_LOGD("[%d] base to be reduced", working - first); - area.setRect(visibleBounds); - checkForNewBases = tossPicture = true; - } - if (area.intersects(inval)) { - DBG_SET_LOGD("[%d] base to be redrawn", working - first); - tossPicture = true; - } - } - if (tossPicture) { - SkSafeUnref(working->mPicture); - working->mPicture = NULL; // mark to redraw - } - if (working->mPicture == NULL) // may have been set to null elsewhere - rebuild = true; - drawn.op(area, SkRegion::kUnion_Op); - } - // collapse out empty regions - Pictures* writer = first; - for (working = first; working != last; working++) { - if (working->mArea.isEmpty()) - continue; - *writer++ = *working; - } -#if PICTURE_SET_DEBUG - if ((unsigned) (writer - first) != mPictures.size()) - DBG_SET_LOGD("shrink=%d (was %d)", writer - first, mPictures.size()); -#endif - mPictures.shrink(writer - first); - /* When a base is discarded because it was entirely drawn over, all - remaining pictures are checked to see if one has become a base. */ - if (checkForNewBases) { - drawn.setEmpty(); - Pictures* last = mPictures.end(); - for (working = mPictures.begin(); working != last; working++) { - SkRegion& area = working->mArea; - if (drawn.contains(working->mArea) == false) { - working->mBase = true; - DBG_SET_LOGD("[%d] new base", working - mPictures.begin()); - } - drawn.op(working->mArea, SkRegion::kUnion_Op); - } - } - validate(__FUNCTION__); - return rebuild; -} - -void PictureSet::checkDimensions(int width, int height, SkRegion* inval) -{ - if (mWidth == width && mHeight == height) - return; - DBG_SET_LOGD("%p old:(w=%d,h=%d) new:(w=%d,h=%d)", this, - mWidth, mHeight, width, height); - if (mWidth == width && height > mHeight) { // only grew vertically - SkIRect rect; - rect.set(0, mHeight, width, height - mHeight); - inval->op(rect, SkRegion::kUnion_Op); - } else { - clear(); // if both width/height changed, clear the old cache - inval->setRect(0, 0, width, height); - } - mWidth = width; - mHeight = height; -} - -void PictureSet::clear() -{ - DBG_SET_LOG(""); - Pictures* last = mPictures.end(); - for (Pictures* working = mPictures.begin(); working != last; working++) { - working->mArea.setEmpty(); - SkSafeUnref(working->mPicture); - } - mPictures.clear(); - mWidth = mHeight = 0; -} - -bool PictureSet::draw(SkCanvas* canvas) -{ - validate(__FUNCTION__); - Pictures* first = mPictures.begin(); - Pictures* last = mPictures.end(); - Pictures* working; - SkRect bounds; - if (canvas->getClipBounds(&bounds) == false) - return false; - SkIRect irect; - bounds.roundOut(&irect); - for (working = last; working != first; ) { - --working; - if (working->mArea.contains(irect)) { -#if PICTURE_SET_DEBUG - const SkIRect& b = working->mArea.getBounds(); - DBG_SET_LOGD("contains working->mArea={%d,%d,%d,%d}" - " irect={%d,%d,%d,%d}", b.fLeft, b.fTop, b.fRight, b.fBottom, - irect.fLeft, irect.fTop, irect.fRight, irect.fBottom); -#endif - first = working; - break; - } - } - DBG_SET_LOGD("%p first=%d last=%d", this, first - mPictures.begin(), - last - mPictures.begin()); - uint32_t maxElapsed = 0; - for (working = first; working != last; working++) { - const SkRegion& area = working->mArea; - if (area.quickReject(irect)) { -#if PICTURE_SET_DEBUG - const SkIRect& b = area.getBounds(); - DBG_SET_LOGD("[%d] %p quickReject working->mArea={%d,%d,%d,%d}" - " irect={%d,%d,%d,%d}", working - first, working, - b.fLeft, b.fTop, b.fRight, b.fBottom, - irect.fLeft, irect.fTop, irect.fRight, irect.fBottom); -#endif - working->mElapsed = 0; - continue; - } - int saved = canvas->save(); - SkRect pathBounds; - if (area.isComplex()) { - SkPath pathClip; - area.getBoundaryPath(&pathClip); - canvas->clipPath(pathClip); - pathBounds = pathClip.getBounds(); - } else { - pathBounds.set(area.getBounds()); - canvas->clipRect(pathBounds); - } - canvas->translate(pathBounds.fLeft, pathBounds.fTop); - canvas->save(); - uint32_t startTime = getThreadMsec(); - canvas->drawPicture(*working->mPicture); - size_t elapsed = working->mElapsed = getThreadMsec() - startTime; - working->mWroteElapsed = true; - if (maxElapsed < elapsed && (pathBounds.width() >= MIN_SPLITTABLE || - pathBounds.height() >= MIN_SPLITTABLE)) - maxElapsed = elapsed; - canvas->restoreToCount(saved); -#define DRAW_TEST_IMAGE 01 -#if DRAW_TEST_IMAGE && PICTURE_SET_DEBUG - SkColor color = 0x3f000000 | (0xffffff & (unsigned) working); - canvas->drawColor(color); - SkPaint paint; - color ^= 0x00ffffff; - paint.setColor(color); - char location[256]; - for (int x = area.getBounds().fLeft & ~0x3f; - x < area.getBounds().fRight; x += 0x40) { - for (int y = area.getBounds().fTop & ~0x3f; - y < area.getBounds().fBottom; y += 0x40) { - int len = snprintf(location, sizeof(location) - 1, "(%d,%d)", x, y); - canvas->drawText(location, len, x, y, paint); - } - } -#endif - DBG_SET_LOGD("[%d] %p working->mArea={%d,%d,%d,%d} elapsed=%d base=%s", - working - first, working, - area.getBounds().fLeft, area.getBounds().fTop, - area.getBounds().fRight, area.getBounds().fBottom, - working->mElapsed, working->mBase ? "true" : "false"); - } - // dump(__FUNCTION__); - return maxElapsed >= MAX_DRAW_TIME; -} - -void PictureSet::dump(const char* label) const -{ -#if PICTURE_SET_DUMP - DBG_SET_LOGD("%p %s (%d) (w=%d,h=%d)", this, label, mPictures.size(), - mWidth, mHeight); - const Pictures* last = mPictures.end(); - for (const Pictures* working = mPictures.begin(); working != last; working++) { - const SkIRect& bounds = working->mArea.getBounds(); - const SkIRect& unsplit = working->mUnsplit; - MeasureStream measure; - if (working->mPicture != NULL) - working->mPicture->serialize(&measure); - LOGD(" [%d]" - " mArea.bounds={%d,%d,r=%d,b=%d}" - " mPicture=%p" - " mUnsplit={%d,%d,r=%d,b=%d}" - " mElapsed=%d" - " mSplit=%s" - " mWroteElapsed=%s" - " mBase=%s" - " pict-size=%d", - working - mPictures.begin(), - bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, - working->mPicture, - unsplit.fLeft, unsplit.fTop, unsplit.fRight, unsplit.fBottom, - working->mElapsed, working->mSplit ? "true" : "false", - working->mWroteElapsed ? "true" : "false", - working->mBase ? "true" : "false", - measure.mTotal); - } -#endif -} - -class IsEmptyBounder : public SkBounder { - virtual bool onIRect(const SkIRect& rect) { - return false; - } -}; - -class IsEmptyCanvas : public SkCanvas { -public: - IsEmptyCanvas(SkBounder* bounder, SkPicture* picture) : - mPicture(picture), mEmpty(true) { - setBounder(bounder); - } - - void notEmpty() { - mEmpty = false; - mPicture->abortPlayback(); - } - - virtual bool clipPath(const SkPath&, SkRegion::Op) { - // this can be expensive to actually do, and doesn't affect the - // question of emptiness, so we make it a no-op - return true; - } - - virtual void commonDrawBitmap(const SkBitmap& bitmap, const SkIRect* rect, - const SkMatrix& , const SkPaint& ) { - if (bitmap.width() <= 1 || bitmap.height() <= 1) - return; - DBG_SET_LOGD("abort {%d,%d}", bitmap.width(), bitmap.height()); - notEmpty(); - } - - virtual void drawPaint(const SkPaint& paint) { - } - - virtual void drawPath(const SkPath& , const SkPaint& paint) { - DBG_SET_LOG("abort"); - notEmpty(); - } - - virtual void drawPoints(PointMode , size_t , const SkPoint [], - const SkPaint& paint) { - } - - virtual void drawRect(const SkRect& , const SkPaint& paint) { - // wait for visual content - if (paint.getColor() != SK_ColorWHITE) - notEmpty(); - } - - virtual void drawSprite(const SkBitmap& , int , int , - const SkPaint* paint = NULL) { - DBG_SET_LOG("abort"); - notEmpty(); - } - - virtual void drawText(const void* , size_t byteLength, SkScalar , - SkScalar , const SkPaint& paint) { - DBG_SET_LOGD("abort %d", byteLength); - notEmpty(); - } - - virtual void drawPosText(const void* , size_t byteLength, - const SkPoint [], const SkPaint& paint) { - DBG_SET_LOGD("abort %d", byteLength); - notEmpty(); - } - - virtual void drawPosTextH(const void* , size_t byteLength, - const SkScalar [], SkScalar , - const SkPaint& paint) { - DBG_SET_LOGD("abort %d", byteLength); - notEmpty(); - } - - virtual void drawTextOnPath(const void* , size_t byteLength, - const SkPath& , const SkMatrix* , - const SkPaint& paint) { - DBG_SET_LOGD("abort %d", byteLength); - notEmpty(); - } - - virtual void drawPicture(SkPicture& picture) { - SkCanvas::drawPicture(picture); - } - - SkPicture* mPicture; - bool mEmpty; -}; - -bool PictureSet::emptyPicture(SkPicture* picture) const -{ - IsEmptyBounder isEmptyBounder; - IsEmptyCanvas checker(&isEmptyBounder, picture); - SkBitmap bitmap; - bitmap.setConfig(SkBitmap::kARGB_8888_Config, mWidth, mHeight); - checker.setBitmapDevice(bitmap); - checker.drawPicture(*picture); - return checker.mEmpty; -} - -bool PictureSet::isEmpty() const -{ - const Pictures* last = mPictures.end(); - for (const Pictures* working = mPictures.begin(); working != last; working++) { - if (!working->mEmpty) - return false; - } - return true; -} - -bool PictureSet::reuseSubdivided(const SkRegion& inval) -{ - validate(__FUNCTION__); - if (inval.isComplex()) - return false; - Pictures* working, * last = mPictures.end(); - const SkIRect& invalBounds = inval.getBounds(); - bool steal = false; - for (working = mPictures.begin(); working != last; working++) { - if (working->mSplit && invalBounds == working->mUnsplit) { - steal = true; - continue; - } - if (steal == false) - continue; - SkRegion temp = SkRegion(inval); - temp.op(working->mArea, SkRegion::kIntersect_Op); - if (temp.isEmpty() || temp == working->mArea) - continue; - return false; - } - if (steal == false) - return false; - for (working = mPictures.begin(); working != last; working++) { - if ((working->mSplit == false || invalBounds != working->mUnsplit) && - inval.contains(working->mArea) == false) - continue; - SkSafeUnref(working->mPicture); - working->mPicture = NULL; - } - return true; -} - -void PictureSet::set(const PictureSet& src) -{ - DBG_SET_LOGD("start %p src=%p", this, &src); - clear(); - mWidth = src.mWidth; - mHeight = src.mHeight; - const Pictures* last = src.mPictures.end(); - for (const Pictures* working = src.mPictures.begin(); working != last; working++) - add(working); - // dump(__FUNCTION__); - validate(__FUNCTION__); - DBG_SET_LOG("end"); -} - -void PictureSet::setDrawTimes(const PictureSet& src) -{ - validate(__FUNCTION__); - if (mWidth != src.mWidth || mHeight != src.mHeight) - return; - Pictures* last = mPictures.end(); - Pictures* working = mPictures.begin(); - if (working == last) - return; - const Pictures* srcLast = src.mPictures.end(); - const Pictures* srcWorking = src.mPictures.begin(); - for (; srcWorking != srcLast; srcWorking++) { - if (srcWorking->mWroteElapsed == false) - continue; - while ((srcWorking->mArea != working->mArea || - srcWorking->mPicture != working->mPicture)) { - if (++working == last) - return; - } - DBG_SET_LOGD("%p [%d] [%d] {%d,%d,r=%d,b=%d} working->mElapsed=%d <- %d", - this, working - mPictures.begin(), srcWorking - src.mPictures.begin(), - working->mArea.getBounds().fLeft, working->mArea.getBounds().fTop, - working->mArea.getBounds().fRight, working->mArea.getBounds().fBottom, - working->mElapsed, srcWorking->mElapsed); - working->mElapsed = srcWorking->mElapsed; - } -} - -void PictureSet::setPicture(size_t i, SkPicture* p) -{ - SkSafeUnref(mPictures[i].mPicture); - mPictures[i].mPicture = p; - mPictures[i].mEmpty = emptyPicture(p); -} - -void PictureSet::split(PictureSet* out) const -{ - dump(__FUNCTION__); - DBG_SET_LOGD("%p", this); - SkIRect totalBounds; - out->mWidth = mWidth; - out->mHeight = mHeight; - totalBounds.set(0, 0, mWidth, mHeight); - SkRegion* total = new SkRegion(totalBounds); - const Pictures* last = mPictures.end(); - const Pictures* working; - uint32_t balance = 0; - int multiUnsplitFastPictures = 0; // > 1 has more than 1 - for (working = mPictures.begin(); working != last; working++) { - if (working->mElapsed >= MAX_DRAW_TIME || working->mSplit) - continue; - if (++multiUnsplitFastPictures > 1) - break; - } - for (working = mPictures.begin(); working != last; working++) { - uint32_t elapsed = working->mElapsed; - if (elapsed < MAX_DRAW_TIME) { - bool split = working->mSplit; - DBG_SET_LOGD("elapsed=%d working=%p total->getBounds()=" - "{%d,%d,r=%d,b=%d} split=%s", elapsed, working, - total->getBounds().fLeft, total->getBounds().fTop, - total->getBounds().fRight, total->getBounds().fBottom, - split ? "true" : "false"); - if (multiUnsplitFastPictures <= 1 || split) { - total->op(working->mArea, SkRegion::kDifference_Op); - out->add(working->mArea, working->mPicture, elapsed, split, - working->mEmpty); - } else if (balance < elapsed) - balance = elapsed; - continue; - } - total->op(working->mArea, SkRegion::kDifference_Op); - const SkIRect& bounds = working->mArea.getBounds(); - int width = bounds.width(); - int height = bounds.height(); - int across = 1; - int down = 1; - while (height >= MIN_SPLITTABLE || width >= MIN_SPLITTABLE) { - if (height >= width) { - height >>= 1; - down <<= 1; - } else { - width >>= 1; - across <<= 1 ; - } - if ((elapsed >>= 1) < MAX_DRAW_TIME) - break; - } - width = bounds.width(); - height = bounds.height(); - int top = bounds.fTop; - for (int indexY = 0; indexY < down; ) { - int bottom = bounds.fTop + height * ++indexY / down; - int left = bounds.fLeft; - for (int indexX = 0; indexX < across; ) { - int right = bounds.fLeft + width * ++indexX / across; - SkIRect cBounds; - cBounds.set(left, top, right, bottom); - out->add(SkRegion(cBounds), (across | down) != 1 ? NULL : - working->mPicture, elapsed, true, - (across | down) != 1 ? false : working->mEmpty); - left = right; - } - top = bottom; - } - } - DBG_SET_LOGD("%p w=%d h=%d total->isEmpty()=%s multiUnsplitFastPictures=%d", - this, mWidth, mHeight, total->isEmpty() ? "true" : "false", - multiUnsplitFastPictures); - if (!total->isEmpty() && multiUnsplitFastPictures > 1) - out->add(*total, NULL, balance, false, false); - delete total; - validate(__FUNCTION__); - out->dump("split-out"); -} - -bool PictureSet::validate(const char* funct) const -{ - bool valid = true; -#if PICTURE_SET_VALIDATE - SkRegion all; - const Pictures* first = mPictures.begin(); - for (const Pictures* working = mPictures.end(); working != first; ) { - --working; - const SkPicture* pict = working->mPicture; - const SkRegion& area = working->mArea; - const SkIRect& bounds = area.getBounds(); - bool localValid = false; - if (working->mUnsplit.isEmpty()) - LOGD("%s working->mUnsplit.isEmpty()", funct); - else if (working->mUnsplit.contains(bounds) == false) - LOGD("%s working->mUnsplit.contains(bounds) == false", funct); - else if (working->mElapsed >= 1000) - LOGD("%s working->mElapsed >= 1000", funct); - else if ((working->mSplit & 0xfe) != 0) - LOGD("%s (working->mSplit & 0xfe) != 0", funct); - else if ((working->mWroteElapsed & 0xfe) != 0) - LOGD("%s (working->mWroteElapsed & 0xfe) != 0", funct); - else if (pict != NULL) { - int pictWidth = pict->width(); - int pictHeight = pict->height(); - if (pictWidth < bounds.width()) - LOGD("%s pictWidth=%d < bounds.width()=%d", funct, pictWidth, bounds.width()); - else if (pictHeight < bounds.height()) - LOGD("%s pictHeight=%d < bounds.height()=%d", funct, pictHeight, bounds.height()); - else if (working->mArea.isEmpty()) - LOGD("%s working->mArea.isEmpty()", funct); - else - localValid = true; - } else - localValid = true; - working->mArea.validate(); - if (localValid == false) { - if (all.contains(area) == true) - LOGD("%s all.contains(area) == true", funct); - else - localValid = true; - } - valid &= localValid; - all.op(area, SkRegion::kUnion_Op); - } - const SkIRect& allBounds = all.getBounds(); - if (valid) { - valid = false; - if (allBounds.width() != mWidth) - LOGD("%s allBounds.width()=%d != mWidth=%d", funct, allBounds.width(), mWidth); - else if (allBounds.height() != mHeight) - LOGD("%s allBounds.height()=%d != mHeight=%d", funct, allBounds.height(), mHeight); - else - valid = true; - } - while (valid == false) - ; -#endif - return valid; -} - -} /* namespace android */ diff --git a/WebKit/android/jni/PictureSet.h b/WebKit/android/jni/PictureSet.h deleted file mode 100644 index b177958..0000000 --- a/WebKit/android/jni/PictureSet.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2008, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef PICTURESET_H -#define PICTURESET_H - -#define PICTURE_SET_DUMP 0 -#define PICTURE_SET_DEBUG 0 -#define PICTURE_SET_VALIDATE 0 - -#if PICTURE_SET_DEBUG -#define DBG_SET_LOG(message) LOGD("%s %s", __FUNCTION__, message) -#define DBG_SET_LOGD(format, ...) LOGD("%s " format, __FUNCTION__, __VA_ARGS__) -#define DEBUG_SET_UI_LOGD(...) LOGD(__VA_ARGS__) -#else -#define DBG_SET_LOG(message) ((void)0) -#define DBG_SET_LOGD(format, ...) ((void)0) -#define DEBUG_SET_UI_LOGD(...) ((void)0) -#endif - -#include "jni.h" -#include "SkRegion.h" -#include - -class SkCanvas; -class SkPicture; -class SkIRect; - -namespace android { - - class PictureSet { - public: - PictureSet(); - PictureSet(const PictureSet& src) { set(src); } - virtual ~PictureSet(); - void add(const SkRegion& area, SkPicture* picture, - uint32_t elapsed, bool split) - { - add(area, picture, elapsed, split, emptyPicture(picture)); - } - void add(const SkRegion& area, SkPicture* picture, - uint32_t elapsed, bool split, bool empty); - const SkIRect& bounds(size_t i) const { - return mPictures[i].mArea.getBounds(); } - bool build(); - // Update mWidth/mHeight, and adds any additional inval region - void checkDimensions(int width, int height, SkRegion* inval); - void clear(); - bool draw(SkCanvas* ); - static PictureSet* GetNativePictureSet(JNIEnv* env, jobject jpic); - int height() const { return mHeight; } - bool isEmpty() const; // returns true if empty or only trivial content - bool reuseSubdivided(const SkRegion& ); - void set(const PictureSet& ); - void setDrawTimes(const PictureSet& ); - void setPicture(size_t i, SkPicture* p); - size_t size() const { return mPictures.size(); } - void split(PictureSet* result) const; - bool upToDate(size_t i) const { return mPictures[i].mPicture != NULL; } - int width() const { return mWidth; } - void dump(const char* label) const; - bool validate(const char* label) const; - private: - bool emptyPicture(SkPicture* ) const; // true if no text, images, paths - struct Pictures { - SkRegion mArea; - SkPicture* mPicture; - SkIRect mUnsplit; - uint32_t mElapsed; - bool mSplit : 8; - bool mWroteElapsed : 8; - bool mBase : 8; // true if nothing is drawn underneath this - bool mEmpty : 8; // true if the picture only draws white - }; - void add(const Pictures* temp); - WTF::Vector mPictures; - int mHeight; - int mWidth; - }; -} - -#endif diff --git a/WebKit/android/jni/WebCoreFrameBridge.cpp b/WebKit/android/jni/WebCoreFrameBridge.cpp deleted file mode 100644 index 15b6d20..0000000 --- a/WebKit/android/jni/WebCoreFrameBridge.cpp +++ /dev/null @@ -1,2125 +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 "WebCoreFrameBridge.h" - -#include "Arena.h" -#include "BackForwardList.h" -#include "MemoryCache.h" -#include "Chrome.h" -#include "ChromeClientAndroid.h" -#include "ChromiumInit.h" -#include "ContextMenuClientAndroid.h" -#include "DeviceMotionClientAndroid.h" -#include "DeviceOrientationClientAndroid.h" -#include "Document.h" -#include "DocumentLoader.h" -#include "DragClientAndroid.h" -#include "EditorClientAndroid.h" -#include "Element.h" -#include "FocusController.h" -#include "Font.h" -#include "Frame.h" -#include "FrameLoader.h" -#include "FrameLoaderClientAndroid.h" -#include "FrameLoadRequest.h" -#include "FrameTree.h" -#include "FrameView.h" -#include "GraphicsContext.h" -#include "HistoryItem.h" -#include "HTMLCollection.h" -#include "HTMLElement.h" -#include "HTMLFormElement.h" -#include "HTMLInputElement.h" -#include "HTMLNames.h" -#include "IconDatabase.h" -#include "Image.h" -#include "InspectorClientAndroid.h" -#include "KURL.h" -#include "Page.h" -#include "PageCache.h" -#include "PlatformString.h" -#include "RenderPart.h" -#include "RenderSkinAndroid.h" -#include "RenderTreeAsText.h" -#include "RenderView.h" -#include "ResourceHandle.h" -#include "ResourceHandleInternal.h" -#include "ScriptController.h" -#include "ScriptValue.h" -#include "SecurityOrigin.h" -#include "SelectionController.h" -#include "Settings.h" -#include "SubstituteData.h" -#include "UrlInterceptResponse.h" -#include "UserGestureIndicator.h" -#include "WebCache.h" -#include "WebCoreJni.h" -#include "WebCoreResourceLoader.h" -#include "WebHistory.h" -#include "WebIconDatabase.h" -#include "WebFrameView.h" -#include "WebUrlLoaderClient.h" -#include "WebViewCore.h" -#include "android_graphics.h" -#include "jni.h" -#include "wds/DebugServer.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if USE(JSC) -#include "GCController.h" -#include "JSDOMWindow.h" -#include "JavaInstanceJSC.h" -#include -#include -#include -#elif USE(V8) -#include "JavaNPObjectV8.h" -#include "JavaInstanceV8.h" -#include "V8Counters.h" -#endif // USE(JSC) - -#ifdef ANDROID_INSTRUMENT -#include "TimeCounter.h" -#endif - -#if ENABLE(ARCHIVE) -#include "WebArchiveAndroid.h" -#endif - -#if ENABLE(WEB_AUTOFILL) -#include "autofill/WebAutoFill.h" -#endif - -using namespace JSC::Bindings; - -static String* gUploadFileLabel; -static String* gResetLabel; -static String* gSubmitLabel; -static String* gNoFileChosenLabel; - -String* WebCore::PlatformBridge::globalLocalizedName( - WebCore::PlatformBridge::rawResId resId) -{ - switch (resId) { - case WebCore::PlatformBridge::FileUploadLabel: - return gUploadFileLabel; - case WebCore::PlatformBridge::ResetLabel: - return gResetLabel; - case WebCore::PlatformBridge::SubmitLabel: - return gSubmitLabel; - case WebCore::PlatformBridge::FileUploadNoFileChosenLabel: - return gNoFileChosenLabel; - - default: - return 0; - } -} -/** - * Instantiate the localized name desired. - */ -void initGlobalLocalizedName(WebCore::PlatformBridge::rawResId resId, - android::WebFrame* webFrame) -{ - String** pointer; - switch (resId) { - case WebCore::PlatformBridge::FileUploadLabel: - pointer = &gUploadFileLabel; - break; - case WebCore::PlatformBridge::ResetLabel: - pointer = &gResetLabel; - break; - case WebCore::PlatformBridge::SubmitLabel: - pointer = &gSubmitLabel; - break; - case WebCore::PlatformBridge::FileUploadNoFileChosenLabel: - pointer = &gNoFileChosenLabel; - break; - default: - return; - } - if (!(*pointer) && webFrame) { - (*pointer) = new String(webFrame->getRawResourceFilename(resId).impl()); - } -} - -namespace android { - -// ---------------------------------------------------------------------------- - -#define WEBCORE_MEMORY_CAP 15 * 1024 * 1024 - -// ---------------------------------------------------------------------------- - -struct WebFrame::JavaBrowserFrame -{ - jweak mObj; - jweak mHistoryList; // WebBackForwardList object - jmethodID mStartLoadingResource; - jmethodID mMaybeSavePassword; - jmethodID mShouldInterceptRequest; - jmethodID mLoadStarted; - jmethodID mTransitionToCommitted; - jmethodID mLoadFinished; - jmethodID mReportError; - jmethodID mSetTitle; - jmethodID mWindowObjectCleared; - jmethodID mSetProgress; - jmethodID mDidReceiveIcon; - jmethodID mDidReceiveTouchIconUrl; - jmethodID mUpdateVisitedHistory; - jmethodID mHandleUrl; - jmethodID mCreateWindow; - jmethodID mCloseWindow; - jmethodID mDecidePolicyForFormResubmission; - jmethodID mRequestFocus; - jmethodID mGetRawResFilename; - jmethodID mDensity; - jmethodID mGetFileSize; - jmethodID mGetFile; - jmethodID mDidReceiveAuthenticationChallenge; - jmethodID mReportSslCertError; - jmethodID mDownloadStart; - jmethodID mDidReceiveData; - jmethodID mDidFinishLoading; - jmethodID mSetCertificate; - jmethodID mShouldSaveFormData; - jmethodID mSaveFormData; - jmethodID mAutoLogin; - AutoJObject frame(JNIEnv* env) { - return getRealObject(env, mObj); - } - AutoJObject history(JNIEnv* env) { - return getRealObject(env, mHistoryList); - } -}; - -static jfieldID gFrameField; -#define GET_NATIVE_FRAME(env, obj) ((WebCore::Frame*)env->GetIntField(obj, gFrameField)) -#define SET_NATIVE_FRAME(env, obj, frame) (env->SetIntField(obj, gFrameField, frame)) - -// ---------------------------------------------------------------------------- - -WebFrame::WebFrame(JNIEnv* env, jobject obj, jobject historyList, WebCore::Page* page) - : mPage(page) -{ - jclass clazz = env->GetObjectClass(obj); - 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 = - env->GetMethodID(clazz, "shouldInterceptRequest", - "(Ljava/lang/String;)Landroid/webkit/WebResourceResponse;"); - mJavaFrame->mLoadStarted = env->GetMethodID(clazz, "loadStarted", - "(Ljava/lang/String;Landroid/graphics/Bitmap;IZ)V"); - mJavaFrame->mTransitionToCommitted = env->GetMethodID(clazz, "transitionToCommitted", - "(IZ)V"); - mJavaFrame->mLoadFinished = env->GetMethodID(clazz, "loadFinished", - "(Ljava/lang/String;IZ)V"); - mJavaFrame->mReportError = env->GetMethodID(clazz, "reportError", - "(ILjava/lang/String;Ljava/lang/String;)V"); - mJavaFrame->mSetTitle = env->GetMethodID(clazz, "setTitle", - "(Ljava/lang/String;)V"); - mJavaFrame->mWindowObjectCleared = env->GetMethodID(clazz, "windowObjectCleared", - "(I)V"); - mJavaFrame->mSetProgress = env->GetMethodID(clazz, "setProgress", - "(I)V"); - mJavaFrame->mDidReceiveIcon = env->GetMethodID(clazz, "didReceiveIcon", - "(Landroid/graphics/Bitmap;)V"); - mJavaFrame->mDidReceiveTouchIconUrl = env->GetMethodID(clazz, "didReceiveTouchIconUrl", - "(Ljava/lang/String;Z)V"); - mJavaFrame->mUpdateVisitedHistory = env->GetMethodID(clazz, "updateVisitedHistory", - "(Ljava/lang/String;Z)V"); - mJavaFrame->mHandleUrl = env->GetMethodID(clazz, "handleUrl", - "(Ljava/lang/String;)Z"); - mJavaFrame->mCreateWindow = env->GetMethodID(clazz, "createWindow", - "(ZZ)Landroid/webkit/BrowserFrame;"); - mJavaFrame->mCloseWindow = env->GetMethodID(clazz, "closeWindow", - "(Landroid/webkit/WebViewCore;)V"); - mJavaFrame->mDecidePolicyForFormResubmission = env->GetMethodID(clazz, - "decidePolicyForFormResubmission", "(I)V"); - mJavaFrame->mRequestFocus = env->GetMethodID(clazz, "requestFocus", - "()V"); - mJavaFrame->mGetRawResFilename = env->GetMethodID(clazz, "getRawResFilename", - "(I)Ljava/lang/String;"); - mJavaFrame->mDensity = env->GetMethodID(clazz, "density","()F"); - mJavaFrame->mGetFileSize = env->GetMethodID(clazz, "getFileSize", "(Ljava/lang/String;)I"); - mJavaFrame->mGetFile = env->GetMethodID(clazz, "getFile", "(Ljava/lang/String;[BII)I"); - mJavaFrame->mDidReceiveAuthenticationChallenge = env->GetMethodID(clazz, "didReceiveAuthenticationChallenge", - "(ILjava/lang/String;Ljava/lang/String;Z)V"); - mJavaFrame->mReportSslCertError = env->GetMethodID(clazz, "reportSslCertError", "(II[B)V"); - mJavaFrame->mDownloadStart = env->GetMethodID(clazz, "downloadStart", - "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;J)V"); - mJavaFrame->mDidReceiveData = env->GetMethodID(clazz, "didReceiveData", "([BI)V"); - mJavaFrame->mDidFinishLoading = env->GetMethodID(clazz, "didFinishLoading", "()V"); - mJavaFrame->mSetCertificate = env->GetMethodID(clazz, "setCertificate", "([B)V"); - mJavaFrame->mShouldSaveFormData = env->GetMethodID(clazz, "shouldSaveFormData", "()Z"); - mJavaFrame->mSaveFormData = env->GetMethodID(clazz, "saveFormData", "(Ljava/util/HashMap;)V"); - mJavaFrame->mAutoLogin = env->GetMethodID(clazz, "autoLogin", - "(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->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"); - - mUserAgent = WTF::String(); - mUserInitiatedAction = false; - mBlockNetworkLoads = false; - m_renderSkins = 0; -} - -WebFrame::~WebFrame() -{ - if (mJavaFrame->mObj) { - JNIEnv* env = getJNIEnv(); - env->DeleteWeakGlobalRef(mJavaFrame->mObj); - env->DeleteWeakGlobalRef(mJavaFrame->mHistoryList); - mJavaFrame->mObj = 0; - } - delete mJavaFrame; - delete m_renderSkins; -} - -WebFrame* WebFrame::getWebFrame(const WebCore::Frame* frame) -{ - FrameLoaderClientAndroid* client = - static_cast (frame->loader()->client()); - return client->webFrame(); -} - -static jobject createJavaMapFromHTTPHeaders(JNIEnv* env, const WebCore::HTTPHeaderMap& map) -{ - jclass mapClass = env->FindClass("java/util/HashMap"); - LOG_ASSERT(mapClass, "Could not find HashMap class!"); - jmethodID init = env->GetMethodID(mapClass, "", "(I)V"); - LOG_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"); - 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"); - - WebCore::HTTPHeaderMap::const_iterator end = map.end(); - for (WebCore::HTTPHeaderMap::const_iterator i = map.begin(); i != end; ++i) { - if (i->first.length() == 0 || i->second.length() == 0) - continue; - jstring key = wtfStringToJstring(env, i->first); - jstring val = wtfStringToJstring(env, i->second); - if (key && val) { - env->CallObjectMethod(hashMap, put, key, val); - } - env->DeleteLocalRef(key); - env->DeleteLocalRef(val); - } - - env->DeleteLocalRef(mapClass); - - return hashMap; -} - -// This class stores the URI and the size of each file for upload. The URI is -// stored so we do not have to create it again. The size is stored so we can -// compare the actual size of the file with the stated size. If the actual size -// is larger, we will not copy it, since we will not have enough space in our -// buffer. -class FileInfo { -public: - FileInfo(JNIEnv* env, const WTF::String& name) { - m_uri = wtfStringToJstring(env, name); - checkException(env); - m_size = 0; - m_env = env; - } - ~FileInfo() { - m_env->DeleteLocalRef(m_uri); - } - int getSize() { return m_size; } - jstring getUri() { return m_uri; } - void setSize(int size) { m_size = size; } -private: - // This is only a pointer to the JNIEnv* returned by - // JSC::Bindings::getJNIEnv(). Used to delete the jstring when finished. - JNIEnv* m_env; - jstring m_uri; - int m_size; -}; - -PassRefPtr -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()); - - WTF::String method = request.httpMethod(); - WebCore::HTTPHeaderMap headers = request.httpHeaderFields(); - - JNIEnv* env = getJNIEnv(); - 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(mJavaFrame->frame(env).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 NULL; - - PassRefPtr 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()); - - JNIEnv* env = getJNIEnv(); - jstring urlStr = wtfStringToJstring(env, url); - jobject response = env->CallObjectMethod(mJavaFrame->frame(env).get(), mJavaFrame->mShouldInterceptRequest, urlStr); - env->DeleteLocalRef(urlStr); - if (response == 0) - return 0; - return new UrlInterceptResponse(env, response); -} - -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()); - JNIEnv* env = getJNIEnv(); - - jstring descStr = wtfStringToJstring(env, description); - jstring failUrl = wtfStringToJstring(env, failingUrl); - env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mReportError, - errorCode, descStr, failUrl); - env->DeleteLocalRef(descStr); - env->DeleteLocalRef(failUrl); -} - -void -WebFrame::loadStarted(WebCore::Frame* frame) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); -#endif - // activeDocumentLoader() can return null. - DocumentLoader* documentLoader = frame->loader()->activeDocumentLoader(); - if (documentLoader == NULL) - return; - - const WebCore::KURL& url = documentLoader->url(); - if (url.isEmpty()) - return; - LOGV("::WebCore:: loadStarted %s", url.string().ascii().data()); - - bool isMainFrame = (!frame->tree() || !frame->tree()->parent()); - WebCore::FrameLoadType loadType = frame->loader()->loadType(); - - if (loadType == WebCore::FrameLoadTypeReplace || - (loadType == WebCore::FrameLoadTypeRedirectWithLockedBackForwardList && - !isMainFrame)) - return; - - JNIEnv* env = getJNIEnv(); - const WTF::String& urlString = url.string(); - // If this is the main frame and we already have a favicon in the database, - // send it along with the page started notification. - jobject favicon = NULL; - if (isMainFrame) { - WebCore::Image* icon = WebCore::iconDatabase()->iconForPageURL(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()); - } - jstring urlStr = wtfStringToJstring(env, urlString); - - env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mLoadStarted, urlStr, favicon, - (int)loadType, isMainFrame); - checkException(env); - env->DeleteLocalRef(urlStr); - if (favicon) - env->DeleteLocalRef(favicon); - - // Inform the client that the main frame has started a new load. - if (isMainFrame && mPage) { - Chrome* chrome = mPage->chrome(); - if (chrome) { - ChromeClientAndroid* client = static_cast(chrome->client()); - if (client) - client->onMainFrameLoadStarted(); - } - } -} - -void -WebFrame::transitionToCommitted(WebCore::Frame* frame) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); -#endif - JNIEnv* env = getJNIEnv(); - WebCore::FrameLoadType loadType = frame->loader()->loadType(); - bool isMainFrame = (!frame->tree() || !frame->tree()->parent()); - env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mTransitionToCommitted, - (int)loadType, isMainFrame); - checkException(env); -} - -void -WebFrame::didFinishLoad(WebCore::Frame* frame) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); -#endif - JNIEnv* env = getJNIEnv(); - - // activeDocumentLoader() can return null. - WebCore::FrameLoader* loader = frame->loader(); - DocumentLoader* documentLoader = loader->activeDocumentLoader(); - if (documentLoader == NULL) - return; - - const WebCore::KURL& url = documentLoader->url(); - if (url.isEmpty()) - return; - LOGV("::WebCore:: didFinishLoad %s", url.string().ascii().data()); - - bool isMainFrame = (!frame->tree() || !frame->tree()->parent()); - WebCore::FrameLoadType loadType = loader->loadType(); - const WTF::String& urlString = url.string(); - jstring urlStr = wtfStringToJstring(env, urlString); - env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mLoadFinished, urlStr, - (int)loadType, isMainFrame); - checkException(env); - env->DeleteLocalRef(urlStr); -} - -void -WebFrame::addHistoryItem(WebCore::HistoryItem* item) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); -#endif - LOGV("::WebCore:: addHistoryItem"); - JNIEnv* env = getJNIEnv(); - WebHistory::AddItem(mJavaFrame->history(env), item); -} - -void -WebFrame::removeHistoryItem(int index) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); -#endif - LOGV("::WebCore:: removeHistoryItem at %d", index); - JNIEnv* env = getJNIEnv(); - WebHistory::RemoveItem(mJavaFrame->history(env), index); -} - -void -WebFrame::updateHistoryIndex(int newIndex) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); -#endif - LOGV("::WebCore:: updateHistoryIndex to %d", newIndex); - JNIEnv* env = getJNIEnv(); - WebHistory::UpdateHistoryIndex(mJavaFrame->history(env), newIndex); -} - -void -WebFrame::setTitle(const WTF::String& title) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); -#endif -#ifndef NDEBUG - LOGV("setTitle(%s)", title.ascii().data()); -#endif - JNIEnv* env = getJNIEnv(); - jstring jTitleStr = wtfStringToJstring(env, title); - - env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mSetTitle, jTitleStr); - checkException(env); - env->DeleteLocalRef(jTitleStr); -} - -void -WebFrame::windowObjectCleared(WebCore::Frame* frame) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); -#endif - LOGV("::WebCore:: windowObjectCleared"); - JNIEnv* env = getJNIEnv(); - - env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mWindowObjectCleared, (int)frame); - checkException(env); -} - -void -WebFrame::setProgress(float newProgress) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); -#endif - JNIEnv* env = getJNIEnv(); - int progress = (int) (100 * newProgress); - env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mSetProgress, progress); - checkException(env); -} - -const WTF::String -WebFrame::userAgentForURL(const WebCore::KURL* url) -{ - return mUserAgent; -} - -void -WebFrame::didReceiveIcon(WebCore::Image* icon) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); -#endif - LOG_ASSERT(icon, "DidReceiveIcon called without an image!"); - JNIEnv* env = getJNIEnv(); - jobject bitmap = webcoreImageToJavaBitmap(env, icon); - if (!bitmap) - return; - - env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mDidReceiveIcon, bitmap); - env->DeleteLocalRef(bitmap); - checkException(env); -} - -void -WebFrame::didReceiveTouchIconURL(const WTF::String& url, bool precomposed) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); -#endif - JNIEnv* env = getJNIEnv(); - jstring jUrlStr = wtfStringToJstring(env, url); - - env->CallVoidMethod(mJavaFrame->frame(env).get(), - mJavaFrame->mDidReceiveTouchIconUrl, jUrlStr, precomposed); - env->DeleteLocalRef(jUrlStr); - checkException(env); -} - -void -WebFrame::updateVisitedHistory(const WebCore::KURL& url, bool reload) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); -#endif - const WTF::String& urlStr = url.string(); - JNIEnv* env = getJNIEnv(); - jstring jUrlStr = wtfStringToJstring(env, urlStr); - - env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mUpdateVisitedHistory, jUrlStr, reload); - env->DeleteLocalRef(jUrlStr); - checkException(env); -} - -bool -WebFrame::canHandleRequest(const WebCore::ResourceRequest& request) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); -#endif - // always handle "POST" in place - if (equalIgnoringCase(request.httpMethod(), "POST")) - return true; - const WebCore::KURL& requestUrl = request.url(); - bool isUserGesture = UserGestureIndicator::processingUserGesture(); - if (!mUserInitiatedAction && !isUserGesture && - (requestUrl.protocolIs("http") || requestUrl.protocolIs("https") || - requestUrl.protocolIs("file") || requestUrl.protocolIs("about") || - WebCore::protocolIsJavaScript(requestUrl.string()))) - return true; - const WTF::String& url = requestUrl.string(); - // Empty urls should not be sent to java - if (url.isEmpty()) - return true; - JNIEnv* env = getJNIEnv(); - jstring jUrlStr = wtfStringToJstring(env, url); - - // check to see whether browser app wants to hijack url loading. - // if browser app handles the url, we will return false to bail out WebCore loading - jboolean ret = env->CallBooleanMethod(mJavaFrame->frame(env).get(), mJavaFrame->mHandleUrl, jUrlStr); - checkException(env); - env->DeleteLocalRef(jUrlStr); - return (ret == 0); -} - -bool -WebFrame::shouldSaveFormData() -{ - JNIEnv* env = getJNIEnv(); - jboolean ret = env->CallBooleanMethod(mJavaFrame->frame(env).get(), - mJavaFrame->mShouldSaveFormData); - checkException(env); - return ret; -} - -WebCore::Frame* -WebFrame::createWindow(bool dialog, bool userGesture) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); -#endif - JNIEnv* env = getJNIEnv(); - jobject obj = env->CallObjectMethod(mJavaFrame->frame(env).get(), - mJavaFrame->mCreateWindow, dialog, userGesture); - if (obj) { - WebCore::Frame* frame = GET_NATIVE_FRAME(env, obj); - return frame; - } - return NULL; -} - -void -WebFrame::requestFocus() const -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); -#endif - JNIEnv* env = getJNIEnv(); - env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mRequestFocus); - checkException(env); -} - -void -WebFrame::closeWindow(WebViewCore* webViewCore) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); -#endif - assert(webViewCore); - JNIEnv* env = getJNIEnv(); - env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mCloseWindow, - webViewCore->getJavaObject().get()); -} - -struct PolicyFunctionWrapper { - WebCore::FramePolicyFunction func; -}; - -void -WebFrame::decidePolicyForFormResubmission(WebCore::FramePolicyFunction func) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); -#endif - JNIEnv* env = getJNIEnv(); - PolicyFunctionWrapper* p = new PolicyFunctionWrapper; - p->func = func; - env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mDecidePolicyForFormResubmission, p); -} - -WTF::String -WebFrame::getRawResourceFilename(WebCore::PlatformBridge::rawResId id) const -{ - JNIEnv* env = getJNIEnv(); - jstring ret = (jstring) env->CallObjectMethod(mJavaFrame->frame(env).get(), - mJavaFrame->mGetRawResFilename, (int)id); - - return jstringToWtfString(env, ret); -} - -float -WebFrame::density() const -{ - JNIEnv* env = getJNIEnv(); - jfloat dpi = env->CallFloatMethod(mJavaFrame->frame(env).get(), mJavaFrame->mDensity); - checkException(env); - return dpi; -} - -#if USE(CHROME_NETWORK_STACK) -void -WebFrame::didReceiveAuthenticationChallenge(WebUrlLoaderClient* client, const std::string& host, const std::string& realm, bool useCachedCredentials) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); -#endif - JNIEnv* env = getJNIEnv(); - int jHandle = reinterpret_cast(client); - jstring jHost = stdStringToJstring(env, host, true); - jstring jRealm = stdStringToJstring(env, realm, true); - - env->CallVoidMethod(mJavaFrame->frame(env).get(), - mJavaFrame->mDidReceiveAuthenticationChallenge, jHandle, jHost, jRealm, useCachedCredentials); - env->DeleteLocalRef(jHost); - env->DeleteLocalRef(jRealm); - checkException(env); -} -#endif - -void -WebFrame::reportSslCertError(WebUrlLoaderClient* client, int cert_error, const std::string& cert) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); -#endif - JNIEnv* env = getJNIEnv(); - int jHandle = reinterpret_cast(client); - - int len = cert.length(); - jbyteArray jCert = env->NewByteArray(len); - jbyte* bytes = env->GetByteArrayElements(jCert, NULL); - cert.copy(reinterpret_cast(bytes), len); - - env->CallVoidMethod(mJavaFrame->frame(env).get(), - mJavaFrame->mReportSslCertError, jHandle, cert_error, jCert); - env->DeleteLocalRef(jCert); - checkException(env); -} - -#if USE(CHROME_NETWORK_STACK) -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(); - jstring jUrl = stdStringToJstring(env, url, true); - jstring jUserAgent = stdStringToJstring(env, userAgent, true); - jstring jContentDisposition = stdStringToJstring(env, contentDisposition, true); - jstring jMimetype = stdStringToJstring(env, mimetype, true); - - env->CallVoidMethod(mJavaFrame->frame(env).get(), - mJavaFrame->mDownloadStart, jUrl, jUserAgent, jContentDisposition, jMimetype, contentLength); - - env->DeleteLocalRef(jUrl); - env->DeleteLocalRef(jUserAgent); - env->DeleteLocalRef(jContentDisposition); - env->DeleteLocalRef(jMimetype); - checkException(env); -} - -void -WebFrame::didReceiveData(const char* data, int size) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); -#endif - JNIEnv* env = getJNIEnv(); - - jbyteArray jData = env->NewByteArray(size); - jbyte* bytes = env->GetByteArrayElements(jData, NULL); - memcpy(reinterpret_cast(bytes), data, size); - - env->CallVoidMethod(mJavaFrame->frame(env).get(), - mJavaFrame->mDidReceiveData, jData, size); - env->DeleteLocalRef(jData); - checkException(env); -} - -void -WebFrame::didFinishLoading() { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); -#endif - JNIEnv* env = getJNIEnv(); - - env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mDidFinishLoading); - checkException(env); -} - -#endif - -#if USE(CHROME_NETWORK_STACK) -void WebFrame::setCertificate(const std::string& cert) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter); -#endif - JNIEnv* env = getJNIEnv(); - - int len = cert.length(); - jbyteArray jCert = env->NewByteArray(len); - jbyte* bytes = env->GetByteArrayElements(jCert, NULL); - cert.copy(reinterpret_cast(bytes), len); - - env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mSetCertificate, jCert); - - env->DeleteLocalRef(jCert); - checkException(env); -} -#endif - -void WebFrame::autoLogin(const std::string& loginHeader) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimerCoutner::JavaCallbackTimeCounter); -#endif - WTF::String header(loginHeader.c_str(), loginHeader.length()); - WTF::Vector split; - header.split('&', split); - if (!split.isEmpty()) { - WTF::String realm; - WTF::String account; - WTF::String args; - int len = split.size(); - while (len--) { - WTF::String& str = split[len]; - size_t equals = str.find('='); - if (equals == WTF::notFound) - continue; - - WTF::String* result = 0; - if (str.startsWith("realm", false)) - result = &realm; - else if (str.startsWith("account", false)) - result = &account; - else if (str.startsWith("args", false)) - result = &args; - - if (result) - // Decode url escape sequences before sending to the app. - *result = WebCore::decodeURLEscapeSequences(str.substring(equals + 1)); - } - - // realm and args are required parameters. - if (realm.isEmpty() || args.isEmpty()) - return; - - JNIEnv* env = getJNIEnv(); - jstring jRealm = wtfStringToJstring(env, realm, true); - jstring jAccount = wtfStringToJstring(env, account); - jstring jArgs = wtfStringToJstring(env, args, true); - env->CallVoidMethod(mJavaFrame->frame(env).get(), - mJavaFrame->mAutoLogin, jRealm, jAccount, jArgs); - } -} - -void WebFrame::maybeSavePassword(WebCore::Frame* frame, const WebCore::ResourceRequest& request) -{ - if (request.httpMethod() != "POST") - return; - - WTF::String username; - WTF::String password; - if (!getUsernamePasswordFromDom(frame, username, password)) - return; - - JNIEnv* env = getJNIEnv(); - jstring jUsername = wtfStringToJstring(env, username); - jstring jPassword = wtfStringToJstring(env, password); - jbyteArray jPostData = getPostData(request); - if (jPostData) { - env->CallVoidMethod(mJavaFrame->frame(env).get(), - mJavaFrame->mMaybeSavePassword, jPostData, jUsername, jPassword); - } - - env->DeleteLocalRef(jPostData); - env->DeleteLocalRef(jUsername); - env->DeleteLocalRef(jPassword); - checkException(env); -} - -bool WebFrame::getUsernamePasswordFromDom(WebCore::Frame* frame, WTF::String& username, WTF::String& password) -{ - bool found = false; - WTF::PassRefPtr form = frame->document()->forms(); - WebCore::Node* node = form->firstItem(); - while (node && !found && !node->namespaceURI().isNull() && - !node->namespaceURI().isEmpty()) { - const WTF::Vector& elements = - ((WebCore::HTMLFormElement*)node)->associatedElements(); - size_t size = elements.size(); - for (size_t i = 0; i< size && !found; i++) { - WebCore::HTMLElement* e = toHTMLElement(elements[i]); - if (e->hasLocalName(WebCore::HTMLNames::inputTag)) { - WebCore::HTMLInputElement* input = (WebCore::HTMLInputElement*)e; - if (input->autoComplete() == false) - continue; - if (input->isPasswordField()) - password = input->value(); - else if (input->isTextField() || input->isEmailField()) - username = input->value(); - if (!username.isNull() && !password.isNull()) - found = true; - } - } - node = form->nextItem(); - } - return found; -} - -jbyteArray WebFrame::getPostData(const WebCore::ResourceRequest& request) -{ - jbyteArray jPostDataStr = NULL; - WebCore::FormData* formdata = request.httpBody(); - if (formdata) { - JNIEnv* env = getJNIEnv(); - AutoJObject obj = mJavaFrame->frame(env); - - // We can use the formdata->flatten() but it will result in two - // memcpys, first through loading up the vector with the form data - // then another to copy it out of the vector and into the java byte - // array. Instead, we copy the form data ourselves below saving a - // memcpy. - const WTF::Vector& elements = - formdata->elements(); - - // Sizing pass - int size = 0; - size_t n = elements.size(); - FileInfo** fileinfos = new FileInfo*[n]; - for (size_t i = 0; i < n; ++i) { - fileinfos[i] = 0; - const WebCore::FormDataElement& e = elements[i]; - if (e.m_type == WebCore::FormDataElement::data) { - size += e.m_data.size(); - } else if (e.m_type == WebCore::FormDataElement::encodedFile) { - fileinfos[i] = new FileInfo(env, e.m_filename); - int delta = env->CallIntMethod(obj.get(), - mJavaFrame->mGetFileSize, fileinfos[i]->getUri()); - checkException(env); - fileinfos[i]->setSize(delta); - size += delta; - } - } - - // Only create the byte array if there is POST data to pass up. - // The Java code is expecting null if there is no data. - if (size > 0) { - // Copy the actual form data. - jPostDataStr = env->NewByteArray(size); - if (jPostDataStr) { - // Write the form data to the java array. - jbyte* bytes = env->GetByteArrayElements(jPostDataStr, NULL); - int offset = 0; - for (size_t i = 0; i < n; ++i) { - const WebCore::FormDataElement& e = elements[i]; - if (e.m_type == WebCore::FormDataElement::data) { - int delta = e.m_data.size(); - memcpy(bytes + offset, e.m_data.data(), delta); - offset += delta; - } else if (e.m_type - == WebCore::FormDataElement::encodedFile) { - int delta = env->CallIntMethod(obj.get(), - mJavaFrame->mGetFile, fileinfos[i]->getUri(), - jPostDataStr, offset, fileinfos[i]->getSize()); - checkException(env); - offset += delta; - } - } - env->ReleaseByteArrayElements(jPostDataStr, bytes, 0); - } - } - delete[] fileinfos; - } - return jPostDataStr; -} - -// ---------------------------------------------------------------------------- - -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!"); - PolicyFunctionWrapper* pFunc = (PolicyFunctionWrapper*)func; - LOG_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) - pFrame->loader()->resetMultipleFormSubmissionProtection(); - - (pFrame->loader()->policyChecker()->*(pFunc->func))((WebCore::PolicyAction)decision); -} - -static void CreateFrame(JNIEnv* env, jobject obj, jobject javaview, jobject jAssetManager, jobject historyList) -{ - 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; - DeviceMotionClientAndroid* deviceMotionC = new DeviceMotionClientAndroid; - DeviceOrientationClientAndroid* deviceOrientationC = new DeviceOrientationClientAndroid; - - WebCore::Page::PageClients pageClients; - pageClients.chromeClient = chromeC; - pageClients.contextMenuClient = new ContextMenuClientAndroid; - pageClients.editorClient = editorC; - pageClients.dragClient = new DragClientAndroid; - pageClients.inspectorClient = new InspectorClientAndroid; - pageClients.deviceMotionClient = deviceMotionC; - pageClients.deviceOrientationClient = deviceOrientationC; - WebCore::Page* page = new WebCore::Page(pageClients); - - editorC->setPage(page); - page->setGroupName("android.webkit"); - - // Create a WebFrame to access the Java BrowserFrame associated with this page - WebFrame* webFrame = new WebFrame(env, obj, historyList, page); - // Attach webFrame to pageClients.chromeClient and release our ownership - chromeC->setWebFrame(webFrame); - Release(webFrame); - - FrameLoaderClientAndroid* loaderC = new FrameLoaderClientAndroid(webFrame); - // Create a Frame and the page holds its reference - WebCore::Frame* frame = WebCore::Frame::create(page, NULL, loaderC).get(); - loaderC->setFrame(frame); -#if ENABLE(WDS) - WDS::server()->addFrame(frame); -#endif - - // Create a WebViewCore to access the Java WebViewCore associated with this page - WebViewCore* webViewCore = new WebViewCore(env, javaview, frame); - -#if ENABLE(WEB_AUTOFILL) - editorC->getAutoFill()->setWebViewCore(webViewCore); -#endif - - // Create a FrameView - RefPtr frameView = WebCore::FrameView::create(frame); - // Create a WebFrameView - WebFrameView* webFrameView = new WebFrameView(frameView.get(), webViewCore); - // As webFrameView Retains webViewCore, release our ownership - Release(webViewCore); - // As frameView Retains webFrameView, release our ownership - Release(webFrameView); - // Attach the frameView to the frame and release our ownership - frame->setView(frameView); - // Set the frame to active to turn on keyboard focus. - frame->init(); - frame->selection()->setFocused(true); - frame->page()->focusController()->setFocused(true); - deviceMotionC->setWebViewCore(webViewCore); - deviceOrientationC->setWebViewCore(webViewCore); - - // Allow local access to file:/// and substitute data - WebCore::SecurityOrigin::setLocalLoadPolicy( - WebCore::SecurityOrigin::AllowLocalLoadsForLocalAndSubstituteData); - - LOGV("::WebCore:: createFrame %p", frame); - - // Set the mNativeFrame field in Frame - SET_NATIVE_FRAME(env, obj, (int)frame); - - String directory = webFrame->getRawResourceFilename( - WebCore::PlatformBridge::DrawableDir); - if (directory.isEmpty()) - LOGE("Can't find the drawable directory"); - else { - // Setup the asset manager. - AssetManager* am = assetManagerForJavaObject(env, jAssetManager); - // Initialize our skinning classes - webFrame->setRenderSkins(new WebCore::RenderSkinAndroid(am, directory)); - } - for (int i = WebCore::PlatformBridge::FileUploadLabel; - i <= WebCore::PlatformBridge::FileUploadNoFileChosenLabel; i++) - initGlobalLocalizedName( - static_cast(i), webFrame); -} - -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!"); - - LOGV("::WebCore:: deleting frame %p", pFrame); - - WebCore::FrameView* view = pFrame->view(); - view->ref(); - // detachFromParent will cause the page to be closed. - WebCore::FrameLoader* fl = pFrame->loader(); - // retain a pointer because detachFromParent will set the page to null. - WebCore::Page* page = pFrame->page(); - if (fl) - fl->detachFromParent(); - delete page; - view->deref(); - - SET_NATIVE_FRAME(env, obj, 0); -#if ENABLE(WDS) - WDS::server()->removeFrame(pFrame); -#endif -} - -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!"); - - WTF::String webcoreUrl = jstringToWtfString(env, url); - WebCore::KURL kurl(WebCore::KURL(), webcoreUrl); - WebCore::ResourceRequest request(kurl); - if (headers) { - // dalvikvm will raise exception if any of these fail - jclass mapClass = env->FindClass("java/util/Map"); - jmethodID entrySet = env->GetMethodID(mapClass, "entrySet", - "()Ljava/util/Set;"); - jobject set = env->CallObjectMethod(headers, entrySet); - - jclass setClass = env->FindClass("java/util/Set"); - jmethodID iterator = env->GetMethodID(setClass, "iterator", - "()Ljava/util/Iterator;"); - jobject iter = env->CallObjectMethod(set, iterator); - - jclass iteratorClass = env->FindClass("java/util/Iterator"); - jmethodID hasNext = env->GetMethodID(iteratorClass, "hasNext", "()Z"); - jmethodID next = env->GetMethodID(iteratorClass, "next", - "()Ljava/lang/Object;"); - jclass entryClass = env->FindClass("java/util/Map$Entry"); - jmethodID getKey = env->GetMethodID(entryClass, "getKey", - "()Ljava/lang/Object;"); - jmethodID getValue = env->GetMethodID(entryClass, "getValue", - "()Ljava/lang/Object;"); - - while (env->CallBooleanMethod(iter, hasNext)) { - jobject entry = env->CallObjectMethod(iter, next); - jstring key = (jstring) env->CallObjectMethod(entry, getKey); - jstring value = (jstring) env->CallObjectMethod(entry, getValue); - request.setHTTPHeaderField(jstringToWtfString(env, key), jstringToWtfString(env, value)); - env->DeleteLocalRef(entry); - env->DeleteLocalRef(key); - env->DeleteLocalRef(value); - } - - env->DeleteLocalRef(entryClass); - env->DeleteLocalRef(iteratorClass); - env->DeleteLocalRef(iter); - env->DeleteLocalRef(setClass); - env->DeleteLocalRef(set); - env->DeleteLocalRef(mapClass); - } - LOGV("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!"); - - WebCore::KURL kurl(WebCore::KURL(), jstringToWtfString(env, url)); - WebCore::ResourceRequest request(kurl); - request.setHTTPMethod("POST"); - request.setHTTPContentType("application/x-www-form-urlencoded"); - - if (postData) { - jsize size = env->GetArrayLength(postData); - jbyte* bytes = env->GetByteArrayElements(postData, NULL); - RefPtr formData = FormData::create((const void*)bytes, size); - // the identifier uses the same logic as generateFormDataIdentifier() in - // HTMLFormElement.cpp - formData->setIdentifier(static_cast(WTF::currentTime() * 1000000.0)); - request.setHTTPBody(formData); - env->ReleaseByteArrayElements(postData, bytes, 0); - } - - LOGV("PostUrl %s", kurl.string().latin1().data()); - WebCore::FrameLoadRequest frameRequest(pFrame->document()->securityOrigin(), request); - pFrame->loader()->loadFrameRequest(frameRequest, false, false, 0, 0, WebCore::SendReferrer); -} - -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!"); - - // Setup the resource request - WebCore::ResourceRequest request(jstringToWtfString(env, baseUrl)); - - // Setup the substituteData - const char* dataStr = env->GetStringUTFChars(data, NULL); - WTF::PassRefPtr sharedBuffer = - WebCore::SharedBuffer::create(); - LOG_ASSERT(dataStr, "nativeLoadData has a null data string."); - sharedBuffer->append(dataStr, strlen(dataStr)); - env->ReleaseStringUTFChars(data, dataStr); - - WebCore::SubstituteData substituteData(sharedBuffer, - jstringToWtfString(env, mimeType), jstringToWtfString(env, encoding), - WebCore::KURL(ParsedURLString, jstringToWtfString(env, failUrl))); - - // Perform the load - pFrame->loader()->load(request, substituteData, false); -} - -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); - - // Stop loading the page and do not send an unload event - pFrame->loader()->stopForUserCancel(); -} - -#if ENABLE(ARCHIVE) -static String saveArchiveAutoname(String basename, String name, String extension) { - if (name.isNull() || name.isEmpty()) { - name = String("index"); - } - - String testname = basename; - testname.append(name); - testname.append(extension); - - errno = 0; - struct stat permissions; - if (stat(testname.utf8().data(), &permissions) < 0) { - if (errno == ENOENT) - return testname; - return String(); - } - - const int maxAttempts = 100; - for (int i = 1; i < maxAttempts; i++) { - String testname = basename; - testname.append(name); - testname.append("-"); - testname.append(String::number(i)); - testname.append(extension); - - errno = 0; - if (stat(testname.utf8().data(), &permissions) < 0) { - if (errno == ENOENT) - return testname; - return String(); - } - } - - return String(); -} -#endif - -static jstring SaveWebArchive(JNIEnv *env, jobject obj, jstring basename, jboolean autoname) -{ -#if ENABLE(ARCHIVE) - WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj); - LOG_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; - - const char* basenameNative = getCharactersFromJStringInEnv(env, basename); - String basenameString = String::fromUTF8(basenameNative); - String filename; - - if (autoname) { - String name = pFrame->loader()->documentLoader()->originalURL().lastPathComponent(); - String extension = String(".webarchivexml"); - filename = saveArchiveAutoname(basenameString, name, extension); - } else { - filename = basenameString; - } - - if (filename.isNull() || filename.isEmpty()) { - LOGD("saveWebArchive: Failed to select a filename to save."); - releaseCharactersForJStringInEnv(env, basename, basenameNative); - return NULL; - } - - const int noCompression = 0; - xmlTextWriterPtr writer = xmlNewTextWriterFilename(filename.utf8().data(), noCompression); - if (writer == NULL) { - LOGD("saveWebArchive: Failed to initialize xml writer."); - releaseCharactersForJStringInEnv(env, basename, basenameNative); - return NULL; - } - - RefPtr archive = WebCore::WebArchiveAndroid::create(pFrame); - - bool result = archive->saveWebArchive(writer); - - releaseCharactersForJStringInEnv(env, basename, basenameNative); - xmlFreeTextWriter(writer); - - if (result) - return wtfStringToJstring(env, filename); - - return NULL; -#endif -} - -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!"); - - // Request external representation of the render tree - WTF::String renderDump = WebCore::externalRepresentation(pFrame); - return wtfStringToJstring(env, renderDump); -} - -static StringBuilder FrameAsText(WebCore::Frame *pFrame, jboolean dumpChildFrames) { - StringBuilder renderDump; - if (!pFrame) - return renderDump; - WebCore::Element *documentElement = pFrame->document()->documentElement(); - if (!documentElement) - return renderDump; - if (pFrame->tree()->parent()) { - renderDump.append("\n--------\nFrame: '"); - renderDump.append(pFrame->tree()->name()); - renderDump.append("'\n--------\n"); - } - renderDump.append(((WebCore::HTMLElement*)documentElement)->innerText()); - renderDump.append("\n"); - if (dumpChildFrames) { - for (unsigned i = 0; i < pFrame->tree()->childCount(); ++i) { - renderDump.append(FrameAsText(pFrame->tree()->child(i), dumpChildFrames).toString()); - } - } - return renderDump; -} - -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!"); - - WTF::String renderDump = FrameAsText(pFrame, false /* dumpChildFrames */).toString(); - return wtfStringToJstring(env, renderDump); -} - -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!"); - - StringBuilder renderDumpBuilder; - for (unsigned i = 0; i < pFrame->tree()->childCount(); ++i) { - renderDumpBuilder.append(FrameAsText(pFrame->tree()->child(i), true /* dumpChildFrames */).toString()); - } - WTF::String renderDump = renderDumpBuilder.toString(); - return wtfStringToJstring(env, renderDump); -} - -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!"); - - WebCore::FrameLoader* loader = pFrame->loader(); - if (allowStale) { - // load the current page with FrameLoadTypeIndexedBackForward so that it - // will use cache when it is possible - WebCore::Page* page = pFrame->page(); - WebCore::HistoryItem* item = page->backForwardList()->currentItem(); - if (item) - page->goToItem(item, FrameLoadTypeIndexedBackForward); - } else - loader->reload(true); -} - -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!"); - - if (pos == 1) - pFrame->page()->goForward(); - else if (pos == -1) - pFrame->page()->goBack(); - else - pFrame->page()->goBackOrForward(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!"); - - WebCore::ScriptValue value = - pFrame->script()->executeScript(jstringToWtfString(env, script), true); - WTF::String result = WTF::String(); - ScriptState* scriptState = mainWorldScriptState(pFrame); - if (!value.getString(scriptState, result)) - return NULL; - return wtfStringToJstring(env, result); -} - -// 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. -class WeakJavaInstance : public JavaInstance { -public: -#if USE(JSC) - static PassRefPtr create(jobject obj, PassRefPtr root) - { - return adoptRef(new WeakJavaInstance(obj, root)); - } -#elif USE(V8) - static PassRefPtr create(jobject obj) - { - return adoptRef(new WeakJavaInstance(obj)); - } -#endif - -private: -#if USE(JSC) - WeakJavaInstance(jobject instance, PassRefPtr rootObject) - : JavaInstance(instance, rootObject) -#elif USE(V8) - WeakJavaInstance(jobject instance) - : JavaInstance(instance) -#endif - , m_beginEndDepth(0) - { - JNIEnv* env = getJNIEnv(); - // JavaInstance creates a global ref to instance in its constructor. - env->DeleteGlobalRef(m_instance->instance()); - // Set the object to a weak reference. - m_instance->setInstance(env->NewWeakGlobalRef(instance)); - } - ~WeakJavaInstance() - { - JNIEnv* env = getJNIEnv(); - // Store the weak reference so we can delete it later. - jweak weak = m_instance->instance(); - // The JavaInstance destructor attempts to delete the global ref stored - // in m_instance. Since we replaced it in our constructor with a weak - // reference, restore the global ref here so the vm will not complain. - m_instance->setInstance(env->NewGlobalRef( - getRealObject(env, m_instance->instance()).get())); - // Delete the weak reference. - env->DeleteWeakGlobalRef(weak); - } - - virtual void virtualBegin() - { - if (m_beginEndDepth++ > 0) - return; - m_weakRef = m_instance->instance(); - JNIEnv* env = getJNIEnv(); - // This is odd. getRealObject returns an AutoJObject which is used to - // cleanly create and delete a local reference. But, here we need to - // maintain the local reference across calls to virtualBegin() and - // virtualEnd(). So, release the local reference from the AutoJObject - // and delete the local reference in virtualEnd(). - m_realObject = getRealObject(env, m_weakRef).release(); - // Point to the real object - m_instance->setInstance(m_realObject); - // Call the base class method - INHERITED::virtualBegin(); - } - - virtual void virtualEnd() - { - if (--m_beginEndDepth > 0) - return; - // Call the base class method first to pop the local frame. - INHERITED::virtualEnd(); - // Get rid of the local reference to the real object. - getJNIEnv()->DeleteLocalRef(m_realObject); - // Point back to the WeakReference. - m_instance->setInstance(m_weakRef); - } - -private: - typedef JavaInstance INHERITED; - jobject m_realObject; - jweak m_weakRef; - // The current depth of nested calls to virtualBegin and virtualEnd. - int m_beginEndDepth; -}; - -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!"); - - 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) - if (pFrame) { - RefPtr addedObject = WeakJavaInstance::create(javascriptObj); - const char* name = getCharactersFromJStringInEnv(env, interfaceName); - // Pass ownership of the added object to bindToWindowObject. - NPObject* npObject = JavaInstanceToNPObject(addedObject.get()); - pFrame->script()->bindToWindowObject(pFrame, name, npObject); - // bindToWindowObject calls NPN_RetainObject on the - // returned one (see createV8ObjectForNPObject in V8NPObject.cpp). - // bindToWindowObject also increases obj's ref count and decreases - // the ref count when the object is not reachable from JavaScript - // side. Code here must release the reference count increased by - // bindToWindowObject. - - // Note that while this function is declared in WebCore/bridge/npruntime.h, for V8 builds - // we use WebCore/bindings/v8/npruntime.cpp (rather than - // WebCore/bridge/npruntime.cpp), so the function is implemented there. - // TODO: Combine the two versions of these NPAPI files. - 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::cache()->setDisabled(disabled); -} - -static jboolean CacheDisabled(JNIEnv *env, jobject obj) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter); -#endif - return WebCore::cache()->disabled(); -} - -static void ClearWebCoreCache() -{ - if (!WebCore::cache()->disabled()) { - // Disabling the cache will remove all resources from the cache. They may - // still live on if they are referenced by some Web page though. - WebCore::cache()->setDisabled(true); - WebCore::cache()->setDisabled(false); - } - - // clear page cache - int pageCapacity = WebCore::pageCache()->capacity(); - // Setting size to 0, makes all pages be released. - WebCore::pageCache()->setCapacity(0); - WebCore::pageCache()->releaseAutoreleasedPagesNow(); - WebCore::pageCache()->setCapacity(pageCapacity); -} - -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", - cache()->getLiveSize(), cache()->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!"); - - 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!"); - - bool found = false; - WTF::PassRefPtr 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. - while (node && !found && !node->namespaceURI().isNull() && - !node->namespaceURI().isEmpty()) { - const WTF::Vector& elements = - ((WebCore::HTMLFormElement*)node)->associatedElements(); - size_t size = elements.size(); - for (size_t i = 0; i< size && !found; i++) { - WebCore::HTMLElement* e = toHTMLElement(elements[i]); - if (e->hasLocalName(WebCore::HTMLNames::inputTag)) { - if (static_cast(e)->isPasswordField()) - found = true; - } - } - node = form->nextItem(); - } - return found; -} - -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!"); - jobjectArray strArray = NULL; - WTF::String username; - WTF::String password; - if (WebFrame::getWebFrame(pFrame)->getUsernamePasswordFromDom(pFrame, username, password)) { - jclass stringClass = env->FindClass("java/lang/String"); - strArray = env->NewObjectArray(2, stringClass, NULL); - env->DeleteLocalRef(stringClass); - env->SetObjectArrayElement(strArray, 0, wtfStringToJstring(env, username)); - env->SetObjectArrayElement(strArray, 1, wtfStringToJstring(env, password)); - } - return strArray; -} - -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!"); - - WebCore::HTMLInputElement* usernameEle = NULL; - WebCore::HTMLInputElement* passwordEle = NULL; - bool found = false; - WTF::PassRefPtr form = pFrame->document()->forms(); - WebCore::Node* node = form->firstItem(); - while (node && !found && !node->namespaceURI().isNull() && - !node->namespaceURI().isEmpty()) { - const WTF::Vector& elements = - ((WebCore::HTMLFormElement*)node)->associatedElements(); - size_t size = elements.size(); - for (size_t i = 0; i< size && !found; i++) { - WebCore::HTMLElement* e = toHTMLElement(elements[i]); - if (e->hasLocalName(WebCore::HTMLNames::inputTag)) { - WebCore::HTMLInputElement* input = (WebCore::HTMLInputElement*)e; - if (input->autoComplete() == false) - continue; - if (input->isPasswordField()) - passwordEle = input; - else if (input->isTextField() || input->isEmailField()) - usernameEle = input; - if (usernameEle != NULL && passwordEle != NULL) - found = true; - } - } - node = form->nextItem(); - } - if (found) { - usernameEle->setValue(jstringToWtfString(env, username)); - passwordEle->setValue(jstringToWtfString(env, password)); - } -} - -void -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!"); - jmethodID init = env->GetMethodID(mapClass, "", "(I)V"); - LOG_ASSERT(init, "Could not find constructor for HashMap"); - jobject hashMap = env->NewObject(mapClass, init, 1); - LOG_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"); - WTF::Vector elements = form->associatedElements(); - size_t size = elements.size(); - for (size_t i = 0; i < size; i++) { - WebCore::HTMLElement* e = toHTMLElement(elements[i]); - if (e->hasTagName(WebCore::HTMLNames::inputTag)) { - WebCore::HTMLInputElement* input = static_cast(e); - if (input->isTextField() && !input->isPasswordField() - && input->autoComplete()) { - WTF::String value = input->value(); - int len = value.length(); - if (len) { - 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"); - env->CallObjectMethod(hashMap, put, key, val); - env->DeleteLocalRef(key); - env->DeleteLocalRef(val); - } - } - } - } - env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mSaveFormData, hashMap); - env->DeleteLocalRef(hashMap); - env->DeleteLocalRef(mapClass); - } -} - -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); - pFrame->sendOrientationChangeEvent(orientation); -} - -#if USE(CHROME_NETWORK_STACK) - -static void AuthenticationProceed(JNIEnv *env, jobject obj, int handle, jstring jUsername, jstring jPassword) -{ - WebUrlLoaderClient* client = reinterpret_cast(handle); - std::string username = jstringToStdString(env, jUsername); - std::string password = jstringToStdString(env, jPassword); - client->setAuth(username, password); -} - -static void AuthenticationCancel(JNIEnv *env, jobject obj, int handle) -{ - WebUrlLoaderClient* client = reinterpret_cast(handle); - client->cancelAuth(); -} - -static void SslCertErrorProceed(JNIEnv *env, jobject obj, int handle) -{ - WebUrlLoaderClient* client = reinterpret_cast(handle); - client->proceedSslCertError(); -} - -static void SslCertErrorCancel(JNIEnv *env, jobject obj, int handle, int cert_error) -{ - WebUrlLoaderClient* client = reinterpret_cast(handle); - client->cancelSslCertError(cert_error); -} - -#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"); -} - -#endif // USE(CHROME_NETWORK_STACK) - -// ---------------------------------------------------------------------------- - -/* - * JNI registration. - */ -static JNINativeMethod gBrowserFrameNativeMethods[] = { - /* name, signature, funcPtr */ - { "nativeCallPolicyFunction", "(II)V", - (void*) CallPolicyFunction }, - { "nativeCreateFrame", "(Landroid/webkit/WebViewCore;Landroid/content/res/AssetManager;Landroid/webkit/WebBackForwardList;)V", - (void*) CreateFrame }, - { "nativeDestroyFrame", "()V", - (void*) DestroyFrame }, - { "nativeStopLoading", "()V", - (void*) StopLoading }, - { "nativeLoadUrl", "(Ljava/lang/String;Ljava/util/Map;)V", - (void*) LoadUrl }, - { "nativePostUrl", "(Ljava/lang/String;[B)V", - (void*) PostUrl }, - { "nativeLoadData", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V", - (void*) LoadData }, - { "nativeSaveWebArchive", "(Ljava/lang/String;Z)Ljava/lang/String;", - (void*) SaveWebArchive }, - { "externalRepresentation", "()Ljava/lang/String;", - (void*) ExternalRepresentation }, - { "documentAsText", "()Ljava/lang/String;", - (void*) DocumentAsText }, - { "childFramesAsText", "()Ljava/lang/String;", - (void*) ChildFramesAsText }, - { "reload", "(Z)V", - (void*) Reload }, - { "nativeGoBackOrForward", "(I)V", - (void*) GoBackOrForward }, - { "nativeAddJavascriptInterface", "(ILjava/lang/Object;Ljava/lang/String;)V", - (void*) AddJavascriptInterface }, - { "stringByEvaluatingJavaScriptFromString", - "(Ljava/lang/String;)Ljava/lang/String;", - (void*) StringByEvaluatingJavaScriptFromString }, - { "setCacheDisabled", "(Z)V", - (void*) SetCacheDisabled }, - { "cacheDisabled", "()Z", - (void*) CacheDisabled }, - { "clearCache", "()V", - (void*) ClearCache }, - { "documentHasImages", "()Z", - (void*) DocumentHasImages }, - { "hasPasswordField", "()Z", - (void*) HasPasswordField }, - { "getUsernamePassword", "()[Ljava/lang/String;", - (void*) GetUsernamePassword }, - { "setUsernamePassword", "(Ljava/lang/String;Ljava/lang/String;)V", - (void*) SetUsernamePassword }, - { "nativeOrientationChanged", "(I)V", - (void*) OrientationChanged }, - { "nativeAuthenticationProceed", "(ILjava/lang/String;Ljava/lang/String;)V", - (void*) AuthenticationProceed }, - { "nativeAuthenticationCancel", "(I)V", - (void*) AuthenticationCancel }, - { "nativeSslCertErrorProceed", "(I)V", - (void*) SslCertErrorProceed }, - { "nativeSslCertErrorCancel", "(II)V", - (void*) SslCertErrorCancel }, -}; - -int registerWebFrame(JNIEnv* env) -{ - jclass clazz = env->FindClass("android/webkit/BrowserFrame"); - LOG_ASSERT(clazz, "Cannot find BrowserFrame"); - gFrameField = env->GetFieldID(clazz, "mNativeFrame", "I"); - LOG_ASSERT(gFrameField, "Cannot find mNativeFrame on BrowserFrame"); - env->DeleteLocalRef(clazz); - - return jniRegisterNativeMethods(env, "android/webkit/BrowserFrame", - gBrowserFrameNativeMethods, NELEM(gBrowserFrameNativeMethods)); -} - -} /* namespace android */ diff --git a/WebKit/android/jni/WebCoreFrameBridge.h b/WebKit/android/jni/WebCoreFrameBridge.h deleted file mode 100644 index 6522a5f..0000000 --- a/WebKit/android/jni/WebCoreFrameBridge.h +++ /dev/null @@ -1,173 +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. - */ - -// TODO: change name to WebFrame.h - -#ifndef WEBFRAME_H -#define WEBFRAME_H - -#include "FrameLoaderClient.h" -#include "PlatformBridge.h" -#include "PlatformString.h" -#include "WebCoreRefObject.h" -#include -#include -#include - -namespace WebCore { - class HTMLFormElement; - class Frame; - class HistoryItem; - class Image; - class Page; - class RenderPart; - class RenderSkinAndroid; - class ResourceHandle; - class ResourceLoaderAndroid; - class ResourceRequest; -} - -namespace android { - -class WebViewCore; -class WebUrlLoaderClient; -class UrlInterceptResponse; - -// one instance of WebFrame per Page for calling into Java's BrowserFrame -class WebFrame : public WebCoreRefObject { - public: - WebFrame(JNIEnv* env, jobject obj, jobject historyList, WebCore::Page* page); - ~WebFrame(); - - // helper function - static WebFrame* getWebFrame(const WebCore::Frame* frame); - - virtual PassRefPtr 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, - const WTF::String& failingUrl); - - void loadStarted(WebCore::Frame* frame); - - void transitionToCommitted(WebCore::Frame* frame); - - void didFinishLoad(WebCore::Frame* frame); - - void addHistoryItem(WebCore::HistoryItem* item); - - void removeHistoryItem(int index); - - void updateHistoryIndex(int newIndex); - - void setTitle(const WTF::String& title); - - void windowObjectCleared(WebCore::Frame* frame); - - void setProgress(float newProgress); - - const WTF::String userAgentForURL(const WebCore::KURL* url); - - void didReceiveIcon(WebCore::Image* icon); - - void didReceiveTouchIconURL(const WTF::String& url, bool precomposed); - - void updateVisitedHistory(const WebCore::KURL& url, bool reload); - - virtual bool canHandleRequest(const WebCore::ResourceRequest& request); - - WebCore::Frame* createWindow(bool dialog, bool userGesture); - - void requestFocus() const; - - void closeWindow(WebViewCore* webViewCore); - - void decidePolicyForFormResubmission(WebCore::FramePolicyFunction func); - - void setUserAgent(WTF::String userAgent) { mUserAgent = userAgent; } - - WTF::String getRawResourceFilename(WebCore::PlatformBridge::rawResId) const; - - float density() const; - - void didReceiveAuthenticationChallenge(WebUrlLoaderClient*, const std::string& host, const std::string& realm, bool useCachedCredentials); - - void reportSslCertError(WebUrlLoaderClient* client, int cert_error, const std::string& cert); - - void downloadStart(const std::string& url, const std::string& userAgent, const std::string& contentDisposition, const std::string& mimetype, long long contentLength); - - void didReceiveData(const char* data, int size); - - void didFinishLoading(); - - void maybeSavePassword(WebCore::Frame* frame, const WebCore::ResourceRequest& request); - - void setCertificate(const std::string& cert); - - // Parse the x-auto-login header and propagate the parameters to the - // application. - void autoLogin(const std::string& loginHeader); - - /** - * When the user initiates a click, we set mUserInitiatedAction to true. - * If a load happens due to this click, then we ask the application if it wants - * to override the load. Otherwise, we attempt to load the resource internally. - */ - void setUserInitiatedAction(bool userInitiatedAction) { mUserInitiatedAction = userInitiatedAction; } - - WebCore::Page* page() const { return mPage; } - - // Currently used only by the chrome net stack. A similar field is used by - // FrameLoader.java to block java network loads. - void setBlockNetworkLoads(bool block) { mBlockNetworkLoads = block; } - bool blockNetworkLoads() const { return mBlockNetworkLoads; } - - /** - * Helper methods. These are typically chunks of code that are called in - * slightly different ways by the Apache and Chrome HTTP stacks. - */ - bool getUsernamePasswordFromDom(WebCore::Frame* frame, WTF::String& username, WTF::String& password); - jbyteArray getPostData(const WebCore::ResourceRequest& request); - - bool shouldSaveFormData(); - void saveFormData(WebCore::HTMLFormElement*); - const WebCore::RenderSkinAndroid* renderSkins() const { return m_renderSkins; } - void setRenderSkins(const WebCore::RenderSkinAndroid* skins) { m_renderSkins = skins; } -private: - struct JavaBrowserFrame; - JavaBrowserFrame* mJavaFrame; - WebCore::Page* mPage; - WTF::String mUserAgent; - bool mBlockNetworkLoads; - bool mUserInitiatedAction; - const WebCore::RenderSkinAndroid* m_renderSkins; -}; - -} // namespace android - -#endif // WEBFRAME_H diff --git a/WebKit/android/jni/WebCoreJni.cpp b/WebKit/android/jni/WebCoreJni.cpp deleted file mode 100644 index 2a07999..0000000 --- a/WebKit/android/jni/WebCoreJni.cpp +++ /dev/null @@ -1,117 +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. - */ - -#define LOG_TAG "webcoreglue" - -#include "config.h" -#include "WebCoreJni.h" - -#include "NotImplemented.h" -#include -#include -#include - -namespace android { - -AutoJObject getRealObject(JNIEnv* env, jobject obj) -{ - jobject real = env->NewLocalRef(obj); - LOG_ASSERT(real, "The real object has been deleted!"); - return AutoJObject(env, real); -} - -/** - * Helper method for checking java exceptions - * @return true if an exception occurred. - */ -bool checkException(JNIEnv* env) -{ - if (env->ExceptionCheck() != 0) - { - LOGE("*** Uncaught exception returned from Java call!\n"); - env->ExceptionDescribe(); - return true; - } - return false; -} - -// This method is safe to call from the ui thread and the WebCore thread. -WTF::String jstringToWtfString(JNIEnv* env, jstring str) -{ - if (!str || !env) - return WTF::String(); - const jchar* s = env->GetStringChars(str, NULL); - if (!s) - return WTF::String(); - WTF::String ret(s, env->GetStringLength(str)); - env->ReleaseStringChars(str, s); - checkException(env); - return ret; -} - -jstring wtfStringToJstring(JNIEnv* env, const WTF::String& str, bool validOnZeroLength) -{ - int length = str.length(); - return length || validOnZeroLength ? env->NewString(str.characters(), length) : 0; -} - - -#if USE(CHROME_NETWORK_STACK) -string16 jstringToString16(JNIEnv* env, jstring jstr) -{ - if (!jstr || !env) - return string16(); - - const char* s = env->GetStringUTFChars(jstr, 0); - if (!s) - return string16(); - string16 str = UTF8ToUTF16(s); - env->ReleaseStringUTFChars(jstr, s); - checkException(env); - return str; -} - -std::string jstringToStdString(JNIEnv* env, jstring jstr) -{ - if (!jstr || !env) - return std::string(); - - const char* s = env->GetStringUTFChars(jstr, 0); - if (!s) - return std::string(); - std::string str(s); - env->ReleaseStringUTFChars(jstr, s); - checkException(env); - return str; -} - -jstring stdStringToJstring(JNIEnv* env, const std::string& str, bool validOnZeroLength) -{ - return !str.empty() || validOnZeroLength ? env->NewStringUTF(str.c_str()) : 0; -} - -#endif - -} diff --git a/WebKit/android/jni/WebCoreJni.h b/WebKit/android/jni/WebCoreJni.h deleted file mode 100644 index ec25c8f..0000000 --- a/WebKit/android/jni/WebCoreJni.h +++ /dev/null @@ -1,96 +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 ANDROID_WEBKIT_WEBCOREJNI_H -#define ANDROID_WEBKIT_WEBCOREJNI_H - -#include "ChromiumIncludes.h" -#include "PlatformString.h" -#include - -namespace android { - -// A helper class that automatically deletes the local reference to the jobject -// returned from getRealObject. -class AutoJObject { -public: - AutoJObject(const AutoJObject& other) - : m_env(other.m_env) - , m_obj(other.m_obj ? other.m_env->NewLocalRef(other.m_obj) : NULL) {} - ~AutoJObject() { - if (m_obj) - m_env->DeleteLocalRef(m_obj); - } - jobject get() const { - return m_obj; - } - // Releases the local reference to the caller. The caller *must* delete the - // local reference when it is done with it. - jobject release() { - jobject obj = m_obj; - m_obj = 0; - return obj; - } - JNIEnv* env() const { - return m_env; - } -private: - AutoJObject(); // Not permitted. - AutoJObject(JNIEnv* env, jobject obj) - : m_env(env) - , m_obj(obj) {} - JNIEnv* m_env; - jobject m_obj; - friend AutoJObject getRealObject(JNIEnv*, jobject); -}; - -// Get the real object stored in the weak reference returned as an -// AutoJObject. -AutoJObject getRealObject(JNIEnv*, jobject); - -// Helper method for check java exceptions. Returns true if an exception -// occurred and logs the exception. -bool checkException(JNIEnv* env); - -// Create a WTF::String object from a jstring object. -WTF::String jstringToWtfString(JNIEnv*, jstring); -// Returns a local reference to a new jstring. If validOnZeroLength is true then -// passing in an empty WTF String will result in an empty jstring. Otherwise -// 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); -// Returns a local reference to a new jstring. If validOnZeroLength is true then -// 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 - -} - -#endif diff --git a/WebKit/android/jni/WebCoreJniOnLoad.cpp b/WebKit/android/jni/WebCoreJniOnLoad.cpp deleted file mode 100644 index 1f264a2..0000000 --- a/WebKit/android/jni/WebCoreJniOnLoad.cpp +++ /dev/null @@ -1,319 +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 "webcoreglue" - -#include "config.h" - -#include "BackForwardList.h" -#include "ChromeClientAndroid.h" -#include "ContextMenuClientAndroid.h" -#include "CookieClient.h" -#include "DeviceMotionClientAndroid.h" -#include "DeviceOrientationClientAndroid.h" -#include "DragClientAndroid.h" -#include "EditorClientAndroid.h" -#include "FocusController.h" -#include "Frame.h" -#include "FrameLoader.h" -#include "FrameLoaderClientAndroid.h" -#include "FrameView.h" -#include "GraphicsContext.h" -#include "HistoryItem.h" -#include "InspectorClientAndroid.h" -#include "IntRect.h" -#include "JavaSharedClient.h" -#include "Page.h" -#include "PlatformGraphicsContext.h" -#include "ResourceRequest.h" -#include "ScriptController.h" -#include "SecurityOrigin.h" -#include "SelectionController.h" -#include "Settings.h" -#include "SharedBuffer.h" -#include "SkBitmap.h" -#include "SkCanvas.h" -#include "SkImageEncoder.h" -#include "SubstituteData.h" -#include "TimerClient.h" -#include "TextEncoding.h" -#include "WebCoreViewBridge.h" -#include "WebFrameView.h" -#include "WebViewCore.h" -#include "benchmark/Intercept.h" -#include "benchmark/MyJavaVM.h" - -#include -#include -#include - -#define EXPORT __attribute__((visibility("default"))) - -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*); -extern int registerWebIconDatabase(JNIEnv*); -extern int registerWebSettings(JNIEnv*); -extern int registerWebView(JNIEnv*); -#if ENABLE(DATABASE) -extern int registerWebStorage(JNIEnv*); -#endif -extern int registerGeolocationPermissions(JNIEnv*); -extern int registerMockGeolocation(JNIEnv*); -#if ENABLE(VIDEO) -extern int registerMediaPlayerAudio(JNIEnv*); -extern int registerMediaPlayerVideo(JNIEnv*); -#endif -extern int registerDeviceMotionAndOrientationManager(JNIEnv*); -extern int registerCookieManager(JNIEnv*); -#if USE(CHROME_NETWORK_STACK) -extern int registerCacheManager(JNIEnv*); -#endif - -} - -struct RegistrationMethod { - const char* name; - int (*func)(JNIEnv*); -}; - -static RegistrationMethod gWebCoreRegMethods[] = { - { "JavaBridge", android::registerJavaBridge }, - { "JniUtil", android::registerJniUtil }, - { "WebFrame", android::registerWebFrame }, - { "WebCoreResourceLoader", android::registerResourceLoader }, - { "WebViewCore", android::registerWebViewCore }, - { "WebHistory", android::registerWebHistory }, - { "WebIconDatabase", android::registerWebIconDatabase }, - { "WebSettings", android::registerWebSettings }, -#if ENABLE(DATABASE) - { "WebStorage", android::registerWebStorage }, -#endif - { "WebView", android::registerWebView }, - { "GeolocationPermissions", android::registerGeolocationPermissions }, - { "MockGeolocation", android::registerMockGeolocation }, -#if ENABLE(VIDEO) - { "HTML5Audio", android::registerMediaPlayerAudio }, - { "HTML5VideoViewProxy", android::registerMediaPlayerVideo }, -#endif - { "DeviceMotionAndOrientationManager", android::registerDeviceMotionAndOrientationManager }, - { "CookieManager", android::registerCookieManager }, -#if USE(CHROME_NETWORK_STACK) - { "CacheManager", android::registerCacheManager }, -#endif -}; - -EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) -{ - // Save the JavaVM pointer for use globally. - JSC::Bindings::setJavaVM(vm); - - JNIEnv* env = NULL; - jint result = -1; - - if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { - LOGE("GetEnv failed!"); - return result; - } - LOG_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); - return result; - } - method++; - } - - // Initialize rand() function. The rand() function is used in - // FileSystemAndroid to create a random temporary filename. - srand(time(NULL)); - - 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::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::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, NULL); - 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/WebKit/android/jni/WebCoreRefObject.h b/WebKit/android/jni/WebCoreRefObject.h deleted file mode 100644 index 4228db6..0000000 --- a/WebKit/android/jni/WebCoreRefObject.h +++ /dev/null @@ -1,46 +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 WEBCORE_FOUNDATION_h -#define WEBCORE_FOUNDATION_h - -#include "SkRefCnt.h" - -typedef SkRefCnt WebCoreRefObject; - -static inline WebCoreRefObject* Retain(WebCoreRefObject* obj) -{ - if (obj) - obj->ref(); - return obj; -} - -static inline void Release(WebCoreRefObject* obj) -{ - if (obj) - obj->unref(); -} - -#endif // WEBCORE_FOUNDATION_h diff --git a/WebKit/android/jni/WebCoreResourceLoader.cpp b/WebKit/android/jni/WebCoreResourceLoader.cpp deleted file mode 100644 index f9acc97..0000000 --- a/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 -#include -#include -#include -#include -#include -#include - -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 WebCoreResourceLoader::create(JNIEnv *env, jobject jLoadListener) -{ - return adoptRef(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/WebKit/android/jni/WebCoreResourceLoader.h b/WebKit/android/jni/WebCoreResourceLoader.h deleted file mode 100644 index c60b3f5..0000000 --- a/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 ANDROID_WEBKIT_RESOURCELOADLISTENER_H -#define ANDROID_WEBKIT_RESOURCELOADLISTENER_H - -#include -#include -#include - -namespace android { - -class WebCoreResourceLoader : public WebCore::ResourceLoaderAndroid -{ -public: - static PassRefPtr 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/WebKit/android/jni/WebCoreViewBridge.h b/WebKit/android/jni/WebCoreViewBridge.h deleted file mode 100644 index 59e1c9a..0000000 --- a/WebKit/android/jni/WebCoreViewBridge.h +++ /dev/null @@ -1,106 +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 WEBCORE_VIEW_BRIDGE_H -#define WEBCORE_VIEW_BRIDGE_H - -// TODO: move this outside of jni directory - -#include "IntRect.h" -#include "WebCoreRefObject.h" - -namespace WebCore -{ - class GraphicsContext; -} - -class WebCoreViewBridge : public WebCoreRefObject { -public: - WebCoreViewBridge() { } - virtual ~WebCoreViewBridge() { } - - virtual void draw(WebCore::GraphicsContext* ctx, - const WebCore::IntRect& rect) = 0; - - const WebCore::IntRect& getBounds() const - { - return m_bounds; - } - - const WebCore::IntRect& getVisibleBounds() const - { - return m_visibleBounds; - } - - const WebCore::IntRect& getWindowBounds() const - { - return m_windowBounds; - } - - void setSize(int w, int h) - { - m_bounds.setWidth(w); - m_bounds.setHeight(h); - } - - void setVisibleSize(int w, int h) - { - m_visibleBounds.setWidth(w); - m_visibleBounds.setHeight(h); - } - - void setLocation(int x, int y) - { - m_bounds.setX(x); - m_bounds.setY(y); - m_visibleBounds.setX(x); - m_visibleBounds.setY(y); - } - - void setWindowBounds(int x, int y, int h, int v) - { - m_windowBounds = WebCore::IntRect(x, y, h, v); - } - - int width() const { return m_bounds.width(); } - int height() const { return m_bounds.height(); } - int locX() const { return m_bounds.x(); } - int locY() const { return m_bounds.y(); } - - int visibleWidth() const { return m_visibleBounds.width(); } - int visibleHeight() const { return m_visibleBounds.height(); } - int visibleX() const { return m_visibleBounds.x(); } - int visibleY() const { return m_visibleBounds.y(); } - - virtual bool forFrameView() const { return false; } - virtual bool forPluginView() const { return false; } - -private: - WebCore::IntRect m_bounds; - WebCore::IntRect m_windowBounds; - WebCore::IntRect m_visibleBounds; -}; - -#endif // WEBCORE_VIEW_BRIDGE_H diff --git a/WebKit/android/jni/WebFrameView.cpp b/WebKit/android/jni/WebFrameView.cpp deleted file mode 100644 index 8e5eac4..0000000 --- a/WebKit/android/jni/WebFrameView.cpp +++ /dev/null @@ -1,104 +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 "webcoreglue" - -#include -#include "WebFrameView.h" - -#include "android_graphics.h" -#include "GraphicsContext.h" -#include "Frame.h" -#include "FrameTree.h" -#include "FrameView.h" -#include "HostWindow.h" -#include "PlatformGraphicsContext.h" -#include "WebViewCore.h" - -#include - -namespace android { - -WebFrameView::WebFrameView(WebCore::FrameView* frameView, WebViewCore* webViewCore) - : WebCoreViewBridge() - , mFrameView(frameView) - , mWebViewCore(webViewCore) { - // attach itself to mFrameView - mFrameView->setPlatformWidget(this); - Retain(mWebViewCore); -} - -WebFrameView::~WebFrameView() { - Release(mWebViewCore); -} - -void WebFrameView::draw(WebCore::GraphicsContext* ctx, const WebCore::IntRect& rect) { - WebCore::Frame* frame = mFrameView->frame(); - - if (NULL == frame->contentRenderer()) { - // We only do this if there is nothing else to draw. - // If there is a renderer, it will fill the bg itself, so we don't want to - // double-draw (slow) - SkCanvas* canvas = ctx->platformContext()->mCanvas; - canvas->drawColor(SK_ColorWHITE); - } else if (frame->tree()->parent()) { - // Note: this code was moved from FrameLoaderClientAndroid - // - // For subframe, create a new translated rect from the given rectangle. - WebCore::IntRect transRect(rect); - // In Frame::markAllMatchesForText(), it does a fake paint. So we need - // to handle the case where platformContext() is null. However, we still - // want to call paint, since WebKit must have called the paint for a reason. - SkCanvas* canvas = ctx->platformContext() ? ctx->platformContext()->mCanvas : NULL; - if (canvas) { - const WebCore::IntRect& bounds = getBounds(); - - // Grab the intersection of transRect and the frame's bounds. - transRect.intersect(bounds); - if (transRect.isEmpty()) - return; - - // Move the transRect into the frame's local coordinates. - transRect.move(-bounds.x(), -bounds.y()); - - // Translate the canvas, add a clip. - canvas->save(); - canvas->translate(SkIntToScalar(bounds.x()), SkIntToScalar(bounds.y())); - canvas->clipRect(transRect); - } - mFrameView->paintContents(ctx, transRect); - if (canvas) - canvas->restore(); - } else { - mFrameView->paintContents(ctx, rect); - } -} - -void WebFrameView::setView(WebCore::FrameView* frameView) { - mFrameView = frameView; - mFrameView->setPlatformWidget(this); -} - -} // namespace android diff --git a/WebKit/android/jni/WebFrameView.h b/WebKit/android/jni/WebFrameView.h deleted file mode 100644 index 823f2b4..0000000 --- a/WebKit/android/jni/WebFrameView.h +++ /dev/null @@ -1,65 +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 WEB_FRAMEVIEW_H -#define WEB_FRAMEVIEW_H - -#include "WebCoreViewBridge.h" - -namespace WebCore { - class FrameView; -} - -namespace android { - class WebViewCore; - - class WebFrameView: public WebCoreViewBridge { - public: - WebFrameView(WebCore::FrameView* frameView, WebViewCore* webViewCore); - virtual ~WebFrameView(); - - virtual void draw(WebCore::GraphicsContext* ctx, - const WebCore::IntRect& rect); - - WebViewCore* webViewCore() const { - return mWebViewCore; - } - - void setView(WebCore::FrameView* frameView); - - WebCore::FrameView* view() const { - return mFrameView; - } - - virtual bool forFrameView() const { return true; } - - private: - WebCore::FrameView* mFrameView; - WebViewCore* mWebViewCore; - }; - -} // namespace android - -#endif // WEB_FRAMEVIEW_H diff --git a/WebKit/android/jni/WebHistory.cpp b/WebKit/android/jni/WebHistory.cpp deleted file mode 100644 index 97ce23b..0000000 --- a/WebKit/android/jni/WebHistory.cpp +++ /dev/null @@ -1,857 +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. - */ - -#define LOG_TAG "webhistory" - -#include "config.h" -#include "WebHistory.h" - -#include "BackForwardList.h" -#include "BackForwardListImpl.h" -#include "DocumentLoader.h" -#include "Frame.h" -#include "FrameLoader.h" -#include "FrameLoaderClientAndroid.h" -#include "FrameTree.h" -#include "HistoryItem.h" -#include "IconDatabase.h" -#include "Page.h" -#include "TextEncoding.h" -#include "WebCoreFrameBridge.h" -#include "WebCoreJni.h" -#include "WebIconDatabase.h" - -#include -#include "JNIUtility.h" -#include -#include -#include -#include -#include - -namespace android { - -// Forward declarations -static void write_item(WTF::Vector& v, WebCore::HistoryItem* item); -static void write_children_recursive(WTF::Vector& v, WebCore::HistoryItem* parent); -static bool read_item_recursive(WebCore::HistoryItem* child, const char** pData, int length); - -// Field ids for WebHistoryItems -struct WebHistoryItemFields { - jmethodID mInit; - jmethodID mUpdate; - jfieldID mTitle; - jfieldID mUrl; -} gWebHistoryItem; - -struct WebBackForwardListFields { - jmethodID mAddHistoryItem; - jmethodID mRemoveHistoryItem; - jmethodID mSetCurrentIndex; -} gWebBackForwardList; - -//-------------------------------------------------------------------------- -// WebBackForwardList native methods. -//-------------------------------------------------------------------------- - -static void WebHistoryClose(JNIEnv* env, jobject obj, jint frame) -{ - LOG_ASSERT(frame, "Close needs a valid Frame pointer!"); - WebCore::Frame* pFrame = (WebCore::Frame*)frame; - - WebCore::BackForwardListImpl* list = static_cast(pFrame->page()->backForwardList()); - RefPtr current = list->currentItem(); - // Remove each item instead of using close(). close() is intended to be used - // right before the list is deleted. - WebCore::HistoryItemVector& entries = list->entries(); - int size = entries.size(); - for (int i = size - 1; i >= 0; --i) - list->removeItem(entries[i].get()); - // Add the current item back to the list. - if (current) { - current->setBridge(0); - // addItem will update the children to match the newly created bridge - list->addItem(current); - - /* - * The Grand Prix site uses anchor navigations to change the display. - * WebKit tries to be smart and not load child frames that have the - * same history urls during an anchor navigation. This means that the - * current history item stored in the child frame's loader does not - * match the item found in the history tree. If we remove all the - * entries in the back/foward list, we have to restore the entire tree - * or else a HistoryItem might have a deleted parent. - * - * In order to restore the history tree correctly, we have to look up - * all the frames first and then look up the history item. We do this - * because the history item in the tree may be null at this point. - * Unfortunately, a HistoryItem can only search its immediately - * children so we do a breadth-first rebuild of the tree. - */ - - // Keep a small list of child frames to traverse. - WTF::Vector frameQueue; - // Fix the top-level item. - pFrame->loader()->history()->setCurrentItem(current.get()); - WebCore::Frame* child = pFrame->tree()->firstChild(); - // Remember the parent history item so we can search for a child item. - RefPtr parent = current; - while (child) { - // Use the old history item since the current one may have a - // deleted parent. - WebCore::HistoryItem* item = parent->childItemWithTarget(child->tree()->name()); - child->loader()->history()->setCurrentItem(item); - // Append the first child to the queue if it exists. If there is no - // item, then we do not need to traverse the children since there - // will be no parent history item. - WebCore::Frame* firstChild; - if (item && (firstChild = child->tree()->firstChild())) - frameQueue.append(firstChild); - child = child->tree()->nextSibling(); - // If we don't have a sibling for this frame and the queue isn't - // empty, use the next entry in the queue. - if (!child && !frameQueue.isEmpty()) { - child = frameQueue.at(0); - frameQueue.remove(0); - // Figure out the parent history item used when searching for - // the history item to use. - parent = child->tree()->parent()->loader()->history()->currentItem(); - } - } - } -} - -static void WebHistoryRestoreIndex(JNIEnv* env, jobject obj, jint frame, jint index) -{ - LOG_ASSERT(frame, "RestoreState needs a valid Frame pointer!"); - WebCore::Frame* pFrame = (WebCore::Frame*)frame; - WebCore::Page* page = pFrame->page(); - WebCore::HistoryItem* currentItem = - static_cast(page->backForwardList())->entries()[index].get(); - - // load the current page with FrameLoadTypeIndexedBackForward so that it - // will use cache when it is possible - page->goToItem(currentItem, FrameLoadTypeIndexedBackForward); -} - -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!"); - - // Get the actual bytes and the length from the java array. - const jbyte* bytes = env->GetByteArrayElements(data, NULL); - jsize size = env->GetArrayLength(data); - - // Inflate the history tree into one HistoryItem or null if the inflation - // failed. - RefPtr newItem = WebCore::HistoryItem::create(); - WebHistoryItem* bridge = new WebHistoryItem(env, obj, newItem.get()); - newItem->setBridge(bridge); - - // Inflate the item recursively. If it fails, that is ok. We'll have an - // incomplete HistoryItem but that is better than crashing due to a null - // item. - // We have a 2nd local variable since read_item_recursive may change the - // ptr's value. We can't pass &bytes since we have to send bytes to - // ReleaseByteArrayElements unchanged. - const char* ptr = reinterpret_cast(bytes); - read_item_recursive(newItem.get(), &ptr, (int)size); - env->ReleaseByteArrayElements(data, const_cast(bytes), JNI_ABORT); - bridge->setActive(); - - // Add the new item to the back/forward list. - WebCore::Frame* pFrame = (WebCore::Frame*)frame; - pFrame->page()->backForwardList()->addItem(newItem); - - // Update the item. - bridge->updateHistoryItem(newItem.get()); -} - -// 6 empty strings + no document state + children count + 2 scales = 10 unsigned values -// 1 char for isTargetItem. -#define HISTORY_MIN_SIZE ((int)(sizeof(unsigned) * 10 + sizeof(char))) - -jbyteArray WebHistory::Flatten(JNIEnv* env, WTF::Vector& v, 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); - - // Write the top-level history item and then write all the children - // recursively. - LOG_ASSERT(item->bridge(), "Why don't we have a bridge object here?"); - write_item(v, item); - write_children_recursive(v, item); - - // Try to create a new java byte array. - jbyteArray b = env->NewByteArray(v.size()); - if (!b) - return NULL; - - // Write our flattened data to the java array. - env->SetByteArrayRegion(b, 0, v.size(), (const jbyte*)v.data()); - return b; -} - -WebHistoryItem::WebHistoryItem(JNIEnv* env, jobject obj, - WebCore::HistoryItem* item) : WebCore::AndroidWebHistoryBridge(item) { - m_object = env->NewWeakGlobalRef(obj); - m_parent = 0; -} - -WebHistoryItem::~WebHistoryItem() { - if (m_object) { - JNIEnv* env = JSC::Bindings::getJNIEnv(); - if (!env) - return; - env->DeleteWeakGlobalRef(m_object); - } -} - -void WebHistoryItem::updateHistoryItem(WebCore::HistoryItem* item) { - // Do not want to update during inflation. - if (!m_active) - return; - WebHistoryItem* webItem = this; - // Now we need to update the top-most WebHistoryItem based on the top-most - // HistoryItem. - if (m_parent) { - webItem = m_parent.get(); - if (webItem->hasOneRef()) { - // 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"); - return; - } - while (webItem->parent()) - webItem = webItem->parent(); - item = webItem->historyItem(); - if (!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"); - return; - } - } - JNIEnv* env = JSC::Bindings::getJNIEnv(); - if (!env) - return; - - // Don't do anything if the item has been gc'd already - AutoJObject realItem = getRealObject(env, webItem->m_object); - if (!realItem.get()) - return; - - const WTF::String& urlString = item->urlString(); - jstring urlStr = NULL; - if (!urlString.isNull()) - urlStr = wtfStringToJstring(env, urlString); - const WTF::String& originalUrlString = item->originalURLString(); - jstring originalUrlStr = NULL; - if (!originalUrlString.isNull()) - originalUrlStr = wtfStringToJstring(env, originalUrlString); - const WTF::String& titleString = item->title(); - jstring titleStr = NULL; - if (!titleString.isNull()) - titleStr = wtfStringToJstring(env, titleString); - - // Try to get the favicon from the history item. For some pages like Grand - // Prix, there are history items with anchors. If the icon fails for the - // item, try to get the icon using the url without the ref. - jobject favicon = NULL; - WTF::String url = item->urlString(); - if (item->url().hasFragmentIdentifier()) { - int refIndex = url.reverseFind('#'); - url = url.substring(0, refIndex); - } - WebCore::Image* icon = WebCore::iconDatabase()->iconForPageURL(url, - WebCore::IntSize(16, 16)); - - if (icon) - favicon = webcoreImageToJavaBitmap(env, icon); - - WTF::Vector data; - jbyteArray array = WebHistory::Flatten(env, data, item); - env->CallVoidMethod(realItem.get(), gWebHistoryItem.mUpdate, urlStr, - originalUrlStr, titleStr, favicon, array); - env->DeleteLocalRef(urlStr); - env->DeleteLocalRef(originalUrlStr); - env->DeleteLocalRef(titleStr); - if (favicon) - env->DeleteLocalRef(favicon); - env->DeleteLocalRef(array); -} - -static void historyItemChanged(WebCore::HistoryItem* item) { - LOG_ASSERT(item, "historyItemChanged called with a null item"); - - if (item->bridge()) - item->bridge()->updateHistoryItem(item); -} - -void WebHistory::AddItem(const AutoJObject& list, WebCore::HistoryItem* item) -{ - LOG_ASSERT(item, "newItem must take a valid HistoryItem!"); - // Item already added. Should only happen when we are inflating the list. - if (item->bridge() || !list.get()) - return; - - JNIEnv* env = list.env(); - // Allocate a blank WebHistoryItem - jclass clazz = env->FindClass("android/webkit/WebHistoryItem"); - jobject newItem = env->NewObject(clazz, gWebHistoryItem.mInit); - env->DeleteLocalRef(clazz); - - // Create the bridge, make it active, and attach it to the item. - WebHistoryItem* bridge = new WebHistoryItem(env, newItem, item); - bridge->setActive(); - item->setBridge(bridge); - - // Update the history item which will flatten the data and call update on - // the java item. - bridge->updateHistoryItem(item); - - // Add it to the list. - env->CallVoidMethod(list.get(), gWebBackForwardList.mAddHistoryItem, newItem); - - // Delete our local reference. - env->DeleteLocalRef(newItem); -} - -void WebHistory::RemoveItem(const AutoJObject& list, int index) -{ - if (list.get()) - list.env()->CallVoidMethod(list.get(), gWebBackForwardList.mRemoveHistoryItem, index); -} - -void WebHistory::UpdateHistoryIndex(const AutoJObject& list, int newIndex) -{ - if (list.get()) - list.env()->CallVoidMethod(list.get(), gWebBackForwardList.mSetCurrentIndex, newIndex); -} - -static void write_string(WTF::Vector& v, const WTF::String& str) -{ - unsigned strLen = str.length(); - // Only do work if the string has data. - if (strLen) { - // 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 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); - // Grab the position to write to. - char* data = v.begin() + vectorLen; - // Write the actual string - int l = SkUTF16_ToUTF8(str.characters(), strLen, data); - LOGV("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); - } else - v.append((char*)&strLen, sizeof(unsigned)); -} - -static void write_item(WTF::Vector& v, WebCore::HistoryItem* item) -{ - // Original url - write_string(v, item->originalURLString()); - - // Url - write_string(v, item->urlString()); - - // Title - write_string(v, item->title()); - - // Form content type - write_string(v, item->formContentType()); - - // Form data - const WebCore::FormData* formData = item->formData(); - if (formData) { - write_string(v, 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)); - } else - write_string(v, WTF::String()); // Empty constructor does not allocate a buffer. - - // Target - write_string(v, item->target()); - - AndroidWebHistoryBridge* bridge = item->bridge(); - LOG_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)); - const float textWrapScale = bridge->textWrapScale(); - LOGV("Writing text wrap scale %f", textWrapScale); - v.append((char*)&textWrapScale, sizeof(float)); - - // Scroll position. - const int scrollX = item->scrollPoint().x(); - v.append((char*)&scrollX, sizeof(int)); - const int scrollY = item->scrollPoint().y(); - v.append((char*)&scrollY, sizeof(int)); - - // Document state - const WTF::Vector& docState = item->documentState(); - WTF::Vector::const_iterator end = docState.end(); - unsigned stateSize = docState.size(); - LOGV("Writing docState %d", stateSize); - v.append((char*)&stateSize, sizeof(unsigned)); - for (WTF::Vector::const_iterator i = docState.begin(); i != end; ++i) { - write_string(v, *i); - } - - // Is target item - LOGV("Writing isTargetItem %d", item->isTargetItem()); - v.append((char)item->isTargetItem()); - - // Children count - unsigned childCount = item->children().size(); - LOGV("Writing childCount %d", childCount); - v.append((char*)&childCount, sizeof(unsigned)); -} - -static void write_children_recursive(WTF::Vector& v, 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(), - "The parent item should have a bridge object!"); - if (!item->bridge()) { - WebHistoryItem* bridge = new WebHistoryItem(static_cast(parent->bridge())); - item->setBridge(bridge); - bridge->setActive(); - } else { - // The only time this item's parent may not be the same as the - // parent's bridge is during history close. In that case, the - // parent must not have a parent bridge. - WebHistoryItem* bridge = static_cast(item->bridge()); - WebHistoryItem* parentBridge = static_cast(parent->bridge()); - LOG_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); - } -} - -static bool read_item_recursive(WebCore::HistoryItem* newItem, - const char** pData, int length) -{ - if (!pData || length < HISTORY_MIN_SIZE) - return false; - - const WebCore::TextEncoding& e = WebCore::UTF8Encoding(); - const char* data = *pData; - const char* end = data + length; - int sizeofUnsigned = (int)sizeof(unsigned); - - // Read the original url - // Read the expected length of the string. - int 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) - 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) - 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) - return false; - - // Generate a new ResourceRequest object for populating form information. - WTF::String formContentType; - WTF::PassRefPtr formData = NULL; - - // 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) - 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 - 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); - } - } - if (end - data < sizeofUnsigned) - return false; - - // Set up the form info - if (formData != NULL) { - WebCore::ResourceRequest r; - r.setHTTPMethod("POST"); - r.setHTTPContentType(formContentType); - r.setHTTPBody(formData); - newItem->setFormInfoFromRequest(r); - } - - // 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) - return false; - - AndroidWebHistoryBridge* bridge = newItem->bridge(); - LOG_ASSERT(bridge, "There should be a bridge object during inflate"); - float fValue; - // 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); - - if (end - data < sizeofUnsigned) - 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) - return false; - - // 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; - // Create a new vector and reserve enough space for the document state. - WTF::Vector 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)); - 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) - return false; - - // Read the child count - memcpy(&l, data, sizeofUnsigned); - LOGV("Child count %d", l); - data += sizeofUnsigned; - *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--) { - // 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 child = WebCore::HistoryItem::create(); - // Set a bridge that will not call into java. - child->setBridge(new WebHistoryItem(static_cast(bridge))); - // Read the child item. - if (!read_item_recursive(child.get(), pData, end - data)) { - child.clear(); - return false; - } - child->bridge()->setActive(); - newItem->addChildItem(child); - } - } - return true; -} - -// On arm, this test will cause memory corruption since converting char* will -// byte align the result and this test does not use memset (it probably -// should). -// On the simulator, using HistoryItem will invoke the IconDatabase which will -// initialize the main thread. Since this is invoked by the Zygote process, the -// 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() -{ - LOGD("Entering history unit test!"); - const char* test1 = new char[0]; - WTF::RefPtr 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!"); - delete[] test1; - const char* test2 = new char[2]; - LOG_ASSERT(!read_item_recursive(testItem, &test2, 2), "Small array should fail!"); - delete[] test2; - LOG_ASSERT(!read_item_recursive(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!"); - // 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!"); - // 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!"); - // 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!"); - // 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!"); - // 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 - // 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!"); - // 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!"); - // 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; - // Test document state - 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!"); - delete[] test3; - test3 = new char[HISTORY_MIN_SIZE + 2 * sizeof(unsigned)]; - memset(test3, 0, HISTORY_MIN_SIZE + 2 * sizeof(unsigned)); - ptr = (const char*)test3; - *(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!"); - delete[] test3; -} -#endif - -//--------------------------------------------------------- -// JNI registration -//--------------------------------------------------------- -static JNINativeMethod gWebBackForwardListMethods[] = { - { "nativeClose", "(I)V", - (void*) WebHistoryClose }, - { "restoreIndex", "(II)V", - (void*) WebHistoryRestoreIndex } -}; - -static JNINativeMethod gWebHistoryItemMethods[] = { - { "inflate", "(I[B)V", - (void*) WebHistoryInflate } -}; - -int registerWebHistory(JNIEnv* env) -{ - // Get notified of all changes to history items. - WebCore::notifyHistoryItemChanged = historyItemChanged; -#ifdef UNIT_TEST - unit_test(); -#endif - // Find WebHistoryItem, its constructor, and the update method. - jclass clazz = env->FindClass("android/webkit/WebHistoryItem"); - LOG_ASSERT(clazz, "Unable to find class android/webkit/WebHistoryItem"); - gWebHistoryItem.mInit = env->GetMethodID(clazz, "", "()V"); - LOG_ASSERT(gWebHistoryItem.mInit, "Could not find WebHistoryItem constructor"); - gWebHistoryItem.mUpdate = env->GetMethodID(clazz, "update", - "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Landroid/graphics/Bitmap;[B)V"); - LOG_ASSERT(gWebHistoryItem.mUpdate, "Could not find method update in WebHistoryItem"); - - // Find the field ids for mTitle and mUrl. - gWebHistoryItem.mTitle = env->GetFieldID(clazz, "mTitle", "Ljava/lang/String;"); - LOG_ASSERT(gWebHistoryItem.mTitle, "Could not find field mTitle in WebHistoryItem"); - gWebHistoryItem.mUrl = env->GetFieldID(clazz, "mUrl", "Ljava/lang/String;"); - LOG_ASSERT(gWebHistoryItem.mUrl, "Could not find field mUrl in WebHistoryItem"); - 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"); - gWebBackForwardList.mAddHistoryItem = env->GetMethodID(clazz, "addHistoryItem", - "(Landroid/webkit/WebHistoryItem;)V"); - LOG_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"); - gWebBackForwardList.mSetCurrentIndex = env->GetMethodID(clazz, "setCurrentIndex", "(I)V"); - LOG_ASSERT(gWebBackForwardList.mSetCurrentIndex, "Could not find method setCurrentIndex"); - env->DeleteLocalRef(clazz); - - int result = jniRegisterNativeMethods(env, "android/webkit/WebBackForwardList", - gWebBackForwardListMethods, NELEM(gWebBackForwardListMethods)); - return (result < 0) ? result : jniRegisterNativeMethods(env, "android/webkit/WebHistoryItem", - gWebHistoryItemMethods, NELEM(gWebHistoryItemMethods)); -} - -} /* namespace android */ diff --git a/WebKit/android/jni/WebHistory.h b/WebKit/android/jni/WebHistory.h deleted file mode 100644 index 2d86aa4..0000000 --- a/WebKit/android/jni/WebHistory.h +++ /dev/null @@ -1,68 +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 ANDROID_WEBKIT_WEBHISTORY_H -#define ANDROID_WEBKIT_WEBHISTORY_H - -#include "AndroidWebHistoryBridge.h" - -#include -#include -#include - -namespace android { - -class AutoJObject; - -class WebHistory { -public: - static jbyteArray Flatten(JNIEnv*, WTF::Vector&, WebCore::HistoryItem*); - static void AddItem(const AutoJObject&, WebCore::HistoryItem*); - static void RemoveItem(const AutoJObject&, int); - static void UpdateHistoryIndex(const AutoJObject&, int); -}; - -// there are two scale factors saved with each history item. m_scale reflects the -// viewport scale factor, default to 100 means 100%. m_textWrapScale records -// the scale factor for wrapping the text paragraph. -class WebHistoryItem : public WebCore::AndroidWebHistoryBridge { -public: - WebHistoryItem(WebHistoryItem* parent) - : WebCore::AndroidWebHistoryBridge(0) - , m_parent(parent) - , m_object(NULL) { } - WebHistoryItem(JNIEnv*, jobject, WebCore::HistoryItem*); - ~WebHistoryItem(); - void updateHistoryItem(WebCore::HistoryItem* item); - void setParent(WebHistoryItem* parent) { m_parent = parent; } - WebHistoryItem* parent() const { return m_parent.get(); } -private: - RefPtr m_parent; - jweak m_object; -}; - -}; - -#endif diff --git a/WebKit/android/jni/WebIconDatabase.cpp b/WebKit/android/jni/WebIconDatabase.cpp deleted file mode 100644 index 2a660d1..0000000 --- a/WebKit/android/jni/WebIconDatabase.cpp +++ /dev/null @@ -1,237 +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 "favicons" - -#include "config.h" -#include "WebIconDatabase.h" - -#include "FileSystem.h" -#include "GraphicsJNI.h" -#include "IconDatabase.h" -#include "Image.h" -#include "IntRect.h" -#include "JavaSharedClient.h" -#include "KURL.h" -#include "WebCoreJni.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace android { - -jobject webcoreImageToJavaBitmap(JNIEnv* env, WebCore::Image* icon) -{ - if (!icon) - return NULL; - SkBitmap bm; - WebCore::SharedBuffer* buffer = icon->data(); - if (!buffer || !SkImageDecoder::DecodeMemory(buffer->data(), buffer->size(), - &bm, SkBitmap::kNo_Config, - SkImageDecoder::kDecodePixels_Mode)) - return NULL; - - return GraphicsJNI::createBitmap(env, new SkBitmap(bm), false, NULL); -} - -static WebIconDatabase* gIconDatabaseClient = new WebIconDatabase(); - -// XXX: Called by the IconDatabase thread -void WebIconDatabase::dispatchDidAddIconForPageURL(const WTF::String& pageURL) -{ - mNotificationsMutex.lock(); - mNotifications.append(pageURL); - if (!mDeliveryRequested) { - mDeliveryRequested = true; - JavaSharedClient::EnqueueFunctionPtr(DeliverNotifications, this); - } - mNotificationsMutex.unlock(); -} - -// Called in the WebCore thread -void WebIconDatabase::RegisterForIconNotification(WebIconDatabaseClient* client) -{ - WebIconDatabase* db = gIconDatabaseClient; - for (unsigned i = 0; i < db->mClients.size(); ++i) { - // Do not add the same client twice. - if (db->mClients[i] == client) - return; - } - gIconDatabaseClient->mClients.append(client); -} - -// Called in the WebCore thread -void WebIconDatabase::UnregisterForIconNotification(WebIconDatabaseClient* client) -{ - WebIconDatabase* db = gIconDatabaseClient; - for (unsigned i = 0; i < db->mClients.size(); ++i) { - if (db->mClients[i] == client) { - db->mClients.remove(i); - break; - } - } -} - -// Called in the WebCore thread -void WebIconDatabase::DeliverNotifications(void* v) -{ - ASSERT(v); - ((WebIconDatabase*)v)->deliverNotifications(); -} - -// Called in the WebCore thread -void WebIconDatabase::deliverNotifications() -{ - ASSERT(mDeliveryRequested); - - // Swap the notifications queue - Vector queue; - mNotificationsMutex.lock(); - queue.swap(mNotifications); - mDeliveryRequested = false; - mNotificationsMutex.unlock(); - - // Swap the clients queue - Vector clients; - clients.swap(mClients); - - for (unsigned i = 0; i < queue.size(); ++i) { - for (unsigned j = 0; j < clients.size(); ++j) { - clients[j]->didAddIconForPageUrl(queue[i]); - } - } -} - -static void Open(JNIEnv* env, jobject obj, jstring path) -{ - WebCore::IconDatabase* iconDb = WebCore::iconDatabase(); - if (iconDb->isOpen()) - return; - iconDb->setEnabled(true); - iconDb->setClient(gIconDatabaseClient); - LOG_ASSERT(path, "No path given to nativeOpen"); - WTF::String pathStr = jstringToWtfString(env, path); - WTF::CString fullPath = WebCore::pathByAppendingComponent(pathStr, - WebCore::IconDatabase::defaultDatabaseFilename()).utf8(); - mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP; - bool didSetPermissions = false; - if (access(fullPath.data(), F_OK) == 0) { - if (chmod(fullPath.data(), mode) == 0) - didSetPermissions = true; - } else { - int fd = open(fullPath.data(), O_CREAT, mode); - if (fd >= 0) { - close(fd); - didSetPermissions = true; - } - } - if (didSetPermissions) { - LOGV("Opening WebIconDatabase file '%s'", pathStr.latin1().data()); - bool res = iconDb->open(pathStr); - if (!res) - LOGE("Open failed!"); - } else - LOGE("Failed to set permissions on '%s'", fullPath.data()); -} - -static void Close(JNIEnv* env, jobject obj) -{ - WebCore::iconDatabase()->close(); -} - -static void RemoveAllIcons(JNIEnv* env, jobject obj) -{ - LOGV("Removing all icons"); - WebCore::iconDatabase()->removeAllIcons(); -} - -static jobject IconForPageUrl(JNIEnv* env, jobject obj, jstring url) -{ - LOG_ASSERT(url, "No url given to iconForPageUrl"); - WTF::String urlStr = jstringToWtfString(env, url); - - WebCore::Image* icon = WebCore::iconDatabase()->iconForPageURL(urlStr, - WebCore::IntSize(16, 16)); - LOGV("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"); - WTF::String urlStr = jstringToWtfString(env, url); - - LOGV("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"); - WTF::String urlStr = jstringToWtfString(env, url); - - LOGV("Releasing icon for '%s'", urlStr.latin1().data()); - WebCore::iconDatabase()->releaseIconForPageURL(urlStr); -} - -/* - * JNI registration - */ -static JNINativeMethod gWebIconDatabaseMethods[] = { - { "nativeOpen", "(Ljava/lang/String;)V", - (void*) Open }, - { "nativeClose", "()V", - (void*) Close }, - { "nativeRemoveAllIcons", "()V", - (void*) RemoveAllIcons }, - { "nativeIconForPageUrl", "(Ljava/lang/String;)Landroid/graphics/Bitmap;", - (void*) IconForPageUrl }, - { "nativeRetainIconForPageUrl", "(Ljava/lang/String;)V", - (void*) RetainIconForPageUrl }, - { "nativeReleaseIconForPageUrl", "(Ljava/lang/String;)V", - (void*) ReleaseIconForPageUrl } -}; - -int registerWebIconDatabase(JNIEnv* env) -{ -#ifndef NDEBUG - jclass webIconDatabase = env->FindClass("android/webkit/WebIconDatabase"); - LOG_ASSERT(webIconDatabase, "Unable to find class android.webkit.WebIconDatabase"); - env->DeleteLocalRef(webIconDatabase); -#endif - - return jniRegisterNativeMethods(env, "android/webkit/WebIconDatabase", - gWebIconDatabaseMethods, NELEM(gWebIconDatabaseMethods)); -} - -} diff --git a/WebKit/android/jni/WebIconDatabase.h b/WebKit/android/jni/WebIconDatabase.h deleted file mode 100644 index b2169aa..0000000 --- a/WebKit/android/jni/WebIconDatabase.h +++ /dev/null @@ -1,75 +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 ANDROID_WEBKIT_WEBICONDATABASE_H -#define ANDROID_WEBKIT_WEBICONDATABASE_H - -#include "IconDatabaseClient.h" -#include "PlatformString.h" -#include "utils/threads.h" -#include -#include - -namespace WebCore { - class Image; -} - -namespace android { - - class WebIconDatabaseClient { - public: - virtual ~WebIconDatabaseClient() {} - virtual void didAddIconForPageUrl(const WTF::String& pageUrl) = 0; - }; - - class WebIconDatabase : public WebCore::IconDatabaseClient { - public: - WebIconDatabase() : mDeliveryRequested(false) {} - // IconDatabaseClient method - virtual void dispatchDidAddIconForPageURL(const WTF::String& pageURL); - - static void RegisterForIconNotification(WebIconDatabaseClient* client); - static void UnregisterForIconNotification(WebIconDatabaseClient* client); - static void DeliverNotifications(void*); - - private: - // Deliver all the icon notifications - void deliverNotifications(); - - // List of clients. - Vector mClients; - - // Queue of page urls that have received an icon. - Vector mNotifications; - android::Mutex mNotificationsMutex; - // Flag to indicate that we have requested a delivery of notifications. - bool mDeliveryRequested; - }; - - jobject webcoreImageToJavaBitmap(JNIEnv* env, WebCore::Image* icon); - -}; - -#endif diff --git a/WebKit/android/jni/WebSettings.cpp b/WebKit/android/jni/WebSettings.cpp deleted file mode 100644 index 468e7b0..0000000 --- a/WebKit/android/jni/WebSettings.cpp +++ /dev/null @@ -1,599 +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. - */ - -#define LOG_TAG "websettings" - -#include -#include - -#include "ApplicationCacheStorage.h" -#include "BitmapAllocatorAndroid.h" -#include "CachedResourceLoader.h" -#include "ChromiumIncludes.h" -#include "DatabaseTracker.h" -#include "Database.h" -#include "Document.h" -#include "EditorClientAndroid.h" -#include "FileSystem.h" -#include "Frame.h" -#include "FrameLoader.h" -#include "FrameView.h" -#include "GeolocationPermissions.h" -#include "GeolocationPositionCache.h" -#include "Page.h" -#include "PageCache.h" -#include "RenderTable.h" -#include "SQLiteFileSystem.h" -#include "Settings.h" -#include "WebCoreFrameBridge.h" -#include "WebCoreJni.h" -#if USE(V8) -#include "WorkerContextExecutionProxy.h" -#endif -#include "WebRequestContext.h" -#include "WebViewCore.h" - -#include -#include -#include - -namespace android { - -static const int permissionFlags660 = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP; - -struct FieldIds { - FieldIds(JNIEnv* env, jclass clazz) { - mLayoutAlgorithm = env->GetFieldID(clazz, "mLayoutAlgorithm", - "Landroid/webkit/WebSettings$LayoutAlgorithm;"); - mTextSize = env->GetFieldID(clazz, "mTextSize", - "Landroid/webkit/WebSettings$TextSize;"); - mStandardFontFamily = env->GetFieldID(clazz, "mStandardFontFamily", - "Ljava/lang/String;"); - mFixedFontFamily = env->GetFieldID(clazz, "mFixedFontFamily", - "Ljava/lang/String;"); - mSansSerifFontFamily = env->GetFieldID(clazz, "mSansSerifFontFamily", - "Ljava/lang/String;"); - mSerifFontFamily = env->GetFieldID(clazz, "mSerifFontFamily", - "Ljava/lang/String;"); - mCursiveFontFamily = env->GetFieldID(clazz, "mCursiveFontFamily", - "Ljava/lang/String;"); - mFantasyFontFamily = env->GetFieldID(clazz, "mFantasyFontFamily", - "Ljava/lang/String;"); - mDefaultTextEncoding = env->GetFieldID(clazz, "mDefaultTextEncoding", - "Ljava/lang/String;"); - mUserAgent = env->GetFieldID(clazz, "mUserAgent", - "Ljava/lang/String;"); - mAcceptLanguage = env->GetFieldID(clazz, "mAcceptLanguage", "Ljava/lang/String;"); - mMinimumFontSize = env->GetFieldID(clazz, "mMinimumFontSize", "I"); - mMinimumLogicalFontSize = env->GetFieldID(clazz, "mMinimumLogicalFontSize", "I"); - mDefaultFontSize = env->GetFieldID(clazz, "mDefaultFontSize", "I"); - mDefaultFixedFontSize = env->GetFieldID(clazz, "mDefaultFixedFontSize", "I"); - mLoadsImagesAutomatically = env->GetFieldID(clazz, "mLoadsImagesAutomatically", "Z"); -#ifdef ANDROID_BLOCK_NETWORK_IMAGE - mBlockNetworkImage = env->GetFieldID(clazz, "mBlockNetworkImage", "Z"); -#endif - mBlockNetworkLoads = env->GetFieldID(clazz, "mBlockNetworkLoads", "Z"); - mJavaScriptEnabled = env->GetFieldID(clazz, "mJavaScriptEnabled", "Z"); - mPluginState = env->GetFieldID(clazz, "mPluginState", - "Landroid/webkit/WebSettings$PluginState;"); -#if ENABLE(DATABASE) - mDatabaseEnabled = env->GetFieldID(clazz, "mDatabaseEnabled", "Z"); -#endif -#if ENABLE(DOM_STORAGE) - mDomStorageEnabled = env->GetFieldID(clazz, "mDomStorageEnabled", "Z"); -#endif -#if ENABLE(DATABASE) || ENABLE(DOM_STORAGE) - // The databases saved to disk for both the SQL and DOM Storage APIs are stored - // in the same base directory. - mDatabasePath = env->GetFieldID(clazz, "mDatabasePath", "Ljava/lang/String;"); - mDatabasePathHasBeenSet = env->GetFieldID(clazz, "mDatabasePathHasBeenSet", "Z"); -#endif -#if ENABLE(OFFLINE_WEB_APPLICATIONS) - mAppCacheEnabled = env->GetFieldID(clazz, "mAppCacheEnabled", "Z"); - mAppCachePath = env->GetFieldID(clazz, "mAppCachePath", "Ljava/lang/String;"); - mAppCacheMaxSize = env->GetFieldID(clazz, "mAppCacheMaxSize", "J"); -#endif -#if ENABLE(WORKERS) - mWorkersEnabled = env->GetFieldID(clazz, "mWorkersEnabled", "Z"); -#endif - mGeolocationEnabled = env->GetFieldID(clazz, "mGeolocationEnabled", "Z"); - mGeolocationDatabasePath = env->GetFieldID(clazz, "mGeolocationDatabasePath", "Ljava/lang/String;"); - mXSSAuditorEnabled = env->GetFieldID(clazz, "mXSSAuditorEnabled", "Z"); - mJavaScriptCanOpenWindowsAutomatically = env->GetFieldID(clazz, - "mJavaScriptCanOpenWindowsAutomatically", "Z"); - mUseWideViewport = env->GetFieldID(clazz, "mUseWideViewport", "Z"); - mSupportMultipleWindows = env->GetFieldID(clazz, "mSupportMultipleWindows", "Z"); - mShrinksStandaloneImagesToFit = env->GetFieldID(clazz, "mShrinksStandaloneImagesToFit", "Z"); - mMaximumDecodedImageSize = env->GetFieldID(clazz, "mMaximumDecodedImageSize", "J"); - mPrivateBrowsingEnabled = env->GetFieldID(clazz, "mPrivateBrowsingEnabled", "Z"); - mSyntheticLinksEnabled = env->GetFieldID(clazz, "mSyntheticLinksEnabled", "Z"); - mUseDoubleTree = env->GetFieldID(clazz, "mUseDoubleTree", "Z"); - mPageCacheCapacity = env->GetFieldID(clazz, "mPageCacheCapacity", "I"); -#if ENABLE(WEB_AUTOFILL) - mAutoFillEnabled = env->GetFieldID(clazz, "mAutoFillEnabled", "Z"); - mAutoFillProfile = env->GetFieldID(clazz, "mAutoFillProfile", "Landroid/webkit/WebSettings$AutoFillProfile;"); - jclass autoFillProfileClass = env->FindClass("android/webkit/WebSettings$AutoFillProfile"); - mAutoFillProfileFullName = env->GetFieldID(autoFillProfileClass, "mFullName", "Ljava/lang/String;"); - mAutoFillProfileEmailAddress = env->GetFieldID(autoFillProfileClass, "mEmailAddress", "Ljava/lang/String;"); - mAutoFillProfileCompanyName = env->GetFieldID(autoFillProfileClass, "mCompanyName", "Ljava/lang/String;"); - mAutoFillProfileAddressLine1 = env->GetFieldID(autoFillProfileClass, "mAddressLine1", "Ljava/lang/String;"); - mAutoFillProfileAddressLine2 = env->GetFieldID(autoFillProfileClass, "mAddressLine2", "Ljava/lang/String;"); - mAutoFillProfileCity = env->GetFieldID(autoFillProfileClass, "mCity", "Ljava/lang/String;"); - mAutoFillProfileState = env->GetFieldID(autoFillProfileClass, "mState", "Ljava/lang/String;"); - mAutoFillProfileZipCode = env->GetFieldID(autoFillProfileClass, "mZipCode", "Ljava/lang/String;"); - mAutoFillProfileCountry = env->GetFieldID(autoFillProfileClass, "mCountry", "Ljava/lang/String;"); - 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"); -#ifdef ANDROID_BLOCK_NETWORK_IMAGE - LOG_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"); -#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"); -#endif -#if ENABLE(WORKERS) - LOG_ASSERT(mWorkersEnabled, "Could not find field mWorkersEnabled"); -#endif - LOG_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"); - - jclass enumClass = env->FindClass("java/lang/Enum"); - LOG_ASSERT(enumClass, "Could not find Enum class!"); - mOrdinal = env->GetMethodID(enumClass, "ordinal", "()I"); - LOG_ASSERT(mOrdinal, "Could not find method ordinal"); - env->DeleteLocalRef(enumClass); - - jclass textSizeClass = env->FindClass("android/webkit/WebSettings$TextSize"); - LOG_ASSERT(textSizeClass, "Could not find TextSize enum"); - mTextSizeValue = env->GetFieldID(textSizeClass, "value", "I"); - env->DeleteLocalRef(textSizeClass); - } - - // Field ids - jfieldID mLayoutAlgorithm; - jfieldID mTextSize; - jfieldID mStandardFontFamily; - jfieldID mFixedFontFamily; - jfieldID mSansSerifFontFamily; - jfieldID mSerifFontFamily; - jfieldID mCursiveFontFamily; - jfieldID mFantasyFontFamily; - jfieldID mDefaultTextEncoding; - jfieldID mUserAgent; - jfieldID mAcceptLanguage; - jfieldID mMinimumFontSize; - jfieldID mMinimumLogicalFontSize; - jfieldID mDefaultFontSize; - jfieldID mDefaultFixedFontSize; - jfieldID mLoadsImagesAutomatically; -#ifdef ANDROID_BLOCK_NETWORK_IMAGE - jfieldID mBlockNetworkImage; -#endif - jfieldID mBlockNetworkLoads; - jfieldID mJavaScriptEnabled; - jfieldID mPluginState; -#if ENABLE(OFFLINE_WEB_APPLICATIONS) - jfieldID mAppCacheEnabled; - jfieldID mAppCachePath; - jfieldID mAppCacheMaxSize; -#endif -#if ENABLE(WORKERS) - jfieldID mWorkersEnabled; -#endif - jfieldID mJavaScriptCanOpenWindowsAutomatically; - jfieldID mUseWideViewport; - jfieldID mSupportMultipleWindows; - jfieldID mShrinksStandaloneImagesToFit; - jfieldID mMaximumDecodedImageSize; - jfieldID mPrivateBrowsingEnabled; - jfieldID mSyntheticLinksEnabled; - jfieldID mUseDoubleTree; - jfieldID mPageCacheCapacity; - // Ordinal() method and value field for enums - jmethodID mOrdinal; - jfieldID mTextSizeValue; - -#if ENABLE(DATABASE) - jfieldID mDatabaseEnabled; -#endif -#if ENABLE(DOM_STORAGE) - jfieldID mDomStorageEnabled; -#endif - jfieldID mGeolocationEnabled; - jfieldID mGeolocationDatabasePath; - jfieldID mXSSAuditorEnabled; -#if ENABLE(DATABASE) || ENABLE(DOM_STORAGE) - jfieldID mDatabasePath; - jfieldID mDatabasePathHasBeenSet; -#endif -#if ENABLE(WEB_AUTOFILL) - jfieldID mAutoFillEnabled; - jfieldID mAutoFillProfile; - jfieldID mAutoFillProfileFullName; - jfieldID mAutoFillProfileEmailAddress; - jfieldID mAutoFillProfileCompanyName; - jfieldID mAutoFillProfileAddressLine1; - jfieldID mAutoFillProfileAddressLine2; - jfieldID mAutoFillProfileCity; - jfieldID mAutoFillProfileState; - jfieldID mAutoFillProfileZipCode; - jfieldID mAutoFillProfileCountry; - jfieldID mAutoFillProfilePhoneNumber; -#endif -#if USE(CHROME_NETWORK_STACK) - jfieldID mOverrideCacheMode; -#endif -}; - -static struct FieldIds* gFieldIds; - -// Note: This is moved from the old FrameAndroid.cpp -static void recursiveCleanupForFullLayout(WebCore::RenderObject* obj) -{ - obj->setNeedsLayout(true, false); -#ifdef ANDROID_LAYOUT - if (obj->isTable()) - (static_cast(obj))->clearSingleColumn(); -#endif - for (WebCore::RenderObject* n = obj->firstChild(); n; n = n->nextSibling()) - recursiveCleanupForFullLayout(n); -} - -#if ENABLE(WEB_AUTOFILL) -inline string16 getStringFieldAsString16(JNIEnv* env, jobject autoFillProfile, jfieldID fieldId) -{ - jstring str = static_cast(env->GetObjectField(autoFillProfile, fieldId)); - return str ? jstringToString16(env, str) : string16(); -} - -void syncAutoFillProfile(JNIEnv* env, jobject autoFillProfile, WebAutoFill* webAutoFill) -{ - string16 fullName = getStringFieldAsString16(env, autoFillProfile, gFieldIds->mAutoFillProfileFullName); - string16 emailAddress = getStringFieldAsString16(env, autoFillProfile, gFieldIds->mAutoFillProfileEmailAddress); - string16 companyName = getStringFieldAsString16(env, autoFillProfile, gFieldIds->mAutoFillProfileCompanyName); - string16 addressLine1 = getStringFieldAsString16(env, autoFillProfile, gFieldIds->mAutoFillProfileAddressLine1); - string16 addressLine2 = getStringFieldAsString16(env, autoFillProfile, gFieldIds->mAutoFillProfileAddressLine2); - string16 city = getStringFieldAsString16(env, autoFillProfile, gFieldIds->mAutoFillProfileCity); - string16 state = getStringFieldAsString16(env, autoFillProfile, gFieldIds->mAutoFillProfileState); - string16 zipCode = getStringFieldAsString16(env, autoFillProfile, gFieldIds->mAutoFillProfileZipCode); - string16 country = getStringFieldAsString16(env, autoFillProfile, gFieldIds->mAutoFillProfileCountry); - string16 phoneNumber = getStringFieldAsString16(env, autoFillProfile, gFieldIds->mAutoFillProfilePhoneNumber); - - webAutoFill->setProfile(fullName, emailAddress, companyName, addressLine1, addressLine2, city, state, zipCode, country, phoneNumber); -} -#endif - -class WebSettings { -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__); - WebCore::Settings* s = pFrame->settings(); - if (!s) - return; - WebCore::CachedResourceLoader* cachedResourceLoader = pFrame->document()->cachedResourceLoader(); - -#ifdef ANDROID_LAYOUT - jobject layout = env->GetObjectField(obj, gFieldIds->mLayoutAlgorithm); - WebCore::Settings::LayoutAlgorithm l = (WebCore::Settings::LayoutAlgorithm) - env->CallIntMethod(layout, gFieldIds->mOrdinal); - if (s->layoutAlgorithm() != l) { - s->setLayoutAlgorithm(l); - if (pFrame->document()) { - 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"); - 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 - // WebViewCore, on the UI side, so there needs to be a new way to do this. - //pFrame->makeFocusVisible(); - } - } - } -#endif - jobject textSize = env->GetObjectField(obj, gFieldIds->mTextSize); - float zoomFactor = env->GetIntField(textSize, gFieldIds->mTextSizeValue) / 100.0f; - if (pFrame->textZoomFactor() != zoomFactor) - pFrame->setTextZoomFactor(zoomFactor); - - jstring str = (jstring)env->GetObjectField(obj, gFieldIds->mStandardFontFamily); - s->setStandardFontFamily(jstringToWtfString(env, str)); - - str = (jstring)env->GetObjectField(obj, gFieldIds->mFixedFontFamily); - s->setFixedFontFamily(jstringToWtfString(env, str)); - - str = (jstring)env->GetObjectField(obj, gFieldIds->mSansSerifFontFamily); - s->setSansSerifFontFamily(jstringToWtfString(env, str)); - - str = (jstring)env->GetObjectField(obj, gFieldIds->mSerifFontFamily); - s->setSerifFontFamily(jstringToWtfString(env, str)); - - str = (jstring)env->GetObjectField(obj, gFieldIds->mCursiveFontFamily); - s->setCursiveFontFamily(jstringToWtfString(env, str)); - - str = (jstring)env->GetObjectField(obj, gFieldIds->mFantasyFontFamily); - s->setFantasyFontFamily(jstringToWtfString(env, str)); - - str = (jstring)env->GetObjectField(obj, gFieldIds->mDefaultTextEncoding); - s->setDefaultTextEncodingName(jstringToWtfString(env, str)); - - 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); - WebViewCore::getWebViewCore(pFrame->view())->setWebRequestContextCacheMode(cacheMode); - - str = (jstring)env->GetObjectField(obj, gFieldIds->mAcceptLanguage); - WebRequestContext::setAcceptLanguage(jstringToWtfString(env, str)); -#endif - - jint size = env->GetIntField(obj, gFieldIds->mMinimumFontSize); - s->setMinimumFontSize(size); - - size = env->GetIntField(obj, gFieldIds->mMinimumLogicalFontSize); - s->setMinimumLogicalFontSize(size); - - size = env->GetIntField(obj, gFieldIds->mDefaultFontSize); - s->setDefaultFontSize(size); - - size = env->GetIntField(obj, gFieldIds->mDefaultFixedFontSize); - s->setDefaultFixedFontSize(size); - - jboolean flag = env->GetBooleanField(obj, gFieldIds->mLoadsImagesAutomatically); - s->setLoadsImagesAutomatically(flag); - if (flag) - cachedResourceLoader->setAutoLoadImages(true); - -#ifdef ANDROID_BLOCK_NETWORK_IMAGE - flag = env->GetBooleanField(obj, gFieldIds->mBlockNetworkImage); - s->setBlockNetworkImage(flag); - if(!flag) - cachedResourceLoader->setBlockNetworkImage(false); -#endif - flag = env->GetBooleanField(obj, gFieldIds->mBlockNetworkLoads); - WebFrame* webFrame = WebFrame::getWebFrame(pFrame); - webFrame->setBlockNetworkLoads(flag); - - flag = env->GetBooleanField(obj, gFieldIds->mJavaScriptEnabled); - s->setJavaScriptEnabled(flag); - - // ON = 0 - // ON_DEMAND = 1 - // OFF = 2 - jobject pluginState = env->GetObjectField(obj, gFieldIds->mPluginState); - int state = env->CallIntMethod(pluginState, gFieldIds->mOrdinal); - s->setPluginsEnabled(state < 2); -#ifdef ANDROID_PLUGINS - s->setPluginsOnDemand(state == 1); -#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); - // 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) - close(fd); - } - } - jlong maxsize = env->GetLongField(obj, gFieldIds->mAppCacheMaxSize); - cacheStorage().setMaximumSize(maxsize); -#endif - - flag = env->GetBooleanField(obj, gFieldIds->mJavaScriptCanOpenWindowsAutomatically); - s->setJavaScriptCanOpenWindowsAutomatically(flag); - -#ifdef ANDROID_LAYOUT - flag = env->GetBooleanField(obj, gFieldIds->mUseWideViewport); - s->setUseWideViewport(flag); -#endif - -#ifdef ANDROID_MULTIPLE_WINDOWS - flag = env->GetBooleanField(obj, gFieldIds->mSupportMultipleWindows); - s->setSupportMultipleWindows(flag); -#endif - flag = env->GetBooleanField(obj, gFieldIds->mShrinksStandaloneImagesToFit); - s->setShrinksStandaloneImagesToFit(flag); - jlong maxImage = env->GetLongField(obj, gFieldIds->mMaximumDecodedImageSize); - // Since in ImageSourceAndroid.cpp, the image will always not exceed - // MAX_SIZE_BEFORE_SUBSAMPLE, there's no need to pass the max value to - // WebCore, which checks (image_width * image_height * 4) as an - // estimation against the max value, which is done in CachedImage.cpp. - // And there're cases where the decoded image size will not - // exceed the max, but the WebCore estimation will. So the following - // code is commented out to fix those cases. - // if (maxImage == 0) - // maxImage = computeMaxBitmapSizeForCache(); - s->setMaximumDecodedImageSize(maxImage); - - flag = env->GetBooleanField(obj, gFieldIds->mPrivateBrowsingEnabled); - s->setPrivateBrowsingEnabled(flag); - - flag = env->GetBooleanField(obj, gFieldIds->mSyntheticLinksEnabled); - s->setDefaultFormatDetection(flag); - s->setFormatDetectionAddress(flag); - s->setFormatDetectionEmail(flag); - s->setFormatDetectionTelephone(flag); -#if ENABLE(DATABASE) - flag = env->GetBooleanField(obj, gFieldIds->mDatabaseEnabled); - WebCore::Database::setIsAvailable(flag); - - flag = env->GetBooleanField(obj, gFieldIds->mDatabasePathHasBeenSet); - if (flag) { - // If the user has set the database path, sync it to the DatabaseTracker. - str = (jstring)env->GetObjectField(obj, gFieldIds->mDatabasePath); - if (str) { - String path = jstringToWtfString(env, str); - DatabaseTracker::tracker().setDatabaseDirectoryPath(path); - // This database is created when the first HTML5 Database object is - // instantiated. If the file doesn't exist, we create it and set its - // permissions. The filename must match that in - // DatabaseTracker.cpp. - String filename = SQLiteFileSystem::appendDatabaseFileNameToPath(path, "Databases.db"); - int fd = open(filename.utf8().data(), O_CREAT | O_EXCL, permissionFlags660); - if (fd >= 0) - close(fd); - } - } -#endif -#if ENABLE(DOM_STORAGE) - flag = env->GetBooleanField(obj, gFieldIds->mDomStorageEnabled); - s->setLocalStorageEnabled(flag); - str = (jstring)env->GetObjectField(obj, gFieldIds->mDatabasePath); - if (str) { - WTF::String localStorageDatabasePath = jstringToWtfString(env,str); - if (localStorageDatabasePath.length()) { - localStorageDatabasePath = WebCore::pathByAppendingComponent( - localStorageDatabasePath, "localstorage"); - // We need 770 for folders - mkdir(localStorageDatabasePath.utf8().data(), - permissionFlags660 | S_IXUSR | S_IXGRP); - s->setLocalStorageDatabasePath(localStorageDatabasePath); - } - } -#endif - - flag = env->GetBooleanField(obj, gFieldIds->mGeolocationEnabled); - GeolocationPermissions::setAlwaysDeny(!flag); - str = (jstring)env->GetObjectField(obj, gFieldIds->mGeolocationDatabasePath); - if (str) { - String path = jstringToWtfString(env, str); - GeolocationPermissions::setDatabasePath(path); - GeolocationPositionCache::instance()->setDatabasePath(path); - // This database is created when the first Geolocation object is - // instantiated. If the file doesn't exist, we create it and set its - // permissions. The filename must match that in - // GeolocationPositionCache.cpp. - String filename = SQLiteFileSystem::appendDatabaseFileNameToPath(path, "CachedGeoposition.db"); - int fd = open(filename.utf8().data(), O_CREAT | O_EXCL, permissionFlags660); - if (fd >= 0) - close(fd); - } - - flag = env->GetBooleanField(obj, gFieldIds->mXSSAuditorEnabled); - s->setXSSAuditorEnabled(flag); - - size = env->GetIntField(obj, gFieldIds->mPageCacheCapacity); - if (size > 0) { - s->setUsesPageCache(true); - WebCore::pageCache()->setCapacity(size); - } else - s->setUsesPageCache(false); - -#if ENABLE(WEB_AUTOFILL) - flag = env->GetBooleanField(obj, gFieldIds->mAutoFillEnabled); - // TODO: This updates the Settings WebCore side with the user's - // preference for autofill and will stop WebCore making requests - // into the chromium autofill code. That code in Chromium also has - // a notion of being enabled/disabled that gets read from the users - // preferences. At the moment, it's hardcoded to true on Android - // (see chrome/browser/autofill/autofill_manager.cc:405). This - // setting should probably be synced into Chromium also. - - s->setAutoFillEnabled(flag); - - if (flag) { - EditorClientAndroid* editorC = static_cast(pFrame->page()->editorClient()); - WebAutoFill* webAutoFill = editorC->getAutoFill(); - // Set the active AutoFillProfile data. - jobject autoFillProfile = env->GetObjectField(obj, gFieldIds->mAutoFillProfile); - if (autoFillProfile) - syncAutoFillProfile(env, autoFillProfile, webAutoFill); - else { - // The autofill profile is null. We need to tell Chromium about this because - // this may be because the user just deleted their profile but left the - // autofill feature setting enabled. - webAutoFill->clearProfiles(); - } - } -#endif - } -}; - - -//------------------------------------------------------------- -// JNI registration -//------------------------------------------------------------- - -static JNINativeMethod gWebSettingsMethods[] = { - { "nativeSync", "(I)V", - (void*) WebSettings::Sync } -}; - -int registerWebSettings(JNIEnv* env) -{ - jclass clazz = env->FindClass("android/webkit/WebSettings"); - LOG_ASSERT(clazz, "Unable to find class WebSettings!"); - gFieldIds = new FieldIds(env, clazz); - env->DeleteLocalRef(clazz); - return jniRegisterNativeMethods(env, "android/webkit/WebSettings", - gWebSettingsMethods, NELEM(gWebSettingsMethods)); -} - -} diff --git a/WebKit/android/jni/WebStorage.cpp b/WebKit/android/jni/WebStorage.cpp deleted file mode 100644 index 9ce207d..0000000 --- a/WebKit/android/jni/WebStorage.cpp +++ /dev/null @@ -1,188 +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 "config.h" - -#if ENABLE(DATABASE) - -#include "ApplicationCacheStorage.h" -#include "DatabaseTracker.h" -#include "JNIUtility.h" -#include "JavaSharedClient.h" -#include "KURL.h" -#include "PageGroup.h" -#include "SecurityOrigin.h" -#include "WebCoreJni.h" - -#include - -namespace android { - -static jobject GetOrigins(JNIEnv* env, jobject obj) -{ - Vector > coreOrigins; - WebCore::DatabaseTracker::tracker().origins(coreOrigins); - Vector manifestUrls; - if (WebCore::cacheStorage().manifestURLs(&manifestUrls)) { - int size = manifestUrls.size(); - for (int i = 0; i < size; ++i) { - RefPtr manifestOrigin = WebCore::SecurityOrigin::create(manifestUrls[i]); - if (manifestOrigin.get() == 0) - continue; - coreOrigins.append(manifestOrigin); - } - } - - jclass setClass = env->FindClass("java/util/HashSet"); - jmethodID cid = env->GetMethodID(setClass, "", "()V"); - jmethodID mid = env->GetMethodID(setClass, "add", "(Ljava/lang/Object;)Z"); - jobject set = env->NewObject(setClass, cid); - env->DeleteLocalRef(setClass); - - for (unsigned i = 0; i < coreOrigins.size(); ++i) { - WebCore::SecurityOrigin* origin = coreOrigins[i].get(); - WTF::String url = origin->toString(); - jstring jUrl = wtfStringToJstring(env, url); - env->CallBooleanMethod(set, mid, jUrl); - env->DeleteLocalRef(jUrl); - } - - return set; -} - -static unsigned long long GetQuotaForOrigin(JNIEnv* env, jobject obj, jstring origin) -{ - WTF::String originStr = jstringToWtfString(env, origin); - RefPtr securityOrigin = WebCore::SecurityOrigin::createFromString(originStr); - unsigned long long quota = WebCore::DatabaseTracker::tracker().quotaForOrigin(securityOrigin.get()); - return quota; -} - -static unsigned long long GetUsageForOrigin(JNIEnv* env, jobject obj, jstring origin) -{ - WTF::String originStr = jstringToWtfString(env, origin); - RefPtr securityOrigin = WebCore::SecurityOrigin::createFromString(originStr); - unsigned long long usage = WebCore::DatabaseTracker::tracker().usageForOrigin(securityOrigin.get()); - Vector manifestUrls; - if (!WebCore::cacheStorage().manifestURLs(&manifestUrls)) - return usage; - int size = manifestUrls.size(); - for (int i = 0; i < size; ++i) { - RefPtr manifestOrigin = WebCore::SecurityOrigin::create(manifestUrls[i]); - if (manifestOrigin.get() == 0) - continue; - if (manifestOrigin->isSameSchemeHostPort(securityOrigin.get())) { - int64_t cacheSize = 0; - WebCore::cacheStorage().cacheGroupSize(manifestUrls[i].string(), &cacheSize); - usage += cacheSize; - } - } - return usage; -} - -static void SetQuotaForOrigin(JNIEnv* env, jobject obj, jstring origin, unsigned long long quota) -{ - WTF::String originStr = jstringToWtfString(env, origin); - RefPtr securityOrigin = WebCore::SecurityOrigin::createFromString(originStr); - WebCore::DatabaseTracker::tracker().setQuota(securityOrigin.get(), quota); -} - -static void DeleteOrigin(JNIEnv* env, jobject obj, jstring origin) -{ - WTF::String originStr = jstringToWtfString(env, origin); - RefPtr securityOrigin = WebCore::SecurityOrigin::createFromString(originStr); - WebCore::DatabaseTracker::tracker().deleteOrigin(securityOrigin.get()); - - Vector manifestUrls; - if (!WebCore::cacheStorage().manifestURLs(&manifestUrls)) - return; - int size = manifestUrls.size(); - for (int i = 0; i < size; ++i) { - RefPtr manifestOrigin = WebCore::SecurityOrigin::create(manifestUrls[i]); - if (manifestOrigin.get() == 0) - continue; - if (manifestOrigin->isSameSchemeHostPort(securityOrigin.get())) - WebCore::cacheStorage().deleteCacheGroup(manifestUrls[i]); - } -} - -static void DeleteAllData(JNIEnv* env, jobject obj) -{ - WebCore::DatabaseTracker::tracker().deleteAllDatabases(); - - Vector manifestUrls; - if (!WebCore::cacheStorage().manifestURLs(&manifestUrls)) - return; - int size = manifestUrls.size(); - for (int i = 0; i < size; ++i) - WebCore::cacheStorage().deleteCacheGroup(manifestUrls[i]); - - // FIXME: this is a workaround for eliminating any DOM Storage data (both - // session and local storage) as there is no functionality inside WebKit at the - // moment to do it. That functionality is a WIP in https://bugs.webkit.org/show_bug.cgi?id=51878 - // and when that patch lands and we merge it, we should move towards that approach instead. - WebCore::PageGroup::clearDomStorage(); -} - -static void SetAppCacheMaximumSize(JNIEnv* env, jobject obj, unsigned long long size) -{ - WebCore::cacheStorage().setMaximumSize(size); -} - -/* - * JNI registration - */ -static JNINativeMethod gWebStorageMethods[] = { - { "nativeGetOrigins", "()Ljava/util/Set;", - (void*) GetOrigins }, - { "nativeGetUsageForOrigin", "(Ljava/lang/String;)J", - (void*) GetUsageForOrigin }, - { "nativeGetQuotaForOrigin", "(Ljava/lang/String;)J", - (void*) GetQuotaForOrigin }, - { "nativeSetQuotaForOrigin", "(Ljava/lang/String;J)V", - (void*) SetQuotaForOrigin }, - { "nativeDeleteOrigin", "(Ljava/lang/String;)V", - (void*) DeleteOrigin }, - { "nativeDeleteAllData", "()V", - (void*) DeleteAllData }, - { "nativeSetAppCacheMaximumSize", "(J)V", - (void*) SetAppCacheMaximumSize } -}; - -int registerWebStorage(JNIEnv* env) -{ -#ifndef NDEBUG - jclass webStorage = env->FindClass("android/webkit/WebStorage"); - LOG_ASSERT(webStorage, "Unable to find class android.webkit.WebStorage"); - env->DeleteLocalRef(webStorage); -#endif - - return jniRegisterNativeMethods(env, "android/webkit/WebStorage", - gWebStorageMethods, NELEM(gWebStorageMethods)); -} - -} - -#endif //ENABLE(DATABASE) diff --git a/WebKit/android/jni/WebViewCore.cpp b/WebKit/android/jni/WebViewCore.cpp deleted file mode 100644 index f2680b5..0000000 --- a/WebKit/android/jni/WebViewCore.cpp +++ /dev/null @@ -1,4598 +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 "WebViewCore.h" - -#include "AccessibilityObject.h" -#include "Attribute.h" -#include "BaseLayerAndroid.h" -#include "CachedNode.h" -#include "CachedRoot.h" -#include "Chrome.h" -#include "ChromeClientAndroid.h" -#include "ChromiumIncludes.h" -#include "ClientRect.h" -#include "ClientRectList.h" -#include "Color.h" -#include "CSSPropertyNames.h" -#include "CSSValueKeywords.h" -#include "DatabaseTracker.h" -#include "Document.h" -#include "DOMWindow.h" -#include "DOMSelection.h" -#include "Element.h" -#include "Editor.h" -#include "EditorClientAndroid.h" -#include "EventHandler.h" -#include "EventNames.h" -#include "ExceptionCode.h" -#include "FocusController.h" -#include "Font.h" -#include "Frame.h" -#include "FrameLoader.h" -#include "FrameLoaderClientAndroid.h" -#include "FrameTree.h" -#include "FrameView.h" -#include "Geolocation.h" -#include "GraphicsContext.h" -#include "GraphicsJNI.h" -#include "HTMLAnchorElement.h" -#include "HTMLAreaElement.h" -#include "HTMLElement.h" -#include "HTMLFormControlElement.h" -#include "HTMLImageElement.h" -#include "HTMLInputElement.h" -#include "HTMLLabelElement.h" -#include "HTMLMapElement.h" -#include "HTMLNames.h" -#include "HTMLOptGroupElement.h" -#include "HTMLOptionElement.h" -#include "HTMLSelectElement.h" -#include "HTMLTextAreaElement.h" -#include "HistoryItem.h" -#include "HitTestRequest.h" -#include "HitTestResult.h" -#include "InlineTextBox.h" -#include "MemoryUsage.h" -#include "NamedNodeMap.h" -#include "Navigator.h" -#include "Node.h" -#include "NodeList.h" -#include "Page.h" -#include "PageGroup.h" -#include "PlatformKeyboardEvent.h" -#include "PlatformString.h" -#include "PluginWidgetAndroid.h" -#include "PluginView.h" -#include "Position.h" -#include "ProgressTracker.h" -#include "Range.h" -#include "RenderBox.h" -#include "RenderInline.h" -#include "RenderLayer.h" -#include "RenderPart.h" -#include "RenderText.h" -#include "RenderTextControl.h" -#include "RenderThemeAndroid.h" -#include "RenderView.h" -#include "ResourceRequest.h" -#include "SchemeRegistry.h" -#include "SelectionController.h" -#include "Settings.h" -#include "SkANP.h" -#include "SkTemplates.h" -#include "SkTDArray.h" -#include "SkTypes.h" -#include "SkCanvas.h" -#include "SkPicture.h" -#include "SkUtils.h" -#include "Text.h" -#include "TypingCommand.h" -#include "WebCoreFrameBridge.h" -#include "WebFrameView.h" -#include "WindowsKeyboardCodes.h" -#include "android_graphics.h" -#include "autofill/WebAutoFill.h" -#include "htmlediting.h" -#include "markup.h" - -#include -#include -#include -#include -#include -#include - -#if USE(V8) -#include "ScriptController.h" -#include "V8Counters.h" -#include -#endif - -#if DEBUG_NAV_UI -#include "SkTime.h" -#endif - -#if ENABLE(TOUCH_EVENTS) // Android -#include "PlatformTouchEvent.h" -#endif - -#ifdef ANDROID_DOM_LOGGING -#include "AndroidLog.h" -#include "RenderTreeAsText.h" -#include - -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 - -/* We pass this flag when recording the actual content, so that we don't spend - time actually regionizing complex path clips, when all we really want to do - is record them. - */ -#define PICT_RECORD_FLAGS SkPicture::kUsePathBoundsForClip_RecordingFlag - -//////////////////////////////////////////////////////////////////////////////////////////////// - -namespace android { - -static SkTDArray gInstanceList; - -void WebViewCore::addInstance(WebViewCore* inst) { - *gInstanceList.append() = inst; -} - -void WebViewCore::removeInstance(WebViewCore* inst) { - int index = gInstanceList.find(inst); - LOG_ASSERT(index >= 0, "RemoveInstance inst not found"); - if (index >= 0) { - gInstanceList.removeShuffle(index); - } -} - -bool WebViewCore::isInstance(WebViewCore* inst) { - return gInstanceList.find(inst) >= 0; -} - -jobject WebViewCore::getApplicationContext() { - - // check to see if there is a valid webviewcore object - if (gInstanceList.isEmpty()) - return 0; - - // get the context from the webview - jobject context = gInstanceList[0]->getContext(); - - if (!context) - return 0; - - // get the application context using JNI - JNIEnv* env = JSC::Bindings::getJNIEnv(); - jclass contextClass = env->GetObjectClass(context); - jmethodID appContextMethod = env->GetMethodID(contextClass, "getApplicationContext", "()Landroid/content/Context;"); - env->DeleteLocalRef(contextClass); - jobject result = env->CallObjectMethod(context, appContextMethod); - checkException(env); - return result; -} - - -struct WebViewCoreStaticMethods { - jmethodID m_isSupportedMediaMimeType; -} gWebViewCoreStaticMethods; - -// Check whether a media mimeType is supported in Android media framework. -bool WebViewCore::isSupportedMediaMimeType(const WTF::String& mimeType) { - JNIEnv* env = JSC::Bindings::getJNIEnv(); - jstring jMimeType = wtfStringToJstring(env, mimeType); - jclass webViewCore = env->FindClass("android/webkit/WebViewCore"); - bool val = env->CallStaticBooleanMethod(webViewCore, - gWebViewCoreStaticMethods.m_isSupportedMediaMimeType, jMimeType); - checkException(env); - env->DeleteLocalRef(webViewCore); - env->DeleteLocalRef(jMimeType); - - return val; -} - -// ---------------------------------------------------------------------------- - -#define GET_NATIVE_VIEW(env, obj) ((WebViewCore*)env->GetIntField(obj, gWebViewCoreFields.m_nativeClass)) - -// Field ids for WebViewCore -struct WebViewCoreFields { - jfieldID m_nativeClass; - jfieldID m_viewportWidth; - jfieldID m_viewportHeight; - jfieldID m_viewportInitialScale; - jfieldID m_viewportMinimumScale; - jfieldID m_viewportMaximumScale; - jfieldID m_viewportUserScalable; - jfieldID m_viewportDensityDpi; - jfieldID m_webView; - jfieldID m_drawIsPaused; - jfieldID m_lowMemoryUsageMb; - jfieldID m_highMemoryUsageMb; - jfieldID m_highUsageDeltaMb; -} gWebViewCoreFields; - -// ---------------------------------------------------------------------------- - -struct WebViewCore::JavaGlue { - jweak m_obj; - jmethodID m_scrollTo; - jmethodID m_contentDraw; - jmethodID m_layersDraw; - jmethodID m_requestListBox; - jmethodID m_openFileChooser; - jmethodID m_requestSingleListBox; - jmethodID m_jsAlert; - jmethodID m_jsConfirm; - jmethodID m_jsPrompt; - jmethodID m_jsUnload; - jmethodID m_jsInterrupt; - jmethodID m_didFirstLayout; - jmethodID m_updateViewport; - jmethodID m_sendNotifyProgressFinished; - jmethodID m_sendViewInvalidate; - jmethodID m_updateTextfield; - jmethodID m_updateTextSelection; - jmethodID m_clearTextEntry; - jmethodID m_restoreScale; - jmethodID m_needTouchEvents; - jmethodID m_requestKeyboard; - jmethodID m_requestKeyboardWithSelection; - jmethodID m_exceededDatabaseQuota; - jmethodID m_reachedMaxAppCacheSize; - jmethodID m_populateVisitedLinks; - jmethodID m_geolocationPermissionsShowPrompt; - jmethodID m_geolocationPermissionsHidePrompt; - jmethodID m_getDeviceMotionService; - jmethodID m_getDeviceOrientationService; - jmethodID m_addMessageToConsole; - jmethodID m_formDidBlur; - jmethodID m_getPluginClass; - jmethodID m_showFullScreenPlugin; - jmethodID m_hideFullScreenPlugin; - jmethodID m_createSurface; - jmethodID m_addSurface; - jmethodID m_updateSurface; - 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_setWebTextViewAutoFillable; - jmethodID m_selectAt; - AutoJObject object(JNIEnv* env) { - return getRealObject(env, m_obj); - } -}; - -/* - * WebViewCore Implementation - */ - -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); - return m; -} - -Mutex WebViewCore::gFrameCacheMutex; -Mutex WebViewCore::gButtonMutex; -Mutex WebViewCore::gCursorBoundsMutex; - -WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* mainframe) - : m_pluginInvalTimer(this, &WebViewCore::pluginInvalTimerFired) - , m_deviceMotionAndOrientationManager(this) -{ - m_mainFrame = mainframe; - - m_popupReply = 0; - m_moveGeneration = 0; - m_lastGeneration = 0; - m_touchGeneration = 0; - m_blockTextfieldUpdates = false; - // just initial values. These should be set by client - m_maxXScroll = 320/4; - m_maxYScroll = 240/4; - m_textGeneration = 0; - m_screenWidth = 320; - m_textWrapWidth = 320; - m_scale = 1; -#if ENABLE(TOUCH_EVENTS) - m_forwardingTouchEvents = false; -#endif - m_isPaused = false; - m_screenOnCounter = 0; - m_shouldPaintCaret = true; - - LOG_ASSERT(m_mainFrame, "Uh oh, somehow a frameview was made without an initial frame!"); - - jclass clazz = env->GetObjectClass(javaWebViewCore); - m_javaGlue = new JavaGlue; - m_javaGlue->m_obj = env->NewWeakGlobalRef(javaWebViewCore); - m_javaGlue->m_scrollTo = GetJMethod(env, clazz, "contentScrollTo", "(IIZZ)V"); - m_javaGlue->m_contentDraw = GetJMethod(env, clazz, "contentDraw", "()V"); - m_javaGlue->m_layersDraw = GetJMethod(env, clazz, "layersDraw", "()V"); - m_javaGlue->m_requestListBox = GetJMethod(env, clazz, "requestListBox", "([Ljava/lang/String;[I[I)V"); - m_javaGlue->m_openFileChooser = GetJMethod(env, clazz, "openFileChooser", "(Ljava/lang/String;)Ljava/lang/String;"); - m_javaGlue->m_requestSingleListBox = GetJMethod(env, clazz, "requestListBox", "([Ljava/lang/String;[II)V"); - m_javaGlue->m_jsAlert = GetJMethod(env, clazz, "jsAlert", "(Ljava/lang/String;Ljava/lang/String;)V"); - m_javaGlue->m_jsConfirm = GetJMethod(env, clazz, "jsConfirm", "(Ljava/lang/String;Ljava/lang/String;)Z"); - m_javaGlue->m_jsPrompt = GetJMethod(env, clazz, "jsPrompt", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"); - m_javaGlue->m_jsUnload = GetJMethod(env, clazz, "jsUnload", "(Ljava/lang/String;Ljava/lang/String;)Z"); - m_javaGlue->m_jsInterrupt = GetJMethod(env, clazz, "jsInterrupt", "()Z"); - m_javaGlue->m_didFirstLayout = GetJMethod(env, clazz, "didFirstLayout", "(Z)V"); - m_javaGlue->m_updateViewport = GetJMethod(env, clazz, "updateViewport", "()V"); - m_javaGlue->m_sendNotifyProgressFinished = GetJMethod(env, clazz, "sendNotifyProgressFinished", "()V"); - m_javaGlue->m_sendViewInvalidate = GetJMethod(env, clazz, "sendViewInvalidate", "(IIII)V"); - m_javaGlue->m_updateTextfield = GetJMethod(env, clazz, "updateTextfield", "(IZLjava/lang/String;I)V"); - m_javaGlue->m_updateTextSelection = GetJMethod(env, clazz, "updateTextSelection", "(IIII)V"); - m_javaGlue->m_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"); - m_javaGlue->m_geolocationPermissionsShowPrompt = GetJMethod(env, clazz, "geolocationPermissionsShowPrompt", "(Ljava/lang/String;)V"); - m_javaGlue->m_geolocationPermissionsHidePrompt = GetJMethod(env, clazz, "geolocationPermissionsHidePrompt", "()V"); - m_javaGlue->m_getDeviceMotionService = GetJMethod(env, clazz, "getDeviceMotionService", "()Landroid/webkit/DeviceMotionService;"); - m_javaGlue->m_getDeviceOrientationService = GetJMethod(env, clazz, "getDeviceOrientationService", "()Landroid/webkit/DeviceOrientationService;"); - m_javaGlue->m_addMessageToConsole = GetJMethod(env, clazz, "addMessageToConsole", "(Ljava/lang/String;ILjava/lang/String;I)V"); - m_javaGlue->m_formDidBlur = GetJMethod(env, clazz, "formDidBlur", "(I)V"); - m_javaGlue->m_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;I)V"); - m_javaGlue->m_hideFullScreenPlugin = GetJMethod(env, clazz, "hideFullScreenPlugin", "()V"); - m_javaGlue->m_createSurface = GetJMethod(env, clazz, "createSurface", "(Landroid/view/View;)Landroid/webkit/ViewManager$ChildView;"); - m_javaGlue->m_addSurface = GetJMethod(env, clazz, "addSurface", "(Landroid/view/View;IIII)Landroid/webkit/ViewManager$ChildView;"); - m_javaGlue->m_updateSurface = GetJMethod(env, clazz, "updateSurface", "(Landroid/webkit/ViewManager$ChildView;IIII)V"); - 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"); -#endif - m_javaGlue->m_setWebTextViewAutoFillable = GetJMethod(env, clazz, "setWebTextViewAutoFillable", "(ILjava/lang/String;)V"); - m_javaGlue->m_selectAt = GetJMethod(env, clazz, "selectAt", "(II)V"); - env->DeleteLocalRef(clazz); - - env->SetIntField(javaWebViewCore, gWebViewCoreFields.m_nativeClass, (jint)this); - - m_scrollOffsetX = m_scrollOffsetY = 0; - - PageGroup::setShouldTrackVisitedLinks(true); - - reset(true); - - MemoryUsage::setLowMemoryUsageMb(env->GetIntField(javaWebViewCore, gWebViewCoreFields.m_lowMemoryUsageMb)); - MemoryUsage::setHighMemoryUsageMb(env->GetIntField(javaWebViewCore, gWebViewCoreFields.m_highMemoryUsageMb)); - MemoryUsage::setHighUsageDeltaMb(env->GetIntField(javaWebViewCore, gWebViewCoreFields.m_highUsageDeltaMb)); - - WebViewCore::addInstance(this); - -#if USE(CHROME_NETWORK_STACK) - AndroidNetworkLibraryImpl::InitWithApplicationContext(env, 0); -#endif -} - -WebViewCore::~WebViewCore() -{ - WebViewCore::removeInstance(this); - - // Release the focused view - Release(m_popupReply); - - if (m_javaGlue->m_obj) { - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->DeleteWeakGlobalRef(m_javaGlue->m_obj); - m_javaGlue->m_obj = 0; - } - delete m_javaGlue; - delete m_frameCacheKit; - delete m_navPictureKit; -} - -WebViewCore* WebViewCore::getWebViewCore(const WebCore::FrameView* view) -{ - return getWebViewCore(static_cast(view)); -} - -WebViewCore* WebViewCore::getWebViewCore(const WebCore::ScrollView* view) -{ - if (!view) - return 0; - - WebFrameView* webFrameView = static_cast(view->platformWidget()); - if (!webFrameView) - return 0; - return webFrameView->webViewCore(); -} - -void WebViewCore::reset(bool fromConstructor) -{ - DBG_SET_LOG(""); - if (fromConstructor) { - m_frameCacheKit = 0; - m_navPictureKit = 0; - } else { - gFrameCacheMutex.lock(); - delete m_frameCacheKit; - delete m_navPictureKit; - m_frameCacheKit = 0; - m_navPictureKit = 0; - gFrameCacheMutex.unlock(); - } - - m_lastFocused = 0; - m_blurringNodePointer = 0; - m_lastFocusedBounds = WebCore::IntRect(0,0,0,0); - m_focusBoundsChanged = false; - m_lastFocusedSelStart = 0; - m_lastFocusedSelEnd = 0; - clearContent(); - m_updatedFrameCache = true; - m_frameCacheOutOfDate = true; - m_skipContentDraw = false; - m_findIsUp = false; - m_domtree_version = 0; - m_check_domtree_version = true; - m_progressDone = false; - m_hasCursorBounds = false; - - m_scrollOffsetX = 0; - m_scrollOffsetY = 0; - m_screenWidth = 0; - m_screenHeight = 0; - m_groupForVisitedLinks = 0; - m_currentNodeDomNavigationAxis = 0; -} - -static bool layoutIfNeededRecursive(WebCore::Frame* f) -{ - if (!f) - return true; - - WebCore::FrameView* v = f->view(); - if (!v) - return true; - - if (v->needsLayout()) - v->layout(f->tree()->parent()); - - WebCore::Frame* child = f->tree()->firstChild(); - bool success = true; - while (child) { - success &= layoutIfNeededRecursive(child); - child = child->tree()->nextSibling(); - } - - return success && !v->needsLayout(); -} - -CacheBuilder& WebViewCore::cacheBuilder() -{ - return FrameLoaderClientAndroid::get(m_mainFrame)->getCacheBuilder(); -} - -WebCore::Node* WebViewCore::currentFocus() -{ - return cacheBuilder().currentFocus(); -} - -void WebViewCore::recordPicture(SkPicture* picture) -{ - // if there is no document yet, just return - if (!m_mainFrame->document()) { - DBG_NAV_LOG("no document"); - return; - } - // Call layout to ensure that the contentWidth and contentHeight are correct - if (!layoutIfNeededRecursive(m_mainFrame)) { - DBG_NAV_LOG("layout failed"); - return; - } - // draw into the picture's recording canvas - WebCore::FrameView* view = m_mainFrame->view(); - DBG_NAV_LOGD("view=(w=%d,h=%d)", view->contentsWidth(), - view->contentsHeight()); - SkAutoPictureRecord arp(picture, view->contentsWidth(), - view->contentsHeight(), PICT_RECORD_FLAGS); - SkAutoMemoryUsageProbe mup(__FUNCTION__); - - // Copy m_buttons so we can pass it to our graphics context. - gButtonMutex.lock(); - WTF::Vector buttons(m_buttons); - gButtonMutex.unlock(); - - WebCore::PlatformGraphicsContext pgc(arp.getRecordingCanvas(), &buttons); - WebCore::GraphicsContext gc(&pgc); - view->platformWidget()->draw(&gc, WebCore::IntRect(0, 0, - view->contentsWidth(), view->contentsHeight())); - - gButtonMutex.lock(); - updateButtonList(&buttons); - gButtonMutex.unlock(); -} - -void WebViewCore::recordPictureSet(PictureSet* content) -{ - // if there is no document yet, just return - if (!m_mainFrame->document()) { - DBG_SET_LOG("!m_mainFrame->document()"); - return; - } - // If there is a pending style recalculation, just return. - if (m_mainFrame->document()->isPendingStyleRecalc()) { - LOGW("recordPictureSet: pending style recalc, ignoring."); - return; - } - if (m_addInval.isEmpty()) { - DBG_SET_LOG("m_addInval.isEmpty()"); - return; - } - // Call layout to ensure that the contentWidth and contentHeight are correct - // it's fine for layout to gather invalidates, but defeat sending a message - // back to java to call webkitDraw, since we're already in the middle of - // doing that - m_skipContentDraw = true; - bool success = layoutIfNeededRecursive(m_mainFrame); - m_skipContentDraw = false; - - // We may be mid-layout and thus cannot draw. - if (!success) - return; - - { // collect WebViewCoreRecordTimeCounter after layoutIfNeededRecursive -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreRecordTimeCounter); -#endif - - // if the webkit page dimensions changed, discard the pictureset and redraw. - WebCore::FrameView* view = m_mainFrame->view(); - int width = view->contentsWidth(); - int height = view->contentsHeight(); - - // Use the contents width and height as a starting point. - SkIRect contentRect; - contentRect.set(0, 0, width, height); - SkIRect total(contentRect); - - // Traverse all the frames and add their sizes if they are in the visible - // rectangle. - for (WebCore::Frame* frame = m_mainFrame->tree()->traverseNext(); frame; - frame = frame->tree()->traverseNext()) { - // If the frame doesn't have an owner then it is the top frame and the - // view size is the frame size. - WebCore::RenderPart* owner = frame->ownerRenderer(); - if (owner && owner->style()->visibility() == VISIBLE) { - int x = owner->x(); - int y = owner->y(); - - // Traverse the tree up to the parent to find the absolute position - // of this frame. - WebCore::Frame* parent = frame->tree()->parent(); - while (parent) { - WebCore::RenderPart* parentOwner = parent->ownerRenderer(); - if (parentOwner) { - x += parentOwner->x(); - y += parentOwner->y(); - } - parent = parent->tree()->parent(); - } - // Use the owner dimensions so that padding and border are - // included. - int right = x + owner->width(); - int bottom = y + owner->height(); - SkIRect frameRect = {x, y, right, bottom}; - // Ignore a width or height that is smaller than 1. Some iframes - // have small dimensions in order to be hidden. The iframe - // expansion code does not expand in that case so we should ignore - // them here. - if (frameRect.width() > 1 && frameRect.height() > 1 - && SkIRect::Intersects(total, frameRect)) - total.join(x, y, right, bottom); - } - } - - // If the new total is larger than the content, resize the view to include - // all the content. - if (!contentRect.contains(total)) { - // Resize the view to change the overflow clip. - view->resize(total.fRight, total.fBottom); - - // We have to force a layout in order for the clip to change. - m_mainFrame->contentRenderer()->setNeedsLayoutAndPrefWidthsRecalc(); - view->forceLayout(); - - // Relayout similar to above - m_skipContentDraw = true; - bool success = layoutIfNeededRecursive(m_mainFrame); - m_skipContentDraw = false; - if (!success) - return; - - // Set the computed content width - width = view->contentsWidth(); - height = view->contentsHeight(); - } - - if (cacheBuilder().pictureSetDisabled()) - content->clear(); - - content->checkDimensions(width, height, &m_addInval); - - // The inval region may replace existing pictures. The existing pictures - // may have already been split into pieces. If reuseSubdivided() returns - // true, the split pieces are the last entries in the picture already. They - // are marked as invalid, and are rebuilt by rebuildPictureSet(). - - // If the new region doesn't match a set of split pieces, add it to the end. - if (!content->reuseSubdivided(m_addInval)) { - const SkIRect& inval = m_addInval.getBounds(); - SkPicture* picture = rebuildPicture(inval); - DBG_SET_LOGD("{%d,%d,w=%d,h=%d}", inval.fLeft, - inval.fTop, inval.width(), inval.height()); - content->add(m_addInval, picture, 0, false); - SkSafeUnref(picture); - } - // Remove any pictures already in the set that are obscured by the new one, - // and check to see if any already split pieces need to be redrawn. - if (content->build()) - 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(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(); - env->CallVoidMethod(m_javaGlue->object(env).get(), - m_javaGlue->m_sendFindAgain); - checkException(env); - } -} - -void WebViewCore::updateButtonList(WTF::Vector* buttons) -{ - // All the entries in buttons are either updates of previous entries in - // m_buttons or they need to be added to it. - Container* end = buttons->end(); - for (Container* updatedContainer = buttons->begin(); - updatedContainer != end; updatedContainer++) { - bool updated = false; - // Search for a previous entry that references the same node as our new - // data - Container* lastPossibleMatch = m_buttons.end(); - for (Container* possibleMatch = m_buttons.begin(); - possibleMatch != lastPossibleMatch; possibleMatch++) { - if (updatedContainer->matches(possibleMatch->node())) { - // Update our record, and skip to the next one. - possibleMatch->setRect(updatedContainer->rect()); - updated = true; - break; - } - } - if (!updated) { - // This is a brand new button, so append it to m_buttons - m_buttons.append(*updatedContainer); - } - } - size_t i = 0; - // count will decrease each time one is removed, so check count each time. - while (i < m_buttons.size()) { - if (m_buttons[i].canBeRemoved()) { - m_buttons[i] = m_buttons.last(); - m_buttons.removeLast(); - } else { - i++; - } - } -} - -// 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() -{ - DBG_SET_LOG(""); - m_content.clear(); - m_addInval.setEmpty(); - m_rebuildInval.setEmpty(); -} - -bool WebViewCore::focusBoundsChanged() -{ - bool result = m_focusBoundsChanged; - m_focusBoundsChanged = false; - return result; -} - -SkPicture* WebViewCore::rebuildPicture(const SkIRect& inval) -{ - WebCore::FrameView* view = m_mainFrame->view(); - int width = view->contentsWidth(); - int height = view->contentsHeight(); - SkPicture* picture = new SkPicture(); - SkAutoPictureRecord arp(picture, width, height, PICT_RECORD_FLAGS); - SkAutoMemoryUsageProbe mup(__FUNCTION__); - SkCanvas* recordingCanvas = arp.getRecordingCanvas(); - - gButtonMutex.lock(); - WTF::Vector buttons(m_buttons); - gButtonMutex.unlock(); - - WebCore::PlatformGraphicsContext pgc(recordingCanvas, &buttons); - WebCore::GraphicsContext gc(&pgc); - recordingCanvas->translate(-inval.fLeft, -inval.fTop); - recordingCanvas->save(); - view->platformWidget()->draw(&gc, WebCore::IntRect(inval.fLeft, - inval.fTop, inval.width(), inval.height())); - m_rebuildInval.op(inval, SkRegion::kUnion_Op); - DBG_SET_LOGD("m_rebuildInval={%d,%d,r=%d,b=%d}", - m_rebuildInval.getBounds().fLeft, m_rebuildInval.getBounds().fTop, - m_rebuildInval.getBounds().fRight, m_rebuildInval.getBounds().fBottom); - - gButtonMutex.lock(); - updateButtonList(&buttons); - gButtonMutex.unlock(); - - return picture; -} - -void WebViewCore::rebuildPictureSet(PictureSet* pictureSet) -{ - WebCore::FrameView* view = m_mainFrame->view(); - size_t size = pictureSet->size(); - for (size_t index = 0; index < size; index++) { - if (pictureSet->upToDate(index)) - continue; - const SkIRect& inval = pictureSet->bounds(index); - DBG_SET_LOGD("pictSet=%p [%d] {%d,%d,w=%d,h=%d}", pictureSet, index, - inval.fLeft, inval.fTop, inval.width(), inval.height()); - pictureSet->setPicture(index, rebuildPicture(inval)); - } - pictureSet->validate(__FUNCTION__); -} - -BaseLayerAndroid* WebViewCore::createBaseLayer() -{ - BaseLayerAndroid* base = new BaseLayerAndroid(); - base->setContent(m_content); - - bool layoutSucceeded = layoutIfNeededRecursive(m_mainFrame); - // Layout only fails if called during a layout. - LOG_ASSERT(layoutSucceeded, "Can never be called recursively"); - -#if USE(ACCELERATED_COMPOSITING) - // We set the background color - if (m_mainFrame && m_mainFrame->document() - && m_mainFrame->document()->body()) { - Document* document = m_mainFrame->document(); - RefPtr style = document->styleForElementIgnoringPendingStylesheets(document->body()); - if (style->hasBackground()) { - Color color = style->visitedDependentColor(CSSPropertyBackgroundColor); - if (color.isValid() && color.alpha() > 0) - base->setBackgroundColor(color); - } - } - - // We update the layers - ChromeClientAndroid* chromeC = static_cast(m_mainFrame->page()->chrome()->client()); - GraphicsLayerAndroid* root = static_cast(chromeC->layersSync()); - if (root) { - root->notifyClientAnimationStarted(); - LayerAndroid* copyLayer = new LayerAndroid(*root->contentLayer()); - base->addChild(copyLayer); - copyLayer->unref(); - } -#endif - - return base; -} - -BaseLayerAndroid* WebViewCore::recordContent(SkRegion* region, SkIPoint* point) -{ - DBG_SET_LOG("start"); - float progress = (float) m_mainFrame->page()->progress()->estimatedProgress(); - m_progressDone = progress <= 0.0f || progress >= 1.0f; - recordPictureSet(&m_content); - if (!m_progressDone && m_content.isEmpty()) { - DBG_SET_LOGD("empty (progress=%g)", progress); - return 0; - } - region->set(m_addInval); - m_addInval.setEmpty(); - region->op(m_rebuildInval, SkRegion::kUnion_Op); - m_rebuildInval.setEmpty(); - point->fX = m_content.width(); - point->fY = m_content.height(); - DBG_SET_LOGD("region={%d,%d,r=%d,b=%d}", region->getBounds().fLeft, - region->getBounds().fTop, region->getBounds().fRight, - region->getBounds().fBottom); - DBG_SET_LOG("end"); - - return createBaseLayer(); -} - -void WebViewCore::splitContent(PictureSet* content) -{ - bool layoutSucceeded = layoutIfNeededRecursive(m_mainFrame); - LOG_ASSERT(layoutSucceeded, "Can never be called recursively"); - content->split(&m_content); - rebuildPictureSet(&m_content); - content->set(m_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!"); - -// LOGD("WebViewCore::scrollTo(%d %d)\n", x, y); - - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_scrollTo, - x, y, animate, false); - checkException(env); -} - -void WebViewCore::sendNotifyProgressFinished() -{ - LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_sendNotifyProgressFinished); - checkException(env); -} - -void WebViewCore::viewInvalidate(const WebCore::IntRect& rect) -{ - LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), - m_javaGlue->m_sendViewInvalidate, - rect.x(), rect.y(), rect.right(), rect.bottom()); - checkException(env); -} - -void WebViewCore::contentDraw() -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_contentDraw); - checkException(env); -} - -void WebViewCore::layersDraw() -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_layersDraw); - checkException(env); -} - -void WebViewCore::contentInvalidate(const WebCore::IntRect &r) -{ - DBG_SET_LOGD("rect={%d,%d,w=%d,h=%d}", r.x(), r.y(), r.width(), r.height()); - SkIRect rect(r); - if (!rect.intersect(0, 0, INT_MAX, INT_MAX)) - return; - m_addInval.op(rect, SkRegion::kUnion_Op); - DBG_SET_LOGD("m_addInval={%d,%d,r=%d,b=%d}", - m_addInval.getBounds().fLeft, m_addInval.getBounds().fTop, - m_addInval.getBounds().fRight, m_addInval.getBounds().fBottom); - if (!m_skipContentDraw) - contentDraw(); -} - -void WebViewCore::contentInvalidateAll() -{ - WebCore::FrameView* view = m_mainFrame->view(); - contentInvalidate(WebCore::IntRect(0, 0, - view->contentsWidth(), view->contentsHeight())); -} - -void WebViewCore::offInvalidate(const WebCore::IntRect &r) -{ - // FIXME: these invalidates are offscreen, and can be throttled or - // deferred until the area is visible. For now, treat them as - // regular invals so that drawing happens (inefficiently) for now. - 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!"); - - WebCore::FrameLoader* loader = m_mainFrame->loader(); - const WebCore::KURL& url = loader->url(); - if (url.isEmpty()) - return; - LOGV("::WebCore:: didFirstLayout %s", url.string().ascii().data()); - - WebCore::FrameLoadType loadType = loader->loadType(); - - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_didFirstLayout, - loadType == WebCore::FrameLoadTypeStandard - // When redirect with locked history, we would like to reset the - // scale factor. This is important for www.yahoo.com as it is - // redirected to www.yahoo.com/?rs=1 on load. - || loadType == WebCore::FrameLoadTypeRedirectWithLockedBackForwardList); - 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!"); - - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_updateViewport); - checkException(env); -} - -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!"); - - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_restoreScale, scale, textWrapScale); - checkException(env); -} - -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!"); - -#if ENABLE(TOUCH_EVENTS) - if (m_forwardingTouchEvents == need) - return; - - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_needTouchEvents, need); - checkException(env); - - m_forwardingTouchEvents = 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(); - env->CallVoidMethod(m_javaGlue->object(env).get(), - m_javaGlue->m_requestKeyboardWithSelection, - reinterpret_cast(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!"); - - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), - m_javaGlue->m_requestKeyboard, showKeyboard); - checkException(env); -} - -void WebViewCore::notifyProgressFinished() -{ - m_check_domtree_version = true; - sendNotifyProgressFinished(); -} - -void WebViewCore::doMaxScroll(CacheBuilder::Direction dir) -{ - int dx = 0, dy = 0; - - switch (dir) { - case CacheBuilder::LEFT: - dx = -m_maxXScroll; - break; - case CacheBuilder::UP: - dy = -m_maxYScroll; - break; - case CacheBuilder::RIGHT: - dx = m_maxXScroll; - break; - case CacheBuilder::DOWN: - dy = m_maxYScroll; - break; - case CacheBuilder::UNINITIALIZED: - default: - LOG_ASSERT(0, "unexpected focus selector"); - } - WebCore::FrameView* view = m_mainFrame->view(); - this->scrollTo(view->scrollX() + dx, view->scrollY() + dy, true); -} - -void WebViewCore::setScrollOffset(int moveGeneration, bool sendScrollEvent, int dx, int dy) -{ - 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; - // The visible rect is located within our coordinate space so it - // contains the actual scroll position. Setting the location makes hit - // testing work correctly. - m_mainFrame->view()->platformWidget()->setLocation(m_scrollOffsetX, - m_scrollOffsetY); - if (sendScrollEvent) { - m_mainFrame->eventHandler()->sendScrollEvent(); - - // Only update history position if it's user scrolled. - // Update history item to reflect the new scroll position. - // This also helps save the history information when the browser goes to - // background, so scroll position will be restored if browser gets - // killed while in background. - WebCore::HistoryController* history = m_mainFrame->loader()->history(); - // Because the history item saving could be heavy for large sites and - // scrolling can generate lots of small scroll offset, the following code - // reduces the saving frequency. - static const int MIN_SCROLL_DIFF = 32; - if (history->currentItem()) { - WebCore::IntPoint currentPoint = history->currentItem()->scrollPoint(); - if (std::abs(currentPoint.x() - dx) >= MIN_SCROLL_DIFF || - std::abs(currentPoint.y() - dy) >= MIN_SCROLL_DIFF) { - history->saveScrollPositionAndViewStateToItem(history->currentItem()); - } - } - } - - // 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); -} - -void WebViewCore::setSizeScreenWidthAndScale(int width, int height, - int textWrapWidth, float scale, int screenWidth, int screenHeight, - int anchorX, int anchorY, bool ignoreHeight) -{ - WebCoreViewBridge* window = m_mainFrame->view()->platformWidget(); - int ow = window->width(); - int oh = window->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; - if (scale >= 0) // negative means keep the current scale - m_scale = scale; - m_maxXScroll = screenWidth >> 2; - m_maxYScroll = m_maxXScroll * height / width; - // Don't reflow if the diff is small. - const bool reflow = otw && textWrapWidth && - ((float) abs(otw - textWrapWidth) / textWrapWidth) >= 0.01f; - - // When the screen size change, fixed positioned element should be updated. - // This is supposed to be light weighted operation without a full layout. - if (osh != screenHeight || osw != screenWidth) - m_mainFrame->view()->updatePositionedObjects(); - - 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 node; - WebCore::IntRect bounds; - WebCore::IntPoint offset; - // If the text wrap changed, it is probably zoom change or - // orientation change. Try to keep the anchor at the same place. - if (otw && textWrapWidth && otw != textWrapWidth && - (anchorX != 0 || anchorY != 0)) { - WebCore::HitTestResult hitTestResult = - m_mainFrame->eventHandler()->hitTestResultAtPoint( - anchorPoint, false); - node = hitTestResult.innerNode(); - } - if (node) { - bounds = node->getRect(); - DBG_NAV_LOGD("ob:(x=%d,y=%d,w=%d,h=%d)", - bounds.x(), bounds.y(), bounds.width(), bounds.height()); - // sites like nytimes.com insert a non-standard tag - // in the html. If it is the HitTestResult, it may have zero - // width and height. In this case, use its parent node. - if (bounds.width() == 0) { - 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()); - } - } - } - - // Set the size after finding the old anchor point as - // hitTestResultAtPoint causes a layout. - window->setSize(width, height); - window->setVisibleSize(screenWidth, screenHeight); - if (width != screenWidth) { - m_mainFrame->view()->setUseFixedLayout(true); - m_mainFrame->view()->setFixedLayoutSize(IntSize(width, height)); - } else { - m_mainFrame->view()->setUseFixedLayout(false); - } - r->setNeedsLayoutAndPrefWidthsRecalc(); - m_mainFrame->view()->forceLayout(); - - // 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(); - // force left align if width is not changed while height changed. - // the anchorPoint is probably at some white space in the node - // which is affected by text wrap around the screen width. - const bool leftAlign = (otw != textWrapWidth) - && (bounds.width() == newBounds.width()) - && (bounds.height() != newBounds.height()); - const float xPercentInDoc = - leftAlign ? 0.0 : (float) (anchorX - bounds.x()) / bounds.width(); - const float xPercentInView = - leftAlign ? 0.0 : (float) (anchorX - m_scrollOffsetX) / osw; - const float yPercentInDoc = (float) (anchorY - bounds.y()) / bounds.height(); - const float yPercentInView = (float) (anchorY - m_scrollOffsetY) / osh; - showRect(newBounds.x(), newBounds.y(), newBounds.width(), - newBounds.height(), view->contentsWidth(), - view->contentsHeight(), - xPercentInDoc, xPercentInView, - yPercentInDoc, yPercentInView); - } - } - } - } else { - window->setSize(width, height); - window->setVisibleSize(screenWidth, screenHeight); - m_mainFrame->view()->resize(width, height); - if (width != screenWidth) { - m_mainFrame->view()->setUseFixedLayout(true); - m_mainFrame->view()->setFixedLayoutSize(IntSize(width, height)); - } else { - m_mainFrame->view()->setUseFixedLayout(false); - } - } - - // update the currently visible screen as perceived by the plugin - sendPluginVisibleScreen(); -} - -void WebViewCore::dumpDomTree(bool useFile) -{ -#ifdef ANDROID_DOM_LOGGING - if (useFile) - gDomTreeFile = fopen(DOM_TREE_LOG_FILE, "w"); - m_mainFrame->document()->showTreeForThis(); - if (gDomTreeFile) { - fclose(gDomTreeFile); - gDomTreeFile = 0; - } -#endif -} - -void WebViewCore::dumpRenderTree(bool useFile) -{ -#ifdef ANDROID_DOM_LOGGING - WTF::CString renderDump = WebCore::externalRepresentation(m_mainFrame).utf8(); - const char* data = renderDump.data(); - if (useFile) { - gRenderTreeFile = fopen(RENDER_TREE_LOG_FILE, "w"); - DUMP_RENDER_LOGD("%s", data); - fclose(gRenderTreeFile); - gRenderTreeFile = 0; - } else { - // adb log can only output 1024 characters, so write out line by line. - // exclude '\n' as adb log adds it for each output. - int length = renderDump.length(); - for (int i = 0, last = 0; i < length; i++) { - if (data[i] == '\n') { - if (i != last) - DUMP_RENDER_LOGD("%.*s", (i - last), &(data[last])); - last = i + 1; - } - } - } -#endif -} - -void WebViewCore::dumpNavTree() -{ -#if DUMP_NAV_CACHE - cacheBuilder().mDebug.print(); -#endif -} - -HTMLElement* WebViewCore::retrieveElement(int x, int y, - const QualifiedName& tagName) -{ - HitTestResult hitTestResult = m_mainFrame->eventHandler() - ->hitTestResultAtPoint(IntPoint(x, y), false, false, - DontHitTestScrollbars, HitTestRequest::Active | HitTestRequest::ReadOnly, - IntSize(1, 1)); - if (!hitTestResult.innerNode() || !hitTestResult.innerNode()->inDocument()) { - LOGE("Should not happen: no in document Node found"); - return 0; - } - const ListHashSet >& list = hitTestResult.rectBasedTestResult(); - if (list.isEmpty()) { - LOGE("Should not happen: no rect-based-test nodes found"); - return 0; - } - Node* node = hitTestResult.innerNode(); - Node* element = node; - while (element && (!element->isElementNode() - || !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() : ""); - return static_cast(element); -} - -HTMLAnchorElement* WebViewCore::retrieveAnchorElement(int x, int y) -{ - return static_cast - (retrieveElement(x, y, HTMLNames::aTag)); -} - -HTMLImageElement* WebViewCore::retrieveImageElement(int x, int y) -{ - return static_cast - (retrieveElement(x, y, HTMLNames::imgTag)); -} - -WTF::String WebViewCore::retrieveHref(int x, int y) -{ - WebCore::HTMLAnchorElement* anchor = retrieveAnchorElement(x, y); - return anchor ? anchor->href() : WTF::String(); -} - -WTF::String WebViewCore::retrieveAnchorText(int x, int y) -{ - WebCore::HTMLAnchorElement* anchor = retrieveAnchorElement(x, y); - return anchor ? anchor->text() : WTF::String(); -} - -WTF::String WebViewCore::retrieveImageSource(int x, int y) -{ - HTMLImageElement* image = retrieveImageElement(x, y); - return image ? image->src().string() : WTF::String(); -} - -WTF::String WebViewCore::requestLabel(WebCore::Frame* frame, - WebCore::Node* node) -{ - if (node && CacheBuilder::validNode(m_mainFrame, frame, node)) { - RefPtr list = node->document()->getElementsByTagName("label"); - unsigned length = list->length(); - for (unsigned i = 0; i < length; i++) { - WebCore::HTMLLabelElement* label = static_cast( - list->item(i)); - if (label->control() == node) { - Node* node = label; - String result; - while ((node = node->traverseNextNode(label))) { - if (node->isTextNode()) { - Text* textNode = static_cast(node); - result += textNode->dataImpl(); - } - } - return result; - } - } - } - return WTF::String(); -} - -static bool isContentEditable(const WebCore::Node* node) -{ - if (!node) return false; - return node->document()->frame()->selection()->isContentEditable(); -} - -// Returns true if the node is a textfield, textarea, or contentEditable -static bool isTextInput(const WebCore::Node* node) -{ - if (isContentEditable(node)) - return true; - if (!node) - return false; - WebCore::RenderObject* renderer = node->renderer(); - return renderer && (renderer->isTextField() || renderer->isTextArea()); -} - -void WebViewCore::revealSelection() -{ - WebCore::Node* focus = currentFocus(); - if (!focus) - return; - if (!isTextInput(focus)) - return; - WebCore::Frame* focusedFrame = focus->document()->frame(); - if (!focusedFrame->page()->focusController()->isActive()) - return; - 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; -#if DEBUG_NAV_UI - m_now = SkTime::GetMSecs(); -#endif - 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; - IntRect mBounds; -}; - -// get the bounding box of the Node -static IntRect getAbsoluteBoundingBox(Node* node) { - IntRect rect; - RenderObject* render = node->renderer(); - if (render->isRenderInline()) - rect = toRenderInline(render)->linesVisualOverflowBoundingBox(); - else if (render->isBox()) - rect = toRenderBox(render)->visualOverflowRect(); - else if (render->isText()) - rect = toRenderText(render)->linesBoundingBox(); - else - LOGE("getAbsoluteBoundingBox failed for node %p, name %s", node, render->renderName()); - FloatPoint absPos = render->localToAbsolute(); - rect.move(absPos.x(), absPos.y()); - return rect; -} - -// get the highlight rectangles for the touch point (x, y) with the slop -Vector WebViewCore::getTouchHighlightRects(int x, int y, int slop) -{ - Vector rects; - m_mousePos = IntPoint(x - m_scrollOffsetX, y - m_scrollOffsetY); - HitTestResult hitTestResult = m_mainFrame->eventHandler()->hitTestResultAtPoint(IntPoint(x, y), - false, false, DontHitTestScrollbars, HitTestRequest::Active | HitTestRequest::ReadOnly, IntSize(slop, slop)); - if (!hitTestResult.innerNode() || !hitTestResult.innerNode()->inDocument()) { - LOGE("Should not happen: no in document Node found"); - return rects; - } - const ListHashSet >& list = hitTestResult.rectBasedTestResult(); - if (list.isEmpty()) { - LOGE("Should not happen: no rect-based-test nodes found"); - return rects; - } - Frame* frame = hitTestResult.innerNode()->document()->frame(); - Vector nodeDataList; - ListHashSet >::const_iterator last = list.end(); - for (ListHashSet >::const_iterator it = list.begin(); it != last; ++it) { - // TODO: it seems reasonable to not search across the frame. Isn't it? - // if the node is not in the same frame as the innerNode, skip it - if (it->get()->document()->frame() != frame) - continue; - // traverse up the tree to find the first node that needs highlight - bool found = false; - Node* eventNode = it->get(); - while (eventNode) { - RenderObject* render = eventNode->renderer(); - if (render->isBody() || render->isRenderView()) - break; - if (eventNode->supportsFocus() - || eventNode->hasEventListeners(eventNames().clickEvent) - || eventNode->hasEventListeners(eventNames().mousedownEvent) - || eventNode->hasEventListeners(eventNames().mouseupEvent)) { - found = true; - break; - } - // the nodes in the rectBasedTestResult() are ordered based on z-index during hit testing. - // so do not search for the eventNode across explicit z-index border. - // TODO: this is a hard one to call. z-index is quite complicated as its value only - // matters when you compare two RenderLayer in the same hierarchy level. e.g. in - // the following example, "b" is on the top as its z level is the highest. even "c" - // has 100 as z-index, it is still below "d" as its parent has the same z-index as - // "d" and logically before "d". Of course "a" is the lowest in the z level. - // - // z-index:auto "a" - // z-index:2 "b" - // z-index:1 - // z-index:100 "c" - // z-index:1 "d" - // - // If the fat point touches everyone, the order in the list should be "b", "d", "c" - // and "a". When we search for the event node for "b", we really don't want "a" as - // in the z-order it is behind everything else. - if (!render->style()->hasAutoZIndex()) - break; - eventNode = eventNode->parentNode(); - } - // didn't find any eventNode, skip it - if (!found) - continue; - // first quick check whether it is a duplicated node before computing bounding box - Vector::const_iterator nlast = nodeDataList.end(); - for (Vector::const_iterator n = nodeDataList.begin(); n != nlast; ++n) { - // found the same node, skip it - if (eventNode == n->mNode) { - found = false; - break; - } - } - if (!found) - continue; - // next check whether the node is fully covered by or fully covering another node. - found = false; - IntRect rect = getAbsoluteBoundingBox(eventNode); - if (rect.isEmpty()) { - // if the node's bounds is empty and it is not a ContainerNode, skip it. - if (!eventNode->isContainerNode()) - continue; - // if the node's children are all positioned objects, its bounds can be empty. - // Walk through the children to find the bounding box. - Node* child = static_cast(eventNode)->firstChild(); - while (child) { - IntRect childrect; - if (child->renderer()) - childrect = getAbsoluteBoundingBox(child); - if (!childrect.isEmpty()) { - rect.unite(childrect); - child = child->traverseNextSibling(eventNode); - } else - child = child->traverseNextNode(eventNode); - } - } - for (int i = nodeDataList.size() - 1; i >= 0; i--) { - TouchNodeData n = nodeDataList.at(i); - // the new node is enclosing an existing node, skip it - if (rect.contains(n.mBounds)) { - found = true; - break; - } - // the new node is fully inside an existing node, remove the existing node - if (n.mBounds.contains(rect)) - nodeDataList.remove(i); - } - if (!found) { - TouchNodeData newNode; - newNode.mNode = eventNode; - newNode.mBounds = rect; - nodeDataList.append(newNode); - } - } - if (!nodeDataList.size()) - return rects; - // finally select the node with the largest overlap with the fat point - TouchNodeData final; - final.mNode = 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; - Vector::const_iterator nlast = nodeDataList.end(); - for (Vector::const_iterator n = nodeDataList.begin(); n != nlast; ++n) { - IntRect rect = n->mBounds; - rect.intersect(testRect); - int a = rect.width() * rect.height(); - if (a > area) { - final = *n; - area = a; - } - } - // now get the node's highlight rectangles in the page coordinate system - if (final.mNode) { - IntPoint frameAdjust; - if (frame != m_mainFrame) { - frameAdjust = frame->view()->contentsToWindow(IntPoint()); - frameAdjust.move(m_scrollOffsetX, m_scrollOffsetY); - } - if (final.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].right()) { - 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].bottom()) { - if (y - rects[i].bottom() + 1 < distance) { - newx = x; - newy = rects[i].bottom() - 1; - distance = y - rects[i].bottom() + 1; - } - } - } else if (y >= rects[i].y() && y < rects[i].bottom()) { - 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].right()) { - if (x - rects[i].right() + 1 < distance) { - newx = rects[i].right() - 1; - newy = y; - distance = x - rects[i].right() + 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); - } - } - return rects; -} - -/////////////////////////////////////////////////////////////////////////////// - -void WebViewCore::addPlugin(PluginWidgetAndroid* w) -{ -// SkDebugf("----------- addPlugin %p", w); - /* The plugin must be appended to the end of the array. This ensures that if - the plugin is added while iterating through the array (e.g. sendEvent(...)) - that the iteration process is not corrupted. - */ - *m_plugins.append() = w; -} - -void WebViewCore::removePlugin(PluginWidgetAndroid* w) -{ -// SkDebugf("----------- removePlugin %p", w); - int index = m_plugins.find(w); - if (index < 0) { - SkDebugf("--------------- pluginwindow not found! %p\n", w); - } else { - m_plugins.removeShuffle(index); - } -} - -bool WebViewCore::isPlugin(PluginWidgetAndroid* w) const -{ - return m_plugins.find(w) >= 0; -} - -void WebViewCore::invalPlugin(PluginWidgetAndroid* w) -{ - const double PLUGIN_INVAL_DELAY = 1.0 / 60; - - if (!m_pluginInvalTimer.isActive()) { - m_pluginInvalTimer.startOneShot(PLUGIN_INVAL_DELAY); - } -} - -void WebViewCore::drawPlugins() -{ - SkRegion inval; // accumualte what needs to be redrawn - PluginWidgetAndroid** iter = m_plugins.begin(); - PluginWidgetAndroid** stop = m_plugins.end(); - - for (; iter < stop; ++iter) { - PluginWidgetAndroid* w = *iter; - SkIRect dirty; - if (w->isDirty(&dirty)) { - w->draw(); - inval.op(dirty, SkRegion::kUnion_Op); - } - } - - if (!inval.isEmpty()) { - // inval.getBounds() is our rectangle - const SkIRect& bounds = inval.getBounds(); - WebCore::IntRect r(bounds.fLeft, bounds.fTop, - bounds.width(), bounds.height()); - this->viewInvalidate(r); - } -} - -void WebViewCore::notifyPluginsOnFrameLoad(const Frame* frame) { - // if frame is the parent then notify all plugins - if (!frame->tree()->parent()) { - // trigger an event notifying the plugins that the page has loaded - ANPEvent event; - SkANP::InitEvent(&event, kLifecycle_ANPEventType); - event.data.lifecycle.action = kOnLoad_ANPLifecycleAction; - sendPluginEvent(event); - // trigger the on/off screen notification if the page was reloaded - sendPluginVisibleScreen(); - } - // else if frame's parent has completed - else if (!frame->tree()->parent()->loader()->isLoading()) { - // send to all plugins who have this frame in their heirarchy - PluginWidgetAndroid** iter = m_plugins.begin(); - PluginWidgetAndroid** stop = m_plugins.end(); - for (; iter < stop; ++iter) { - Frame* currentFrame = (*iter)->pluginView()->parentFrame(); - while (currentFrame) { - if (frame == currentFrame) { - ANPEvent event; - SkANP::InitEvent(&event, kLifecycle_ANPEventType); - event.data.lifecycle.action = kOnLoad_ANPLifecycleAction; - (*iter)->sendEvent(event); - - // trigger the on/off screen notification if the page was reloaded - ANPRectI visibleRect; - getVisibleScreen(visibleRect); - (*iter)->setVisibleScreen(visibleRect, m_scale); - - break; - } - currentFrame = currentFrame->tree()->parent(); - } - } - } -} - -void WebViewCore::getVisibleScreen(ANPRectI& visibleRect) -{ - visibleRect.left = m_scrollOffsetX; - visibleRect.top = m_scrollOffsetY; - visibleRect.right = m_scrollOffsetX + m_screenWidth; - visibleRect.bottom = m_scrollOffsetY + m_screenHeight; -} - -void WebViewCore::sendPluginVisibleScreen() -{ - /* We may want to cache the previous values and only send the notification - to the plugin in the event that one of the values has changed. - */ - - ANPRectI visibleRect; - getVisibleScreen(visibleRect); - - PluginWidgetAndroid** iter = m_plugins.begin(); - PluginWidgetAndroid** stop = m_plugins.end(); - for (; iter < stop; ++iter) { - (*iter)->setVisibleScreen(visibleRect, m_scale); - } -} - -void WebViewCore::sendPluginEvent(const ANPEvent& evt) -{ - /* The list of plugins may be manipulated as we iterate through the list. - This implementation allows for the addition of new plugins during an - iteration, but may fail if a plugin is removed. Currently, there are not - any use cases where a plugin is deleted while processing this loop, but - if it does occur we will have to use an alternate data structure and/or - iteration mechanism. - */ - for (int x = 0; x < m_plugins.count(); x++) { - m_plugins[x]->sendEvent(evt); - } -} - -PluginWidgetAndroid* WebViewCore::getPluginWidget(NPP npp) -{ - PluginWidgetAndroid** iter = m_plugins.begin(); - PluginWidgetAndroid** stop = m_plugins.end(); - for (; iter < stop; ++iter) { - if ((*iter)->pluginView()->instance() == npp) { - return (*iter); - } - } - return 0; -} - -static PluginView* nodeIsPlugin(Node* node) { - RenderObject* renderer = node->renderer(); - if (renderer && renderer->isWidget()) { - Widget* widget = static_cast(renderer)->widget(); - if (widget && widget->isPluginView()) - return static_cast(widget); - } - return 0; -} - -Node* WebViewCore::cursorNodeIsPlugin() { - gCursorBoundsMutex.lock(); - bool hasCursorBounds = m_hasCursorBounds; - Frame* frame = (Frame*) m_cursorFrame; - Node* node = (Node*) m_cursorNode; - gCursorBoundsMutex.unlock(); - if (hasCursorBounds && CacheBuilder::validNode(m_mainFrame, frame, node) - && nodeIsPlugin(node)) { - return node; - } - return 0; -} - -/////////////////////////////////////////////////////////////////////////////// -void WebViewCore::moveMouseIfLatest(int moveGeneration, - WebCore::Frame* frame, int x, int y) -{ - DBG_NAV_LOGD("m_moveGeneration=%d moveGeneration=%d" - " frame=%p x=%d y=%d", - m_moveGeneration, moveGeneration, frame, x, y); - if (m_moveGeneration > moveGeneration) { - DBG_NAV_LOGD("m_moveGeneration=%d > moveGeneration=%d", - m_moveGeneration, moveGeneration); - return; // short-circuit if a newer move has already been generated - } - m_lastGeneration = moveGeneration; - moveMouse(frame, x, y); -} - -void WebViewCore::moveFocus(WebCore::Frame* frame, WebCore::Node* node) -{ - DBG_NAV_LOGD("frame=%p node=%p", frame, node); - if (!node || !CacheBuilder::validNode(m_mainFrame, frame, node) - || !node->isElementNode()) - return; - // Code borrowed from FocusController::advanceFocus - WebCore::FocusController* focusController - = m_mainFrame->page()->focusController(); - WebCore::Document* oldDoc - = focusController->focusedOrMainFrame()->document(); - if (oldDoc->focusedNode() == node) - return; - if (node->document() != oldDoc) - oldDoc->setFocusedNode(0); - focusController->setFocusedFrame(frame); - static_cast(node)->focus(false); -} - -// Update mouse position -void WebViewCore::moveMouse(WebCore::Frame* frame, int x, int y) -{ - DBG_NAV_LOGD("frame=%p x=%d y=%d scrollOffset=(%d,%d)", frame, - x, y, m_scrollOffsetX, m_scrollOffsetY); - if (!frame || !CacheBuilder::validNode(m_mainFrame, frame, 0)) - frame = m_mainFrame; - // mouse event expects the position in the window coordinate - m_mousePos = WebCore::IntPoint(x - m_scrollOffsetX, y - m_scrollOffsetY); - // validNode will still return true if the node is null, as long as we have - // a valid frame. Do not want to make a call on frame unless it is valid. - WebCore::PlatformMouseEvent mouseEvent(m_mousePos, m_mousePos, - WebCore::NoButton, WebCore::MouseEventMoved, 1, false, false, false, - false, WTF::currentTime()); - frame->eventHandler()->handleMouseMoveEvent(mouseEvent); - updateCacheOnNodeChange(); -} - -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; - } - // 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( - m_mainFrame->editor()->client()); - client->setUiGeneratedSelectionChange(true); - setSelectionRange(focus, start, end); - client->setUiGeneratedSelectionChange(false); - WebCore::Frame* focusedFrame = focus->document()->frame(); - bool isPasswordField = false; - if (focus->isElementNode()) { - WebCore::Element* element = static_cast(focus); - if (WebCore::InputElement* inputElement = WebCore::toInputElement(element)) - isPasswordField = static_cast(inputElement)->isPasswordField(); - } - // For password fields, this is done in the UI side via - // bringPointIntoView, since the UI does the drawing. - if (renderer->isTextArea() || !isPasswordField) - revealSelection(); -} - -String WebViewCore::modifySelection(const int direction, const int axis) -{ - DOMSelection* selection = m_mainFrame->domWindow()->getSelection(); - if (selection->rangeCount() > 1) - selection->removeAllRanges(); - switch (axis) { - case AXIS_CHARACTER: - case AXIS_WORD: - case AXIS_SENTENCE: - return modifySelectionTextNavigationAxis(selection, direction, axis); - case AXIS_HEADING: - case AXIS_SIBLING: - case AXIS_PARENT_FIRST_CHILD: - case AXIS_DOCUMENT: - return modifySelectionDomNavigationAxis(selection, direction, axis); - default: - LOGE("Invalid navigation axis: %d", axis); - return String(); - } -} - -void WebViewCore::scrollNodeIntoView(Frame* frame, Node* node) -{ - if (!frame || !node) - return; - - Element* elementNode = 0; - - // If not an Element, find a visible predecessor - // Element to scroll into view. - if (!node->isElementNode()) { - HTMLElement* body = frame->document()->body(); - do { - if (!node || node == body) - return; - node = node->parentNode(); - } while (!node->isElementNode() && !isVisible(node)); - } - - elementNode = static_cast(node); - elementNode->scrollIntoViewIfNeeded(true); -} - -String WebViewCore::modifySelectionTextNavigationAxis(DOMSelection* selection, int direction, int axis) -{ - Node* body = m_mainFrame->document()->body(); - - ExceptionCode ec = 0; - String markup; - - // initialize the selection if necessary - if (selection->rangeCount() == 0) { - if (m_currentNodeDomNavigationAxis - && CacheBuilder::validNode(m_mainFrame, - m_mainFrame, m_currentNodeDomNavigationAxis)) { - PassRefPtr rangeRef = - selection->frame()->document()->createRange(); - rangeRef->selectNode(m_currentNodeDomNavigationAxis, ec); - m_currentNodeDomNavigationAxis = 0; - if (ec) - return String(); - 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 rangeRef = - selection->frame()->document()->createRange(); - rangeRef->selectNode(reinterpret_cast(m_cursorNode), ec); - if (ec) - return String(); - selection->addRange(rangeRef.get()); - } else { - selection->setPosition(body, 0, ec); - } - if (ec) - return String(); - } - - // collapse the selection - if (direction == DIRECTION_FORWARD) - selection->collapseToEnd(ec); - else - selection->collapseToStart(ec); - if (ec) - return String(); - - // Make sure the anchor node is a text node since we are generating - // the markup of the selection which includes the anchor, the focus, - // and any crossed nodes. Forcing the condition that the selection - // starts and ends on text nodes guarantees symmetric selection markup. - // Also this way the text content, rather its container, is highlighted. - Node* anchorNode = selection->anchorNode(); - if (anchorNode->isElementNode()) { - // Collapsed selection while moving forward points to the - // next unvisited node and while moving backward to the - // last visited node. - if (direction == DIRECTION_FORWARD) - advanceAnchorNode(selection, direction, markup, false, ec); - else - advanceAnchorNode(selection, direction, markup, true, ec); - if (ec) - return String(); - if (!markup.isEmpty()) - return markup; - } - - // If the selection is at the end of a non white space text move - // it to the next visible text node with non white space content. - // This is a workaround for the selection getting stuck. - anchorNode = selection->anchorNode(); - if (anchorNode->isTextNode()) { - if (direction == DIRECTION_FORWARD) { - String suffix = anchorNode->textContent().substring( - selection->anchorOffset(), caretMaxOffset(anchorNode)); - // If at the end of non white space text we advance the - // anchor node to either an input element or non empty text. - if (suffix.stripWhiteSpace().isEmpty()) { - advanceAnchorNode(selection, direction, markup, true, ec); - } - } else { - String prefix = anchorNode->textContent().substring(0, - selection->anchorOffset()); - // If at the end of non white space text we advance the - // anchor node to either an input element or non empty text. - if (prefix.stripWhiteSpace().isEmpty()) { - advanceAnchorNode(selection, direction, markup, true, ec); - } - } - if (ec) - return String(); - if (!markup.isEmpty()) - return markup; - } - - // extend the selection - String directionStr; - if (direction == DIRECTION_FORWARD) - directionStr = "forward"; - else - directionStr = "backward"; - - String axisStr; - if (axis == AXIS_CHARACTER) - axisStr = "character"; - else if (axis == AXIS_WORD) - axisStr = "word"; - else - axisStr = "sentence"; - - selection->modify("extend", directionStr, axisStr); - - // Make sure the focus node is a text node in order to have the - // selection generate symmetric markup because the latter - // includes all nodes crossed by the selection. Also this way - // the text content, rather its container, is highlighted. - Node* focusNode = selection->focusNode(); - if (focusNode->isElementNode()) { - focusNode = getImplicitBoundaryNode(selection->focusNode(), - selection->focusOffset(), direction); - if (!focusNode) - return String(); - if (direction == DIRECTION_FORWARD) { - focusNode = focusNode->traversePreviousSiblingPostOrder(body); - if (focusNode && !isContentTextNode(focusNode)) { - Node* textNode = traverseNextContentTextNode(focusNode, - anchorNode, DIRECTION_BACKWARD); - if (textNode) - anchorNode = textNode; - } - if (focusNode && isContentTextNode(focusNode)) { - selection->extend(focusNode, caretMaxOffset(focusNode), ec); - if (ec) - return String(); - } - } else { - focusNode = focusNode->traverseNextSibling(); - if (focusNode && !isContentTextNode(focusNode)) { - Node* textNode = traverseNextContentTextNode(focusNode, - anchorNode, DIRECTION_FORWARD); - if (textNode) - anchorNode = textNode; - } - if (anchorNode && isContentTextNode(anchorNode)) { - selection->extend(focusNode, 0, ec); - if (ec) - return String(); - } - } - } - - // Enforce that the selection does not cross anchor boundaries. This is - // a workaround for the asymmetric behavior of WebKit while crossing - // anchors. - anchorNode = getImplicitBoundaryNode(selection->anchorNode(), - selection->anchorOffset(), direction); - focusNode = getImplicitBoundaryNode(selection->focusNode(), - selection->focusOffset(), direction); - if (anchorNode && focusNode && anchorNode != focusNode) { - Node* inputControl = getIntermediaryInputElement(anchorNode, focusNode, - direction); - if (inputControl) { - if (direction == DIRECTION_FORWARD) { - if (isDescendantOf(inputControl, anchorNode)) { - focusNode = inputControl; - } else { - focusNode = inputControl->traversePreviousSiblingPostOrder( - body); - if (!focusNode) - focusNode = inputControl; - } - // We prefer a text node contained in the input element. - if (!isContentTextNode(focusNode)) { - Node* textNode = traverseNextContentTextNode(focusNode, - anchorNode, DIRECTION_BACKWARD); - if (textNode) - focusNode = textNode; - } - // If we found text in the input select it. - // Otherwise, select the input element itself. - if (isContentTextNode(focusNode)) { - selection->extend(focusNode, caretMaxOffset(focusNode), ec); - } else if (anchorNode != focusNode) { - // Note that the focusNode always has parent and that - // the offset can be one more that the index of the last - // element - this is how WebKit selects such elements. - selection->extend(focusNode->parentNode(), - focusNode->nodeIndex() + 1, ec); - } - if (ec) - return String(); - } else { - if (isDescendantOf(inputControl, anchorNode)) { - focusNode = inputControl; - } else { - focusNode = inputControl->traverseNextSibling(); - if (!focusNode) - focusNode = inputControl; - } - // We prefer a text node contained in the input element. - if (!isContentTextNode(focusNode)) { - Node* textNode = traverseNextContentTextNode(focusNode, - anchorNode, DIRECTION_FORWARD); - if (textNode) - focusNode = textNode; - } - // If we found text in the input select it. - // Otherwise, select the input element itself. - if (isContentTextNode(focusNode)) { - selection->extend(focusNode, caretMinOffset(focusNode), ec); - } else if (anchorNode != focusNode) { - // Note that the focusNode always has parent and that - // the offset can be one more that the index of the last - // element - this is how WebKit selects such elements. - selection->extend(focusNode->parentNode(), - focusNode->nodeIndex() + 1, ec); - } - if (ec) - return String(); - } - } - } - - // make sure the selection is visible - if (direction == DIRECTION_FORWARD) - scrollNodeIntoView(m_mainFrame, selection->focusNode()); - else - scrollNodeIntoView(m_mainFrame, selection->anchorNode()); - - // format markup for the visible content - PassRefPtr 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()); - - return markup; -} - -Node* WebViewCore::getImplicitBoundaryNode(Node* node, unsigned offset, int direction) -{ - if (node->offsetInCharacters()) - return node; - if (!node->hasChildNodes()) - return node; - if (offset < node->childNodeCount()) - return node->childNode(offset); - else - if (direction == DIRECTION_FORWARD) - return node->traverseNextSibling(); - else - return node->traversePreviousNodePostOrder( - node->document()->body()); -} - -Node* WebViewCore::getNextAnchorNode(Node* anchorNode, bool ignoreFirstNode, int direction) -{ - Node* body = 0; - Node* currentNode = 0; - if (direction == DIRECTION_FORWARD) { - if (ignoreFirstNode) - currentNode = anchorNode->traverseNextNode(body); - else - currentNode = anchorNode; - } else { - body = anchorNode->document()->body(); - if (ignoreFirstNode) - currentNode = anchorNode->traversePreviousSiblingPostOrder(body); - else - currentNode = anchorNode; - } - while (currentNode) { - if (isContentTextNode(currentNode) - || isContentInputElement(currentNode)) - return currentNode; - if (direction == DIRECTION_FORWARD) - currentNode = currentNode->traverseNextNode(); - else - currentNode = currentNode->traversePreviousNodePostOrder(body); - } - return 0; -} - -void WebViewCore::advanceAnchorNode(DOMSelection* selection, int direction, - String& markup, bool ignoreFirstNode, ExceptionCode& ec) -{ - Node* anchorNode = getImplicitBoundaryNode(selection->anchorNode(), - selection->anchorOffset(), direction); - if (!anchorNode) { - ec = NOT_FOUND_ERR; - return; - } - // If the anchor offset is invalid i.e. the anchor node has no - // child with that index getImplicitAnchorNode returns the next - // logical node in the current direction. In such a case our - // position in the DOM tree was has already been advanced, - // therefore we there is no need to do that again. - if (selection->anchorNode()->isElementNode()) { - unsigned anchorOffset = selection->anchorOffset(); - unsigned childNodeCount = selection->anchorNode()->childNodeCount(); - if (anchorOffset >= childNodeCount) - ignoreFirstNode = false; - } - // Find the next anchor node given our position in the DOM and - // whether we want the current node to be considered as well. - Node* nextAnchorNode = getNextAnchorNode(anchorNode, ignoreFirstNode, - direction); - if (!nextAnchorNode) { - ec = NOT_FOUND_ERR; - return; - } - if (nextAnchorNode->isElementNode()) { - // If this is an input element tell the WebView thread - // to set the cursor to that control. - if (isContentInputElement(nextAnchorNode)) { - IntRect bounds = nextAnchorNode->getRect(); - selectAt(bounds.center().x(), bounds.center().y()); - } - Node* textNode = 0; - // Treat the text content of links as any other text but - // for the rest input elements select the control itself. - if (nextAnchorNode->hasTagName(WebCore::HTMLNames::aTag)) - textNode = traverseNextContentTextNode(nextAnchorNode, - nextAnchorNode, direction); - // We prefer to select the text content of the link if such, - // otherwise just select the element itself. - if (textNode) { - nextAnchorNode = textNode; - } else { - if (direction == DIRECTION_FORWARD) { - selection->setBaseAndExtent(nextAnchorNode, - caretMinOffset(nextAnchorNode), nextAnchorNode, - caretMaxOffset(nextAnchorNode), ec); - } else { - selection->setBaseAndExtent(nextAnchorNode, - caretMaxOffset(nextAnchorNode), nextAnchorNode, - caretMinOffset(nextAnchorNode), ec); - } - if (!ec) - markup = formatMarkup(selection); - // make sure the selection is visible - scrollNodeIntoView(selection->frame(), nextAnchorNode); - return; - } - } - if (direction == DIRECTION_FORWARD) - selection->setPosition(nextAnchorNode, - caretMinOffset(nextAnchorNode), ec); - else - selection->setPosition(nextAnchorNode, - caretMaxOffset(nextAnchorNode), ec); -} - -bool WebViewCore::isContentInputElement(Node* node) -{ - return (isVisible(node) - && (node->hasTagName(WebCore::HTMLNames::selectTag) - || node->hasTagName(WebCore::HTMLNames::aTag) - || node->hasTagName(WebCore::HTMLNames::inputTag) - || node->hasTagName(WebCore::HTMLNames::buttonTag))); -} - -bool WebViewCore::isContentTextNode(Node* node) -{ - if (!node || !node->isTextNode()) - return false; - Text* textNode = static_cast(node); - return (isVisible(textNode) && textNode->length() > 0 - && !textNode->containsOnlyWhitespace()); -} - -Text* WebViewCore::traverseNextContentTextNode(Node* fromNode, Node* toNode, int direction) -{ - Node* currentNode = fromNode; - do { - if (direction == DIRECTION_FORWARD) - currentNode = currentNode->traverseNextNode(toNode); - else - currentNode = currentNode->traversePreviousNodePostOrder(toNode); - } while (currentNode && !isContentTextNode(currentNode)); - return static_cast(currentNode); -} - -Node* WebViewCore::getIntermediaryInputElement(Node* fromNode, Node* toNode, int direction) -{ - if (fromNode == toNode) - return 0; - if (direction == DIRECTION_FORWARD) { - Node* currentNode = fromNode; - while (currentNode && currentNode != toNode) { - if (isContentInputElement(currentNode)) - return currentNode; - currentNode = currentNode->traverseNextNodePostOrder(); - } - currentNode = fromNode; - while (currentNode && currentNode != toNode) { - if (isContentInputElement(currentNode)) - return currentNode; - currentNode = currentNode->traverseNextNode(); - } - } else { - Node* currentNode = fromNode->traversePreviousNode(); - while (currentNode && currentNode != toNode) { - if (isContentInputElement(currentNode)) - return currentNode; - currentNode = currentNode->traversePreviousNode(); - } - currentNode = fromNode->traversePreviousNodePostOrder(); - while (currentNode && currentNode != toNode) { - if (isContentInputElement(currentNode)) - return currentNode; - currentNode = currentNode->traversePreviousNodePostOrder(); - } - } - return 0; -} - -bool WebViewCore::isDescendantOf(Node* parent, Node* node) -{ - Node* currentNode = node; - while (currentNode) { - if (currentNode == parent) { - return true; - } - currentNode = currentNode->parentNode(); - } - return false; -} - -String WebViewCore::modifySelectionDomNavigationAxis(DOMSelection* selection, int direction, int axis) -{ - HTMLElement* body = m_mainFrame->document()->body(); - if (!m_currentNodeDomNavigationAxis && selection->focusNode()) { - m_currentNodeDomNavigationAxis = selection->focusNode(); - selection->empty(); - if (m_currentNodeDomNavigationAxis->isTextNode()) - m_currentNodeDomNavigationAxis = - m_currentNodeDomNavigationAxis->parentNode(); - } - if (!m_currentNodeDomNavigationAxis) - m_currentNodeDomNavigationAxis = currentFocus(); - if (!m_currentNodeDomNavigationAxis - || !CacheBuilder::validNode(m_mainFrame, m_mainFrame, - m_currentNodeDomNavigationAxis)) - m_currentNodeDomNavigationAxis = body; - Node* currentNode = m_currentNodeDomNavigationAxis; - if (axis == AXIS_HEADING) { - if (currentNode == body && direction == DIRECTION_BACKWARD) - currentNode = currentNode->lastDescendant(); - do { - if (direction == DIRECTION_FORWARD) - currentNode = currentNode->traverseNextNode(body); - else - currentNode = currentNode->traversePreviousNode(body); - } while (currentNode && (currentNode->isTextNode() - || !isVisible(currentNode) || !isHeading(currentNode))); - } else if (axis == AXIS_PARENT_FIRST_CHILD) { - if (direction == DIRECTION_FORWARD) { - currentNode = currentNode->firstChild(); - while (currentNode && (currentNode->isTextNode() - || !isVisible(currentNode))) - currentNode = currentNode->nextSibling(); - } else { - do { - if (currentNode == body) - return String(); - currentNode = currentNode->parentNode(); - } while (currentNode && (currentNode->isTextNode() - || !isVisible(currentNode))); - } - } else if (axis == AXIS_SIBLING) { - do { - if (direction == DIRECTION_FORWARD) - currentNode = currentNode->nextSibling(); - else { - if (currentNode == body) - return String(); - currentNode = currentNode->previousSibling(); - } - } while (currentNode && (currentNode->isTextNode() - || !isVisible(currentNode))); - } else if (axis == AXIS_DOCUMENT) { - currentNode = body; - if (direction == DIRECTION_FORWARD) - currentNode = currentNode->lastDescendant(); - } else { - LOGE("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()); - return selectionString; - } - return String(); -} - -bool WebViewCore::isHeading(Node* node) -{ - if (node->hasTagName(WebCore::HTMLNames::h1Tag) - || node->hasTagName(WebCore::HTMLNames::h2Tag) - || node->hasTagName(WebCore::HTMLNames::h3Tag) - || node->hasTagName(WebCore::HTMLNames::h4Tag) - || node->hasTagName(WebCore::HTMLNames::h5Tag) - || node->hasTagName(WebCore::HTMLNames::h6Tag)) { - return true; - } - - if (node->isElementNode()) { - Element* element = static_cast(node); - String roleAttribute = - element->getAttribute(WebCore::HTMLNames::roleAttr).string(); - if (equalIgnoringCase(roleAttribute, "heading")) - return true; - } - - return false; -} - -bool WebViewCore::isVisible(Node* node) -{ - // start off an element - Element* element = 0; - if (node->isElementNode()) - element = static_cast(node); - else - element = node->parentElement(); - // check renderer - if (!element->renderer()) { - return false; - } - // check size - if (element->offsetHeight() == 0 || element->offsetWidth() == 0) { - return false; - } - // check style - Node* body = m_mainFrame->document()->body(); - Node* currentNode = element; - while (currentNode && currentNode != body) { - RenderStyle* style = currentNode->computedStyle(); - if (style && - (style->display() == NONE || style->visibility() == HIDDEN)) { - return false; - } - currentNode = currentNode->parentNode(); - } - return true; -} - -String WebViewCore::formatMarkup(DOMSelection* selection) -{ - ExceptionCode ec = 0; - String markup = String(); - PassRefPtr wholeRange = selection->getRangeAt(0, ec); - if (ec) - return String(); - if (!wholeRange->startContainer() || !wholeRange->startContainer()) - return String(); - // Since formatted markup contains invisible nodes it - // is created from the concatenation of the visible fragments. - Node* firstNode = wholeRange->firstNode(); - Node* pastLastNode = wholeRange->pastLastNode(); - Node* currentNode = firstNode; - PassRefPtr currentRange; - - while (currentNode != pastLastNode) { - Node* nextNode = currentNode->traverseNextNode(); - if (!isVisible(currentNode)) { - if (currentRange) { - markup = markup + currentRange->toHTML().utf8().data(); - currentRange = 0; - } - } else { - if (!currentRange) { - currentRange = selection->frame()->document()->createRange(); - if (ec) - break; - if (currentNode == firstNode) { - currentRange->setStart(wholeRange->startContainer(), - wholeRange->startOffset(), ec); - if (ec) - break; - } else { - currentRange->setStart(currentNode->parentNode(), - currentNode->nodeIndex(), ec); - if (ec) - break; - } - } - if (nextNode == pastLastNode) { - currentRange->setEnd(wholeRange->endContainer(), - wholeRange->endOffset(), ec); - if (ec) - break; - markup = markup + currentRange->toHTML().utf8().data(); - } else { - if (currentNode->offsetInCharacters()) - currentRange->setEnd(currentNode, - currentNode->maxCharacterOffset(), ec); - else - currentRange->setEnd(currentNode->parentNode(), - currentNode->nodeIndex() + 1, ec); - if (ec) - break; - } - } - currentNode = nextNode; - } - return markup.stripWhiteSpace(); -} - -void WebViewCore::selectAt(int x, int y) -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_selectAt, - x, y); - checkException(env); -} - -void WebViewCore::deleteSelection(int start, int end, int textGeneration) -{ - setSelection(start, end); - if (start == end) - return; - WebCore::Node* focus = currentFocus(); - if (!focus) - return; - // Prevent our editor client from passing a message to change the - // selection. - EditorClientAndroid* client = static_cast( - m_mainFrame->editor()->client()); - client->setUiGeneratedSelectionChange(true); - PlatformKeyboardEvent down(AKEYCODE_DEL, 0, 0, true, false, false, false); - PlatformKeyboardEvent up(AKEYCODE_DEL, 0, 0, false, false, false, false); - key(down); - key(up); - client->setUiGeneratedSelectionChange(false); - m_textGeneration = textGeneration; - m_shouldPaintCaret = true; -} - -void WebViewCore::replaceTextfieldText(int oldStart, - int oldEnd, const WTF::String& replace, int start, int end, - int textGeneration) -{ - WebCore::Node* focus = currentFocus(); - if (!focus) - return; - setSelection(oldStart, oldEnd); - // Prevent our editor client from passing a message to change the - // selection. - EditorClientAndroid* client = static_cast( - m_mainFrame->editor()->client()); - client->setUiGeneratedSelectionChange(true); - WebCore::TypingCommand::insertText(focus->document(), replace, - false); - 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, - const PlatformKeyboardEvent& event) -{ - 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; - } - // Block text field updates during a key press. - m_blockTextfieldUpdates = true; - // Also prevent our editor client from passing a message to change the - // selection. - EditorClientAndroid* client = static_cast( - m_mainFrame->editor()->client()); - client->setUiGeneratedSelectionChange(true); - key(event); - client->setUiGeneratedSelectionChange(false); - m_blockTextfieldUpdates = false; - m_textGeneration = generation; - WebCore::RenderTextControl* renderText = - static_cast(renderer); - WTF::String test = renderText->text(); - 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); - clearTextEntry(); - return; - } - WebCore::RenderTextControl* renderText = - static_cast(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); -} - -void WebViewCore::setFocusControllerActive(bool active) -{ - m_mainFrame->page()->focusController()->setActive(active); -} - -void WebViewCore::saveDocumentState(WebCore::Frame* frame) -{ - if (!CacheBuilder::validNode(m_mainFrame, frame, 0)) - frame = m_mainFrame; - WebCore::HistoryItem *item = frame->loader()->history()->currentItem(); - - // item can be null when there is no offical URL for the current page. This happens - // when the content is loaded using with WebCoreFrameBridge::LoadData() and there - // is no failing URL (common case is when content is loaded using data: scheme) - if (item) { - item->setDocumentState(frame->document()->formElementsState()); - } -} - -// Create an array of java Strings. -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"); - jobjectArray array = env->NewObjectArray(count, stringClass, 0); - LOG_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]); - env->SetObjectArrayElement(array, i, newString); - env->DeleteLocalRef(newString); - checkException(env); - } - env->DeleteLocalRef(stringClass); - return array; -} - -void WebViewCore::openFileChooser(PassRefPtr chooser) { - if (!chooser) - return; - JNIEnv* env = JSC::Bindings::getJNIEnv(); - - WTF::String acceptType = chooser->acceptTypes(); - jstring jAcceptType = wtfStringToJstring(env, acceptType, true); - jstring jName = (jstring) env->CallObjectMethod( - m_javaGlue->object(env).get(), m_javaGlue->m_openFileChooser, jAcceptType); - checkException(env); - env->DeleteLocalRef(jAcceptType); - - const UChar* string = static_cast(env->GetStringChars(jName, NULL)); - - if (!string) - return; - - WTF::String webcoreString = jstringToWtfString(env, jName); - env->ReleaseStringChars(jName, string); - - if (webcoreString.length()) - chooser->chooseFile(webcoreString); -} - -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) -{ - // If m_popupReply is not null, then we already have a list showing. - if (m_popupReply != 0) - return; - - LOG_ASSERT(m_javaGlue->m_obj, "No java widget associated with this view!"); - - // Create an array of java Strings for the drop down. - JNIEnv* env = JSC::Bindings::getJNIEnv(); - jobjectArray labelArray = makeLabelArray(env, labels, count); - - // Create an array determining whether each item is enabled. - jintArray enabledArray = env->NewIntArray(enabledCount); - checkException(env); - jint* ptrArray = env->GetIntArrayElements(enabledArray, 0); - checkException(env); - for (size_t i = 0; i < enabledCount; i++) { - ptrArray[i] = enabled[i]; - } - env->ReleaseIntArrayElements(enabledArray, ptrArray, 0); - checkException(env); - - if (multiple) { - // Pass up an array representing which items are selected. - jintArray selectedArray = env->NewIntArray(selectedCountOrSelection); - checkException(env); - jint* selArray = env->GetIntArrayElements(selectedArray, 0); - checkException(env); - for (size_t i = 0; i < selectedCountOrSelection; i++) { - selArray[i] = selected[i]; - } - env->ReleaseIntArrayElements(selectedArray, selArray, 0); - - env->CallVoidMethod(m_javaGlue->object(env).get(), - m_javaGlue->m_requestListBox, labelArray, enabledArray, - selectedArray); - env->DeleteLocalRef(selectedArray); - } else { - // Pass up the single selection. - env->CallVoidMethod(m_javaGlue->object(env).get(), - m_javaGlue->m_requestSingleListBox, labelArray, enabledArray, - selectedCountOrSelection); - } - - env->DeleteLocalRef(labelArray); - env->DeleteLocalRef(enabledArray); - checkException(env); - - Retain(reply); - m_popupReply = reply; -} - -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(); - bool handled = eventHandler->keyEvent(event); - 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 - // return false so that the key will be sent back to our navigation - // system. - handled |= frame->selection()->selection() != old; - } - return handled; - } else { - eventHandler = m_mainFrame->eventHandler(); - } - return eventHandler->keyEvent(event); -} - -// For when the user clicks the trackball, presses dpad center, or types into an -// unfocused textfield. In the latter case, 'fake' will be true -void WebViewCore::click(WebCore::Frame* frame, WebCore::Node* node, bool fake) { - if (!node) { - WebCore::IntPoint pt = m_mousePos; - pt.move(m_scrollOffsetX, m_scrollOffsetY); - WebCore::HitTestResult hitTestResult = m_mainFrame->eventHandler()-> - hitTestResultAtPoint(pt, false); - node = hitTestResult.innerNode(); - frame = node->document()->frame(); - DBG_NAV_LOGD("m_mousePos=(%d,%d) m_scrollOffset=(%d,%d) pt=(%d,%d)" - " node=%p", m_mousePos.x(), m_mousePos.y(), - m_scrollOffsetX, m_scrollOffsetY, pt.x(), pt.y(), node); - } - if (node) { - EditorClientAndroid* client - = static_cast( - m_mainFrame->editor()->client()); - client->setShouldChangeSelectedRange(false); - handleMouseClick(frame, node, fake); - client->setShouldChangeSelectedRange(true); - } -} - -#if USE(ACCELERATED_COMPOSITING) -GraphicsLayerAndroid* WebViewCore::graphicsRootLayer() const -{ - RenderView* contentRenderer = m_mainFrame->contentRenderer(); - if (!contentRenderer) - return 0; - return static_cast( - contentRenderer->compositor()->rootPlatformLayer()); -} -#endif - -bool WebViewCore::handleTouchEvent(int action, Vector& ids, Vector& points, int actionIndex, int metaState) -{ - bool preventDefault = false; - -#if USE(ACCELERATED_COMPOSITING) - GraphicsLayerAndroid* rootLayer = graphicsRootLayer(); - if (rootLayer) - rootLayer->pauseDisplay(true); -#endif - -#if ENABLE(TOUCH_EVENTS) // Android - #define MOTION_EVENT_ACTION_POINTER_DOWN 5 - #define MOTION_EVENT_ACTION_POINTER_UP 6 - - WebCore::TouchEventType type = WebCore::TouchStart; - WebCore::PlatformTouchPoint::State defaultTouchState; - Vector touchStates(points.size()); - - switch (action) { - case 0: // MotionEvent.ACTION_DOWN - type = WebCore::TouchStart; - defaultTouchState = WebCore::PlatformTouchPoint::TouchPressed; - break; - case 1: // MotionEvent.ACTION_UP - type = WebCore::TouchEnd; - defaultTouchState = WebCore::PlatformTouchPoint::TouchReleased; - break; - case 2: // MotionEvent.ACTION_MOVE - type = WebCore::TouchMove; - defaultTouchState = WebCore::PlatformTouchPoint::TouchMoved; - break; - case 3: // MotionEvent.ACTION_CANCEL - type = WebCore::TouchCancel; - defaultTouchState = WebCore::PlatformTouchPoint::TouchCancelled; - break; - case 5: // MotionEvent.ACTION_POINTER_DOWN - type = WebCore::TouchStart; - defaultTouchState = WebCore::PlatformTouchPoint::TouchStationary; - break; - case 6: // MotionEvent.ACTION_POINTER_UP - type = WebCore::TouchEnd; - defaultTouchState = WebCore::PlatformTouchPoint::TouchStationary; - break; - case 0x100: // WebViewCore.ACTION_LONGPRESS - type = WebCore::TouchLongPress; - defaultTouchState = WebCore::PlatformTouchPoint::TouchPressed; - break; - case 0x200: // WebViewCore.ACTION_DOUBLETAP - type = WebCore::TouchDoubleTap; - defaultTouchState = WebCore::PlatformTouchPoint::TouchPressed; - break; - default: - // We do not support other kinds of touch event inside WebCore - // at the moment. - LOGW("Java passed a touch event type that we do not support in WebCore: %d", action); - return 0; - } - - for (int c = 0; c < static_cast(points.size()); c++) { - points[c].setX(points[c].x() - m_scrollOffsetX); - points[c].setY(points[c].y() - m_scrollOffsetY); - - // Setting the touch state for each point. - // Note: actionIndex will be 0 for all actions that are not ACTION_POINTER_DOWN/UP. - if (action == MOTION_EVENT_ACTION_POINTER_DOWN && c == actionIndex) { - touchStates[c] = WebCore::PlatformTouchPoint::TouchPressed; - } else if (action == MOTION_EVENT_ACTION_POINTER_UP && c == actionIndex) { - touchStates[c] = WebCore::PlatformTouchPoint::TouchReleased; - } else { - touchStates[c] = defaultTouchState; - }; - } - - WebCore::PlatformTouchEvent te(ids, points, type, touchStates, metaState); - preventDefault = m_mainFrame->eventHandler()->handleTouchEvent(te); -#endif - -#if USE(ACCELERATED_COMPOSITING) - if (rootLayer) - rootLayer->pauseDisplay(false); -#endif - return preventDefault; -} - -void WebViewCore::touchUp(int touchGeneration, - WebCore::Frame* frame, WebCore::Node* node, int x, int y) -{ - if (touchGeneration == 0) { - // m_mousePos should be set in getTouchHighlightRects() - WebCore::HitTestResult hitTestResult = m_mainFrame->eventHandler()->hitTestResultAtPoint(m_mousePos, false); - node = hitTestResult.innerNode(); - if (node) - frame = node->document()->frame(); - else - frame = 0; - DBG_NAV_LOGD("touch up on (%d, %d), scrollOffset is (%d, %d), node:%p, frame:%p", m_mousePos.x() + m_scrollOffsetX, m_mousePos.y() + m_scrollOffsetY, m_scrollOffsetX, m_scrollOffsetY, node, frame); - } else { - if (m_touchGeneration > touchGeneration) { - DBG_NAV_LOGD("m_touchGeneration=%d > touchGeneration=%d" - " x=%d y=%d", m_touchGeneration, touchGeneration, x, y); - return; // short circuit if a newer touch has been generated - } - // This moves m_mousePos to the correct place, and handleMouseClick uses - // m_mousePos to determine where the click happens. - moveMouse(frame, x, y); - m_lastGeneration = touchGeneration; - } - if (frame && CacheBuilder::validNode(m_mainFrame, frame, 0)) { - frame->loader()->resetMultipleFormSubmissionProtection(); - } - DBG_NAV_LOGD("touchGeneration=%d handleMouseClick frame=%p node=%p" - " x=%d y=%d", touchGeneration, frame, node, x, y); - handleMouseClick(frame, node, false); -} - -// Check for the "x-webkit-soft-keyboard" attribute. If it is there and -// set to hidden, do not show the soft keyboard. Node passed as a parameter -// must not be null. -static bool shouldSuppressKeyboard(const WebCore::Node* node) { - LOG_ASSERT(node, "node passed to shouldSuppressKeyboard cannot be null"); - const NamedNodeMap* attributes = node->attributes(); - if (!attributes) return false; - size_t length = attributes->length(); - for (size_t i = 0; i < length; i++) { - const Attribute* a = attributes->attributeItem(i); - if (a->localName() == "x-webkit-soft-keyboard" && a->value() == "hidden") - return true; - } - return false; -} - -// Common code for both clicking with the trackball and touchUp -// Also used when typing into a non-focused textfield to give the textfield focus, -// in which case, 'fake' is set to true -bool WebViewCore::handleMouseClick(WebCore::Frame* framePtr, WebCore::Node* nodePtr, bool fake) -{ - bool valid = !framePtr || CacheBuilder::validNode(m_mainFrame, framePtr, nodePtr); - WebFrame* webFrame = WebFrame::getWebFrame(m_mainFrame); - if (valid && nodePtr) { - // Need to special case area tags because an image map could have an area element in the middle - // so when attempting to get the default, the point chosen would be follow the wrong link. - if (nodePtr->hasTagName(WebCore::HTMLNames::areaTag)) { - webFrame->setUserInitiatedAction(true); - nodePtr->dispatchSimulatedClick(0, true, true); - webFrame->setUserInitiatedAction(false); - DBG_NAV_LOG("area"); - return true; - } - } - if (!valid || !framePtr) - framePtr = m_mainFrame; - webFrame->setUserInitiatedAction(true); - WebCore::PlatformMouseEvent mouseDown(m_mousePos, m_mousePos, WebCore::LeftButton, - WebCore::MouseEventPressed, 1, false, false, false, false, - WTF::currentTime()); - // ignore the return from as it will return true if the hit point can trigger selection change - framePtr->eventHandler()->handleMousePressEvent(mouseDown); - WebCore::PlatformMouseEvent mouseUp(m_mousePos, m_mousePos, WebCore::LeftButton, - WebCore::MouseEventReleased, 1, false, false, false, false, - WTF::currentTime()); - bool handled = framePtr->eventHandler()->handleMouseReleaseEvent(mouseUp); - webFrame->setUserInitiatedAction(false); - - // If the user clicked on a textfield, make the focusController active - // so we show the blinking cursor. - WebCore::Node* focusNode = currentFocus(); - DBG_NAV_LOGD("m_mousePos={%d,%d} focusNode=%p handled=%s", m_mousePos.x(), - m_mousePos.y(), focusNode, handled ? "true" : "false"); - if (focusNode) { - WebCore::RenderObject* renderer = focusNode->renderer(); - if (renderer && (renderer->isTextField() || renderer->isTextArea())) { - bool ime = !shouldSuppressKeyboard(focusNode) - && !(static_cast(focusNode))->readOnly(); - if (ime) { -#if ENABLE(WEB_AUTOFILL) - if (renderer->isTextField()) { - EditorClientAndroid* editorC = static_cast(framePtr->page()->editorClient()); - WebAutoFill* autoFill = editorC->getAutoFill(); - autoFill->formFieldFocused(static_cast(focusNode)); - } -#endif - if (!fake) { - RenderTextControl* rtc - = static_cast (renderer); - requestKeyboardWithSelection(focusNode, rtc->selectionStart(), - rtc->selectionEnd()); - } - } else if (!fake) { - requestKeyboard(false); - } - } else if (!fake){ - // If the selection is contentEditable, show the keyboard so the - // user can type. Otherwise hide the keyboard because no text - // input is needed. - if (isContentEditable(focusNode)) { - requestKeyboard(true); - } else if (!nodeIsPlugin(focusNode)) { - clearTextEntry(); - } - } - } else if (!fake) { - // There is no focusNode, so the keyboard is not needed. - clearTextEntry(); - } - return handled; -} - -void WebViewCore::popupReply(int index) -{ - if (m_popupReply) { - m_popupReply->replyInt(index); - Release(m_popupReply); - m_popupReply = 0; - } -} - -void WebViewCore::popupReply(const int* array, int count) -{ - if (m_popupReply) { - m_popupReply->replyIntArray(array, count); - Release(m_popupReply); - m_popupReply = 0; - } -} - -void WebViewCore::formDidBlur(const WebCore::Node* node) -{ - // If the blur is on a text input, keep track of the node so we can - // hide the soft keyboard when the new focus is set, if it is not a - // text input. - if (isTextInput(node)) - m_blurringNodePointer = reinterpret_cast(node); -} - -void WebViewCore::focusNodeChanged(const WebCore::Node* newFocus) -{ - if (isTextInput(newFocus)) - m_shouldPaintCaret = true; - else if (m_blurringNodePointer) { - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), - m_javaGlue->m_formDidBlur, m_blurringNodePointer); - checkException(env); - m_blurringNodePointer = 0; - } -} - -void WebViewCore::addMessageToConsole(const WTF::String& message, unsigned int lineNumber, const WTF::String& sourceID, int msgLevel) { - JNIEnv* env = JSC::Bindings::getJNIEnv(); - jstring jMessageStr = wtfStringToJstring(env, message); - jstring jSourceIDStr = wtfStringToJstring(env, sourceID); - env->CallVoidMethod(m_javaGlue->object(env).get(), - m_javaGlue->m_addMessageToConsole, jMessageStr, lineNumber, - jSourceIDStr, msgLevel); - env->DeleteLocalRef(jMessageStr); - env->DeleteLocalRef(jSourceIDStr); - checkException(env); -} - -void WebViewCore::jsAlert(const WTF::String& url, const WTF::String& text) -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - jstring jInputStr = wtfStringToJstring(env, text); - jstring jUrlStr = wtfStringToJstring(env, url); - env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsAlert, jUrlStr, jInputStr); - env->DeleteLocalRef(jInputStr); - env->DeleteLocalRef(jUrlStr); - checkException(env); -} - -void WebViewCore::exceededDatabaseQuota(const WTF::String& url, const WTF::String& databaseIdentifier, const unsigned long long currentQuota, unsigned long long estimatedSize) -{ -#if ENABLE(DATABASE) - JNIEnv* env = JSC::Bindings::getJNIEnv(); - jstring jDatabaseIdentifierStr = wtfStringToJstring(env, databaseIdentifier); - jstring jUrlStr = wtfStringToJstring(env, url); - env->CallVoidMethod(m_javaGlue->object(env).get(), - m_javaGlue->m_exceededDatabaseQuota, jUrlStr, - jDatabaseIdentifierStr, currentQuota, estimatedSize); - env->DeleteLocalRef(jDatabaseIdentifierStr); - env->DeleteLocalRef(jUrlStr); - checkException(env); -#endif -} - -void WebViewCore::reachedMaxAppCacheSize(const unsigned long long spaceNeeded) -{ -#if ENABLE(OFFLINE_WEB_APPLICATIONS) - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), - m_javaGlue->m_reachedMaxAppCacheSize, spaceNeeded); - checkException(env); -#endif -} - -void WebViewCore::populateVisitedLinks(WebCore::PageGroup* group) -{ - m_groupForVisitedLinks = group; - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_populateVisitedLinks); - checkException(env); -} - -void WebViewCore::geolocationPermissionsShowPrompt(const WTF::String& origin) -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - jstring originString = wtfStringToJstring(env, origin); - env->CallVoidMethod(m_javaGlue->object(env).get(), - m_javaGlue->m_geolocationPermissionsShowPrompt, - originString); - env->DeleteLocalRef(originString); - checkException(env); -} - -void WebViewCore::geolocationPermissionsHidePrompt() -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), - m_javaGlue->m_geolocationPermissionsHidePrompt); - checkException(env); -} - -jobject WebViewCore::getDeviceMotionService() -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - jobject object = env->CallObjectMethod(m_javaGlue->object(env).get(), - m_javaGlue->m_getDeviceMotionService); - checkException(env); - return object; -} - -jobject WebViewCore::getDeviceOrientationService() -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - jobject object = env->CallObjectMethod(m_javaGlue->object(env).get(), - m_javaGlue->m_getDeviceOrientationService); - checkException(env); - return object; -} - -bool WebViewCore::jsConfirm(const WTF::String& url, const WTF::String& text) -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - jstring jInputStr = wtfStringToJstring(env, text); - jstring jUrlStr = wtfStringToJstring(env, url); - jboolean result = env->CallBooleanMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsConfirm, jUrlStr, jInputStr); - env->DeleteLocalRef(jInputStr); - env->DeleteLocalRef(jUrlStr); - checkException(env); - return result; -} - -bool WebViewCore::jsPrompt(const WTF::String& url, const WTF::String& text, const WTF::String& defaultValue, WTF::String& result) -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - jstring jUrlStr = wtfStringToJstring(env, url); - jstring jInputStr = wtfStringToJstring(env, text); - jstring jDefaultStr = wtfStringToJstring(env, defaultValue); - jstring returnVal = static_cast(env->CallObjectMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsPrompt, jUrlStr, jInputStr, jDefaultStr)); - env->DeleteLocalRef(jUrlStr); - env->DeleteLocalRef(jInputStr); - env->DeleteLocalRef(jDefaultStr); - checkException(env); - - // If returnVal is null, it means that the user cancelled the dialog. - if (!returnVal) - return false; - - result = jstringToWtfString(env, returnVal); - env->DeleteLocalRef(returnVal); - return true; -} - -bool WebViewCore::jsUnload(const WTF::String& url, const WTF::String& message) -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - jstring jInputStr = wtfStringToJstring(env, message); - jstring jUrlStr = wtfStringToJstring(env, url); - jboolean result = env->CallBooleanMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsUnload, jUrlStr, jInputStr); - env->DeleteLocalRef(jInputStr); - env->DeleteLocalRef(jUrlStr); - checkException(env); - return result; -} - -bool WebViewCore::jsInterrupt() -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - jboolean result = env->CallBooleanMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsInterrupt); - checkException(env); - return result; -} - -AutoJObject -WebViewCore::getJavaObject() -{ - return m_javaGlue->object(JSC::Bindings::getJNIEnv()); -} - -jobject -WebViewCore::getWebViewJavaObject() -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - return env->GetObjectField(m_javaGlue->object(env).get(), gWebViewCoreFields.m_webView); -} - -void WebViewCore::updateTextSelection() { - WebCore::Node* focusNode = currentFocus(); - if (!focusNode) - return; - RenderObject* renderer = focusNode->renderer(); - if (!renderer || (!renderer->isTextArea() && !renderer->isTextField())) - return; - RenderTextControl* rtc = static_cast(renderer); - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), - m_javaGlue->m_updateTextSelection, reinterpret_cast(focusNode), - rtc->selectionStart(), rtc->selectionEnd(), m_textGeneration); - checkException(env); -} - -void WebViewCore::updateTextfield(WebCore::Node* ptr, bool changeToPassword, - const WTF::String& text) -{ - if (m_blockTextfieldUpdates) - return; - JNIEnv* env = JSC::Bindings::getJNIEnv(); - if (changeToPassword) { - env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_updateTextfield, - (int) ptr, true, 0, m_textGeneration); - checkException(env); - return; - } - jstring string = wtfStringToJstring(env, text); - env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_updateTextfield, - (int) ptr, false, string, m_textGeneration); - env->DeleteLocalRef(string); - checkException(env); -} - -void WebViewCore::clearTextEntry() -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), - m_javaGlue->m_clearTextEntry); -} - -void WebViewCore::setBackgroundColor(SkColor c) -{ - WebCore::FrameView* view = m_mainFrame->view(); - if (!view) - return; - - // need (int) cast to find the right constructor - WebCore::Color bcolor((int)SkColorGetR(c), (int)SkColorGetG(c), - (int)SkColorGetB(c), (int)SkColorGetA(c)); - view->setBaseBackgroundColor(bcolor); - - // Background color of 0 indicates we want a transparent background - if (c == 0) - view->setTransparent(true); -} - -jclass WebViewCore::getPluginClass(const WTF::String& libName, const char* className) -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - - jstring libString = wtfStringToJstring(env, libName); - jstring classString = env->NewStringUTF(className); - jobject pluginClass = env->CallObjectMethod(m_javaGlue->object(env).get(), - m_javaGlue->m_getPluginClass, - libString, classString); - checkException(env); - - // cleanup unneeded local JNI references - env->DeleteLocalRef(libString); - env->DeleteLocalRef(classString); - - if (pluginClass != NULL) { - return static_cast(pluginClass); - } else { - return NULL; - } -} - -void WebViewCore::showFullScreenPlugin(jobject childView, NPP npp) -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - AutoJObject obj = m_javaGlue->object(env); - - env->CallVoidMethod(obj.get(), - m_javaGlue->m_showFullScreenPlugin, childView, (int)npp); - checkException(env); -} - -void WebViewCore::hideFullScreenPlugin() -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), - m_javaGlue->m_hideFullScreenPlugin); - checkException(env); -} - -jobject WebViewCore::createSurface(jobject view) -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - jobject result = env->CallObjectMethod(m_javaGlue->object(env).get(), - m_javaGlue->m_createSurface, view); - checkException(env); - return result; -} - -jobject WebViewCore::addSurface(jobject view, int x, int y, int width, int height) -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - jobject result = env->CallObjectMethod(m_javaGlue->object(env).get(), - m_javaGlue->m_addSurface, - view, x, y, width, height); - checkException(env); - return result; -} - -void WebViewCore::updateSurface(jobject childView, int x, int y, int width, int height) -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), - m_javaGlue->m_updateSurface, childView, - x, y, width, height); - checkException(env); -} - -void WebViewCore::destroySurface(jobject childView) -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_destroySurface, childView); - checkException(env); -} - -jobject WebViewCore::getContext() -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - AutoJObject obj = m_javaGlue->object(env); - - jobject result = env->CallObjectMethod(obj.get(), m_javaGlue->m_getContext); - checkException(env); - return result; -} - -void WebViewCore::keepScreenOn(bool screenOn) { - if ((screenOn && m_screenOnCounter == 0) || (!screenOn && m_screenOnCounter == 1)) { - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_keepScreenOn, screenOn); - checkException(env); - } - - // update the counter - if (screenOn) - m_screenOnCounter++; - else if (m_screenOnCounter > 0) - m_screenOnCounter--; -} - -bool WebViewCore::validNodeAndBounds(Frame* frame, Node* node, - const IntRect& originalAbsoluteBounds) -{ - bool valid = CacheBuilder::validNode(m_mainFrame, frame, node); - if (!valid) - return false; - RenderObject* renderer = node->renderer(); - if (!renderer) - return false; - IntRect absBounds = node->hasTagName(HTMLNames::areaTag) - ? CacheBuilder::getAreaRect(static_cast(node)) - : renderer->absoluteBoundingBoxRect(); - return absBounds == originalAbsoluteBounds; -} - -void WebViewCore::showRect(int left, int top, int width, int height, - int contentWidth, int contentHeight, float xPercentInDoc, - float xPercentInView, float yPercentInDoc, float yPercentInView) -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_showRect, - left, top, width, height, contentWidth, contentHeight, - xPercentInDoc, xPercentInView, yPercentInDoc, yPercentInView); - checkException(env); -} - -void WebViewCore::centerFitRect(int x, int y, int width, int height) -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), - m_javaGlue->m_centerFitRect, x, y, width, height); - checkException(env); -} - - -void WebViewCore::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode verticalMode) -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_setScrollbarModes, - horizontalMode, verticalMode); - checkException(env); -} - -void WebViewCore::notifyWebAppCanBeInstalled() -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_setInstallableWebApp); - checkException(env); -} - -#if ENABLE(VIDEO) -void WebViewCore::enterFullscreenForVideoLayer(int layerId, const WTF::String& url) -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - jstring jUrlStr = wtfStringToJstring(env, url); - env->CallVoidMethod(m_javaGlue->object(env).get(), - m_javaGlue->m_enterFullscreenForVideoLayer, layerId, jUrlStr); - checkException(env); -} -#endif - -void WebViewCore::setWebTextViewAutoFillable(int queryId, const string16& previewSummary) -{ -#if ENABLE(WEB_AUTOFILL) - JNIEnv* env = JSC::Bindings::getJNIEnv(); - jstring preview = env->NewString(previewSummary.data(), previewSummary.length()); - env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_setWebTextViewAutoFillable, queryId, preview); - env->DeleteLocalRef(preview); -#endif -} - -bool WebViewCore::drawIsPaused() const -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - return env->GetBooleanField(m_javaGlue->object(env).get(), - gWebViewCoreFields.m_drawIsPaused); -} - -#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 - if (m_webRequestContext) - m_webRequestContext->setUserAgent(WebFrame::getWebFrame(m_mainFrame)->userAgentForURL(0)); // URL not used -} - -void WebViewCore::setWebRequestContextCacheMode(int cacheMode) -{ - m_cacheMode = cacheMode; - // We cannot create a WebRequestContext, because we might not know it this is a private tab or not yet - if (!m_webRequestContext) - return; - - m_webRequestContext->setCacheMode(cacheMode); -} - -WebRequestContext* WebViewCore::webRequestContext() -{ - if (!m_webRequestContext) { - Settings* settings = mainFrame()->settings(); - m_webRequestContext = new WebRequestContext(settings && settings->privateBrowsingEnabled()); - setWebRequestContextUserAgent(); - setWebRequestContextCacheMode(m_cacheMode); - } - return m_webRequestContext.get(); -} -#endif - -void WebViewCore::scrollRenderLayer(int layer, const SkRect& rect) -{ -#if USE(ACCELERATED_COMPOSITING) - GraphicsLayerAndroid* root = graphicsRootLayer(); - if (!root) - return; - - LayerAndroid* layerAndroid = root->platformLayer(); - if (!layerAndroid) - return; - - LayerAndroid* target = layerAndroid->findById(layer); - if (!target) - return; - - RenderLayer* owner = target->owningLayer(); - if (!owner) - return; - - if (owner->stackingContext()) - owner->scrollToOffset(rect.fLeft, rect.fTop, true, false); -#endif -} - -//---------------------------------------------------------------------- -// Native JNI methods -//---------------------------------------------------------------------- -static void RevealSelection(JNIEnv *env, jobject obj) -{ - GET_NATIVE_VIEW(env, obj)->revealSelection(); -} - -static jstring RequestLabel(JNIEnv *env, jobject obj, int framePointer, - int nodePointer) -{ - return wtfStringToJstring(env, GET_NATIVE_VIEW(env, obj)->requestLabel( - (WebCore::Frame*) framePointer, (WebCore::Node*) nodePointer)); -} - -static void ClearContent(JNIEnv *env, jobject obj) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - viewImpl->clearContent(); -} - -static void UpdateFrameCacheIfLoading(JNIEnv *env, jobject obj) -{ - GET_NATIVE_VIEW(env, obj)->updateFrameCacheIfLoading(); -} - -static void SetSize(JNIEnv *env, jobject obj, jint width, jint height, - jint textWrapWidth, jfloat scale, jint screenWidth, jint screenHeight, - jint anchorX, jint anchorY, jboolean ignoreHeight) -{ -#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"); - 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) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_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) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_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) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - return GET_NATIVE_VIEW(env, obj)->key(PlatformKeyboardEvent(keyCode, - unichar, repeatCount, isDown, isShift, isAlt, isSym)); -} - -static void Click(JNIEnv *env, jobject obj, 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"); - - viewImpl->click(reinterpret_cast(framePtr), - reinterpret_cast(nodePtr), fake); -} - -static void ContentInvalidateAll(JNIEnv *env, jobject obj) -{ - GET_NATIVE_VIEW(env, obj)->contentInvalidateAll(); -} - -static void DeleteSelection(JNIEnv *env, jobject obj, jint start, jint end, - jint textGeneration) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - viewImpl->deleteSelection(start, end, textGeneration); -} - -static void SetSelection(JNIEnv *env, jobject obj, jint start, jint end) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - viewImpl->setSelection(start, end); -} - -static jstring ModifySelection(JNIEnv *env, jobject obj, jint direction, jint granularity) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - String selectionString = viewImpl->modifySelection(direction, granularity); - return wtfStringToJstring(env, selectionString); -} - -static void ReplaceTextfieldText(JNIEnv *env, jobject obj, - 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); - WTF::String webcoreString = jstringToWtfString(env, replace); - viewImpl->replaceTextfieldText(oldStart, - oldEnd, webcoreString, start, end, textGeneration); -} - -static void PassToJs(JNIEnv *env, jobject obj, - 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, - PlatformKeyboardEvent(keyCode, keyValue, 0, down, cap, fn, sym)); -} - -static void ScrollFocusedTextInput(JNIEnv *env, jobject obj, jfloat xPercent, - jint y) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - viewImpl->scrollFocusedTextInput(xPercent, y); -} - -static void SetFocusControllerActive(JNIEnv *env, jobject obj, 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"); - viewImpl->setFocusControllerActive(active); -} - -static void SaveDocumentState(JNIEnv *env, jobject obj, 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"); - viewImpl->saveDocumentState((WebCore::Frame*) frame); -} - -void WebViewCore::addVisitedLink(const UChar* string, int length) -{ - if (m_groupForVisitedLinks) - m_groupForVisitedLinks->addVisitedLink(string, length); -} - -static jint UpdateLayers(JNIEnv *env, jobject obj, jobject region) -{ - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - BaseLayerAndroid* result = viewImpl->createBaseLayer(); - SkRegion* nativeRegion = GraphicsJNI::getNativeRegion(env, region); - if (result) { - SkIRect bounds; - LayerAndroid* root = static_cast(result->getChild(0)); - if (root) { - root->bounds().roundOut(&bounds); - nativeRegion->setRect(bounds); - } - } - return reinterpret_cast(result); -} - -static jint RecordContent(JNIEnv *env, jobject obj, jobject region, jobject pt) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - SkRegion* nativeRegion = GraphicsJNI::getNativeRegion(env, region); - SkIPoint nativePt; - BaseLayerAndroid* result = viewImpl->recordContent(nativeRegion, &nativePt); - GraphicsJNI::ipoint_to_jpoint(nativePt, env, pt); - return reinterpret_cast(result); -} - -static void SplitContent(JNIEnv *env, jobject obj, jint content) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - viewImpl->splitContent(reinterpret_cast(content)); -} - -static void SendListBoxChoice(JNIEnv* env, jobject obj, 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"); - viewImpl->popupReply(choice); -} - -// Set aside a predetermined amount of space in which to place the listbox -// choices, to avoid unnecessary allocations. -// The size here is arbitrary. We want the size to be at least as great as the -// 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) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoices"); - jboolean* ptrArray = env->GetBooleanArrayElements(jArray, 0); - SkAutoSTMalloc storage(size); - int* array = storage.get(); - int count = 0; - for (int i = 0; i < size; i++) { - if (ptrArray[i]) { - array[count++] = i; - } - } - env->ReleaseBooleanArrayElements(jArray, ptrArray, JNI_ABORT); - viewImpl->popupReply(array, count); -} - -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; - jstring ret = 0; - if (success) - ret = env->NewString(addrChars + start, end - start); - env->ReleaseStringChars(addr, addrChars); - return ret; -} - -static jboolean HandleTouchEvent(JNIEnv *env, jobject obj, 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__); - jint* ptrIdArray = env->GetIntArrayElements(idArray, 0); - jint* ptrXArray = env->GetIntArrayElements(xArray, 0); - jint* ptrYArray = env->GetIntArrayElements(yArray, 0); - Vector ids(count); - Vector points(count); - for (int c = 0; c < count; c++) { - ids[c] = ptrIdArray[c]; - points[c].setX(ptrXArray[c]); - points[c].setY(ptrYArray[c]); - } - env->ReleaseIntArrayElements(idArray, ptrIdArray, JNI_ABORT); - env->ReleaseIntArrayElements(xArray, ptrXArray, JNI_ABORT); - env->ReleaseIntArrayElements(yArray, ptrYArray, JNI_ABORT); - - 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) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); - viewImpl->touchUp(touchGeneration, - (WebCore::Frame*) frame, (WebCore::Node*) node, x, y); -} - -static jstring RetrieveHref(JNIEnv *env, jobject obj, 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__); - 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) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); - WTF::String result = viewImpl->retrieveAnchorText(x, y); - if (!result.isEmpty()) - return wtfStringToJstring(env, result); - return 0; -} - -static jstring RetrieveImageSource(JNIEnv *env, jobject obj, jint x, jint y) -{ - WTF::String result = GET_NATIVE_VIEW(env, obj)->retrieveImageSource(x, y); - return !result.isEmpty() ? wtfStringToJstring(env, result) : 0; -} - -static void StopPaintingCaret(JNIEnv *env, jobject obj) -{ - GET_NATIVE_VIEW(env, obj)->setShouldPaintCaret(false); -} - -static void MoveFocus(JNIEnv *env, jobject obj, jint framePtr, jint nodePtr) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); - viewImpl->moveFocus((WebCore::Frame*) framePtr, (WebCore::Node*) nodePtr); -} - -static void MoveMouse(JNIEnv *env, jobject obj, jint frame, - jint x, jint y) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); - viewImpl->moveMouse((WebCore::Frame*) frame, x, y); -} - -static void MoveMouseIfLatest(JNIEnv *env, jobject obj, jint moveGeneration, - jint frame, jint x, jint y) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); - viewImpl->moveMouseIfLatest(moveGeneration, - (WebCore::Frame*) frame, x, y); -} - -static void UpdateFrameCache(JNIEnv *env, jobject obj) -{ -#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) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); - - WebCore::Frame* frame = viewImpl->mainFrame(); - if (frame) { - WebCore::Document* document = frame->document(); - if (document) { - WebCore::RenderObject* renderer = document->renderer(); - if (renderer && renderer->isRenderView()) { - return renderer->minPreferredLogicalWidth(); - } - } - } - return 0; -} - -static void SetViewportSettingsFromNative(JNIEnv *env, jobject obj) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); - - WebCore::Settings* s = viewImpl->mainFrame()->page()->settings(); - if (!s) - return; - -#ifdef ANDROID_META_SUPPORT - env->SetIntField(obj, gWebViewCoreFields.m_viewportWidth, s->viewportWidth()); - env->SetIntField(obj, gWebViewCoreFields.m_viewportHeight, s->viewportHeight()); - env->SetIntField(obj, gWebViewCoreFields.m_viewportInitialScale, s->viewportInitialScale()); - env->SetIntField(obj, gWebViewCoreFields.m_viewportMinimumScale, s->viewportMinimumScale()); - env->SetIntField(obj, gWebViewCoreFields.m_viewportMaximumScale, s->viewportMaximumScale()); - env->SetBooleanField(obj, gWebViewCoreFields.m_viewportUserScalable, s->viewportUserScalable()); - env->SetIntField(obj, gWebViewCoreFields.m_viewportDensityDpi, s->viewportTargetDensityDpi()); -#endif -} - -static void SetBackgroundColor(JNIEnv *env, jobject obj, 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__); - - viewImpl->setBackgroundColor((SkColor) color); -} - -static void DumpDomTree(JNIEnv *env, jobject obj, jboolean useFile) -{ - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); - - viewImpl->dumpDomTree(useFile); -} - -static void DumpRenderTree(JNIEnv *env, jobject obj, jboolean useFile) -{ - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); - - viewImpl->dumpRenderTree(useFile); -} - -static void DumpNavTree(JNIEnv *env, jobject obj) -{ - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); - - viewImpl->dumpNavTree(); -} - -static void DumpV8Counters(JNIEnv*, jobject) -{ -#if USE(V8) -#ifdef ANDROID_INSTRUMENT - V8Counters::dumpCounters(); -#endif -#endif -} - -static void SetJsFlags(JNIEnv *env, jobject obj, jstring flags) -{ -#if USE(V8) - WTF::String flagsString = jstringToWtfString(env, flags); - WTF::CString utf8String = flagsString.utf8(); - WebCore::ScriptController::setFlags(utf8String.data(), utf8String.length()); -#endif -} - - -// Called from the Java side to set a new quota for the origin or new appcache -// max size in response to a notification that the original quota was exceeded or -// that the appcache has reached its maximum size. -static void SetNewStorageLimit(JNIEnv* env, jobject obj, jlong quota) { -#if ENABLE(DATABASE) || ENABLE(OFFLINE_WEB_APPLICATIONS) - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - Frame* frame = viewImpl->mainFrame(); - - // The main thread is blocked awaiting this response, so now we can wake it - // up. - ChromeClientAndroid* chromeC = static_cast(frame->page()->chrome()->client()); - chromeC->wakeUpMainThreadWithNewQuota(quota); -#endif -} - -// 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); - Frame* frame = viewImpl->mainFrame(); - - ChromeClientAndroid* chromeClient = static_cast(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 - WebCore::SchemeRegistry::registerURLSchemeAsLocal(jstringToWtfString(env, scheme)); -} - -static bool FocusBoundsChanged(JNIEnv* env, jobject obj) -{ - return GET_NATIVE_VIEW(env, obj)->focusBoundsChanged(); -} - -static void Pause(JNIEnv* env, jobject obj) -{ - // 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(); - ChromeClientAndroid* chromeClientAndroid = static_cast(chromeClient); - chromeClientAndroid->storeGeolocationPermissions(); - - Frame* mainFrame = GET_NATIVE_VIEW(env, obj)->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(); - - ANPEvent event; - SkANP::InitEvent(&event, kLifecycle_ANPEventType); - event.data.lifecycle.action = kPause_ANPLifecycleAction; - GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event); - - GET_NATIVE_VIEW(env, obj)->setIsPaused(true); -} - -static void Resume(JNIEnv* env, jobject obj) -{ - Frame* mainFrame = GET_NATIVE_VIEW(env, obj)->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(); - - ANPEvent event; - SkANP::InitEvent(&event, kLifecycle_ANPEventType); - event.data.lifecycle.action = kResume_ANPLifecycleAction; - GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event); - - GET_NATIVE_VIEW(env, obj)->setIsPaused(false); -} - -static void FreeMemory(JNIEnv* env, jobject obj) -{ - ANPEvent event; - SkANP::InitEvent(&event, kLifecycle_ANPEventType); - event.data.lifecycle.action = kFreeMemory_ANPLifecycleAction; - GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event); -} - -static void ProvideVisitedHistory(JNIEnv *env, jobject obj, jobject hist) -{ - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); - - jobjectArray array = static_cast(hist); - - jsize len = env->GetArrayLength(array); - for (jsize i = 0; i < len; i++) { - jstring item = static_cast(env->GetObjectArrayElement(array, i)); - const UChar* str = static_cast(env->GetStringChars(item, 0)); - jsize len = env->GetStringLength(item); - viewImpl->addVisitedLink(str, len); - env->ReleaseStringChars(item, str); - env->DeleteLocalRef(item); - } -} - -// Notification from the UI thread that the plugin's full-screen surface has been discarded -static void FullScreenPluginHidden(JNIEnv* env, jobject obj, jint npp) -{ - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - PluginWidgetAndroid* plugin = viewImpl->getPluginWidget((NPP)npp); - if (plugin) - plugin->exitFullScreen(false); -} - -static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj) -{ - int L, T, R, B; - GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B); - return WebCore::IntRect(L, T, R - L, B - T); -} - -static bool ValidNodeAndBounds(JNIEnv *env, jobject obj, int frame, int node, - jobject rect) -{ - IntRect nativeRect = jrect_to_webrect(env, rect); - return GET_NATIVE_VIEW(env, obj)->validNodeAndBounds( - reinterpret_cast(frame), - reinterpret_cast(node), nativeRect); -} - -static jobject GetTouchHighlightRects(JNIEnv* env, jobject obj, jint x, jint y, jint slop) -{ - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - if (!viewImpl) - return 0; - Vector 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, "", "(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, "", "(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].right(), rects[i].bottom()); - if (rect) { - env->CallBooleanMethod(array, add, rect); - env->DeleteLocalRef(rect); - } - } - - env->DeleteLocalRef(rectClass); - env->DeleteLocalRef(arrayClass); - return array; -} - -static void AutoFillForm(JNIEnv* env, jobject obj, jint queryId) -{ -#if ENABLE(WEB_AUTOFILL) - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - if (!viewImpl) - return; - - WebCore::Frame* frame = viewImpl->mainFrame(); - if (frame) { - EditorClientAndroid* editorC = static_cast(frame->page()->editorClient()); - WebAutoFill* autoFill = editorC->getAutoFill(); - autoFill->fillFormFields(queryId); - } -#endif -} - -static void ScrollRenderLayer(JNIEnv* env, jobject obj, jint layer, jobject jRect) -{ - SkRect rect; - GraphicsJNI::jrect_to_rect(env, jRect, &rect); - GET_NATIVE_VIEW(env, obj)->scrollRenderLayer(layer, rect); -} - -// ---------------------------------------------------------------------------- - -/* - * JNI registration. - */ -static JNINativeMethod gJavaWebViewCoreMethods[] = { - { "nativeClearContent", "()V", - (void*) ClearContent }, - { "nativeFocusBoundsChanged", "()Z", - (void*) FocusBoundsChanged } , - { "nativeKey", "(IIIZZZZ)Z", - (void*) Key }, - { "nativeClick", "(IIZ)V", - (void*) Click }, - { "nativeContentInvalidateAll", "()V", - (void*) ContentInvalidateAll }, - { "nativeSendListBoxChoices", "([ZI)V", - (void*) SendListBoxChoices }, - { "nativeSendListBoxChoice", "(I)V", - (void*) SendListBoxChoice }, - { "nativeSetSize", "(IIIFIIIIZ)V", - (void*) SetSize }, - { "nativeSetScrollOffset", "(IZII)V", - (void*) SetScrollOffset }, - { "nativeSetGlobalBounds", "(IIII)V", - (void*) SetGlobalBounds }, - { "nativeSetSelection", "(II)V", - (void*) SetSelection } , - { "nativeModifySelection", "(II)Ljava/lang/String;", - (void*) ModifySelection }, - { "nativeDeleteSelection", "(III)V", - (void*) DeleteSelection } , - { "nativeReplaceTextfieldText", "(IILjava/lang/String;III)V", - (void*) ReplaceTextfieldText } , - { "nativeMoveFocus", "(II)V", - (void*) MoveFocus }, - { "nativeMoveMouse", "(III)V", - (void*) MoveMouse }, - { "nativeMoveMouseIfLatest", "(IIII)V", - (void*) MoveMouseIfLatest }, - { "passToJs", "(ILjava/lang/String;IIZZZZ)V", - (void*) PassToJs }, - { "nativeScrollFocusedTextInput", "(FI)V", - (void*) ScrollFocusedTextInput }, - { "nativeSetFocusControllerActive", "(Z)V", - (void*) SetFocusControllerActive }, - { "nativeSaveDocumentState", "(I)V", - (void*) SaveDocumentState }, - { "nativeFindAddress", "(Ljava/lang/String;Z)Ljava/lang/String;", - (void*) FindAddress }, - { "nativeHandleTouchEvent", "(I[I[I[IIII)Z", - (void*) HandleTouchEvent }, - { "nativeTouchUp", "(IIIII)V", - (void*) TouchUp }, - { "nativeRetrieveHref", "(II)Ljava/lang/String;", - (void*) RetrieveHref }, - { "nativeRetrieveAnchorText", "(II)Ljava/lang/String;", - (void*) RetrieveAnchorText }, - { "nativeRetrieveImageSource", "(II)Ljava/lang/String;", - (void*) RetrieveImageSource }, - { "nativeStopPaintingCaret", "()V", - (void*) StopPaintingCaret }, - { "nativeUpdateFrameCache", "()V", - (void*) UpdateFrameCache }, - { "nativeGetContentMinPrefWidth", "()I", - (void*) GetContentMinPrefWidth }, - { "nativeUpdateLayers", "(Landroid/graphics/Region;)I", - (void*) UpdateLayers }, - { "nativeRecordContent", "(Landroid/graphics/Region;Landroid/graphics/Point;)I", - (void*) RecordContent }, - { "setViewportSettingsFromNative", "()V", - (void*) SetViewportSettingsFromNative }, - { "nativeSplitContent", "(I)V", - (void*) SplitContent }, - { "nativeSetBackgroundColor", "(I)V", - (void*) SetBackgroundColor }, - { "nativeRegisterURLSchemeAsLocal", "(Ljava/lang/String;)V", - (void*) RegisterURLSchemeAsLocal }, - { "nativeDumpDomTree", "(Z)V", - (void*) DumpDomTree }, - { "nativeDumpRenderTree", "(Z)V", - (void*) DumpRenderTree }, - { "nativeDumpNavTree", "()V", - (void*) DumpNavTree }, - { "nativeDumpV8Counters", "()V", - (void*) DumpV8Counters }, - { "nativeSetNewStorageLimit", "(J)V", - (void*) SetNewStorageLimit }, - { "nativeGeolocationPermissionsProvide", "(Ljava/lang/String;ZZ)V", - (void*) GeolocationPermissionsProvide }, - { "nativePause", "()V", (void*) Pause }, - { "nativeResume", "()V", (void*) Resume }, - { "nativeFreeMemory", "()V", (void*) FreeMemory }, - { "nativeSetJsFlags", "(Ljava/lang/String;)V", (void*) SetJsFlags }, - { "nativeRequestLabel", "(II)Ljava/lang/String;", - (void*) RequestLabel }, - { "nativeRevealSelection", "()V", (void*) RevealSelection }, - { "nativeUpdateFrameCacheIfLoading", "()V", - (void*) UpdateFrameCacheIfLoading }, - { "nativeProvideVisitedHistory", "([Ljava/lang/String;)V", - (void*) ProvideVisitedHistory }, - { "nativeFullScreenPluginHidden", "(I)V", - (void*) FullScreenPluginHidden }, - { "nativeValidNodeAndBounds", "(IILandroid/graphics/Rect;)Z", - (void*) ValidNodeAndBounds }, - { "nativeGetTouchHighlightRects", "(III)Ljava/util/ArrayList;", - (void*) GetTouchHighlightRects }, - { "nativeAutoFillForm", "(I)V", - (void*) AutoFillForm }, - { "nativeScrollLayer", "(ILandroid/graphics/Rect;)V", - (void*) ScrollRenderLayer }, -}; - -int registerWebViewCore(JNIEnv* env) -{ - jclass widget = env->FindClass("android/webkit/WebViewCore"); - LOG_ASSERT(widget, - "Unable to find class android/webkit/WebViewCore"); - gWebViewCoreFields.m_nativeClass = env->GetFieldID(widget, "mNativeClass", - "I"); - LOG_ASSERT(gWebViewCoreFields.m_nativeClass, - "Unable to find android/webkit/WebViewCore.mNativeClass"); - gWebViewCoreFields.m_viewportWidth = env->GetFieldID(widget, - "mViewportWidth", "I"); - LOG_ASSERT(gWebViewCoreFields.m_viewportWidth, - "Unable to find android/webkit/WebViewCore.mViewportWidth"); - gWebViewCoreFields.m_viewportHeight = env->GetFieldID(widget, - "mViewportHeight", "I"); - LOG_ASSERT(gWebViewCoreFields.m_viewportHeight, - "Unable to find android/webkit/WebViewCore.mViewportHeight"); - gWebViewCoreFields.m_viewportInitialScale = env->GetFieldID(widget, - "mViewportInitialScale", "I"); - LOG_ASSERT(gWebViewCoreFields.m_viewportInitialScale, - "Unable to find android/webkit/WebViewCore.mViewportInitialScale"); - gWebViewCoreFields.m_viewportMinimumScale = env->GetFieldID(widget, - "mViewportMinimumScale", "I"); - LOG_ASSERT(gWebViewCoreFields.m_viewportMinimumScale, - "Unable to find android/webkit/WebViewCore.mViewportMinimumScale"); - gWebViewCoreFields.m_viewportMaximumScale = env->GetFieldID(widget, - "mViewportMaximumScale", "I"); - LOG_ASSERT(gWebViewCoreFields.m_viewportMaximumScale, - "Unable to find android/webkit/WebViewCore.mViewportMaximumScale"); - gWebViewCoreFields.m_viewportUserScalable = env->GetFieldID(widget, - "mViewportUserScalable", "Z"); - LOG_ASSERT(gWebViewCoreFields.m_viewportUserScalable, - "Unable to find android/webkit/WebViewCore.mViewportUserScalable"); - gWebViewCoreFields.m_viewportDensityDpi = env->GetFieldID(widget, - "mViewportDensityDpi", "I"); - LOG_ASSERT(gWebViewCoreFields.m_viewportDensityDpi, - "Unable to find android/webkit/WebViewCore.mViewportDensityDpi"); - gWebViewCoreFields.m_webView = env->GetFieldID(widget, - "mWebView", "Landroid/webkit/WebView;"); - LOG_ASSERT(gWebViewCoreFields.m_webView, - "Unable to find android/webkit/WebViewCore.mWebView"); - gWebViewCoreFields.m_drawIsPaused = env->GetFieldID(widget, - "mDrawIsPaused", "Z"); - LOG_ASSERT(gWebViewCoreFields.m_drawIsPaused, - "Unable to find android/webkit/WebViewCore.mDrawIsPaused"); - gWebViewCoreFields.m_lowMemoryUsageMb = env->GetFieldID(widget, "mLowMemoryUsageThresholdMb", "I"); - gWebViewCoreFields.m_highMemoryUsageMb = env->GetFieldID(widget, "mHighMemoryUsageThresholdMb", "I"); - gWebViewCoreFields.m_highUsageDeltaMb = env->GetFieldID(widget, "mHighUsageDeltaMb", "I"); - - gWebViewCoreStaticMethods.m_isSupportedMediaMimeType = - env->GetStaticMethodID(widget, "isSupportedMediaMimeType", "(Ljava/lang/String;)Z"); - LOG_FATAL_IF(!gWebViewCoreStaticMethods.m_isSupportedMediaMimeType, - "Could not find static method isSupportedMediaMimeType from WebViewCore"); - - env->DeleteLocalRef(widget); - - return jniRegisterNativeMethods(env, "android/webkit/WebViewCore", - gJavaWebViewCoreMethods, NELEM(gJavaWebViewCoreMethods)); -} - -} /* namespace android */ diff --git a/WebKit/android/jni/WebViewCore.h b/WebKit/android/jni/WebViewCore.h deleted file mode 100644 index 8d8f303..0000000 --- a/WebKit/android/jni/WebViewCore.h +++ /dev/null @@ -1,714 +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 WEBVIEWCORE_H -#define WEBVIEWCORE_H - -#include "CacheBuilder.h" -#include "CachedHistory.h" -#include "DeviceMotionAndOrientationManager.h" -#include "DOMSelection.h" -#include "FileChooser.h" -#include "PictureSet.h" -#include "PlatformGraphicsContext.h" -#include "SkColor.h" -#include "SkTDArray.h" -#include "SkRegion.h" -#include "Timer.h" -#include "WebCoreRefObject.h" -#include "WebCoreJni.h" -#include "WebRequestContext.h" -#include "android_npapi.h" - -#include -#include -#include - -namespace WebCore { - class Color; - class FrameView; - class HTMLAnchorElement; - class HTMLElement; - class HTMLImageElement; - class HTMLSelectElement; - class RenderPart; - class RenderText; - class Node; - class PlatformKeyboardEvent; - class QualifiedName; - class RenderTextControl; - class ScrollView; - class TimerBase; - class PageGroup; -} - -#if USE(ACCELERATED_COMPOSITING) -namespace WebCore { - class GraphicsLayerAndroid; -} -#endif - -namespace WebCore { - class BaseLayerAndroid; -} - -struct PluginWidgetAndroid; -class SkPicture; -class SkIRect; - -namespace android { - - enum Direction { - DIRECTION_BACKWARD = 0, - DIRECTION_FORWARD = 1 - }; - - enum NavigationAxis { - AXIS_CHARACTER = 0, - AXIS_WORD = 1, - AXIS_SENTENCE = 2, - AXIS_HEADING = 3, - AXIS_SIBLING = 4, - AXIS_PARENT_FIRST_CHILD = 5, - AXIS_DOCUMENT = 6 - }; - - class CachedFrame; - class CachedNode; - class CachedRoot; - class ListBoxReply; - - class WebCoreReply : public WebCoreRefObject { - public: - virtual ~WebCoreReply() {} - - virtual void replyInt(int value) { - SkDEBUGF(("WebCoreReply::replyInt(%d) not handled\n", value)); - } - - virtual void replyIntArray(const int* array, int count) { - SkDEBUGF(("WebCoreReply::replyIntArray() not handled\n")); - } - // add more replyFoo signatures as needed - }; - - // one instance of WebViewCore per page for calling into Java's WebViewCore - class WebViewCore : public WebCoreRefObject { - public: - /** - * Initialize the native WebViewCore with a JNI environment, a Java - * WebViewCore object and the main frame. - */ - WebViewCore(JNIEnv* env, jobject javaView, WebCore::Frame* mainframe); - ~WebViewCore(); - - // helper function - static WebViewCore* getWebViewCore(const WebCore::FrameView* view); - static WebViewCore* getWebViewCore(const WebCore::ScrollView* view); - - // Followings are called from native WebCore to Java - - /** - * Notification that a form was blurred. Pass a message to hide the - * keyboard if it was showing for that Node. - * @param Node The Node that blurred. - */ - void formDidBlur(const WebCore::Node*); - void focusNodeChanged(const WebCore::Node*); - - /** - * Scroll to an absolute position. - * @param x The x coordinate. - * @param y The y coordinate. - * @param animate If it is true, animate to the new scroll position - * - * This method calls Java to trigger a gradual scroll event. - */ - void scrollTo(int x, int y, bool animate = false); - - /** - * Record the invalid rectangle - */ - void contentInvalidate(const WebCore::IntRect &rect); - void contentInvalidateAll(); - - /** - * Satisfy any outstanding invalidates, so that the current state - * of the DOM is drawn. - */ - void contentDraw(); - - /** - * copy the layers to the UI side - */ - void layersDraw(); - -#if USE(ACCELERATED_COMPOSITING) - GraphicsLayerAndroid* graphicsRootLayer() const; -#endif - - /** Invalidate the view/screen, NOT the content/DOM, but expressed in - * content/DOM coordinates (i.e. they need to eventually be scaled, - * by webview into view.java coordinates - */ - void viewInvalidate(const WebCore::IntRect& rect); - - /** - * Invalidate part of the content that may be offscreen at the moment - */ - void offInvalidate(const WebCore::IntRect &rect); - - /** - * Called by webcore when the progress indicator is done - * used to rebuild and display any changes in focus - */ - void notifyProgressFinished(); - - /** - * Notify the view that WebCore did its first layout. - */ - void didFirstLayout(); - - /** - * Notify the view to update the viewport. - */ - void updateViewport(); - - /** - * Notify the view to restore the screen width, which in turn restores - * the scale. Also restore the scale for the text wrap. - */ - void restoreScale(float scale, float textWrapScale); - - /** - * Tell the java side to update the focused textfield - * @param pointer Pointer to the node for the input field. - * @param changeToPassword If true, we are changing the textfield to - * a password field, and ignore the String - * @param text If changeToPassword is false, this is the new text that - * should go into the textfield. - */ - void updateTextfield(WebCore::Node* pointer, - bool changeToPassword, const WTF::String& text); - - /** - * Tell the java side to update the current selection in the focused - * textfield to the WebTextView. This function finds the currently - * focused textinput, and passes its selection to java. - * If there is no focus, or it is not a text input, this does nothing. - */ - void updateTextSelection(); - - void clearTextEntry(); - // JavaScript support - void jsAlert(const WTF::String& url, const WTF::String& text); - bool jsConfirm(const WTF::String& url, const WTF::String& text); - bool jsPrompt(const WTF::String& url, const WTF::String& message, - const WTF::String& defaultValue, WTF::String& result); - bool jsUnload(const WTF::String& url, const WTF::String& message); - bool jsInterrupt(); - - /** - * Tell the Java side that the origin has exceeded its database quota. - * @param url The URL of the page that caused the quota overflow - * @param databaseIdentifier the id of the database that caused the - * quota overflow. - * @param currentQuota The current quota for the origin - * @param estimatedSize The estimated size of the database - */ - void exceededDatabaseQuota(const WTF::String& url, - const WTF::String& databaseIdentifier, - const unsigned long long currentQuota, - const unsigned long long estimatedSize); - - /** - * Tell the Java side that the appcache has exceeded its max size. - * @param spaceNeeded is the amount of disk space that would be needed - * in order for the last appcache operation to succeed. - */ - void reachedMaxAppCacheSize(const unsigned long long spaceNeeded); - - /** - * Set up the PageGroup's idea of which links have been visited, - * with the browser history. - * @param group the object to deliver the links to. - */ - void populateVisitedLinks(WebCore::PageGroup*); - - /** - * Instruct the browser to show a Geolocation permission prompt for the - * specified origin. - * @param origin The origin of the frame requesting Geolocation - * permissions. - */ - void geolocationPermissionsShowPrompt(const WTF::String& origin); - /** - * Instruct the browser to hide the Geolocation permission prompt. - */ - void geolocationPermissionsHidePrompt(); - - jobject getDeviceMotionService(); - jobject getDeviceOrientationService(); - - void addMessageToConsole(const String& message, unsigned int lineNumber, const String& sourceID, int msgLevel); - - /** - * Tell the Java side of the scrollbar mode - */ - void setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode verticalMode); - - // - // Followings support calls from Java to native WebCore - // - - WTF::String retrieveHref(int x, int y); - WTF::String retrieveAnchorText(int x, int y); - WTF::String retrieveImageSource(int x, int y); - WTF::String requestLabel(WebCore::Frame* , WebCore::Node* ); - - // If the focus is a textfield (), textarea, or contentEditable, - // scroll the selection on screen (if necessary). - void revealSelection(); - // Create a single picture to represent the drawn DOM (used by navcache) - void recordPicture(SkPicture* picture); - - void moveFocus(WebCore::Frame* frame, WebCore::Node* node); - void moveMouse(WebCore::Frame* frame, int x, int y); - void moveMouseIfLatest(int moveGeneration, - WebCore::Frame* frame, int x, int y); - - // set the scroll amount that webview.java is currently showing - void setScrollOffset(int moveGeneration, bool sendScrollEvent, int dx, int dy); - - void setGlobalBounds(int x, int y, int h, int v); - - void setSizeScreenWidthAndScale(int width, int height, int screenWidth, - float scale, int realScreenWidth, int screenHeight, int anchorX, - int anchorY, bool ignoreHeight); - - /** - * Handle key events from Java. - * @return Whether keyCode was handled by this class. - */ - bool key(const WebCore::PlatformKeyboardEvent& event); - - /** - * Handle (trackball) click event / dpad center press from Java. - * Also used when typing into an unfocused textfield, in which case 'fake' - * will be true. - */ - void click(WebCore::Frame* frame, WebCore::Node* node, bool fake); - - /** - * Handle touch event - */ - bool handleTouchEvent(int action, Vector& ids, Vector& points, int actionIndex, int metaState); - - /** - * Handle motionUp event from the UI thread (called touchUp in the - * WebCore thread). - * @param touchGeneration Generation number for touches so we can ignore - * touches when a newer one has been generated. - * @param frame Pointer to Frame containing the node that was touched. - * @param node Pointer to Node that was touched. - * @param x x-position of the touch. - * @param y y-position of the touch. - */ - void touchUp(int touchGeneration, WebCore::Frame* frame, - WebCore::Node* node, int x, int y); - - /** - * Sets the index of the label from a popup - */ - void popupReply(int index); - void popupReply(const int* array, int count); - - /** - * Delete text from start to end in the focused textfield. - * If start == end, set the selection, but perform no deletion. - * If there is no focus, silently fail. - * If start and end are out of order, swap them. - */ - void deleteSelection(int start, int end, int textGeneration); - - /** - * Set the selection of the currently focused textfield to (start, end). - * If start and end are out of order, swap them. - */ - void setSelection(int start, int end); - - /** - * Modifies the current selection. - * - * Note: Accessibility support. - * - * direction - The direction in which to alter the selection. - * granularity - The granularity of the selection modification. - * - * returns - The selected HTML as a string. This is not a well formed - * HTML, rather the selection annotated with the tags of all - * intermediary elements it crosses. - */ - String modifySelection(const int direction, const int granularity); - - /** - * Moves the selection to the given node in a given frame i.e. selects that node. - * - * Note: Accessibility support. - * - * frame - The frame in which to select is the node to be selected. - * node - The node to be selected. - * - * returns - The selected HTML as a string. This is not a well formed - * HTML, rather the selection annotated with the tags of all - * intermediary elements it crosses. - */ - String moveSelection(WebCore::Frame* frame, WebCore::Node* node); - - /** - * In the currently focused textfield, replace the characters from oldStart to oldEnd - * (if oldStart == oldEnd, this will be an insert at that position) with replace, - * and set the selection to (start, end). - */ - void replaceTextfieldText(int oldStart, - int oldEnd, const WTF::String& replace, int start, int end, - int textGeneration); - void passToJs(int generation, - const WTF::String& , const WebCore::PlatformKeyboardEvent& ); - /** - * Scroll the focused textfield to (x, y) in document space - */ - void scrollFocusedTextInput(float x, int y); - /** - * Set the FocusController's active and focused states, so that - * the caret will draw (true) or not. - */ - void setFocusControllerActive(bool active); - - void saveDocumentState(WebCore::Frame* frame); - - void addVisitedLink(const UChar*, int); - - // TODO: I don't like this hack but I need to access the java object in - // order to send it as a parameter to java - AutoJObject getJavaObject(); - - // Return the parent WebView Java object associated with this - // WebViewCore. - 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 - pageflipping bitmap. - */ - void addPlugin(PluginWidgetAndroid*); - void removePlugin(PluginWidgetAndroid*); - // returns true if the pluginwidgit is in our active list - bool isPlugin(PluginWidgetAndroid*) const; - void invalPlugin(PluginWidgetAndroid*); - void drawPlugins(); - - // send the current screen size/zoom to all of the plugins in our list - void sendPluginVisibleScreen(); - - // send onLoad event to plugins who are descendents of the given frame - void notifyPluginsOnFrameLoad(const Frame*); - - // gets a rect representing the current on-screen portion of the document - void getVisibleScreen(ANPRectI&); - - // send this event to all of the plugins in our list - void sendPluginEvent(const ANPEvent&); - - // 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); - - void requestKeyboardWithSelection(const WebCore::Node*, int selStart, int selEnd); - // Notify the Java side that webkit is requesting a keyboard - void requestKeyboard(bool showKeyboard); - - // Generates a class loader that contains classes from the plugin's apk - jclass getPluginClass(const WTF::String& libName, const char* className); - - // Creates a full screen surface for a plugin - void showFullScreenPlugin(jobject webkitPlugin, NPP npp); - - // Instructs the UI thread to discard the plugin's full-screen surface - void hideFullScreenPlugin(); - - // Creates a childView for the plugin but does not attach to the view hierarchy - jobject createSurface(jobject view); - - // Adds the plugin's view (aka surface) to the view hierarchy - jobject addSurface(jobject view, int x, int y, int width, int height); - - // Updates a Surface coordinates and dimensions for a plugin - void updateSurface(jobject childView, int x, int y, int width, int height); - - // Destroys a SurfaceView for a plugin - void destroySurface(jobject childView); - - // Returns the context (android.content.Context) of the WebView - jobject getContext(); - - // Manages requests to keep the screen on while the WebView is visible - void keepScreenOn(bool screenOn); - - bool validNodeAndBounds(Frame* , Node* , const IntRect& ); - - // Make the rect (left, top, width, height) visible. If it can be fully - // fit, center it on the screen. Otherwise make sure the point specified - // by (left + xPercentInDoc * width, top + yPercentInDoc * height) - // pinned at the screen position (xPercentInView, yPercentInView). - void showRect(int left, int top, int width, int height, int contentWidth, - int contentHeight, float xPercentInDoc, float xPercentInView, - float yPercentInDoc, float yPercentInView); - - // Scale the rect (x, y, width, height) to make it just fit and centered - // in the current view. - 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 getTouchHighlightRects(int x, int y, int slop); - - // Open a file chooser for selecting a file to upload - void openFileChooser(PassRefPtr ); - - // reset the picture set to empty - void clearContent(); - - bool focusBoundsChanged(); - - // record the inval area, and the picture size - BaseLayerAndroid* recordContent(SkRegion* , SkIPoint* ); - - // This creates a new BaseLayerAndroid by copying the current m_content - // and doing a copy of the layers. The layers' content may be updated - // as we are calling layersSync(). - BaseLayerAndroid* createBaseLayer(); - - int textWrapWidth() const { return m_textWrapWidth; } - float scale() const { return m_scale; } - float textWrapScale() const { return m_screenWidth * m_scale / m_textWrapWidth; } - WebCore::Frame* mainFrame() const { return m_mainFrame; } - void updateCursorBounds(const CachedRoot* root, - const CachedFrame* cachedFrame, const CachedNode* cachedNode); - void updateFrameCacheIfLoading(); - - // utility to split slow parts of the picture set - void splitContent(PictureSet*); - - void notifyWebAppCanBeInstalled(); - -#if ENABLE(VIDEO) - void enterFullscreenForVideoLayer(int layerId, const WTF::String& url); -#endif - - void setWebTextViewAutoFillable(int queryId, const string16& previewSummary); - - DeviceMotionAndOrientationManager* deviceMotionAndOrientationManager() { return &m_deviceMotionAndOrientationManager; } - - 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); - // call only from webkit thread (like add/remove), return true if inst - // is still alive - static bool isInstance(WebViewCore*); - // if there exists at least one WebViewCore instance then we return the - // application context, otherwise NULL is returned. - static jobject getApplicationContext(); - // Check whether a media mimeType is supported in Android media framework. - static bool isSupportedMediaMimeType(const WTF::String& mimeType); - - // 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; - // These two fields go together: we use the mutex to protect access to - // m_buttons, so that we, and webview.cpp can look/modify the m_buttons - // field safely from our respective threads - static Mutex gButtonMutex; - WTF::Vector m_buttons; - // end of shared members - - // internal functions - private: - CacheBuilder& cacheBuilder(); - WebCore::Node* currentFocus(); - // Compare the new set of buttons to the old one. All of the new - // buttons either replace our old ones or should be added to our list. - // Then check the old buttons to see if any are no longer needed. - void updateButtonList(WTF::Vector* buttons); - void reset(bool fromConstructor); - // 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); - - friend class ListBoxReply; - struct JavaGlue; - struct JavaGlue* m_javaGlue; - WebCore::Frame* m_mainFrame; - WebCoreReply* m_popupReply; - WebCore::Node* m_lastFocused; - WebCore::IntRect m_lastFocusedBounds; - int m_blurringNodePointer; - int m_lastFocusedSelStart; - int m_lastFocusedSelEnd; - PictureSet m_content; // the set of pictures to draw - SkRegion m_addInval; // the accumulated inval region (not yet drawn) - SkRegion m_rebuildInval; // the accumulated region for rebuilt pictures - // Used in passToJS to avoid updating the UI text field until after the - // key event has been processed. - bool m_blockTextfieldUpdates; - bool m_focusBoundsChanged; - bool m_skipContentDraw; - // Passed in with key events to know when they were generated. Store it - // with the cache so that we can ignore stale text changes. - int m_textGeneration; - CachedRoot* m_temp; - SkPicture* m_tempPict; - int m_maxXScroll; - int m_maxYScroll; - int m_scrollOffsetX; // webview.java's current scroll in X - int m_scrollOffsetY; // webview.java's current scroll in Y - WebCore::IntPoint m_mousePos; - bool m_frameCacheOutOfDate; - bool m_progressDone; - int m_lastPassed; - int m_lastVelocity; - 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; - float m_scale; - unsigned m_domtree_version; - bool m_check_domtree_version; - PageGroup* m_groupForVisitedLinks; - bool m_isPaused; - int m_cacheMode; - bool m_shouldPaintCaret; - - SkTDArray m_plugins; - WebCore::Timer m_pluginInvalTimer; - void pluginInvalTimerFired(WebCore::Timer*) { - this->drawPlugins(); - } - int m_screenOnCounter; - - void doMaxScroll(CacheBuilder::Direction dir); - SkPicture* rebuildPicture(const SkIRect& inval); - void rebuildPictureSet(PictureSet* ); - void sendNotifyProgressFinished(); - /* - * Handle a mouse click, either from a touch or trackball press. - * @param frame Pointer to the Frame containing the node that was clicked on. - * @param node Pointer to the Node that was clicked on. - * @param fake This is a fake mouse click, used to put a textfield into focus. Do not - * open the IME. - */ - bool handleMouseClick(WebCore::Frame*, WebCore::Node*, bool fake); - WebCore::HTMLAnchorElement* retrieveAnchorElement(int x, int y); - WebCore::HTMLElement* retrieveElement(int x, int y, - const WebCore::QualifiedName& ); - WebCore::HTMLImageElement* retrieveImageElement(int x, int y); - // below are members responsible for accessibility support - String modifySelectionTextNavigationAxis(DOMSelection* selection, int direction, int granularity); - String modifySelectionDomNavigationAxis(DOMSelection* selection, int direction, int granularity); - Text* traverseNextContentTextNode(Node* fromNode, Node* toNode ,int direction); - bool isVisible(Node* node); - bool isHeading(Node* node); - String formatMarkup(DOMSelection* selection); - void selectAt(int x, int y); - Node* m_currentNodeDomNavigationAxis; - void scrollNodeIntoView(Frame* frame, Node* node); - bool isContentTextNode(Node* node); - Node* getIntermediaryInputElement(Node* fromNode, Node* toNode, int direction); - bool isContentInputElement(Node* node); - bool isDescendantOf(Node* parent, Node* node); - void advanceAnchorNode(DOMSelection* selection, int direction, String& markup, bool ignoreFirstNode, ExceptionCode& ec); - Node* getNextAnchorNode(Node* anchorNode, bool skipFirstHack, int direction); - Node* getImplicitBoundaryNode(Node* node, unsigned offset, int direction); - -#if ENABLE(TOUCH_EVENTS) - bool m_forwardingTouchEvents; -#endif -#if DEBUG_NAV_UI - uint32_t m_now; -#endif - DeviceMotionAndOrientationManager m_deviceMotionAndOrientationManager; -#if USE(CHROME_NETWORK_STACK) - scoped_refptr m_webRequestContext; -#endif - - // called from constructor, to add this to a global list - static void addInstance(WebViewCore*); - // called from destructor, to remove this from a global list - static void removeInstance(WebViewCore*); - }; - -} // namespace android - -#endif // WEBVIEWCORE_H diff --git a/WebKit/android/nav/CacheBuilder.cpp b/WebKit/android/nav/CacheBuilder.cpp deleted file mode 100644 index dc10f21..0000000 --- a/WebKit/android/nav/CacheBuilder.cpp +++ /dev/null @@ -1,3201 +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 - -#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(), false, false); -} - -#if DUMP_NAV_CACHE - -static bool hasEventListener(Node* node, const AtomicString& eventType) { - if (!node->isElementNode()) - return false; - Element* element = static_cast(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(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(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(node); - wideString(anchor->href()); - } else if (node->hasTagName(HTMLNames::imgTag)) { - HTMLImageElement* image = static_cast(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(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(renderer); - if (renderer->isRenderBlock() && renderBlock->hasColumns()) { - const RenderBox* box = static_cast(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 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(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& 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 tracker(1); // sentinel - { - FocusTracker* baseTracker = tracker.data(); - bzero(baseTracker, sizeof(FocusTracker)); - baseTracker->mCachedNodeIndex = -1; - } - WTF::Vector layerTracker(1); // sentinel - bzero(layerTracker.data(), sizeof(LayerTracker)); - WTF::Vector clipTracker(1); // sentinel - bzero(clipTracker.data(), sizeof(ClipColumnTracker)); - WTF::Vector tabIndexTracker(1); // sentinel - bzero(tabIndexTracker.data(), sizeof(TabIndexTracker)); - WTF::Vector 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(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 (node->hasTagName(HTMLNames::canvasTag)) - mPictureSetDisabled = true; - if (checkForPluginViewThatWantsFocus(nodeRenderer)) { - bounds = absBounds; - isUnclipped = true; - takesFocus = true; - type = PLUGIN_CACHEDNODETYPE; - goto keepNode; - } - // Only use the root contentEditable element - if (node->isContentEditable() && !node->parentOrHostNode()->isContentEditable()) { - 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(node); - if (input->isTextField()) { - if (input->readOnly()) - continue; - type = TEXT_INPUT_CACHEDNODETYPE; - cachedInput.init(); - cachedInput.setAutoComplete(input->autoComplete()); - 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(node); - if (area->readOnly()) - continue; - cachedInput.init(); - type = TEXT_INPUT_CACHEDNODETYPE; - cachedInput.setFormPointer(area->form()); - cachedInput.setIsTextArea(true); - 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(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(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.setNavableRects(); - 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(); - lastCached->setNavableRects(); - 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(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->getRect(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(renderer)->widget(); - if (widget == NULL) - return NULL; - if (widget->isFrameView() == false) - return NULL; - return static_cast(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(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(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(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(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 (layer->width() == 0 || layer->height() == 0) - 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->width(), layer->height()); - 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, - 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, false, false); -#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(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* result, IntRect* focusBounds) -{ - if (bounds.isEmpty()) - return true; - bounds.move(x, y); - if (bounds.right() <= 0 || bounds.bottom() <= 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* result, - int* imageCountPtr) -{ - WTF::Vector 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 - int left = bounds.x() + ((RenderBox*)renderer)->paddingLeft() - + ((RenderBox*)renderer)->borderLeft(); - int top = bounds.y() + ((RenderBox*)renderer)->paddingTop() - + ((RenderBox*)renderer)->borderTop(); - int right = bounds.right() - ((RenderBox*)renderer)->paddingRight() - - ((RenderBox*)renderer)->borderRight(); - int bottom = bounds.bottom() - ((RenderBox*)renderer)->paddingBottom() - - ((RenderBox*)renderer)->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* 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* 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/WebKit/android/nav/CacheBuilder.h b/WebKit/android/nav/CacheBuilder.h deleted file mode 100644 index d48a045..0000000 --- a/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 -#include - -#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* 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 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* 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* result); - static bool ConstructTextRects(Text* node, int start, - Text* last, int end, int x, int y, IntRect* focusBounds, - const IntRect& clip, WTF::Vector* 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, - 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/WebKit/android/nav/CachedColor.cpp b/WebKit/android/nav/CachedColor.cpp deleted file mode 100644 index c610022..0000000 --- a/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/WebKit/android/nav/CachedColor.h b/WebKit/android/nav/CachedColor.h deleted file mode 100644 index 4b39810..0000000 --- a/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/WebKit/android/nav/CachedDebug.h b/WebKit/android/nav/CachedDebug.h deleted file mode 100644 index 3d9e012..0000000 --- a/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 -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/WebKit/android/nav/CachedFrame.cpp b/WebKit/android/nav/CachedFrame.cpp deleted file mode 100644 index b26e24b..0000000 --- a/WebKit/android/nav/CachedFrame.cpp +++ /dev/null @@ -1,1494 +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.bottom() : prior.bottom(); - 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.right(); - int testRight = bestRect.right(); - if (right < testRight) - right = testRight; - width = right - left; - } else { - left = direction == LEFT ? bestRect.right() : prior.right(); - 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.bottom(); - int testBottom = bestRect.bottom(); - 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(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.right(), rect.bottom(), - testRect.x(), testRect.y(), testRect.right(), testRect.bottom()); - 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.right(), - cursorRect.bottom()); - 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->right() - testBounds.x(); break; - case RIGHT: distance = testBounds.right() - clip->x(); break; - case UP: distance = clip->bottom() - testBounds.y(); break; - case DOWN: distance = testBounds.bottom() - clip->y(); break; -#endif - default: - distance = 0; ASSERT(0); - } - 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(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(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.bottom(); - int testX = mNodeBounds.x(); - int testRight = mNodeBounds.right(); - setNavOverlap(navBounds.width(), navBounds.right() - 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.bottom() - mNodeBounds.bottom(); - setNavInclusion(testRight - navBounds.right(), 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.right(); - int testY = mNodeBounds.y(); - int testBottom = mNodeBounds.bottom(); - setNavOverlap(navBounds.height(), navBounds.bottom() - testY, - testBottom - navBounds.y()); - if (canBeReachedByAnotherDirection()) { - mNode->setCondition(CachedNode::BEST_DIRECTION); - return REJECT_TEST; - } - int inNavRight = navBounds.right() - mNodeBounds.right(); - 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.bottom()); - 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.right(); - int testY = mNodeBounds.y(); - int testBottom = mNodeBounds.bottom(); - setNavOverlap(navBounds.height(), navBounds.bottom() - 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.right() - mNodeBounds.right(); - setNavInclusion(testBottom - navBounds.bottom(), 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.bottom(); - int testX = mNodeBounds.x(); - int testRight = mNodeBounds.right(); - setNavOverlap(navBounds.width(), navBounds.right() - testX, - testRight - navBounds.x()); - if (canBeReachedByAnotherDirection()) { - mNode->setCondition(CachedNode::BEST_DIRECTION); - return REJECT_TEST; - } - int inNavBottom = navBounds.bottom() - mNodeBounds.bottom(); - 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.right()); - 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/WebKit/android/nav/CachedFrame.h b/WebKit/android/nav/CachedFrame.h deleted file mode 100644 index 039a0ee..0000000 --- a/WebKit/android/nav/CachedFrame.h +++ /dev/null @@ -1,285 +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 CachedFrame_H -#define CachedFrame_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(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().bottom(); } - 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().right(); } - 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 mCachedColors; - WTF::Vector mCachedNodes; - WTF::Vector mCachedFrames; - WTF::Vector mCachedTextInputs; -#if USE(ACCELERATED_COMPOSITING) - WTF::Vector 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 diff --git a/WebKit/android/nav/CachedHistory.cpp b/WebKit/android/nav/CachedHistory.cpp deleted file mode 100644 index 9066412..0000000 --- a/WebKit/android/nav/CachedHistory.cpp +++ /dev/null @@ -1,187 +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.bottom()) - mMinWorkingHorizontal = viewBounds.y(); - if (mMaxWorkingHorizontal > viewBounds.bottom() || - mMaxWorkingHorizontal <= viewBounds.y()) - mMaxWorkingHorizontal = viewBounds.bottom(); - if (mMinWorkingVertical < viewBounds.x() || - mMinWorkingVertical >= viewBounds.right()) - mMinWorkingVertical = viewBounds.x(); - if (mMaxWorkingVertical > viewBounds.right() || - mMaxWorkingVertical <= viewBounds.x()) - mMaxWorkingVertical = viewBounds.right(); -} - -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->bottom(); - } - if (lastAxis != CachedFrame::UP && navBounds->width() > 0) { - mMinWorkingVertical = navBounds->x(); - mMaxWorkingVertical = navBounds->right(); - } - } - 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/WebKit/android/nav/CachedHistory.h b/WebKit/android/nav/CachedHistory.h deleted file mode 100644 index e8c1ad9..0000000 --- a/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/WebKit/android/nav/CachedInput.cpp b/WebKit/android/nav/CachedInput.cpp deleted file mode 100644 index a6a57ef..0000000 --- a/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/WebKit/android/nav/CachedInput.h b/WebKit/android/nav/CachedInput.h deleted file mode 100644 index f7f9eea..0000000 --- a/WebKit/android/nav/CachedInput.h +++ /dev/null @@ -1,112 +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 setTextSize(float textSize) { mTextSize = textSize; } - 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 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/WebKit/android/nav/CachedLayer.cpp b/WebKit/android/nav/CachedLayer.cpp deleted file mode 100644 index 299f2d1..0000000 --- a/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(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(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 SkLayer* 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/WebKit/android/nav/CachedLayer.h b/WebKit/android/nav/CachedLayer.h deleted file mode 100644 index 3d963e0..0000000 --- a/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/WebKit/android/nav/CachedNode.cpp b/WebKit/android/nav/CachedNode.cpp deleted file mode 100644 index e3ba34d..0000000 --- a/WebKit/android/nav/CachedNode.cpp +++ /dev/null @@ -1,432 +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(parent->hasFrame(this)); - child->clearCursor(); - } - mIsCursor = false; -} - -bool CachedNode::Clip(const WebCore::IntRect& outer, WebCore::IntRect* inner, - WTF::Vector* 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* 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 = mNavableRects; - ASSERT(partMax > 0); - WebCore::IntRect bounds = mCursorRing[0]; - for (int partIndex = 1; 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 (mNavableRects <= 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->bottom(); - int unitLeft = unitBoundsPtr->x(); - int unitRight = unitBoundsPtr->right(); - WebCore::IntRect* testBoundsPtr = mCursorRing.begin() - 1; - while (++testBoundsPtr < unitBoundsEnd) { - if (unitBoundsPtr == testBoundsPtr) - continue; - int testTop = testBoundsPtr->y(); - int testBottom = testBoundsPtr->bottom(); - int testLeft = testBoundsPtr->x(); - int testRight = testBoundsPtr->right(); - 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->bottom()) - candidateTop = checkBoundsPtr->bottom(); - else if (candidateTop < checkBoundsPtr->y() && - candidateBottom <= checkBoundsPtr->bottom()) - candidateBottom = checkBoundsPtr->y(); - else - goto nextCheck; - } else { - if (candidateLeft >= checkBoundsPtr->x() && - candidateRight > checkBoundsPtr->right()) - candidateLeft = checkBoundsPtr->right(); - else if (candidateLeft < checkBoundsPtr->x() && - candidateRight <= checkBoundsPtr->right()) - 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(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* 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 = mNavableRects; - int innerMax = other->mNavableRects; - 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* 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 mNavableRects=%d;\n", b->mNavableRects); - 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/WebKit/android/nav/CachedNode.h b/WebKit/android/nav/CachedNode.h deleted file mode 100644 index f9bcbed..0000000 --- a/WebKit/android/nav/CachedNode.h +++ /dev/null @@ -1,247 +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 -#include - -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* 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* ) 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* ) 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 mNavableRects; } - 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& 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 setNavableRects() { mNavableRects = mCursorRing.size(); } - 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 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 mNavableRects; // FIXME: could be bitfield once I limit max number of rects - 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/WebKit/android/nav/CachedNodeType.h b/WebKit/android/nav/CachedNodeType.h deleted file mode 100644 index 8bc9328..0000000 --- a/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/WebKit/android/nav/CachedPrefix.h b/WebKit/android/nav/CachedPrefix.h deleted file mode 100644 index 73a5c2c..0000000 --- a/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 -#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/WebKit/android/nav/CachedRoot.cpp b/WebKit/android/nav/CachedRoot.cpp deleted file mode 100644 index 64bf19a..0000000 --- a/WebKit/android/nav/CachedRoot.cpp +++ /dev/null @@ -1,1813 +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& 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->right(), r->bottom()}; - 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 mLayers; - Vector 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(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(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(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(mBounder).startText(paint); - INHERITED::drawPosTextH(text, byteLength, xpos, constY, paint); - } - - virtual int save(SaveFlags flags) - { - RingCheck& bounder = static_cast(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(mBounder); - bounder.push(CommonCheck::kPushLayer_Type, getTotalClip().getBounds()); - return INHERITED::save(flags); - } - - virtual void restore() - { - RingCheck& bounder = static_cast(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.right(), - contentBounds.bottom(), - overBounds.x(), overBounds.y(), overBounds.right(), overBounds.bottom(), - mScrolledBounds.x(), mScrolledBounds.y(), mScrolledBounds.right(), - mScrolledBounds.bottom(), - mViewBounds.x(), mViewBounds.y(), mViewBounds.right(), - mViewBounds.bottom(), - bitBounds->x(), bitBounds->y(), bitBounds->right(), - bitBounds->bottom()); -} - - -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& 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.right(), bitBounds.bottom(), - nodeBounds.x(), nodeBounds.y(), nodeBounds.right(), nodeBounds.bottom(), - testBounds.x(), testBounds.y(), testBounds.right(), testBounds.bottom(), - 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 (mRootLayer) CachedLayer::Debug::printRootLayerAndroid(mRootLayer); -#endif - int best = INT_MAX; - bool inside = false; - (const_cast(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.right()); - setupScrolledBounds(); - // (line up) - mScrolledBounds.setHeight(mScrolledBounds.height() + mMaxYScroll); - int testTop = mScrolledBounds.y(); - int viewBottom = mViewBounds.bottom(); - const WebCore::IntRect& navBounds = mHistory->mNavBounds; - if (navBounds.isEmpty() == false && - navBounds.bottom() > viewBottom && viewBottom < mContents.height()) - return false; - if (navBounds.isEmpty() == false) { - int navTop = navBounds.y(); - int scrollBottom; - if (testTop < navTop && navTop < (scrollBottom = mScrolledBounds.bottom())) { - 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.bottom()); - setupScrolledBounds(); - mScrolledBounds.setX(mScrolledBounds.x() - mMaxXScroll); - mScrolledBounds.setWidth(mScrolledBounds.width() + mMaxXScroll); - int testRight = mScrolledBounds.right(); - 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.right(); - 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.right(), - 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.bottom(), 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.right() < newBounds.right()) - offsetX = mViewBounds.right() - mHistory->mNavBounds.right(); - if (mViewBounds.y() > newBounds.y()) - offsetY = mViewBounds.y() - mHistory->mNavBounds.y(); - else if (mViewBounds.bottom() < newBounds.bottom()) - offsetY = mViewBounds.bottom() - mHistory->mNavBounds.bottom(); - mHistory->mNavBounds.move(offsetX, offsetY); - } - mHistory->setDidFirstLayout(false); -} - -bool CachedRoot::innerRight(const CachedNode* test, BestData* bestData) const -{ - ASSERT(minWorkingHorizontal() >= mViewBounds.y()); - ASSERT(maxWorkingHorizontal() <= mViewBounds.bottom()); - setupScrolledBounds(); - // (align) - mScrolledBounds.setWidth(mScrolledBounds.width() + mMaxXScroll); - int testLeft = mScrolledBounds.x(); - int viewRight = mViewBounds.right(); - const WebCore::IntRect& navBounds = mHistory->mNavBounds; - if (navBounds.isEmpty() == false && - navBounds.right() > viewRight && viewRight < mContents.width()) - return false; - if (navBounds.isEmpty() == false) { - int navLeft = navBounds.x(); - int scrollRight; - if (testLeft < navLeft && navLeft < (scrollRight = mScrolledBounds.right())) { - 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.right()); - setupScrolledBounds(); - mScrolledBounds.setY(mScrolledBounds.y() - mMaxYScroll); - mScrolledBounds.setHeight(mScrolledBounds.height() + mMaxYScroll); - int testBottom = mScrolledBounds.bottom(); - 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.bottom(); - 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 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(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 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(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.right() <= mViewBounds.right(); - case UP: - *delta = -mMaxYScroll; - return newOutset.y() >= mViewBounds.y(); - case DOWN: - *delta = mMaxYScroll; - return newOutset.bottom() <= mViewBounds.bottom(); - 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 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/WebKit/android/nav/CachedRoot.h b/WebKit/android/nav/CachedRoot.h deleted file mode 100644 index 1f8b851..0000000 --- a/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; } - const 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/WebKit/android/nav/DrawExtra.h b/WebKit/android/nav/DrawExtra.h deleted file mode 100644 index 6716a65..0000000 --- a/WebKit/android/nav/DrawExtra.h +++ /dev/null @@ -1,48 +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 DrawExtra_h -#define DrawExtra_h - -class SkCanvas; - -namespace WebCore { - class IntRect; - class LayerAndroid; -} - -using namespace WebCore; - -namespace android { - -class DrawExtra { -public: - virtual ~DrawExtra() {} - virtual void draw(SkCanvas* , LayerAndroid* , IntRect* ) = 0; -}; - -} - -#endif diff --git a/WebKit/android/nav/FindCanvas.cpp b/WebKit/android/nav/FindCanvas.cpp deleted file mode 100644 index 2d310b3..0000000 --- a/WebKit/android/nav/FindCanvas.cpp +++ /dev/null @@ -1,699 +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 - -#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(); - 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 (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]; - // FIXME: this should test if the match in the layer is visible - if (info.isInLayer()) - return noBounds; - 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(); -} - -// 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* 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/WebKit/android/nav/FindCanvas.h b/WebKit/android/nav/FindCanvas.h deleted file mode 100644 index 76ee1e2..0000000 --- a/WebKit/android/nav/FindCanvas.h +++ /dev/null @@ -1,255 +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 -#include - -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. - bool isInLayer() const { return m_layerId >= 0; } - int layerId() const { return m_layerId; } - void set(const SkRegion& region, SkPicture* pic, int 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* detachMatches() { - WTF::Vector* 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* mMatches; - const UChar* mLowerText; - const UChar* mUpperText; - Vector mLowerReversed; - Vector mUpperReversed; - size_t mLength; - FindBounder mBounder; - int mNumFound; - SkScalar mOutset; - SkTDArray 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() { delete m_matches; } - void clearCurrentLocation() { m_hasCurrentLocation = false; } - IntRect currentMatchBounds() const; - int currentMatchIndex() const { return m_findIndex; } - bool currentMatchIsInLayer() const; - virtual void draw(SkCanvas* , LayerAndroid* , IntRect* ); - void findNext(bool forward); - bool isCurrentLocationValid() { return m_hasCurrentLocation; } - void setMatches(WTF::Vector* matches); -private: - void drawMatch(const SkRegion& region, SkCanvas* canvas, bool focused); - void setUpFindPaint(); - void storeCurrentMatchLocation(); - WTF::Vector* 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/WebKit/android/nav/ParseCanvas.h b/WebKit/android/nav/ParseCanvas.h deleted file mode 100644 index 9b7a889..0000000 --- a/WebKit/android/nav/ParseCanvas.h +++ /dev/null @@ -1,52 +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 PARSE_CANVAS_H -#define PARSE_CANVAS_H - -#include "SkCanvas.h" - -namespace android { - -class ParseCanvas : public SkCanvas { -protected: - virtual ~ParseCanvas() { - setBounder(0); - } - - // Pictures parsed for content never want to create offscreen bitmaps. - // Instead, just save and restore the canvas state -- this also keeps - // the picture contents at their original coordinates. - virtual int saveLayer(const SkRect* , const SkPaint* , SaveFlags flags) { - return INHERITED::save(flags); - } -private: - typedef SkCanvas INHERITED; -}; - -} - -#endif - diff --git a/WebKit/android/nav/SelectText.cpp b/WebKit/android/nav/SelectText.cpp deleted file mode 100644 index f8ea799..0000000 --- a/WebKit/android/nav/SelectText.cpp +++ /dev/null @@ -1,1983 +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 "CachedPrefix.h" -#include "BidiResolver.h" -#include "CachedRoot.h" -#include "LayerAndroid.h" -#include "ParseCanvas.h" -#include "SelectText.h" -#include "SkBitmap.h" -#include "SkBounder.h" -#include "SkGradientShader.h" -#include "SkMatrix.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 -#include -#endif - -#define VERBOSE_LOGGING 0 -// #define EXTRA_NOISY_LOGGING 1 - -// TextRunIterator has been copied verbatim from GraphicsContext.cpp -namespace WebCore { - -class TextRunIterator { -public: - TextRunIterator() - : m_textRun(0) - , m_offset(0) - { - } - - TextRunIterator(const TextRun* textRun, unsigned offset) - : m_textRun(textRun) - , m_offset(offset) - { - } - - TextRunIterator(const TextRunIterator& other) - : m_textRun(other.m_textRun) - , m_offset(other.m_offset) - { - } - - unsigned offset() const { return m_offset; } - void increment() { m_offset++; } - bool atEnd() const { return !m_textRun || m_offset >= m_textRun->length(); } - UChar current() const { return (*m_textRun)[m_offset]; } - WTF::Unicode::Direction direction() const { return atEnd() ? WTF::Unicode::OtherNeutral : WTF::Unicode::direction(current()); } - - bool operator==(const TextRunIterator& other) - { - return m_offset == other.m_offset && m_textRun == other.m_textRun; - } - - bool operator!=(const TextRunIterator& other) { return !operator==(other); } - -private: - const TextRun* m_textRun; - int m_offset; -}; - -// ReverseBidi is a trimmed-down version of GraphicsContext::drawBidiText() -void ReverseBidi(UChar* chars, int len) { - using namespace WTF::Unicode; - WTF::Vector result; - result.reserveCapacity(len); - TextRun run(chars, len); - BidiResolver bidiResolver; - bidiResolver.setStatus(BidiStatus(LeftToRight, LeftToRight, LeftToRight, - BidiContext::create(0, LeftToRight, false))); - bidiResolver.setPosition(TextRunIterator(&run, 0)); - bidiResolver.createBidiRunsForLine(TextRunIterator(&run, len)); - if (!bidiResolver.runCount()) - return; - BidiCharacterRun* bidiRun = bidiResolver.firstRun(); - while (bidiRun) { - int bidiStart = bidiRun->start(); - int bidiStop = bidiRun->stop(); - int size = result.size(); - int bidiCount = bidiStop - bidiStart; - result.append(chars + bidiStart, bidiCount); - if (bidiRun->level() % 2) { - UChar* start = &result[size]; - UChar* end = start + bidiCount; - // reverse the order of any RTL substrings - while (start < end) { - UChar temp = *start; - *start++ = *--end; - *end = temp; - } - start = &result[size]; - end = start + bidiCount - 1; - // if the RTL substring had a surrogate pair, restore its order - while (start < end) { - UChar trail = *start++; - if (!U16_IS_SURROGATE(trail)) - continue; - start[-1] = *start; // lead - *start++ = trail; - } - } - bidiRun = bidiRun->next(); - } - bidiResolver.deleteRuns(); - memcpy(chars, &result[0], len * sizeof(UChar)); -} - -} - -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(-1); - mLastCandidate.fGlyphID = static_cast(-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(-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(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 mParagraphs; - SkTDArray 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 sortedBounds; - SkTDArray 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 mSelectBounds; - SkTDArray mSelectEnd; - SkTDArray mSelectStart; - int mSelectStartIndex; - SkTDArray 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(picture)); - bool flipped = builder.flipped(); - if (flipped) { - TextCanvas checker(&builder); - checker.drawPicture(const_cast(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(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(picture)); - return finder.bestBounds(base); -} - -static WTF::String text(const SkPicture& picture, const SkIRect& area, - const SkIRect& start, int startBase, const SkIRect& end, - int endBase, bool flipped) -{ - TextExtractor extractor(start, startBase, end, endBase, area, flipped); - TextCanvas checker(&extractor); - checker.drawPicture(const_cast(picture)); - return extractor.text(); -} - -#define CONTROL_NOTCH 16 -#define CONTROL_HEIGHT 35 -#define CONTROL_WIDTH 21 -#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 - -#define SLOP 35 - -SelectText::SelectText() -{ - 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::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 - canvas->save(); - canvas->translate(m_selStart.fLeft, m_selStart.fBottom); - canvas->drawPicture(m_startControl); - canvas->restore(); - canvas->save(); - canvas->translate(m_selEnd.fRight, m_selEnd.fBottom); - canvas->drawPicture(m_endControl); - canvas->restore(); - 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(picture)); - lineCheck.finish(m_selRegion); - check.setLines(&lineCheck); - TextCanvas checker(&check); - checker.drawPicture(const_cast(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(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, cy); - test.inset(-SLOP, -SLOP); - return test.contains(x, y); -} - -bool SelectText::hitSelection(int x, int y) const -{ - x -= m_startOffset.fX; - y -= m_startOffset.fY; - int left = m_selStart.fLeft - CONTROL_WIDTH / 2; - int top = m_selStart.fBottom + CONTROL_HEIGHT / 2; - if (hitCorner(left, top, x, y)) - return true; - int right = m_selEnd.fRight + CONTROL_WIDTH / 2; - int bottom = m_selEnd.fBottom + CONTROL_HEIGHT / 2; - if (hitCorner(right, bottom, x, y)) - return true; - return m_selRegion.contains(x, y); -} - -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; - } - int left = m_selStart.fLeft - CONTROL_WIDTH / 2; - int top = m_selStart.fBottom + CONTROL_HEIGHT / 2; - m_hitTopLeft = hitCorner(left, top, x, y); - int right = m_selEnd.fRight + CONTROL_WIDTH / 2; - int bottom = m_selEnd.fBottom + CONTROL_HEIGHT / 2; - bool hitBottomRight = hitCorner(right, bottom, 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 && (!hitBottomRight || y - top < bottom - y)) { - 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; -} - -/* selects the word at (x, y) -* a word is normally delimited by spaces -* a string of digits (even with inside spaces) is a word (for phone numbers) -* FIXME: digit find isn't implemented yet -* returns true if a word was selected -*/ -bool SelectText::wordSelection(const CachedRoot* root, const IntRect& vis, - int x, int y) -{ - IntRect tapArea = IntRect(x - TOUCH_SLOP, y - TOUCH_SLOP, TOUCH_SLOP * 2, - TOUCH_SLOP * 2); - if (!startSelection(root, tapArea, x, y)) - return false; - extendSelection(tapArea, x, y); - if (m_selStart.isEmpty()) - return false; - setDrawPointer(false); - setVisibleRect(vis); - SkIRect ivisBounds = m_visibleRect; - ivisBounds.join(m_selStart); - ivisBounds.join(m_selEnd); - DBG_NAV_LOGD("m_selStart=(%d,%d,r=%d,b=%d) m_selEnd=(%d,%d,r=%d,b=%d)" - " ivisBounds=(%d,%d,r=%d,b=%d)", - m_selStart.fLeft, m_selStart.fTop, m_selStart.fRight, m_selStart.fBottom, - m_selEnd.fLeft, m_selEnd.fTop, m_selEnd.fRight, m_selEnd.fBottom, - ivisBounds.fLeft, ivisBounds.fTop, ivisBounds.fRight, ivisBounds.fBottom); - m_selRegion.setEmpty(); - buildSelection(*m_picture, ivisBounds, m_selStart, m_startBase, - m_selEnd, m_endBase, &m_selRegion); - x = m_selStart.fLeft; - y = (m_selStart.fTop + m_selStart.fBottom) >> 1; - SkIRect clipRect = m_visibleRect; - clipRect.fLeft -= m_visibleRect.width() >> 1; - clipRect.fLeft = std::max(clipRect.fLeft, 0); - int base; - SkIRect left = findLeft(*m_picture, clipRect, x, y, &base); - if (!left.isEmpty()) { - m_startBase = base; - m_selStart = left; - } - x = m_selEnd.fRight; - y = (m_selEnd.fTop + m_selEnd.fBottom) >> 1; - clipRect = m_visibleRect; - clipRect.fRight += m_visibleRect.width() >> 1; - SkIRect right = findRight(*m_picture, clipRect, x, y, &base); - if (!right.isEmpty()) { - m_endBase = base; - m_selEnd = right; - } - DBG_NAV_LOGD("m_selStart=(%d, %d, %d, %d) m_selEnd=(%d, %d, %d, %d)", - m_selStart.fLeft, m_selStart.fTop, m_selStart.fRight, m_selStart.fBottom, - m_selEnd.fLeft, m_selEnd.fTop, m_selEnd.fRight, m_selEnd.fBottom); - if (!left.isEmpty() || !right.isEmpty()) { - m_wordBounds = m_selStart; - m_wordBounds.join(m_selEnd); - m_extendSelection = m_wordSelection = true; - m_outsideWord = false; - return true; - } - return false; -} - -void SelectText::swapAsNeeded() -{ - if (m_selStart.fTop >= (m_selEnd.fTop + m_selEnd.fBottom) >> 1 - || (m_selEnd.fTop < (m_selStart.fTop + m_selStart.fBottom) >> 1 - && m_selStart.fRight > m_selEnd.fLeft)) - { - SkTSwap(m_startBase, m_endBase); - SkTSwap(m_selStart, m_selEnd); - m_hitTopLeft ^= true; - DBG_NAV_LOGD("m_hitTopLeft=%s", m_hitTopLeft ? "true" : "false"); - } -} - -} diff --git a/WebKit/android/nav/SelectText.h b/WebKit/android/nav/SelectText.h deleted file mode 100644 index 42239cf..0000000 --- a/WebKit/android/nav/SelectText.h +++ /dev/null @@ -1,116 +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 SELECT_TEXT_H -#define SELECT_TEXT_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); -public: - float m_inverseScale; // inverse scale, x, y used for drawing select path - int m_selectX; - int m_selectY; -private: - 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; - 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; -}; - -} - -namespace WebCore { - -void ReverseBidi(UChar* chars, int len); - -} - -#endif diff --git a/WebKit/android/nav/WebView.cpp b/WebKit/android/nav/WebView.cpp deleted file mode 100644 index ff5d73d..0000000 --- a/WebKit/android/nav/WebView.cpp +++ /dev/null @@ -1,2673 +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. - */ - -#define LOG_TAG "webviewglue" - -#include "config.h" - -#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" -#include "IntPoint.h" -#include "IntRect.h" -#include "LayerAndroid.h" -#include "Node.h" -#include "utils/Functor.h" -#include "private/hwui/DrawGlInfo.h" -#include "PlatformGraphicsContext.h" -#include "PlatformString.h" -#include "ScrollableLayerAndroid.h" -#include "SelectText.h" -#include "SkCanvas.h" -#include "SkDumpCanvas.h" -#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" -#include "WebViewCore.h" -#include "android_graphics.h" - -#ifdef GET_NATIVE_VIEW -#undef GET_NATIVE_VIEW -#endif - -#define GET_NATIVE_VIEW(env, obj) ((WebView*)env->GetIntField(obj, gWebViewField)) - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace android { - -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); - return m; -} - -//------------------------------------- -// This class provides JNI for making calls into native code from the UI side -// of the multi-threaded WebView. -class WebView -{ -public: -enum FrameCachePermission { - DontAllowNewer, - AllowNewer, - AllowNewest -}; - -enum DrawExtras { // keep this in sync with WebView.java - DrawExtrasNone = 0, - DrawExtrasFind = 1, - DrawExtrasSelection = 2, - DrawExtrasCursorRing = 3 -}; - -struct JavaGlue { - jweak m_obj; - jmethodID m_calcOurContentVisibleRectF; - jmethodID m_overrideLoading; - jmethodID m_scrollBy; - jmethodID m_sendMoveFocus; - jmethodID m_sendMoveMouse; - jmethodID m_sendMoveMouseIfLatest; - jmethodID m_sendMotionUp; - jmethodID m_domChangedFocus; - jmethodID m_getScaledMaxXScroll; - jmethodID m_getScaledMaxYScroll; - jmethodID m_getVisibleRect; - jmethodID m_rebuildWebTextView; - jmethodID m_viewInvalidate; - jmethodID m_viewInvalidateRect; - jmethodID m_postInvalidateDelayed; - jmethodID m_inFullScreenMode; - jfieldID m_rectLeft; - jfieldID m_rectTop; - jmethodID m_rectWidth; - jmethodID m_rectHeight; - jfieldID m_rectFLeft; - jfieldID m_rectFTop; - jmethodID m_rectFWidth; - jmethodID m_rectFHeight; - AutoJObject object(JNIEnv* env) { - return getRealObject(env, m_obj); - } -} m_javaGlue; - -WebView(JNIEnv* env, jobject javaWebView, int viewImpl, WTF::String drawableDir, AssetManager* am) : - m_ring((WebViewCore*) viewImpl) -{ - jclass clazz = env->FindClass("android/webkit/WebView"); - // m_javaGlue = new JavaGlue; - m_javaGlue.m_obj = env->NewWeakGlobalRef(javaWebView); - m_javaGlue.m_scrollBy = GetJMethod(env, clazz, "setContentScrollBy", "(IIZ)Z"); - m_javaGlue.m_calcOurContentVisibleRectF = GetJMethod(env, clazz, "calcOurContentVisibleRectF", "(Landroid/graphics/RectF;)V"); - m_javaGlue.m_overrideLoading = GetJMethod(env, clazz, "overrideLoading", "(Ljava/lang/String;)V"); - m_javaGlue.m_sendMoveFocus = GetJMethod(env, clazz, "sendMoveFocus", "(II)V"); - m_javaGlue.m_sendMoveMouse = GetJMethod(env, clazz, "sendMoveMouse", "(IIII)V"); - m_javaGlue.m_sendMoveMouseIfLatest = GetJMethod(env, clazz, "sendMoveMouseIfLatest", "(ZZ)V"); - m_javaGlue.m_sendMotionUp = GetJMethod(env, clazz, "sendMotionUp", "(IIIII)V"); - m_javaGlue.m_domChangedFocus = GetJMethod(env, clazz, "domChangedFocus", "()V"); - m_javaGlue.m_getScaledMaxXScroll = GetJMethod(env, clazz, "getScaledMaxXScroll", "()I"); - m_javaGlue.m_getScaledMaxYScroll = GetJMethod(env, clazz, "getScaledMaxYScroll", "()I"); - m_javaGlue.m_getVisibleRect = GetJMethod(env, clazz, "sendOurVisibleRect", "()Landroid/graphics/Rect;"); - m_javaGlue.m_rebuildWebTextView = GetJMethod(env, clazz, "rebuildWebTextView", "()V"); - m_javaGlue.m_viewInvalidate = GetJMethod(env, clazz, "viewInvalidate", "()V"); - m_javaGlue.m_viewInvalidateRect = GetJMethod(env, clazz, "viewInvalidate", "(IIII)V"); - m_javaGlue.m_postInvalidateDelayed = GetJMethod(env, clazz, - "viewInvalidateDelayed", "(JIIII)V"); - m_javaGlue.m_inFullScreenMode = GetJMethod(env, clazz, "inFullScreenMode", "()Z"); - env->DeleteLocalRef(clazz); - - jclass rectClass = env->FindClass("android/graphics/Rect"); - LOG_ASSERT(rectClass, "Could not find Rect class"); - m_javaGlue.m_rectLeft = env->GetFieldID(rectClass, "left", "I"); - m_javaGlue.m_rectTop = env->GetFieldID(rectClass, "top", "I"); - m_javaGlue.m_rectWidth = GetJMethod(env, rectClass, "width", "()I"); - m_javaGlue.m_rectHeight = GetJMethod(env, rectClass, "height", "()I"); - env->DeleteLocalRef(rectClass); - - jclass rectClassF = env->FindClass("android/graphics/RectF"); - LOG_ASSERT(rectClassF, "Could not find RectF class"); - m_javaGlue.m_rectFLeft = env->GetFieldID(rectClassF, "left", "F"); - m_javaGlue.m_rectFTop = env->GetFieldID(rectClassF, "top", "F"); - m_javaGlue.m_rectFWidth = GetJMethod(env, rectClassF, "width", "()F"); - m_javaGlue.m_rectFHeight = GetJMethod(env, rectClassF, "height", "()F"); - env->DeleteLocalRef(rectClassF); - - 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; - if (drawableDir.isEmpty()) - m_buttonSkin = 0; - else - m_buttonSkin = new RenderSkinButton(am, drawableDir); -#if USE(ACCELERATED_COMPOSITING) - m_glWebViewState = 0; -#endif -} - -~WebView() -{ - if (m_javaGlue.m_obj) - { - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->DeleteWeakGlobalRef(m_javaGlue.m_obj); - m_javaGlue.m_obj = 0; - } -#if USE(ACCELERATED_COMPOSITING) - // We must remove the m_glWebViewState prior to deleting m_baseLayer. If we - // do not remove it here, we risk having BaseTiles trying to paint using a - // deallocated base layer. - stopGL(); -#endif - delete m_frameCacheUI; - delete m_navPictureUI; - SkSafeUnref(m_baseLayer); - delete m_glDrawFunctor; - delete m_buttonSkin; -} - -void stopGL() -{ -#if USE(ACCELERATED_COMPOSITING) - delete m_glWebViewState; - m_glWebViewState = 0; -#endif -} - -WebViewCore* getWebViewCore() const { - return m_viewImpl; -} - -// 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); -} - -void hideCursor(CachedRoot* root) -{ - DBG_NAV_LOG("inner"); - m_viewImpl->m_hasCursorBounds = false; - root->hideCursor(); - viewInvalidate(); -} - -#if DUMP_NAV_CACHE -void debugDump() -{ - CachedRoot* root = getFrameCache(DontAllowNewer); - if (root) - root->mDebug.print(); -} -#endif - -// Traverse our stored array of buttons that are in our picture, and update -// their subpictures according to their current state. -// Called from the UI thread. This is the one place in the UI thread where we -// access the buttons stored in the WebCore thread. -// hasFocus keeps track of whether the WebView has focus && windowFocus. -// If not, we do not want to draw the button in a selected or pressed state -void nativeRecordButtons(bool hasFocus, bool pressed, bool invalidate) -{ - bool cursorIsOnButton = false; - const CachedFrame* cachedFrame; - const CachedNode* cachedCursor = 0; - // Lock the mutex, since we now share with the WebCore thread. - m_viewImpl->gButtonMutex.lock(); - if (m_viewImpl->m_buttons.size() && m_buttonSkin) { - // FIXME: In a future change, we should keep track of whether the selection - // has changed to short circuit (note that we would still need to update - // if we received new buttons from the WebCore thread). - WebCore::Node* cursor = 0; - CachedRoot* root = getFrameCache(DontAllowNewer); - if (root) { - cachedCursor = root->currentCursor(&cachedFrame); - if (cachedCursor) - cursor = (WebCore::Node*) cachedCursor->nodePointer(); - } - - // Traverse the array, and update each button, depending on whether it - // is selected. - Container* end = m_viewImpl->m_buttons.end(); - for (Container* ptr = m_viewImpl->m_buttons.begin(); ptr != end; ptr++) { - RenderSkinAndroid::State state = RenderSkinAndroid::kNormal; - if (ptr->matches(cursor)) { - cursorIsOnButton = true; - // If the WebView is out of focus/window focus, set the state to - // normal, but still keep track of the fact that the selected is a - // button - if (hasFocus) { - if (pressed || m_ring.m_isPressed) - state = RenderSkinAndroid::kPressed; - else if (SkTime::GetMSecs() < m_ringAnimationEnd) - state = RenderSkinAndroid::kFocused; - } - } - ptr->updateFocusState(state, m_buttonSkin); - } - } - m_viewImpl->gButtonMutex.unlock(); - if (invalidate && cachedCursor && cursorIsOnButton) { - const WebCore::IntRect& b = cachedCursor->bounds(cachedFrame); - viewInvalidateRect(b.x(), b.y(), b.right(), b.bottom()); - } -} - -// The caller has already determined that the desired document rect corresponds -// to the main picture, and not a layer -void scrollRectOnScreen(const IntRect& rect) -{ - if (rect.isEmpty()) - return; - SkRect visible; - calcOurContentVisibleRect(&visible); - int dx = 0; - int left = rect.x(); - int right = rect.right(); - if (left < visible.fLeft) { - dx = left - visible.fLeft; - // Only scroll right if the entire width can fit on screen. - } else if (right > visible.fRight && right - left < visible.width()) { - dx = right - visible.fRight; - } - int dy = 0; - int top = rect.y(); - int bottom = rect.bottom(); - if (top < visible.fTop) { - dy = top - visible.fTop; - // Only scroll down if the entire height can fit on screen - } else if (bottom > visible.fBottom && bottom - top < visible.height()) { - dy = bottom - visible.fBottom; - } - if ((dx|dy) == 0 || !scrollBy(dx, dy)) - return; - viewInvalidate(); -} - -void calcOurContentVisibleRect(SkRect* r) -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - jclass rectClass = env->FindClass("android/graphics/RectF"); - jmethodID init = env->GetMethodID(rectClass, "", "(FFFF)V"); - jobject jRect = env->NewObject(rectClass, init, 0, 0, 0, 0); - env->CallVoidMethod(m_javaGlue.object(env).get(), - m_javaGlue.m_calcOurContentVisibleRectF, jRect); - r->fLeft = env->GetFloatField(jRect, m_javaGlue.m_rectFLeft); - r->fTop = env->GetFloatField(jRect, m_javaGlue.m_rectFTop); - r->fRight = r->fLeft + env->CallFloatMethod(jRect, m_javaGlue.m_rectFWidth); - r->fBottom = r->fTop + env->CallFloatMethod(jRect, m_javaGlue.m_rectFHeight); - env->DeleteLocalRef(rectClass); - env->DeleteLocalRef(jRect); - checkException(env); -} - -void resetCursorRing() -{ - m_ringAnimationEnd = 0; - m_viewImpl->m_hasCursorBounds = false; -} - -bool drawCursorPreamble(CachedRoot* root) -{ - 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 = const_cast(root->rootLayer()); - SkRect visible; - calcOurContentVisibleRect(&visible); - layer->updateFixedLayersPositions(visible); - 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(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()) - return false; - - if (!m_glWebViewState) { - m_glWebViewState = new GLWebViewState(&m_viewImpl->gButtonMutex); - 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, false); - } - } - - CachedRoot* root = getFrameCache(AllowNewer); - if (!root) { - DBG_NAV_LOG("!root"); - if (extras == DrawExtrasCursorRing) - resetCursorRing(); - return false; - } - DrawExtra* extra = 0; - switch (extras) { - case DrawExtrasFind: - extra = &m_findOnPage; - break; - case DrawExtrasSelection: - extra = &m_selectText; - break; - case DrawExtrasCursorRing: - if (drawCursorPreamble(root) && m_ring.setup()) { - if (!m_ring.m_isButton) - extra = &m_ring; - drawCursorPostamble(); - } - break; - default: - ; - } - - unsigned int pic = m_glWebViewState->currentPictureCounter(); - - SkPicture picture; - IntRect rect(0, 0, 0, 0); - bool allowSame = false; - m_glWebViewState->resetRings(); - if (extra) { - if (extra == &m_ring) { - m_glWebViewState->setRings(m_ring.rings(), m_ring.m_isPressed); - } else { - LayerAndroid mainPicture(m_navPictureUI); - PictureSet* content = m_baseLayer->content(); - SkCanvas* canvas = picture.beginRecording(content->width(), - content->height()); - extra->draw(canvas, &mainPicture, &rect); - picture.endRecording(); - } - } else if (extras == DrawExtrasCursorRing && m_ring.m_isButton) { - const CachedFrame* cachedFrame; - const CachedNode* cachedCursor = root->currentCursor(&cachedFrame); - if (cachedCursor) { - rect = cachedCursor->bounds(cachedFrame); - allowSame = true; - } - } - m_glWebViewState->setExtra(m_baseLayer, picture, rect, allowSame); - - LayerAndroid* compositeLayer = compositeRoot(); - if (compositeLayer) - compositeLayer->setExtra(extra); - - SkRect visibleRect; - calcOurContentVisibleRect(&visibleRect); - bool ret = m_glWebViewState->drawGL(viewRect, visibleRect, invalRect, - webViewRect, titleBarHeight, clip, scale); - if (ret || m_glWebViewState->currentPictureCounter() != pic) - return true; -#endif - return false; -} - -PictureSet* draw(SkCanvas* canvas, SkColor bgColor, int extras, bool split) -{ - PictureSet* ret = 0; - if (!m_baseLayer) { - canvas->drawColor(bgColor); - return ret; - } - - // draw the content of the base layer first - PictureSet* content = m_baseLayer->content(); - int sc = canvas->save(SkCanvas::kClip_SaveFlag); - canvas->clipRect(SkRect::MakeLTRB(0, 0, content->width(), - content->height()), SkRegion::kDifference_Op); - canvas->drawColor(bgColor); - canvas->restoreToCount(sc); - if (content->draw(canvas)) - ret = split ? new PictureSet(*content) : 0; - - CachedRoot* root = getFrameCache(AllowNewer); - if (!root) { - DBG_NAV_LOG("!root"); - if (extras == DrawExtrasCursorRing) - resetCursorRing(); - return ret; - } - LayerAndroid mainPicture(m_navPictureUI); - DrawExtra* extra = 0; - switch (extras) { - case DrawExtrasFind: - extra = &m_findOnPage; - break; - case DrawExtrasSelection: - extra = &m_selectText; - break; - case DrawExtrasCursorRing: - if (drawCursorPreamble(root) && m_ring.setup()) { - if (!m_ring.m_isButton) - extra = &m_ring; - drawCursorPostamble(); - } - break; - default: - ; - } - if (extra) { - IntRect dummy; // inval area, unused for now - extra->draw(canvas, &mainPicture, &dummy); - } -#if USE(ACCELERATED_COMPOSITING) - LayerAndroid* compositeLayer = compositeRoot(); - if (!compositeLayer) - return ret; - compositeLayer->setExtra(extra); - SkRect visible; - calcOurContentVisibleRect(&visible); - // call this to be sure we've adjusted for any scrolling or animations - // before we actually draw - compositeLayer->updateFixedLayersPositions(visible); - compositeLayer->updatePositions(); - // We have to set the canvas' matrix on the base layer - // (to have fixed layers work as intended) - SkAutoCanvasRestore restore(canvas, true); - m_baseLayer->setMatrix(canvas->getTotalMatrix()); - canvas->resetMatrix(); - m_baseLayer->draw(canvas); -#endif - 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.right() - newBounds.right()) > 4) - return; - if (abs(bounds.bottom() - newBounds.bottom()) > 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(frame), - const_cast(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) { - SkRect visible; - calcOurContentVisibleRect(&visible); - LayerAndroid* layer = const_cast( - m_frameCacheUI->rootLayer()); - if (layer) { - layer->updateFixedLayersPositions(visible); - layer->updatePositions(); - } - } -#endif - fixCursor(); - if (oldFocusIsTextInput) { - const CachedNode* newFocus = m_frameCacheUI->currentFocus(); - if (newFocus && oldFocusNodePointer != newFocus->nodePointer() - && newFocus->isTextInput() - && newFocus != m_frameCacheUI->currentCursor()) { - // The focus has changed. We may need to update things. - LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue.object(env).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; -} - -int getScaledMaxXScroll() -{ - LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); - JNIEnv* env = JSC::Bindings::getJNIEnv(); - int result = env->CallIntMethod(m_javaGlue.object(env).get(), m_javaGlue.m_getScaledMaxXScroll); - checkException(env); - return result; -} - -int getScaledMaxYScroll() -{ - LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); - JNIEnv* env = JSC::Bindings::getJNIEnv(); - int result = env->CallIntMethod(m_javaGlue.object(env).get(), m_javaGlue.m_getScaledMaxYScroll); - checkException(env); - return result; -} - -IntRect getVisibleRect() -{ - IntRect rect; - LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); - JNIEnv* env = JSC::Bindings::getJNIEnv(); - jobject jRect = env->CallObjectMethod(m_javaGlue.object(env).get(), m_javaGlue.m_getVisibleRect); - checkException(env); - rect.setX(env->GetIntField(jRect, m_javaGlue.m_rectLeft)); - checkException(env); - rect.setY(env->GetIntField(jRect, m_javaGlue.m_rectTop)); - checkException(env); - rect.setWidth(env->CallIntMethod(jRect, m_javaGlue.m_rectWidth)); - checkException(env); - rect.setHeight(env->CallIntMethod(jRect, m_javaGlue.m_rectHeight)); - checkException(env); - env->DeleteLocalRef(jRect); - checkException(env); - return rect; -} - -static CachedFrame::Direction KeyToDirection(int32_t keyCode) -{ - switch (keyCode) { - case AKEYCODE_DPAD_RIGHT: - DBG_NAV_LOGD("keyCode=%s", "right"); - return CachedFrame::RIGHT; - case AKEYCODE_DPAD_LEFT: - DBG_NAV_LOGD("keyCode=%s", "left"); - return CachedFrame::LEFT; - case AKEYCODE_DPAD_DOWN: - DBG_NAV_LOGD("keyCode=%s", "down"); - return CachedFrame::DOWN; - case AKEYCODE_DPAD_UP: - DBG_NAV_LOGD("keyCode=%s", "up"); - return CachedFrame::UP; - default: - DBG_NAV_LOGD("bad key %d sent", keyCode); - return CachedFrame::UNINITIALIZED; - } -} - -WTF::String imageURI(int x, int y) -{ - const CachedRoot* root = getFrameCache(DontAllowNewer); - return root ? root->imageURI(x, y) : WTF::String(); -} - -bool cursorWantsKeyEvents() -{ - const CachedRoot* root = getFrameCache(DontAllowNewer); - if (root) { - const CachedNode* focus = root->currentCursor(); - if (focus) - return focus->wantsKeyEvents(); - } - return false; -} - - -/* returns true if the key had no effect (neither scrolled nor changed cursor) */ -bool moveCursor(int keyCode, int count, bool ignoreScroll) -{ - CachedRoot* root = getFrameCache(AllowNewer); - if (!root) { - DBG_NAV_LOG("!root"); - return true; - } - - m_viewImpl->m_moveGeneration++; - CachedFrame::Direction direction = KeyToDirection(keyCode); - const CachedFrame* cachedFrame, * oldFrame = 0; - const CachedNode* cursor = root->currentCursor(&oldFrame); - WebCore::IntPoint cursorLocation = root->cursorLocation(); - DBG_NAV_LOGD("old cursor %d (nativeNode=%p) cursorLocation={%d, %d}", - cursor ? cursor->index() : 0, - cursor ? cursor->nodePointer() : 0, cursorLocation.x(), cursorLocation.y()); - WebCore::IntRect visibleRect = setVisibleRect(root); - int xMax = getScaledMaxXScroll(); - int yMax = getScaledMaxYScroll(); - root->setMaxScroll(xMax, yMax); - const CachedNode* cachedNode = 0; - int dx = 0; - int dy = 0; - int counter = count; - while (--counter >= 0) { - WebCore::IntPoint scroll = WebCore::IntPoint(0, 0); - cachedNode = root->moveCursor(direction, &cachedFrame, &scroll); - dx += scroll.x(); - dy += scroll.y(); - } - DBG_NAV_LOGD("new cursor %d (nativeNode=%p) cursorLocation={%d, %d}" - "bounds={%d,%d,w=%d,h=%d}", cachedNode ? cachedNode->index() : 0, - cachedNode ? cachedNode->nodePointer() : 0, - root->cursorLocation().x(), root->cursorLocation().y(), - cachedNode ? cachedNode->bounds(cachedFrame).x() : 0, - cachedNode ? cachedNode->bounds(cachedFrame).y() : 0, - cachedNode ? cachedNode->bounds(cachedFrame).width() : 0, - cachedNode ? cachedNode->bounds(cachedFrame).height() : 0); - // If !m_heightCanMeasure (such as in the browser), we want to scroll no - // matter what - if (!ignoreScroll && (!m_heightCanMeasure || - !cachedNode || - (cursor && cursor->nodePointer() == cachedNode->nodePointer()))) - { - if (count == 1 && dx != 0 && dy == 0 && -m_lastDx == dx && - SkTime::GetMSecs() - m_lastDxTime < 1000) - root->checkForJiggle(&dx); - DBG_NAV_LOGD("scrollBy %d,%d", dx, dy); - if ((dx | dy)) - this->scrollBy(dx, dy); - m_lastDx = dx; - m_lastDxTime = SkTime::GetMSecs(); - } - bool result = false; - if (cachedNode) { - showCursorUntimed(); - m_viewImpl->updateCursorBounds(root, cachedFrame, cachedNode); - root->setCursor(const_cast(cachedFrame), - const_cast(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.bottom() + dy > docHeight) - dy = docHeight - visibleRect.bottom(); - else if (visibleRect.y() + dy < 0) - dy = -visibleRect.y(); - if (visibleRect.right() + dx > docWidth) - dx = docWidth - visibleRect.right(); - 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(frame), - const_cast(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(frame), - const_cast(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) -static const ScrollableLayerAndroid* findScrollableLayer( - const LayerAndroid* parent, int x, int y, SkIRect* foundBounds) { - SkRect bounds; - parent->bounds(&bounds); - // Check the parent bounds first; this will clip to within a masking layer's - // bounds. - if (parent->masksToBounds() && !bounds.contains(x, y)) - return 0; - // Move the hit test local to parent. - x -= bounds.fLeft; - y -= bounds.fTop; - int count = parent->countChildren(); - while (count--) { - const LayerAndroid* child = parent->getChild(count); - const ScrollableLayerAndroid* result = findScrollableLayer(child, x, y, - foundBounds); - if (result) { - foundBounds->offset(bounds.fLeft, bounds.fTop); - if (parent->masksToBounds()) { - if (bounds.width() < foundBounds->width()) - foundBounds->fRight = foundBounds->fLeft + bounds.width(); - if (bounds.height() < foundBounds->height()) - foundBounds->fBottom = foundBounds->fTop + bounds.height(); - } - return result; - } - } - if (parent->contentIsScrollable()) { - foundBounds->set(0, 0, bounds.width(), bounds.height()); - return static_cast(parent); - } - return 0; -} -#endif - -int scrollableLayer(int x, int y, SkIRect* layerRect, SkIRect* bounds) -{ -#if USE(ACCELERATED_COMPOSITING) - const LayerAndroid* layerRoot = compositeRoot(); - if (!layerRoot) - return 0; - const ScrollableLayerAndroid* result = findScrollableLayer(layerRoot, x, y, - bounds); - if (result) { - result->getScrollRect(layerRect); - return result->uniqueId(); - } -#endif - return 0; -} - -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(); - jstring jName = wtfStringToJstring(env, url); - env->CallVoidMethod(m_javaGlue.object(env).get(), - m_javaGlue.m_overrideLoading, jName); - env->DeleteLocalRef(jName); -} - -void setFindIsUp(bool up) -{ - DBG_NAV_LOGD("up=%d", up); - m_viewImpl->m_findIsUp = up; -} - -void setFindIsEmpty() -{ - DBG_NAV_LOG(""); - m_findOnPage.clearCurrentLocation(); -} - -void showCursorTimed() -{ - DBG_NAV_LOG(""); - m_ringAnimationEnd = SkTime::GetMSecs() + 500; - viewInvalidate(); -} - -void showCursorUntimed() -{ - DBG_NAV_LOG(""); - m_ring.m_isPressed = false; - m_ringAnimationEnd = UINT_MAX; - viewInvalidate(); -} - -void setHeightCanMeasure(bool measure) -{ - m_heightCanMeasure = 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; - return m_selectText.startSelection(root, getVisibleRect(), x, y); -} - -bool wordSelection(int x, int y) -{ - const CachedRoot* root = getFrameCache(DontAllowNewer); - if (!root) - return false; - 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) -{ - return m_selectText.hitSelection(x, y); -} - -void setExtendSelection() -{ - m_selectText.setExtendSelection(true); -} - -void setSelectionPointer(bool set, float scale, int x, int y) -{ - m_selectText.setDrawPointer(set); - if (!set) - return; - m_selectText.m_inverseScale = scale; - m_selectText.m_selectX = x; - m_selectText.m_selectY = y; -} - -void sendMoveFocus(WebCore::Frame* framePtr, WebCore::Node* nodePtr) -{ - DBG_NAV_LOGD("framePtr=%p nodePtr=%p", framePtr, nodePtr); - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue.object(env).get(), - m_javaGlue.m_sendMoveFocus, (jint) framePtr, (jint) nodePtr); - checkException(env); -} - -void sendMoveMouse(WebCore::Frame* framePtr, WebCore::Node* nodePtr, int x, int y) -{ - DBG_NAV_LOGD("framePtr=%p nodePtr=%p x=%d y=%d", framePtr, nodePtr, x, y); - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_sendMoveMouse, - (jint) framePtr, (jint) nodePtr, x, y); - checkException(env); -} - -void sendMoveMouseIfLatest(bool clearTextEntry, bool stopPaintingCaret) -{ - LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue.object(env).get(), - m_javaGlue.m_sendMoveMouseIfLatest, clearTextEntry, stopPaintingCaret); - checkException(env); -} - -void sendMotionUp( - WebCore::Frame* framePtr, WebCore::Node* nodePtr, int x, int y) -{ - m_viewImpl->m_touchGeneration = ++m_generation; - DBG_NAV_LOGD("m_generation=%d framePtr=%p nodePtr=%p x=%d y=%d", - m_generation, framePtr, nodePtr, x, y); - LOG_ASSERT(m_javaGlue.m_obj, "A WebView was not associated with this WebViewNative!"); - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_sendMotionUp, - m_generation, (jint) framePtr, (jint) nodePtr, x, y); - checkException(env); -} - -void findNext(bool forward) -{ - m_findOnPage.findNext(forward); - if (!m_findOnPage.currentMatchIsInLayer()) - scrollRectOnScreen(m_findOnPage.currentMatchBounds()); - viewInvalidate(); -} - -// With this call, WebView takes ownership of matches, and is responsible for -// deleting it. -void setMatches(WTF::Vector* 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; - if (sameAsLastSearch && m_findOnPage.isCurrentLocationValid()) { - oldLocation = m_findOnPage.currentMatchBounds(); - checkAgainstOldLocation = true; - } else - checkAgainstOldLocation = false; - - m_findOnPage.setMatches(matches); - - if (!checkAgainstOldLocation - || oldLocation != m_findOnPage.currentMatchBounds()) { - // FIXME: Need to scroll if the match is in a layer. - if (!m_findOnPage.currentMatchIsInLayer()) - scrollRectOnScreen(m_findOnPage.currentMatchBounds()); - } - 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!"); - - JNIEnv* env = JSC::Bindings::getJNIEnv(); - bool result = env->CallBooleanMethod(m_javaGlue.object(env).get(), - m_javaGlue.m_scrollBy, dx, dy, true); - checkException(env); - return result; -} - -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(); - env->CallVoidMethod(m_javaGlue.object(env).get(), - m_javaGlue.m_rebuildWebTextView); - checkException(env); -} - -void viewInvalidate() -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_viewInvalidate); - checkException(env); -} - -void viewInvalidateRect(int l, int t, int r, int b) -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_viewInvalidateRect, l, r, t, b); - checkException(env); -} - -void postInvalidateDelayed(int64_t delay, const WebCore::IntRect& bounds) -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_postInvalidateDelayed, - delay, bounds.x(), bounds.y(), bounds.right(), bounds.bottom()); - checkException(env); -} - -bool inFullScreenMode() -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - jboolean result = env->CallBooleanMethod(m_javaGlue.object(env).get(), - m_javaGlue.m_inFullScreenMode); - checkException(env); - return result; -} - -int moveGeneration() -{ - return m_viewImpl->m_moveGeneration; -} - -LayerAndroid* compositeRoot() const -{ - LOG_ASSERT(!m_baseLayer || m_baseLayer->countChildren() == 1, - "base layer can't have more than one child %s", __FUNCTION__); - if (m_baseLayer && m_baseLayer->countChildren() == 1) - return static_cast(m_baseLayer->getChild(0)); - else - return 0; -} - -#if ENABLE(ANDROID_OVERFLOW_SCROLL) -static void copyScrollPositionRecursive(const LayerAndroid* from, - LayerAndroid* root) -{ - if (!from || !root) - return; - for (int i = 0; i < from->countChildren(); i++) { - const LayerAndroid* l = from->getChild(i); - if (l->contentIsScrollable()) { - const SkPoint& pos = l->getPosition(); - LayerAndroid* match = root->findById(l->uniqueId()); - if (match && match->contentIsScrollable()) - match->setPosition(pos.fX, pos.fY); - } - copyScrollPositionRecursive(l, root); - } -} -#endif - -void setBaseLayer(BaseLayerAndroid* layer, SkRegion& inval, bool showVisualIndicator, - bool isPictureAfterFirstLayout) -{ -#if USE(ACCELERATED_COMPOSITING) - if (m_glWebViewState) - m_glWebViewState->setBaseLayer(layer, inval, showVisualIndicator, - isPictureAfterFirstLayout); -#endif - -#if ENABLE(ANDROID_OVERFLOW_SCROLL) - if (layer) { - LayerAndroid* newCompositeRoot = static_cast(layer->getChild(0)); - copyScrollPositionRecursive(compositeRoot(), newCompositeRoot); - } -#endif - SkSafeUnref(m_baseLayer); - m_baseLayer = layer; - CachedRoot* root = getFrameCache(DontAllowNewer); - if (!root) - return; - root->resetLayers(); - root->setRootLayer(compositeRoot()); -} - -void replaceBaseContent(PictureSet* set) -{ - if (!m_baseLayer) - return; - m_baseLayer->setContent(*set); - delete set; -} - -void copyBaseContentToPicture(SkPicture* picture) -{ - if (!m_baseLayer) - return; - PictureSet* content = m_baseLayer->content(); - m_baseLayer->drawCanvas(picture->beginRecording(content->width(), content->height(), - SkPicture::kUsePathBoundsForClip_RecordingFlag)); - picture->endRecording(); -} - -bool hasContent() { - if (!m_baseLayer) - return false; - return !m_baseLayer->content()->isEmpty(); -} - -void setFunctor(Functor* functor) { - delete m_glDrawFunctor; - m_glDrawFunctor = functor; -} - -Functor* getFunctor() { - return m_glDrawFunctor; -} - -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; - BaseLayerAndroid* m_baseLayer; - Functor* m_glDrawFunctor; -#if USE(ACCELERATED_COMPOSITING) - GLWebViewState* m_glWebViewState; -#endif - const RenderSkinButton* m_buttonSkin; -}; // end of WebView class - - -/** - * This class holds a function pointer and parameters for calling drawGL into a specific - * viewport. The pointer to the Functor will be put on a framework display list to be called - * when the display list is replayed. - */ -class GLDrawFunctor : Functor { - public: - GLDrawFunctor(WebView* _wvInstance, - bool(WebView::*_funcPtr)(WebCore::IntRect&, WebCore::IntRect*, WebCore::IntRect&, int, WebCore::IntRect&, jfloat, jint), - WebCore::IntRect _viewRect, float _scale, int _extras) { - wvInstance = _wvInstance; - funcPtr = _funcPtr; - viewRect = _viewRect; - scale = _scale; - extras = _extras; - }; - status_t operator()(int messageId, void* data) { - if (viewRect.isEmpty()) { - // NOOP operation if viewport is empty - return 0; - } - - WebCore::IntRect inval; - int titlebarHeight = webViewRect.height() - viewRect.height(); - - uirenderer::DrawGlInfo* info = reinterpret_cast(data); - WebCore::IntRect localViewRect = viewRect; - if (info->isLayer) - localViewRect.move(-1 * localViewRect.x(), -1 * localViewRect.y()); - - WebCore::IntRect clip(info->clipLeft, info->clipTop, - info->clipRight - info->clipLeft, - info->clipBottom - info->clipTop); - - bool retVal = (*wvInstance.*funcPtr)(localViewRect, &inval, webViewRect, titlebarHeight, clip, scale, extras); - if (retVal) { - IntRect finalInval; - if (inval.isEmpty()) { - finalInval = webViewRect; - retVal = true; - } else { - finalInval.setX(webViewRect.x() + inval.x()); - finalInval.setY(webViewRect.y() + titlebarHeight + inval.y()); - finalInval.setWidth(inval.width()); - finalInval.setHeight(inval.height()); - } - info->dirtyLeft = finalInval.x(); - info->dirtyTop = finalInval.y(); - info->dirtyRight = finalInval.right(); - info->dirtyBottom = finalInval.bottom(); - } - // return 1 if invalidation needed, 0 otherwise - return retVal ? 1 : 0; - } - void updateRect(WebCore::IntRect& _viewRect) { - viewRect = _viewRect; - } - void updateViewRect(WebCore::IntRect& _viewRect) { - webViewRect = _viewRect; - } - private: - WebView* wvInstance; - bool (WebView::*funcPtr)(WebCore::IntRect&, WebCore::IntRect*, WebCore::IntRect&, int, WebCore::IntRect&, float, int); - WebCore::IntRect viewRect; - WebCore::IntRect webViewRect; - jfloat scale; - jint extras; -}; - -/* - * Native JNI methods - */ -static int nativeCacheHitFramePointer(JNIEnv *env, jobject obj) -{ - return reinterpret_cast(GET_NATIVE_VIEW(env, obj) - ->m_cacheHitFrame->framePointer()); -} - -static jobject nativeCacheHitNodeBounds(JNIEnv *env, jobject obj) -{ - WebCore::IntRect bounds = GET_NATIVE_VIEW(env, obj) - ->m_cacheHitNode->originalAbsoluteBounds(); - jclass rectClass = env->FindClass("android/graphics/Rect"); - jmethodID init = env->GetMethodID(rectClass, "", "(IIII)V"); - jobject rect = env->NewObject(rectClass, init, bounds.x(), - bounds.y(), bounds.right(), bounds.bottom()); - env->DeleteLocalRef(rectClass); - return rect; -} - -static int nativeCacheHitNodePointer(JNIEnv *env, jobject obj) -{ - return reinterpret_cast(GET_NATIVE_VIEW(env, obj) - ->m_cacheHitNode->nodePointer()); -} - -static bool nativeCacheHitIsPlugin(JNIEnv *env, jobject obj) -{ - return GET_NATIVE_VIEW(env, obj)->m_cacheHitNode->isPlugin(); -} - -static void nativeClearCursor(JNIEnv *env, jobject obj) -{ - WebView* view = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(view, "view not set in %s", __FUNCTION__); - view->clearCursor(); -} - -static void nativeCreate(JNIEnv *env, jobject obj, int viewImpl, jstring drawableDir, - jobject jAssetManager) -{ - AssetManager* am = assetManagerForJavaObject(env, jAssetManager); - WTF::String dir = jstringToWtfString(env, drawableDir); - WebView* webview = new WebView(env, obj, viewImpl, dir, am); - // 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(frame ? frame->framePointer() : 0); -} - -static const CachedNode* getCursorNode(JNIEnv *env, jobject obj) -{ - WebView* view = GET_NATIVE_VIEW(env, obj); - CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); - return root ? root->currentCursor() : 0; -} - -static const CachedNode* getCursorNode(JNIEnv *env, jobject obj, - const CachedFrame** frame) -{ - WebView* view = GET_NATIVE_VIEW(env, obj); - CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); - return root ? root->currentCursor(frame) : 0; -} - -static const CachedNode* getFocusCandidate(JNIEnv *env, jobject obj, - const CachedFrame** frame) -{ - WebView* view = GET_NATIVE_VIEW(env, obj); - CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); - if (!root) - return 0; - const CachedNode* cursor = root->currentCursor(frame); - if (cursor && cursor->wantsKeyEvents()) - return cursor; - return root->currentFocus(frame); -} - -static bool focusCandidateHasNextTextfield(JNIEnv *env, jobject obj) -{ - WebView* view = GET_NATIVE_VIEW(env, obj); - CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); - if (!root) - return false; - const CachedNode* cursor = root->currentCursor(); - if (!cursor || !cursor->isTextInput()) - cursor = root->currentFocus(); - if (!cursor || !cursor->isTextInput()) return false; - return root->nextTextField(cursor, 0); -} - -static const CachedNode* getFocusNode(JNIEnv *env, jobject obj) -{ - WebView* view = GET_NATIVE_VIEW(env, obj); - CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); - return root ? root->currentFocus() : 0; -} - -static const CachedNode* getFocusNode(JNIEnv *env, jobject obj, - const CachedFrame** frame) -{ - WebView* view = GET_NATIVE_VIEW(env, obj); - CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); - return root ? root->currentFocus(frame) : 0; -} - -static const CachedInput* getInputCandidate(JNIEnv *env, jobject obj) -{ - WebView* view = GET_NATIVE_VIEW(env, obj); - CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); - if (!root) - return 0; - const CachedFrame* frame; - const CachedNode* cursor = root->currentCursor(&frame); - if (!cursor || !cursor->wantsKeyEvents()) - cursor = root->currentFocus(&frame); - return cursor ? frame->textInput(cursor) : 0; -} - -static jboolean nativePageShouldHandleShiftAndArrows(JNIEnv *env, jobject obj) -{ - const CachedNode* focus = getFocusNode(env, obj); - if (!focus) return false; - // Plugins handle shift and arrows whether or not they have focus. - if (focus->isPlugin()) return true; - const CachedNode* cursor = getCursorNode(env, obj); - // ContentEditable nodes should only receive shift and arrows if they have - // both the cursor and the focus. - return cursor && cursor->nodePointer() == focus->nodePointer() - && cursor->isContentEditable(); -} - -static jobject nativeCursorNodeBounds(JNIEnv *env, jobject obj) -{ - const CachedFrame* frame; - const CachedNode* node = getCursorNode(env, obj, &frame); - WebCore::IntRect bounds = node ? node->bounds(frame) - : WebCore::IntRect(0, 0, 0, 0); - jclass rectClass = env->FindClass("android/graphics/Rect"); - jmethodID init = env->GetMethodID(rectClass, "", "(IIII)V"); - jobject rect = env->NewObject(rectClass, init, bounds.x(), - bounds.y(), bounds.right(), bounds.bottom()); - env->DeleteLocalRef(rectClass); - return rect; -} - -static jint nativeCursorNodePointer(JNIEnv *env, jobject obj) -{ - const CachedNode* node = getCursorNode(env, obj); - return reinterpret_cast(node ? node->nodePointer() : 0); -} - -static jobject nativeCursorPosition(JNIEnv *env, jobject obj) -{ - WebView* view = GET_NATIVE_VIEW(env, obj); - const CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); - WebCore::IntPoint pos = WebCore::IntPoint(0, 0); - if (root) - root->getSimulatedMousePosition(&pos); - jclass pointClass = env->FindClass("android/graphics/Point"); - jmethodID init = env->GetMethodID(pointClass, "", "(II)V"); - jobject point = env->NewObject(pointClass, init, pos.x(), pos.y()); - env->DeleteLocalRef(pointClass); - return point; -} - -static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj) -{ - int L, T, R, B; - GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B); - return WebCore::IntRect(L, T, R - L, B - T); -} - -static bool nativeCursorIntersects(JNIEnv *env, jobject obj, jobject visRect) -{ - const CachedFrame* frame; - const CachedNode* node = getCursorNode(env, obj, &frame); - return node ? node->bounds(frame).intersects( - jrect_to_webrect(env, visRect)) : false; -} - -static bool nativeCursorIsAnchor(JNIEnv *env, jobject obj) -{ - const CachedNode* node = getCursorNode(env, obj); - return node ? node->isAnchor() : false; -} - -static bool nativeCursorIsTextInput(JNIEnv *env, jobject obj) -{ - const CachedNode* node = getCursorNode(env, obj); - return node ? node->isTextInput() : false; -} - -static jobject nativeCursorText(JNIEnv *env, jobject obj) -{ - const CachedNode* node = getCursorNode(env, obj); - if (!node) - return 0; - WTF::String value = node->getExport(); - return wtfStringToJstring(env, value); -} - -static void nativeDebugDump(JNIEnv *env, jobject obj) -{ -#if DUMP_NAV_CACHE - WebView* view = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(view, "view not set in %s", __FUNCTION__); - view->debugDump(); -#endif -} - -static jint nativeDraw(JNIEnv *env, jobject obj, jobject canv, jint color, - jint extras, jboolean split) { - SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv); - return reinterpret_cast(GET_NATIVE_VIEW(env, obj)->draw(canvas, color, extras, split)); -} - -static jint nativeGetDrawGLFunction(JNIEnv *env, jobject obj, jobject jrect, jobject jviewrect, - jfloat scale, jint extras) { - WebCore::IntRect viewRect; - if (jrect == NULL) { - viewRect = WebCore::IntRect(); - } else { - viewRect = jrect_to_webrect(env, jrect); - } - WebView *wvInstance = GET_NATIVE_VIEW(env, obj); - GLDrawFunctor* functor = new GLDrawFunctor(wvInstance, &android::WebView::drawGL, - viewRect, scale, extras); - wvInstance->setFunctor((Functor*) functor); - - WebCore::IntRect webViewRect; - if (jviewrect == NULL) { - webViewRect = WebCore::IntRect(); - } else { - webViewRect = jrect_to_webrect(env, jviewrect); - } - functor->updateViewRect(webViewRect); - - return (jint)functor; -} - -static void nativeUpdateDrawGLFunction(JNIEnv *env, jobject obj, jobject jrect, jobject jviewrect) { - WebView *wvInstance = GET_NATIVE_VIEW(env, obj); - if (wvInstance != NULL) { - GLDrawFunctor* functor = (GLDrawFunctor*) wvInstance->getFunctor(); - if (functor != NULL) { - WebCore::IntRect viewRect; - if (jrect == NULL) { - viewRect = WebCore::IntRect(); - } else { - viewRect = jrect_to_webrect(env, jrect); - } - functor->updateRect(viewRect); - - WebCore::IntRect webViewRect; - if (jviewrect == NULL) { - webViewRect = WebCore::IntRect(); - } else { - webViewRect = jrect_to_webrect(env, jviewrect); - } - functor->updateViewRect(webViewRect); - } - } -} - -static bool nativeEvaluateLayersAnimations(JNIEnv *env, jobject obj) -{ -#if USE(ACCELERATED_COMPOSITING) - LayerAndroid* root = GET_NATIVE_VIEW(env, obj)->compositeRoot(); - if (root) - return root->evaluateAnimations(); -#endif - return false; -} - -static void nativeSetBaseLayer(JNIEnv *env, jobject obj, jint layer, jobject inval, - jboolean showVisualIndicator, - jboolean isPictureAfterFirstLayout) -{ - BaseLayerAndroid* layerImpl = reinterpret_cast(layer); - SkRegion invalRegion; - if (inval) - invalRegion = *GraphicsJNI::getNativeRegion(env, inval); - GET_NATIVE_VIEW(env, obj)->setBaseLayer(layerImpl, invalRegion, showVisualIndicator, - isPictureAfterFirstLayout); -} - -static void nativeReplaceBaseContent(JNIEnv *env, jobject obj, jint content) -{ - PictureSet* set = reinterpret_cast(content); - GET_NATIVE_VIEW(env, obj)->replaceBaseContent(set); -} - -static void nativeCopyBaseContentToPicture(JNIEnv *env, jobject obj, jobject pict) -{ - SkPicture* picture = GraphicsJNI::getNativePicture(env, pict); - GET_NATIVE_VIEW(env, obj)->copyBaseContentToPicture(picture); -} - -static bool nativeHasContent(JNIEnv *env, jobject obj) -{ - return GET_NATIVE_VIEW(env, obj)->hasContent(); -} - -static jobject nativeImageURI(JNIEnv *env, jobject obj, jint x, jint y) -{ - WebView* view = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(view, "view not set in %s", __FUNCTION__); - WTF::String uri = view->imageURI(x, y); - return wtfStringToJstring(env, uri); -} - -static jint nativeFocusCandidateFramePointer(JNIEnv *env, jobject obj) -{ - WebView* view = GET_NATIVE_VIEW(env, obj); - CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); - if (!root) - return 0; - const CachedFrame* frame = 0; - const CachedNode* cursor = root->currentCursor(&frame); - if (!cursor || !cursor->wantsKeyEvents()) - (void) root->currentFocus(&frame); - return reinterpret_cast(frame ? frame->framePointer() : 0); -} - -static bool nativeFocusCandidateIsPassword(JNIEnv *env, jobject obj) -{ - const CachedInput* input = getInputCandidate(env, obj); - return input && input->getType() == CachedInput::PASSWORD; -} - -static bool nativeFocusCandidateIsRtlText(JNIEnv *env, jobject obj) -{ - const CachedInput* input = getInputCandidate(env, obj); - return input ? input->isRtlText() : false; -} - -static bool nativeFocusCandidateIsTextInput(JNIEnv *env, jobject obj) -{ - const CachedNode* node = getFocusCandidate(env, obj, 0); - return node ? node->isTextInput() : false; -} - -static jint nativeFocusCandidateMaxLength(JNIEnv *env, jobject obj) -{ - const CachedInput* input = getInputCandidate(env, obj); - return input ? input->maxLength() : false; -} - -static jint nativeFocusCandidateIsAutoComplete(JNIEnv *env, jobject obj) -{ - const CachedInput* input = getInputCandidate(env, obj); - return input ? input->autoComplete() : false; -} - -static jobject nativeFocusCandidateName(JNIEnv *env, jobject obj) -{ - const CachedInput* input = getInputCandidate(env, obj); - if (!input) - return 0; - const WTF::String& name = input->name(); - return wtfStringToJstring(env, name); -} - -static jobject createJavaRect(JNIEnv* env, int x, int y, int right, int bottom) -{ - jclass rectClass = env->FindClass("android/graphics/Rect"); - jmethodID init = env->GetMethodID(rectClass, "", "(IIII)V"); - jobject rect = env->NewObject(rectClass, init, x, y, right, bottom); - env->DeleteLocalRef(rectClass); - return rect; -} - -static jobject nativeFocusCandidateNodeBounds(JNIEnv *env, jobject obj) -{ - const CachedFrame* frame; - const CachedNode* node = getFocusCandidate(env, obj, &frame); - WebCore::IntRect bounds = node ? node->bounds(frame) - : WebCore::IntRect(0, 0, 0, 0); - return createJavaRect(env, bounds.x(), bounds.y(), bounds.right(), bounds.bottom()); -} - -static jobject nativeFocusCandidatePaddingRect(JNIEnv *env, jobject obj) -{ - const CachedInput* input = getInputCandidate(env, obj); - if (!input) - return 0; - // Note that the Java Rect is being used to pass four integers, rather than - // being used as an actual rectangle. - return createJavaRect(env, input->paddingLeft(), input->paddingTop(), - input->paddingRight(), input->paddingBottom()); -} - -static jint nativeFocusCandidatePointer(JNIEnv *env, jobject obj) -{ - const CachedNode* node = getFocusCandidate(env, obj, 0); - return reinterpret_cast(node ? node->nodePointer() : 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); -} - -static int nativeFocusCandidateLineHeight(JNIEnv *env, jobject obj) -{ - const CachedInput* input = getInputCandidate(env, obj); - return input ? input->lineHeight() : 0; -} - -static jfloat nativeFocusCandidateTextSize(JNIEnv *env, jobject obj) -{ - const CachedInput* input = getInputCandidate(env, obj); - return input ? input->textSize() : 0.f; -} - -static int nativeFocusCandidateType(JNIEnv *env, jobject obj) -{ - const CachedInput* input = getInputCandidate(env, obj); - if (!input) - return CachedInput::NONE; - - if (input->isTextArea()) - return CachedInput::TEXT_AREA; - - return input->getType(); -} - -static bool nativeFocusIsPlugin(JNIEnv *env, jobject obj) -{ - const CachedNode* node = getFocusNode(env, obj); - return node ? node->isPlugin() : false; -} - -static jobject nativeFocusNodeBounds(JNIEnv *env, jobject obj) -{ - const CachedFrame* frame; - const CachedNode* node = getFocusNode(env, obj, &frame); - WebCore::IntRect bounds = node ? node->bounds(frame) - : WebCore::IntRect(0, 0, 0, 0); - jclass rectClass = env->FindClass("android/graphics/Rect"); - jmethodID init = env->GetMethodID(rectClass, "", "(IIII)V"); - jobject rect = env->NewObject(rectClass, init, bounds.x(), - bounds.y(), bounds.right(), bounds.bottom()); - env->DeleteLocalRef(rectClass); - return rect; -} - -static jint nativeFocusNodePointer(JNIEnv *env, jobject obj) -{ - const CachedNode* node = getFocusNode(env, obj); - return node ? reinterpret_cast(node->nodePointer()) : 0; -} - -static bool nativeCursorWantsKeyEvents(JNIEnv* env, jobject jwebview) { - WebView* view = GET_NATIVE_VIEW(env, jwebview); - LOG_ASSERT(view, "view not set in %s", __FUNCTION__); - return view->cursorWantsKeyEvents(); -} - -static void nativeHideCursor(JNIEnv *env, jobject obj) -{ - WebView* view = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(view, "view not set in %s", __FUNCTION__); - view->hideCursor(); -} - -static void nativeInstrumentReport(JNIEnv *env, jobject obj) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounter::reportNow(); -#endif -} - -static void nativeSelectBestAt(JNIEnv *env, jobject obj, jobject jrect) -{ - WebView* view = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(view, "view not set in %s", __FUNCTION__); - WebCore::IntRect rect = jrect_to_webrect(env, jrect); - view->selectBestAt(rect); -} - -static void nativeSelectAt(JNIEnv *env, jobject obj, jint x, jint y) -{ - WebView* view = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(view, "view not set in %s", __FUNCTION__); - WebCore::IntRect rect = IntRect(x, y , 1, 1); - view->selectBestAt(rect); - if (view->hasCursorNode()) - view->showCursorUntimed(); -} - -static jobject nativeLayerBounds(JNIEnv* env, jobject obj, jint jlayer) -{ - SkRect r; -#if USE(ACCELERATED_COMPOSITING) - LayerAndroid* layer = (LayerAndroid*) jlayer; - r = layer->bounds(); -#else - r.setEmpty(); -#endif - SkIRect irect; - r.round(&irect); - jclass rectClass = env->FindClass("android/graphics/Rect"); - jmethodID init = env->GetMethodID(rectClass, "", "(IIII)V"); - jobject rect = env->NewObject(rectClass, init, irect.fLeft, irect.fTop, - irect.fRight, irect.fBottom); - env->DeleteLocalRef(rectClass); - return rect; -} - -static jobject nativeSubtractLayers(JNIEnv* env, jobject obj, jobject jrect) -{ - SkIRect irect = jrect_to_webrect(env, jrect); -#if USE(ACCELERATED_COMPOSITING) - LayerAndroid* root = GET_NATIVE_VIEW(env, obj)->compositeRoot(); - if (root) { - SkRect rect; - rect.set(irect); - rect = root->subtractLayers(rect); - rect.round(&irect); - } -#endif - jclass rectClass = env->FindClass("android/graphics/Rect"); - jmethodID init = env->GetMethodID(rectClass, "", "(IIII)V"); - jobject rect = env->NewObject(rectClass, init, irect.fLeft, irect.fTop, - irect.fRight, irect.fBottom); - env->DeleteLocalRef(rectClass); - return rect; -} - -static jint nativeTextGeneration(JNIEnv *env, jobject obj) -{ - WebView* view = GET_NATIVE_VIEW(env, obj); - CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); - return root ? root->textGeneration() : 0; -} - -static bool nativePointInNavCache(JNIEnv *env, jobject obj, - int x, int y, int slop) -{ - return GET_NATIVE_VIEW(env, obj)->pointInNavCache(x, y, slop); -} - -static bool nativeMotionUp(JNIEnv *env, jobject obj, - int x, int y, int slop) -{ - WebView* view = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(view, "view not set in %s", __FUNCTION__); - return view->motionUp(x, y, slop); -} - -static bool nativeHasCursorNode(JNIEnv *env, jobject obj) -{ - return GET_NATIVE_VIEW(env, obj)->hasCursorNode(); -} - -static bool nativeHasFocusNode(JNIEnv *env, jobject obj) -{ - return GET_NATIVE_VIEW(env, obj)->hasFocusNode(); -} - -static bool nativeMoveCursor(JNIEnv *env, jobject obj, - int key, int count, bool ignoreScroll) -{ - WebView* view = GET_NATIVE_VIEW(env, obj); - DBG_NAV_LOGD("env=%p obj=%p view=%p", env, obj, view); - LOG_ASSERT(view, "view not set in %s", __FUNCTION__); - return view->moveCursor(key, count, ignoreScroll); -} - -static void nativeRecordButtons(JNIEnv* env, jobject obj, bool hasFocus, - bool pressed, bool invalidate) -{ - WebView* view = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(view, "view not set in %s", __FUNCTION__); - view->nativeRecordButtons(hasFocus, pressed, invalidate); -} - -static void nativeSetFindIsUp(JNIEnv *env, jobject obj, jboolean isUp) -{ - WebView* view = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(view, "view not set in %s", __FUNCTION__); - view->setFindIsUp(isUp); -} - -static void nativeSetFindIsEmpty(JNIEnv *env, jobject obj) -{ - GET_NATIVE_VIEW(env, obj)->setFindIsEmpty(); -} - -static void nativeShowCursorTimed(JNIEnv *env, jobject obj) -{ - GET_NATIVE_VIEW(env, obj)->showCursorTimed(); -} - -static void nativeSetHeightCanMeasure(JNIEnv *env, jobject obj, bool measure) -{ - WebView* view = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(view, "view not set in nativeSetHeightCanMeasure"); - 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, "", "(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.right(), webRect.bottom()); - 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* 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(); -} - -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(cachedFocusNode))->setExport(webcoreString); - root->setTextGeneration(generation); - checkException(env); -} - -static jint nativeGetBlockLeftEdge(JNIEnv *env, jobject obj, jint x, jint y, - jfloat scale) -{ - WebView* view = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(view, "view not set in %s", __FUNCTION__); - if (!view) - return -1; - return view->getBlockLeftEdge(x, y, scale); -} - -static void nativeDestroy(JNIEnv *env, jobject obj) -{ - WebView* view = GET_NATIVE_VIEW(env, obj); - LOGD("nativeDestroy view: %p", view); - LOG_ASSERT(view, "view not set in nativeDestroy"); - delete view; -} - -static void nativeStopGL(JNIEnv *env, jobject obj) -{ - GET_NATIVE_VIEW(env, obj)->stopGL(); -} - -static bool nativeMoveCursorToNextTextInput(JNIEnv *env, jobject obj) -{ - WebView* view = GET_NATIVE_VIEW(env, obj); - CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); - if (!root) - return false; - const CachedNode* current = root->currentCursor(); - if (!current || !current->isTextInput()) - current = root->currentFocus(); - if (!current || !current->isTextInput()) - return false; - const CachedFrame* frame; - const CachedNode* next = root->nextTextField(current, &frame); - if (!next) - return false; - const WebCore::IntRect& bounds = next->bounds(frame); - root->rootHistory()->setMouseBounds(bounds); - view->getWebViewCore()->updateCursorBounds(root, frame, next); - view->showCursorUntimed(); - root->setCursor(const_cast(frame), - const_cast(next)); - view->sendMoveFocus(static_cast(frame->framePointer()), - static_cast(next->nodePointer())); - if (!next->isInLayer()) - view->scrollRectOnScreen(bounds); - view->getWebViewCore()->m_moveGeneration++; - return true; -} - -static int nativeMoveGeneration(JNIEnv *env, jobject obj) -{ - WebView* view = GET_NATIVE_VIEW(env, obj); - if (!view) - return 0; - return view->moveGeneration(); -} - -static void nativeMoveSelection(JNIEnv *env, jobject obj, int x, int y) -{ - GET_NATIVE_VIEW(env, obj)->moveSelection(x, y); -} - -static void nativeResetSelection(JNIEnv *env, jobject obj) -{ - return GET_NATIVE_VIEW(env, obj)->resetSelection(); -} - -static jobject nativeSelectableText(JNIEnv* env, jobject obj) -{ - IntPoint pos = GET_NATIVE_VIEW(env, obj)->selectableText(); - jclass pointClass = env->FindClass("android/graphics/Point"); - jmethodID init = env->GetMethodID(pointClass, "", "(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__); - 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, jboolean set, - jfloat scale, jint x, jint y) -{ - GET_NATIVE_VIEW(env, obj)->setSelectionPointer(set, scale, x, y); -} - -#ifdef ANDROID_DUMP_DISPLAY_TREE -static void dumpToFile(const char text[], void* file) { - fwrite(text, 1, strlen(text), reinterpret_cast(file)); - fwrite("\n", 1, 1, reinterpret_cast(file)); -} -#endif - -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__); - - if (view && view->getWebViewCore()) { - FILE* file = fopen(DISPLAY_TREE_LOG_FILE, "w"); - if (file) { - SkFormatDumper dumper(dumpToFile, file); - // dump the URL - if (jurl) { - const char* str = env->GetStringUTFChars(jurl, 0); - SkDebugf("Dumping %s to %s\n", str, DISPLAY_TREE_LOG_FILE); - dumpToFile(str, file); - env->ReleaseStringUTFChars(jurl, str); - } - // now dump the display tree - 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); - // we're done with the file now - fwrite("\n", 1, 1, file); - fclose(file); - } -#if USE(ACCELERATED_COMPOSITING) - const LayerAndroid* rootLayer = view->compositeRoot(); - if (rootLayer) { - FILE* file = fopen(LAYERS_TREE_LOG_FILE,"w"); - if (file) { - rootLayer->dumpLayers(file, 0); - fclose(file); - } - } -#endif - } -#endif -} - -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__); - SkIRect nativeRect, nativeBounds; - int id = view->scrollableLayer(x, y, &nativeRect, &nativeBounds); - if (rect) - GraphicsJNI::irect_to_jrect(nativeRect, env, rect); - if (bounds) - GraphicsJNI::irect_to_jrect(nativeBounds, env, bounds); - return id; -} - -static bool nativeScrollLayer(JNIEnv* env, jobject obj, jint layerId, jint x, - jint y) -{ -#if ENABLE(ANDROID_OVERFLOW_SCROLL) - WebView* view = GET_NATIVE_VIEW(env, obj); - LayerAndroid* root = view->compositeRoot(); - if (!root) - return false; - LayerAndroid* layer = root->findById(layerId); - if (!layer || !layer->contentIsScrollable()) - return false; - return static_cast(layer)->scrollTo(x, y); -#endif - return false; -} - -static void nativeSetExpandedTileBounds(JNIEnv*, jobject, jboolean enabled) -{ - TilesManager::instance()->setExpandedTileBounds(enabled); -} - -/* - * JNI registration - */ -static JNINativeMethod gJavaWebViewMethods[] = { - { "nativeCacheHitFramePointer", "()I", - (void*) nativeCacheHitFramePointer }, - { "nativeCacheHitIsPlugin", "()Z", - (void*) nativeCacheHitIsPlugin }, - { "nativeCacheHitNodeBounds", "()Landroid/graphics/Rect;", - (void*) nativeCacheHitNodeBounds }, - { "nativeCacheHitNodePointer", "()I", - (void*) nativeCacheHitNodePointer }, - { "nativeClearCursor", "()V", - (void*) nativeClearCursor }, - { "nativeCreate", "(ILjava/lang/String;Landroid/content/res/AssetManager;)V", - (void*) nativeCreate }, - { "nativeCursorFramePointer", "()I", - (void*) nativeCursorFramePointer }, - { "nativePageShouldHandleShiftAndArrows", "()Z", - (void*) nativePageShouldHandleShiftAndArrows }, - { "nativeCursorNodeBounds", "()Landroid/graphics/Rect;", - (void*) nativeCursorNodeBounds }, - { "nativeCursorNodePointer", "()I", - (void*) nativeCursorNodePointer }, - { "nativeCursorIntersects", "(Landroid/graphics/Rect;)Z", - (void*) nativeCursorIntersects }, - { "nativeCursorIsAnchor", "()Z", - (void*) nativeCursorIsAnchor }, - { "nativeCursorIsTextInput", "()Z", - (void*) nativeCursorIsTextInput }, - { "nativeCursorPosition", "()Landroid/graphics/Point;", - (void*) nativeCursorPosition }, - { "nativeCursorText", "()Ljava/lang/String;", - (void*) nativeCursorText }, - { "nativeCursorWantsKeyEvents", "()Z", - (void*)nativeCursorWantsKeyEvents }, - { "nativeDebugDump", "()V", - (void*) nativeDebugDump }, - { "nativeDestroy", "()V", - (void*) nativeDestroy }, - { "nativeDraw", "(Landroid/graphics/Canvas;IIZ)I", - (void*) nativeDraw }, - { "nativeGetDrawGLFunction", "(Landroid/graphics/Rect;Landroid/graphics/Rect;FI)I", - (void*) nativeGetDrawGLFunction }, - { "nativeUpdateDrawGLFunction", "(Landroid/graphics/Rect;Landroid/graphics/Rect;)V", - (void*) nativeUpdateDrawGLFunction }, - { "nativeDumpDisplayTree", "(Ljava/lang/String;)V", - (void*) nativeDumpDisplayTree }, - { "nativeEvaluateLayersAnimations", "()Z", - (void*) nativeEvaluateLayersAnimations }, - { "nativeExtendSelection", "(II)V", - (void*) nativeExtendSelection }, - { "nativeFindAll", "(Ljava/lang/String;Ljava/lang/String;Z)I", - (void*) nativeFindAll }, - { "nativeFindNext", "(Z)V", - (void*) nativeFindNext }, - { "nativeFindIndex", "()I", - (void*) nativeFindIndex}, - { "nativeFocusCandidateFramePointer", "()I", - (void*) nativeFocusCandidateFramePointer }, - { "nativeFocusCandidateHasNextTextfield", "()Z", - (void*) focusCandidateHasNextTextfield }, - { "nativeFocusCandidateIsPassword", "()Z", - (void*) nativeFocusCandidateIsPassword }, - { "nativeFocusCandidateIsRtlText", "()Z", - (void*) nativeFocusCandidateIsRtlText }, - { "nativeFocusCandidateIsTextInput", "()Z", - (void*) nativeFocusCandidateIsTextInput }, - { "nativeFocusCandidateLineHeight", "()I", - (void*) nativeFocusCandidateLineHeight }, - { "nativeFocusCandidateMaxLength", "()I", - (void*) nativeFocusCandidateMaxLength }, - { "nativeFocusCandidateIsAutoComplete", "()Z", - (void*) nativeFocusCandidateIsAutoComplete }, - { "nativeFocusCandidateName", "()Ljava/lang/String;", - (void*) nativeFocusCandidateName }, - { "nativeFocusCandidateNodeBounds", "()Landroid/graphics/Rect;", - (void*) nativeFocusCandidateNodeBounds }, - { "nativeFocusCandidatePaddingRect", "()Landroid/graphics/Rect;", - (void*) nativeFocusCandidatePaddingRect }, - { "nativeFocusCandidatePointer", "()I", - (void*) nativeFocusCandidatePointer }, - { "nativeFocusCandidateText", "()Ljava/lang/String;", - (void*) nativeFocusCandidateText }, - { "nativeFocusCandidateTextSize", "()F", - (void*) nativeFocusCandidateTextSize }, - { "nativeFocusCandidateType", "()I", - (void*) nativeFocusCandidateType }, - { "nativeFocusIsPlugin", "()Z", - (void*) nativeFocusIsPlugin }, - { "nativeFocusNodeBounds", "()Landroid/graphics/Rect;", - (void*) nativeFocusNodeBounds }, - { "nativeFocusNodePointer", "()I", - (void*) nativeFocusNodePointer }, - { "nativeGetCursorRingBounds", "()Landroid/graphics/Rect;", - (void*) nativeGetCursorRingBounds }, - { "nativeGetSelection", "()Ljava/lang/String;", - (void*) nativeGetSelection }, - { "nativeHasCursorNode", "()Z", - (void*) nativeHasCursorNode }, - { "nativeHasFocusNode", "()Z", - (void*) nativeHasFocusNode }, - { "nativeHideCursor", "()V", - (void*) nativeHideCursor }, - { "nativeHitSelection", "(II)Z", - (void*) nativeHitSelection }, - { "nativeImageURI", "(II)Ljava/lang/String;", - (void*) nativeImageURI }, - { "nativeInstrumentReport", "()V", - (void*) nativeInstrumentReport }, - { "nativeLayerBounds", "(I)Landroid/graphics/Rect;", - (void*) nativeLayerBounds }, - { "nativeMotionUp", "(III)Z", - (void*) nativeMotionUp }, - { "nativeMoveCursor", "(IIZ)Z", - (void*) nativeMoveCursor }, - { "nativeMoveCursorToNextTextInput", "()Z", - (void*) nativeMoveCursorToNextTextInput }, - { "nativeMoveGeneration", "()I", - (void*) nativeMoveGeneration }, - { "nativeMoveSelection", "(II)V", - (void*) nativeMoveSelection }, - { "nativePointInNavCache", "(III)Z", - (void*) nativePointInNavCache }, - { "nativeRecordButtons", "(ZZZ)V", - (void*) nativeRecordButtons }, - { "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;ZZ)V", - (void*) nativeSetBaseLayer }, - { "nativeReplaceBaseContent", "(I)V", - (void*) nativeReplaceBaseContent }, - { "nativeCopyBaseContentToPicture", "(Landroid/graphics/Picture;)V", - (void*) nativeCopyBaseContentToPicture }, - { "nativeHasContent", "()Z", - (void*) nativeHasContent }, - { "nativeSetSelectionPointer", "(ZFII)V", - (void*) nativeSetSelectionPointer }, - { "nativeShowCursorTimed", "()V", - (void*) nativeShowCursorTimed }, - { "nativeStartSelection", "(II)Z", - (void*) nativeStartSelection }, - { "nativeStopGL", "()V", - (void*) nativeStopGL }, - { "nativeSubtractLayers", "(Landroid/graphics/Rect;)Landroid/graphics/Rect;", - (void*) nativeSubtractLayers }, - { "nativeTextGeneration", "()I", - (void*) nativeTextGeneration }, - { "nativeUpdateCachedTextfield", "(Ljava/lang/String;I)V", - (void*) nativeUpdateCachedTextfield }, - { "nativeWordSelection", "(II)Z", - (void*) nativeWordSelection }, - { "nativeGetBlockLeftEdge", "(IIF)I", - (void*) nativeGetBlockLeftEdge }, - { "nativeScrollableLayer", "(IILandroid/graphics/Rect;Landroid/graphics/Rect;)I", - (void*) nativeScrollableLayer }, - { "nativeScrollLayer", "(III)Z", - (void*) nativeScrollLayer }, - { "nativeSetExpandedTileBounds", "(Z)V", - (void*) nativeSetExpandedTileBounds }, -}; - -int registerWebView(JNIEnv* env) -{ - jclass clazz = env->FindClass("android/webkit/WebView"); - LOG_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"); - env->DeleteLocalRef(clazz); - - return jniRegisterNativeMethods(env, "android/webkit/WebView", gJavaWebViewMethods, NELEM(gJavaWebViewMethods)); -} - -} // namespace android diff --git a/WebKit/android/plugins/ANPBitmapInterface.cpp b/WebKit/android/plugins/ANPBitmapInterface.cpp deleted file mode 100644 index 4c6ad7c..0000000 --- a/WebKit/android/plugins/ANPBitmapInterface.cpp +++ /dev/null @@ -1,71 +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. - */ - -// must include config.h first for webkit to fiddle with new/delete -#include "config.h" -#include "SkANP.h" -#include "SkColorPriv.h" - -static bool anp_getPixelPacking(ANPBitmapFormat fmt, ANPPixelPacking* packing) { - switch (fmt) { - case kRGBA_8888_ANPBitmapFormat: - if (packing) { - packing->AShift = SK_A32_SHIFT; - packing->ABits = SK_A32_BITS; - packing->RShift = SK_R32_SHIFT; - packing->RBits = SK_R32_BITS; - packing->GShift = SK_G32_SHIFT; - packing->GBits = SK_G32_BITS; - packing->BShift = SK_B32_SHIFT; - packing->BBits = SK_B32_BITS; - } - return true; - case kRGB_565_ANPBitmapFormat: - if (packing) { - packing->AShift = 0; - packing->ABits = 0; - packing->RShift = SK_R16_SHIFT; - packing->RBits = SK_R16_BITS; - packing->GShift = SK_G16_SHIFT; - packing->GBits = SK_G16_BITS; - packing->BShift = SK_B16_SHIFT; - packing->BBits = SK_B16_BITS; - } - return true; - default: - break; - } - return false; -} - -/////////////////////////////////////////////////////////////////////////////// - -#define ASSIGN(obj, name) (obj)->name = anp_##name - -void ANPBitmapInterfaceV0_Init(ANPInterface* value) { - ANPBitmapInterfaceV0* i = reinterpret_cast(value); - - ASSIGN(i, getPixelPacking); -} diff --git a/WebKit/android/plugins/ANPCanvasInterface.cpp b/WebKit/android/plugins/ANPCanvasInterface.cpp deleted file mode 100644 index d6d89ff..0000000 --- a/WebKit/android/plugins/ANPCanvasInterface.cpp +++ /dev/null @@ -1,197 +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. - */ - -// must include config.h first for webkit to fiddle with new/delete -#include "config.h" -#include "SkANP.h" - -static ANPCanvas* anp_newCanvas(const ANPBitmap* bitmap) { - SkBitmap bm; - return new ANPCanvas(*SkANP::SetBitmap(&bm, *bitmap)); -} - -static void anp_deleteCanvas(ANPCanvas* canvas) { - delete canvas; -} - -static void anp_save(ANPCanvas* canvas) { - canvas->skcanvas->save(); -} - -static void anp_restore(ANPCanvas* canvas) { - canvas->skcanvas->restore(); -} - -static void anp_translate(ANPCanvas* canvas, float tx, float ty) { - canvas->skcanvas->translate(SkFloatToScalar(tx), SkFloatToScalar(ty)); -} - -static void anp_scale(ANPCanvas* canvas, float sx, float sy) { - canvas->skcanvas->scale(SkFloatToScalar(sx), SkFloatToScalar(sy)); -} - -static void anp_rotate(ANPCanvas* canvas, float degrees) { - canvas->skcanvas->rotate(SkFloatToScalar(degrees)); -} - -static void anp_skew(ANPCanvas* canvas, float kx, float ky) { - canvas->skcanvas->skew(SkFloatToScalar(kx), SkFloatToScalar(ky)); -} - -static void anp_clipRect(ANPCanvas* canvas, const ANPRectF* rect) { - SkRect r; - canvas->skcanvas->clipRect(*SkANP::SetRect(&r, *rect)); -} - -static void anp_clipPath(ANPCanvas* canvas, const ANPPath* path) { - canvas->skcanvas->clipPath(*path); -} -static void anp_concat(ANPCanvas* canvas, const ANPMatrix* matrix) { - canvas->skcanvas->concat(*matrix); -} - -static void anp_getTotalMatrix(ANPCanvas* canvas, ANPMatrix* matrix) { - const SkMatrix& src = canvas->skcanvas->getTotalMatrix(); - *matrix = *reinterpret_cast(&src); -} - -static bool anp_getLocalClipBounds(ANPCanvas* canvas, ANPRectF* r, - bool antialias) { - SkRect bounds; - if (canvas->skcanvas->getClipBounds(&bounds, - antialias ? SkCanvas::kAA_EdgeType : SkCanvas::kBW_EdgeType)) { - SkANP::SetRect(r, bounds); - return true; - } - return false; -} - -static bool anp_getDeviceClipBounds(ANPCanvas* canvas, ANPRectI* r) { - const SkRegion& clip = canvas->skcanvas->getTotalClip(); - if (!clip.isEmpty()) { - SkANP::SetRect(r, clip.getBounds()); - return true; - } - return false; -} - -static void anp_drawColor(ANPCanvas* canvas, ANPColor color) { - canvas->skcanvas->drawColor(color); -} - -static void anp_drawPaint(ANPCanvas* canvas, const ANPPaint* paint) { - canvas->skcanvas->drawPaint(*paint); -} - -static void anp_drawLine(ANPCanvas* canvas, float x0, float y0, - float x1, float y1, const ANPPaint* paint) { - canvas->skcanvas->drawLine(SkFloatToScalar(x0), SkFloatToScalar(y0), - SkFloatToScalar(x1), SkFloatToScalar(y1), *paint); -} - -static void anp_drawRect(ANPCanvas* canvas, const ANPRectF* rect, - const ANPPaint* paint) { - SkRect r; - canvas->skcanvas->drawRect(*SkANP::SetRect(&r, *rect), *paint); -} - -static void anp_drawOval(ANPCanvas* canvas, const ANPRectF* rect, - const ANPPaint* paint) { - SkRect r; - canvas->skcanvas->drawOval(*SkANP::SetRect(&r, *rect), *paint); -} - -static void anp_drawPath(ANPCanvas* canvas, const ANPPath* path, - const ANPPaint* paint) { - canvas->skcanvas->drawPath(*path, *paint); -} - -static void anp_drawText(ANPCanvas* canvas, const void* text, uint32_t length, - float x, float y, const ANPPaint* paint) { - canvas->skcanvas->drawText(text, length, - SkFloatToScalar(x), SkFloatToScalar(y), - *paint); -} - -static void anp_drawPosText(ANPCanvas* canvas, const void* text, - uint32_t byteLength, const float xy[], const ANPPaint* paint) { - canvas->skcanvas->drawPosText(text, byteLength, - reinterpret_cast(xy), *paint); -} - -static void anp_drawBitmap(ANPCanvas* canvas, const ANPBitmap* bitmap, - float x, float y, const ANPPaint* paint) { - SkBitmap bm; - canvas->skcanvas->drawBitmap(*SkANP::SetBitmap(&bm, *bitmap), - SkFloatToScalar(x), SkFloatToScalar(y), - paint); -} - -static void anp_drawBitmapRect(ANPCanvas* canvas, const ANPBitmap* bitmap, - const ANPRectI* src, const ANPRectF* dst, - const ANPPaint* paint) { - SkBitmap bm; - SkRect dstR; - SkIRect srcR, *srcPtr = NULL; - - if (src) { - srcPtr = SkANP::SetRect(&srcR, *src); - } - canvas->skcanvas->drawBitmapRect(*SkANP::SetBitmap(&bm, *bitmap), srcPtr, - *SkANP::SetRect(&dstR, *dst), paint); -} - -/////////////////////////////////////////////////////////////////////////////// - -#define ASSIGN(obj, name) (obj)->name = anp_##name - -void ANPCanvasInterfaceV0_Init(ANPInterface* value) { - ANPCanvasInterfaceV0* i = reinterpret_cast(value); - - ASSIGN(i, newCanvas); - ASSIGN(i, deleteCanvas); - ASSIGN(i, save); - ASSIGN(i, restore); - ASSIGN(i, translate); - ASSIGN(i, scale); - ASSIGN(i, rotate); - ASSIGN(i, skew); - ASSIGN(i, clipRect); - ASSIGN(i, clipPath); - ASSIGN(i, concat); - ASSIGN(i, getTotalMatrix); - ASSIGN(i, getLocalClipBounds); - ASSIGN(i, getDeviceClipBounds); - ASSIGN(i, drawColor); - ASSIGN(i, drawPaint); - ASSIGN(i, drawLine); - ASSIGN(i, drawRect); - ASSIGN(i, drawOval); - ASSIGN(i, drawPath); - ASSIGN(i, drawText); - ASSIGN(i, drawPosText); - ASSIGN(i, drawBitmap); - ASSIGN(i, drawBitmapRect); -} diff --git a/WebKit/android/plugins/ANPEventInterface.cpp b/WebKit/android/plugins/ANPEventInterface.cpp deleted file mode 100644 index 2fdf159..0000000 --- a/WebKit/android/plugins/ANPEventInterface.cpp +++ /dev/null @@ -1,84 +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. - */ - -// must include config.h first for webkit to fiddle with new/delete -#include "config.h" -#include "SkANP.h" -#include "WebViewCore.h" -#include "PluginView.h" -#include "PluginWidgetAndroid.h" - -#include "JavaSharedClient.h" - -using namespace android; - -struct WrappedANPEvent { - WebViewCore* fWVC; - PluginWidgetAndroid* fPWA; - ANPEvent fEvent; -}; - -/* Its possible we may be called after the plugin that initiated the event - has been torn-down. Thus we check that the assicated webviewcore and - pluginwidget are still active before dispatching the event. - */ -static void send_anpevent(void* data) { - WrappedANPEvent* wrapper = static_cast(data); - WebViewCore* core = wrapper->fWVC; - PluginWidgetAndroid* widget = wrapper->fPWA; - - // be sure we're still alive before delivering the event - if (WebViewCore::isInstance(core) && core->isPlugin(widget)) { - widget->sendEvent(wrapper->fEvent); - } - delete wrapper; -} - -static void anp_postEvent(NPP instance, const ANPEvent* event) { - if (instance && instance->ndata && event) { - PluginView* pluginView = static_cast(instance->ndata); - PluginWidgetAndroid* pluginWidget = pluginView->platformPluginWidget(); - WebViewCore* wvc = pluginWidget->webViewCore(); - - WrappedANPEvent* wrapper = new WrappedANPEvent; - // recored these, and recheck that they are valid before delivery - // in send_anpevent - wrapper->fWVC = pluginWidget->webViewCore(); - wrapper->fPWA = pluginWidget; - // make a copy of the event - wrapper->fEvent = *event; - JavaSharedClient::EnqueueFunctionPtr(send_anpevent, wrapper); - } -} - -/////////////////////////////////////////////////////////////////////////////// - -#define ASSIGN(obj, name) (obj)->name = anp_##name - -void ANPEventInterfaceV0_Init(ANPInterface* value) { - ANPEventInterfaceV0* i = reinterpret_cast(value); - - ASSIGN(i, postEvent); -} diff --git a/WebKit/android/plugins/ANPKeyCodes.h b/WebKit/android/plugins/ANPKeyCodes.h deleted file mode 100644 index 969679f..0000000 --- a/WebKit/android/plugins/ANPKeyCodes.h +++ /dev/null @@ -1,229 +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 ANPKeyCodes_DEFINED -#define ANPKeyCodes_DEFINED - -/* List the key codes that are set to a plugin in the ANPKeyEvent. - - These exactly match the values in android/view/KeyEvent.java and the - corresponding .h file android/keycodes.h. -*/ -enum ANPKeyCodes { - kUnknown_ANPKeyCode = 0, - - kSoftLeft_ANPKeyCode = 1, - kSoftRight_ANPKeyCode = 2, - kHome_ANPKeyCode = 3, - kBack_ANPKeyCode = 4, - kCall_ANPKeyCode = 5, - kEndCall_ANPKeyCode = 6, - k0_ANPKeyCode = 7, - k1_ANPKeyCode = 8, - k2_ANPKeyCode = 9, - k3_ANPKeyCode = 10, - k4_ANPKeyCode = 11, - k5_ANPKeyCode = 12, - k6_ANPKeyCode = 13, - k7_ANPKeyCode = 14, - k8_ANPKeyCode = 15, - k9_ANPKeyCode = 16, - kStar_ANPKeyCode = 17, - kPound_ANPKeyCode = 18, - kDpadUp_ANPKeyCode = 19, - kDpadDown_ANPKeyCode = 20, - kDpadLeft_ANPKeyCode = 21, - kDpadRight_ANPKeyCode = 22, - kDpadCenter_ANPKeyCode = 23, - kVolumeUp_ANPKeyCode = 24, - kVolumeDown_ANPKeyCode = 25, - kPower_ANPKeyCode = 26, - kCamera_ANPKeyCode = 27, - kClear_ANPKeyCode = 28, - kA_ANPKeyCode = 29, - kB_ANPKeyCode = 30, - kC_ANPKeyCode = 31, - kD_ANPKeyCode = 32, - kE_ANPKeyCode = 33, - kF_ANPKeyCode = 34, - kG_ANPKeyCode = 35, - kH_ANPKeyCode = 36, - kI_ANPKeyCode = 37, - kJ_ANPKeyCode = 38, - kK_ANPKeyCode = 39, - kL_ANPKeyCode = 40, - kM_ANPKeyCode = 41, - kN_ANPKeyCode = 42, - kO_ANPKeyCode = 43, - kP_ANPKeyCode = 44, - kQ_ANPKeyCode = 45, - kR_ANPKeyCode = 46, - kS_ANPKeyCode = 47, - kT_ANPKeyCode = 48, - kU_ANPKeyCode = 49, - kV_ANPKeyCode = 50, - kW_ANPKeyCode = 51, - kX_ANPKeyCode = 52, - kY_ANPKeyCode = 53, - kZ_ANPKeyCode = 54, - kComma_ANPKeyCode = 55, - kPeriod_ANPKeyCode = 56, - kAltLeft_ANPKeyCode = 57, - kAltRight_ANPKeyCode = 58, - kShiftLeft_ANPKeyCode = 59, - kShiftRight_ANPKeyCode = 60, - kTab_ANPKeyCode = 61, - kSpace_ANPKeyCode = 62, - kSym_ANPKeyCode = 63, - kExplorer_ANPKeyCode = 64, - kEnvelope_ANPKeyCode = 65, - kNewline_ANPKeyCode = 66, - kDel_ANPKeyCode = 67, - kGrave_ANPKeyCode = 68, - kMinus_ANPKeyCode = 69, - kEquals_ANPKeyCode = 70, - kLeftBracket_ANPKeyCode = 71, - kRightBracket_ANPKeyCode = 72, - kBackslash_ANPKeyCode = 73, - kSemicolon_ANPKeyCode = 74, - kApostrophe_ANPKeyCode = 75, - kSlash_ANPKeyCode = 76, - kAt_ANPKeyCode = 77, - kNum_ANPKeyCode = 78, - kHeadSetHook_ANPKeyCode = 79, - kFocus_ANPKeyCode = 80, - kPlus_ANPKeyCode = 81, - kMenu_ANPKeyCode = 82, - kNotification_ANPKeyCode = 83, - kSearch_ANPKeyCode = 84, - kMediaPlayPause_ANPKeyCode = 85, - kMediaStop_ANPKeyCode = 86, - kMediaNext_ANPKeyCode = 87, - kMediaPrevious_ANPKeyCode = 88, - kMediaRewind_ANPKeyCode = 89, - kMediaFastForward_ANPKeyCode = 90, - kMute_ANPKeyCode = 91, - kPageUp_ANPKeyCode = 92, - kPageDown_ANPKeyCode = 93, - kPictsymbols_ANPKeyCode = 94, - kSwitchCharset_ANPKeyCode = 95, - kButtonA_ANPKeyCode = 96, - kButtonB_ANPKeyCode = 97, - kButtonC_ANPKeyCode = 98, - kButtonX_ANPKeyCode = 99, - kButtonY_ANPKeyCode = 100, - kButtonZ_ANPKeyCode = 101, - kButtonL1_ANPKeyCode = 102, - kButtonR1_ANPKeyCode = 103, - kButtonL2_ANPKeyCode = 104, - kButtonR2_ANPKeyCode = 105, - kButtonThumbL_ANPKeyCode = 106, - kButtonThumbR_ANPKeyCode = 107, - kButtonStart_ANPKeyCode = 108, - kButtonSelect_ANPKeyCode = 109, - kButtonMode_ANPKeyCode = 110, - kEscape_ANPKeyCode = 111, - kForwardDel_ANPKeyCode = 112, - kCtrlLeft_ANPKeyCode = 113, - kCtrlRight_ANPKeyCode = 114, - kCapsLock_ANPKeyCode = 115, - kScrollLock_ANPKeyCode = 116, - kMetaLeft_ANPKeyCode = 117, - kMetaRight_ANPKeyCode = 118, - kFunction_ANPKeyCode = 119, - kSysRq_ANPKeyCode = 120, - kBreak_ANPKeyCode = 121, - kMoveHome_ANPKeyCode = 122, - kMoveEnd_ANPKeyCode = 123, - kInsert_ANPKeyCode = 124, - kForward_ANPKeyCode = 125, - kMediaPlay_ANPKeyCode = 126, - kMediaPause_ANPKeyCode = 127, - kMediaClose_ANPKeyCode = 128, - kMediaEject_ANPKeyCode = 129, - kMediaRecord_ANPKeyCode = 130, - kF1_ANPKeyCode = 131, - kF2_ANPKeyCode = 132, - kF3_ANPKeyCode = 133, - kF4_ANPKeyCode = 134, - kF5_ANPKeyCode = 135, - kF6_ANPKeyCode = 136, - kF7_ANPKeyCode = 137, - kF8_ANPKeyCode = 138, - kF9_ANPKeyCode = 139, - kF10_ANPKeyCode = 140, - kF11_ANPKeyCode = 141, - kF12_ANPKeyCode = 142, - kNumLock_ANPKeyCode = 143, - kNumPad0_ANPKeyCode = 144, - kNumPad1_ANPKeyCode = 145, - kNumPad2_ANPKeyCode = 146, - kNumPad3_ANPKeyCode = 147, - kNumPad4_ANPKeyCode = 148, - kNumPad5_ANPKeyCode = 149, - kNumPad6_ANPKeyCode = 150, - kNumPad7_ANPKeyCode = 151, - kNumPad8_ANPKeyCode = 152, - kNumPad9_ANPKeyCode = 153, - kNumPadDivide_ANPKeyCode = 154, - kNumPadMultiply_ANPKeyCode = 155, - kNumPadSubtract_ANPKeyCode = 156, - kNumPadAdd_ANPKeyCode = 157, - kNumPadDot_ANPKeyCode = 158, - kNumPadComma_ANPKeyCode = 159, - kNumPadEnter_ANPKeyCode = 160, - kNumPadEquals_ANPKeyCode = 161, - kNumPadLeftParen_ANPKeyCode = 162, - kNumPadRightParen_ANPKeyCode = 163, - kVolumeMute_ANPKeyCode = 164, - kInfo_ANPKeyCode = 165, - kChannelUp_ANPKeyCode = 166, - kChannelDown_ANPKeyCode = 167, - kZoomIn_ANPKeyCode = 168, - kZoomOut_ANPKeyCode = 169, - kTv_ANPKeyCode = 170, - kWindow_ANPKeyCode = 171, - kGuide_ANPKeyCode = 172, - kDvr_ANPKeyCode = 173, - kBookmark_ANPKeyCode = 174, - kCaptions_ANPKeyCode = 175, - kSettings_ANPKeyCode = 176, - kTvPower_ANPKeyCode = 177, - kTvInput_ANPKeyCode = 178, - kStbPower_ANPKeyCode = 179, - kStbInput_ANPKeyCode = 180, - kAvrPower_ANPKeyCode = 181, - kAvrInput_ANPKeyCode = 182, - kProgRed_ANPKeyCode = 183, - kProgGreen_ANPKeyCode = 184, - kProgYellow_ANPKeyCode = 185, - kProgBlue_ANPKeyCode = 186, - kAppSwitch_ANPKeyCode = 187, - - // NOTE: If you add a new keycode here you must also add it to several other files. - // Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list. -}; - -#endif diff --git a/WebKit/android/plugins/ANPLogInterface.cpp b/WebKit/android/plugins/ANPLogInterface.cpp deleted file mode 100644 index 23a4ed6..0000000 --- a/WebKit/android/plugins/ANPLogInterface.cpp +++ /dev/null @@ -1,60 +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 "webkitPlugin" - -#include "utils/Log.h" -#include "android_npapi.h" -#include - -static void anp_log(ANPLogType logType, const char format[], ...) { - va_list args; - va_start(args, format); - - android_LogPriority priority; - switch (logType) { - case kError_ANPLogType: - priority = ANDROID_LOG_ERROR; - break; - case kWarning_ANPLogType: - priority = ANDROID_LOG_WARN; - break; - case kDebug_ANPLogType: - priority = ANDROID_LOG_DEBUG; - break; - default: - priority = ANDROID_LOG_UNKNOWN; - break; - } - LOG_PRI_VA(priority, "plugin", format, args); - - va_end(args); -} - -void ANPLogInterfaceV0_Init(ANPInterface* value) { - ANPLogInterfaceV0* i = reinterpret_cast(value); - - i->log = anp_log; -} diff --git a/WebKit/android/plugins/ANPMatrixInterface.cpp b/WebKit/android/plugins/ANPMatrixInterface.cpp deleted file mode 100644 index f322315..0000000 --- a/WebKit/android/plugins/ANPMatrixInterface.cpp +++ /dev/null @@ -1,167 +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. - */ - -// must include config.h first for webkit to fiddle with new/delete -#include "config.h" -#include "SkANP.h" - -#ifdef SK_SCALAR_IS_FIXED -static void fromFloat(SkScalar dst[], const float src[], int n) { - for (int i = 0; i < n; i++) { - dst[i] = SkFloatToScalar(src[i]); - } -} - -static void toFloat(float dst[], const SkScalar src[], int n) { - for (int i = 0; i < n; i++) { - dst[i] = SkScalarToFloat(src[i]); - } -} -#endif - -static ANPMatrix* anp_newMatrix() { - return new ANPMatrix; -} - -static void anp_deleteMatrix(ANPMatrix* matrix) { - delete matrix; -} - -static ANPMatrixFlag anp_getFlags(const ANPMatrix* matrix) { - return matrix->getType(); -} - -static void anp_copy(ANPMatrix* dst, const ANPMatrix* src) { - *dst = *src; -} - -static void anp_get3x3(const ANPMatrix* matrix, float dst[9]) { - for (int i = 0; i < 9; i++) { - dst[i] = SkScalarToFloat(matrix->get(i)); - } -} - -static void anp_set3x3(ANPMatrix* matrix, const float src[9]) { - for (int i = 0; i < 9; i++) { - matrix->set(i, SkFloatToScalar(src[i])); - } -} - -static void anp_setIdentity(ANPMatrix* matrix) { - matrix->reset(); -} - -static void anp_preTranslate(ANPMatrix* matrix, float tx, float ty) { - matrix->preTranslate(SkFloatToScalar(tx), SkFloatToScalar(ty)); -} - -static void anp_postTranslate(ANPMatrix* matrix, float tx, float ty) { - matrix->postTranslate(SkFloatToScalar(tx), SkFloatToScalar(ty)); -} - -static void anp_preScale(ANPMatrix* matrix, float sx, float sy) { - matrix->preScale(SkFloatToScalar(sx), SkFloatToScalar(sy)); -} - -static void anp_postScale(ANPMatrix* matrix, float sx, float sy) { - matrix->postScale(SkFloatToScalar(sx), SkFloatToScalar(sy)); -} - -static void anp_preSkew(ANPMatrix* matrix, float kx, float ky) { - matrix->preSkew(SkFloatToScalar(kx), SkFloatToScalar(ky)); -} - -static void anp_postSkew(ANPMatrix* matrix, float kx, float ky) { - matrix->postSkew(SkFloatToScalar(kx), SkFloatToScalar(ky)); -} - -static void anp_preRotate(ANPMatrix* matrix, float degrees) { - matrix->preRotate(SkFloatToScalar(degrees)); -} - -static void anp_postRotate(ANPMatrix* matrix, float degrees) { - matrix->postRotate(SkFloatToScalar(degrees)); -} - -static void anp_preConcat(ANPMatrix* matrix, const ANPMatrix* other) { - matrix->preConcat(*other); -} - -static void anp_postConcat(ANPMatrix* matrix, const ANPMatrix* other) { - matrix->postConcat(*other); -} - -static bool anp_invert(ANPMatrix* dst, const ANPMatrix* src) { - return src->invert(dst); -} - -static void anp_mapPoints(ANPMatrix* matrix, float dst[], const float src[], - int32_t count) { -#ifdef SK_SCALAR_IS_FLOAT - matrix->mapPoints(reinterpret_cast(dst), - reinterpret_cast(src), count); -#else - const int N = 64; - SkPoint tmp[N]; - do { - int n = count; - if (n > N) { - n = N; - } - fromFloat(&tmp[0].fX, src, n*2); - matrix->mapPoints(tmp, n); - toFloat(dst, &tmp[0].fX, n*2); - count -= n; - } while (count > 0); -#endif -} - -/////////////////////////////////////////////////////////////////////////////// - -#define ASSIGN(obj, name) (obj)->name = anp_##name - -void ANPMatrixInterfaceV0_Init(ANPInterface* value) { - ANPMatrixInterfaceV0* i = reinterpret_cast(value); - - ASSIGN(i, newMatrix); - ASSIGN(i, deleteMatrix); - ASSIGN(i, getFlags); - ASSIGN(i, copy); - ASSIGN(i, get3x3); - ASSIGN(i, set3x3); - ASSIGN(i, setIdentity); - ASSIGN(i, preTranslate); - ASSIGN(i, postTranslate); - ASSIGN(i, preScale); - ASSIGN(i, postScale); - ASSIGN(i, preSkew); - ASSIGN(i, postSkew); - ASSIGN(i, preRotate); - ASSIGN(i, postRotate); - ASSIGN(i, preConcat); - ASSIGN(i, postConcat); - ASSIGN(i, invert); - ASSIGN(i, mapPoints); -} diff --git a/WebKit/android/plugins/ANPOpenGLInterface.cpp b/WebKit/android/plugins/ANPOpenGLInterface.cpp deleted file mode 100644 index 839ec17..0000000 --- a/WebKit/android/plugins/ANPOpenGLInterface.cpp +++ /dev/null @@ -1,121 +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. - */ - -// must include config.h first for webkit to fiddle with new/delete -#include "config.h" - -#include "ANPOpenGL_npapi.h" -#include "PluginView.h" -#include "PluginWidgetAndroid.h" -#include "MediaLayer.h" -#include "WebViewCore.h" -#include "Frame.h" -#include "Page.h" -#include "Chrome.h" -#include "ChromeClient.h" - -using namespace android; - -static WebCore::PluginView* pluginViewForInstance(NPP instance) { - if (instance && instance->ndata) - return static_cast(instance->ndata); - return WebCore::PluginView::currentPluginView(); -} - -static EGLContext anp_acquireContext(NPP instance) { - WebCore::PluginView* pluginView = pluginViewForInstance(instance); - PluginWidgetAndroid* pluginWidget = pluginView->platformPluginWidget(); - WebCore::MediaLayer* mediaLayer = pluginWidget->getLayer(); - - if (!mediaLayer) - return EGL_NO_CONTEXT; - - return mediaLayer->getTexture()->producerAcquireContext(); -} - -static ANPTextureInfo anp_lockTexture(NPP instance) { - WebCore::PluginView* pluginView = pluginViewForInstance(instance); - PluginWidgetAndroid* pluginWidget = pluginView->platformPluginWidget(); - WebCore::MediaLayer* mediaLayer = pluginWidget->getLayer(); - WebCore::DoubleBufferedTexture* texture = mediaLayer->getTexture(); - - // lock the texture and cache the internal info - WebCore::TextureInfo* info = texture->producerLock(); - mediaLayer->setCurrentTextureInfo(info); - - ANPTextureInfo anpInfo; - anpInfo.textureId = info->m_textureId; - anpInfo.width = (int32_t) info->m_width; - anpInfo.height = (int32_t) info->m_height; - anpInfo.internalFormat = info->m_internalFormat; - return anpInfo; -} - -static void anp_releaseTexture(NPP instance, const ANPTextureInfo* textureInfo) { - WebCore::PluginView* pluginView = pluginViewForInstance(instance); - PluginWidgetAndroid* pluginWidget = pluginView->platformPluginWidget(); - WebCore::MediaLayer* mediaLayer = pluginWidget->getLayer(); - WebCore::DoubleBufferedTexture* texture = mediaLayer->getTexture(); - - //copy the info into our internal structure - WebCore::TextureInfo* info = mediaLayer->getCurrentTextureInfo(); - info->m_textureId = textureInfo->textureId; - info->m_width = textureInfo->width; - info->m_height = textureInfo->height; - info->m_internalFormat = textureInfo->internalFormat; - - texture->producerReleaseAndSwap(); - - // invalidate the java view so that this content is drawn - pluginWidget->viewInvalidate(); -} - -static void anp_invertPluginContent(NPP instance, bool isContentInverted) { - WebCore::PluginView* pluginView = pluginViewForInstance(instance); - PluginWidgetAndroid* pluginWidget = pluginView->platformPluginWidget(); - WebCore::MediaLayer* mediaLayer = pluginWidget->getLayer(); - - mediaLayer->invertContents(isContentInverted); - - //force the layer to sync to the UI thread - WebViewCore* wvc = pluginWidget->webViewCore(); - if (wvc) - wvc->mainFrame()->page()->chrome()->client()->scheduleCompositingLayerSync(); -} - - - -/////////////////////////////////////////////////////////////////////////////// - -#define ASSIGN(obj, name) (obj)->name = anp_##name - -void ANPOpenGLInterfaceV0_Init(ANPInterface* v) { - ANPOpenGLInterfaceV0* i = reinterpret_cast(v); - - ASSIGN(i, acquireContext); - ASSIGN(i, lockTexture); - ASSIGN(i, releaseTexture); - ASSIGN(i, invertPluginContent); -} diff --git a/WebKit/android/plugins/ANPOpenGL_npapi.h b/WebKit/android/plugins/ANPOpenGL_npapi.h deleted file mode 100644 index 5aabbc4..0000000 --- a/WebKit/android/plugins/ANPOpenGL_npapi.h +++ /dev/null @@ -1,63 +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 ANPOpenGL_npapi_H -#define ANPOpenGL_npapi_H - -#include "android_npapi.h" -#include -#include - -/** - * TODO should we not use EGL and GL data types for ABI safety? - */ -struct ANPTextureInfo { - GLuint textureId; - uint32_t width; - uint32_t height; - GLenum internalFormat; -}; - -struct ANPOpenGLInterfaceV0 : ANPInterface { - /** - */ - EGLContext (*acquireContext)(NPP instance); - - /** - */ - ANPTextureInfo (*lockTexture)(NPP instance); - - /** - */ - void (*releaseTexture)(NPP instance, const ANPTextureInfo*); - - /** - * Invert the contents of the plugin on the y-axis. - * default is to not be inverted (i.e. use OpenGL coordinates) - */ - void (*invertPluginContent)(NPP instance, bool isContentInverted); -}; - -#endif //ANPOpenGL_npapi_H diff --git a/WebKit/android/plugins/ANPPaintInterface.cpp b/WebKit/android/plugins/ANPPaintInterface.cpp deleted file mode 100644 index 5c59df9..0000000 --- a/WebKit/android/plugins/ANPPaintInterface.cpp +++ /dev/null @@ -1,212 +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. - */ - -// must include config.h first for webkit to fiddle with new/delete -#include "config.h" -#include "SkANP.h" -#include "SkTypeface.h" - -static ANPPaint* anp_newPaint() { - return new ANPPaint; -} - -static void anp_deletePaint(ANPPaint* paint) { - delete paint; -} - -static ANPPaintFlags anp_getFlags(const ANPPaint* paint) { - return paint->getFlags(); -} - -static void anp_setFlags(ANPPaint* paint, ANPPaintFlags flags) { - paint->setFlags(flags); -} - -static ANPColor anp_getColor(const ANPPaint* paint) { - return paint->getColor(); -} - -static void anp_setColor(ANPPaint* paint, ANPColor color) { - paint->setColor(color); -} - -static ANPPaintStyle anp_getStyle(const ANPPaint* paint) { - return paint->getStyle(); -} - -static void anp_setStyle(ANPPaint* paint, ANPPaintStyle style) { - paint->setStyle(static_cast(style)); -} - -static float anp_getStrokeWidth(const ANPPaint* paint) { - return SkScalarToFloat(paint->getStrokeWidth()); -} - -static float anp_getStrokeMiter(const ANPPaint* paint) { - return SkScalarToFloat(paint->getStrokeMiter()); -} - -static ANPPaintCap anp_getStrokeCap(const ANPPaint* paint) { - return paint->getStrokeCap(); -} - -static ANPPaintJoin anp_getStrokeJoin(const ANPPaint* paint) { - return paint->getStrokeJoin(); -} - -static void anp_setStrokeWidth(ANPPaint* paint, float width) { - paint->setStrokeWidth(SkFloatToScalar(width)); -} - -static void anp_setStrokeMiter(ANPPaint* paint, float miter) { - paint->setStrokeMiter(SkFloatToScalar(miter)); -} - -static void anp_setStrokeCap(ANPPaint* paint, ANPPaintCap cap) { - paint->setStrokeCap(static_cast(cap)); -} - -static void anp_setStrokeJoin(ANPPaint* paint, ANPPaintJoin join) { - paint->setStrokeJoin(static_cast(join)); -} - -static ANPTextEncoding anp_getTextEncoding(const ANPPaint* paint) { - return paint->getTextEncoding(); -} - -static ANPPaintAlign anp_getTextAlign(const ANPPaint* paint) { - return paint->getTextAlign(); -} - -static float anp_getTextSize(const ANPPaint* paint) { - return SkScalarToFloat(paint->getTextSize()); -} - -static float anp_getTextScaleX(const ANPPaint* paint) { - return SkScalarToFloat(paint->getTextScaleX()); -} - -static float anp_getTextSkewX(const ANPPaint* paint) { - return SkScalarToFloat(paint->getTextSkewX()); -} - -static ANPTypeface* anp_getTypeface(const ANPPaint* paint) { - return reinterpret_cast(paint->getTypeface()); -} - -static void anp_setTextEncoding(ANPPaint* paint, ANPTextEncoding encoding) { - paint->setTextEncoding(static_cast(encoding)); -} - -static void anp_setTextAlign(ANPPaint* paint, ANPPaintAlign align) { - paint->setTextAlign(static_cast(align)); -} - -static void anp_setTextSize(ANPPaint* paint, float textSize) { - paint->setTextSize(SkFloatToScalar(textSize)); -} - -static void anp_setTextScaleX(ANPPaint* paint, float scaleX) { - paint->setTextScaleX(SkFloatToScalar(scaleX)); -} - -static void anp_setTextSkewX(ANPPaint* paint, float skewX) { - paint->setTextSkewX(SkFloatToScalar(skewX)); -} - -static void anp_setTypeface(ANPPaint* paint, ANPTypeface* tf) { - paint->setTypeface(tf); -} - -static float anp_measureText(ANPPaint* paint, const void* text, - uint32_t byteLength, ANPRectF* bounds) { - SkScalar w = paint->measureText(text, byteLength, - reinterpret_cast(bounds)); - return SkScalarToFloat(w); -} - -/** Return the number of unichars specifed by the text. - If widths is not null, returns the array of advance widths for each - unichar. - If bounds is not null, returns the array of bounds for each unichar. - */ -static int anp_getTextWidths(ANPPaint* paint, const void* text, - uint32_t byteLength, float widths[], ANPRectF bounds[]) { - return paint->getTextWidths(text, byteLength, widths, - reinterpret_cast(bounds)); -} - -static float anp_getFontMetrics(ANPPaint* paint, ANPFontMetrics* metrics) { - SkPaint::FontMetrics fm; - SkScalar spacing = paint->getFontMetrics(&fm); - if (metrics) { - metrics->fTop = SkScalarToFloat(fm.fTop); - metrics->fAscent = SkScalarToFloat(fm.fAscent); - metrics->fDescent = SkScalarToFloat(fm.fDescent); - metrics->fBottom = SkScalarToFloat(fm.fBottom); - metrics->fLeading = SkScalarToFloat(fm.fLeading); - } - return SkScalarToFloat(spacing); -} - -/////////////////////////////////////////////////////////////////////////////// - -#define ASSIGN(obj, name) (obj)->name = anp_##name - -void ANPPaintInterfaceV0_Init(ANPInterface* value) { - ANPPaintInterfaceV0* i = reinterpret_cast(value); - - ASSIGN(i, newPaint); - ASSIGN(i, deletePaint); - ASSIGN(i, getFlags); - ASSIGN(i, setFlags); - ASSIGN(i, getColor); - ASSIGN(i, setColor); - ASSIGN(i, getStyle); - ASSIGN(i, setStyle); - ASSIGN(i, getStrokeWidth); - ASSIGN(i, getStrokeMiter); - ASSIGN(i, getStrokeCap); - ASSIGN(i, getStrokeJoin); - ASSIGN(i, setStrokeWidth); - ASSIGN(i, setStrokeMiter); - ASSIGN(i, setStrokeCap); - ASSIGN(i, setStrokeJoin); - ASSIGN(i, getTextEncoding); - ASSIGN(i, getTextAlign); - ASSIGN(i, getTextSize); - ASSIGN(i, getTextScaleX); - ASSIGN(i, getTextSkewX); - ASSIGN(i, getTypeface); - ASSIGN(i, setTextEncoding); - ASSIGN(i, setTextAlign); - ASSIGN(i, setTextSize); - ASSIGN(i, setTextScaleX); - ASSIGN(i, setTextSkewX); - ASSIGN(i, setTypeface); - ASSIGN(i, measureText); - ASSIGN(i, getTextWidths); - ASSIGN(i, getFontMetrics); -} diff --git a/WebKit/android/plugins/ANPPathInterface.cpp b/WebKit/android/plugins/ANPPathInterface.cpp deleted file mode 100644 index 69cabcf..0000000 --- a/WebKit/android/plugins/ANPPathInterface.cpp +++ /dev/null @@ -1,112 +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. - */ - -// must include config.h first for webkit to fiddle with new/delete -#include "config.h" -#include "SkANP.h" - -static ANPPath* anp_newPath() { - return new ANPPath; -} - -static void anp_deletePath(ANPPath* path) { - delete path; -} - -static void anp_copy(ANPPath* dst, const ANPPath* src) { - *dst = *src; -} - -static bool anp_equal(const ANPPath* p0, const ANPPath* p1) { - return *p0 == *p1; -} - -static void anp_reset(ANPPath* path) { - path->reset(); -} - -static bool anp_isEmpty(const ANPPath* path) { - return path->isEmpty(); -} - -static void anp_getBounds(const ANPPath* path, ANPRectF* bounds) { - SkANP::SetRect(bounds, path->getBounds()); -} - -static void anp_moveTo(ANPPath* path, float x, float y) { - path->moveTo(SkFloatToScalar(x), SkFloatToScalar(y)); -} - -static void anp_lineTo(ANPPath* path, float x, float y) { - path->lineTo(SkFloatToScalar(x), SkFloatToScalar(y)); -} - -static void anp_quadTo(ANPPath* path, float x0, float y0, float x1, float y1) { - path->quadTo(SkFloatToScalar(x0), SkFloatToScalar(y0), - SkFloatToScalar(x1), SkFloatToScalar(y1)); -} - -static void anp_cubicTo(ANPPath* path, float x0, float y0, - float x1, float y1, float x2, float y2) { - path->cubicTo(SkFloatToScalar(x0), SkFloatToScalar(y0), - SkFloatToScalar(x1), SkFloatToScalar(y1), - SkFloatToScalar(x2), SkFloatToScalar(y2)); -} - -static void anp_close(ANPPath* path) { - path->close(); -} - -static void anp_offset(ANPPath* path, float dx, float dy, ANPPath* dst) { - path->offset(SkFloatToScalar(dx), SkFloatToScalar(dy), dst); -} - -static void anp_transform(ANPPath* src, const ANPMatrix* matrix, - ANPPath* dst) { - src->transform(*matrix, dst); -} - -/////////////////////////////////////////////////////////////////////////////// - -#define ASSIGN(obj, name) (obj)->name = anp_##name - -void ANPPathInterfaceV0_Init(ANPInterface* value) { - ANPPathInterfaceV0* i = reinterpret_cast(value); - - ASSIGN(i, newPath); - ASSIGN(i, deletePath); - ASSIGN(i, copy); - ASSIGN(i, equal); - ASSIGN(i, reset); - ASSIGN(i, isEmpty); - ASSIGN(i, getBounds); - ASSIGN(i, moveTo); - ASSIGN(i, lineTo); - ASSIGN(i, quadTo); - ASSIGN(i, cubicTo); - ASSIGN(i, close); - ASSIGN(i, offset); - ASSIGN(i, transform); -} diff --git a/WebKit/android/plugins/ANPSoundInterface.cpp b/WebKit/android/plugins/ANPSoundInterface.cpp deleted file mode 100644 index c238872..0000000 --- a/WebKit/android/plugins/ANPSoundInterface.cpp +++ /dev/null @@ -1,163 +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. - */ - -// must include config.h first for webkit to fiddle with new/delete -#include "config.h" -#include "android_npapi.h" - -#include "SkTypes.h" -#include "media/AudioTrack.h" - -#include - -struct ANPAudioTrack { - void* mUser; - ANPAudioCallbackProc mProc; - android::AudioTrack* mTrack; -}; - -static ANPSampleFormat toANPFormat(int fm) { - switch (fm) { - case AUDIO_FORMAT_PCM_16_BIT: - return kPCM16Bit_ANPSampleFormat; - case AUDIO_FORMAT_PCM_8_BIT: - return kPCM8Bit_ANPSampleFormat; - default: - return kUnknown_ANPSamleFormat; - } -} - -static int fromANPFormat(ANPSampleFormat fm) { - switch (fm) { - case kPCM16Bit_ANPSampleFormat: - return AUDIO_FORMAT_PCM_16_BIT; - case kPCM8Bit_ANPSampleFormat: - return AUDIO_FORMAT_PCM_8_BIT; - default: - return AUDIO_FORMAT_INVALID; - } -} - -static void callbackProc(int event, void* user, void* info) { - ANPAudioTrack* track = reinterpret_cast(user); - - switch (event) { - case android::AudioTrack::EVENT_MORE_DATA: { - ANPAudioBuffer dst; - android::AudioTrack::Buffer* src; - - src = reinterpret_cast(info); - dst.bufferData = src->raw; - dst.channelCount = src->channelCount; - dst.format = toANPFormat(src->format); - dst.size = src->size; - track->mProc(kMoreData_ANPAudioEvent, track->mUser, &dst); - // return the updated size field - src->size = dst.size; - break; - } - case android::AudioTrack::EVENT_UNDERRUN: - track->mProc(kUnderRun_ANPAudioEvent, track->mUser, NULL); - break; - default: - SkDebugf("------ unknown audio event for plugin %d\n", event); - break; - } -} - -static ANPAudioTrack* ANPCreateTrack(uint32_t sampleRate, - ANPSampleFormat format, - int channelCount, - ANPAudioCallbackProc proc, - void* user) { - - ANPAudioTrack* track = new ANPAudioTrack; - - track->mUser = user; - track->mProc = proc; - track->mTrack = new android::AudioTrack(AUDIO_STREAM_MUSIC, - sampleRate, - fromANPFormat(format), - (channelCount > 1) ? AUDIO_CHANNEL_OUT_STEREO : AUDIO_CHANNEL_OUT_MONO, - 0, // frameCount - 0, // flags - callbackProc, - track, - 0); - - if (track->mTrack->initCheck() != 0) { // failure - delete track->mTrack; - delete track; - track = NULL; - } - return track; -} - -static void ANPDeleteTrack(ANPAudioTrack* track) { - if (track) { - delete track->mTrack; - delete track; - } -} - -static void ANPTrackStart(ANPAudioTrack* track) { - track->mTrack->start(); -} - -static void ANPTrackPause(ANPAudioTrack* track) { - track->mTrack->pause(); -} - -static void ANPTrackStop(ANPAudioTrack* track) { - track->mTrack->stop(); -} - -static bool ANPTrackIsStopped(ANPAudioTrack* track) { - return track->mTrack->stopped(); -} - -static uint32_t ANPTrackLatency(ANPAudioTrack* track) { - return track->mTrack->latency(); -} - -/////////////////////////////////////////////////////////////////////////////// - -void ANPAudioTrackInterfaceV0_Init(ANPInterface* value) { - ANPAudioTrackInterfaceV0* si = reinterpret_cast(value); - si->newTrack = ANPCreateTrack; - si->deleteTrack = ANPDeleteTrack; - si->start = ANPTrackStart; - si->pause = ANPTrackPause; - si->stop = ANPTrackStop; - si->isStopped = ANPTrackIsStopped; -} - -void ANPAudioTrackInterfaceV1_Init(ANPInterface* value) { - // initialize the functions from the previous interface - ANPAudioTrackInterfaceV0_Init(value); - // add any new functions or override existing functions - ANPAudioTrackInterfaceV1* si = reinterpret_cast(value); - si->trackLatency = ANPTrackLatency; -} diff --git a/WebKit/android/plugins/ANPSurfaceInterface.cpp b/WebKit/android/plugins/ANPSurfaceInterface.cpp deleted file mode 100644 index 4b99b31..0000000 --- a/WebKit/android/plugins/ANPSurfaceInterface.cpp +++ /dev/null @@ -1,174 +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. - */ - -// must include config.h first for webkit to fiddle with new/delete -#include "config.h" -#include "ANPSurface_npapi.h" - -#include "PluginView.h" -#include "PluginWidgetAndroid.h" -#include "SkANP.h" -#include "android_graphics.h" -#include -#include -#include -#include -#include - -using namespace android; - -// used to cache JNI method and field IDs for Surface Objects -static struct ANPSurfaceInterfaceJavaGlue { - bool initialized; - jmethodID getSurfaceHolder; - jmethodID getSurface; - jfieldID surfacePointer; -} gSurfaceJavaGlue; - -static inline sp getSurface(JNIEnv* env, jobject view) { - if (!env || !view) { - return NULL; - } - - if (!gSurfaceJavaGlue.initialized) { - - jclass surfaceViewClass = env->FindClass("android/view/SurfaceView"); - gSurfaceJavaGlue.getSurfaceHolder = env->GetMethodID(surfaceViewClass, "getHolder", - "()Landroid/view/SurfaceHolder;"); - - jclass surfaceHolderClass = env->FindClass("android/view/SurfaceHolder"); - gSurfaceJavaGlue.getSurface = env->GetMethodID(surfaceHolderClass, "getSurface", - "()Landroid/view/Surface;"); - - jclass surfaceClass = env->FindClass("android/view/Surface"); - gSurfaceJavaGlue.surfacePointer = env->GetFieldID(surfaceClass, - ANDROID_VIEW_SURFACE_JNI_ID, "I"); - - env->DeleteLocalRef(surfaceClass); - env->DeleteLocalRef(surfaceViewClass); - env->DeleteLocalRef(surfaceHolderClass); - - gSurfaceJavaGlue.initialized = true; - } - - jobject holder = env->CallObjectMethod(view, gSurfaceJavaGlue.getSurfaceHolder); - jobject surface = env->CallObjectMethod(holder, gSurfaceJavaGlue.getSurface); - jint surfacePointer = env->GetIntField(surface, gSurfaceJavaGlue.surfacePointer); - - env->DeleteLocalRef(holder); - env->DeleteLocalRef(surface); - - return sp((Surface*) surfacePointer); -} - -static inline ANPBitmapFormat convertPixelFormat(PixelFormat format) { - switch (format) { - case PIXEL_FORMAT_RGBA_8888: return kRGBA_8888_ANPBitmapFormat; - case PIXEL_FORMAT_RGB_565: return kRGB_565_ANPBitmapFormat; - default: return kUnknown_ANPBitmapFormat; - } -} - -static bool anp_lock(JNIEnv* env, jobject surfaceView, ANPBitmap* bitmap, ANPRectI* dirtyRect) { - if (!bitmap || !surfaceView) { - return false; - } - - sp surface = getSurface(env, surfaceView); - - if (!bitmap || !Surface::isValid(surface)) { - return false; - } - - Region dirtyRegion; - if (dirtyRect) { - Rect rect(dirtyRect->left, dirtyRect->top, dirtyRect->right, dirtyRect->bottom); - if (!rect.isEmpty()) { - dirtyRegion.set(rect); - } - } else { - dirtyRegion.set(Rect(0x3FFF, 0x3FFF)); - } - - Surface::SurfaceInfo info; - status_t err = surface->lock(&info, &dirtyRegion); - if (err < 0) { - return false; - } - - // the surface may have expanded the dirty region so we must to pass that - // information back to the plugin. - if (dirtyRect) { - Rect dirtyBounds = dirtyRegion.getBounds(); - dirtyRect->left = dirtyBounds.left; - dirtyRect->right = dirtyBounds.right; - dirtyRect->top = dirtyBounds.top; - dirtyRect->bottom = dirtyBounds.bottom; - } - - ssize_t bpr = info.s * bytesPerPixel(info.format); - - bitmap->format = convertPixelFormat(info.format); - bitmap->width = info.w; - bitmap->height = info.h; - bitmap->rowBytes = bpr; - - if (info.w > 0 && info.h > 0) { - bitmap->baseAddr = info.bits; - } else { - bitmap->baseAddr = NULL; - return false; - } - - return true; -} - -static void anp_unlock(JNIEnv* env, jobject surfaceView) { - if (!surfaceView) { - return; - } - - sp surface = getSurface(env, surfaceView); - - if (!Surface::isValid(surface)) { - return; - } - - surface->unlockAndPost(); -} - -/////////////////////////////////////////////////////////////////////////////// - -#define ASSIGN(obj, name) (obj)->name = anp_##name - -void ANPSurfaceInterfaceV0_Init(ANPInterface* value) { - ANPSurfaceInterfaceV0* i = reinterpret_cast(value); - - ASSIGN(i, lock); - ASSIGN(i, unlock); - - // setup the java glue struct - gSurfaceJavaGlue.initialized = false; -} diff --git a/WebKit/android/plugins/ANPSurface_npapi.h b/WebKit/android/plugins/ANPSurface_npapi.h deleted file mode 100644 index 910a948..0000000 --- a/WebKit/android/plugins/ANPSurface_npapi.h +++ /dev/null @@ -1,48 +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 ANPSurface_npapi_H -#define ANPSurface_npapi_H - -#include "android_npapi.h" -#include - -struct ANPSurfaceInterfaceV0 : ANPInterface { - /** Locks the surface from manipulation by other threads and provides a bitmap - to be written to. The dirtyRect param specifies which portion of the - bitmap will be written to. If the dirtyRect is NULL then the entire - surface will be considered dirty. If the lock was successful the function - will return true and the bitmap will be set to point to a valid bitmap. - If not the function will return false and the bitmap will be set to NULL. - */ - bool (*lock)(JNIEnv* env, jobject surface, ANPBitmap* bitmap, ANPRectI* dirtyRect); - /** Given a locked surface handle (i.e. result of a successful call to lock) - the surface is unlocked and the contents of the bitmap, specifically - those inside the dirtyRect are written to the screen. - */ - void (*unlock)(JNIEnv* env, jobject surface); -}; - -#endif //ANPSurface_npapi_H diff --git a/WebKit/android/plugins/ANPSystemInterface.cpp b/WebKit/android/plugins/ANPSystemInterface.cpp deleted file mode 100644 index 7199635..0000000 --- a/WebKit/android/plugins/ANPSystemInterface.cpp +++ /dev/null @@ -1,222 +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. - */ - -// must include config.h first for webkit to fiddle with new/delete -#include "config.h" - -#include "ANPSystem_npapi.h" -#include "Frame.h" -#include "JavaSharedClient.h" -#include "PluginClient.h" -#include "PluginPackage.h" -#include "PluginView.h" -#include "PluginWidgetAndroid.h" -#include "Settings.h" -#include "SkString.h" -#include "WebViewCore.h" -#include - -#include - -//#define PLUGIN_DEBUG_LOCAL // controls the printing of log messages -#include "PluginDebugAndroid.h" - -static const char* gApplicationDataDir = NULL; -static const char* gApplicationDataDirIncognito = NULL; - -using namespace android; - -static WebCore::PluginView* pluginViewForInstance(NPP instance) { - if (instance && instance->ndata) - return static_cast(instance->ndata); - return WebCore::PluginView::currentPluginView(); -} - -static const char* anp_getApplicationDataDirectory() { - if (NULL == gApplicationDataDir) { - PluginClient* client = JavaSharedClient::GetPluginClient(); - if (!client) - return NULL; - - WTF::String path = client->getPluginSharedDataDirectory(); - int length = path.length(); - if (length == 0) - return NULL; - - char* storage = (char*) malloc(length + 1); - if (NULL == storage) - return NULL; - - memcpy(storage, path.utf8().data(), length); - storage[length] = '\0'; - - static const char incognitoPath[] = "/incognito_plugins"; - char* incognitoStorage = (char*) malloc(length + strlen(incognitoPath) + 1); - - strcpy(incognitoStorage, storage); - strcat(incognitoStorage, incognitoPath); - - // save this assignment for last, so that if multiple threads call us - // (which should never happen), we never return an incomplete global. - // At worst, we would allocate storage for the path twice. - gApplicationDataDir = storage; - gApplicationDataDirIncognito = incognitoStorage; - } - - return gApplicationDataDir; -} - -static const char* anp_getApplicationDataDirectoryV2(NPP instance) { - WebCore::PluginView* pluginView = pluginViewForInstance(instance); - PluginWidgetAndroid* pluginWidget = pluginView->platformPluginWidget(); - - if (NULL == gApplicationDataDir) { - anp_getApplicationDataDirectory(); - } - - WebCore::Settings* settings = pluginWidget->webViewCore()->mainFrame()->settings(); - if (settings && settings->privateBrowsingEnabled()) { - // if this is an incognito view then check the path to see if it exists - // and if it is a directory, otherwise if it does not exist create it. - struct stat st; - if (stat(gApplicationDataDirIncognito, &st) == 0) { - if (!S_ISDIR(st.st_mode)) { - return NULL; - } - } else { - if (mkdir(gApplicationDataDirIncognito, S_IRWXU) != 0) { - return NULL; - } - } - - return gApplicationDataDirIncognito; - } - - return gApplicationDataDir; -} - -static jclass anp_loadJavaClass(NPP instance, const char* className) { - WebCore::PluginView* pluginView = pluginViewForInstance(instance); - PluginWidgetAndroid* pluginWidget = pluginView->platformPluginWidget(); - - jclass result; - result = pluginWidget->webViewCore()->getPluginClass(pluginView->plugin()->path(), - className); - return result; -} - -static void anp_setPowerState(NPP instance, ANPPowerState powerState) { - WebCore::PluginView* pluginView = pluginViewForInstance(instance); - PluginWidgetAndroid* pluginWidget = pluginView->platformPluginWidget(); - - pluginWidget->setPowerState(powerState); -} - -/////////////////////////////////////////////////////////////////////////////// - -#define ASSIGN(obj, name) (obj)->name = anp_##name - -void ANPSystemInterfaceV0_Init(ANPInterface* v) { - ANPSystemInterfaceV0* i = reinterpret_cast(v); - - ASSIGN(i, getApplicationDataDirectory); - ASSIGN(i, loadJavaClass); -} - -void ANPSystemInterfaceV1_Init(ANPInterface* v) { - // initialize the functions from the previous interface - ANPSystemInterfaceV0_Init(v); - // add any new functions or override existing functions - ANPSystemInterfaceV1* i = reinterpret_cast(v); - ASSIGN(i, setPowerState); -} - -void ANPSystemInterfaceV2_Init(ANPInterface* v) { - // initialize the functions from the previous interface - ANPSystemInterfaceV1_Init(v); - // add any new functions or override existing functions - ANPSystemInterfaceV2* i = reinterpret_cast(v); - i->getApplicationDataDirectory = anp_getApplicationDataDirectoryV2; -} - -/////////////////////////////////////////////////////////////////////////////// - -static bool isDirectory(const char* path) { - struct stat st; - return stat(path, &st) == 0 && S_ISDIR(st.st_mode); -} - -static void removeDirectory(const char* path) { - // create a pointer to a directory - DIR *dir = NULL; - dir = opendir(path); - if (!dir) - return; - - struct dirent* entry = 0; - while ((entry = readdir(dir))) { // while there is still something in the directory to list - if (!entry) - return; - - if (!strcmp(".", entry->d_name) || !strcmp("..", entry->d_name)) { - PLUGIN_LOG(". file: %s", entry->d_name); - continue; - } - - // concatenate the strings to get the complete path - static const char separator[] = "/"; - char* file = (char*) malloc(strlen(path) + strlen(separator) + strlen(entry->d_name) + 1); - strcpy(file, path); - strcat(file, separator); - strcat(file, entry->d_name); - - if (isDirectory(file) == true) { - PLUGIN_LOG("remove dir: %s", file); - removeDirectory(file); - } else { // it's a file, we can use remove - PLUGIN_LOG("remove file: %s", file); - remove(file); - } - - free(file); - } - - // clean up - closedir (dir); // close the directory - rmdir(path); // delete the directory -} - -void ANPSystemInterface_CleanupIncognito() { - PLUGIN_LOG("cleanup incognito plugin directory"); - - if (gApplicationDataDirIncognito == NULL) - anp_getApplicationDataDirectory(); - if (gApplicationDataDirIncognito == NULL) - return; - - // check to see if the directory exists and if so delete it - if (isDirectory(gApplicationDataDirIncognito)) - removeDirectory(gApplicationDataDirIncognito); -} diff --git a/WebKit/android/plugins/ANPSystem_npapi.h b/WebKit/android/plugins/ANPSystem_npapi.h deleted file mode 100644 index 835bc7c..0000000 --- a/WebKit/android/plugins/ANPSystem_npapi.h +++ /dev/null @@ -1,72 +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 ANPSystem_npapi_H -#define ANPSystem_npapi_H - -#include "android_npapi.h" -#include - -struct ANPSystemInterfaceV0 : ANPInterface { - /** Return the path name for the current Application's plugin data directory, - or NULL if not supported - */ - const char* (*getApplicationDataDirectory)(); - - /** A helper function to load java classes from the plugin's apk. The - function looks for a class given the fully qualified and null terminated - string representing the className. For example, - - const char* className = "com.android.mypackage.MyClass"; - - If the class cannot be found or there is a problem loading the class - NULL will be returned. - */ - jclass (*loadJavaClass)(NPP instance, const char* className); -}; - -enum ANPPowerStates { - kDefault_ANPPowerState = 0, - kScreenOn_ANPPowerState = 1 -}; -typedef int32_t ANPPowerState; - -struct ANPSystemInterfaceV1 : ANPSystemInterfaceV0 { - void (*setPowerState)(NPP instance, ANPPowerState powerState); -}; - -struct ANPSystemInterfaceV2 : ANPInterface { - /** Return the path name for the current Application's plugin data directory, - or NULL if not supported. This directory will change depending on whether - or not the plugin is found within an incognito tab. - */ - const char* (*getApplicationDataDirectory)(NPP instance); - - // redeclaration of existing features - jclass (*loadJavaClass)(NPP instance, const char* className); - void (*setPowerState)(NPP instance, ANPPowerState powerState); -}; - -#endif //ANPSystem_npapi_H diff --git a/WebKit/android/plugins/ANPTypefaceInterface.cpp b/WebKit/android/plugins/ANPTypefaceInterface.cpp deleted file mode 100644 index 99734a7..0000000 --- a/WebKit/android/plugins/ANPTypefaceInterface.cpp +++ /dev/null @@ -1,104 +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. - */ - -// must include config.h first for webkit to fiddle with new/delete -#include "config.h" -#include "SkANP.h" -#include "SkFontHost.h" - -static ANPTypeface* anp_createFromName(const char name[], ANPTypefaceStyle s) { - SkTypeface* tf = SkTypeface::CreateFromName(name, - static_cast(s)); - return reinterpret_cast(tf); -} - -static ANPTypeface* anp_createFromTypeface(const ANPTypeface* family, - ANPTypefaceStyle s) { - SkTypeface* tf = SkTypeface::CreateFromTypeface(family, - static_cast(s)); - return reinterpret_cast(tf); -} - -static int32_t anp_getRefCount(const ANPTypeface* tf) { - return tf ? tf->getRefCnt() : 0; -} - -static void anp_ref(ANPTypeface* tf) { - SkSafeRef(tf); -} - -static void anp_unref(ANPTypeface* tf) { - SkSafeUnref(tf); -} - -static ANPTypefaceStyle anp_getStyle(const ANPTypeface* tf) { - SkTypeface::Style s = tf ? tf->style() : SkTypeface::kNormal; - return static_cast(s); -} - -static int32_t anp_getFontPath(const ANPTypeface* tf, char fileName[], - int32_t length, int32_t* index) { - size_t size = SkFontHost::GetFileName(SkTypeface::UniqueID(tf), fileName, - length, index); - return static_cast(size); -} - -static const char* gFontDir; -#define FONT_DIR_SUFFIX "/fonts/" - -static const char* anp_getFontDirectoryPath() { - if (NULL == gFontDir) { - const char* root = getenv("ANDROID_ROOT"); - size_t len = strlen(root); - char* storage = (char*)malloc(len + sizeof(FONT_DIR_SUFFIX)); - if (NULL == storage) { - return NULL; - } - memcpy(storage, root, len); - memcpy(storage + len, FONT_DIR_SUFFIX, sizeof(FONT_DIR_SUFFIX)); - // save this assignment for last, so that if multiple threads call us - // (which should never happen), we never return an incomplete global. - // At worst, we would allocate storage for the path twice. - gFontDir = storage; - } - return gFontDir; -} - -/////////////////////////////////////////////////////////////////////////////// - -#define ASSIGN(obj, name) (obj)->name = anp_##name - -void ANPTypefaceInterfaceV0_Init(ANPInterface* v) { - ANPTypefaceInterfaceV0* i = reinterpret_cast(v); - - ASSIGN(i, createFromName); - ASSIGN(i, createFromTypeface); - ASSIGN(i, getRefCount); - ASSIGN(i, ref); - ASSIGN(i, unref); - ASSIGN(i, getStyle); - ASSIGN(i, getFontPath); - ASSIGN(i, getFontDirectoryPath); -} diff --git a/WebKit/android/plugins/ANPVideoInterface.cpp b/WebKit/android/plugins/ANPVideoInterface.cpp deleted file mode 100644 index 8eb9846..0000000 --- a/WebKit/android/plugins/ANPVideoInterface.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/* - * 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. - */ - -// must include config.h first for webkit to fiddle with new/delete -#include "config.h" -#include "ANPVideo_npapi.h" -#include "SkANP.h" - -#include "PluginView.h" -#include "PluginWidgetAndroid.h" -#include "MediaLayer.h" - -static WebCore::PluginView* pluginViewForInstance(NPP instance) { - if (instance && instance->ndata) - return static_cast(instance->ndata); - return WebCore::PluginView::currentPluginView(); -} - -static WebCore::MediaLayer* mediaLayerForInstance(NPP instance) { - WebCore::PluginView* pluginView = pluginViewForInstance(instance); - PluginWidgetAndroid* pluginWidget = pluginView->platformPluginWidget(); - return pluginWidget->getLayer(); -} - -static ANativeWindow* anp_acquireNativeWindow(NPP instance) { - WebCore::MediaLayer* mediaLayer = mediaLayerForInstance(instance); - - return mediaLayer->acquireNativeWindowForVideo(); -} - -static void anp_setWindowDimensions(NPP instance, const ANativeWindow* window, - const ANPRectF* dimensions) { - - WebCore::MediaLayer* mediaLayer = mediaLayerForInstance(instance); - if (!mediaLayer) - return; - - SkRect rect; - mediaLayer->setWindowDimensionsForVideo(window, *SkANP::SetRect(&rect, *dimensions)); -} - - -static void anp_releaseNativeWindow(NPP instance, ANativeWindow* window) { - WebCore::MediaLayer* mediaLayer = mediaLayerForInstance(instance); - if (!mediaLayer) - return; - - mediaLayer->releaseNativeWindowForVideo(window); -} - -/////////////////////////////////////////////////////////////////////////////// - -#define ASSIGN(obj, name) (obj)->name = anp_##name - -void ANPVideoInterfaceV0_Init(ANPInterface* value) { - ANPVideoInterfaceV0* i = reinterpret_cast(value); - - ASSIGN(i, acquireNativeWindow); - ASSIGN(i, setWindowDimensions); - ASSIGN(i, releaseNativeWindow); -} diff --git a/WebKit/android/plugins/ANPVideo_npapi.h b/WebKit/android/plugins/ANPVideo_npapi.h deleted file mode 100644 index 18e0231..0000000 --- a/WebKit/android/plugins/ANPVideo_npapi.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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 ANPVideo_npapi_H -#define ANPVideo_npapi_H - -#include "android_npapi.h" -#include - -struct ANPVideoInterfaceV0 : ANPInterface { - - /** - * Constructs a new native window to be used for rendering video content. - * - * Subsequent calls will produce new windows, but may also return NULL after - * n attempts if the browser has reached it's limit. Further, if the browser - * is unable to acquire the window quickly it may also return NULL in order - * to not prevent the plugin from executing. A subsequent call will then - * return the window if it is avaiable. - * - * NOTE: The hardware may fail if you try to decode more than the allowable - * number of videos supported on that device. - */ - ANativeWindow* (*acquireNativeWindow)(NPP instance); - - /** - * Sets the rectangle that specifies where the video content is to be drawn. - * The dimensions are in document space. Further, if the rect is NULL the - * browser will not attempt to draw the window, therefore do not set the - * dimensions until you queue the first buffer in the window. - */ - void (*setWindowDimensions)(NPP instance, const ANativeWindow* window, const ANPRectF* dimensions); - - /** - */ - void (*releaseNativeWindow)(NPP instance, ANativeWindow* window); -}; - -#endif //ANPVideo_npapi_H diff --git a/WebKit/android/plugins/ANPWindowInterface.cpp b/WebKit/android/plugins/ANPWindowInterface.cpp deleted file mode 100644 index a74616c..0000000 --- a/WebKit/android/plugins/ANPWindowInterface.cpp +++ /dev/null @@ -1,103 +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. - */ - -// must include config.h first for webkit to fiddle with new/delete -#include "config.h" -#include "SkANP.h" -#include "WebViewCore.h" -#include "PluginView.h" -#include "PluginWidgetAndroid.h" - -static PluginView* pluginViewForInstance(NPP instance) { - if (instance && instance->ndata) - return static_cast(instance->ndata); - return PluginView::currentPluginView(); -} - -static void anp_setVisibleRects(NPP instance, const ANPRectI rects[], int32_t count) { - PluginView* pluginView = pluginViewForInstance(instance); - PluginWidgetAndroid* pluginWidget = pluginView->platformPluginWidget(); - pluginWidget->setVisibleRects(rects, count); -} - -static void anp_clearVisibleRects(NPP instance) { - anp_setVisibleRects(instance, NULL, 0); -} - -static void anp_showKeyboard(NPP instance, bool value) { - PluginView* pluginView = pluginViewForInstance(instance); - PluginWidgetAndroid* pluginWidget = pluginView->platformPluginWidget(); - if(pluginWidget->hasFocus()) - pluginWidget->webViewCore()->requestKeyboard(value); -} - -static void anp_requestFullScreen(NPP instance) { - PluginView* pluginView = pluginViewForInstance(instance); - // call focusPluginElement() so that the pluginView receives keyboard events - pluginView->focusPluginElement(); - PluginWidgetAndroid* pluginWidget = pluginView->platformPluginWidget(); - pluginWidget->requestFullScreen(); -} - -static void anp_exitFullScreen(NPP instance) { - PluginView* pluginView = pluginViewForInstance(instance); - PluginWidgetAndroid* pluginWidget = pluginView->platformPluginWidget(); - pluginWidget->exitFullScreen(true); -} - -static void anp_requestCenterFitZoom(NPP instance) { - PluginView* pluginView = pluginViewForInstance(instance); - PluginWidgetAndroid* pluginWidget = pluginView->platformPluginWidget(); - pluginWidget->requestCenterFitZoom(); -} - -static ANPRectI anp_visibleRect(NPP instance) { - PluginView* pluginView = pluginViewForInstance(instance); - PluginWidgetAndroid* pluginWidget = pluginView->platformPluginWidget(); - return pluginWidget->visibleRect(); -} - -/////////////////////////////////////////////////////////////////////////////// - -#define ASSIGN(obj, name) (obj)->name = anp_##name - -void ANPWindowInterfaceV0_Init(ANPInterface* value) { - ANPWindowInterfaceV0* i = reinterpret_cast(value); - - ASSIGN(i, setVisibleRects); - ASSIGN(i, clearVisibleRects); - ASSIGN(i, showKeyboard); - ASSIGN(i, requestFullScreen); - ASSIGN(i, exitFullScreen); - ASSIGN(i, requestCenterFitZoom); -} - -void ANPWindowInterfaceV1_Init(ANPInterface* value) { - // initialize the functions from the previous interface - ANPWindowInterfaceV0_Init(value); - // add any new functions or override existing functions - ANPWindowInterfaceV1* i = reinterpret_cast(value); - ASSIGN(i, visibleRect); -} diff --git a/WebKit/android/plugins/PluginDebugAndroid.cpp b/WebKit/android/plugins/PluginDebugAndroid.cpp deleted file mode 100644 index 3958714..0000000 --- a/WebKit/android/plugins/PluginDebugAndroid.cpp +++ /dev/null @@ -1,137 +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 "PluginDebugAndroid.h" -#include "utils/Log.h" -#include "utils/SystemClock.h" -#include - -#define ARRAY_COUNT(array) static_cast(sizeof(array) / sizeof(array[0])) - -// used for key, mouse, and touch inputs -static const char* const inputActions[] = { - "down", - "up", - "move", /* touch only */ - "cancel", /* touch only */ - "longPress", /* touch only */ - "doubleTap" /* touch only */ -}; - -static const char* const lifecycleActions[] = { - "kPause_ANPLifecycleAction", - "kResume_ANPLifecycleAction", - "kGainFocus_ANPLifecycleAction", - "kLoseFocus_ANPLifecycleAction", - "kFreeMemory_ANPLifecycleAction", - "kOnLoad_ANPLifecycleAction", - "kEnterFullScreen_ANPLifecycleAction", - "kExitFullScreen_ANPLifecycleAction", - "kOnScreen_ANPLifecycleAction", - "kOffScreen_ANPLifecycleAction" -}; - -void anp_logPlugin(const char format[], ...) { - va_list args; - va_start(args, format); - LOG_PRI_VA(ANDROID_LOG_DEBUG, "webkit_plugin", format, args); - va_end(args); -} - -void anp_logPluginEvent(void* npp, const ANPEvent* evt, int16_t returnVal, int elapsedTime) { - - switch(evt->eventType) { - - case kNull_ANPEventType: - PLUGIN_LOG("%p EVENT::NULL", npp); - break; - - case kKey_ANPEventType: - if(evt->data.key.action < ARRAY_COUNT(inputActions)) { - anp_logPlugin("%p EVENT::KEY[%d] time=%d action=%s code=%d vcode=%d unichar=%d repeat=%d mods=%x", - npp, returnVal, elapsedTime, inputActions[evt->data.key.action], - evt->data.key.nativeCode, evt->data.key.virtualCode, - evt->data.key.unichar, evt->data.key.repeatCount, - evt->data.key.modifiers); - } else { - PLUGIN_LOG("%p EVENT::KEY[%d] unknown action", npp, returnVal); - } - break; - - case kMouse_ANPEventType: - if(evt->data.mouse.action < ARRAY_COUNT(inputActions)) { - anp_logPlugin("%p EVENT::MOUSE[%d] time=%d action=%s [%d %d]", npp, - returnVal, elapsedTime, inputActions[evt->data.mouse.action], - evt->data.touch.x, evt->data.touch.y); - } else { - anp_logPlugin("%p EVENT::MOUSE[%d] unknown action", npp, returnVal); - } - break; - - case kTouch_ANPEventType: - if(evt->data.touch.action < ARRAY_COUNT(inputActions)) { - - anp_logPlugin("%p EVENT::TOUCH[%d] time=%d action=%s [%d %d]", - npp, returnVal, elapsedTime, - inputActions[evt->data.touch.action], evt->data.touch.x, - evt->data.touch.y); - } else { - anp_logPlugin("%p EVENT::TOUCH[%d] unknown action", npp, returnVal); - } - break; - - case kDraw_ANPEventType: - if (evt->data.draw.model == kBitmap_ANPDrawingModel) { - anp_logPlugin("%p EVENT::DRAW bitmap time=%d format=%d clip=[%d,%d,%d,%d]", - npp, elapsedTime, evt->data.draw.data.bitmap.format, - evt->data.draw.clip.left, evt->data.draw.clip.top, - evt->data.draw.clip.right, evt->data.draw.clip.bottom); - } else if (evt->data.draw.model == kOpenGL_ANPDrawingModel) { - anp_logPlugin("%p EVENT::DRAW openGL time=%d dimensions=[%d,%d]", - npp, elapsedTime, evt->data.draw.data.surface.width, - evt->data.draw.data.surface.height); - } else { - anp_logPlugin("%p EVENT::DRAW unknown drawing model", npp); - } - break; - - case kLifecycle_ANPEventType: - if(evt->data.lifecycle.action < ARRAY_COUNT(lifecycleActions)) { - anp_logPlugin("%p EVENT::LIFECYCLE time=%d action=%s", npp, elapsedTime, - lifecycleActions[evt->data.lifecycle.action]); - } else { - anp_logPlugin("%p EVENT::LIFECYCLE unknown action", npp); - } - break; - - case kCustom_ANPEventType: - anp_logPlugin("%p EVENT::CUSTOM time=%d", npp, elapsedTime); - break; - - default: - anp_logPlugin("%p EVENT::UNKNOWN", npp); - break; - } -} diff --git a/WebKit/android/plugins/PluginDebugAndroid.h b/WebKit/android/plugins/PluginDebugAndroid.h deleted file mode 100644 index 5002882..0000000 --- a/WebKit/android/plugins/PluginDebugAndroid.h +++ /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. - */ - -#ifndef PLUGIN_DEBUG_ANDROID_H__ -#define PLUGIN_DEBUG_ANDROID_H__ - -#include "android_npapi.h" - -// Define PLUGIN_DEBUG_LOCAL in an individual C++ file to enable for -// that file only. - -// Define PLUGIN_DEBUG_GLOBAL to 1 to turn plug-in debug for all -// Android plug-in code in this directory. -#define PLUGIN_DEBUG_GLOBAL 0 - -#if PLUGIN_DEBUG_GLOBAL || defined(PLUGIN_DEBUG_LOCAL) -# define PLUGIN_LOG(FORMAT, ARGS...) do { anp_logPlugin(FORMAT, ## ARGS); } while(0) -# define PLUGIN_LOG_EVENT(NPP, EVT, RET, TIME) do { anp_logPluginEvent(NPP, EVT, RET, TIME); } while(0) - -/* Logs the given character array and optional arguments. All log entries use - the DEBUG priority and use the same "webkit_plugin" log tag. - */ -void anp_logPlugin(const char format[], ...); -/* Logs a user readable description of a plugin event. The relevant contents of - each event are logged, as well as the value returned by the plugin instance - and how long the instance took to process the event (in milliseconds). - */ -void anp_logPluginEvent(void* npp, const ANPEvent* event, int16_t returnVal, int elapsedTime); - -#else -# define PLUGIN_LOG(A, B...) do { } while(0) -# define PLUGIN_LOG_EVENT(NPP, EVT, RET, TIME) do { } while(0) - -#endif - -#endif // defined(PLUGIN_DEBUG_ANDROID_H__) diff --git a/WebKit/android/plugins/PluginTimer.cpp b/WebKit/android/plugins/PluginTimer.cpp deleted file mode 100644 index dfa7272..0000000 --- a/WebKit/android/plugins/PluginTimer.cpp +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright 2009, The Android Open Source Project - * Copyright (C) 2008 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. - * - * 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 "PluginTimer.h" -#include "RefPtr.h" - -namespace WebCore { - - static uint32_t gTimerID; - - PluginTimer::PluginTimer(PluginTimer** list, NPP instance, bool repeat, - void (*timerFunc)(NPP npp, uint32_t timerID)) - : m_list(list), - m_instance(instance), - m_timerFunc(timerFunc), - m_repeat(repeat), - m_unscheduled(false) - { - m_timerID = ++gTimerID; - - m_next = *list; - if (m_next) { - m_next->m_prev = this; - } - m_prev = 0; - *list = this; - relaxAdoptionRequirement(); - } - - PluginTimer::~PluginTimer() - { - if (m_next) { - m_next->m_prev = m_prev; - } - if (m_prev) { - m_prev->m_next = m_next; - } else { - *m_list = m_next; - } - } - - void PluginTimer::fired() - { - // ensure the timer cannot be deleted until this method completes - RefPtr protector(this); - - if (!m_unscheduled) - m_timerFunc(m_instance, m_timerID); - - // remove the timer if it is a one-shot timer (!m_repeat) or if is a - // repeating timer that has been unscheduled. In either case we must - // ensure that the refcount is 2 or greater since the PluginTimerList - // could have been deleted by the timerFunc and we must ensure that we - // do not double delete. - if ((!m_repeat || m_unscheduled) && refCount() > 1) - deref(); // mark the timer for deletion as it is no longer needed - } - - // may return null if timerID is not found - PluginTimer* PluginTimer::Find(PluginTimer* list, uint32_t timerID) - { - PluginTimer* curr = list; - while (curr) { - if (curr->m_timerID == timerID) { - break; - } - curr = curr->m_next; - } - return curr; - } - - /////////////////////////////////////////////////////////////////////////// - - PluginTimerList::~PluginTimerList() - { - PluginTimer* curr = m_list; - PluginTimer* next; - while (curr) { - next = curr->next(); - curr->deref(); - curr = next; - } - } - - uint32_t PluginTimerList::schedule(NPP instance, uint32_t interval, bool repeat, - void (*proc)(NPP npp, uint32_t timerID)) - { - PluginTimer* timer = new PluginTimer(&m_list, instance, repeat, proc); - - double dinterval = interval * 0.001; // milliseconds to seconds - if (repeat) { - timer->startRepeating(dinterval); - } else { - timer->startOneShot(dinterval); - } - return timer->timerID(); - } - - void PluginTimerList::unschedule(NPP instance, uint32_t timerID) - { - // Although it looks like simply deleting the timer would work here - // (stop() will be executed by the dtor), we cannot do this, as - // the plugin can call us while we are in the fired() method, - // (when we execute the timerFunc callback). Deleting the object - // we are in would then be a rather bad move... - PluginTimer* timer = PluginTimer::Find(m_list, timerID); - if (timer) - timer->unschedule(); - } - -} // namespace WebCore diff --git a/WebKit/android/plugins/PluginTimer.h b/WebKit/android/plugins/PluginTimer.h deleted file mode 100644 index 20c0816..0000000 --- a/WebKit/android/plugins/PluginTimer.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2009, The Android Open Source Project - * Copyright (C) 2008 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. - * - * 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 PluginTimer_H -#define PluginTimer_H - -#include "RefCounted.h" -#include "Timer.h" -#include "npapi.h" - -namespace WebCore { - - class PluginTimerList; - - class PluginTimer : public TimerBase, public RefCounted { - public: - PluginTimer(PluginTimer** list, NPP instance, bool repeat, - void (*proc)(NPP npp, uint32_t timerID)); - virtual ~PluginTimer(); - - uint32_t timerID() const { return m_timerID; } - - void unschedule() { m_unscheduled = true; } - - static PluginTimer* Find(PluginTimer* list, uint32_t timerID); - - private: - // override from TimerBase - virtual void fired(); - - PluginTimer* next() const { return m_next; } - friend class PluginTimerList; - - PluginTimer** m_list; - PluginTimer* m_prev; - PluginTimer* m_next; - NPP m_instance; - void (*m_timerFunc)(NPP, uint32_t); - uint32_t m_timerID; - bool m_repeat; - bool m_unscheduled; - }; - - class PluginTimerList { - public: - PluginTimerList() : m_list(0) {} - ~PluginTimerList(); - - uint32_t schedule(NPP instance, uint32_t interval, bool repeat, - void (*proc)(NPP npp, uint32_t timerID)); - void unschedule(NPP instance, uint32_t timerID); - - private: - PluginTimer* m_list; - }; - -} // namespace WebCore - -#endif diff --git a/WebKit/android/plugins/PluginViewBridgeAndroid.cpp b/WebKit/android/plugins/PluginViewBridgeAndroid.cpp deleted file mode 100644 index 2be9dc3..0000000 --- a/WebKit/android/plugins/PluginViewBridgeAndroid.cpp +++ /dev/null @@ -1,38 +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. - */ - -#include "config.h" -#include "PluginViewBridgeAndroid.h" - -namespace WebCore { - - void PluginViewBridgeAndroid::draw(GraphicsContext* gc, - const IntRect& rect) {} - - bool PluginViewBridgeAndroid::forPluginView() const { - return true; - } - -} diff --git a/WebKit/android/plugins/PluginViewBridgeAndroid.h b/WebKit/android/plugins/PluginViewBridgeAndroid.h deleted file mode 100644 index 5d16f46..0000000 --- a/WebKit/android/plugins/PluginViewBridgeAndroid.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2009, The Android Open Source Project - * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. - * Copyright (C) 2008 Collabora Ltd. 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. - * - * 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 PluginViewBridgeAndroid_H -#define PluginViewBridgeAndroid_H - -#include "PluginView.h" -#include "WebCoreViewBridge.h" - -namespace WebCore { - - // (Dummy for now) WebCoreViewBridge associated with a PluginView Widget. - class PluginViewBridgeAndroid : public WebCoreViewBridge { - public: - PluginViewBridgeAndroid() {} - - // overrides - virtual void draw(GraphicsContext* gc, const IntRect& rect); - virtual bool forPluginView() const; - }; - -} // namespace WebCore - -#endif diff --git a/WebKit/android/plugins/PluginWidgetAndroid.cpp b/WebKit/android/plugins/PluginWidgetAndroid.cpp deleted file mode 100644 index b8a10cc..0000000 --- a/WebKit/android/plugins/PluginWidgetAndroid.cpp +++ /dev/null @@ -1,690 +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. - */ - -#include "config.h" -#include "PluginWidgetAndroid.h" - -#if ENABLE(TOUCH_EVENTS) -#include "ChromeClient.h" -#endif -#include "Document.h" -#include "Element.h" -#include "Frame.h" -#include "Page.h" -#include "PluginPackage.h" -#include "PluginView.h" -#include "PluginWidgetAndroid.h" -#include "ScrollView.h" -#include "SkANP.h" -#include "SkFlipPixelRef.h" -#include "SkString.h" -#include "SkTime.h" -#include "WebViewCore.h" -#include "android_graphics.h" -#include - -// #define PLUGIN_DEBUG_LOCAL // controls the printing of log messages -#define DEBUG_EVENTS 0 // logs event contents, return value, and processing time -#define DEBUG_VISIBLE_RECTS 0 // temporary debug printfs and fixes - -// this include statement must follow the declaration of PLUGIN_DEBUG_LOCAL -#include "PluginDebugAndroid.h" - -PluginWidgetAndroid::PluginWidgetAndroid(WebCore::PluginView* view) - : m_pluginView(view) { - m_flipPixelRef = NULL; - m_core = NULL; - m_drawingModel = kBitmap_ANPDrawingModel; - m_eventFlags = 0; - m_pluginWindow = NULL; - m_requestedVisibleRectCount = 0; - m_requestedVisibleRect.setEmpty(); - m_visibleDocRect.setEmpty(); - m_pluginBounds.setEmpty(); - m_hasFocus = false; - m_isFullScreen = false; - m_visible = false; - m_cachedZoomLevel = 0; - m_embeddedView = NULL; - m_embeddedViewAttached = false; - m_acceptEvents = false; - m_isSurfaceClippedOut = false; - m_layer = 0; - m_powerState = kDefault_ANPPowerState; -} - -PluginWidgetAndroid::~PluginWidgetAndroid() { - PLUGIN_LOG("%p Deleting Plugin", m_pluginView->instance()); - m_acceptEvents = false; - if (m_core) { - setPowerState(kDefault_ANPPowerState); - m_core->removePlugin(this); - if (m_isFullScreen) { - exitFullScreen(true); - } - if (m_embeddedView) { - m_core->destroySurface(m_embeddedView); - } - } - - // cleanup any remaining JNI References - JNIEnv* env = JSC::Bindings::getJNIEnv(); - if (m_embeddedView) { - env->DeleteGlobalRef(m_embeddedView); - } - - SkSafeUnref(m_flipPixelRef); - - if (m_layer) - m_layer->unref(); -} - -void PluginWidgetAndroid::init(android::WebViewCore* core) { - m_core = core; - m_core->addPlugin(this); - m_acceptEvents = true; - PLUGIN_LOG("%p Initialized Plugin", m_pluginView->instance()); -} - -static SkBitmap::Config computeConfig(bool isTransparent) { - return isTransparent ? SkBitmap::kARGB_8888_Config - : SkBitmap::kRGB_565_Config; -} - -void PluginWidgetAndroid::setWindow(NPWindow* window, bool isTransparent) { - - // store the reference locally for easy lookup - m_pluginWindow = window; - - // make a copy of the previous bounds - SkIRect oldPluginBounds = m_pluginBounds; - - // keep a local copy of the plugin bounds because the m_pluginWindow pointer - // gets updated values prior to this method being called - m_pluginBounds.set(m_pluginWindow->x, m_pluginWindow->y, - m_pluginWindow->x + m_pluginWindow->width, - m_pluginWindow->y + m_pluginWindow->height); - - PLUGIN_LOG("%p PluginBounds (%d,%d,%d,%d)", m_pluginView->instance(), - m_pluginBounds.fLeft, m_pluginBounds.fTop, - m_pluginBounds.fRight, m_pluginBounds.fBottom); - - const bool boundsChanged = m_pluginBounds != oldPluginBounds; - - //TODO hack to ensure that we grab the most recent screen dimensions and scale - ANPRectI screenCoords; - m_core->getVisibleScreen(screenCoords); - float scale = m_core->scale(); - bool scaleChanged = m_cachedZoomLevel != scale; - setVisibleScreen(screenCoords, scale); - - // if the scale changed then setVisibleScreen will call this function and - // this call will potentially fire a duplicate draw event - if (!scaleChanged) { - sendSizeAndVisibilityEvents(boundsChanged); - } - layoutSurface(boundsChanged); - - if (m_drawingModel != kSurface_ANPDrawingModel) { - SkSafeUnref(m_flipPixelRef); - m_flipPixelRef = new SkFlipPixelRef(computeConfig(isTransparent), - window->width, window->height); - } -} - -bool PluginWidgetAndroid::setDrawingModel(ANPDrawingModel model) { - - if (model == kOpenGL_ANPDrawingModel && m_layer == 0) { - JNIEnv* env = JSC::Bindings::getJNIEnv(); - jobject webview = m_core->getWebViewJavaObject(); - jobject weakWebViewRef = 0; - if (webview) - weakWebViewRef = env->NewWeakGlobalRef(webview); - m_layer = new WebCore::MediaLayer(weakWebViewRef); - } - else if (model != kOpenGL_ANPDrawingModel && m_layer != 0) { - m_layer->unref(); - m_layer = 0; - } - - if (m_drawingModel != model) { - // Trigger layer computation in RenderLayerCompositor - m_pluginView->getElement()->setNeedsStyleRecalc(SyntheticStyleChange); - } - - m_drawingModel = model; - return true; -} - -// returned rect is in the page coordinate -bool PluginWidgetAndroid::isDirty(SkIRect* rect) const { - // nothing to report if we haven't had setWindow() called yet - if (NULL == m_flipPixelRef) { - return false; - } - - const SkRegion& dirty = m_flipPixelRef->dirtyRgn(); - if (dirty.isEmpty()) { - return false; - } else { - if (rect) { - *rect = dirty.getBounds(); - rect->offset(m_pluginWindow->x, m_pluginWindow->y); - } - return true; - } -} - -void PluginWidgetAndroid::inval(const WebCore::IntRect& rect, - bool signalRedraw) { - // nothing to do if we haven't had setWindow() called yet. m_flipPixelRef - // will also be null if this is a Surface model. - if (NULL == m_flipPixelRef) { - return; - } - - m_flipPixelRef->inval(rect); - - if (signalRedraw && m_flipPixelRef->isDirty()) { - m_core->invalPlugin(this); - } -} - -void PluginWidgetAndroid::viewInvalidate() { - WebCore::IntRect rect(m_pluginBounds.fLeft, m_pluginBounds.fTop, - m_pluginBounds.width(), m_pluginBounds.height()); - m_core->viewInvalidate(rect); -} - -void PluginWidgetAndroid::draw(SkCanvas* canvas) { - if (NULL == m_flipPixelRef || !m_flipPixelRef->isDirty()) { - return; - } - - SkAutoFlipUpdate update(m_flipPixelRef); - const SkBitmap& bitmap = update.bitmap(); - const SkRegion& dirty = update.dirty(); - - ANPEvent event; - SkANP::InitEvent(&event, kDraw_ANPEventType); - - event.data.draw.model = m_drawingModel; - SkANP::SetRect(&event.data.draw.clip, dirty.getBounds()); - - switch (m_drawingModel) { - case kBitmap_ANPDrawingModel: { - WebCore::PluginPackage* pkg = m_pluginView->plugin(); - NPP instance = m_pluginView->instance(); - - if (SkANP::SetBitmap(&event.data.draw.data.bitmap, - bitmap) && - pkg->pluginFuncs()->event(instance, &event)) { - - if (canvas && m_pluginWindow) { - SkBitmap bm(bitmap); - bm.setPixelRef(m_flipPixelRef); - canvas->drawBitmap(bm, 0, 0); - } - } - break; - } - default: - break; - } -} - -void PluginWidgetAndroid::setSurfaceClip(const SkIRect& clip) { - - if (m_drawingModel != kSurface_ANPDrawingModel) - return; - - /* don't display surfaces that are either entirely clipped or only 1x1 in - size. It appears that when an element is absolutely positioned and has - been completely clipped in CSS that webkit still sends a clip of 1x1. - */ - bool clippedOut = (clip.width() <= 1 && clip.height() <= 1); - if(clippedOut != m_isSurfaceClippedOut) { - m_isSurfaceClippedOut = clippedOut; - layoutSurface(); - } -} - -void PluginWidgetAndroid::layoutSurface(bool pluginBoundsChanged) { - - if (m_drawingModel != kSurface_ANPDrawingModel) - return; - if (!m_pluginWindow) - return; - - - bool displayPlugin = m_pluginView->isVisible() && !m_isSurfaceClippedOut; - PLUGIN_LOG("%p DisplayPlugin[%d] visible=[%d] clipped=[%d]", - m_pluginView->instance(), displayPlugin, - m_pluginView->isVisible(), m_isSurfaceClippedOut); - - // if the surface does not exist then create a new surface - if (!m_embeddedView && displayPlugin) { - - WebCore::PluginPackage* pkg = m_pluginView->plugin(); - NPP instance = m_pluginView->instance(); - - jobject pluginSurface; - pkg->pluginFuncs()->getvalue(instance, kJavaSurface_ANPGetValue, - static_cast(&pluginSurface)); - - jobject tempObj = m_core->addSurface(pluginSurface, - m_pluginWindow->x, m_pluginWindow->y, - m_pluginWindow->width, m_pluginWindow->height); - - if (tempObj) { - JNIEnv* env = JSC::Bindings::getJNIEnv(); - m_embeddedView = env->NewGlobalRef(tempObj); - m_embeddedViewAttached = true; - } - // if the view is unattached but visible then attach it - } else if (m_embeddedView && !m_embeddedViewAttached && displayPlugin && !m_isFullScreen) { - m_core->updateSurface(m_embeddedView, m_pluginWindow->x, m_pluginWindow->y, - m_pluginWindow->width, m_pluginWindow->height); - m_embeddedViewAttached = true; - // if the view is attached but invisible then remove it - } else if (m_embeddedView && m_embeddedViewAttached && !displayPlugin) { - m_core->destroySurface(m_embeddedView); - m_embeddedViewAttached = false; - // if the plugin's bounds have changed and it's visible then update it - } else if (pluginBoundsChanged && displayPlugin && !m_isFullScreen) { - m_core->updateSurface(m_embeddedView, m_pluginWindow->x, m_pluginWindow->y, - m_pluginWindow->width, m_pluginWindow->height); - - } -} - -int16_t PluginWidgetAndroid::sendEvent(const ANPEvent& evt) { - if (!m_acceptEvents) - return 0; - WebCore::PluginPackage* pkg = m_pluginView->plugin(); - NPP instance = m_pluginView->instance(); - // "missing" plugins won't have these - if (pkg && instance) { - - // if the plugin is gaining focus then update our state now to allow - // the plugin's event handler to perform actions that require focus - if (evt.eventType == kLifecycle_ANPEventType && - evt.data.lifecycle.action == kGainFocus_ANPLifecycleAction) { - m_hasFocus = true; - } - -#if DEBUG_EVENTS - SkMSec startTime = SkTime::GetMSecs(); -#endif - - // make a localCopy since the actual plugin may not respect its constness, - // and so we don't want our caller to have its param modified - ANPEvent localCopy = evt; - int16_t result = pkg->pluginFuncs()->event(instance, &localCopy); - -#if DEBUG_EVENTS - SkMSec endTime = SkTime::GetMSecs(); - PLUGIN_LOG_EVENT(instance, &evt, result, endTime - startTime); -#endif - - // if the plugin is losing focus then delay the update of our state - // until after we notify the plugin and allow them to perform actions - // that may require focus - if (evt.eventType == kLifecycle_ANPEventType && - evt.data.lifecycle.action == kLoseFocus_ANPLifecycleAction) { - m_hasFocus = false; - } - - return result; - } - return 0; -} - -void PluginWidgetAndroid::updateEventFlags(ANPEventFlags flags) { - - // if there are no differences then immediately return - if (m_eventFlags == flags) { - return; - } - - Document* doc = m_pluginView->parentFrame()->document(); -#if ENABLE(TOUCH_EVENTS) - if((m_eventFlags ^ flags) & kTouch_ANPEventFlag) { - if (flags & kTouch_ANPEventFlag) - doc->addListenerTypeIfNeeded(eventNames().touchstartEvent); - } -#endif - - m_eventFlags = flags; -} - -bool PluginWidgetAndroid::isAcceptingEvent(ANPEventFlag flag) { - return m_eventFlags & flag; -} - -void PluginWidgetAndroid::sendSizeAndVisibilityEvents(const bool updateDimensions) { - // TODO update the bitmap size based on the zoom? (for kBitmap_ANPDrawingModel) - - const float zoomLevel = m_core->scale(); - - // notify the plugin of the new size - if (m_drawingModel == kOpenGL_ANPDrawingModel && updateDimensions && m_pluginWindow) { - PLUGIN_LOG("%s (%d,%d)[%f]", __FUNCTION__, m_pluginWindow->width, - m_pluginWindow->height, zoomLevel); - ANPEvent event; - SkANP::InitEvent(&event, kDraw_ANPEventType); - event.data.draw.model = kOpenGL_ANPDrawingModel; - event.data.draw.data.surface.width = m_pluginWindow->width * zoomLevel; - event.data.draw.data.surface.height = m_pluginWindow->height * zoomLevel; - sendEvent(event); - } - - bool visible = SkIRect::Intersects(m_visibleDocRect, m_pluginBounds); - if(m_visible != visible) { - -#if DEBUG_VISIBLE_RECTS - PLUGIN_LOG("%p changeVisiblity[%d] pluginBounds(%d,%d,%d,%d)", - m_pluginView->instance(), visible, - m_pluginBounds.fLeft, m_pluginBounds.fTop, - m_pluginBounds.fRight, m_pluginBounds.fBottom); -#endif - - // change the visibility - m_visible = visible; - // send the event - ANPEvent event; - SkANP::InitEvent(&event, kLifecycle_ANPEventType); - event.data.lifecycle.action = visible ? kOnScreen_ANPLifecycleAction - : kOffScreen_ANPLifecycleAction; - sendEvent(event); - } -} - -void PluginWidgetAndroid::setVisibleScreen(const ANPRectI& visibleDocRect, float zoom) { -#if DEBUG_VISIBLE_RECTS - PLUGIN_LOG("%s (%d,%d,%d,%d)[%f]", __FUNCTION__, visibleDocRect.left, - visibleDocRect.top, visibleDocRect.right, - visibleDocRect.bottom, zoom); -#endif - int oldScreenW = m_visibleDocRect.width(); - int oldScreenH = m_visibleDocRect.height(); - - const bool zoomChanged = m_cachedZoomLevel != zoom; - - // make local copies of the parameters - m_cachedZoomLevel = zoom; - m_visibleDocRect.set(visibleDocRect.left, - visibleDocRect.top, - visibleDocRect.right, - visibleDocRect.bottom); - - int newScreenW = m_visibleDocRect.width(); - int newScreenH = m_visibleDocRect.height(); - - // if the screen dimensions have changed by more than 5 pixels in either - // direction then recompute the plugin's visible rectangle - if (abs(oldScreenW - newScreenW) > 5 || abs(oldScreenH - newScreenH) > 5) { - PLUGIN_LOG("%s VisibleDoc old=[%d,%d] new=[%d,%d] ", __FUNCTION__, - oldScreenW, oldScreenH, newScreenW, newScreenH); - computeVisiblePluginRect(); - } - - sendSizeAndVisibilityEvents(zoomChanged); -} - -ANPRectI PluginWidgetAndroid::visibleRect() { - - SkIRect visibleRect; - visibleRect.setEmpty(); - - // compute the interesection of the visible screen and the plugin - bool visible = visibleRect.intersect(m_visibleDocRect, m_pluginBounds); - if (visible) { - // convert from absolute coordinates to the plugin's relative coordinates - visibleRect.offset(-m_pluginBounds.fLeft, -m_pluginBounds.fTop); - } - - // convert from SkRect to ANPRect - ANPRectI result; - memcpy(&result, &visibleRect, sizeof(ANPRectI)); - return result; -} - -void PluginWidgetAndroid::setVisibleRects(const ANPRectI rects[], int32_t count) { -#if DEBUG_VISIBLE_RECTS - PLUGIN_LOG("%s count=%d", __FUNCTION__, count); -#endif - // ensure the count does not exceed our allocated space - if (count > MAX_REQUESTED_RECTS) - count = MAX_REQUESTED_RECTS; - - // store the values in member variables - m_requestedVisibleRectCount = count; - memcpy(m_requestedVisibleRects, rects, count * sizeof(rects[0])); - -#if DEBUG_VISIBLE_RECTS // FIXME: this fixes bad data from the plugin - // take it out once plugin supplies better data - for (int index = 0; index < count; index++) { - PLUGIN_LOG("%s [%d](%d,%d,%d,%d)", __FUNCTION__, index, - m_requestedVisibleRects[index].left, - m_requestedVisibleRects[index].top, - m_requestedVisibleRects[index].right, - m_requestedVisibleRects[index].bottom); - if (m_requestedVisibleRects[index].left == - m_requestedVisibleRects[index].right) { - m_requestedVisibleRects[index].right += 1; - } - if (m_requestedVisibleRects[index].top == - m_requestedVisibleRects[index].bottom) { - m_requestedVisibleRects[index].bottom += 1; - } - } -#endif - computeVisiblePluginRect(); -} - -void PluginWidgetAndroid::computeVisiblePluginRect() { - - // ensure the visibleDocRect has been set (i.e. not equal to zero) - if (m_visibleDocRect.isEmpty() || !m_pluginWindow || m_requestedVisibleRectCount < 1) - return; - - // create a rect that will contain as many of the rects that will fit on screen - SkIRect visibleRect; - visibleRect.setEmpty(); - - for (int counter = 0; counter < m_requestedVisibleRectCount; counter++) { - - ANPRectI* rect = &m_requestedVisibleRects[counter]; - - // create skia rect for easier manipulation and convert it to page coordinates - SkIRect pluginRect; - pluginRect.set(rect->left, rect->top, rect->right, rect->bottom); - pluginRect.offset(m_pluginWindow->x, m_pluginWindow->y); - - // ensure the rect falls within the plugin's bounds - if (!m_pluginBounds.contains(pluginRect)) { -#if DEBUG_VISIBLE_RECTS - PLUGIN_LOG("%s (%d,%d,%d,%d) !contain (%d,%d,%d,%d)", __FUNCTION__, - m_pluginBounds.fLeft, m_pluginBounds.fTop, - m_pluginBounds.fRight, m_pluginBounds.fBottom, - pluginRect.fLeft, pluginRect.fTop, - pluginRect.fRight, pluginRect.fBottom); - // assume that the desired outcome is to clamp to the container - if (pluginRect.intersect(m_pluginBounds)) { - visibleRect = pluginRect; - } -#endif - continue; - } - - // combine this new rect with the higher priority rects - pluginRect.join(visibleRect); - - // check to see if the new rect could be made to fit within the screen - // bounds. If this is the highest priority rect then attempt to center - // even if it doesn't fit on the screen. - if (counter > 0 && (m_visibleDocRect.width() < pluginRect.width() || - m_visibleDocRect.height() < pluginRect.height())) - break; - - // set the new visible rect - visibleRect = pluginRect; - } - - m_requestedVisibleRect = visibleRect; - scrollToVisiblePluginRect(); -} - -void PluginWidgetAndroid::scrollToVisiblePluginRect() { - - if (!m_hasFocus || m_requestedVisibleRect.isEmpty() || m_visibleDocRect.isEmpty()) { -#if DEBUG_VISIBLE_RECTS - PLUGIN_LOG("%s call m_hasFocus=%d m_requestedVisibleRect.isEmpty()=%d" - " m_visibleDocRect.isEmpty()=%d", __FUNCTION__, m_hasFocus, - m_requestedVisibleRect.isEmpty(), m_visibleDocRect.isEmpty()); -#endif - return; - } - // if the entire rect is already visible then we don't need to scroll - if (m_visibleDocRect.contains(m_requestedVisibleRect)) - return; - - // find the center of the visibleRect in document coordinates - int rectCenterX = m_requestedVisibleRect.fLeft + m_requestedVisibleRect.width()/2; - int rectCenterY = m_requestedVisibleRect.fTop + m_requestedVisibleRect.height()/2; - - // find document coordinates for center of the visible screen - int visibleDocCenterX = m_visibleDocRect.fLeft + m_visibleDocRect.width()/2; - int visibleDocCenterY = m_visibleDocRect.fTop + m_visibleDocRect.height()/2; - - //compute the delta of the two points and scale to screen coordinates - int deltaX = rectCenterX - visibleDocCenterX; - int deltaY = rectCenterY - visibleDocCenterY; - - ScrollView* scrollView = m_pluginView->parent(); - android::WebViewCore* core = android::WebViewCore::getWebViewCore(scrollView); -#if DEBUG_VISIBLE_RECTS - PLUGIN_LOG("%s call scrollBy (%d,%d)", __FUNCTION__, deltaX, deltaY); -#endif - core->scrollTo(rectCenterX, rectCenterY, true); -} - -void PluginWidgetAndroid::requestFullScreen() { - if (m_isFullScreen) { - return; - } - - if (!m_embeddedView && m_drawingModel == kOpenGL_ANPDrawingModel) { - WebCore::PluginPackage* pkg = m_pluginView->plugin(); - NPP instance = m_pluginView->instance(); - - jobject pluginSurface; - pkg->pluginFuncs()->getvalue(instance, kJavaSurface_ANPGetValue, - static_cast(&pluginSurface)); - - // create the surface, but do not add it to the view hierarchy - jobject tempObj = m_core->createSurface(pluginSurface); - - if (tempObj) { - JNIEnv* env = JSC::Bindings::getJNIEnv(); - m_embeddedView = env->NewGlobalRef(tempObj); - m_embeddedViewAttached = false; - } - } - - if (!m_embeddedView) { - return; - } - - // send event to notify plugin of full screen change - ANPEvent event; - SkANP::InitEvent(&event, kLifecycle_ANPEventType); - event.data.lifecycle.action = kEnterFullScreen_ANPLifecycleAction; - sendEvent(event); - - // remove the embedded surface from the view hierarchy - if (m_drawingModel != kOpenGL_ANPDrawingModel) - m_core->destroySurface(m_embeddedView); - - // add the full screen view - m_core->showFullScreenPlugin(m_embeddedView, m_pluginView->instance()); - m_isFullScreen = true; -} - -void PluginWidgetAndroid::exitFullScreen(bool pluginInitiated) { - if (!m_isFullScreen || !m_embeddedView) { - return; - } - - // remove the full screen surface from the view hierarchy - if (pluginInitiated) { - m_core->hideFullScreenPlugin(); - } - - // add the embedded view back - if (m_drawingModel != kOpenGL_ANPDrawingModel) - m_core->updateSurface(m_embeddedView, m_pluginWindow->x, m_pluginWindow->y, - m_pluginWindow->width, m_pluginWindow->height); - - // send event to notify plugin of full screen change - ANPEvent event; - SkANP::InitEvent(&event, kLifecycle_ANPEventType); - event.data.lifecycle.action = kExitFullScreen_ANPLifecycleAction; - sendEvent(event); - - m_isFullScreen = false; -} - -void PluginWidgetAndroid::requestCenterFitZoom() { - m_core->centerFitRect(m_pluginWindow->x, m_pluginWindow->y, - m_pluginWindow->width, m_pluginWindow->height); -} - -void PluginWidgetAndroid::setPowerState(ANPPowerState powerState) { - if(m_powerState == powerState) - return; - - // cleanup the old power state - switch (m_powerState) { - case kDefault_ANPPowerState: - break; - case kScreenOn_ANPPowerState: - m_core->keepScreenOn(false); - break; - } - - // setup the new power state - switch (powerState) { - case kDefault_ANPPowerState: - break; - case kScreenOn_ANPPowerState: - m_core->keepScreenOn(true); - break; - } - - m_powerState = powerState; -} - diff --git a/WebKit/android/plugins/PluginWidgetAndroid.h b/WebKit/android/plugins/PluginWidgetAndroid.h deleted file mode 100644 index 5d586b1..0000000 --- a/WebKit/android/plugins/PluginWidgetAndroid.h +++ /dev/null @@ -1,219 +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 PluginWidgetAndroid_H -#define PluginWidgetAndroid_H - -#include "android_npapi.h" -#include "ANPSystem_npapi.h" -#include "IntPoint.h" -#include "IntRect.h" -#include "MediaLayer.h" -#include "SkRect.h" -#include - -namespace WebCore { - class PluginView; -} - -namespace android { - class PluginSurface; - class WebViewCore; -} - -class SkCanvas; -class SkFlipPixelRef; - -/* - This is our extended state in a PluginView. This object is created and - kept insync with the PluginView, but is also available to WebViewCore - to allow its draw() method to be called from outside of the PluginView. - */ -struct PluginWidgetAndroid { - // initialize with our host pluginview. This will delete us when it is - // destroyed. - PluginWidgetAndroid(WebCore::PluginView* view); - ~PluginWidgetAndroid(); - - WebCore::PluginView* pluginView() const { return m_pluginView; } - - // Needed by PluginSurface to manage the java SurfaceView. - android::WebViewCore* webViewCore() const { return m_core; } - - /* Can't determine our core at construction time, so PluginView calls this - as soon as it has a parent. - */ - void init(android::WebViewCore*); - /* Called each time the PluginView gets a new size or position. - */ - void setWindow(NPWindow* window, bool isTransparent); - - /* Called whenever the plugin itself requests a new drawing model. If the - hardware does not support the requested model then false is returned, - otherwise true is returned. - */ - bool setDrawingModel(ANPDrawingModel); - - /* Called to check if the plugin is running in "windowed" mode (i.e. surface - view). - */ - bool isSurfaceDrawingModel() const { return kSurface_ANPDrawingModel == m_drawingModel; } - - bool isOpenGLDrawingModel() const { return kOpenGL_ANPDrawingModel == m_drawingModel; } - - /* Returns true (and optionally updates rect with the dirty bounds in the - page coordinate) if the plugin has invalidate us. - */ - bool isDirty(SkIRect* dirtyBounds = NULL) const; - /* Called by PluginView to invalidate a portion of the plugin area (in - local plugin coordinates). If signalRedraw is true, this also triggers - a subsequent call to draw(NULL). - */ - void inval(const WebCore::IntRect&, bool signalRedraw); - - /* Called to draw into the plugin's bitmap. If canvas is non-null, the - bitmap itself is then drawn into the canvas. - */ - void draw(SkCanvas* canvas = NULL); - - /* Send this event to the plugin instance. A non-zero value will be - returned if the plugin handled the event. - */ - int16_t sendEvent(const ANPEvent&); - - /* Update the plugins event flags. If a flag is set to true then the plugin - wants to be notified of events of this type. - */ - void updateEventFlags(ANPEventFlags); - - /* Called to check if a plugin wants to accept a given event type. It - returns true if the plugin wants the events and false otherwise. - */ - bool isAcceptingEvent(ANPEventFlag); - - /* Notify the plugin of the currently visible screen coordinates (document - space) and the current zoom level. - */ - void setVisibleScreen(const ANPRectI& visibleScreenRect, float zoom); - - /** Returns a rectangle representing the visible area of the plugin on - screen. The coordinates are relative to the size of the plugin in the - document and will not be negative or exceed the plugin's size. - */ - ANPRectI visibleRect(); - - /** Registers a set of rectangles that the plugin would like to keep on - screen. The rectangles are listed in order of priority with the highest - priority rectangle in location rects[0]. The browser will attempt to keep - as many of the rectangles on screen as possible and will scroll them into - view in response to the invocation of this method and other various events. - The count specifies how many rectangles are in the array. If the count is - zero it signals the plugin that any existing rectangles should be cleared - and no rectangles will be tracked. - */ - void setVisibleRects(const ANPRectI rects[], int32_t count); - - /** Called when a plugin wishes to enter into full screen mode. It invokes - the plugin's Java class (defined in the plugin's apk manifest), which is - called asynchronously and provides a View to be displayed full screen. - */ - void requestFullScreen(); - - /** Called when a plugin wishes to exit from full screen mode. As a result, - the plugin's full-screen view is discarded by the view system. It is also - called in order to notify the native code that the browser has discarded - the view. - */ - void exitFullScreen(bool pluginInitiated); - - bool inFullScreen() { return m_isFullScreen; } - - /** Called to check if a plugin currently has document focus, which is - required for certain operations (e.g. show/hide keyboard). It returns - true if the plugin currently has focus and false otherwise. - */ - bool hasFocus() const { return m_hasFocus; } - - /** Called to ensure the surface is being correctly displayed within the - view hierarchy. For instance, if the visibility of the plugin has - changed then we need to ensure the surface is added or removed from the - view system. - */ - void layoutSurface(bool pluginBoundsChanged = false); - - /** send the surface the currently visible portion of the plugin. This is not - the portion of the plugin visible on the screen but rather the portion of - the plugin that is not obscured by other HTML content. - */ - void setSurfaceClip(const SkIRect& clip); - - /** Called when a plugin wishes to be zoomed and centered in the current view. - */ - void requestCenterFitZoom(); - - WebCore::MediaLayer* getLayer() const { return m_layer; } - - void setPowerState(ANPPowerState powerState); - - void viewInvalidate(); - -private: - void computeVisiblePluginRect(); - void scrollToVisiblePluginRect(); - void sendSizeAndVisibilityEvents(const bool updateDimensions); - - WebCore::MediaLayer* m_layer; - - WebCore::PluginView* m_pluginView; - android::WebViewCore* m_core; - SkFlipPixelRef* m_flipPixelRef; - ANPDrawingModel m_drawingModel; - ANPEventFlags m_eventFlags; - NPWindow* m_pluginWindow; - SkIRect m_pluginBounds; // relative to the page - SkIRect m_visibleDocRect; // relative to the page - SkIRect m_requestedVisibleRect; // relative to the page - bool m_hasFocus; - bool m_isFullScreen; - bool m_visible; - float m_cachedZoomLevel; // used for comparison only - jobject m_embeddedView; - bool m_embeddedViewAttached; - bool m_acceptEvents; - bool m_isSurfaceClippedOut; - ANPPowerState m_powerState; - - /* We limit the number of rectangles to minimize storage and ensure adequate - speed. - */ - enum { - MAX_REQUESTED_RECTS = 5, - }; - - ANPRectI m_requestedVisibleRects[MAX_REQUESTED_RECTS]; - int32_t m_requestedVisibleRectCount; -}; - -#endif diff --git a/WebKit/android/plugins/SkANP.cpp b/WebKit/android/plugins/SkANP.cpp deleted file mode 100644 index 720387d..0000000 --- a/WebKit/android/plugins/SkANP.cpp +++ /dev/null @@ -1,106 +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. - */ - -// must include config.h first for webkit to fiddle with new/delete -#include "config.h" -#include "SkANP.h" -#include - -SkRect* SkANP::SetRect(SkRect* dst, const ANPRectF& src) { - dst->set(SkFloatToScalar(src.left), - SkFloatToScalar(src.top), - SkFloatToScalar(src.right), - SkFloatToScalar(src.bottom)); - return dst; -} - -SkIRect* SkANP::SetRect(SkIRect* dst, const ANPRectI& src) { - dst->set(src.left, src.top, src.right, src.bottom); - return dst; -} - -ANPRectI* SkANP::SetRect(ANPRectI* dst, const SkIRect& src) { - dst->left = src.fLeft; - dst->top = src.fTop; - dst->right = src.fRight; - dst->bottom = src.fBottom; - return dst; -} - -ANPRectF* SkANP::SetRect(ANPRectF* dst, const SkRect& src) { - dst->left = SkScalarToFloat(src.fLeft); - dst->top = SkScalarToFloat(src.fTop); - dst->right = SkScalarToFloat(src.fRight); - dst->bottom = SkScalarToFloat(src.fBottom); - return dst; -} - -SkBitmap* SkANP::SetBitmap(SkBitmap* dst, const ANPBitmap& src) { - SkBitmap::Config config = SkBitmap::kNo_Config; - - switch (src.format) { - case kRGBA_8888_ANPBitmapFormat: - config = SkBitmap::kARGB_8888_Config; - break; - case kRGB_565_ANPBitmapFormat: - config = SkBitmap::kRGB_565_Config; - break; - default: - break; - } - - dst->setConfig(config, src.width, src.height, src.rowBytes); - dst->setPixels(src.baseAddr); - return dst; -} - -bool SkANP::SetBitmap(ANPBitmap* dst, const SkBitmap& src) { - if (!(dst->baseAddr = src.getPixels())) { - SkDebugf("SkANP::SetBitmap - getPixels() returned null\n"); - return false; - } - - switch (src.config()) { - case SkBitmap::kARGB_8888_Config: - dst->format = kRGBA_8888_ANPBitmapFormat; - break; - case SkBitmap::kRGB_565_Config: - dst->format = kRGB_565_ANPBitmapFormat; - break; - default: - SkDebugf("SkANP::SetBitmap - unsupported src.config %d\n", src.config()); - return false; - } - - dst->width = src.width(); - dst->height = src.height(); - dst->rowBytes = src.rowBytes(); - return true; -} - -void SkANP::InitEvent(ANPEvent* event, ANPEventType et) { - event->inSize = sizeof(ANPEvent); - event->eventType = et; -} diff --git a/WebKit/android/plugins/SkANP.h b/WebKit/android/plugins/SkANP.h deleted file mode 100644 index 5c2a936..0000000 --- a/WebKit/android/plugins/SkANP.h +++ /dev/null @@ -1,79 +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 SkANP_DEFINED -#define SkANP_DEFINED - -#include "android_npapi.h" -#include "SkCanvas.h" -#include "SkMatrix.h" -#include "SkPaint.h" -#include "SkPath.h" -#include "SkTypeface.h" - -struct ANPMatrix : SkMatrix { -}; - -struct ANPPath : SkPath { -}; - -struct ANPPaint : SkPaint { -}; - -struct ANPTypeface : SkTypeface { -}; - -struct ANPCanvas { - SkCanvas* skcanvas; - - // draw into the specified bitmap - explicit ANPCanvas(const SkBitmap& bm) { - skcanvas = new SkCanvas(bm); - } - - // redirect all drawing to the specific SkCanvas - explicit ANPCanvas(SkCanvas* other) { - skcanvas = other; - skcanvas->ref(); - } - - ~ANPCanvas() { - skcanvas->unref(); - } -}; - -class SkANP { -public: - static SkRect* SetRect(SkRect* dst, const ANPRectF& src); - static SkIRect* SetRect(SkIRect* dst, const ANPRectI& src); - static ANPRectI* SetRect(ANPRectI* dst, const SkIRect& src); - static ANPRectF* SetRect(ANPRectF* dst, const SkRect& src); - static SkBitmap* SetBitmap(SkBitmap* dst, const ANPBitmap& src); - static bool SetBitmap(ANPBitmap* dst, const SkBitmap& src); - - static void InitEvent(ANPEvent* event, ANPEventType et); -}; - -#endif diff --git a/WebKit/android/plugins/SurfaceCallback.h b/WebKit/android/plugins/SurfaceCallback.h deleted file mode 100644 index 945fc3f..0000000 --- a/WebKit/android/plugins/SurfaceCallback.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2009, The Android Open Source Project - * Copyright (C) 2008 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. - * - * 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 SurfaceCallback_H -#define SurfaceCallback_H - -namespace android { - - class SurfaceCallback { - public: - virtual ~SurfaceCallback() {} - virtual void surfaceCreated() = 0; - virtual void surfaceChanged(int format, int width, int height) = 0; - virtual void surfaceDestroyed() = 0; - }; - -} // namespace android - -#endif diff --git a/WebKit/android/plugins/android_npapi.h b/WebKit/android/plugins/android_npapi.h deleted file mode 100644 index b0c3765..0000000 --- a/WebKit/android/plugins/android_npapi.h +++ /dev/null @@ -1,987 +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. - */ - -/* Defines the android-specific types and functions as part of npapi - - In particular, defines the window and event types that are passed to - NPN_GetValue, NPP_SetWindow and NPP_HandleEvent. - - To minimize what native libraries the plugin links against, some - functionality is provided via function-ptrs (e.g. time, sound) - */ - -#ifndef android_npapi_H -#define android_npapi_H - -#include - -#include "npapi.h" - -/////////////////////////////////////////////////////////////////////////////// -// General types - -enum ANPBitmapFormats { - kUnknown_ANPBitmapFormat = 0, - kRGBA_8888_ANPBitmapFormat = 1, - kRGB_565_ANPBitmapFormat = 2 -}; -typedef int32_t ANPBitmapFormat; - -struct ANPPixelPacking { - uint8_t AShift; - uint8_t ABits; - uint8_t RShift; - uint8_t RBits; - uint8_t GShift; - uint8_t GBits; - uint8_t BShift; - uint8_t BBits; -}; - -struct ANPBitmap { - void* baseAddr; - ANPBitmapFormat format; - int32_t width; - int32_t height; - int32_t rowBytes; -}; - -struct ANPRectF { - float left; - float top; - float right; - float bottom; -}; - -struct ANPRectI { - int32_t left; - int32_t top; - int32_t right; - int32_t bottom; -}; - -struct ANPCanvas; -struct ANPMatrix; -struct ANPPaint; -struct ANPPath; -struct ANPRegion; -struct ANPTypeface; - -enum ANPMatrixFlags { - kIdentity_ANPMatrixFlag = 0, - kTranslate_ANPMatrixFlag = 0x01, - kScale_ANPMatrixFlag = 0x02, - kAffine_ANPMatrixFlag = 0x04, - kPerspective_ANPMatrixFlag = 0x08, -}; -typedef uint32_t ANPMatrixFlag; - -/////////////////////////////////////////////////////////////////////////////// -// NPN_GetValue - -/** queries for a specific ANPInterface. - - Maybe called with NULL for the NPP instance - - NPN_GetValue(inst, interface_enum, ANPInterface*) - */ -#define kLogInterfaceV0_ANPGetValue ((NPNVariable)1000) -#define kAudioTrackInterfaceV0_ANPGetValue ((NPNVariable)1001) -#define kCanvasInterfaceV0_ANPGetValue ((NPNVariable)1002) -#define kMatrixInterfaceV0_ANPGetValue ((NPNVariable)1003) -#define kPaintInterfaceV0_ANPGetValue ((NPNVariable)1004) -#define kPathInterfaceV0_ANPGetValue ((NPNVariable)1005) -#define kTypefaceInterfaceV0_ANPGetValue ((NPNVariable)1006) -#define kWindowInterfaceV0_ANPGetValue ((NPNVariable)1007) -#define kBitmapInterfaceV0_ANPGetValue ((NPNVariable)1008) -#define kSurfaceInterfaceV0_ANPGetValue ((NPNVariable)1009) -#define kSystemInterfaceV0_ANPGetValue ((NPNVariable)1010) -#define kEventInterfaceV0_ANPGetValue ((NPNVariable)1011) - -#define kAudioTrackInterfaceV1_ANPGetValue ((NPNVariable)1012) -#define kOpenGLInterfaceV0_ANPGetValue ((NPNVariable)1013) -#define kWindowInterfaceV1_ANPGetValue ((NPNVariable)1014) -#define kVideoInterfaceV0_ANPGetValue ((NPNVariable)1015) -#define kSystemInterfaceV1_ANPGetValue ((NPNVariable)1016) - -#define kSystemInterfaceV2_ANPGetValue ((NPNVariable)1017) - -/** queries for the drawing models supported on this device. - - NPN_GetValue(inst, kSupportedDrawingModel_ANPGetValue, uint32_t* bits) - */ -#define kSupportedDrawingModel_ANPGetValue ((NPNVariable)2000) - -/** queries for the context (android.content.Context) of the plugin. If no - instance is specified the application's context is returned. If the instance - is given then the context returned is identical to the context used to - create the webview in which that instance resides. - - NOTE: Holding onto a non-application context after your instance has been - destroyed will cause a memory leak. Refer to the android documentation to - determine what context is best suited for your particular scenario. - - NPN_GetValue(inst, kJavaContext_ANPGetValue, jobject context) - */ -#define kJavaContext_ANPGetValue ((NPNVariable)2001) - -/////////////////////////////////////////////////////////////////////////////// -// NPN_SetValue - -/** Request to set the drawing model. SetValue will return false if the drawing - model is not supported or has insufficient information for configuration. - - NPN_SetValue(inst, kRequestDrawingModel_ANPSetValue, (void*)foo_ANPDrawingModel) - */ -#define kRequestDrawingModel_ANPSetValue ((NPPVariable)1000) - -/** These are used as bitfields in ANPSupportedDrawingModels_EnumValue, - and as-is in ANPRequestDrawingModel_EnumValue. The drawing model determines - how to interpret the ANPDrawingContext provided in the Draw event and how - to interpret the NPWindow->window field. - */ -enum ANPDrawingModels { - /** Draw into a bitmap from the browser thread in response to a Draw event. - NPWindow->window is reserved (ignore) - */ - kBitmap_ANPDrawingModel = 1 << 0, - /** Draw into a surface (e.g. raster, openGL, etc.) using the Java surface - interface. When this model is used the browser will invoke the Java - class specified in the plugin's apk manifest. From that class the browser - will invoke the appropriate method to return an an instance of a android - Java View. The instance is then embedded in the html. The plugin can then - manipulate the view as it would any normal Java View in android. - - Unlike the bitmap model, a surface model is opaque so no html content - behind the plugin will be visible. Unless the plugin needs to be - transparent the surface model should be chosen over the bitmap model as - it will have better performance. - - Further, a plugin can manipulate some surfaces in native code using the - ANPSurfaceInterface. This interface can be used to manipulate Java - objects that extend Surface.class by allowing them to access the - surface's underlying bitmap in native code. For instance, if a raster - surface is used the plugin can lock, draw directly into the bitmap, and - unlock the surface in native code without making JNI calls to the Java - surface object. - */ - kSurface_ANPDrawingModel = 1 << 1, - kOpenGL_ANPDrawingModel = 1 << 2, -}; -typedef int32_t ANPDrawingModel; - -/** Request to receive/disable events. If the pointer is NULL then all flags will - be disabled. Otherwise, the event type will be enabled iff its corresponding - bit in the EventFlags bit field is set. - - NPN_SetValue(inst, ANPAcceptEvents, (void*)EventFlags) - */ -#define kAcceptEvents_ANPSetValue ((NPPVariable)1001) - -/** The EventFlags are a set of bits used to determine which types of events the - plugin wishes to receive. For example, if the value is 0x03 then both key - and touch events will be provided to the plugin. - */ -enum ANPEventFlag { - kKey_ANPEventFlag = 0x01, - kTouch_ANPEventFlag = 0x02, -}; -typedef uint32_t ANPEventFlags; - -/////////////////////////////////////////////////////////////////////////////// -// NPP_GetValue - -/** Requests that the plugin return a java surface to be displayed. This will - only be used if the plugin has choosen the kSurface_ANPDrawingModel. - - NPP_GetValue(inst, kJavaSurface_ANPGetValue, jobject surface) - */ -#define kJavaSurface_ANPGetValue ((NPPVariable)2000) - - -/////////////////////////////////////////////////////////////////////////////// -// ANDROID INTERFACE DEFINITIONS - -/** Interfaces provide additional functionality to the plugin via function ptrs. - Once an interface is retrieved, it is valid for the lifetime of the plugin - (just like browserfuncs). - - All ANPInterfaces begin with an inSize field, which must be set by the - caller (plugin) with the number of bytes allocated for the interface. - e.g. SomeInterface si; si.inSize = sizeof(si); browser->getvalue(..., &si); - */ -struct ANPInterface { - uint32_t inSize; // size (in bytes) of this struct -}; - -enum ANPLogTypes { - kError_ANPLogType = 0, // error - kWarning_ANPLogType = 1, // warning - kDebug_ANPLogType = 2 // debug only (informational) -}; -typedef int32_t ANPLogType; - -struct ANPLogInterfaceV0 : ANPInterface { - /** dumps printf messages to the log file - e.g. interface->log(instance, kWarning_ANPLogType, "value is %d", value); - */ - void (*log)(ANPLogType, const char format[], ...); -}; - -struct ANPBitmapInterfaceV0 : ANPInterface { - /** Returns true if the specified bitmap format is supported, and if packing - is non-null, sets it to the packing info for that format. - */ - bool (*getPixelPacking)(ANPBitmapFormat, ANPPixelPacking* packing); -}; - -struct ANPMatrixInterfaceV0 : ANPInterface { - /** Return a new identity matrix - */ - ANPMatrix* (*newMatrix)(); - /** Delete a matrix previously allocated by newMatrix() - */ - void (*deleteMatrix)(ANPMatrix*); - - ANPMatrixFlag (*getFlags)(const ANPMatrix*); - - void (*copy)(ANPMatrix* dst, const ANPMatrix* src); - - /** Return the matrix values in a float array (allcoated by the caller), - where the values are treated as follows: - w = x * [6] + y * [7] + [8]; - x' = (x * [0] + y * [1] + [2]) / w; - y' = (x * [3] + y * [4] + [5]) / w; - */ - void (*get3x3)(const ANPMatrix*, float[9]); - /** Initialize the matrix from values in a float array, - where the values are treated as follows: - w = x * [6] + y * [7] + [8]; - x' = (x * [0] + y * [1] + [2]) / w; - y' = (x * [3] + y * [4] + [5]) / w; - */ - void (*set3x3)(ANPMatrix*, const float[9]); - - void (*setIdentity)(ANPMatrix*); - void (*preTranslate)(ANPMatrix*, float tx, float ty); - void (*postTranslate)(ANPMatrix*, float tx, float ty); - void (*preScale)(ANPMatrix*, float sx, float sy); - void (*postScale)(ANPMatrix*, float sx, float sy); - void (*preSkew)(ANPMatrix*, float kx, float ky); - void (*postSkew)(ANPMatrix*, float kx, float ky); - void (*preRotate)(ANPMatrix*, float degrees); - void (*postRotate)(ANPMatrix*, float degrees); - void (*preConcat)(ANPMatrix*, const ANPMatrix*); - void (*postConcat)(ANPMatrix*, const ANPMatrix*); - - /** Return true if src is invertible, and if so, return its inverse in dst. - If src is not invertible, return false and ignore dst. - */ - bool (*invert)(ANPMatrix* dst, const ANPMatrix* src); - - /** Transform the x,y pairs in src[] by this matrix, and store the results - in dst[]. The count parameter is treated as the number of pairs in the - array. It is legal for src and dst to point to the same memory, but - illegal for the two arrays to partially overlap. - */ - void (*mapPoints)(ANPMatrix*, float dst[], const float src[], - int32_t count); -}; - -struct ANPPathInterfaceV0 : ANPInterface { - /** Return a new path */ - ANPPath* (*newPath)(); - - /** Delete a path previously allocated by ANPPath() */ - void (*deletePath)(ANPPath*); - - /** Make a deep copy of the src path, into the dst path (already allocated - by the caller). - */ - void (*copy)(ANPPath* dst, const ANPPath* src); - - /** Returns true if the two paths are the same (i.e. have the same points) - */ - bool (*equal)(const ANPPath* path0, const ANPPath* path1); - - /** Remove any previous points, initializing the path back to empty. */ - void (*reset)(ANPPath*); - - /** Return true if the path is empty (has no lines, quads or cubics). */ - bool (*isEmpty)(const ANPPath*); - - /** Return the path's bounds in bounds. */ - void (*getBounds)(const ANPPath*, ANPRectF* bounds); - - void (*moveTo)(ANPPath*, float x, float y); - void (*lineTo)(ANPPath*, float x, float y); - void (*quadTo)(ANPPath*, float x0, float y0, float x1, float y1); - void (*cubicTo)(ANPPath*, float x0, float y0, float x1, float y1, - float x2, float y2); - void (*close)(ANPPath*); - - /** Offset the src path by [dx, dy]. If dst is null, apply the - change directly to the src path. If dst is not null, write the - changed path into dst, and leave the src path unchanged. In that case - dst must have been previously allocated by the caller. - */ - void (*offset)(ANPPath* src, float dx, float dy, ANPPath* dst); - - /** Transform the path by the matrix. If dst is null, apply the - change directly to the src path. If dst is not null, write the - changed path into dst, and leave the src path unchanged. In that case - dst must have been previously allocated by the caller. - */ - void (*transform)(ANPPath* src, const ANPMatrix*, ANPPath* dst); -}; - -/** ANPColor is always defined to have the same packing on all platforms, and - it is always unpremultiplied. - - This is in contrast to 32bit format(s) in bitmaps, which are premultiplied, - and their packing may vary depending on the platform, hence the need for - ANPBitmapInterface::getPixelPacking() - */ -typedef uint32_t ANPColor; -#define ANPColor_ASHIFT 24 -#define ANPColor_RSHIFT 16 -#define ANPColor_GSHIFT 8 -#define ANPColor_BSHIFT 0 -#define ANP_MAKE_COLOR(a, r, g, b) \ - (((a) << ANPColor_ASHIFT) | \ - ((r) << ANPColor_RSHIFT) | \ - ((g) << ANPColor_GSHIFT) | \ - ((b) << ANPColor_BSHIFT)) - -enum ANPPaintFlag { - kAntiAlias_ANPPaintFlag = 1 << 0, - kFilterBitmap_ANPPaintFlag = 1 << 1, - kDither_ANPPaintFlag = 1 << 2, - kUnderlineText_ANPPaintFlag = 1 << 3, - kStrikeThruText_ANPPaintFlag = 1 << 4, - kFakeBoldText_ANPPaintFlag = 1 << 5, -}; -typedef uint32_t ANPPaintFlags; - -enum ANPPaintStyles { - kFill_ANPPaintStyle = 0, - kStroke_ANPPaintStyle = 1, - kFillAndStroke_ANPPaintStyle = 2 -}; -typedef int32_t ANPPaintStyle; - -enum ANPPaintCaps { - kButt_ANPPaintCap = 0, - kRound_ANPPaintCap = 1, - kSquare_ANPPaintCap = 2 -}; -typedef int32_t ANPPaintCap; - -enum ANPPaintJoins { - kMiter_ANPPaintJoin = 0, - kRound_ANPPaintJoin = 1, - kBevel_ANPPaintJoin = 2 -}; -typedef int32_t ANPPaintJoin; - -enum ANPPaintAligns { - kLeft_ANPPaintAlign = 0, - kCenter_ANPPaintAlign = 1, - kRight_ANPPaintAlign = 2 -}; -typedef int32_t ANPPaintAlign; - -enum ANPTextEncodings { - kUTF8_ANPTextEncoding = 0, - kUTF16_ANPTextEncoding = 1, -}; -typedef int32_t ANPTextEncoding; - -enum ANPTypefaceStyles { - kBold_ANPTypefaceStyle = 1 << 0, - kItalic_ANPTypefaceStyle = 1 << 1 -}; -typedef uint32_t ANPTypefaceStyle; - -typedef uint32_t ANPFontTableTag; - -struct ANPFontMetrics { - /** The greatest distance above the baseline for any glyph (will be <= 0) */ - float fTop; - /** The recommended distance above the baseline (will be <= 0) */ - float fAscent; - /** The recommended distance below the baseline (will be >= 0) */ - float fDescent; - /** The greatest distance below the baseline for any glyph (will be >= 0) */ - float fBottom; - /** The recommended distance to add between lines of text (will be >= 0) */ - float fLeading; -}; - -struct ANPTypefaceInterfaceV0 : ANPInterface { - /** Return a new reference to the typeface that most closely matches the - requested name and style. Pass null as the name to return - the default font for the requested style. Will never return null - - The 5 generic font names "serif", "sans-serif", "monospace", "cursive", - "fantasy" are recognized, and will be mapped to their logical font - automatically by this call. - - @param name May be NULL. The name of the font family. - @param style The style (normal, bold, italic) of the typeface. - @return reference to the closest-matching typeface. Caller must call - unref() when they are done with the typeface. - */ - ANPTypeface* (*createFromName)(const char name[], ANPTypefaceStyle); - - /** Return a new reference to the typeface that most closely matches the - requested typeface and specified Style. Use this call if you want to - pick a new style from the same family of the existing typeface. - If family is NULL, this selects from the default font's family. - - @param family May be NULL. The name of the existing type face. - @param s The style (normal, bold, italic) of the type face. - @return reference to the closest-matching typeface. Call must call - unref() when they are done. - */ - ANPTypeface* (*createFromTypeface)(const ANPTypeface* family, - ANPTypefaceStyle); - - /** Return the owner count of the typeface. A newly created typeface has an - owner count of 1. When the owner count is reaches 0, the typeface is - deleted. - */ - int32_t (*getRefCount)(const ANPTypeface*); - - /** Increment the owner count on the typeface - */ - void (*ref)(ANPTypeface*); - - /** Decrement the owner count on the typeface. When the count goes to 0, - the typeface is deleted. - */ - void (*unref)(ANPTypeface*); - - /** Return the style bits for the specified typeface - */ - ANPTypefaceStyle (*getStyle)(const ANPTypeface*); - - /** Some fonts are stored in files. If that is true for the fontID, then - this returns the byte length of the full file path. If path is not null, - then the full path is copied into path (allocated by the caller), up to - length bytes. If index is not null, then it is set to the truetype - collection index for this font, or 0 if the font is not in a collection. - - Note: getFontPath does not assume that path is a null-terminated string, - so when it succeeds, it only copies the bytes of the file name and - nothing else (i.e. it copies exactly the number of bytes returned by the - function. If the caller wants to treat path[] as a C string, it must be - sure that it is allocated at least 1 byte larger than the returned size, - and it must copy in the terminating 0. - - If the fontID does not correspond to a file, then the function returns - 0, and the path and index parameters are ignored. - - @param fontID The font whose file name is being queried - @param path Either NULL, or storage for receiving up to length bytes - of the font's file name. Allocated by the caller. - @param length The maximum space allocated in path (by the caller). - Ignored if path is NULL. - @param index Either NULL, or receives the TTC index for this font. - If the font is not a TTC, then will be set to 0. - @return The byte length of th font's file name, or 0 if the font is not - baked by a file. - */ - int32_t (*getFontPath)(const ANPTypeface*, char path[], int32_t length, - int32_t* index); - - /** Return a UTF8 encoded path name for the font directory, or NULL if not - supported. If returned, this string address will be valid for the life - of the plugin instance. It will always end with a '/' character. - */ - const char* (*getFontDirectoryPath)(); -}; - -struct ANPPaintInterfaceV0 : ANPInterface { - /** Return a new paint object, which holds all of the color and style - attributes that affect how things (geometry, text, bitmaps) are drawn - in a ANPCanvas. - - The paint that is returned is not tied to any particular plugin - instance, but it must only be accessed from one thread at a time. - */ - ANPPaint* (*newPaint)(); - void (*deletePaint)(ANPPaint*); - - ANPPaintFlags (*getFlags)(const ANPPaint*); - void (*setFlags)(ANPPaint*, ANPPaintFlags); - - ANPColor (*getColor)(const ANPPaint*); - void (*setColor)(ANPPaint*, ANPColor); - - ANPPaintStyle (*getStyle)(const ANPPaint*); - void (*setStyle)(ANPPaint*, ANPPaintStyle); - - float (*getStrokeWidth)(const ANPPaint*); - float (*getStrokeMiter)(const ANPPaint*); - ANPPaintCap (*getStrokeCap)(const ANPPaint*); - ANPPaintJoin (*getStrokeJoin)(const ANPPaint*); - void (*setStrokeWidth)(ANPPaint*, float); - void (*setStrokeMiter)(ANPPaint*, float); - void (*setStrokeCap)(ANPPaint*, ANPPaintCap); - void (*setStrokeJoin)(ANPPaint*, ANPPaintJoin); - - ANPTextEncoding (*getTextEncoding)(const ANPPaint*); - ANPPaintAlign (*getTextAlign)(const ANPPaint*); - float (*getTextSize)(const ANPPaint*); - float (*getTextScaleX)(const ANPPaint*); - float (*getTextSkewX)(const ANPPaint*); - void (*setTextEncoding)(ANPPaint*, ANPTextEncoding); - void (*setTextAlign)(ANPPaint*, ANPPaintAlign); - void (*setTextSize)(ANPPaint*, float); - void (*setTextScaleX)(ANPPaint*, float); - void (*setTextSkewX)(ANPPaint*, float); - - /** Return the typeface ine paint, or null if there is none. This does not - modify the owner count of the returned typeface. - */ - ANPTypeface* (*getTypeface)(const ANPPaint*); - - /** Set the paint's typeface. If the paint already had a non-null typeface, - its owner count is decremented. If the new typeface is non-null, its - owner count is incremented. - */ - void (*setTypeface)(ANPPaint*, ANPTypeface*); - - /** Return the width of the text. If bounds is not null, return the bounds - of the text in that rectangle. - */ - float (*measureText)(ANPPaint*, const void* text, uint32_t byteLength, - ANPRectF* bounds); - - /** Return the number of unichars specifed by the text. - If widths is not null, returns the array of advance widths for each - unichar. - If bounds is not null, returns the array of bounds for each unichar. - */ - int (*getTextWidths)(ANPPaint*, const void* text, uint32_t byteLength, - float widths[], ANPRectF bounds[]); - - /** Return in metrics the spacing values for text, respecting the paint's - typeface and pointsize, and return the spacing between lines - (descent - ascent + leading). If metrics is NULL, it will be ignored. - */ - float (*getFontMetrics)(ANPPaint*, ANPFontMetrics* metrics); -}; - -struct ANPCanvasInterfaceV0 : ANPInterface { - /** Return a canvas that will draw into the specified bitmap. Note: the - canvas copies the fields of the bitmap, so it need not persist after - this call, but the canvas DOES point to the same pixel memory that the - bitmap did, so the canvas should not be used after that pixel memory - goes out of scope. In the case of creating a canvas to draw into the - pixels provided by kDraw_ANPEventType, those pixels are only while - handling that event. - - The canvas that is returned is not tied to any particular plugin - instance, but it must only be accessed from one thread at a time. - */ - ANPCanvas* (*newCanvas)(const ANPBitmap*); - void (*deleteCanvas)(ANPCanvas*); - - void (*save)(ANPCanvas*); - void (*restore)(ANPCanvas*); - void (*translate)(ANPCanvas*, float tx, float ty); - void (*scale)(ANPCanvas*, float sx, float sy); - void (*rotate)(ANPCanvas*, float degrees); - void (*skew)(ANPCanvas*, float kx, float ky); - void (*concat)(ANPCanvas*, const ANPMatrix*); - void (*clipRect)(ANPCanvas*, const ANPRectF*); - void (*clipPath)(ANPCanvas*, const ANPPath*); - - /** Return the current matrix on the canvas - */ - void (*getTotalMatrix)(ANPCanvas*, ANPMatrix*); - /** Return the current clip bounds in local coordinates, expanding it to - account for antialiasing edge effects if aa is true. If the - current clip is empty, return false and ignore the bounds argument. - */ - bool (*getLocalClipBounds)(ANPCanvas*, ANPRectF* bounds, bool aa); - /** Return the current clip bounds in device coordinates in bounds. If the - current clip is empty, return false and ignore the bounds argument. - */ - bool (*getDeviceClipBounds)(ANPCanvas*, ANPRectI* bounds); - - void (*drawColor)(ANPCanvas*, ANPColor); - void (*drawPaint)(ANPCanvas*, const ANPPaint*); - void (*drawLine)(ANPCanvas*, float x0, float y0, float x1, float y1, - const ANPPaint*); - void (*drawRect)(ANPCanvas*, const ANPRectF*, const ANPPaint*); - void (*drawOval)(ANPCanvas*, const ANPRectF*, const ANPPaint*); - void (*drawPath)(ANPCanvas*, const ANPPath*, const ANPPaint*); - void (*drawText)(ANPCanvas*, const void* text, uint32_t byteLength, - float x, float y, const ANPPaint*); - void (*drawPosText)(ANPCanvas*, const void* text, uint32_t byteLength, - const float xy[], const ANPPaint*); - void (*drawBitmap)(ANPCanvas*, const ANPBitmap*, float x, float y, - const ANPPaint*); - void (*drawBitmapRect)(ANPCanvas*, const ANPBitmap*, - const ANPRectI* src, const ANPRectF* dst, - const ANPPaint*); -}; - -struct ANPWindowInterfaceV0 : ANPInterface { - /** Registers a set of rectangles that the plugin would like to keep on - screen. The rectangles are listed in order of priority with the highest - priority rectangle in location rects[0]. The browser will attempt to keep - as many of the rectangles on screen as possible and will scroll them into - view in response to the invocation of this method and other various events. - The count specifies how many rectangles are in the array. If the count is - zero it signals the browser that any existing rectangles should be cleared - and no rectangles will be tracked. - */ - void (*setVisibleRects)(NPP instance, const ANPRectI rects[], int32_t count); - /** Clears any rectangles that are being tracked as a result of a call to - setVisibleRects. This call is equivalent to setVisibleRect(inst, NULL, 0). - */ - void (*clearVisibleRects)(NPP instance); - /** Given a boolean value of true the device will be requested to provide - a keyboard. A value of false will result in a request to hide the - keyboard. Further, the on-screen keyboard will not be displayed if a - physical keyboard is active. - */ - void (*showKeyboard)(NPP instance, bool value); - /** Called when a plugin wishes to enter into full screen mode. The plugin's - Java class (defined in the plugin's apk manifest) will be called - asynchronously to provide a View object to be displayed full screen. - */ - void (*requestFullScreen)(NPP instance); - /** Called when a plugin wishes to exit from full screen mode. As a result, - the plugin's full screen view will be discarded by the view system. - */ - void (*exitFullScreen)(NPP instance); - /** Called when a plugin wishes to be zoomed and centered in the current view. - */ - void (*requestCenterFitZoom)(NPP instance); -}; - -struct ANPWindowInterfaceV1 : ANPWindowInterfaceV0 { - /** Returns a rectangle representing the visible area of the plugin on - screen. The coordinates are relative to the size of the plugin in the - document and therefore will never be negative or exceed the plugin's size. - */ - ANPRectI (*visibleRect)(NPP instance); -}; - -/////////////////////////////////////////////////////////////////////////////// - -enum ANPSampleFormats { - kUnknown_ANPSamleFormat = 0, - kPCM16Bit_ANPSampleFormat = 1, - kPCM8Bit_ANPSampleFormat = 2 -}; -typedef int32_t ANPSampleFormat; - -/** The audio buffer is passed to the callback proc to request more samples. - It is owned by the system, and the callback may read it, but should not - maintain a pointer to it outside of the scope of the callback proc. - */ -struct ANPAudioBuffer { - // RO - repeat what was specified in newTrack() - int32_t channelCount; - // RO - repeat what was specified in newTrack() - ANPSampleFormat format; - /** This buffer is owned by the caller. Inside the callback proc, up to - "size" bytes of sample data should be written into this buffer. The - address is only valid for the scope of a single invocation of the - callback proc. - */ - void* bufferData; - /** On input, specifies the maximum number of bytes that can be written - to "bufferData". On output, specifies the actual number of bytes that - the callback proc wrote into "bufferData". - */ - uint32_t size; -}; - -enum ANPAudioEvents { - /** This event is passed to the callback proc when the audio-track needs - more sample data written to the provided buffer parameter. - */ - kMoreData_ANPAudioEvent = 0, - /** This event is passed to the callback proc if the audio system runs out - of sample data. In this event, no buffer parameter will be specified - (i.e. NULL will be passed to the 3rd parameter). - */ - kUnderRun_ANPAudioEvent = 1 -}; -typedef int32_t ANPAudioEvent; - -/** Called to feed sample data to the track. This will be called in a separate - thread. However, you may call trackStop() from the callback (but you - cannot delete the track). - - For example, when you have written the last chunk of sample data, you can - immediately call trackStop(). This will take effect after the current - buffer has been played. - - The "user" parameter is the same value that was passed to newTrack() - */ -typedef void (*ANPAudioCallbackProc)(ANPAudioEvent event, void* user, - ANPAudioBuffer* buffer); - -struct ANPAudioTrack; // abstract type for audio tracks - -struct ANPAudioTrackInterfaceV0 : ANPInterface { - /** Create a new audio track, or NULL on failure. The track is initially in - the stopped state and therefore ANPAudioCallbackProc will not be called - until the track is started. - */ - ANPAudioTrack* (*newTrack)(uint32_t sampleRate, // sampling rate in Hz - ANPSampleFormat, - int channelCount, // MONO=1, STEREO=2 - ANPAudioCallbackProc, - void* user); - /** Deletes a track that was created using newTrack. The track can be - deleted in any state and it waits for the ANPAudioCallbackProc thread - to exit before returning. - */ - void (*deleteTrack)(ANPAudioTrack*); - - void (*start)(ANPAudioTrack*); - void (*pause)(ANPAudioTrack*); - void (*stop)(ANPAudioTrack*); - /** Returns true if the track is not playing (e.g. pause or stop was called, - or start was never called. - */ - bool (*isStopped)(ANPAudioTrack*); -}; - -struct ANPAudioTrackInterfaceV1 : ANPAudioTrackInterfaceV0 { - /** Returns the track's latency in milliseconds. */ - uint32_t (*trackLatency)(ANPAudioTrack*); -}; - -/////////////////////////////////////////////////////////////////////////////// -// DEFINITION OF VALUES PASSED THROUGH NPP_HandleEvent - -enum ANPEventTypes { - kNull_ANPEventType = 0, - kKey_ANPEventType = 1, - /** Mouse events are triggered by either clicking with the navigational pad - or by tapping the touchscreen (if the kDown_ANPTouchAction is handled by - the plugin then no mouse event is generated). The kKey_ANPEventFlag has - to be set to true in order to receive these events. - */ - kMouse_ANPEventType = 2, - /** Touch events are generated when the user touches on the screen. The - kTouch_ANPEventFlag has to be set to true in order to receive these - events. - */ - kTouch_ANPEventType = 3, - /** Only triggered by a plugin using the kBitmap_ANPDrawingModel. This event - signals that the plugin needs to redraw itself into the provided bitmap. - */ - kDraw_ANPEventType = 4, - kLifecycle_ANPEventType = 5, - - /** This event type is completely defined by the plugin. - When creating an event, the caller must always set the first - two fields, the remaining data is optional. - ANPEvent evt; - evt.inSize = sizeof(ANPEvent); - evt.eventType = kCustom_ANPEventType - // other data slots are optional - evt.other[] = ...; - To post a copy of the event, call - eventInterface->postEvent(myNPPInstance, &evt); - That call makes a copy of the event struct, and post that on the event - queue for the plugin. - */ - kCustom_ANPEventType = 6, - /** MultiTouch events are generated when the user touches on the screen. The - kTouch_ANPEventFlag has to be set to true in order to receive these - events. This type is a replacement for the older kTouch_ANPEventType. - */ - kMultiTouch_ANPEventType = 7, -}; -typedef int32_t ANPEventType; - -enum ANPKeyActions { - kDown_ANPKeyAction = 0, - kUp_ANPKeyAction = 1, -}; -typedef int32_t ANPKeyAction; - -#include "ANPKeyCodes.h" -typedef int32_t ANPKeyCode; - -enum ANPKeyModifiers { - kAlt_ANPKeyModifier = 1 << 0, - kShift_ANPKeyModifier = 1 << 1, -}; -// bit-field containing some number of ANPKeyModifier bits -typedef uint32_t ANPKeyModifier; - -enum ANPMouseActions { - kDown_ANPMouseAction = 0, - kUp_ANPMouseAction = 1, -}; -typedef int32_t ANPMouseAction; - -enum ANPTouchActions { - /** This occurs when the user first touches on the screen. As such, this - action will always occur prior to any of the other touch actions. If - the plugin chooses to not handle this action then no other events - related to that particular touch gesture will be generated. - */ - kDown_ANPTouchAction = 0, - kUp_ANPTouchAction = 1, - kMove_ANPTouchAction = 2, - kCancel_ANPTouchAction = 3, - // The web view will ignore the return value from the following actions - kLongPress_ANPTouchAction = 4, - kDoubleTap_ANPTouchAction = 5, -}; -typedef int32_t ANPTouchAction; - -enum ANPLifecycleActions { - /** The web view containing this plugin has been paused. See documentation - on the android activity lifecycle for more information. - */ - kPause_ANPLifecycleAction = 0, - /** The web view containing this plugin has been resumed. See documentation - on the android activity lifecycle for more information. - */ - kResume_ANPLifecycleAction = 1, - /** The plugin has focus and is now the recipient of input events (e.g. key, - touch, etc.) - */ - kGainFocus_ANPLifecycleAction = 2, - /** The plugin has lost focus and will not receive any input events until it - regains focus. This event is always preceded by a GainFocus action. - */ - kLoseFocus_ANPLifecycleAction = 3, - /** The browser is running low on available memory and is requesting that - the plugin free any unused/inactive resources to prevent a performance - degradation. - */ - kFreeMemory_ANPLifecycleAction = 4, - /** The page has finished loading. This happens when the page's top level - frame reports that it has completed loading. - */ - kOnLoad_ANPLifecycleAction = 5, - /** The browser is honoring the plugin's request to go full screen. Upon - returning from this event the browser will resize the plugin's java - surface to full-screen coordinates. - */ - kEnterFullScreen_ANPLifecycleAction = 6, - /** The browser has exited from full screen mode. Immediately prior to - sending this event the browser has resized the plugin's java surface to - its original coordinates. - */ - kExitFullScreen_ANPLifecycleAction = 7, - /** The plugin is visible to the user on the screen. This event will always - occur after a kOffScreen_ANPLifecycleAction event. - */ - kOnScreen_ANPLifecycleAction = 8, - /** The plugin is no longer visible to the user on the screen. This event - will always occur prior to an kOnScreen_ANPLifecycleAction event. - */ - kOffScreen_ANPLifecycleAction = 9, -}; -typedef uint32_t ANPLifecycleAction; - -struct TouchPoint { - int32_t id; - float x; // relative to your "window" (0...width) - float y; // relative to your "window" (0...height) - float pressure; - float size; // normalized to a value between 0...1 -}; - -/* This is what is passed to NPP_HandleEvent() */ -struct ANPEvent { - uint32_t inSize; // size of this struct in bytes - ANPEventType eventType; - // use based on the value in eventType - union { - struct { - ANPKeyAction action; - ANPKeyCode nativeCode; - int32_t virtualCode; // windows virtual key code - ANPKeyModifier modifiers; - int32_t repeatCount; // 0 for initial down (or up) - int32_t unichar; // 0 if there is no value - } key; - struct { - ANPMouseAction action; - int32_t x; // relative to your "window" (0...width) - int32_t y; // relative to your "window" (0...height) - } mouse; - struct { - ANPTouchAction action; - ANPKeyModifier modifiers; - int32_t x; // relative to your "window" (0...width) - int32_t y; // relative to your "window" (0...height) - } touch; - struct { - ANPLifecycleAction action; - } lifecycle; - struct { - ANPDrawingModel model; - // relative to (0,0) in top-left of your plugin - ANPRectI clip; - // use based on the value in model - union { - ANPBitmap bitmap; - struct { - int32_t width; - int32_t height; - } surface; - } data; - } draw; - struct { - int64_t timestamp; - int32_t id; - ANPTouchAction action; - int32_t pointerCount; - TouchPoint* touchPoint; - } multiTouch; - int32_t other[8]; - } data; -}; - -struct ANPEventInterfaceV0 : ANPInterface { - /** Post a copy of the specified event to the plugin. The event will be - delivered to the plugin in its main thread (the thread that receives - other ANPEvents). If, after posting before delivery, the NPP instance - is torn down, the event will be discarded. - */ - void (*postEvent)(NPP inst, const ANPEvent* event); -}; - - -#endif diff --git a/WebKit/android/smoke/MessageThread.cpp b/WebKit/android/smoke/MessageThread.cpp deleted file mode 100644 index 48f2222..0000000 --- a/WebKit/android/smoke/MessageThread.cpp +++ /dev/null @@ -1,146 +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. - */ - -#define LOG_TAG "MessageThread" - -#include "config.h" - -#include -#include - -#include "MessageThread.h" -#include "ScriptController.h" - -#include - -namespace android { - -static bool compareMessages(const Message& msg1, - const Message& msg2, - bool memberIsNull) { - return (msg1.object() == msg2.object() && - (memberIsNull || msg1.member() == msg2.member())); -} - -bool MessageQueue::hasMessages(const Message& message) { - AutoMutex lock(m_mutex); - - static const Message::GenericMemberFunction nullMember = NULL; - const bool memberIsNull = message.member() == nullMember; - - for (list::iterator it = m_messages.begin(); - it != m_messages.end(); ++it) { - Message* m = *it; - if (compareMessages(message, *m, memberIsNull)) - return true; - } - return false; -} - -void MessageQueue::remove(const Message& message) { - AutoMutex lock(m_mutex); - - static const Message::GenericMemberFunction nullMember = NULL; - const bool memberIsNull = message.member() == nullMember; - - for (list::iterator it = m_messages.begin(); - it != m_messages.end(); ++it) { - Message* m = *it; - if (compareMessages(message, *m, memberIsNull)) { - it = m_messages.erase(it); - delete m; - } - } -} - -void MessageQueue::post(Message* message) { - AutoMutex lock(m_mutex); - - double when = message->m_when; - LOG_ASSERT(when > 0, "Message time may not be 0"); - - list::iterator it; - for (it = m_messages.begin(); it != m_messages.end(); ++it) { - Message* m = *it; - if (when < m->m_when) { - break; - } - } - m_messages.insert(it, message); - m_condition.signal(); -} - -void MessageQueue::postAtFront(Message* message) { - AutoMutex lock(m_mutex); - message->m_when = 0; - m_messages.push_front(message); -} - -Message* MessageQueue::next() { - AutoMutex lock(m_mutex); - while (true) { - if (m_messages.empty()) { - // No messages, wait until another arrives - m_condition.wait(m_mutex); - } - Message* next = m_messages.front(); - double now = WTF::currentTimeMS(); - double diff = next->m_when - now; - if (diff > 0) { - // Not time for this message yet, wait the difference in nanos - m_condition.waitRelative(m_mutex, - static_cast(diff * 1000000) /* nanos */); - } else { - // Time for this message to run. - m_messages.pop_front(); - return next; - } - } -} - -bool MessageThread::threadLoop() { - WebCore::ScriptController::initializeThreading(); - - while (true) { - Message* message = m_queue.next(); - if (message != NULL) { - message->run(); - } - } - return false; -} - -// Global thread object obtained by messageThread(). -static sp gMessageThread; - -MessageThread* messageThread() { - if (gMessageThread == NULL) { - gMessageThread = new MessageThread(); - gMessageThread->run("WebCoreThread"); - } - return gMessageThread.get(); -} - -} // namespace android diff --git a/WebKit/android/smoke/MessageThread.h b/WebKit/android/smoke/MessageThread.h deleted file mode 100644 index ca0115b..0000000 --- a/WebKit/android/smoke/MessageThread.h +++ /dev/null @@ -1,108 +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 ANDROID_WEBKIT_MESSAGETHREAD_H -#define ANDROID_WEBKIT_MESSAGETHREAD_H - -#include - -#include "MessageTypes.h" - -#include - -using std::list; - -namespace android { - -class MessageQueue { -public: - MessageQueue() {} - - // Return true if the queue has messages with the given object and member - // function. If member is null, return true if the message has the same - // object. - template - bool hasMessages(T* object, void (T::*member)(void)); - - // Remove all messages with the given object and member function. If - // member is null, remove all messages with the given object. - template - void remove(T* object, void (T::*member)(void)); - - // Post a new message to the queue. - void post(Message* closure); - - // Post a new message at the front of the queue. - void postAtFront(Message* closure); - - // Obtain the next message. Blocks until either a new message arrives or - // we reach the time of the next message. - Message* next(); - -private: - bool hasMessages(const Message& message); - void remove(const Message& message); - - list m_messages; - Mutex m_mutex; - Condition m_condition; -}; - -template -bool MessageQueue::hasMessages(T* object, void (T::*member)(void)) { - MemberFunctionMessage message(object, member); - return hasMessages(message); -} - -template -void MessageQueue::remove(T* object, void (T::*member)(void)) { - MemberFunctionMessage message(object, member); - remove(message); -} - -class MessageThread : public Thread { -public: - MessageQueue& queue() { return m_queue; } - -private: - MessageThread() : Thread(true /* canCallJava */) {} - - virtual bool threadLoop(); - - MessageQueue m_queue; - // Used for thread initialization - Mutex m_mutex; - Condition m_condition; - - friend MessageThread* messageThread(); -}; - -// Get (possibly creating) the global MessageThread object used to pass -// messages to WebCore. -MessageThread* messageThread(); - -} // namespace android - -#endif // ANDROID_WEBKIT_MESSAGETHREAD_H diff --git a/WebKit/android/smoke/MessageTypes.h b/WebKit/android/smoke/MessageTypes.h deleted file mode 100644 index 7da6cb8..0000000 --- a/WebKit/android/smoke/MessageTypes.h +++ /dev/null @@ -1,159 +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 ANDROID_WEBKIT_MESSAGETYPES_H_ -#define ANDROID_WEBKIT_MESSAGETYPES_H_ - -#include - -// TODO(phanna): autogenerate these types! - -namespace android { - -// Forward declared for friendship! -class MessageQueue; - -// Removes the reference from the typename so we store the actual value in the -// closure. -template struct remove_reference { typedef T type; }; -template struct remove_reference { typedef T type; }; - -// Prevent the compiler from inferring the type. -template struct identity { typedef T type; }; - -// Message base class. Defines the public run() method and contains generic -// object and member function variables for use in MessageQueue. -// -// Note: The template subclass MemberFunctionMessage casts its object and -// member function to the generic void* and Message::* types. During run(), -// each template specialization downcasts to the original type and invokes the -// correct function. This may seem dangerous but the compiler enforces -// correctness in NewMessage and in the template constructor. -class Message { -public: - typedef void (Message::*GenericMemberFunction)(void); - - virtual ~Message() {} - virtual void run() = 0; - - // The wall time that the message is supposed to run. - double m_when; - - void* object() const { return m_object; } - GenericMemberFunction member() const { return m_member; } - -protected: - Message(void* object, GenericMemberFunction member, long delay = 0) - : m_object(object) - , m_member(member) { - m_when = WTF::currentTimeMS() + delay; - } - - // Downcast back to the original template params in run(). Also accessed - // by MessageQueue to compare messages. - void* m_object; - GenericMemberFunction m_member; - -private: - // Disallow copy - Message(const Message&); -}; - -// Forward declaration for partial specialization. -template -class MemberFunctionMessage; - -template -class MemberFunctionMessage : public Message { -private: - typedef void (T::*MemberSignature)(); - -public: - inline MemberFunctionMessage(T* object, - MemberSignature member, - long delay = 0) - : Message(reinterpret_cast(object), - reinterpret_cast(member), - delay) {} - - virtual void run() { - MemberSignature member = reinterpret_cast(m_member); - (reinterpret_cast(m_object)->*member)(); - delete this; - } -}; - -template -inline Message* NewMessage(T* object, void (T::*member)()) { - return new MemberFunctionMessage(object, member); -} - -template -inline Message* NewDelayedMessage(T* object, void (T::*member)(), long delay) { - return new MemberFunctionMessage(object, member, delay); -} - -template -class MemberFunctionMessage : public Message { -private: - typedef void (T::*MemberSignature)(A1); - -public: - inline MemberFunctionMessage(T* object, - MemberSignature member, - A1 arg1, - long delay = 0) - : Message(reinterpret_cast(object), - reinterpret_cast(member), - delay) - , m_arg1(arg1) {} - - virtual void run() { - MemberSignature member = reinterpret_cast(m_member); - (reinterpret_cast(m_object)->*member)(m_arg1); - delete this; - } - -private: - typename remove_reference::type m_arg1; -}; - -template -inline Message* NewMessage(T* object, void (T::*member)(A1), - typename identity::type arg1) { - return new MemberFunctionMessage( - object, member, arg1); -} - -template -inline Message* NewDelayedMessage(T* object, void (T::*member)(A1), - typename identity::type arg1, long delay) { - return new MemberFunctionMessage(object, member, arg1, delay); -} - -} // namespace android - - -#endif // ANDROID_WEBKIT_MESSAGETYPES_H_ diff --git a/WebKit/android/wds/Command.cpp b/WebKit/android/wds/Command.cpp deleted file mode 100644 index bd8536f..0000000 --- a/WebKit/android/wds/Command.cpp +++ /dev/null @@ -1,154 +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 "wds" -#include "config.h" - -#include "AndroidLog.h" -#include "Command.h" -#include "Connection.h" -#include "DebugServer.h" -#include "Frame.h" -#include "RenderTreeAsText.h" -#include "RenderView.h" -#include "WebViewCore.h" -#include -#include - -#if ENABLE(WDS) - -using namespace WebCore; - -namespace android { - -namespace WDS { - -//------------------------------------------------------------------------------ -// Actual commands -- XXX should be moved somewhere else -//------------------------------------------------------------------------------ -static bool callDumpRenderTree(const Frame* frame, const Connection* conn) { - CString str = externalRepresentation(frame->contentRenderer()).latin1(); - conn->write(str.data(), str.length()); - return true; -} - -static bool callDumpDomTree(const Frame* frame, const Connection* conn) { - WebViewCore::getWebViewCore(frame->view())->dumpDomTree(true); - - FILE* f = fopen(DOM_TREE_LOG_FILE, "r"); - if (!f) { - conn->write("Dom tree written to logcat\n"); - } else { - char buf[512]; - while (true) { - int nread = fread(buf, 1, sizeof(buf), f); - if (nread <= 0) - break; - conn->write(buf, nread); - } - fclose(f); - } - return true; -} - -class WebCoreHandler : public Handler { -public: - virtual void post(TargetThreadFunction func, void* v) const { - callOnMainThread(func, v); - } -}; -static WebCoreHandler s_webcoreHandler; - -//------------------------------------------------------------------------------ -// End command section -//------------------------------------------------------------------------------ - -class InternalCommand : public Command { -public: - InternalCommand(const Command* comm, const Frame* frame, - const Connection* connection) - : Command(*comm) - , m_frame(frame) - , m_connection(connection) {} - virtual ~InternalCommand() { delete m_connection; } - - void doCommand() const { - LOGD("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); - } - -private: - const Frame* m_frame; - const Connection* m_connection; -}; - -static void commandDispatcher(void* v) { - InternalCommand* c = static_cast(v); - c->doCommand(); - delete c; -} - -void Command::dispatch() { - m_handler.post(commandDispatcher, this); -} - -Vector* Command::s_commands; - -void Command::Init() { - // Do not initialize twice. - if (s_commands) - return; - // XXX: Move this somewhere else. - s_commands = new Vector(); - s_commands->append(new Command("DDOM", "Dump Dom Tree", - callDumpDomTree, s_webcoreHandler)); - s_commands->append(new Command("DDRT", "Dump Render Tree", - callDumpRenderTree, s_webcoreHandler)); -} - -Command* Command::Find(const Connection* conn) { - char buf[COMMAND_LENGTH]; - if (conn->read(buf, sizeof(buf)) != COMMAND_LENGTH) - return NULL; - - // Linear search of commands. TODO: binary search when more commands are - // added. - Vector::const_iterator i = s_commands->begin(); - Vector::const_iterator end = s_commands->end(); - while (i != end) { - if (strncmp(buf, (*i)->name(), sizeof(buf)) == 0) - return new InternalCommand(*i, server()->getFrame(0), conn); - i++; - } - return NULL; -} - -} // end namespace WDS - -} // end namespace android - -#endif diff --git a/WebKit/android/wds/Command.h b/WebKit/android/wds/Command.h deleted file mode 100644 index 90861d4..0000000 --- a/WebKit/android/wds/Command.h +++ /dev/null @@ -1,108 +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 WDS_COMMAND_H -#define WDS_COMMAND_H - -#include "wtf/MainThread.h" -#include "wtf/Vector.h" - -namespace WebCore { -class Frame; -} - -using namespace WTF; -using namespace WebCore; - -namespace android { - -// WebCore Debug Server -namespace WDS { - -class Connection; - -// Command identifier length -#define COMMAND_LENGTH 4 - -// The dispatcher function called with a Frame for context and the established -// connection to the client. The connection can be used to read and write to the -// client application. Return true on successful completion of the command, -// return false to indicate failure. -typedef bool (*DispatchFunction)(const Frame*, const Connection*); - -// Note: Although the type is named MainThreadFunction, it may not always be -// the main thread. The type is generic enough to reuse here but named -// something more appropriate. -typedef MainThreadFunction TargetThreadFunction; - -// Helper class to dipatch functions on a particular thread. -class Handler { -public: - virtual ~Handler() {} - virtual void post(TargetThreadFunction, void*) const = 0; -}; - -// Class for containing information about particular commands. -class Command { -public: - Command(const char* name, const char* desc, const DispatchFunction func, - const Handler& handler) - : m_name(name) - , m_description(desc) - , m_dispatch(func) - , m_handler(handler) {} - Command(const Command& comm) - : m_name(comm.m_name) - , m_description(comm.m_description) - , m_dispatch(comm.m_dispatch) - , m_handler(comm.m_handler) {} - virtual ~Command() {} - - // Initialize the debug server commands - static void Init(); - - // Find the command specified by the client request. - static Command* Find(const Connection* conn); - - // Dispatch this command - void dispatch(); - - const char* name() const { return m_name; } - -protected: - const char* m_name; - const char* m_description; - const DispatchFunction m_dispatch; - -private: - const Handler& m_handler; - static Vector* s_commands; -}; - -} // end namespace WDS - -} // end namespace android - -#endif diff --git a/WebKit/android/wds/Connection.cpp b/WebKit/android/wds/Connection.cpp deleted file mode 100644 index d7e55ac..0000000 --- a/WebKit/android/wds/Connection.cpp +++ /dev/null @@ -1,93 +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 "wds" -#include "config.h" - -#include "DebugServer.h" // used for ENABLE_WDS -#include "Connection.h" -#include -#include -#include - -#if ENABLE(WDS) - -#define MAX_CONNECTION_QUEUE 5 -#define log_errno(x) LOGE("%s: %d", x, strerror(errno)) - -namespace android { - -namespace WDS { - -bool Socket::open() { - m_fd = socket(PF_INET, SOCK_STREAM, 0); - if (m_fd < 0) { - log_errno("Failed to create file descriptor"); - return false; - } - return true; -} - -bool ConnectionServer::connect(short port) { - if (!m_socket.open()) - return false; - int fd = m_socket.fd(); - - // Build our sockaddr_in structure use to listen to incoming connections - sockaddr_in addr; - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = htonl(INADDR_ANY); - addr.sin_port = htons(port); - - // Try to bind to the given port - if (bind(fd, (sockaddr*) &addr, sizeof(addr)) < 0) { - log_errno("Failed to bind to local host"); - return false; - } - - // Try to listen - if (listen(fd, MAX_CONNECTION_QUEUE) < 0) { - log_errno("Failed to listen"); - return false; - } - - return true; -} - -Connection* ConnectionServer::accept() const { - int conn = ::accept(m_socket.fd(), NULL, NULL); - if (conn < 0) { - log_errno("Accept failed"); - return NULL; - } - return new Connection(conn); -} - -} // end namespace WDS - -} // end namespace android - -#endif diff --git a/WebKit/android/wds/Connection.h b/WebKit/android/wds/Connection.h deleted file mode 100644 index d67179e..0000000 --- a/WebKit/android/wds/Connection.h +++ /dev/null @@ -1,86 +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 WDS_CONNECTION_H -#define WDS_CONNECTION_H - -#include -#include - -namespace android { - -namespace WDS { - -class Socket { -public: - Socket(): m_fd(-1) {} - Socket(int fd): m_fd(fd) {} - ~Socket() { - if (m_fd != -1) { - shutdown(m_fd, SHUT_RDWR); - close(m_fd); - } - } - // Open a new socket using PF_INET and SOCK_STREAM - bool open(); - int fd() const { return m_fd; } -private: - int m_fd; -}; - -class Connection { -public: - Connection(int conn): m_socket(conn) {} - int read(char buf[], size_t length) const { - return recv(m_socket.fd(), buf, length, 0); - } - int write(const char buf[], size_t length) const { - return send(m_socket.fd(), buf, length, 0); - } - int write(const char buf[]) const { - return write(buf, strlen(buf)); - } -private: - Socket m_socket; -}; - -class ConnectionServer { -public: - ConnectionServer() {} - - // Establish a connection to the local host on the given port. - bool connect(short port); - - // Blocks on the established socket until a new connection arrives. - Connection* accept() const; -private: - Socket m_socket; -}; - -} // end namespace WDS - -} // end namespace android - -#endif diff --git a/WebKit/android/wds/DebugServer.cpp b/WebKit/android/wds/DebugServer.cpp deleted file mode 100644 index f33a65b..0000000 --- a/WebKit/android/wds/DebugServer.cpp +++ /dev/null @@ -1,116 +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 "wds" -#include "config.h" - -#include "Command.h" -#include "Connection.h" -#include "DebugServer.h" -#include "wtf/MainThread.h" -#include "wtf/Threading.h" -#include -#include -#include -#include -#include -#include -#include - -#if ENABLE(WDS) - -#define DEFAULT_PORT 9999 -#define log_errno(x) LOGE("%s: %d", x, strerror(errno)) - -namespace android { - -namespace WDS { - -static DebugServer* s_server = NULL; - -// Main thread function for createThread -static void* mainThread(void* v) { - DebugServer* server = static_cast(v); - server->start(); - delete server; - s_server = NULL; - return NULL; -} - -DebugServer* server() { - if (s_server == NULL) - s_server = new DebugServer(); - return s_server; -} - -DebugServer::DebugServer() { - // Read webcore.wds.enable to determine if the debug server should run - char buf[PROPERTY_VALUE_MAX]; - int ret = property_get("webcore.wds.enable", buf, NULL); - if (ret != -1 && strcmp(buf, "1") == 0) { - LOGD("WDS Enabled"); - m_threadId = createThread(mainThread, this, "WDS"); - } - // Initialize the available commands. - Command::Init(); -} - -void DebugServer::start() { - LOGD("DebugServer thread started"); - - ConnectionServer cs; - if (!cs.connect(DEFAULT_PORT)) { - LOGE("Failed to start the server socket connection"); - return; - } - - while (true ) { - LOGD("Waiting for incoming connections..."); - Connection* conn = cs.accept(); - if (!conn) { - log_errno("Failed to accept new connections"); - return; - } - LOGD("...Connection established"); - - Command* c = Command::Find(conn); - if (!c) { - LOGE("Could not find matching command"); - delete conn; - } else { - // Dispatch the command, it will handle cleaning up the connection - // when finished. - c->dispatch(); - } - } - - LOGD("DebugServer thread finished"); -} - -} // end namespace WDS - -} // end namespace android - -#endif diff --git a/WebKit/android/wds/DebugServer.h b/WebKit/android/wds/DebugServer.h deleted file mode 100644 index 92edad9..0000000 --- a/WebKit/android/wds/DebugServer.h +++ /dev/null @@ -1,77 +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 DEBUGSERVER_H -#define DEBUGSERVER_H - -// Turn on the wds feature in webkit -#define ENABLE_WDS 0 - -#include "wtf/Threading.h" -#include "wtf/Vector.h" - -// Forward declarations. -namespace WebCore { - class Frame; -} - -using namespace WTF; -using namespace WebCore; - -namespace android { - -// WebCore Debug Server -namespace WDS { - -class DebugServer : WTFNoncopyable::Noncopyable { -public: - void start(); - void addFrame(Frame* frame) { - m_frames.append(frame); - } - void removeFrame(Frame* frame) { - size_t i = m_frames.find(frame); - if (i != notFound) - m_frames.remove(i); - } - Frame* getFrame(unsigned idx) { - if (idx < m_frames.size()) - return m_frames.at(idx); - return NULL; - } -private: - DebugServer(); - WTF::Vector m_frames; - ThreadIdentifier m_threadId; - friend DebugServer* server(); -}; - -DebugServer* server(); - -} // end namespace WDS - -} // end namespace android - -#endif diff --git a/WebKit/android/wds/client/AdbConnection.cpp b/WebKit/android/wds/client/AdbConnection.cpp deleted file mode 100644 index 465f9c3..0000000 --- a/WebKit/android/wds/client/AdbConnection.cpp +++ /dev/null @@ -1,237 +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 "wdsclient" - -#include "AdbConnection.h" -#include "ClientUtils.h" -#include "Device.h" -#include -#include -#include -#include -#include -#include - -void AdbConnection::close() { - if (m_fd != -1) { - shutdown(m_fd, SHUT_RDWR); - ::close(m_fd); - m_fd = -1; - } -} - -// Default adb port -#define ADB_PORT 5037 - -bool AdbConnection::connect() { - // Some commands (host:devices for example) close the connection so we call - // connect after the response. - close(); - - m_fd = socket(PF_INET, SOCK_STREAM, 0); - if (m_fd < 0) { - log_errno("Failed to create socket for connecting to adb"); - return false; - } - - // Create the socket address struct - sockaddr_in adb; - createTcpSocket(adb, ADB_PORT); - - // Connect to adb - if (::connect(m_fd, (sockaddr*) &adb, sizeof(adb)) < 0) { - log_errno("Failed to connect to adb"); - return false; - } - - // Connected - return true; -} - -// Adb protocol stuff -#define MAX_COMMAND_LENGTH 1024 -#define PAYLOAD_LENGTH 4 -#define PAYLOAD_FORMAT "%04X" - -bool AdbConnection::sendRequest(const char* fmt, ...) const { - if (m_fd == -1) { - LOGE("Connection is closed"); - return false; - } - - // Build the command (service) - char buf[MAX_COMMAND_LENGTH]; - va_list args; - va_start(args, fmt); - int res = vsnprintf(buf, MAX_COMMAND_LENGTH, fmt, args); - va_end(args); - - LOGV("Sending command: %04X%.*s", res, res, buf); - - // Construct the payload length - char payloadLen[PAYLOAD_LENGTH + 1]; - snprintf(payloadLen, sizeof(payloadLen), PAYLOAD_FORMAT, res); - - // First, send the payload length - if (send(m_fd, payloadLen, PAYLOAD_LENGTH, 0) < 0) { - log_errno("Failure when sending payload"); - return false; - } - - // Send the actual command - if (send(m_fd, buf, res, 0) < 0) { - log_errno("Failure when sending command"); - return false; - } - - // Check for the OKAY from adb - return checkOkayResponse(); -} - -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"); - lenStr[PAYLOAD_LENGTH] = 0; - - // Parse the hex payload - payloadLen = strtol(lenStr, NULL, 16); - if (payloadLen < 0) - return; - - // Grab the message - char* msg = new char[payloadLen + 1]; // include null-terminator - int res = recv(fd, msg, payloadLen, 0); - if (res < 0) { - log_errno("Failure reading failure message from adb"); - return; - } else if (res != payloadLen) { - LOGE("Incorrect payload length %d - expected %d", res, payloadLen); - return; - } - msg[res] = 0; - - // Tell somebody about it - LOGE("Received failure from adb: %s", msg); - - // Cleanup - delete[] msg; -} - -#define ADB_RESPONSE_LENGTH 4 - -bool AdbConnection::checkOkayResponse() const { - LOG_ASSERT(m_fd != -1, "Connection has been closed!"); - - char buf[ADB_RESPONSE_LENGTH]; - int res = recv(m_fd, buf, sizeof(buf), 0); - if (res < 0) { - log_errno("Failure reading response from adb"); - return false; - } - - // Check for a response other than OKAY/FAIL - if ((res == ADB_RESPONSE_LENGTH) && (strncmp(buf, "OKAY", res) == 0)) { - LOGV("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); - return false; -} - -void AdbConnection::clearDevices() { - for (unsigned i = 0; i < m_devices.size(); i++) - delete m_devices.editItemAt(i); - m_devices.clear(); -} - -const DeviceList& AdbConnection::getDeviceList() { - // Clear the current device list - clearDevices(); - - if (m_fd == -1) { - LOGE("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"); - return m_devices; - } - - // Get the payload length - char lenStr[PAYLOAD_LENGTH + 1]; - int res = recv(m_fd, lenStr, sizeof(lenStr) - 1, 0); - if (res < 0) { - log_errno("Failure to read payload size of device list"); - return m_devices; - } - lenStr[PAYLOAD_LENGTH] = 0; - - // Parse the hex payload - int payloadLen = strtol(lenStr, NULL, 16); - if (payloadLen < 0) - return m_devices; - - // Grab the list of devices. The format is as follows: - // - char* msg = new char[payloadLen + 1]; - res = recv(m_fd, msg, payloadLen, 0); - if (res < 0) { - log_errno("Failure reading the device list"); - return m_devices; - } else if (res != payloadLen) { - LOGE("Incorrect payload length %d - expected %d", res, payloadLen); - return m_devices; - } - msg[res] = 0; - - char serial[32]; - char state[32]; - int numRead; - char* ptr = msg; - while (sscanf(ptr, "%31s\t%31s\n%n", serial, state, &numRead) > 1) { - Device::DeviceType t = Device::DEVICE; - static const char emulator[] = "emulator-"; - if (strncmp(serial, emulator, sizeof(emulator) - 1) == 0) - t = Device::EMULATOR; - LOGV("Adding device %s (%s)", serial, state); - m_devices.add(new Device(serial, t, this)); - - // Reset for the next line - ptr += numRead; - } - // Cleanup - delete[] msg; - - return m_devices; -} diff --git a/WebKit/android/wds/client/AdbConnection.h b/WebKit/android/wds/client/AdbConnection.h deleted file mode 100644 index 58bad67..0000000 --- a/WebKit/android/wds/client/AdbConnection.h +++ /dev/null @@ -1,47 +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 WDS_ADB_CONNECTION_H -#define WDS_ADB_CONNECTION_H - -#include "DeviceList.h" - -class AdbConnection { -public: - AdbConnection() : m_fd(-1) {} - ~AdbConnection() { clearDevices(); } - void close(); - bool connect(); - bool sendRequest(const char* fmt, ...) const; - const DeviceList& getDeviceList(); - -private: - bool checkOkayResponse() const; - void clearDevices(); - DeviceList m_devices; - int m_fd; -}; - -#endif diff --git a/WebKit/android/wds/client/Android.mk b/WebKit/android/wds/client/Android.mk deleted file mode 100644 index db79dd4..0000000 --- a/WebKit/android/wds/client/Android.mk +++ /dev/null @@ -1,39 +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. -## - -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - AdbConnection.cpp \ - ClientUtils.cpp \ - Device.cpp \ - main.cpp - -LOCAL_STATIC_LIBRARIES := liblog libutils libcutils - -LOCAL_MODULE:= wdsclient - -include $(BUILD_HOST_EXECUTABLE) diff --git a/WebKit/android/wds/client/ClientUtils.cpp b/WebKit/android/wds/client/ClientUtils.cpp deleted file mode 100644 index f8ca889..0000000 --- a/WebKit/android/wds/client/ClientUtils.cpp +++ /dev/null @@ -1,35 +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 "ClientUtils.h" -#include -#include - -void createTcpSocket(sockaddr_in& addr, short port) { - memset(&addr, 0, sizeof(sockaddr_in)); - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr); -} diff --git a/WebKit/android/wds/client/ClientUtils.h b/WebKit/android/wds/client/ClientUtils.h deleted file mode 100644 index 5da1624..0000000 --- a/WebKit/android/wds/client/ClientUtils.h +++ /dev/null @@ -1,46 +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 WDS_CLIENT_UTILS_H -#define WDS_CLIENT_UTILS_H - -#include - -/* - * included for sockaddr_in structure, AF_INET definiton and etc. - */ -#ifdef __FreeBSD__ -#include -#include -#endif - -// Callers need to include Log.h and errno.h to use this macro -#define log_errno(str) LOGE("%s: %s", str, strerror(errno)) - -// Fill in the sockaddr_in structure for binding to the localhost on the given -// port -void createTcpSocket(sockaddr_in& addr, short port); - -#endif diff --git a/WebKit/android/wds/client/Device.cpp b/WebKit/android/wds/client/Device.cpp deleted file mode 100644 index 789a89d..0000000 --- a/WebKit/android/wds/client/Device.cpp +++ /dev/null @@ -1,31 +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 "AdbConnection.h" -#include "Device.h" - -bool Device::sendRequest(const char* req) const { - return m_connection->sendRequest("host-serial:%s:%s", m_name, req); -} diff --git a/WebKit/android/wds/client/Device.h b/WebKit/android/wds/client/Device.h deleted file mode 100644 index 39d4b12..0000000 --- a/WebKit/android/wds/client/Device.h +++ /dev/null @@ -1,62 +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 WDS_DEVICE_H -#define WDS_DEVICE_H - -#include - -class AdbConnection; - -class Device { -public: - // Type of device. - // TODO: Add simulator support - enum DeviceType { - NONE = -1, - EMULATOR, - DEVICE - }; - - // Takes ownership of name - Device(char* name, DeviceType type, const AdbConnection* conn) - : m_connection(conn) - , m_name(strdup(name)) - , m_type(type) {} - ~Device() { free(m_name); } - - const char* name() const { return m_name; } - DeviceType type() const { return m_type; } - - // Send a request to this device. - bool sendRequest(const char* req) const; - -private: - const AdbConnection* m_connection; - char* m_name; - DeviceType m_type; -}; - -#endif diff --git a/WebKit/android/wds/client/DeviceList.h b/WebKit/android/wds/client/DeviceList.h deleted file mode 100644 index 45bfb87..0000000 --- a/WebKit/android/wds/client/DeviceList.h +++ /dev/null @@ -1,35 +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 WDS_DEVICE_LIST_H -#define WDS_DEVICE_LIST_H - -#include - -class Device; - -typedef android::Vector DeviceList; - -#endif diff --git a/WebKit/android/wds/client/main.cpp b/WebKit/android/wds/client/main.cpp deleted file mode 100644 index 1c7d856..0000000 --- a/WebKit/android/wds/client/main.cpp +++ /dev/null @@ -1,173 +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 "wdsclient" - -#include "AdbConnection.h" -#include "ClientUtils.h" -#include "Device.h" -#include -#include -#include -#include -#include -#include -#include -#include - -#define DEFAULT_WDS_PORT 9999 -#define STR(x) #x -#define XSTR(x) STR(x) -#define PORT_STR XSTR(DEFAULT_WDS_PORT) - -int wds_open() { - // Create the structure for connecting to the forwarded 9999 port - sockaddr_in addr; - createTcpSocket(addr, DEFAULT_WDS_PORT); - - // Create our socket - int fd = socket(PF_INET, SOCK_STREAM, 0); - if (fd < 0) { - log_errno("Failed to create file descriptor"); - return -1; - } - // Connect to the remote wds server thread - if (connect(fd, (sockaddr*)&addr, sizeof(addr)) < 0) { - log_errno("Failed to connect to remote debug server"); - return -1; - } - return fd; -} - -// Clean up the file descriptor and connections -void wds_close(int fd) { - if (fd != -1) { - shutdown(fd, SHUT_RDWR); - close(fd); - } -} - -int main(int argc, char** argv) { - - Device::DeviceType type = Device::NONE; - - if (argc <= 1) { - LOGE("wdsclient takes at least 1 argument"); - return 1; - } else { - // Parse the options, look for -e or -d to choose a device. - while (true) { - int c = getopt(argc, argv, "ed"); - if (c == -1) - break; - switch (c) { - case 'e': - type = Device::EMULATOR; - break; - case 'd': - type = Device::DEVICE; - break; - default: - break; - } - } - if (optind == argc) { - LOGE("No command specified"); - return 1; - } - } - - // Do the initial connection. - AdbConnection conn; - conn.connect(); - - const DeviceList& devices = conn.getDeviceList(); - // host:devices closes the connection, reconnect - conn.connect(); - - // 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"); - return 1; - } else if (devices.size() == 0) { - LOGE("No devices connected"); - return 1; - } - - // Find the correct device - const Device* device = NULL; - if (type == Device::NONE) - device = devices[0]; // grab the only one - else { - // Search for a matching device type - for (unsigned i = 0; i < devices.size(); i++) { - if (devices[i]->type() == type) { - device = devices[i]; - break; - } - } - } - - if (!device) { - LOGE("No device found!"); - return 1; - } - - // Forward tcp:9999 - if (!device->sendRequest("forward:tcp:" PORT_STR ";tcp:" PORT_STR)) { - LOGE("Failed to send forwarding request"); - return 1; - } - - LOGV("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); - return 1; - } - - // Open the wds connection - int wdsFd = wds_open(); - if (wdsFd == -1) - return 1; - - // Send the command specified - send(wdsFd, command, WDS_COMMAND_LENGTH, 0); // commands are 4 bytes - - // Read and display the response - char response[256]; - int res = 0; - while ((res = recv(wdsFd, response, sizeof(response), 0)) > 0) - printf("%.*s", res, response); - printf("\n\n"); - - // Shutdown - wds_close(wdsFd); - - return 0; -} -- cgit v1.1