diff options
author | Ben Murdoch <benm@google.com> | 2010-12-02 15:38:31 +0000 |
---|---|---|
committer | Ben Murdoch <benm@google.com> | 2010-12-06 12:10:01 +0000 |
commit | 95a009844dd8e8b8d3d92d7ef14c31bd48468423 (patch) | |
tree | 5f91e590376116f9b3fee9ce118430d2adc2dbf9 | |
parent | 2e99fe47543f09c4d9e797beff199b62e0c5c2a3 (diff) | |
download | external_webkit-95a009844dd8e8b8d3d92d7ef14c31bd48468423.zip external_webkit-95a009844dd8e8b8d3d92d7ef14c31bd48468423.tar.gz external_webkit-95a009844dd8e8b8d3d92d7ef14c31bd48468423.tar.bz2 |
Refactor AutoFill so it runs lazily.
This CL refactors the AutoFill code so that we only search for forms
when we need to, i.e. the user has focused a form field. This helps
page load times. We also re-search the document for forms if the dom
version number has changed. These changes fix a bug where a crash
occurs if the form is focused before the page has finished loading.
We also move the callsite of formFieldFocused so that it only occurs
when the IME is requested which is a more appropriate place called less
frequently than it's current callsite in EditorClientAndroid.
Bug: 3243567
Change-Id: I04fe13944d3f8248197d71a0e58c21f01c4abdd0
-rw-r--r-- | WebKit/android/WebCoreSupport/EditorClientAndroid.cpp | 13 | ||||
-rw-r--r-- | WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp | 9 | ||||
-rw-r--r-- | WebKit/android/WebCoreSupport/autofill/WebAutoFill.cpp | 47 | ||||
-rw-r--r-- | WebKit/android/WebCoreSupport/autofill/WebAutoFill.h | 7 | ||||
-rw-r--r-- | WebKit/android/jni/WebCoreFrameBridge.cpp | 7 | ||||
-rw-r--r-- | WebKit/android/jni/WebSettings.cpp | 10 | ||||
-rw-r--r-- | WebKit/android/jni/WebViewCore.cpp | 7 |
7 files changed, 59 insertions, 41 deletions
diff --git a/WebKit/android/WebCoreSupport/EditorClientAndroid.cpp b/WebKit/android/WebCoreSupport/EditorClientAndroid.cpp index f5f8211..3c5243e 100644 --- a/WebKit/android/WebCoreSupport/EditorClientAndroid.cpp +++ b/WebKit/android/WebCoreSupport/EditorClientAndroid.cpp @@ -238,19 +238,6 @@ void EditorClientAndroid::respondToChangedSelection() { Frame* frame = m_page->focusController()->focusedOrMainFrame(); if (!frame || !frame->view()) return; - -#if ENABLE(WEB_AUTOFILL) - WebCore::Node* focusedNode = frame->document()->focusedNode(); - if (focusedNode && focusedNode->hasTagName(inputTag)) { - WebCore::HTMLInputElement* element = static_cast<WebCore::HTMLInputElement*>(focusedNode); - // TODO: If it's a text field, inform AutoFill that it should get AutoFill suggestions for - // the form it belongs to. AutoFill can also work with select-one elements (i.e. <select> - // without the "multiple" attribute set. Is it safe to call this function with select elements? - // How should AutoFill communicate select suggestions to Java? - if (element->isTextField()) - m_autoFill->formFieldFocused(static_cast<HTMLFormControlElement*>(focusedNode)); - } -#endif WebViewCore* webViewCore = WebViewCore::getWebViewCore(frame->view()); webViewCore->updateTextSelection(); } diff --git a/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp b/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp index ed1da87..a563c6a 100644 --- a/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp +++ b/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp @@ -36,6 +36,7 @@ #include "DOMImplementation.h" #include "Document.h" #include "DocumentLoader.h" +#include "EditorClientAndroid.h" #include "Frame.h" #include "FrameLoader.h" #include "FrameNetworkingContextAndroid.h" @@ -74,6 +75,7 @@ #include "WebIconDatabase.h" #include "WebFrameView.h" #include "WebViewCore.h" +#include "autofill/WebAutoFill.h" #include "android_graphics.h" #include <utils/AssetManager.h> @@ -292,6 +294,13 @@ void FrameLoaderClientAndroid::dispatchDidReceiveTitle(const String& title) { } void FrameLoaderClientAndroid::dispatchDidCommitLoad() { +#if ENABLE(WEB_AUTOFILL) + if (m_frame == m_frame->page()->mainFrame()) { + EditorClientAndroid* editorC = static_cast<EditorClientAndroid*>(m_frame->page()->editorClient()); + WebAutoFill* autoFill = editorC->getAutoFill(); + autoFill->reset(); + } +#endif verifiedOk(); } diff --git a/WebKit/android/WebCoreSupport/autofill/WebAutoFill.cpp b/WebKit/android/WebCoreSupport/autofill/WebAutoFill.cpp index 4fa0e54..8c7e4ee 100644 --- a/WebKit/android/WebCoreSupport/autofill/WebAutoFill.cpp +++ b/WebKit/android/WebCoreSupport/autofill/WebAutoFill.cpp @@ -52,7 +52,10 @@ namespace android WebAutoFill::WebAutoFill() : mQueryId(1) , mWebViewCore(0) + , mLastSearchDomVersion(0) { + mTabContents = new TabContents(); + setEmptyProfile(); } void WebAutoFill::init() @@ -65,12 +68,9 @@ void WebAutoFill::init() ASSERT(mWebViewCore); AndroidURLRequestContextGetter::Get()->SetURLRequestContext(mWebViewCore->webRequestContext()); AndroidURLRequestContextGetter::Get()->SetIOThread(WebUrlLoaderClient::ioThread()); - mTabContents = new TabContents(); mAutoFillManager = new AutoFillManager(mTabContents.get()); mAutoFillHost = new AutoFillHostAndroid(this); mTabContents->SetAutoFillHost(mAutoFillHost.get()); - - setEmptyProfile(); } WebAutoFill::~WebAutoFill() @@ -81,12 +81,6 @@ WebAutoFill::~WebAutoFill() void WebAutoFill::searchDocument(WebCore::Frame* frame) { - // TODO: This method is called when the main frame finishes loading and - // scans the document for forms and tries to work out the type of the - // fields in those forms. It's currently synchronous and might be slow - // if the page has many or complex forms. Might want to make this an - // async method. - if (!enabled()) return; @@ -94,17 +88,43 @@ void WebAutoFill::searchDocument(WebCore::Frame* frame) mQueryMap.clear(); mUniqueIdMap.clear(); + mForms.clear(); mQueryId = 1; + + ASSERT(mFormManager); + ASSERT(mAutoFillManager); + mAutoFillManager->Reset(); mFormManager->Reset(); + mFormManager->ExtractForms(frame); - mForms.clear(); mFormManager->GetFormsInFrame(frame, FormManager::REQUIRE_AUTOCOMPLETE, &mForms); mAutoFillManager->FormsSeen(mForms); + } 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 @@ -153,7 +173,12 @@ void WebAutoFill::fillFormFields(int queryId) webkit_glue::FormData* form = mQueryMap[queryId]; ASSERT(form); AutoFillQueryToUniqueIdMap::iterator iter = mUniqueIdMap.find(queryId); - ASSERT(iter != mUniqueIdMap.end()); + 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, iter->second); mUniqueIdMap.erase(iter); } diff --git a/WebKit/android/WebCoreSupport/autofill/WebAutoFill.h b/WebKit/android/WebCoreSupport/autofill/WebAutoFill.h index 4025b5a..3713aa4 100644 --- a/WebKit/android/WebCoreSupport/autofill/WebAutoFill.h +++ b/WebKit/android/WebCoreSupport/autofill/WebAutoFill.h @@ -54,8 +54,6 @@ class WebAutoFill : public Noncopyable public: WebAutoFill(); virtual ~WebAutoFill(); - - void searchDocument(WebCore::Frame*); void formFieldFocused(WebCore::HTMLFormControlElement*); void fillFormFields(int queryId); void querySuccessful(const string16& value, const string16& label, int uniqueId); @@ -70,8 +68,11 @@ public: bool updateProfileLabel(); + void reset() { mLastSearchDomVersion = 0; } + private: void init(); + void searchDocument(WebCore::Frame*); void setEmptyProfile(); OwnPtr<FormManager> mFormManager; @@ -91,6 +92,8 @@ private: int mQueryId; WebViewCore* mWebViewCore; + + int mLastSearchDomVersion; }; } diff --git a/WebKit/android/jni/WebCoreFrameBridge.cpp b/WebKit/android/jni/WebCoreFrameBridge.cpp index 1ddbb82..5fa5dfb 100644 --- a/WebKit/android/jni/WebCoreFrameBridge.cpp +++ b/WebKit/android/jni/WebCoreFrameBridge.cpp @@ -609,13 +609,6 @@ WebFrame::didFinishLoad(WebCore::Frame* frame) (int)loadType, isMainFrame); checkException(env); env->DeleteLocalRef(urlStr); -#if ENABLE(WEB_AUTOFILL) - // TODO: Need to consider child frames. - if (isMainFrame) { - EditorClientAndroid* editorClient = static_cast<EditorClientAndroid*>(mPage->editorClient()); - editorClient->getAutoFill()->searchDocument(frame); - } -#endif } void diff --git a/WebKit/android/jni/WebSettings.cpp b/WebKit/android/jni/WebSettings.cpp index 75f42b3..dc3723d 100644 --- a/WebKit/android/jni/WebSettings.cpp +++ b/WebKit/android/jni/WebSettings.cpp @@ -504,17 +504,11 @@ public: // (see chrome/browser/autofill/autofill_manager.cc:405). This // setting should probably be synced into Chromium also. - // If we toggle from disabled to enabled, then re search the document - // for forms. - bool oldAutoFillSetting = s->autoFillEnabled(); s->setAutoFillEnabled(flag); - EditorClientAndroid* editorC = static_cast<EditorClientAndroid*>(pFrame->page()->editorClient()); - WebAutoFill* webAutoFill = editorC->getAutoFill(); - if (!oldAutoFillSetting && flag) - webAutoFill->searchDocument(pFrame); - if (flag) { + EditorClientAndroid* editorC = static_cast<EditorClientAndroid*>(pFrame->page()->editorClient()); + WebAutoFill* webAutoFill = editorC->getAutoFill(); // Set the active AutoFillProfile data. jobject autoFillProfile = env->GetObjectField(obj, gFieldIds->mAutoFillProfile); if (autoFillProfile) diff --git a/WebKit/android/jni/WebViewCore.cpp b/WebKit/android/jni/WebViewCore.cpp index ec701f9..6b1ca44 100644 --- a/WebKit/android/jni/WebViewCore.cpp +++ b/WebKit/android/jni/WebViewCore.cpp @@ -2947,6 +2947,13 @@ bool WebViewCore::handleMouseClick(WebCore::Frame* framePtr, WebCore::Node* node bool ime = !(static_cast<WebCore::HTMLInputElement*>(focusNode)) ->readOnly(); if (ime) { +#if ENABLE(WEB_AUTOFILL) + if (renderer->isTextField()) { + EditorClientAndroid* editorC = static_cast<EditorClientAndroid*>(framePtr->page()->editorClient()); + WebAutoFill* autoFill = editorC->getAutoFill(); + autoFill->formFieldFocused(static_cast<HTMLFormControlElement*>(focusNode)); + } +#endif RenderTextControl* rtc = static_cast<RenderTextControl*> (renderer); requestKeyboardWithSelection(focusNode, rtc->selectionStart(), |