diff options
Diffstat (limited to 'content/renderer')
-rw-r--r-- | content/renderer/render_view.cc | 53 | ||||
-rw-r--r-- | content/renderer/render_view.h | 5 | ||||
-rw-r--r-- | content/renderer/render_widget.cc | 36 | ||||
-rw-r--r-- | content/renderer/render_widget.h | 12 |
4 files changed, 98 insertions, 8 deletions
diff --git a/content/renderer/render_view.cc b/content/renderer/render_view.cc index 63c36b4..62b1e99 100644 --- a/content/renderer/render_view.cc +++ b/content/renderer/render_view.cc @@ -632,6 +632,7 @@ bool RenderView::OnMessageReceived(const IPC::Message& message) { OnEnumerateDirectoryResponse) IPC_MESSAGE_HANDLER(ViewMsg_RunFileChooserResponse, OnFileChooserResponse) IPC_MESSAGE_HANDLER(ViewMsg_ShouldClose, OnShouldClose) + IPC_MESSAGE_HANDLER(ViewMsg_SwapOut, OnSwapOut) IPC_MESSAGE_HANDLER(ViewMsg_ClosePage, OnClosePage) IPC_MESSAGE_HANDLER(ViewMsg_ThemeChanged, OnThemeChanged) IPC_MESSAGE_HANDLER(ViewMsg_DisassociateFromPopupCount, @@ -685,6 +686,10 @@ void RenderView::OnNavigate(const ViewMsg_Navigate_Params& params) { if (!webview()) return; + // Swap this renderer back in if necessary. + if (is_swapped_out_) + SetSwappedOut(false); + history_list_offset_ = params.current_history_list_offset; history_list_length_ = params.current_history_list_length; @@ -1564,6 +1569,12 @@ bool RenderView::runModalPromptDialog( bool RenderView::runModalBeforeUnloadDialog( WebFrame* frame, const WebString& message) { + // If we are swapping out, we have already run the beforeunload handler. + // TODO(creis): Fix OnSwapOut to clear the frame without running beforeunload + // at all, to avoid running it twice. + if (is_swapped_out_) + return true; + bool success = false; // This is an ignored return value, but is included so we can accept the same // response as RunJavaScriptMessage. @@ -1926,6 +1937,12 @@ void RenderView::loadURLExternally( WebNavigationPolicy RenderView::decidePolicyForNavigation( WebFrame* frame, const WebURLRequest& request, WebNavigationType type, const WebNode&, WebNavigationPolicy default_policy, bool is_redirect) { + // TODO(creis): Remove this when we fix OnSwapOut to not need a navigation. + if (is_swapped_out_) { + DCHECK(request.url() == GURL("about:swappedout")); + return default_policy; + } + // 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. @@ -3510,7 +3527,38 @@ void RenderView::OnShouldClose() { Send(new ViewHostMsg_ShouldClose_ACK(routing_id_, should_close)); } -void RenderView::OnClosePage(const ViewMsg_ClosePage_Params& params) { +void RenderView::OnSwapOut(const ViewMsg_SwapOut_Params& params) { + if (is_swapped_out_) + return; + + // Swap this RenderView out so the tab can navigate to a page rendered by a + // different process. This involves running the unload handler and clearing + // the page. Once WasSwappedOut is called, we also allow this process to exit + // if there are no other active RenderViews in it. + + // Send an UpdateState message before we get swapped out. + SyncNavigationState(); + + // Synchronously run the unload handler before sending the ACK. + webview()->dispatchUnloadEvent(); + + // Swap out and stop sending any IPC messages that are not ACKs. + SetSwappedOut(true); + + // Replace the page with a blank dummy URL. The unload handler will not be + // run a second time, thanks to a check in FrameLoader::stopLoading. + // TODO(creis): Need to add a better way to do this that avoids running the + // beforeunload handler. For now, we just run it a second time silently. + webview()->mainFrame()->loadHTMLString(std::string(), + GURL("about:swappedout"), + GURL("about:swappedout"), + false); + + // Just echo back the params in the ACK. + Send(new ViewHostMsg_SwapOut_ACK(routing_id_, params)); +} + +void RenderView::OnClosePage() { // TODO(creis): We'd rather use webview()->Close() here, but that currently // sets the WebView's delegate_ to NULL, preventing any JavaScript dialogs // in the onunload handler from appearing. For now, we're bypassing that and @@ -3520,8 +3568,7 @@ void RenderView::OnClosePage(const ViewMsg_ClosePage_Params& params) { // http://b/issue?id=753080. webview()->dispatchUnloadEvent(); - // Just echo back the params in the ACK. - Send(new ViewHostMsg_ClosePage_ACK(routing_id_, params)); + Send(new ViewHostMsg_ClosePage_ACK(routing_id_)); } void RenderView::OnThemeChanged() { diff --git a/content/renderer/render_view.h b/content/renderer/render_view.h index 4cdf0e2..a5c7f28 100644 --- a/content/renderer/render_view.h +++ b/content/renderer/render_view.h @@ -71,7 +71,7 @@ class WebUIBindings; struct ContextMenuMediaParams; struct PP_Flash_NetAddress; struct ViewHostMsg_RunFileChooser_Params; -struct ViewMsg_ClosePage_Params; +struct ViewMsg_SwapOut_Params; struct ViewMsg_Navigate_Params; struct ViewMsg_StopFinding_Params; struct WebDropData; @@ -710,7 +710,7 @@ class RenderView : public RenderWidget, IPC::ChannelHandle handle); void OnCancelDownload(int32 download_id); void OnClearFocusedNode(); - void OnClosePage(const ViewMsg_ClosePage_Params& params); + void OnClosePage(); #if defined(ENABLE_FLAPPER_HACKS) void OnConnectTcpACK(int request_id, IPC::PlatformFileForTransit socket_for_transit, @@ -796,6 +796,7 @@ class RenderView : public RenderWidget, void OnShouldClose(); void OnStop(); void OnStopFinding(const ViewMsg_StopFinding_Params& params); + void OnSwapOut(const ViewMsg_SwapOut_Params& params); void OnThemeChanged(); void OnUndo(); void OnUpdateTargetURLAck(); diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc index 2597ad6..7572b7e 100644 --- a/content/renderer/render_widget.cc +++ b/content/renderer/render_widget.cc @@ -12,6 +12,7 @@ #include "base/metrics/histogram.h" #include "build/build_config.h" #include "content/common/content_switches.h" +#include "content/common/swapped_out_messages.h" #include "content/common/view_messages.h" #include "content/renderer/render_process.h" #include "content/renderer/render_thread.h" @@ -74,6 +75,7 @@ RenderWidget::RenderWidget(RenderThreadBase* render_thread, has_focus_(false), handling_input_event_(false), closing_(false), + is_swapped_out_(false), input_method_is_active_(false), text_input_type_(WebKit::WebTextInputTypeNone), popup_type_(popup_type), @@ -92,7 +94,9 @@ RenderWidget::~RenderWidget() { RenderProcess::current()->ReleaseTransportDIB(current_paint_buf_); current_paint_buf_ = NULL; } - RenderProcess::current()->ReleaseProcess(); + // If we are swapped out, we have released already. + if (!is_swapped_out_) + RenderProcess::current()->ReleaseProcess(); } // static @@ -160,6 +164,20 @@ void RenderWidget::CompleteInit(gfx::NativeViewId parent_hwnd, Send(new ViewHostMsg_RenderViewReady(routing_id_)); } +void RenderWidget::SetSwappedOut(bool is_swapped_out) { + // We should only toggle between states. + DCHECK(is_swapped_out_ != is_swapped_out); + is_swapped_out_ = is_swapped_out; + + // If we are swapping out, we will call ReleaseProcess, allowing the process + // to exit if all of its RenderViews are swapped out. We wait until the + // WasSwappedOut call to do this, to avoid showing the sad tab. + // If we are swapping in, we call AddRefProcess to prevent the process from + // exiting. + if (!is_swapped_out) + RenderProcess::current()->AddRefProcess(); +} + bool RenderWidget::OnMessageReceived(const IPC::Message& message) { bool handled = true; IPC_BEGIN_MESSAGE_MAP(RenderWidget, message) @@ -168,6 +186,7 @@ bool RenderWidget::OnMessageReceived(const IPC::Message& message) { IPC_MESSAGE_HANDLER(ViewMsg_Resize, OnResize) IPC_MESSAGE_HANDLER(ViewMsg_WasHidden, OnWasHidden) IPC_MESSAGE_HANDLER(ViewMsg_WasRestored, OnWasRestored) + IPC_MESSAGE_HANDLER(ViewMsg_WasSwappedOut, OnWasSwappedOut) IPC_MESSAGE_HANDLER(ViewMsg_UpdateRect_ACK, OnUpdateRectAck) IPC_MESSAGE_HANDLER(ViewMsg_HandleInputEvent, OnHandleInputEvent) IPC_MESSAGE_HANDLER(ViewMsg_MouseCaptureLost, OnMouseCaptureLost) @@ -185,8 +204,11 @@ bool RenderWidget::OnMessageReceived(const IPC::Message& message) { } bool RenderWidget::Send(IPC::Message* message) { - // Don't send any messages after the browser has told us to close. - if (closing_) { + // Don't send any messages after the browser has told us to close, and filter + // most outgoing messages while swapped out. + if ((is_swapped_out_ && + !content::SwappedOutMessages::CanSendWhileSwappedOut(message)) || + closing_) { delete message; return false; } @@ -299,6 +321,14 @@ void RenderWidget::OnWasRestored(bool needs_repainting) { } } +void RenderWidget::OnWasSwappedOut() { + // If we have been swapped out and no one else is using this process, + // it's safe to exit now. If we get swapped back in, we will call + // AddRefProcess in SetSwappedOut. + if (is_swapped_out_) + RenderProcess::current()->ReleaseProcess(); +} + void RenderWidget::OnRequestMoveAck() { DCHECK(pending_window_rect_count_); pending_window_rect_count_--; diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h index 63580c7..74944f6 100644 --- a/content/renderer/render_widget.h +++ b/content/renderer/render_widget.h @@ -154,6 +154,12 @@ class RenderWidget : public IPC::Channel::Listener, void CompleteInit(gfx::NativeViewId parent, gfx::PluginWindowHandle compositing_surface); + // Sets whether this RenderWidget has been swapped out to be displayed by + // a RenderWidget in a different process. If so, no new IPC messages will be + // sent (only ACKs) and the process is free to exit when there are no other + // active RenderWidgets. + void SetSwappedOut(bool is_swapped_out); + // Paints the given rectangular region of the WebWidget into canvas (a // shared memory segment returned by AllocPaintBuf on Windows). The caller // must ensure that the given rect fits within the bounds of the WebWidget. @@ -183,6 +189,7 @@ class RenderWidget : public IPC::Channel::Listener, const gfx::Rect& resizer_rect); virtual void OnWasHidden(); virtual void OnWasRestored(bool needs_repainting); + virtual void OnWasSwappedOut(); void OnUpdateRectAck(); void OnCreateVideoAck(int32 video_id); void OnUpdateVideoAck(int32 video_id); @@ -343,6 +350,11 @@ class RenderWidget : public IPC::Channel::Listener, // be sent, except for a Close. bool closing_; + // Whether this RenderWidget is currently swapped out, such that the view is + // being rendered by another process. If all RenderWidgets in a process are + // swapped out, the process can exit. + bool is_swapped_out_; + // Indicates if an input method is active in the browser process. bool input_method_is_active_; |