summaryrefslogtreecommitdiffstats
path: root/content/renderer
diff options
context:
space:
mode:
Diffstat (limited to 'content/renderer')
-rw-r--r--content/renderer/render_view.cc53
-rw-r--r--content/renderer/render_view.h5
-rw-r--r--content/renderer/render_widget.cc36
-rw-r--r--content/renderer/render_widget.h12
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_;