web_ui_mojo_context_state.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
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_context_state.h" 6 7#include "base/bind.h" 8#include "base/stl_util.h" 9#include "content/public/renderer/resource_fetcher.h" 10#include "content/renderer/web_ui_runner.h" 11#include "gin/converter.h" 12#include "gin/modules/module_registry.h" 13#include "gin/per_context_data.h" 14#include "gin/public/context_holder.h" 15#include "gin/try_catch.h" 16#include "mojo/bindings/js/core.h" 17#include "mojo/bindings/js/support.h" 18#include "third_party/WebKit/public/platform/WebURLResponse.h" 19#include "third_party/WebKit/public/web/WebFrame.h" 20#include "third_party/WebKit/public/web/WebScriptSource.h" 21 22using v8::Context; 23using v8::HandleScope; 24using v8::Isolate; 25using v8::Object; 26using v8::ObjectTemplate; 27using v8::Script; 28 29namespace content { 30 31namespace { 32 33// All modules have this prefixed to them when downloading. 34// TODO(sky): move this into some common place. 35const char kModulePrefix[] = "chrome://mojo/"; 36 37void RunMain(base::WeakPtr<gin::Runner> runner, 38 mojo::ScopedHandle* handle, 39 v8::Handle<v8::Value> module) { 40 v8::Isolate* isolate = runner->GetContextHolder()->isolate(); 41 v8::Handle<v8::Function> start; 42 CHECK(gin::ConvertFromV8(isolate, module, &start)); 43 v8::Handle<v8::Value> args[] = { 44 gin::ConvertToV8(isolate, handle->release().value()) }; 45 runner->Call(start, runner->global(), 1, args); 46} 47 48} // namespace 49 50// WebUIMojo ------------------------------------------------------------------- 51 52WebUIMojoContextState::WebUIMojoContextState(blink::WebFrame* frame, 53 v8::Handle<v8::Context> context) 54 : frame_(frame), 55 module_added_(false) { 56 gin::PerContextData* context_data = gin::PerContextData::From(context); 57 gin::ContextHolder* context_holder = context_data->context_holder(); 58 runner_.reset(new WebUIRunner(frame_, context_holder)); 59 gin::Runner::Scope scoper(runner_.get()); 60 gin::ModuleRegistry::From(context)->AddObserver(this); 61 runner_->RegisterBuiltinModules(); 62 gin::ModuleRegistry::InstallGlobals(context->GetIsolate(), context->Global()); 63 // Warning |frame| may be destroyed. 64 // TODO(sky): add test for this. 65} 66 67WebUIMojoContextState::~WebUIMojoContextState() { 68 gin::Runner::Scope scoper(runner_.get()); 69 gin::ModuleRegistry::From( 70 runner_->GetContextHolder()->context())->RemoveObserver(this); 71} 72 73void WebUIMojoContextState::SetHandle(mojo::ScopedHandle handle) { 74 gin::ContextHolder* context_holder = runner_->GetContextHolder(); 75 mojo::ScopedHandle* passed_handle = new mojo::ScopedHandle(handle.Pass()); 76 gin::ModuleRegistry::From(context_holder->context())->LoadModule( 77 context_holder->isolate(), 78 "main", 79 base::Bind(RunMain, runner_->GetWeakPtr(), base::Owned(passed_handle))); 80} 81 82void WebUIMojoContextState::FetchModules(const std::vector<std::string>& ids) { 83 gin::Runner::Scope scoper(runner_.get()); 84 gin::ContextHolder* context_holder = runner_->GetContextHolder(); 85 gin::ModuleRegistry* registry = gin::ModuleRegistry::From( 86 context_holder->context()); 87 for (size_t i = 0; i < ids.size(); ++i) { 88 if (fetched_modules_.find(ids[i]) == fetched_modules_.end() && 89 registry->available_modules().count(ids[i]) == 0) { 90 FetchModule(ids[i]); 91 } 92 } 93} 94 95void WebUIMojoContextState::FetchModule(const std::string& id) { 96 const GURL url(kModulePrefix + id); 97 // TODO(sky): better error checks here? 98 DCHECK(url.is_valid() && !url.is_empty()); 99 DCHECK(fetched_modules_.find(id) == fetched_modules_.end()); 100 fetched_modules_.insert(id); 101 ResourceFetcher* fetcher = ResourceFetcher::Create(url); 102 module_fetchers_.push_back(fetcher); 103 fetcher->Start(frame_, blink::WebURLRequest::TargetIsScript, 104 base::Bind(&WebUIMojoContextState::OnFetchModuleComplete, 105 base::Unretained(this), fetcher)); 106} 107 108void WebUIMojoContextState::OnFetchModuleComplete( 109 ResourceFetcher* fetcher, 110 const blink::WebURLResponse& response, 111 const std::string& data) { 112 DCHECK_EQ(kModulePrefix, 113 response.url().string().utf8().substr(0, arraysize(kModulePrefix) - 1)); 114 const std::string module = 115 response.url().string().utf8().substr(arraysize(kModulePrefix)); 116 // We can't delete fetch right now as the arguments to this function come from 117 // it and are used below. Instead use a scope_ptr to cleanup. 118 scoped_ptr<ResourceFetcher> deleter(fetcher); 119 module_fetchers_.weak_erase( 120 std::find(module_fetchers_.begin(), module_fetchers_.end(), fetcher)); 121 if (data.empty()) { 122 NOTREACHED(); 123 return; // TODO(sky): log something? 124 } 125 126 runner_->Run(data, module); 127} 128 129void WebUIMojoContextState::OnDidAddPendingModule( 130 const std::string& id, 131 const std::vector<std::string>& dependencies) { 132 FetchModules(dependencies); 133 134 gin::ContextHolder* context_holder = runner_->GetContextHolder(); 135 gin::ModuleRegistry* registry = gin::ModuleRegistry::From( 136 context_holder->context()); 137 registry->AttemptToLoadMoreModules(context_holder->isolate()); 138} 139 140} // namespace content 141