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 "mojo/services/html_viewer/blink_platform_impl.h"
6
7#include <cmath>
8
9#include "base/rand_util.h"
10#include "base/stl_util.h"
11#include "base/synchronization/waitable_event.h"
12#include "base/threading/platform_thread.h"
13#include "base/time/time.h"
14#include "mojo/public/cpp/application/application_impl.h"
15#include "mojo/services/html_viewer/webclipboard_impl.h"
16#include "mojo/services/html_viewer/webcookiejar_impl.h"
17#include "mojo/services/html_viewer/websockethandle_impl.h"
18#include "mojo/services/html_viewer/webthread_impl.h"
19#include "mojo/services/html_viewer/weburlloader_impl.h"
20#include "net/base/data_url.h"
21#include "net/base/mime_util.h"
22#include "net/base/net_errors.h"
23#include "third_party/WebKit/public/platform/WebWaitableEvent.h"
24
25namespace mojo {
26namespace {
27
28// TODO(darin): Figure out what our UA should really be.
29const char kUserAgentString[] =
30  "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) "
31  "Chrome/35.0.1916.153 Safari/537.36";
32
33class WebWaitableEventImpl : public blink::WebWaitableEvent {
34 public:
35  WebWaitableEventImpl() : impl_(new base::WaitableEvent(false, false)) {}
36  virtual ~WebWaitableEventImpl() {}
37
38  virtual void wait() { impl_->Wait(); }
39  virtual void signal() { impl_->Signal(); }
40
41  base::WaitableEvent* impl() {
42    return impl_.get();
43  }
44
45 private:
46  scoped_ptr<base::WaitableEvent> impl_;
47  DISALLOW_COPY_AND_ASSIGN(WebWaitableEventImpl);
48};
49
50}  // namespace
51
52BlinkPlatformImpl::BlinkPlatformImpl(ApplicationImpl* app)
53    : main_loop_(base::MessageLoop::current()),
54      shared_timer_func_(NULL),
55      shared_timer_fire_time_(0.0),
56      shared_timer_fire_time_was_set_while_suspended_(false),
57      shared_timer_suspended_(0),
58      current_thread_slot_(&DestroyCurrentThread) {
59  app->ConnectToService("mojo:mojo_network_service", &network_service_);
60
61  CookieStorePtr cookie_store;
62  network_service_->GetCookieStore(Get(&cookie_store));
63  cookie_jar_.reset(new WebCookieJarImpl(cookie_store.Pass()));
64
65  ClipboardPtr clipboard;
66  app->ConnectToService("mojo:mojo_clipboard", &clipboard);
67  clipboard_.reset(new WebClipboardImpl(clipboard.Pass()));
68}
69
70BlinkPlatformImpl::~BlinkPlatformImpl() {
71}
72
73blink::WebCookieJar* BlinkPlatformImpl::cookieJar() {
74  return cookie_jar_.get();
75}
76
77blink::WebClipboard* BlinkPlatformImpl::clipboard() {
78  return clipboard_.get();
79}
80
81blink::WebMimeRegistry* BlinkPlatformImpl::mimeRegistry() {
82  return &mime_registry_;
83}
84
85blink::WebThemeEngine* BlinkPlatformImpl::themeEngine() {
86  return &theme_engine_;
87}
88
89blink::WebString BlinkPlatformImpl::defaultLocale() {
90  return blink::WebString::fromUTF8("en-US");
91}
92
93double BlinkPlatformImpl::currentTime() {
94  return base::Time::Now().ToDoubleT();
95}
96
97double BlinkPlatformImpl::monotonicallyIncreasingTime() {
98  return base::TimeTicks::Now().ToInternalValue() /
99      static_cast<double>(base::Time::kMicrosecondsPerSecond);
100}
101
102void BlinkPlatformImpl::cryptographicallyRandomValues(unsigned char* buffer,
103                                                      size_t length) {
104  base::RandBytes(buffer, length);
105}
106
107void BlinkPlatformImpl::setSharedTimerFiredFunction(void (*func)()) {
108  shared_timer_func_ = func;
109}
110
111void BlinkPlatformImpl::setSharedTimerFireInterval(
112    double interval_seconds) {
113  shared_timer_fire_time_ = interval_seconds + monotonicallyIncreasingTime();
114  if (shared_timer_suspended_) {
115    shared_timer_fire_time_was_set_while_suspended_ = true;
116    return;
117  }
118
119  // By converting between double and int64 representation, we run the risk
120  // of losing precision due to rounding errors. Performing computations in
121  // microseconds reduces this risk somewhat. But there still is the potential
122  // of us computing a fire time for the timer that is shorter than what we
123  // need.
124  // As the event loop will check event deadlines prior to actually firing
125  // them, there is a risk of needlessly rescheduling events and of
126  // needlessly looping if sleep times are too short even by small amounts.
127  // This results in measurable performance degradation unless we use ceil() to
128  // always round up the sleep times.
129  int64 interval = static_cast<int64>(
130      ceil(interval_seconds * base::Time::kMillisecondsPerSecond)
131      * base::Time::kMicrosecondsPerMillisecond);
132
133  if (interval < 0)
134    interval = 0;
135
136  shared_timer_.Stop();
137  shared_timer_.Start(FROM_HERE, base::TimeDelta::FromMicroseconds(interval),
138                      this, &BlinkPlatformImpl::DoTimeout);
139}
140
141void BlinkPlatformImpl::stopSharedTimer() {
142  shared_timer_.Stop();
143}
144
145void BlinkPlatformImpl::callOnMainThread(
146    void (*func)(void*), void* context) {
147  main_loop_->PostTask(FROM_HERE, base::Bind(func, context));
148}
149
150bool BlinkPlatformImpl::isThreadedCompositingEnabled() {
151  return true;
152}
153
154blink::WebCompositorSupport* BlinkPlatformImpl::compositorSupport() {
155  return &compositor_support_;
156}
157
158blink::WebScrollbarBehavior* BlinkPlatformImpl::scrollbarBehavior() {
159  return &scrollbar_behavior_;
160}
161
162const unsigned char* BlinkPlatformImpl::getTraceCategoryEnabledFlag(
163    const char* category_name) {
164  static const unsigned char buf[] = "*";
165  return buf;
166}
167
168blink::WebURLLoader* BlinkPlatformImpl::createURLLoader() {
169  return new WebURLLoaderImpl(network_service_.get());
170}
171
172blink::WebSocketHandle* BlinkPlatformImpl::createWebSocketHandle() {
173  return new WebSocketHandleImpl(network_service_.get());
174}
175
176blink::WebString BlinkPlatformImpl::userAgent() {
177  return blink::WebString::fromUTF8(kUserAgentString);
178}
179
180blink::WebData BlinkPlatformImpl::parseDataURL(
181    const blink::WebURL& url,
182    blink::WebString& mimetype_out,
183    blink::WebString& charset_out) {
184  std::string mimetype, charset, data;
185  if (net::DataURL::Parse(url, &mimetype, &charset, &data)
186      && net::IsSupportedMimeType(mimetype)) {
187    mimetype_out = blink::WebString::fromUTF8(mimetype);
188    charset_out = blink::WebString::fromUTF8(charset);
189    return data;
190  }
191  return blink::WebData();
192}
193
194blink::WebURLError BlinkPlatformImpl::cancelledError(const blink::WebURL& url)
195    const {
196  blink::WebURLError error;
197  error.domain = blink::WebString::fromUTF8(net::kErrorDomain);
198  error.reason = net::ERR_ABORTED;
199  error.unreachableURL = url;
200  error.staleCopyInCache = false;
201  error.isCancellation = true;
202  return error;
203}
204
205blink::WebThread* BlinkPlatformImpl::createThread(const char* name) {
206  return new WebThreadImpl(name);
207}
208
209blink::WebThread* BlinkPlatformImpl::currentThread() {
210  WebThreadImplForMessageLoop* thread =
211      static_cast<WebThreadImplForMessageLoop*>(current_thread_slot_.Get());
212  if (thread)
213    return (thread);
214
215  scoped_refptr<base::MessageLoopProxy> message_loop =
216      base::MessageLoopProxy::current();
217  if (!message_loop.get())
218    return NULL;
219
220  thread = new WebThreadImplForMessageLoop(message_loop.get());
221  current_thread_slot_.Set(thread);
222  return thread;
223}
224
225void BlinkPlatformImpl::yieldCurrentThread() {
226  base::PlatformThread::YieldCurrentThread();
227}
228
229blink::WebWaitableEvent* BlinkPlatformImpl::createWaitableEvent() {
230  return new WebWaitableEventImpl();
231}
232
233blink::WebWaitableEvent* BlinkPlatformImpl::waitMultipleEvents(
234    const blink::WebVector<blink::WebWaitableEvent*>& web_events) {
235  std::vector<base::WaitableEvent*> events;
236  for (size_t i = 0; i < web_events.size(); ++i)
237    events.push_back(static_cast<WebWaitableEventImpl*>(web_events[i])->impl());
238  size_t idx = base::WaitableEvent::WaitMany(
239      vector_as_array(&events), events.size());
240  DCHECK_LT(idx, web_events.size());
241  return web_events[idx];
242}
243
244// static
245void BlinkPlatformImpl::DestroyCurrentThread(void* thread) {
246  WebThreadImplForMessageLoop* impl =
247      static_cast<WebThreadImplForMessageLoop*>(thread);
248  delete impl;
249}
250
251}  // namespace mojo
252