1// Copyright (c) 2012 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 "extensions/renderer/app_window_custom_bindings.h"
6
7#include <string>
8
9#include "base/command_line.h"
10#include "content/public/renderer/render_thread.h"
11#include "content/public/renderer/render_view.h"
12#include "content/public/renderer/render_view_observer.h"
13#include "content/public/renderer/render_view_visitor.h"
14#include "content/public/renderer/v8_value_converter.h"
15#include "extensions/common/extension_messages.h"
16#include "extensions/common/switches.h"
17#include "extensions/renderer/dispatcher.h"
18#include "extensions/renderer/scoped_persistent.h"
19#include "extensions/renderer/script_context.h"
20#include "extensions/renderer/script_context_set.h"
21#include "grit/extensions_renderer_resources.h"
22#include "third_party/WebKit/public/web/WebLocalFrame.h"
23#include "third_party/WebKit/public/web/WebView.h"
24#include "ui/base/resource/resource_bundle.h"
25#include "v8/include/v8.h"
26
27namespace extensions {
28
29class DidCreateDocumentElementObserver : public content::RenderViewObserver {
30 public:
31  DidCreateDocumentElementObserver(content::RenderView* view,
32                                   Dispatcher* dispatcher)
33      : content::RenderViewObserver(view), dispatcher_(dispatcher) {}
34
35  virtual void DidCreateDocumentElement(blink::WebLocalFrame* frame) OVERRIDE {
36    DCHECK(frame);
37    DCHECK(dispatcher_);
38    // Don't attempt to inject the titlebar into iframes.
39    if (frame->parent())
40      return;
41    v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
42    ScriptContext* script_context =
43        dispatcher_->script_context_set().GetByV8Context(
44            frame->mainWorldScriptContext());
45
46    if (!script_context)
47      return;
48    v8::Context::Scope context_scope(script_context->v8_context());
49    script_context->module_system()->CallModuleMethod(
50        "injectAppTitlebar", "didCreateDocumentElement");
51  }
52
53 private:
54  Dispatcher* dispatcher_;
55};
56
57AppWindowCustomBindings::AppWindowCustomBindings(Dispatcher* dispatcher,
58                                                 ScriptContext* context)
59    : ObjectBackedNativeHandler(context), dispatcher_(dispatcher) {
60  RouteFunction("GetView",
61      base::Bind(&AppWindowCustomBindings::GetView,
62                 base::Unretained(this)));
63
64  RouteFunction("GetWindowControlsHtmlTemplate",
65      base::Bind(&AppWindowCustomBindings::GetWindowControlsHtmlTemplate,
66                 base::Unretained(this)));
67}
68
69void AppWindowCustomBindings::GetView(
70    const v8::FunctionCallbackInfo<v8::Value>& args) {
71  // TODO(jeremya): convert this to IDL nocompile to get validation, and turn
72  // these argument checks into CHECK().
73  if (args.Length() != 2)
74    return;
75
76  if (!args[0]->IsInt32())
77    return;
78
79  if (!args[1]->IsBoolean())
80    return;
81
82  int view_id = args[0]->Int32Value();
83
84  bool inject_titlebar = args[1]->BooleanValue();
85
86  if (view_id == MSG_ROUTING_NONE)
87    return;
88
89  content::RenderView* view = content::RenderView::FromRoutingID(view_id);
90  if (!view)
91    return;
92
93  if (inject_titlebar)
94    new DidCreateDocumentElementObserver(view, dispatcher_);
95
96  // TODO(jeremya): it doesn't really make sense to set the opener here, but we
97  // need to make sure the security origin is set up before returning the DOM
98  // reference. A better way to do this would be to have the browser pass the
99  // opener through so opener_id is set in RenderViewImpl's constructor.
100  content::RenderView* render_view = context()->GetRenderView();
101  if (!render_view)
102    return;
103  blink::WebFrame* opener = render_view->GetWebView()->mainFrame();
104  blink::WebFrame* frame = view->GetWebView()->mainFrame();
105  frame->setOpener(opener);
106  content::RenderThread::Get()->Send(
107      new ExtensionHostMsg_ResumeRequests(view->GetRoutingID()));
108
109  v8::Local<v8::Value> window = frame->mainWorldScriptContext()->Global();
110  args.GetReturnValue().Set(window);
111}
112
113void AppWindowCustomBindings::GetWindowControlsHtmlTemplate(
114    const v8::FunctionCallbackInfo<v8::Value>& args) {
115  CHECK_EQ(args.Length(), 0);
116
117  v8::Handle<v8::Value> result = v8::String::Empty(args.GetIsolate());
118  if (CommandLine::ForCurrentProcess()->HasSwitch(
119      switches::kEnableAppWindowControls)) {
120    base::StringValue value(
121        ResourceBundle::GetSharedInstance()
122            .GetRawDataResource(IDR_WINDOW_CONTROLS_TEMPLATE_HTML)
123            .as_string());
124    scoped_ptr<content::V8ValueConverter> converter(
125        content::V8ValueConverter::create());
126    result = converter->ToV8Value(&value, context()->v8_context());
127  }
128  args.GetReturnValue().Set(result);
129}
130
131}  // namespace extensions
132