| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/renderer/render_view.h" | 5 #include "chrome/renderer/render_view.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <string> | 8 #include <string> |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 91 #include "webkit/glue/webview.h" | 91 #include "webkit/glue/webview.h" |
| 92 | 92 |
| 93 #if defined(OS_WIN) | 93 #if defined(OS_WIN) |
| 94 // TODO(port): these files are currently Windows only because they concern: | 94 // TODO(port): these files are currently Windows only because they concern: |
| 95 // * theming | 95 // * theming |
| 96 #include "base/gfx/native_theme.h" | 96 #include "base/gfx/native_theme.h" |
| 97 #endif | 97 #endif |
| 98 | 98 |
| 99 using base::Time; | 99 using base::Time; |
| 100 using base::TimeDelta; | 100 using base::TimeDelta; |
| 101 using webkit_glue::AltErrorPageResourceFetcher; |
| 101 using webkit_glue::AutofillForm; | 102 using webkit_glue::AutofillForm; |
| 102 using webkit_glue::PasswordForm; | 103 using webkit_glue::PasswordForm; |
| 103 using webkit_glue::PasswordFormDomManager; | 104 using webkit_glue::PasswordFormDomManager; |
| 104 using webkit_glue::SearchableFormData; | 105 using webkit_glue::SearchableFormData; |
| 105 using WebKit::WebConsoleMessage; | 106 using WebKit::WebConsoleMessage; |
| 106 using WebKit::WebData; | 107 using WebKit::WebData; |
| 107 using WebKit::WebDataSource; | 108 using WebKit::WebDataSource; |
| 108 using WebKit::WebDragData; | 109 using WebKit::WebDragData; |
| 109 using WebKit::WebForm; | 110 using WebKit::WebForm; |
| 110 using WebKit::WebHistoryItem; | 111 using WebKit::WebHistoryItem; |
| (...skipping 847 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 958 } else { | 959 } else { |
| 959 // Subframe navigation: the type depends on whether this navigation | 960 // Subframe navigation: the type depends on whether this navigation |
| 960 // generated a new session history entry. When they do generate a session | 961 // generated a new session history entry. When they do generate a session |
| 961 // history entry, it means the user initiated the navigation and we should | 962 // history entry, it means the user initiated the navigation and we should |
| 962 // mark it as such. This test checks if this is the first time UpdateURL | 963 // mark it as such. This test checks if this is the first time UpdateURL |
| 963 // has been called since WillNavigateToURL was called to initiate the load. | 964 // has been called since WillNavigateToURL was called to initiate the load. |
| 964 if (page_id_ > last_page_id_sent_to_browser_) | 965 if (page_id_ > last_page_id_sent_to_browser_) |
| 965 params.transition = PageTransition::MANUAL_SUBFRAME; | 966 params.transition = PageTransition::MANUAL_SUBFRAME; |
| 966 else | 967 else |
| 967 params.transition = PageTransition::AUTO_SUBFRAME; | 968 params.transition = PageTransition::AUTO_SUBFRAME; |
| 969 //XXX navigation_state->set_transition_type(params.transition); |
| 968 | 970 |
| 969 Send(new ViewHostMsg_FrameNavigate(routing_id_, params)); | 971 Send(new ViewHostMsg_FrameNavigate(routing_id_, params)); |
| 970 } | 972 } |
| 971 | 973 |
| 972 last_page_id_sent_to_browser_ = | 974 last_page_id_sent_to_browser_ = |
| 973 std::max(last_page_id_sent_to_browser_, page_id_); | 975 std::max(last_page_id_sent_to_browser_, page_id_); |
| 974 | 976 |
| 975 // If we end up reusing this WebRequest (for example, due to a #ref click), | 977 // If we end up reusing this WebRequest (for example, due to a #ref click), |
| 976 // we don't want the transition type to persist. Just clear it. | 978 // we don't want the transition type to persist. Just clear it. |
| 977 navigation_state->set_transition_type(PageTransition::LINK); | 979 navigation_state->set_transition_type(PageTransition::LINK); |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1133 if (event_time != 0.0) | 1135 if (event_time != 0.0) |
| 1134 navigation_state->set_request_time(Time::FromDoubleT(event_time)); | 1136 navigation_state->set_request_time(Time::FromDoubleT(event_time)); |
| 1135 } | 1137 } |
| 1136 | 1138 |
| 1137 bool is_top_most = !frame->GetParent(); | 1139 bool is_top_most = !frame->GetParent(); |
| 1138 if (is_top_most) { | 1140 if (is_top_most) { |
| 1139 navigation_gesture_ = gesture; | 1141 navigation_gesture_ = gesture; |
| 1140 | 1142 |
| 1141 // Make sure redirect tracking state is clear for the new load. | 1143 // Make sure redirect tracking state is clear for the new load. |
| 1142 completed_client_redirect_src_ = GURL(); | 1144 completed_client_redirect_src_ = GURL(); |
| 1145 } else if (frame->GetParent()->IsLoading()) { |
| 1146 // Take note of AUTO_SUBFRAME loads here, so that we can know how to |
| 1147 // load an error page. See DidFailProvisionalLoadWithError. |
| 1148 navigation_state->set_transition_type(PageTransition::AUTO_SUBFRAME); |
| 1143 } | 1149 } |
| 1144 | 1150 |
| 1145 Send(new ViewHostMsg_DidStartProvisionalLoadForFrame( | 1151 Send(new ViewHostMsg_DidStartProvisionalLoadForFrame( |
| 1146 routing_id_, is_top_most, ds->request().url())); | 1152 routing_id_, is_top_most, ds->request().url())); |
| 1147 } | 1153 } |
| 1148 | 1154 |
| 1149 bool RenderView::DidLoadResourceFromMemoryCache(WebView* webview, | 1155 bool RenderView::DidLoadResourceFromMemoryCache(WebView* webview, |
| 1150 const WebURLRequest& request, | 1156 const WebURLRequest& request, |
| 1151 const WebURLResponse& response, | 1157 const WebURLResponse& response, |
| 1152 WebFrame* frame) { | 1158 WebFrame* frame) { |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1204 show_repost_interstitial)); | 1210 show_repost_interstitial)); |
| 1205 | 1211 |
| 1206 // Don't display an error page if this is simply a cancelled load. Aside | 1212 // Don't display an error page if this is simply a cancelled load. Aside |
| 1207 // from being dumb, WebCore doesn't expect it and it will cause a crash. | 1213 // from being dumb, WebCore doesn't expect it and it will cause a crash. |
| 1208 if (error.reason == net::ERR_ABORTED) | 1214 if (error.reason == net::ERR_ABORTED) |
| 1209 return; | 1215 return; |
| 1210 | 1216 |
| 1211 // Make sure we never show errors in view source mode. | 1217 // Make sure we never show errors in view source mode. |
| 1212 frame->SetInViewSourceMode(false); | 1218 frame->SetInViewSourceMode(false); |
| 1213 | 1219 |
| 1220 NavigationState* navigation_state = NavigationState::FromDataSource(ds); |
| 1221 |
| 1214 // If this is a failed back/forward/reload navigation, then we need to do a | 1222 // If this is a failed back/forward/reload navigation, then we need to do a |
| 1215 // 'replace' load. This is necessary to avoid messing up session history. | 1223 // 'replace' load. This is necessary to avoid messing up session history. |
| 1216 // Otherwise, we do a normal load, which simulates a 'go' navigation as far | 1224 // Otherwise, we do a normal load, which simulates a 'go' navigation as far |
| 1217 // as session history is concerned. | 1225 // as session history is concerned. |
| 1218 bool replace = !NavigationState::FromDataSource(ds)->is_new_navigation(); | 1226 // |
| 1227 // AUTO_SUBFRAME loads should always be treated as loads that do not advance |
| 1228 // the page id. |
| 1229 // |
| 1230 bool replace = |
| 1231 navigation_state->pending_page_id() != -1 || |
| 1232 navigation_state->transition_type() == PageTransition::AUTO_SUBFRAME; |
| 1219 | 1233 |
| 1220 // Use the alternate error page service if this is a DNS failure or | 1234 // If we failed on a browser initiated request, then make sure that our error |
| 1221 // connection failure. ERR_CONNECTION_FAILED can be dropped once we no longer | 1235 // page load is regarded as the same browser initiated request. |
| 1222 // use winhttp. | 1236 if (!navigation_state->is_content_initiated()) { |
| 1223 int ec = error.reason; | 1237 pending_navigation_state_.reset(NavigationState::CreateBrowserInitiated( |
| 1224 if (ec == net::ERR_NAME_NOT_RESOLVED || | 1238 navigation_state->pending_page_id(), |
| 1225 ec == net::ERR_CONNECTION_FAILED || | 1239 navigation_state->transition_type(), |
| 1226 ec == net::ERR_CONNECTION_REFUSED || | 1240 navigation_state->request_time())); |
| 1227 ec == net::ERR_ADDRESS_UNREACHABLE || | |
| 1228 ec == net::ERR_TIMED_OUT) { | |
| 1229 const GURL& failed_url = error.unreachableURL; | |
| 1230 const GURL& error_page_url = GetAlternateErrorPageURL(failed_url, | |
| 1231 ec == net::ERR_NAME_NOT_RESOLVED ? WebViewDelegate::DNS_ERROR | |
| 1232 : WebViewDelegate::CONNECTION_ERROR); | |
| 1233 if (error_page_url.is_valid()) { | |
| 1234 // Ask the WebFrame to fetch the alternate error page for us. | |
| 1235 frame->LoadAlternateHTMLErrorPage(failed_request, error, error_page_url, | |
| 1236 replace, GURL(kUnreachableWebDataURL)); | |
| 1237 return; | |
| 1238 } | |
| 1239 } | 1241 } |
| 1240 | 1242 |
| 1243 // Provide the user with a more helpful error page? |
| 1244 if (MaybeLoadAlternateErrorPage(frame, error, replace)) |
| 1245 return; |
| 1246 |
| 1241 // Fallback to a local error page. | 1247 // Fallback to a local error page. |
| 1242 LoadNavigationErrorPage(frame, failed_request, error, std::string(), | 1248 LoadNavigationErrorPage(frame, failed_request, error, std::string(), |
| 1243 replace); | 1249 replace); |
| 1244 } | 1250 } |
| 1245 | 1251 |
| 1246 void RenderView::LoadNavigationErrorPage(WebFrame* frame, | 1252 void RenderView::LoadNavigationErrorPage(WebFrame* frame, |
| 1247 const WebURLRequest& failed_request, | 1253 const WebURLRequest& failed_request, |
| 1248 const WebURLError& error, | 1254 const WebURLError& error, |
| 1249 const std::string& html, | 1255 const std::string& html, |
| 1250 bool replace) { | 1256 bool replace) { |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1290 UpdateSessionHistory(frame); | 1296 UpdateSessionHistory(frame); |
| 1291 | 1297 |
| 1292 // We bump our Page ID to correspond with the new session history entry. | 1298 // We bump our Page ID to correspond with the new session history entry. |
| 1293 page_id_ = next_page_id_++; | 1299 page_id_ = next_page_id_++; |
| 1294 | 1300 |
| 1295 MessageLoop::current()->PostDelayedTask(FROM_HERE, | 1301 MessageLoop::current()->PostDelayedTask(FROM_HERE, |
| 1296 method_factory_.NewRunnableMethod(&RenderView::CapturePageInfo, | 1302 method_factory_.NewRunnableMethod(&RenderView::CapturePageInfo, |
| 1297 page_id_, true), | 1303 page_id_, true), |
| 1298 kDelayForForcedCaptureMs); | 1304 kDelayForForcedCaptureMs); |
| 1299 } else { | 1305 } else { |
| 1300 // Inspect the navigation_state on the main frame (set in our Navigate | 1306 // Inspect the navigation_state on this frame to see if the navigation |
| 1301 // method) to see if the navigation corresponds to a session history | 1307 // corresponds to a session history navigation... Note: |frame| may or |
| 1302 // navigation... Note: |frame| may or may not be the toplevel frame, but | 1308 // may not be the toplevel frame, but for the case of capturing session |
| 1303 // for the case of capturing session history, the first committed frame | 1309 // history, the first committed frame suffices. We keep track of whether |
| 1304 // suffices. We keep track of whether we've seen this commit before so | 1310 // we've seen this commit before so that only capture session history once |
| 1305 // that only capture session history once per navigation. | 1311 // per navigation. |
| 1306 // | 1312 // |
| 1307 // Note that we need to check if the page ID changed. In the case of a | 1313 // Note that we need to check if the page ID changed. In the case of a |
| 1308 // reload, the page ID doesn't change, and UpdateSessionHistory gets the | 1314 // reload, the page ID doesn't change, and UpdateSessionHistory gets the |
| 1309 // previous URL and the current page ID, which would be wrong. | 1315 // previous URL and the current page ID, which would be wrong. |
| 1310 if (!navigation_state->is_new_navigation() && | 1316 if (navigation_state->pending_page_id() != -1 && |
| 1311 !navigation_state->request_committed() && | 1317 navigation_state->pending_page_id() != page_id_ && |
| 1312 page_id_ != navigation_state->pending_page_id()) { | 1318 !navigation_state->request_committed()) { |
| 1313 // This is a successful session history navigation! | 1319 // This is a successful session history navigation! |
| 1314 UpdateSessionHistory(frame); | 1320 UpdateSessionHistory(frame); |
| 1315 page_id_ = navigation_state->pending_page_id(); | 1321 page_id_ = navigation_state->pending_page_id(); |
| 1316 } | 1322 } |
| 1317 } | 1323 } |
| 1318 | 1324 |
| 1319 // Remember that we've already processed this request, so we don't update | 1325 // Remember that we've already processed this request, so we don't update |
| 1320 // the session history again. We do this regardless of whether this is | 1326 // the session history again. We do this regardless of whether this is |
| 1321 // a session history navigation, because if we attempted a session history | 1327 // a session history navigation, because if we attempted a session history |
| 1322 // navigation without valid HistoryItem state, WebCore will think it is a | 1328 // navigation without valid HistoryItem state, WebCore will think it is a |
| (...skipping 1497 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2820 target); | 2826 target); |
| 2821 } | 2827 } |
| 2822 | 2828 |
| 2823 void RenderView::OnDisassociateFromPopupCount() { | 2829 void RenderView::OnDisassociateFromPopupCount() { |
| 2824 if (decrement_shared_popup_at_destruction_) | 2830 if (decrement_shared_popup_at_destruction_) |
| 2825 shared_popup_counter_->data--; | 2831 shared_popup_counter_->data--; |
| 2826 shared_popup_counter_ = new SharedRenderViewCounter(0); | 2832 shared_popup_counter_ = new SharedRenderViewCounter(0); |
| 2827 decrement_shared_popup_at_destruction_ = false; | 2833 decrement_shared_popup_at_destruction_ = false; |
| 2828 } | 2834 } |
| 2829 | 2835 |
| 2836 bool RenderView::MaybeLoadAlternateErrorPage(WebFrame* frame, |
| 2837 const WebURLError& error, |
| 2838 bool replace) { |
| 2839 // We only show alternate error pages in the main frame. They are |
| 2840 // intended to assist the user when navigating, so there is not much |
| 2841 // value in showing them for failed subframes. Ideally, we would be |
| 2842 // able to use the TYPED transition type for this, but that flag is |
| 2843 // not preserved across page reloads. |
| 2844 if (frame->GetParent()) |
| 2845 return false; |
| 2846 |
| 2847 // Use the alternate error page service if this is a DNS failure or |
| 2848 // connection failure. ERR_CONNECTION_FAILED can be dropped once we no |
| 2849 // longer use winhttp. |
| 2850 int ec = error.reason; |
| 2851 if (ec != net::ERR_NAME_NOT_RESOLVED && |
| 2852 ec != net::ERR_CONNECTION_FAILED && |
| 2853 ec != net::ERR_CONNECTION_REFUSED && |
| 2854 ec != net::ERR_ADDRESS_UNREACHABLE && |
| 2855 ec != net::ERR_TIMED_OUT) |
| 2856 return false; |
| 2857 |
| 2858 const GURL& error_page_url = GetAlternateErrorPageURL(error.unreachableURL, |
| 2859 ec == net::ERR_NAME_NOT_RESOLVED ? WebViewDelegate::DNS_ERROR |
| 2860 : WebViewDelegate::CONNECTION_ERROR); |
| 2861 if (!error_page_url.is_valid()) |
| 2862 return false; |
| 2863 |
| 2864 // Load an empty page first so there is an immediate response to the error, |
| 2865 // and then kick off a request for the alternate error page. |
| 2866 frame->LoadHTMLString(std::string(), |
| 2867 GURL(kUnreachableWebDataURL), |
| 2868 error.unreachableURL, |
| 2869 replace); |
| 2870 |
| 2871 // Now, create a fetcher for the error page and associate it with the data |
| 2872 // source we just created via the LoadHTMLString call. That way if another |
| 2873 // navigation occurs, the fetcher will get destroyed. |
| 2874 NavigationState* navigation_state = |
| 2875 NavigationState::FromDataSource(frame->GetProvisionalDataSource()); |
| 2876 navigation_state->set_alt_error_page_fetcher( |
| 2877 new AltErrorPageResourceFetcher( |
| 2878 error_page_url, frame, error.unreachableURL, |
| 2879 NewCallback(this, &RenderView::AltErrorPageFinished))); |
| 2880 return true; |
| 2881 } |
| 2882 |
| 2830 std::string RenderView::GetAltHTMLForTemplate( | 2883 std::string RenderView::GetAltHTMLForTemplate( |
| 2831 const DictionaryValue& error_strings, int template_resource_id) const { | 2884 const DictionaryValue& error_strings, int template_resource_id) const { |
| 2832 const StringPiece template_html( | 2885 const StringPiece template_html( |
| 2833 ResourceBundle::GetSharedInstance().GetRawDataResource( | 2886 ResourceBundle::GetSharedInstance().GetRawDataResource( |
| 2834 template_resource_id)); | 2887 template_resource_id)); |
| 2835 | 2888 |
| 2836 if (template_html.empty()) { | 2889 if (template_html.empty()) { |
| 2837 NOTREACHED() << "unable to load template. ID: " << template_resource_id; | 2890 NOTREACHED() << "unable to load template. ID: " << template_resource_id; |
| 2838 return ""; | 2891 return ""; |
| 2839 } | 2892 } |
| 2840 | 2893 |
| 2841 // "t" is the id of the templates root node. | 2894 // "t" is the id of the templates root node. |
| 2842 return jstemplate_builder::GetTemplatesHtml( | 2895 return jstemplate_builder::GetTemplatesHtml( |
| 2843 template_html, &error_strings, "t"); | 2896 template_html, &error_strings, "t"); |
| 2844 } | 2897 } |
| 2845 | 2898 |
| 2899 void RenderView::AltErrorPageFinished(WebFrame* frame, |
| 2900 const GURL& unreachable_url, |
| 2901 const std::string& html) { |
| 2902 // Here, we replace the blank page we loaded previously. |
| 2903 WebURLError error; |
| 2904 error.unreachableURL = unreachable_url; |
| 2905 LoadNavigationErrorPage(frame, WebURLRequest(), error, html, true); |
| 2906 } |
| 2907 |
| 2846 void RenderView::OnMoveOrResizeStarted() { | 2908 void RenderView::OnMoveOrResizeStarted() { |
| 2847 if (webview()) | 2909 if (webview()) |
| 2848 webview()->HideAutofillPopup(); | 2910 webview()->HideAutofillPopup(); |
| 2849 } | 2911 } |
| 2850 | 2912 |
| 2851 void RenderView::OnResize(const gfx::Size& new_size, | 2913 void RenderView::OnResize(const gfx::Size& new_size, |
| 2852 const gfx::Rect& resizer_rect) { | 2914 const gfx::Rect& resizer_rect) { |
| 2853 if (webview()) | 2915 if (webview()) |
| 2854 webview()->HideAutofillPopup(); | 2916 webview()->HideAutofillPopup(); |
| 2855 RenderWidget::OnResize(new_size, resizer_rect); | 2917 RenderWidget::OnResize(new_size, resizer_rect); |
| (...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3098 Send(new ViewHostMsg_PasswordFormsSeen(routing_id_, password_forms)); | 3160 Send(new ViewHostMsg_PasswordFormsSeen(routing_id_, password_forms)); |
| 3099 } | 3161 } |
| 3100 | 3162 |
| 3101 void RenderView::Print(WebFrame* frame, bool script_initiated) { | 3163 void RenderView::Print(WebFrame* frame, bool script_initiated) { |
| 3102 DCHECK(frame); | 3164 DCHECK(frame); |
| 3103 if (print_helper_.get() == NULL) { | 3165 if (print_helper_.get() == NULL) { |
| 3104 print_helper_.reset(new PrintWebViewHelper(this)); | 3166 print_helper_.reset(new PrintWebViewHelper(this)); |
| 3105 } | 3167 } |
| 3106 print_helper_->Print(frame, script_initiated); | 3168 print_helper_->Print(frame, script_initiated); |
| 3107 } | 3169 } |
| OLD | NEW |