summaryrefslogtreecommitdiffstats
path: root/chrome/renderer/render_view.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/renderer/render_view.cc')
-rw-r--r--chrome/renderer/render_view.cc228
1 files changed, 144 insertions, 84 deletions
diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc
index 7c26b73..3922941 100644
--- a/chrome/renderer/render_view.cc
+++ b/chrome/renderer/render_view.cc
@@ -54,6 +54,7 @@
#include "skia/ext/bitmap_platform_device.h"
#include "skia/ext/image_operations.h"
#include "webkit/api/public/WebDragData.h"
+#include "webkit/api/public/WebForm.h"
#include "webkit/api/public/WebPoint.h"
#include "webkit/api/public/WebRect.h"
#include "webkit/api/public/WebScriptSource.h"
@@ -88,8 +89,12 @@
using base::Time;
using base::TimeDelta;
+using webkit_glue::AutofillForm;
+using webkit_glue::PasswordFormDomManager;
+using webkit_glue::SearchableFormData;
using WebKit::WebConsoleMessage;
using WebKit::WebDragData;
+using WebKit::WebForm;
using WebKit::WebRect;
using WebKit::WebScriptSource;
using WebKit::WebWorker;
@@ -139,13 +144,21 @@ static const char* const kBackForwardNavigationScheme = "history";
// Associated with browser-initiated navigations to hold tracking data.
class RenderView::NavigationState : public WebDataSource::ExtraData {
public:
- NavigationState(int32 pending_page_id,
- PageTransition::Type transition,
- Time request_time)
- : transition_type(transition),
- request_time(request_time),
- request_committed(false),
- pending_page_id_(pending_page_id) {
+ static NavigationState* CreateBrowserInitiated(
+ int32 pending_page_id,
+ PageTransition::Type transition_type,
+ Time request_time) {
+ return new NavigationState(transition_type, request_time, false,
+ pending_page_id);
+ }
+
+ static NavigationState* CreateContentInitiated() {
+ // We assume navigations initiated by content are link clicks.
+ return new NavigationState(PageTransition::LINK, Time(), true, -1);
+ }
+
+ static NavigationState* FromDataSource(WebDataSource* ds) {
+ return static_cast<NavigationState*>(ds->GetExtraData());
}
// Contains the page_id for this navigation or -1 if there is none yet.
@@ -156,17 +169,55 @@ class RenderView::NavigationState : public WebDataSource::ExtraData {
// Contains the transition type that the browser specified when it
// initiated the load.
- PageTransition::Type transition_type;
+ PageTransition::Type transition_type() const { return transition_type_; }
+ void set_transition_type(PageTransition::Type type) {
+ transition_type_ = type;
+ }
// The time that this navigation was requested.
- Time request_time;
+ const Time& request_time() const { return request_time_; }
// True if we have already processed the "DidCommitLoad" event for this
// request. Used by session history.
- bool request_committed;
+ bool request_committed() const { return request_committed_; }
+ void set_request_committed(bool value) { request_committed_ = value; }
+
+ // True if this navigation was not initiated via WebFrame::LoadRequest.
+ bool is_content_initiated() const { return is_content_initiated_; }
+
+ SearchableFormData* searchable_form_data() const {
+ return searchable_form_data_.get();
+ }
+ void set_searchable_form_data(SearchableFormData* data) {
+ searchable_form_data_.reset(data);
+ }
+
+ PasswordForm* password_form_data() const {
+ return password_form_data_.get();
+ }
+ void set_password_form_data(PasswordForm* data) {
+ password_form_data_.reset(data);
+ }
private:
+ NavigationState(PageTransition::Type transition_type,
+ const Time& request_time,
+ bool is_content_initiated,
+ int32 pending_page_id)
+ : transition_type_(transition_type),
+ request_time_(request_time),
+ request_committed_(false),
+ is_content_initiated_(is_content_initiated),
+ pending_page_id_(pending_page_id) {
+ }
+
+ PageTransition::Type transition_type_;
+ Time request_time_;
+ bool request_committed_;
+ bool is_content_initiated_;
int32 pending_page_id_;
+ scoped_ptr<SearchableFormData> searchable_form_data_;
+ scoped_ptr<PasswordForm> password_form_data_;
DISALLOW_COPY_AND_ASSIGN(NavigationState);
};
@@ -645,7 +696,7 @@ void RenderView::OnNavigate(const ViewMsg_Navigate_Params& params) {
// as a browser initiated event. Instead, we want it to look as if the page
// initiated any load resulting from JS execution.
if (!params.url.SchemeIs(chrome::kJavaScriptScheme)) {
- pending_navigation_state_.reset(new NavigationState(
+ pending_navigation_state_.reset(NavigationState::CreateBrowserInitiated(
params.page_id, params.transition, params.request_time));
}
@@ -841,9 +892,8 @@ void RenderView::UpdateURL(WebFrame* frame) {
const WebRequest& initial_request = ds->GetInitialRequest();
const WebResponse& response = ds->GetResponse();
- // This will be null if we did not initiate the navigation.
- NavigationState* navigation_state =
- static_cast<NavigationState*>(ds->GetExtraData());
+ NavigationState* navigation_state = NavigationState::FromDataSource(ds);
+ DCHECK(navigation_state);
ViewHostMsg_FrameNavigate_Params params;
params.http_status_code = response.GetHttpStatusCode();
@@ -872,7 +922,7 @@ void RenderView::UpdateURL(WebFrame* frame) {
params.should_update_history = !ds->HasUnreachableURL();
const SearchableFormData* searchable_form_data =
- frame->GetDataSource()->GetSearchableFormData();
+ navigation_state->searchable_form_data();
if (searchable_form_data) {
params.searchable_form_url = searchable_form_data->url();
params.searchable_form_element_name = searchable_form_data->element_name();
@@ -880,7 +930,7 @@ void RenderView::UpdateURL(WebFrame* frame) {
}
const PasswordForm* password_form_data =
- frame->GetDataSource()->GetPasswordFormData();
+ navigation_state->password_form_data();
if (password_form_data)
params.password_form = *password_form_data;
@@ -893,10 +943,7 @@ void RenderView::UpdateURL(WebFrame* frame) {
// Update contents MIME type for main frame.
params.contents_mime_type = ds->GetResponse().GetMimeType();
- // We assume top level navigations initiated by the renderer are link
- // clicks.
- params.transition = navigation_state ?
- navigation_state->transition_type : PageTransition::LINK;
+ params.transition = navigation_state->transition_type();
if (!PageTransition::IsMainFrame(params.transition)) {
// If the main frame does a load, it should not be reported as a subframe
// navigation. This can occur in the following case:
@@ -912,11 +959,6 @@ void RenderView::UpdateURL(WebFrame* frame) {
params.transition = PageTransition::LINK;
}
- if (params.transition == PageTransition::LINK &&
- frame->GetDataSource()->IsFormSubmit()) {
- params.transition = PageTransition::FORM_SUBMIT;
- }
-
// If we have a valid consumed client redirect source,
// the page contained a client redirect (meta refresh, document.loc...),
// so we set the referrer and transition to match.
@@ -954,9 +996,8 @@ void RenderView::UpdateURL(WebFrame* frame) {
std::max(last_page_id_sent_to_browser_, page_id_);
// If we end up reusing this WebRequest (for example, due to a #ref click),
- // we don't want the transition type to persist.
- if (navigation_state)
- navigation_state->transition_type = PageTransition::LINK; // Just clear it.
+ // we don't want the transition type to persist. Just clear it.
+ navigation_state->set_transition_type(PageTransition::LINK);
#if defined(OS_WIN)
if (web_accessibility_manager_.get()) {
@@ -1065,7 +1106,13 @@ void RenderView::DidStopLoading(WebView* webview) {
}
void RenderView::DidCreateDataSource(WebFrame* frame, WebDataSource* ds) {
- ds->SetExtraData(pending_navigation_state_.release());
+ // The rest of RenderView assumes that a WebDataSource will always have a
+ // non-null NavigationState.
+ if (pending_navigation_state_.get()) {
+ ds->SetExtraData(pending_navigation_state_.release());
+ } else {
+ ds->SetExtraData(NavigationState::CreateContentInitiated());
+ }
}
void RenderView::DidStartProvisionalLoadForFrame(
@@ -1079,13 +1126,14 @@ void RenderView::DidStartProvisionalLoadForFrame(
completed_client_redirect_src_ = GURL();
}
+ // We may have better knowledge of when this navigation was requested.
WebDataSource* ds = frame->GetProvisionalDataSource();
if (ds) {
- NavigationState* navigation_state =
- static_cast<NavigationState*>(ds->GetExtraData());
- if (navigation_state)
- ds->SetRequestTime(navigation_state->request_time);
+ NavigationState* navigation_state = NavigationState::FromDataSource(ds);
+ if (!navigation_state->request_time().is_null())
+ ds->SetRequestTime(navigation_state->request_time());
}
+
Send(new ViewHostMsg_DidStartProvisionalLoadForFrame(
routing_id_, webview->GetMainFrame() == frame,
frame->GetProvisionalDataSource()->GetRequest().GetURL()));
@@ -1156,9 +1204,7 @@ void RenderView::DidFailProvisionalLoadWithError(WebView* webview,
// 'replace' load. This is necessary to avoid messing up session history.
// Otherwise, we do a normal load, which simulates a 'go' navigation as far
// as session history is concerned.
- NavigationState* navigation_state =
- static_cast<NavigationState*>(ds->GetExtraData());
- bool replace = navigation_state && !navigation_state->is_new_navigation();
+ bool replace = !NavigationState::FromDataSource(ds)->is_new_navigation();
// Use the alternate error page service if this is a DNS failure or
// connection failure. ERR_CONNECTION_FAILED can be dropped once we no longer
@@ -1225,8 +1271,8 @@ void RenderView::LoadNavigationErrorPage(WebFrame* frame,
void RenderView::DidCommitLoadForFrame(WebView *webview, WebFrame* frame,
bool is_new_navigation) {
- NavigationState* navigation_state = static_cast<NavigationState*>(
- frame->GetDataSource()->GetExtraData());
+ NavigationState* navigation_state =
+ NavigationState::FromDataSource(frame->GetDataSource());
if (is_new_navigation) {
// When we perform a new navigation, we need to update the previous session
@@ -1251,8 +1297,8 @@ void RenderView::DidCommitLoadForFrame(WebView *webview, WebFrame* frame,
// Note that we need to check if the page ID changed. In the case of a
// reload, the page ID doesn't change, and UpdateSessionHistory gets the
// previous URL and the current page ID, which would be wrong.
- if (navigation_state && !navigation_state->is_new_navigation() &&
- !navigation_state->request_committed &&
+ if (!navigation_state->is_new_navigation() &&
+ !navigation_state->request_committed() &&
page_id_ != navigation_state->pending_page_id()) {
// This is a successful session history navigation!
UpdateSessionHistory(frame);
@@ -1265,8 +1311,7 @@ void RenderView::DidCommitLoadForFrame(WebView *webview, WebFrame* frame,
// a session history navigation, because if we attempted a session history
// navigation without valid HistoryItem state, WebCore will think it is a
// new navigation.
- if (navigation_state)
- navigation_state->request_committed = true;
+ navigation_state->set_request_committed(true);
UpdateURL(frame);
@@ -1304,6 +1349,10 @@ void RenderView::DidFinishDocumentLoadForFrame(WebView* webview,
WebFrame* frame) {
Send(new ViewHostMsg_DocumentLoadedInFrame(routing_id_));
+ // The document has now been fully loaded. Scan for password forms to be
+ // sent up to the browser.
+ SendPasswordForms(frame);
+
// Check whether we have new encoding name.
UpdateEncoding(frame, webview->GetMainFrameEncodingName());
@@ -1323,9 +1372,10 @@ void RenderView::DidChangeLocationWithinPageForFrame(WebView* webview,
// could end up having a non-null pending navigation state. We just need to
// update the ExtraData on the datasource so that others who read the
// ExtraData will get the new NavigationState. Similarly, if we did not
- // initiate this navigation, then we need to take care to clear any pre-
- // existing navigation state.
- frame->GetDataSource()->SetExtraData(pending_navigation_state_.release());
+ // initiate this navigation, then we need to take care to reset any pre-
+ // existing navigation state to a content-initiated navigation state.
+ // DidCreateDataSource conveniently takes care of this for us.
+ DidCreateDataSource(frame, frame->GetDataSource());
DidCommitLoadForFrame(webview, frame, is_new_navigation);
@@ -1334,25 +1384,6 @@ void RenderView::DidChangeLocationWithinPageForFrame(WebView* webview,
UpdateTitle(frame, UTF16ToWideHack(title));
}
-void RenderView::DidReceiveIconForFrame(WebView* webview,
- WebFrame* frame) {
-}
-
-void RenderView::WillPerformClientRedirect(WebView* webview,
- WebFrame* frame,
- const GURL& src_url,
- const GURL& dest_url,
- unsigned int delay_seconds,
- unsigned int fire_date) {
-}
-
-void RenderView::DidCancelClientRedirect(WebView* webview,
- WebFrame* frame) {
-}
-
-void RenderView::WillCloseFrame(WebView* view, WebFrame* frame) {
-}
-
void RenderView::DidCompleteClientRedirect(WebView* webview,
WebFrame* frame,
const GURL& source) {
@@ -1360,6 +1391,27 @@ void RenderView::DidCompleteClientRedirect(WebView* webview,
completed_client_redirect_src_ = source;
}
+void RenderView::WillSubmitForm(WebView* webview, WebFrame* frame,
+ const WebForm& form) {
+ NavigationState* navigation_state =
+ NavigationState::FromDataSource(frame->GetProvisionalDataSource());
+
+ if (navigation_state->transition_type() == PageTransition::LINK)
+ navigation_state->set_transition_type(PageTransition::FORM_SUBMIT);
+
+ // Save these to be processed when the ensuing navigation is committed.
+ navigation_state->set_searchable_form_data(
+ SearchableFormData::Create(form));
+ navigation_state->set_password_form_data(
+ PasswordFormDomManager::CreatePasswordForm(form));
+
+ if (form.isAutoCompleteEnabled()) {
+ scoped_ptr<AutofillForm> autofill_form(AutofillForm::Create(form));
+ if (autofill_form.get())
+ Send(new ViewHostMsg_AutofillFormSubmitted(routing_id_, *autofill_form));
+ }
+}
+
void RenderView::WillSendRequest(WebView* webview,
uint32 identifier,
WebRequest* request) {
@@ -1414,11 +1466,11 @@ WindowOpenDisposition RenderView::DispositionForNavigationAction(
WebNavigationType type,
WindowOpenDisposition disposition,
bool is_redirect) {
- // GetExtraData is NULL when we did not issue the request ourselves (see
- // OnNavigate), and so such a request may correspond to a link-click,
- // script, or drag-n-drop initiated navigation.
+ // A content initiated navigation may have originated from a link-click,
+ // script, drag-n-drop operation, etc.
bool is_content_initiated =
- !frame->GetProvisionalDataSource()->GetExtraData();
+ NavigationState::FromDataSource(frame->GetProvisionalDataSource())->
+ is_content_initiated();
// Webkit is asking whether to navigate to a new URL.
// This is fine normally, except if we're showing UI from one security
@@ -2262,16 +2314,6 @@ void RenderView::OnSetPageEncoding(const std::wstring& encoding_name) {
webview()->SetPageEncoding(encoding_name);
}
-void RenderView::OnPasswordFormsSeen(WebView* webview,
- const std::vector<PasswordForm>& forms) {
- Send(new ViewHostMsg_PasswordFormsSeen(routing_id_, forms));
-}
-
-void RenderView::OnAutofillFormSubmitted(WebView* webview,
- const AutofillForm& form) {
- Send(new ViewHostMsg_AutofillFormSubmitted(routing_id_, form));
-}
-
void RenderView::NavigateBackForwardSoon(int offset) {
history_back_list_count_ += offset;
history_forward_list_count_ -= offset;
@@ -2472,7 +2514,7 @@ void RenderView::OnFormFill(const FormData& form) {
}
void RenderView::OnFillPasswordForm(
- const PasswordFormDomManager::FillData& form_data) {
+ const webkit_glue::PasswordFormDomManager::FillData& form_data) {
webkit_glue::FillPasswordForm(this->webview(), form_data);
}
@@ -2679,11 +2721,8 @@ void RenderView::DidAddHistoryItem() {
WebDataSource* ds = main_frame->GetDataSource();
DCHECK(ds != NULL);
- NavigationState* navigation_state =
- static_cast<NavigationState*>(ds->GetExtraData());
-
- if (navigation_state &&
- navigation_state->transition_type == PageTransition::START_PAGE)
+ NavigationState* navigation_state = NavigationState::FromDataSource(ds);
+ if (navigation_state->transition_type() == PageTransition::START_PAGE)
return;
history_back_list_count_++;
@@ -2852,3 +2891,24 @@ void RenderView::FocusAccessibilityObject(
NOTIMPLEMENTED();
#endif
}
+
+void RenderView::SendPasswordForms(WebFrame* frame) {
+ std::vector<WebForm> forms;
+ frame->GetForms(&forms);
+
+ std::vector<PasswordForm> password_forms;
+ for (size_t i = 0; i < forms.size(); ++i) {
+ const WebForm& form = forms[i];
+
+ // Respect autocomplete=off.
+ if (form.isAutoCompleteEnabled()) {
+ scoped_ptr<PasswordForm> password_form(
+ PasswordFormDomManager::CreatePasswordForm(form));
+ if (password_form.get())
+ password_forms.push_back(*password_form);
+ }
+ }
+
+ if (!password_forms.empty())
+ Send(new ViewHostMsg_PasswordFormsSeen(routing_id_, password_forms));
+}