diff options
Diffstat (limited to 'WebKit/android/jni')
| -rw-r--r-- | WebKit/android/jni/JavaBridge.cpp | 19 | ||||
| -rw-r--r-- | WebKit/android/jni/JavaSharedClient.cpp | 12 | ||||
| -rw-r--r-- | WebKit/android/jni/JavaSharedClient.h | 4 | ||||
| -rw-r--r-- | WebKit/android/jni/MIMETypeRegistry.cpp | 5 | ||||
| -rwxr-xr-x | WebKit/android/jni/MockGeolocation.cpp | 2 | ||||
| -rw-r--r-- | WebKit/android/jni/WebCoreFrameBridge.cpp | 193 | ||||
| -rw-r--r-- | WebKit/android/jni/WebCoreJniOnLoad.cpp | 9 | ||||
| -rw-r--r-- | WebKit/android/jni/WebCoreResourceLoader.cpp | 2 | ||||
| -rw-r--r-- | WebKit/android/jni/WebCoreViewBridge.h | 48 | ||||
| -rw-r--r-- | WebKit/android/jni/WebHistory.cpp | 12 | ||||
| -rw-r--r-- | WebKit/android/jni/WebHistory.h | 6 | ||||
| -rw-r--r-- | WebKit/android/jni/WebIconDatabase.cpp | 1 | ||||
| -rw-r--r-- | WebKit/android/jni/WebSettings.cpp | 20 | ||||
| -rw-r--r-- | WebKit/android/jni/WebViewCore.cpp | 681 | ||||
| -rw-r--r-- | WebKit/android/jni/WebViewCore.h | 55 |
15 files changed, 770 insertions, 299 deletions
diff --git a/WebKit/android/jni/JavaBridge.cpp b/WebKit/android/jni/JavaBridge.cpp index 0e65e1c..6aceb1c 100644 --- a/WebKit/android/jni/JavaBridge.cpp +++ b/WebKit/android/jni/JavaBridge.cpp @@ -31,6 +31,7 @@ #include "Cache.h" #include "Connection.h" #include "CookieClient.h" +#include "FileSystemClient.h" #include "JavaSharedClient.h" #include "KeyGeneratorClient.h" #include "KURL.h" @@ -62,7 +63,7 @@ static jfieldID gJavaBridge_ObjectID; // ---------------------------------------------------------------------------- -class JavaBridge : public TimerClient, public CookieClient, public PluginClient, public KeyGeneratorClient +class JavaBridge : public TimerClient, public CookieClient, public PluginClient, public KeyGeneratorClient, public FileSystemClient { public: JavaBridge(JNIEnv* env, jobject obj); @@ -84,6 +85,7 @@ public: virtual WTF::Vector<String> getSupportedKeyStrengthList(); virtual WebCore::String getSignedPublicKeyAndChallengeString(unsigned index, const WebCore::String& challenge, const WebCore::KURL& url); + virtual WebCore::String resolveFilePathForContentUri(const WebCore::String& uri); //////////////////////////////////////////// @@ -120,6 +122,7 @@ private: jmethodID mSignalFuncPtrQueue; jmethodID mGetKeyStrengthList; jmethodID mGetSignedPublicKey; + jmethodID mResolveFilePathForContentUri; }; static void (*sSharedTimerFiredCallback)(); @@ -139,6 +142,7 @@ JavaBridge::JavaBridge(JNIEnv* env, jobject obj) 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;"); LOG_ASSERT(mSetSharedTimer, "Could not find method setSharedTimer"); LOG_ASSERT(mStopSharedTimer, "Could not find method stopSharedTimer"); @@ -154,6 +158,7 @@ JavaBridge::JavaBridge(JNIEnv* env, jobject obj) JavaSharedClient::SetCookieClient(this); JavaSharedClient::SetPluginClient(this); JavaSharedClient::SetKeyGeneratorClient(this); + JavaSharedClient::SetFileSystemClient(this); } JavaBridge::~JavaBridge() @@ -168,6 +173,7 @@ JavaBridge::~JavaBridge() JavaSharedClient::SetCookieClient(NULL); JavaSharedClient::SetPluginClient(NULL); JavaSharedClient::SetKeyGeneratorClient(NULL); + JavaSharedClient::SetFileSystemClient(NULL); } void @@ -308,6 +314,17 @@ WebCore::String JavaBridge::getSignedPublicKeyAndChallengeString(unsigned index, return ret; } +WebCore::String JavaBridge::resolveFilePathForContentUri(const WebCore::String& uri) { + JNIEnv* env = JSC::Bindings::getJNIEnv(); + jstring jUri = env->NewString(uri.characters(), uri.length()); + AutoJObject obj = getRealObject(env, mJavaObject); + jstring path = static_cast<jstring>(env->CallObjectMethod(obj.get(), mResolveFilePathForContentUri, jUri)); + WebCore::String ret = to_string(env, path); + env->DeleteLocalRef(jUri); + env->DeleteLocalRef(path); + return ret; +} + // ---------------------------------------------------------------------------- void JavaBridge::Constructor(JNIEnv* env, jobject obj) diff --git a/WebKit/android/jni/JavaSharedClient.cpp b/WebKit/android/jni/JavaSharedClient.cpp index ce46570..e884c99 100644 --- a/WebKit/android/jni/JavaSharedClient.cpp +++ b/WebKit/android/jni/JavaSharedClient.cpp @@ -24,6 +24,7 @@ */ #include "config.h" +#include "FileSystemClient.h" #include "JavaSharedClient.h" #include "TimerClient.h" #include "SkDeque.h" @@ -50,6 +51,11 @@ namespace android { return gKeyGeneratorClient; } + FileSystemClient* JavaSharedClient::GetFileSystemClient() + { + return gFileSystemClient; + } + void JavaSharedClient::SetTimerClient(TimerClient* client) { gTimerClient = client; @@ -70,10 +76,16 @@ namespace android { 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; /////////////////////////////////////////////////////////////////////////// diff --git a/WebKit/android/jni/JavaSharedClient.h b/WebKit/android/jni/JavaSharedClient.h index d33df67..9a09280 100644 --- a/WebKit/android/jni/JavaSharedClient.h +++ b/WebKit/android/jni/JavaSharedClient.h @@ -32,6 +32,7 @@ namespace android { class CookieClient; class PluginClient; class KeyGeneratorClient; + class FileSystemClient; class JavaSharedClient { @@ -40,11 +41,13 @@ namespace android { 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); @@ -56,6 +59,7 @@ namespace android { static CookieClient* gCookieClient; static PluginClient* gPluginClient; static KeyGeneratorClient* gKeyGeneratorClient; + static FileSystemClient* gFileSystemClient; }; } #endif diff --git a/WebKit/android/jni/MIMETypeRegistry.cpp b/WebKit/android/jni/MIMETypeRegistry.cpp index 32f387d..5fe9ccd 100644 --- a/WebKit/android/jni/MIMETypeRegistry.cpp +++ b/WebKit/android/jni/MIMETypeRegistry.cpp @@ -58,4 +58,9 @@ String MIMETypeRegistry::getMIMETypeForExtension(const String& ext) return result; } +bool MIMETypeRegistry::isApplicationPluginMIMEType(const String&) +{ + return false; +} + } diff --git a/WebKit/android/jni/MockGeolocation.cpp b/WebKit/android/jni/MockGeolocation.cpp index df580c3..1c236c3 100755 --- a/WebKit/android/jni/MockGeolocation.cpp +++ b/WebKit/android/jni/MockGeolocation.cpp @@ -53,7 +53,7 @@ static void setPosition(JNIEnv* env, jobject, double latitude, double longitude, false, 0.0, // altitudeAccuracy, false, 0.0, // heading false, 0.0); // speed - RefPtr<Geoposition> position = Geoposition::create(coordinates.release(), WTF::currentTime()); + RefPtr<Geoposition> position = Geoposition::create(coordinates.release(), WTF::currentTimeMS()); GeolocationServiceMock::setPosition(position.release()); } diff --git a/WebKit/android/jni/WebCoreFrameBridge.cpp b/WebKit/android/jni/WebCoreFrameBridge.cpp index 250ffc9..bfd4b62 100644 --- a/WebKit/android/jni/WebCoreFrameBridge.cpp +++ b/WebKit/android/jni/WebCoreFrameBridge.cpp @@ -32,7 +32,6 @@ #include "AtomicString.h" #include "BackForwardList.h" #include "Cache.h" -#include "CString.h" #include "Chrome.h" #include "ChromeClientAndroid.h" #include "ContextMenuClientAndroid.h" @@ -74,6 +73,7 @@ #include "SecurityOrigin.h" #include "SelectionController.h" #include "Settings.h" +#include "StringBuilder.h" #include "SubstituteData.h" #include "WebCoreJni.h" #include "WebCoreResourceLoader.h" @@ -93,6 +93,7 @@ #include <utils/AssetManager.h> #include <wtf/CurrentTime.h> #include <wtf/Platform.h> +#include <wtf/text/CString.h> #if USE(JSC) #include "GCController.h" @@ -111,11 +112,16 @@ #include "TimeCounter.h" #endif +#if ENABLE(ARCHIVE) +#include "WebArchiveAndroid.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) @@ -127,6 +133,9 @@ String* WebCore::PlatformBridge::globalLocalizedName( return gResetLabel; case WebCore::PlatformBridge::SubmitLabel: return gSubmitLabel; + case WebCore::PlatformBridge::FileUploadNoFileChosenLabel: + return gNoFileChosenLabel; + default: return 0; } @@ -148,6 +157,9 @@ void initGlobalLocalizedName(WebCore::PlatformBridge::rawResId resId, case WebCore::PlatformBridge::SubmitLabel: pointer = &gSubmitLabel; break; + case WebCore::PlatformBridge::FileUploadNoFileChosenLabel: + pointer = &gNoFileChosenLabel; + break; default: return; } @@ -310,9 +322,9 @@ static jobject createJavaMapFromHTTPHeaders(JNIEnv* env, const WebCore::HTTPHead jstring val = env->NewString((unsigned short *)i->second.characters(), i->second.length()); if (key && val) { env->CallObjectMethod(hashMap, put, key, val); - env->DeleteLocalRef(key); - env->DeleteLocalRef(val); } + env->DeleteLocalRef(key); + env->DeleteLocalRef(val); } env->DeleteLocalRef(mapClass); @@ -320,19 +332,6 @@ static jobject createJavaMapFromHTTPHeaders(JNIEnv* env, const WebCore::HTTPHead return hashMap; } -// In WebViewCore.java, we artificially append the filename to the URI so that -// webkit treats the actual display name of the file as the filename, rather -// than the last segment of the URI (which will simply be a number). When we -// pass the URI up to BrowserFrame, we no longer need the appended name (in fact -// it causes problems), so remove it here. -// FIXME: If we rewrite pathGetFileName (the current version is in -// FileSystemPOSIX), we can get the filename that way rather than appending it. -static jstring uriFromUriFileName(JNIEnv* env, const WebCore::String& name) -{ - const WebCore::String fileName = name.left(name.reverseFind('/')); - return env->NewString(fileName.characters(), fileName.length()); -} - // 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 @@ -341,7 +340,7 @@ static jstring uriFromUriFileName(JNIEnv* env, const WebCore::String& name) class FileInfo { public: FileInfo(JNIEnv* env, const WebCore::String& name) { - m_uri = uriFromUriFileName(env, name); + m_uri = env->NewString(name.characters(), name.length()); checkException(env); m_size = 0; m_env = env; @@ -722,6 +721,7 @@ WebFrame::didReceiveTouchIconURL(const WebCore::String& url, bool precomposed) env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mDidReceiveTouchIconUrl, jUrlStr, precomposed); + env->DeleteLocalRef(jUrlStr); checkException(env); } @@ -736,6 +736,7 @@ WebFrame::updateVisitedHistory(const WebCore::KURL& url, bool reload) jstring jUrlStr = env->NewString((unsigned short*)urlStr.characters(), urlStr.length()); env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mUpdateVisitedHistory, jUrlStr, reload); + env->DeleteLocalRef(jUrlStr); checkException(env); } @@ -765,6 +766,7 @@ WebFrame::canHandleRequest(const WebCore::ResourceRequest& request) // 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); } @@ -882,7 +884,8 @@ static void CreateFrame(JNIEnv* env, jobject obj, jobject javaview, jobject jAss dragC, inspectorC, 0, // PluginHalterClient - 0); // GeolocationControllerClient + 0, // GeolocationControllerClient + 0); // DeviceOrientationClient // css files without explicit MIMETYPE is treated as generic text files in // the Java side. So we can't enforce CSS MIMETYPE. page->settings()->setEnforceCSSMIMETypeInStrictMode(false); @@ -940,7 +943,7 @@ static void CreateFrame(JNIEnv* env, jobject obj, jobject javaview, jobject jAss WebCore::RenderSkinAndroid::Init(am, directory); } for (int i = WebCore::PlatformBridge::FileUploadLabel; - i <= WebCore::PlatformBridge::SubmitLabel; i++) + i <= WebCore::PlatformBridge::FileUploadNoFileChosenLabel; i++) initGlobalLocalizedName( static_cast<WebCore::PlatformBridge::rawResId>(i), webFrame); } @@ -1096,6 +1099,91 @@ static void StopLoading(JNIEnv *env, jobject obj) 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 jobject 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!"); + + 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 JNI_FALSE; + } + + 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 JNI_FALSE; + } + + RefPtr<WebArchiveAndroid> archive = WebCore::WebArchiveAndroid::create(pFrame); + + bool result = archive->saveWebArchive(writer); + + releaseCharactersForJStringInEnv(env, basename, basenameNative); + xmlFreeTextWriter(writer); + + if (result) { + return env->NewStringUTF(filename.utf8().data()); + } + + return NULL; +#endif +} + static jstring ExternalRepresentation(JNIEnv *env, jobject obj) { #ifdef ANDROID_INSTRUMENT @@ -1112,6 +1200,28 @@ static jstring ExternalRepresentation(JNIEnv *env, jobject obj) return env->NewString(renderDump.characters(), len); } +static WebCore::StringBuilder FrameAsText(WebCore::Frame *pFrame, jboolean dumpChildFrames) { + WebCore::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 @@ -1120,11 +1230,26 @@ static jstring DocumentAsText(JNIEnv *env, jobject obj) WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj); LOG_ASSERT(pFrame, "android_webcore_nativeDocumentAsText must take a valid frame pointer!"); - WebCore::Element *documentElement = pFrame->document()->documentElement(); - if (!documentElement) + WebCore::String renderDump = FrameAsText(pFrame, false /* dumpChildFrames */).toString(); + unsigned len = renderDump.length(); + if (!len) return NULL; - WebCore::String renderDump = ((WebCore::HTMLElement*)documentElement)->innerText(); - renderDump.append("\n"); + return env->NewString((unsigned short*)renderDump.characters(), len); +} + +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!"); + + WebCore::StringBuilder renderDumpBuilder; + for (unsigned i = 0; i < pFrame->tree()->childCount(); ++i) { + renderDumpBuilder.append(FrameAsText(pFrame->tree()->child(i), true /* dumpChildFrames */).toString()); + } + WebCore::String renderDump = renderDumpBuilder.toString(); unsigned len = renderDump.length(); if (!len) return NULL; @@ -1413,8 +1538,8 @@ static jboolean HasPasswordField(JNIEnv *env, jobject obj) // class, but just normal Element class. while (node && !found && !node->namespaceURI().isNull() && !node->namespaceURI().isEmpty()) { - WTF::Vector<WebCore::HTMLFormControlElement*>& elements = - ((WebCore::HTMLFormElement*)node)->formElements; + const WTF::Vector<WebCore::HTMLFormControlElement*>& elements = + ((WebCore::HTMLFormElement*)node)->associatedElements(); size_t size = elements.size(); for (size_t i = 0; i< size && !found; i++) { WebCore::HTMLFormControlElement* e = elements[i]; @@ -1444,8 +1569,8 @@ static jobjectArray GetUsernamePassword(JNIEnv *env, jobject obj) WebCore::Node* node = form->firstItem(); while (node && !found && !node->namespaceURI().isNull() && !node->namespaceURI().isEmpty()) { - WTF::Vector<WebCore::HTMLFormControlElement*>& elements = - ((WebCore::HTMLFormElement*)node)->formElements; + const WTF::Vector<WebCore::HTMLFormControlElement*>& elements = + ((WebCore::HTMLFormElement*)node)->associatedElements(); size_t size = elements.size(); for (size_t i = 0; i< size && !found; i++) { WebCore::HTMLFormControlElement* e = elements[i]; @@ -1455,7 +1580,7 @@ static jobjectArray GetUsernamePassword(JNIEnv *env, jobject obj) continue; if (input->inputType() == WebCore::HTMLInputElement::PASSWORD) password = input->value(); - else if (input->inputType() == WebCore::HTMLInputElement::TEXT) + else if (input->inputType() == WebCore::HTMLInputElement::TEXT || input->inputType() == WebCore::HTMLInputElement::EMAIL) username = input->value(); if (!username.isNull() && !password.isNull()) found = true; @@ -1490,8 +1615,8 @@ static void SetUsernamePassword(JNIEnv *env, jobject obj, WebCore::Node* node = form->firstItem(); while (node && !found && !node->namespaceURI().isNull() && !node->namespaceURI().isEmpty()) { - WTF::Vector<WebCore::HTMLFormControlElement*>& elements = - ((WebCore::HTMLFormElement*)node)->formElements; + const WTF::Vector<WebCore::HTMLFormControlElement*>& elements = + ((WebCore::HTMLFormElement*)node)->associatedElements(); size_t size = elements.size(); for (size_t i = 0; i< size && !found; i++) { WebCore::HTMLFormControlElement* e = elements[i]; @@ -1501,7 +1626,7 @@ static void SetUsernamePassword(JNIEnv *env, jobject obj, continue; if (input->inputType() == WebCore::HTMLInputElement::PASSWORD) passwordEle = input; - else if (input->inputType() == WebCore::HTMLInputElement::TEXT) + else if (input->inputType() == WebCore::HTMLInputElement::TEXT || input->inputType() == WebCore::HTMLInputElement::EMAIL) usernameEle = input; if (usernameEle != NULL && passwordEle != NULL) found = true; @@ -1543,7 +1668,7 @@ static jobject GetFormTextData(JNIEnv *env, jobject obj) node = collection->nextItem()) { form = static_cast<WebCore::HTMLFormElement*>(node); if (form->autoComplete()) { - WTF::Vector<WebCore::HTMLFormControlElement*> elements = form->formElements; + WTF::Vector<WebCore::HTMLFormControlElement*> elements = form->associatedElements(); size_t size = elements.size(); for (size_t i = 0; i < size; i++) { WebCore::HTMLFormControlElement* e = elements[i]; @@ -1604,10 +1729,14 @@ static JNINativeMethod gBrowserFrameNativeMethods[] = { (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", diff --git a/WebKit/android/jni/WebCoreJniOnLoad.cpp b/WebKit/android/jni/WebCoreJniOnLoad.cpp index b5bf9dd..1a3c676 100644 --- a/WebKit/android/jni/WebCoreJniOnLoad.cpp +++ b/WebKit/android/jni/WebCoreJniOnLoad.cpp @@ -82,7 +82,8 @@ extern int register_webstorage(JNIEnv*); extern int register_geolocation_permissions(JNIEnv*); extern int register_mock_geolocation(JNIEnv*); #if ENABLE(VIDEO) -extern int register_mediaplayer(JNIEnv*); +extern int register_mediaplayer_audio(JNIEnv*); +extern int register_mediaplayer_video(JNIEnv*); #endif } @@ -107,7 +108,8 @@ static RegistrationMethod gWebCoreRegMethods[] = { { "GeolocationPermissions", android::register_geolocation_permissions }, { "MockGeolocation", android::register_mock_geolocation }, #if ENABLE(VIDEO) - { "HTML5VideoViewProxy", android::register_mediaplayer }, + { "HTML5Audio", android::register_mediaplayer_audio }, + { "HTML5VideoViewProxy", android::register_mediaplayer_video }, #endif }; @@ -192,7 +194,8 @@ EXPORT void benchmark(const char* url, int reloadCount, int width, int height) { new DragClientAndroid, new InspectorClientAndroid, 0, // PluginHalterClient - 0); // GeolocationControllerClient + 0, // GeolocationControllerClient + 0); // DeviceOrientationClient editor->setPage(page); // Create MyWebFrame that intercepts network requests diff --git a/WebKit/android/jni/WebCoreResourceLoader.cpp b/WebKit/android/jni/WebCoreResourceLoader.cpp index 297ecb0..32e8cd8 100644 --- a/WebKit/android/jni/WebCoreResourceLoader.cpp +++ b/WebKit/android/jni/WebCoreResourceLoader.cpp @@ -28,7 +28,6 @@ #include "config.h" #include "WebCoreResourceLoader.h" -#include "CString.h" #include "ResourceError.h" #include "ResourceHandle.h" #include "ResourceHandleClient.h" @@ -46,6 +45,7 @@ #include <stdlib.h> #include <utils/misc.h> #include <wtf/Platform.h> +#include <wtf/text/CString.h> namespace android { diff --git a/WebKit/android/jni/WebCoreViewBridge.h b/WebKit/android/jni/WebCoreViewBridge.h index 61990af..59e1c9a 100644 --- a/WebKit/android/jni/WebCoreViewBridge.h +++ b/WebKit/android/jni/WebCoreViewBridge.h @@ -38,20 +38,22 @@ namespace WebCore class WebCoreViewBridge : public WebCoreRefObject { public: - WebCoreViewBridge() : - mBounds(0,0,0,0), - m_windowBounds(0,0,0,0) - {} - virtual ~WebCoreViewBridge() {} + WebCoreViewBridge() { } + virtual ~WebCoreViewBridge() { } virtual void draw(WebCore::GraphicsContext* ctx, const WebCore::IntRect& rect) = 0; const WebCore::IntRect& getBounds() const { - return mBounds; + return m_bounds; } - + + const WebCore::IntRect& getVisibleBounds() const + { + return m_visibleBounds; + } + const WebCore::IntRect& getWindowBounds() const { return m_windowBounds; @@ -59,14 +61,22 @@ public: void setSize(int w, int h) { - mBounds.setWidth(w); - mBounds.setHeight(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) { - mBounds.setX(x); - mBounds.setY(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) @@ -74,17 +84,23 @@ public: m_windowBounds = WebCore::IntRect(x, y, h, v); } - int width() const { return mBounds.width(); } - int height() const { return mBounds.height(); } - int locX() const { return mBounds.x(); } - int locY() const { return mBounds.y(); } + 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 mBounds; + WebCore::IntRect m_bounds; WebCore::IntRect m_windowBounds; + WebCore::IntRect m_visibleBounds; }; #endif // WEBCORE_VIEW_BRIDGE_H diff --git a/WebKit/android/jni/WebHistory.cpp b/WebKit/android/jni/WebHistory.cpp index d518ba8..37a4d1d 100644 --- a/WebKit/android/jni/WebHistory.cpp +++ b/WebKit/android/jni/WebHistory.cpp @@ -29,7 +29,6 @@ #include "WebHistory.h" #include "BackForwardList.h" -#include "CString.h" #include "DocumentLoader.h" #include "Frame.h" #include "FrameLoader.h" @@ -49,6 +48,7 @@ #include <utils/misc.h> #include <wtf/OwnPtr.h> #include <wtf/Platform.h> +#include <wtf/text/CString.h> namespace android { @@ -419,9 +419,9 @@ static void write_item(WTF::Vector<char>& v, WebCore::HistoryItem* item) const int scale = bridge->scale(); LOGV("Writing scale %d", scale); v.append((char*)&scale, sizeof(int)); - const int screenWidthScale = bridge->screenWidthScale(); - LOGV("Writing screen width scale %d", screenWidthScale); - v.append((char*)&screenWidthScale, sizeof(int)); + const int textWrapScale = bridge->textWrapScale(); + LOGV("Writing text wrap scale %d", textWrapScale); + v.append((char*)&textWrapScale, sizeof(int)); // Document state const WTF::Vector<WebCore::String>& docState = item->documentState(); @@ -603,8 +603,8 @@ static bool read_item_recursive(WebCore::HistoryItem* newItem, bridge->setScale(l); data += sizeofUnsigned; memcpy(&l, data, sizeofUnsigned); - LOGV("Screen width scale %d", l); - bridge->setScreenWidthScale(l); + LOGV("Text wrap scale %d", l); + bridge->setTextWrapScale(l); data += sizeofUnsigned; if (end - data < sizeofUnsigned) diff --git a/WebKit/android/jni/WebHistory.h b/WebKit/android/jni/WebHistory.h index 12bf00a..2d86aa4 100644 --- a/WebKit/android/jni/WebHistory.h +++ b/WebKit/android/jni/WebHistory.h @@ -44,9 +44,9 @@ public: static void UpdateHistoryIndex(const AutoJObject&, int); }; -// there are two scale factors saved with each history item. mScale reflects the -// viewport scale factor, default to 100 means 100%. mScreenWidthScale records -// the scale factor for the screen width used to wrap the text paragraph. +// 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) diff --git a/WebKit/android/jni/WebIconDatabase.cpp b/WebKit/android/jni/WebIconDatabase.cpp index 840d161..6a20f6f 100644 --- a/WebKit/android/jni/WebIconDatabase.cpp +++ b/WebKit/android/jni/WebIconDatabase.cpp @@ -38,6 +38,7 @@ #include <JNIHelp.h> #include <JNIUtility.h> +#include <SharedBuffer.h> #include <SkBitmap.h> #include <SkImageDecoder.h> #include <SkTemplates.h> diff --git a/WebKit/android/jni/WebSettings.cpp b/WebKit/android/jni/WebSettings.cpp index 70ecded..d9a7cf0 100644 --- a/WebKit/android/jni/WebSettings.cpp +++ b/WebKit/android/jni/WebSettings.cpp @@ -29,7 +29,9 @@ #include <wtf/Platform.h> #include "ApplicationCacheStorage.h" +#include "BitmapAllocatorAndroid.h" #include "DatabaseTracker.h" +#include "Database.h" #include "DocLoader.h" #include "Document.h" #include "Frame.h" @@ -107,11 +109,13 @@ struct FieldIds { #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"); mUseDoubleTree = env->GetFieldID(clazz, "mUseDoubleTree", "Z"); mPageCacheCapacity = env->GetFieldID(clazz, "mPageCacheCapacity", "I"); @@ -148,6 +152,7 @@ struct FieldIds { 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"); @@ -193,6 +198,7 @@ struct FieldIds { jfieldID mUseWideViewport; jfieldID mSupportMultipleWindows; jfieldID mShrinksStandaloneImagesToFit; + jfieldID mMaximumDecodedImageSize; jfieldID mUseDoubleTree; jfieldID mPageCacheCapacity; // Ordinal() method and value field for enums @@ -207,6 +213,7 @@ struct FieldIds { #endif jfieldID mGeolocationEnabled; jfieldID mGeolocationDatabasePath; + jfieldID mXSSAuditorEnabled; #if ENABLE(DATABASE) || ENABLE(DOM_STORAGE) jfieldID mDatabasePath; jfieldID mDatabasePathHasBeenSet; @@ -260,8 +267,8 @@ public: #endif jobject textSize = env->GetObjectField(obj, gFieldIds->mTextSize); float zoomFactor = env->GetIntField(textSize, gFieldIds->mTextSizeValue) / 100.0f; - if (pFrame->zoomFactor() != zoomFactor) - pFrame->setZoomFactor(zoomFactor, /*isTextOnly*/true); + if (pFrame->view()->zoomFactor() != zoomFactor) + pFrame->view()->setZoomFactor(zoomFactor, WebCore::ZoomTextOnly); jstring str = (jstring)env->GetObjectField(obj, gFieldIds->mStandardFontFamily); s->setStandardFontFamily(to_string(env, str)); @@ -352,9 +359,13 @@ public: #endif flag = env->GetBooleanField(obj, gFieldIds->mShrinksStandaloneImagesToFit); s->setShrinksStandaloneImagesToFit(flag); + jlong maxImage = env->GetIntField(obj, gFieldIds->mMaximumDecodedImageSize); + if (maxImage == 0) + maxImage = computeMaxBitmapSizeForCache(); + s->setMaximumDecodedImageSize(maxImage); #if ENABLE(DATABASE) flag = env->GetBooleanField(obj, gFieldIds->mDatabaseEnabled); - s->setDatabasesEnabled(flag); + WebCore::Database::setIsAvailable(flag); flag = env->GetBooleanField(obj, gFieldIds->mDatabasePathHasBeenSet); if (flag) { @@ -384,6 +395,9 @@ public: WebCore::GeolocationPositionCache::setDatabasePath(to_string(env,str)); } + flag = env->GetBooleanField(obj, gFieldIds->mXSSAuditorEnabled); + s->setXSSAuditorEnabled(flag); + size = env->GetIntField(obj, gFieldIds->mPageCacheCapacity); if (size > 0) { s->setUsesPageCache(true); diff --git a/WebKit/android/jni/WebViewCore.cpp b/WebKit/android/jni/WebViewCore.cpp index 1562775..d3e32d3 100644 --- a/WebKit/android/jni/WebViewCore.cpp +++ b/WebKit/android/jni/WebViewCore.cpp @@ -29,6 +29,7 @@ #include "WebViewCore.h" #include "AtomicString.h" +#include "BaseLayerAndroid.h" #include "CachedNode.h" #include "CachedRoot.h" #include "Chrome.h" @@ -37,6 +38,7 @@ #include "DatabaseTracker.h" #include "Document.h" #include "DOMWindow.h" +#include "DOMSelection.h" #include "Element.h" #include "Editor.h" #include "EditorClientAndroid.h" @@ -65,9 +67,9 @@ #include "HTMLSelectElement.h" #include "HTMLTextAreaElement.h" #include "HistoryItem.h" +#include "HitTestRequest.h" #include "HitTestResult.h" #include "InlineTextBox.h" -#include "KeyboardCodes.h" #include "Navigator.h" #include "Node.h" #include "NodeList.h" @@ -79,7 +81,9 @@ #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" @@ -101,6 +105,7 @@ #include "TypingCommand.h" #include "WebCoreFrameBridge.h" #include "WebFrameView.h" +#include "WindowsKeyboardCodes.h" #include "android_graphics.h" #include <JNIHelp.h> @@ -109,9 +114,9 @@ #include <wtf/CurrentTime.h> #if USE(V8) -#include "CString.h" #include "ScriptController.h" #include "V8Counters.h" +#include <wtf/text/CString.h> #endif #if DEBUG_NAV_UI @@ -125,7 +130,7 @@ #ifdef ANDROID_DOM_LOGGING #include "AndroidLog.h" #include "RenderTreeAsText.h" -#include "CString.h" +#include <wtf/text/CString.h> FILE* gDomTreeFile = 0; FILE* gRenderTreeFile = 0; @@ -226,13 +231,10 @@ struct WebViewCore::JavaGlue { jmethodID m_updateViewport; jmethodID m_sendNotifyProgressFinished; jmethodID m_sendViewInvalidate; - jmethodID m_sendImmediateRepaint; - jmethodID m_setRootLayer; jmethodID m_updateTextfield; jmethodID m_updateTextSelection; jmethodID m_clearTextEntry; jmethodID m_restoreScale; - jmethodID m_restoreScreenWidthScale; jmethodID m_needTouchEvents; jmethodID m_requestKeyboard; jmethodID m_requestKeyboardWithSelection; @@ -253,6 +255,7 @@ struct WebViewCore::JavaGlue { jmethodID m_showRect; jmethodID m_centerFitRect; jmethodID m_setScrollbarModes; + jmethodID m_setInstallableWebApp; AutoJObject object(JNIEnv* env) { return getRealObject(env, m_obj); } @@ -272,7 +275,6 @@ static jmethodID GetJMethod(JNIEnv* env, jclass clazz, const char name[], const Mutex WebViewCore::gFrameCacheMutex; Mutex WebViewCore::gButtonMutex; Mutex WebViewCore::gCursorBoundsMutex; -Mutex WebViewCore::m_contentMutex; WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* mainframe) : m_pluginInvalTimer(this, &WebViewCore::pluginInvalTimerFired) @@ -289,8 +291,8 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m m_maxYScroll = 240/4; m_textGeneration = 0; m_screenWidth = 320; + m_textWrapWidth = 320; m_scale = 1; - m_screenWidthScale = 1; #if ENABLE(TOUCH_EVENTS) m_forwardingTouchEvents = false; #endif @@ -306,7 +308,7 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m m_javaGlue->m_scrollBy = GetJMethod(env, clazz, "contentScrollBy", "(IIZ)V"); m_javaGlue->m_contentDraw = GetJMethod(env, clazz, "contentDraw", "()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;"); + 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"); @@ -317,13 +319,10 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m 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_sendImmediateRepaint = GetJMethod(env, clazz, "sendImmediateRepaint", "()V"); - m_javaGlue->m_setRootLayer = GetJMethod(env, clazz, "setRootLayer", "(I)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", "(I)V"); - m_javaGlue->m_restoreScreenWidthScale = GetJMethod(env, clazz, "restoreScreenWidthScale", "(I)V"); + m_javaGlue->m_restoreScale = GetJMethod(env, clazz, "restoreScale", "(II)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"); @@ -344,6 +343,7 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m 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"); env->SetIntField(javaWebViewCore, gWebViewCoreFields.m_nativeClass, (jint)this); @@ -485,7 +485,8 @@ void WebViewCore::recordPicture(SkPicture* picture) WebCore::PlatformGraphicsContext pgc(arp.getRecordingCanvas(), &buttons); WebCore::GraphicsContext gc(&pgc); - view->platformWidget()->draw(&gc, WebCore::IntRect(0, 0, INT_MAX, INT_MAX)); + view->platformWidget()->draw(&gc, WebCore::IntRect(0, 0, + view->contentsWidth(), view->contentsHeight())); gButtonMutex.lock(); updateButtonList(&buttons); @@ -589,6 +590,9 @@ void WebViewCore::recordPictureSet(PictureSet* content) height = view->contentsHeight(); } + if (cacheBuilder().pictureSetDisabled()) + content->clear(); + content->checkDimensions(width, height, &m_addInval); // The inval region may replace existing pictures. The existing pictures @@ -741,50 +745,11 @@ void WebViewCore::updateCursorBounds(const CachedRoot* root, void WebViewCore::clearContent() { DBG_SET_LOG(""); - m_contentMutex.lock(); m_content.clear(); - m_contentMutex.unlock(); m_addInval.setEmpty(); m_rebuildInval.setEmpty(); } -void WebViewCore::copyContentToPicture(SkPicture* picture) -{ - DBG_SET_LOG("start"); - m_contentMutex.lock(); - PictureSet copyContent = PictureSet(m_content); - m_contentMutex.unlock(); - - int w = copyContent.width(); - int h = copyContent.height(); - copyContent.draw(picture->beginRecording(w, h, PICT_RECORD_FLAGS)); - picture->endRecording(); - DBG_SET_LOG("end"); -} - -bool WebViewCore::drawContent(SkCanvas* canvas, SkColor color) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewUIDrawTimeCounter); -#endif - DBG_SET_LOG("start"); - m_contentMutex.lock(); - PictureSet copyContent = PictureSet(m_content); - m_contentMutex.unlock(); - int sc = canvas->save(SkCanvas::kClip_SaveFlag); - SkRect clip; - clip.set(0, 0, copyContent.width(), copyContent.height()); - canvas->clipRect(clip, SkRegion::kDifference_Op); - canvas->drawColor(color); - canvas->restoreToCount(sc); - bool tookTooLong = copyContent.draw(canvas); - m_contentMutex.lock(); - m_content.setDrawTimes(copyContent); - m_contentMutex.unlock(); - DBG_SET_LOG("end"); - return tookTooLong; -} - bool WebViewCore::focusBoundsChanged() { bool result = m_focusBoundsChanged; @@ -792,18 +757,6 @@ bool WebViewCore::focusBoundsChanged() return result; } -bool WebViewCore::pictureReady() -{ - bool done; - m_contentMutex.lock(); - PictureSet copyContent = PictureSet(m_content); - done = m_progressDone; - m_contentMutex.unlock(); - DBG_NAV_LOGD("done=%s empty=%s", done ? "true" : "false", - copyContent.isEmpty() ? "true" : "false"); - return done || !copyContent.isEmpty(); -} - SkPicture* WebViewCore::rebuildPicture(const SkIRect& inval) { WebCore::FrameView* view = m_mainFrame->view(); @@ -851,48 +804,52 @@ void WebViewCore::rebuildPictureSet(PictureSet* pictureSet) pictureSet->validate(__FUNCTION__); } -bool WebViewCore::recordContent(SkRegion* region, SkIPoint* point) +BaseLayerAndroid* WebViewCore::recordContent(SkRegion* region, SkIPoint* point) { DBG_SET_LOG("start"); float progress = (float) m_mainFrame->page()->progress()->estimatedProgress(); - m_contentMutex.lock(); - PictureSet contentCopy(m_content); m_progressDone = progress <= 0.0f || progress >= 1.0f; - m_contentMutex.unlock(); - recordPictureSet(&contentCopy); - if (!m_progressDone && contentCopy.isEmpty()) { + recordPictureSet(&m_content); + if (!m_progressDone && m_content.isEmpty()) { DBG_SET_LOGD("empty (progress=%g)", progress); - return false; + return 0; } region->set(m_addInval); m_addInval.setEmpty(); region->op(m_rebuildInval, SkRegion::kUnion_Op); m_rebuildInval.setEmpty(); - m_contentMutex.lock(); - contentCopy.setDrawTimes(m_content); - m_content.set(contentCopy); point->fX = m_content.width(); point->fY = m_content.height(); - m_contentMutex.unlock(); 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 true; + + BaseLayerAndroid* base = new BaseLayerAndroid(); + base->setContent(m_content); + +#if USE(ACCELERATED_COMPOSITING) + // We update the layers + ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(m_mainFrame->page()->chrome()->client()); + GraphicsLayerAndroid* root = static_cast<GraphicsLayerAndroid*>(chromeC->layersSync()); + if (root) { + root->notifyClientAnimationStarted(); + LayerAndroid* copyLayer = new LayerAndroid(*root->contentLayer()); + base->addChild(copyLayer); + copyLayer->unref(); + } +#endif + + return base; } -void WebViewCore::splitContent() +void WebViewCore::splitContent(PictureSet* content) { bool layoutSuceeded = layoutIfNeededRecursive(m_mainFrame); LOG_ASSERT(layoutSuceeded, "Can never be called recursively"); - PictureSet tempPictureSet; - m_contentMutex.lock(); - m_content.split(&tempPictureSet); - m_contentMutex.unlock(); - rebuildPictureSet(&tempPictureSet); - m_contentMutex.lock(); - m_content.set(tempPictureSet); - m_contentMutex.unlock(); + content->split(&m_content); + rebuildPictureSet(&m_content); + content->set(m_content); } void WebViewCore::scrollTo(int x, int y, bool animate) @@ -936,28 +893,6 @@ void WebViewCore::scrollBy(int dx, int dy, bool animate) checkException(env); } -#if USE(ACCELERATED_COMPOSITING) - -void WebViewCore::immediateRepaint() -{ - 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_sendImmediateRepaint); - checkException(env); -} - -void WebViewCore::setUIRootLayer(const LayerAndroid* layer) -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), - m_javaGlue->m_setRootLayer, - reinterpret_cast<jint>(layer)); - checkException(env); -} - -#endif // USE(ACCELERATED_COMPOSITING) - void WebViewCore::contentDraw() { JNIEnv* env = JSC::Bindings::getJNIEnv(); @@ -1034,24 +969,13 @@ void WebViewCore::updateViewport() checkException(env); } -void WebViewCore::restoreScale(int scale) +void WebViewCore::restoreScale(int scale, int 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); - checkException(env); -} - -void WebViewCore::restoreScreenWidthScale(int scale) -{ - 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_restoreScreenWidthScale, scale); + env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_restoreScale, scale, textWrapScale); checkException(env); } @@ -1162,42 +1086,45 @@ void WebViewCore::setGlobalBounds(int x, int y, int h, int v) } void WebViewCore::setSizeScreenWidthAndScale(int width, int height, - int screenWidth, float scale, int realScreenWidth, int screenHeight, + 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(); 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); + } int osw = m_screenWidth; - int orsw = m_screenWidth * m_screenWidthScale / m_scale; int osh = m_screenHeight; + int otw = m_textWrapWidth; 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; - if (scale >= 0) { // negative means ignore + m_textWrapWidth = textWrapWidth; + if (scale >= 0) // negative means keep the current scale m_scale = scale; - if (screenWidth != realScreenWidth) - m_screenWidthScale = realScreenWidth * scale / screenWidth; - else - m_screenWidthScale = m_scale; - } m_maxXScroll = screenWidth >> 2; - m_maxYScroll = (screenWidth * height / width) >> 2; - if (ow != width || (!ignoreHeight && oh != height) || osw != screenWidth) { + m_maxYScroll = m_maxXScroll * height / width; + if (ow != width || (!ignoreHeight && oh != height) || otw != textWrapWidth) { WebCore::RenderObject *r = m_mainFrame->contentRenderer(); DBG_NAV_LOGD("renderer=%p view=(w=%d,h=%d)", r, - realScreenWidth, screenHeight); + screenWidth, screenHeight); if (r) { WebCore::IntPoint anchorPoint = WebCore::IntPoint(anchorX, anchorY); DBG_NAV_LOGD("anchorX=%d anchorY=%d", anchorX, anchorY); - WebCore::Node* node = 0; + RefPtr<WebCore::Node> node; WebCore::IntRect bounds; WebCore::IntPoint offset; - // If the screen width changed, it is probably zoom change or + // If the text wrap changed, it is probably zoom change or // orientation change. Try to keep the anchor at the same place. - if (osw && screenWidth && osw != screenWidth) { + if (otw && textWrapWidth && otw != textWrapWidth) { WebCore::HitTestResult hitTestResult = m_mainFrame->eventHandler()-> hitTestResultAtPoint( anchorPoint, false); @@ -1227,19 +1154,19 @@ void WebViewCore::setSizeScreenWidthAndScale(int width, int height, DBG_NAV_LOGD("nb:(x=%d,y=%d,w=%d," "h=%d)", newBounds.x(), newBounds.y(), newBounds.width(), newBounds.height()); - if ((orsw && osh && bounds.width() && bounds.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 = (osw != m_screenWidth) + 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) / orsw; + 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(), @@ -1272,7 +1199,7 @@ void WebViewCore::dumpDomTree(bool useFile) void WebViewCore::dumpRenderTree(bool useFile) { #ifdef ANDROID_DOM_LOGGING - WebCore::CString renderDump = WebCore::externalRepresentation(m_mainFrame).utf8(); + WTF::CString renderDump = WebCore::externalRepresentation(m_mainFrame).utf8(); const char* data = renderDump.data(); if (useFile) { gRenderTreeFile = fopen(RENDER_TREE_LOG_FILE, "w"); @@ -1331,7 +1258,7 @@ WebCore::String WebViewCore::requestLabel(WebCore::Frame* frame, for (unsigned i = 0; i < length; i++) { WebCore::HTMLLabelElement* label = static_cast<WebCore::HTMLLabelElement*>( list->item(i)); - if (label->correspondingControl() == node) { + if (label->control() == node) { Node* node = label; String result; while ((node = node->traverseNextNode(label))) { @@ -1437,6 +1364,252 @@ void WebViewCore::updateFrameCacheIfLoading() 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)->linesVisibleOverflowBoundingBox(); + 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<IntRect> WebViewCore::getTouchHighlightRects(int x, int y, int slop) +{ + Vector<IntRect> rects; + m_mousePos = IntPoint(x - m_scrollOffsetX, y - m_scrollOffsetY); +#ifdef ANDROID_HITTEST_WITHSIZE + HitTestResult hitTestResult = m_mainFrame->eventHandler()->hitTestResultAtPoint(IntPoint(x, y), + false, false, DontHitTestScrollbars, IntSize(slop, slop)); + if (!hitTestResult.innerNode() || !hitTestResult.innerNode()->inDocument()) { + LOGE("Should not happen: no in document Node found"); + return rects; + } + const Vector<RefPtr<Node> >& list = hitTestResult.rawNodeList(); + if (list.isEmpty()) { + LOGE("Should not happen: no raw node found"); + return rects; + } + Frame* frame = hitTestResult.innerNode()->document()->frame(); + Vector<TouchNodeData> nodeDataList; + Vector<RefPtr<Node> >::const_iterator last = list.end(); + for (Vector<RefPtr<Node> >::const_iterator it = list.begin(); it != last; ++it) { + // TODO: it seems reasonable to not search across the frame. Isn't it? + // if the node is not in the same frame as the innerNode, skip it + if (it->get()->document()->frame() != frame) + continue; + // traverse up the tree to find the first node that needs highlight + bool found = false; + Node* eventNode = it->get(); + while (eventNode) { + RenderObject* render = eventNode->renderer(); + if (render->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 rawNodeList() 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<TouchNodeData>::const_iterator nlast = nodeDataList.end(); + for (Vector<TouchNodeData>::const_iterator n = nodeDataList.begin(); n != nlast; ++n) { + // found the same node, skip it + if (eventNode == n->mNode) { + found = false; + break; + } + } + 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<const ContainerNode*>(eventNode)->firstChild(); + while (child) { + IntRect childrect; + if (child->renderer()) + childrect = getAbsoluteBoundingBox(child); + if (!childrect.isEmpty()) { + rect.unite(childrect); + child = child->traverseNextSibling(eventNode); + } else + child = child->traverseNextNode(eventNode); + } + } + for (int i = nodeDataList.size() - 1; i >= 0; i--) { + TouchNodeData n = nodeDataList.at(i); + // the new node is enclosing an existing node, skip it + if (rect.contains(n.mBounds)) { + found = true; + break; + } + // the new node is fully inside an existing node, remove the existing node + if (n.mBounds.contains(rect)) + nodeDataList.remove(i); + } + if (!found) { + TouchNodeData newNode; + newNode.mNode = eventNode; + newNode.mBounds = rect; + nodeDataList.append(newNode); + } + } + 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<TouchNodeData>::const_iterator nlast = nodeDataList.end(); + for (Vector<TouchNodeData>::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); + } + } +#endif + return rects; +} + /////////////////////////////////////////////////////////////////////////////// void WebViewCore::addPlugin(PluginWidgetAndroid* w) @@ -1675,6 +1848,51 @@ void WebViewCore::setSelection(int start, int end) setFocusControllerActive(focusedFrame, true); } +String WebViewCore::modifySelection(const String& alter, const String& direction, const String& granularity) +{ + DOMSelection* selection = m_mainFrame->domWindow()->getSelection(); + + if (selection->rangeCount() == 0) { + Document* document = m_mainFrame->document(); + HTMLElement* body = document->body(); + ExceptionCode ec; + + PassRefPtr<Range> rangeRef = document->createRange(); + rangeRef->setStart(PassRefPtr<Node>(body), 0, ec); + if (ec) { + LOGE("Error setting range start. Error code: %d", ec); + return String(); + } + + rangeRef->setEnd(PassRefPtr<Node>(body), 0, ec); + if (ec) { + LOGE("Error setting range end. Error code: %d", ec); + return String(); + } + + selection->addRange(rangeRef.get()); + } + + if (equalIgnoringCase(direction, "forward")) { + selection->collapseToEnd(); + } else if (equalIgnoringCase(direction, "backward")) { + selection->collapseToStart(); + } else { + LOGE("Invalid direction: %s", direction.utf8().data()); + return String(); + } + + // NOTE: The selection of WebKit misbehaves and I need to add some + // voodoo here to force it behave well. Rachel did something similar + // in JS and I want to make sure it is optimal before adding it here. + + selection->modify(alter, direction, granularity); + String selection_string = selection->toString(); + LOGD("Selection string: %s", selection_string.utf8().data()); + + return selection_string; +} + void WebViewCore::deleteSelection(int start, int end, int textGeneration) { setSelection(start, end); @@ -1918,15 +2136,24 @@ void WebViewCore::openFileChooser(PassRefPtr<WebCore::FileChooser> chooser) { if (!chooser) return; JNIEnv* env = JSC::Bindings::getJNIEnv(); + + WebCore::String acceptType = chooser->acceptTypes(); + jstring jAcceptType = env->NewString(const_cast<unsigned short*>(acceptType.characters()), acceptType.length()); jstring jName = (jstring) env->CallObjectMethod( - m_javaGlue->object(env).get(), m_javaGlue->m_openFileChooser); + m_javaGlue->object(env).get(), m_javaGlue->m_openFileChooser, jAcceptType); checkException(env); - const UChar* string = (const UChar*) env->GetStringChars(jName, NULL); + env->DeleteLocalRef(jAcceptType); + + const UChar* string = static_cast<const UChar*>(env->GetStringChars(jName, NULL)); + if (!string) return; + WebCore::String webcoreString = to_string(env, jName); env->ReleaseStringChars(jName, string); - chooser->chooseFile(webcoreString); + + if (webcoreString.length()) + chooser->chooseFile(webcoreString); } void WebViewCore::listBoxRequest(WebCoreReply* reply, const uint16_t** labels, size_t count, const int enabled[], size_t enabledCount, @@ -1985,12 +2212,25 @@ void WebViewCore::listBoxRequest(WebCoreReply* reply, const uint16_t** labels, s bool WebViewCore::key(const PlatformKeyboardEvent& event) { - WebCore::EventHandler* eventHandler = m_mainFrame->eventHandler(); + WebCore::EventHandler* eventHandler; WebCore::Node* focusNode = currentFocus(); - if (focusNode) - eventHandler = focusNode->document()->frame()->eventHandler(); DBG_NAV_LOGD("keyCode=%s unichar=%d focusNode=%p", event.keyIdentifier().utf8().data(), event.unichar(), focusNode); + if (focusNode) { + WebCore::Frame* frame = focusNode->document()->frame(); + eventHandler = frame->eventHandler(); + if (focusNode->isContentEditable()) { + // 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. + VisibleSelection old = frame->selection()->selection(); + eventHandler->keyEvent(event); + return frame->selection()->selection() != old; + } + } else { + eventHandler = m_mainFrame->eventHandler(); + } return eventHandler->keyEvent(event); } @@ -2075,14 +2315,6 @@ bool WebViewCore::handleTouchEvent(int action, int x, int y, int metaState) // Track previous touch and if stationary set the state. WebCore::IntPoint pt(x - m_scrollOffsetX, y - m_scrollOffsetY); -// handleTouchEvent() in EventHandler.cpp doesn't handle TouchStationary, which -// causes preventDefault be false when it returns. As our Java side may continue -// process the events if WebKit doesn't, it can cause unexpected result. -// if (type == WebCore::TouchMove && pt == m_lastTouchPoint) -// touchState = WebCore::PlatformTouchPoint::TouchStationary; - - m_lastTouchPoint = pt; - WebCore::PlatformTouchEvent te(pt, type, touchState, metaState); preventDefault = m_mainFrame->eventHandler()->handleTouchEvent(te); #endif @@ -2097,6 +2329,16 @@ bool WebViewCore::handleTouchEvent(int action, int x, int y, int metaState) 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); @@ -2106,6 +2348,7 @@ void WebViewCore::touchUp(int touchGeneration, // 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(); } @@ -2203,6 +2446,9 @@ bool WebViewCore::handleMouseClick(WebCore::Frame* framePtr, WebCore::Node* node } else { requestKeyboard(false); } + } else if (focusNode->isContentEditable()) { + setFocusControllerActive(framePtr, true); + requestKeyboard(true); } } return handled; @@ -2542,6 +2788,13 @@ void WebViewCore::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode checkException(env); } +void WebViewCore::notifyWebAppCanBeInstalled() +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_setInstallableWebApp); + checkException(env); +} + //---------------------------------------------------------------------- // Native JNI methods //---------------------------------------------------------------------- @@ -2568,7 +2821,7 @@ static void UpdateFrameCacheIfLoading(JNIEnv *env, jobject obj) } static void SetSize(JNIEnv *env, jobject obj, jint width, jint height, - jint screenWidth, jfloat scale, jint realScreenWidth, jint screenHeight, + jint textWrapWidth, jfloat scale, jint screenWidth, jint screenHeight, jint anchorX, jint anchorY, jboolean ignoreHeight) { #ifdef ANDROID_INSTRUMENT @@ -2577,8 +2830,8 @@ static void SetSize(JNIEnv *env, jobject obj, jint width, jint height, 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, screenWidth, scale, - realScreenWidth, screenHeight, anchorX, anchorY, ignoreHeight); + viewImpl->setSizeScreenWidthAndScale(width, height, textWrapWidth, scale, + screenWidth, screenHeight, anchorX, anchorY, ignoreHeight); } static void SetScrollOffset(JNIEnv *env, jobject obj, jint gen, jint x, jint y) @@ -2646,6 +2899,22 @@ static void SetSelection(JNIEnv *env, jobject obj, jint start, jint end) viewImpl->setSelection(start, end); } +static jstring ModifySelection(JNIEnv *env, jobject obj, jstring alter, jstring direction, jstring granularity) +{ +#ifdef ANDROID_INSTRUMENT + TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); +#endif + String alterString = to_string(env, alter); + String directionString = to_string(env, direction); + String granularityString = to_string(env, granularity); + + WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); + String selection_string = viewImpl->modifySelection(alterString, + directionString, + granularityString); + + return WebCoreStringToJString(env, selection_string); +} static void ReplaceTextfieldText(JNIEnv *env, jobject obj, jint oldStart, jint oldEnd, jstring replace, jint start, jint end, @@ -2710,7 +2979,7 @@ void WebViewCore::addVisitedLink(const UChar* string, int length) m_groupForVisitedLinks->addVisitedLink(string, length); } -static bool RecordContent(JNIEnv *env, jobject obj, jobject region, jobject pt) +static jint RecordContent(JNIEnv *env, jobject obj, jobject region, jobject pt) { #ifdef ANDROID_INSTRUMENT TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); @@ -2718,18 +2987,18 @@ static bool RecordContent(JNIEnv *env, jobject obj, jobject region, jobject pt) WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); SkRegion* nativeRegion = GraphicsJNI::getNativeRegion(env, region); SkIPoint nativePt; - bool result = viewImpl->recordContent(nativeRegion, &nativePt); + BaseLayerAndroid* result = viewImpl->recordContent(nativeRegion, &nativePt); GraphicsJNI::ipoint_to_jpoint(nativePt, env, pt); - return result; + return reinterpret_cast<jint>(result); } -static void SplitContent(JNIEnv *env, jobject obj) +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(); + viewImpl->splitContent(reinterpret_cast<PictureSet*>(content)); } static void SendListBoxChoice(JNIEnv* env, jobject obj, jint choice) @@ -2981,7 +3250,7 @@ static void SetJsFlags(JNIEnv *env, jobject obj, jstring flags) { #if USE(V8) WebCore::String flagsString = to_string(env, flags); - WebCore::CString utf8String = flagsString.utf8(); + WTF::CString utf8String = flagsString.utf8(); WebCore::ScriptController::setFlags(utf8String.data(), utf8String.length()); #endif } @@ -3018,45 +3287,11 @@ static void RegisterURLSchemeAsLocal(JNIEnv* env, jobject obj, jstring scheme) { WebCore::SecurityOrigin::registerURLSchemeAsLocal(to_string(env, scheme)); } -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 CopyContentToPicture(JNIEnv *env, jobject obj, jobject pict) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - if (!viewImpl) - return; - SkPicture* picture = GraphicsJNI::getNativePicture(env, pict); - viewImpl->copyContentToPicture(picture); -} - -static bool DrawContent(JNIEnv *env, jobject obj, jobject canv, jint color) -{ - // Note: this is called from UI thread, don't count it for WebViewCoreTimeCounter - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv); - return viewImpl->drawContent(canvas, color); -} - static bool FocusBoundsChanged(JNIEnv* env, jobject obj) { return GET_NATIVE_VIEW(env, obj)->focusBoundsChanged(); } -static bool PictureReady(JNIEnv* env, jobject obj) -{ - return GET_NATIVE_VIEW(env, obj)->pictureReady(); -} - static void Pause(JNIEnv* env, jobject obj) { // This is called for the foreground tab when the browser is put to the @@ -3151,26 +3386,54 @@ static bool ValidNodeAndBounds(JNIEnv *env, jobject obj, int frame, int node, reinterpret_cast<Node*>(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 NULL; + Vector<IntRect> rects = viewImpl->getTouchHighlightRects(x, y, slop); + if (rects.isEmpty()) + return NULL; + + jclass arrayClass = env->FindClass("java/util/ArrayList"); + LOG_ASSERT(arrayClass, "Could not find java/util/ArrayList"); + jmethodID init = env->GetMethodID(arrayClass, "<init>", "(I)V"); + LOG_ASSERT(init, "Could not find constructor for ArrayList"); + jobject array = env->NewObject(arrayClass, init, rects.size()); + LOG_ASSERT(vector, "Could not create a new ArrayList"); + jmethodID add = env->GetMethodID(arrayClass, "add", "(Ljava/lang/Object;)Z"); + LOG_ASSERT(add, "Could not find add method on ArrayList"); + jclass rectClass = env->FindClass("android/graphics/Rect"); + LOG_ASSERT(rectClass, "Could not find android/graphics/Rect"); + jmethodID rectinit = env->GetMethodID(rectClass, "<init>", "(IIII)V"); + LOG_ASSERT(rectinit, "Could not find init method on Rect"); + + for (size_t i = 0; i < rects.size(); i++) { + jobject rect = env->NewObject(rectClass, rectinit, rects[i].x(), + rects[i].y(), rects[i].right(), rects[i].bottom()); + if (rect) { + env->CallBooleanMethod(array, add, rect); + env->DeleteLocalRef(rect); + } + } + + env->DeleteLocalRef(rectClass); + env->DeleteLocalRef(arrayClass); + return array; +} + // ---------------------------------------------------------------------------- /* * JNI registration. */ static JNINativeMethod gJavaWebViewCoreMethods[] = { - { "nativeClearContent", "()V", - (void*) ClearContent }, - { "nativeCopyContentToPicture", "(Landroid/graphics/Picture;)V", - (void*) CopyContentToPicture }, - { "nativeDrawContent", "(Landroid/graphics/Canvas;I)Z", - (void*) DrawContent } , { "nativeFocusBoundsChanged", "()Z", (void*) FocusBoundsChanged } , { "nativeKey", "(IIIZZZZ)Z", (void*) Key }, { "nativeClick", "(II)V", (void*) Click }, - { "nativePictureReady", "()Z", - (void*) PictureReady } , { "nativeSendListBoxChoices", "([ZI)V", (void*) SendListBoxChoices }, { "nativeSendListBoxChoice", "(I)V", @@ -3183,6 +3446,8 @@ static JNINativeMethod gJavaWebViewCoreMethods[] = { (void*) SetGlobalBounds }, { "nativeSetSelection", "(II)V", (void*) SetSelection } , + { "nativeModifySelection", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", + (void*) ModifySelection }, { "nativeDeleteSelection", "(III)V", (void*) DeleteSelection } , { "nativeReplaceTextfieldText", "(IILjava/lang/String;III)V", @@ -3215,11 +3480,11 @@ static JNINativeMethod gJavaWebViewCoreMethods[] = { (void*) UpdateFrameCache }, { "nativeGetContentMinPrefWidth", "()I", (void*) GetContentMinPrefWidth }, - { "nativeRecordContent", "(Landroid/graphics/Region;Landroid/graphics/Point;)Z", + { "nativeRecordContent", "(Landroid/graphics/Region;Landroid/graphics/Point;)I", (void*) RecordContent }, { "setViewportSettingsFromNative", "()V", (void*) SetViewportSettingsFromNative }, - { "nativeSplitContent", "()V", + { "nativeSplitContent", "(I)V", (void*) SplitContent }, { "nativeSetBackgroundColor", "(I)V", (void*) SetBackgroundColor }, @@ -3251,6 +3516,8 @@ static JNINativeMethod gJavaWebViewCoreMethods[] = { (void*) FullScreenPluginHidden }, { "nativeValidNodeAndBounds", "(IILandroid/graphics/Rect;)Z", (void*) ValidNodeAndBounds }, + { "nativeGetTouchHighlightRects", "(III)Ljava/util/ArrayList;", + (void*) GetTouchHighlightRects }, }; int register_webviewcore(JNIEnv* env) diff --git a/WebKit/android/jni/WebViewCore.h b/WebKit/android/jni/WebViewCore.h index 056dba1..99f02e9 100644 --- a/WebKit/android/jni/WebViewCore.h +++ b/WebKit/android/jni/WebViewCore.h @@ -61,10 +61,13 @@ namespace WebCore { #if USE(ACCELERATED_COMPOSITING) namespace WebCore { class GraphicsLayerAndroid; - class LayerAndroid; } #endif +namespace WebCore { + class BaseLayerAndroid; +} + struct PluginWidgetAndroid; class SkPicture; class SkIRect; @@ -137,8 +140,6 @@ namespace android { #if USE(ACCELERATED_COMPOSITING) GraphicsLayerAndroid* graphicsRootLayer() const; - void immediateRepaint(); - void setUIRootLayer(const LayerAndroid* layer); #endif /** Invalidate the view/screen, NOT the content/DOM, but expressed in @@ -170,15 +171,9 @@ namespace android { /** * Notify the view to restore the screen width, which in turn restores - * the scale. - */ - void restoreScale(int); - - /** - * Notify the view to restore the scale used to calculate the screen - * width for wrapping the text + * the scale. Also restore the scale for the text wrap. */ - void restoreScreenWidthScale(int); + void restoreScale(int scale, int textWrapScale); /** * Tell the java side to update the focused textfield @@ -325,6 +320,18 @@ namespace android { * If start and end are out of order, swap them. */ void setSelection(int start, int end); + + /** + * Modifies the current selection. + * + * alter - Specifies how to alter the selection. + * direction - The direction in which to alter the selection. + * granularity - The granularity of the selection modification. + * + * returns - The selection as string. + */ + String modifySelection(const String& alter, const String& direction, const String& granularity); + /** * 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, @@ -432,6 +439,9 @@ namespace android { // 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<IntRect> getTouchHighlightRects(int x, int y, int slop); + // other public functions public: // Open a file chooser for selecting a file to upload @@ -440,27 +450,22 @@ namespace android { // reset the picture set to empty void clearContent(); - // flatten the picture set to a picture - void copyContentToPicture(SkPicture* ); - - // draw the picture set with the specified background color - bool drawContent(SkCanvas* , SkColor ); bool focusBoundsChanged(); - bool pictureReady(); // record the inval area, and the picture size - bool recordContent(SkRegion* , SkIPoint* ); - int screenWidth() const { return m_screenWidth; } - int screenHeight() const { return m_screenHeight; } + BaseLayerAndroid* recordContent(SkRegion* , SkIPoint* ); + int textWrapWidth() const { return m_textWrapWidth; } float scale() const { return m_scale; } - float screenWidthScale() const { return m_screenWidthScale; } + 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(); + void splitContent(PictureSet*); + + void notifyWebAppCanBeInstalled(); // these members are shared with webview.cpp static Mutex gFrameCacheMutex; @@ -510,8 +515,7 @@ namespace android { WebCore::IntRect m_lastFocusedBounds; int m_lastFocusedSelStart; int m_lastFocusedSelEnd; - static Mutex m_contentMutex; // protects ui/core thread pictureset access - PictureSet m_content; // the set of pictures to draw (accessed by UI too) + 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 @@ -536,8 +540,8 @@ namespace android { 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; - float m_screenWidthScale; unsigned m_domtree_version; bool m_check_domtree_version; PageGroup* m_groupForVisitedLinks; @@ -558,7 +562,6 @@ namespace android { #if ENABLE(TOUCH_EVENTS) bool m_forwardingTouchEvents; - IntPoint m_lastTouchPoint; #endif #if DEBUG_NAV_UI |
