web_ui_mojo.cc revision 116680a4aac90f2aa7413d9095a592090648e557
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.
4
5#include "content/renderer/web_ui_mojo.h"
6
7#include "content/common/view_messages.h"
8#include "content/public/common/service_registry.h"
9#include "content/public/renderer/render_frame.h"
10#include "content/public/renderer/render_view.h"
11#include "content/renderer/web_ui_mojo_context_state.h"
12#include "gin/per_context_data.h"
13#include "third_party/WebKit/public/web/WebKit.h"
14#include "third_party/WebKit/public/web/WebLocalFrame.h"
15#include "third_party/WebKit/public/web/WebView.h"
16#include "v8/include/v8.h"
17
18namespace content {
19
20namespace {
21
22const char kWebUIMojoContextStateKey[] = "WebUIMojoContextState";
23
24struct WebUIMojoContextStateData : public base::SupportsUserData::Data {
25  scoped_ptr<WebUIMojoContextState> state;
26};
27
28}  // namespace
29
30WebUIMojo::MainFrameObserver::MainFrameObserver(WebUIMojo* web_ui_mojo)
31    : RenderFrameObserver(RenderFrame::FromWebFrame(
32          web_ui_mojo->render_view()->GetWebView()->mainFrame())),
33      web_ui_mojo_(web_ui_mojo) {
34}
35
36WebUIMojo::MainFrameObserver::~MainFrameObserver() {
37}
38
39void WebUIMojo::MainFrameObserver::WillReleaseScriptContext(
40    v8::Handle<v8::Context> context,
41    int world_id) {
42  web_ui_mojo_->DestroyContextState(context);
43}
44
45void WebUIMojo::MainFrameObserver::DidFinishDocumentLoad() {
46  web_ui_mojo_->OnDidFinishDocumentLoad();
47}
48
49WebUIMojo::WebUIMojo(RenderView* render_view)
50    : RenderViewObserver(render_view),
51      RenderViewObserverTracker<WebUIMojo>(render_view),
52      main_frame_observer_(this),
53      did_finish_document_load_(false) {
54  CreateContextState();
55}
56
57void WebUIMojo::SetBrowserHandle(mojo::ScopedMessagePipeHandle handle) {
58  if (did_finish_document_load_)
59    SetHandleOnContextState(handle.Pass());
60  else
61    pending_handle_ = handle.Pass();
62}
63
64WebUIMojo::~WebUIMojo() {
65}
66
67void WebUIMojo::CreateContextState() {
68  v8::HandleScope handle_scope(blink::mainThreadIsolate());
69  blink::WebLocalFrame* frame =
70      render_view()->GetWebView()->mainFrame()->toWebLocalFrame();
71  v8::Handle<v8::Context> context = frame->mainWorldScriptContext();
72  gin::PerContextData* context_data = gin::PerContextData::From(context);
73  WebUIMojoContextStateData* data = new WebUIMojoContextStateData;
74  data->state.reset(new WebUIMojoContextState(
75                        render_view()->GetWebView()->mainFrame(), context));
76  context_data->SetUserData(kWebUIMojoContextStateKey, data);
77}
78
79void WebUIMojo::DestroyContextState(v8::Handle<v8::Context> context) {
80  gin::PerContextData* context_data = gin::PerContextData::From(context);
81  if (!context_data)
82    return;
83  context_data->RemoveUserData(kWebUIMojoContextStateKey);
84}
85
86void WebUIMojo::OnDidFinishDocumentLoad() {
87  did_finish_document_load_ = true;
88  mojo::MessagePipe pipe;
89  SetHandleOnContextState(pipe.handle0.Pass());
90  RenderFrame::FromWebFrame(render_view()->GetWebView()->mainFrame())->
91      GetServiceRegistry()->
92          ConnectToRemoteService("webui_controller", pipe.handle1.Pass());
93}
94
95void WebUIMojo::SetHandleOnContextState(mojo::ScopedMessagePipeHandle handle) {
96  DCHECK(did_finish_document_load_);
97  v8::HandleScope handle_scope(blink::mainThreadIsolate());
98  WebUIMojoContextState* state = GetContextState();
99  if (state)
100    state->SetHandle(handle.Pass());
101}
102
103WebUIMojoContextState* WebUIMojo::GetContextState() {
104  blink::WebLocalFrame* frame =
105      render_view()->GetWebView()->mainFrame()->toWebLocalFrame();
106  v8::HandleScope handle_scope(blink::mainThreadIsolate());
107  v8::Handle<v8::Context> context = frame->mainWorldScriptContext();
108  gin::PerContextData* context_data = gin::PerContextData::From(context);
109  if (!context_data)
110    return NULL;
111  WebUIMojoContextStateData* context_state =
112      static_cast<WebUIMojoContextStateData*>(
113          context_data->GetUserData(kWebUIMojoContextStateKey));
114  return context_state ? context_state->state.get() : NULL;
115}
116
117void WebUIMojo::DidClearWindowObject(blink::WebLocalFrame* frame) {
118  if (frame != render_view()->GetWebView()->mainFrame())
119    return;
120
121  // NOTE: this function may be called early on twice. From the constructor
122  // mainWorldScriptContext() may trigger this to be called. If we are created
123  // before the page is loaded (which is very likely), then on first load this
124  // is called. In the case of the latter we may have already supplied the
125  // handle to the context state so that if we destroy now the handle is
126  // lost. If this is the result of the first load then the contextstate should
127  // be empty and we don't need to destroy it.
128  WebUIMojoContextState* state = GetContextState();
129  if (state && !state->module_added())
130    return;
131
132  v8::HandleScope handle_scope(blink::mainThreadIsolate());
133  DestroyContextState(frame->mainWorldScriptContext());
134  CreateContextState();
135}
136
137}  // namespace content
138