summaryrefslogtreecommitdiffstats
path: root/chrome/renderer
diff options
context:
space:
mode:
authordarin@chromium.org <darin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-21 04:42:54 +0000
committerdarin@chromium.org <darin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-21 04:42:54 +0000
commit77f17a8a4b03e493392f04a77d97ea6e1379760d (patch)
tree43b549e31e17bd26849230d37a4a56b4ff631c5b /chrome/renderer
parent852cb1e5ecef7e815963213013e94485654cf5cd (diff)
downloadchromium_src-77f17a8a4b03e493392f04a77d97ea6e1379760d.zip
chromium_src-77f17a8a4b03e493392f04a77d97ea6e1379760d.tar.gz
chromium_src-77f17a8a4b03e493392f04a77d97ea6e1379760d.tar.bz2
Move ExtraData from WebRequest to WebDataSource.
This adds a DidCreateDataSource method to WebViewDelegate, which the embedder uses to know if their LoadRequest resulted in a navigation. The embedder then associates the ExtraData with the WebDataSource at that point. The WebDataSource then proceeds to be treated as the provisional data source, possibly failing or being committed. We then inspect WebFrame::GetDataSource in DidCommitLoadForFrame to recover the ExtraData. We have to take care to handle reference fragment navigations since those do not result in a new WebDataSource being created. So, in DidChangeLocationWithinPage, we update the ExtraData associated with the WebDataSource returned by WebFrame::GetDataSource. One thing that is important to note: In DidCommitLoadForFrame, we would previously always inspect the value of GetDataSource returned from the main frame instead of looking at the frame passed to DidCommitLoadForFrame. This explains why WebFrameImpl:: LoadRequest needed to cached ExtraData on the current WebDataSource, and I think doing so is awkward and wrong. My change is to always store the ExtraData on the first WebDataSource to be created as a result of LoadRequest. Then in DidCommitLoadForFrame, I always inspect the ExtraData from the given WebFrame. This means that for history navigations that only navigate a subframe, we'll end up with ExtraData associated with the WebDataSource of a subframe. I think this is OK even though the old code was trying to avoid this scenario. See the DCHECK removed in RenderView::UpdateURL. BUG=11423 R=brettw Review URL: http://codereview.chromium.org/115575 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@16580 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/renderer')
-rw-r--r--chrome/renderer/render_view.cc149
-rw-r--r--chrome/renderer/render_view.h8
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);
};