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