diff options
Diffstat (limited to 'chrome/renderer')
-rw-r--r-- | chrome/renderer/render_view.cc | 149 | ||||
-rw-r--r-- | chrome/renderer/render_view.h | 8 |
2 files changed, 90 insertions, 67 deletions
diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc index 33a25de..79ddf45 100644 --- a/chrome/renderer/render_view.cc +++ b/chrome/renderer/render_view.cc @@ -140,14 +140,12 @@ static const char* const kUnreachableWebDataURL = static const char* const kBackForwardNavigationScheme = "history"; -namespace { - // Associated with browser-initiated navigations to hold tracking data. -class RenderViewExtraRequestData : public WebRequest::ExtraData { +class RenderView::NavigationState : public WebDataSource::ExtraData { public: - RenderViewExtraRequestData(int32 pending_page_id, - PageTransition::Type transition, - Time request_time) + NavigationState(int32 pending_page_id, + PageTransition::Type transition, + Time request_time) : transition_type(transition), request_time(request_time), request_committed(false), @@ -163,6 +161,8 @@ class RenderViewExtraRequestData : public WebRequest::ExtraData { // Contains the transition type that the browser specified when it // initiated the load. PageTransition::Type transition_type; + + // The time that this navigation was requested. Time request_time; // True if we have already processed the "DidCommitLoad" event for this @@ -172,11 +172,9 @@ class RenderViewExtraRequestData : public WebRequest::ExtraData { private: int32 pending_page_id_; - DISALLOW_COPY_AND_ASSIGN(RenderViewExtraRequestData); + DISALLOW_COPY_AND_ASSIGN(NavigationState); }; -} // namespace - /////////////////////////////////////////////////////////////////////////////// RenderView::RenderView(RenderThreadBase* render_thread) @@ -807,8 +805,14 @@ void RenderView::OnNavigate(const ViewMsg_Navigate_Params& params) { scoped_ptr<WebRequest> request(WebRequest::Create(params.url)); request->SetCachePolicy(cache_policy); - request->SetExtraData(new RenderViewExtraRequestData( - params.page_id, params.transition, params.request_time)); + + // A navigation resulting from loading a javascript URL should not be treated + // 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( + params.page_id, params.transition, params.request_time)); + } // If we are reloading, then WebKit will use the state of the current page. // Otherwise, we give it the state to navigate to. @@ -821,6 +825,9 @@ void RenderView::OnNavigate(const ViewMsg_Navigate_Params& params) { } main_frame->LoadRequest(request.get()); + + // In case LoadRequest failed before DidCreateDataSource was called. + pending_navigation_state_.reset(); } // Stop loading the current page @@ -977,10 +984,9 @@ void RenderView::UpdateURL(WebFrame* frame) { const WebRequest& initial_request = ds->GetInitialRequest(); const WebResponse& response = ds->GetResponse(); - // We don't hold a reference to the extra data. The request's reference will - // be sufficient because we won't modify it during our call. MAY BE NULL. - RenderViewExtraRequestData* extra_data = - static_cast<RenderViewExtraRequestData*>(request.GetExtraData()); + // This will be null if we did not initiate the navigation. + NavigationState* navigation_state = + static_cast<NavigationState*>(ds->GetExtraData()); ViewHostMsg_FrameNavigate_Params params; params.http_status_code = response.GetHttpStatusCode(); @@ -1024,7 +1030,7 @@ void RenderView::UpdateURL(WebFrame* frame) { params.gesture = navigation_gesture_; navigation_gesture_ = NavigationGestureUnknown; - if (webview()->GetMainFrame() == frame) { + if (!frame->GetParent()) { // Top-level navigation. // Update contents MIME type for main frame. @@ -1032,8 +1038,8 @@ void RenderView::UpdateURL(WebFrame* frame) { // We assume top level navigations initiated by the renderer are link // clicks. - params.transition = extra_data ? - extra_data->transition_type : PageTransition::LINK; + params.transition = navigation_state ? + navigation_state->transition_type : PageTransition::LINK; 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: @@ -1084,8 +1090,6 @@ void RenderView::UpdateURL(WebFrame* frame) { else params.transition = PageTransition::AUTO_SUBFRAME; - // The browser should never initiate a subframe navigation. - DCHECK(!extra_data); Send(new ViewHostMsg_FrameNavigate(routing_id_, params)); } @@ -1094,8 +1098,8 @@ void RenderView::UpdateURL(WebFrame* frame) { // If we end up reusing this WebRequest (for example, due to a #ref click), // we don't want the transition type to persist. - if (extra_data) - extra_data->transition_type = PageTransition::LINK; // Just clear it. + if (navigation_state) + navigation_state->transition_type = PageTransition::LINK; // Just clear it. #if defined(OS_WIN) if (web_accessibility_manager_.get()) { @@ -1194,6 +1198,10 @@ void RenderView::DidStopLoading(WebView* webview) { ResetPendingUpload(); } +void RenderView::DidCreateDataSource(WebFrame* frame, WebDataSource* ds) { + ds->SetExtraData(pending_navigation_state_.release()); +} + void RenderView::DidStartProvisionalLoadForFrame( WebView* webview, WebFrame* frame, @@ -1207,12 +1215,10 @@ void RenderView::DidStartProvisionalLoadForFrame( WebDataSource* ds = frame->GetProvisionalDataSource(); if (ds) { - const WebRequest& req = ds->GetRequest(); - RenderViewExtraRequestData* extra_data = - static_cast<RenderViewExtraRequestData*>(req.GetExtraData()); - if (extra_data) { - ds->SetRequestTime(extra_data->request_time); - } + NavigationState* navigation_state = + static_cast<NavigationState*>(ds->GetExtraData()); + if (navigation_state) + ds->SetRequestTime(navigation_state->request_time); } Send(new ViewHostMsg_DidStartProvisionalLoadForFrame( routing_id_, webview->GetMainFrame() == frame, @@ -1284,9 +1290,9 @@ 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. - RenderViewExtraRequestData* extra_data = - static_cast<RenderViewExtraRequestData*>(failed_request.GetExtraData()); - bool replace = extra_data && !extra_data->is_new_navigation(); + NavigationState* navigation_state = + static_cast<NavigationState*>(ds->GetExtraData()); + bool replace = navigation_state && !navigation_state->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 @@ -1353,10 +1359,8 @@ void RenderView::LoadNavigationErrorPage(WebFrame* frame, void RenderView::DidCommitLoadForFrame(WebView *webview, WebFrame* frame, bool is_new_navigation) { - const WebRequest& request = - webview->GetMainFrame()->GetDataSource()->GetRequest(); - RenderViewExtraRequestData* extra_data = - static_cast<RenderViewExtraRequestData*>(request.GetExtraData()); + NavigationState* navigation_state = static_cast<NavigationState*>( + frame->GetDataSource()->GetExtraData()); if (is_new_navigation) { // When we perform a new navigation, we need to update the previous session @@ -1371,22 +1375,22 @@ void RenderView::DidCommitLoadForFrame(WebView *webview, WebFrame* frame, page_id_, true), kDelayForForcedCaptureMs); } else { - // Inspect the extra_data on the main frame (set in our Navigate method) to - // see if the navigation corresponds to a session history navigation... - // Note: |frame| may or may not be the toplevel frame, but for the case - // of capturing session history, the first committed frame suffices. We - // keep track of whether we've seen this commit before so that only capture - // session history once per navigation. + // Inspect the navigation_state on the main frame (set in our Navigate + // method) to see if the navigation corresponds to a session history + // navigation... Note: |frame| may or may not be the toplevel frame, but + // for the case of capturing session history, the first committed frame + // suffices. We keep track of whether we've seen this commit before so + // that only capture session history once per navigation. // // 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 (extra_data && !extra_data->is_new_navigation() && - !extra_data->request_committed && - page_id_ != extra_data->pending_page_id()) { + if (navigation_state && !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); - page_id_ = extra_data->pending_page_id(); + page_id_ = navigation_state->pending_page_id(); } } @@ -1395,8 +1399,8 @@ 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 (extra_data) - extra_data->request_committed = true; + if (navigation_state) + navigation_state->request_committed = true; UpdateURL(frame); @@ -1447,7 +1451,16 @@ void RenderView::DidHandleOnloadEventsForFrame(WebView* webview, void RenderView::DidChangeLocationWithinPageForFrame(WebView* webview, WebFrame* frame, bool is_new_navigation) { + // If this was a reference fragment navigation that we initiated, then we + // 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()); + DidCommitLoadForFrame(webview, frame, is_new_navigation); + const string16& title = webview->GetMainFrame()->GetDataSource()->GetPageTitle(); UpdateTitle(frame, UTF16ToWideHack(title)); @@ -1550,27 +1563,30 @@ 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. + bool is_content_initiated = + !frame->GetProvisionalDataSource()->GetExtraData(); + // Webkit is asking whether to navigate to a new URL. // This is fine normally, except if we're showing UI from one security // context and they're trying to navigate to a different context. const GURL& url = request->GetURL(); + // We only care about navigations that are within the current tab (as opposed // to, for example, opening a new window). // But we sometimes navigate to about:blank to clear a tab, and we want to // still allow that. - if (disposition == CURRENT_TAB && !(url.SchemeIs(chrome::kAboutScheme))) { - // 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. - if (frame == webview->GetMainFrame() && !request->GetExtraData()) { - // When we received such unsolicited navigations, we sometimes want to - // punt them up to the browser to handle. - if (BindingsPolicy::is_dom_ui_enabled(enabled_bindings_) || - frame->GetInViewSourceMode() || - url.SchemeIs(chrome::kViewSourceScheme)) { - OpenURL(webview, url, GURL(), disposition); - return IGNORE_ACTION; // Suppress the load here. - } + if (disposition == CURRENT_TAB && is_content_initiated && + frame->GetParent() == NULL && !url.SchemeIs(chrome::kAboutScheme)) { + // When we received such unsolicited navigations, we sometimes want to + // punt them up to the browser to handle. + if (BindingsPolicy::is_dom_ui_enabled(enabled_bindings_) || + frame->GetInViewSourceMode() || + url.SchemeIs(chrome::kViewSourceScheme)) { + OpenURL(webview, url, GURL(), disposition); + return IGNORE_ACTION; // Suppress the load here. } } @@ -1596,9 +1612,8 @@ WindowOpenDisposition RenderView::DispositionForNavigationAction( frame->GetOpener() == NULL && // Must be a top-level frame. frame->GetParent() == NULL && - // Must not have issued the request from this page. GetExtraData is NULL - // when the navigation is being done by something outside the page. - !request->GetExtraData() && + // Must not have issued the request from this page. + is_content_initiated && // Must be targeted at the current tab. disposition == CURRENT_TAB && // Must be a JavaScript navigation, which appears as "other". @@ -2863,11 +2878,11 @@ void RenderView::DidAddHistoryItem() { WebDataSource* ds = main_frame->GetDataSource(); DCHECK(ds != NULL); - const WebRequest& request = ds->GetRequest(); - RenderViewExtraRequestData* extra_data = - static_cast<RenderViewExtraRequestData*>(request.GetExtraData()); + NavigationState* navigation_state = + static_cast<NavigationState*>(ds->GetExtraData()); - if (extra_data && extra_data->transition_type == PageTransition::START_PAGE) + if (navigation_state && + navigation_state->transition_type == PageTransition::START_PAGE) return; history_back_list_count_++; diff --git a/chrome/renderer/render_view.h b/chrome/renderer/render_view.h index f42b8ff..4de8bb3 100644 --- a/chrome/renderer/render_view.h +++ b/chrome/renderer/render_view.h @@ -170,6 +170,7 @@ class RenderView : public RenderWidget, virtual void DidStartLoading(WebView* webview); virtual void DidStopLoading(WebView* webview); + virtual void DidCreateDataSource(WebFrame* frame, WebDataSource* ds); virtual void DidStartProvisionalLoadForFrame( WebView* webview, WebFrame* frame, @@ -801,6 +802,13 @@ class RenderView : public RenderWidget, // The text selection the last time DidChangeSelection got called. std::string last_selection_; + // Holds state pertaining to a navigation that we initiated. This is held by + // the WebDataSource::ExtraData attribute. We use pending_navigation_state_ + // as a temporary holder for the state until the WebDataSource corresponding + // to the new navigation is created. See DidCreateDataSource. + class NavigationState; + scoped_ptr<NavigationState> pending_navigation_state_; + DISALLOW_COPY_AND_ASSIGN(RenderView); }; |