1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/renderer/web_ui_mojo.h"
7 #include "content/common/view_messages.h"
8 #include "content/public/renderer/render_frame.h"
9 #include "content/public/renderer/render_view.h"
10 #include "content/renderer/web_ui_mojo_context_state.h"
11 #include "gin/per_context_data.h"
12 #include "third_party/WebKit/public/web/WebKit.h"
13 #include "third_party/WebKit/public/web/WebLocalFrame.h"
14 #include "third_party/WebKit/public/web/WebView.h"
15 #include "v8/include/v8.h"
21 const char kWebUIMojoContextStateKey
[] = "WebUIMojoContextState";
23 struct WebUIMojoContextStateData
: public base::SupportsUserData::Data
{
24 scoped_ptr
<WebUIMojoContextState
> state
;
29 WebUIMojo::MainFrameObserver::MainFrameObserver(WebUIMojo
* web_ui_mojo
)
30 : RenderFrameObserver(RenderFrame::FromWebFrame(
31 web_ui_mojo
->render_view()->GetWebView()->mainFrame())),
32 web_ui_mojo_(web_ui_mojo
) {
35 WebUIMojo::MainFrameObserver::~MainFrameObserver() {
38 void WebUIMojo::MainFrameObserver::WillReleaseScriptContext(
39 v8::Handle
<v8::Context
> context
,
41 web_ui_mojo_
->DestroyContextState(context
);
44 void WebUIMojo::MainFrameObserver::DidFinishDocumentLoad() {
45 web_ui_mojo_
->OnDidFinishDocumentLoad();
48 WebUIMojo::WebUIMojo(RenderView
* render_view
)
49 : RenderViewObserver(render_view
),
50 RenderViewObserverTracker
<WebUIMojo
>(render_view
),
51 main_frame_observer_(this),
52 did_finish_document_load_(false) {
56 void WebUIMojo::SetBrowserHandle(mojo::ScopedMessagePipeHandle handle
) {
57 if (did_finish_document_load_
)
58 SetHandleOnContextState(handle
.Pass());
60 pending_handle_
= handle
.Pass();
63 WebUIMojo::~WebUIMojo() {
66 void WebUIMojo::CreateContextState() {
67 v8::HandleScope
handle_scope(blink::mainThreadIsolate());
68 blink::WebLocalFrame
* frame
=
69 render_view()->GetWebView()->mainFrame()->toWebLocalFrame();
70 v8::Handle
<v8::Context
> context
= frame
->mainWorldScriptContext();
71 gin::PerContextData
* context_data
= gin::PerContextData::From(context
);
72 WebUIMojoContextStateData
* data
= new WebUIMojoContextStateData
;
73 data
->state
.reset(new WebUIMojoContextState(
74 render_view()->GetWebView()->mainFrame(), context
));
75 context_data
->SetUserData(kWebUIMojoContextStateKey
, data
);
78 void WebUIMojo::DestroyContextState(v8::Handle
<v8::Context
> context
) {
79 gin::PerContextData
* context_data
= gin::PerContextData::From(context
);
82 context_data
->RemoveUserData(kWebUIMojoContextStateKey
);
85 void WebUIMojo::OnDidFinishDocumentLoad() {
86 did_finish_document_load_
= true;
87 if (pending_handle_
.is_valid())
88 SetHandleOnContextState(pending_handle_
.Pass());
91 void WebUIMojo::SetHandleOnContextState(mojo::ScopedMessagePipeHandle handle
) {
92 DCHECK(did_finish_document_load_
);
93 v8::HandleScope
handle_scope(blink::mainThreadIsolate());
94 WebUIMojoContextState
* state
= GetContextState();
96 state
->SetHandle(handle
.Pass());
99 WebUIMojoContextState
* WebUIMojo::GetContextState() {
100 blink::WebLocalFrame
* frame
=
101 render_view()->GetWebView()->mainFrame()->toWebLocalFrame();
102 v8::HandleScope
handle_scope(blink::mainThreadIsolate());
103 v8::Handle
<v8::Context
> context
= frame
->mainWorldScriptContext();
104 gin::PerContextData
* context_data
= gin::PerContextData::From(context
);
107 WebUIMojoContextStateData
* context_state
=
108 static_cast<WebUIMojoContextStateData
*>(
109 context_data
->GetUserData(kWebUIMojoContextStateKey
));
110 return context_state
? context_state
->state
.get() : NULL
;
113 void WebUIMojo::DidClearWindowObject(blink::WebLocalFrame
* frame
,
115 if (frame
!= render_view()->GetWebView()->mainFrame())
118 // NOTE: this function may be called early on twice. From the constructor
119 // mainWorldScriptContext() may trigger this to be called. If we are created
120 // before the page is loaded (which is very likely), then on first load this
121 // is called. In the case of the latter we may have already supplied the
122 // handle to the context state so that if we destroy now the handle is
123 // lost. If this is the result of the first load then the contextstate should
124 // be empty and we don't need to destroy it.
125 WebUIMojoContextState
* state
= GetContextState();
126 if (state
&& !state
->module_added())
129 v8::HandleScope
handle_scope(blink::mainThreadIsolate());
130 DestroyContextState(frame
->mainWorldScriptContext());
131 CreateContextState();
134 } // namespace content