engine.cc 10.8 KB
Newer Older
1 2 3 4
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5
#include "flutter/sky/shell/ui/engine.h"
6

7
#include <sys/stat.h>
8
#include <unistd.h>
9 10
#include <utility>

11
#include "flutter/assets/directory_asset_bundle.h"
A
Adam Barth 已提交
12
#include "flutter/assets/unzipper_provider.h"
13
#include "flutter/assets/zip_asset_bundle.h"
14
#include "flutter/common/threads.h"
15 16
#include "flutter/glue/movable_wrapper.h"
#include "flutter/glue/trace_event.h"
17 18 19
#include "flutter/lib/ui/mojo_services.h"
#include "flutter/runtime/dart_controller.h"
#include "flutter/runtime/dart_init.h"
20 21 22 23
#include "flutter/sky/engine/public/web/Sky.h"
#include "flutter/sky/shell/ui/animator.h"
#include "flutter/sky/shell/ui/flutter_font_selector.h"
#include "flutter/sky/shell/ui/platform_impl.h"
24 25
#include "lib/ftl/files/path.h"
#include "mojo/public/cpp/application/connect.h"
A
Adam Barth 已提交
26 27
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkPictureRecorder.h"
28 29 30

namespace sky {
namespace shell {
31
namespace {
32

33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
bool PathExists(const std::string& path) {
  return access(path.c_str(), R_OK) == 0;
}

std::string FindPackagesPath(const std::string& main_dart) {
  std::string directory = files::GetDirectoryName(main_dart);
  std::string packages_path = directory + "/.packages";
  if (!PathExists(packages_path)) {
    directory = files::GetDirectoryName(directory);
    packages_path = directory + "/.packages";
    if (!PathExists(packages_path))
      packages_path = std::string();
  }
  return packages_path;
}

49 50
PlatformImpl* g_platform_impl = nullptr;

51 52
}  // namespace

53 54
Engine::Engine(Rasterizer* rasterizer)
    : animator_(new Animator(rasterizer, this)),
55
      binding_(this),
56 57
      activity_running_(false),
      have_surface_(false),
58
      weak_factory_(this) {}
59

60
Engine::~Engine() {}
61

62
ftl::WeakPtr<Engine> Engine::GetWeakPtr() {
63 64 65
  return weak_factory_.GetWeakPtr();
}

66
void Engine::Init() {
67
  TRACE_EVENT0("flutter", "Engine::Init");
A
Adam Barth 已提交
68

69 70 71
  DCHECK(!g_platform_impl);
  g_platform_impl = new PlatformImpl();
  blink::initialize(g_platform_impl);
72
  blink::InitDartVM();
73 74
}

A
Adam Barth 已提交
75
void Engine::BeginFrame(ftl::TimePoint frame_time) {
76
  TRACE_EVENT0("flutter", "Engine::BeginFrame");
77 78
  if (runtime_)
    runtime_->BeginFrame(frame_time);
A
Adam Barth 已提交
79 80
}

81 82
void Engine::RunFromSource(const std::string& main,
                           const std::string& packages,
83
                           const std::string& bundle) {
84
  TRACE_EVENT0("flutter", "Engine::RunFromSource");
85 86 87
  std::string packages_path = packages;
  if (packages_path.empty())
    packages_path = FindPackagesPath(main);
88
  if (!bundle.empty())
89
    ConfigureAssetBundle(bundle);
90 91
  ConfigureRuntime(main);
  runtime_->dart_controller()->RunFromSource(main, packages_path);
92 93
}

94
Dart_Port Engine::GetUIIsolateMainPort() {
95
  if (!runtime_)
96
    return ILLEGAL_PORT;
97
  return runtime_->GetMainPort();
98 99
}

100 101 102 103 104 105 106
std::string Engine::GetUIIsolateName() {
  if (!runtime_) {
    return "";
  }
  return runtime_->GetIsolateName();
}

107 108
void Engine::ConnectToEngine(mojo::InterfaceRequest<SkyEngine> request) {
  binding_.Bind(request.Pass());
109 110
}

111
void Engine::OnOutputSurfaceCreated(const ftl::Closure& gpu_continuation) {
112
  blink::Threads::Gpu()->PostTask(gpu_continuation);
113 114
  have_surface_ = true;
  StartAnimatorIfPossible();
115
  if (runtime_)
116
    ScheduleFrame();
117 118
}

119
void Engine::OnOutputSurfaceDestroyed(const ftl::Closure& gpu_continuation) {
120 121
  have_surface_ = false;
  StopAnimator();
122
  blink::Threads::Gpu()->PostTask(gpu_continuation);
123 124
}

125 126 127
void Engine::SetServices(ServicesDataPtr services) {
  services_ = services.Pass();

A
Adam Barth 已提交
128
  if (services_->incoming_services) {
A
Adam Barth 已提交
129 130
    incoming_services_ =
        mojo::ServiceProviderPtr::Create(services_->incoming_services.Pass());
131
    service_provider_impl_.set_fallback_service_provider(
A
Adam Barth 已提交
132
        incoming_services_.get());
133 134
  }

135 136 137 138 139 140 141 142
  vsync::VSyncProviderPtr vsync_provider;
  if (services_->shell) {
    // We bind and unbind our Shell here, since this is the only place we use
    // it in this class.
    auto shell = mojo::ShellPtr::Create(services_->shell.Pass());
    mojo::ConnectToService(shell.get(), "mojo:vsync",
                           mojo::GetProxy(&vsync_provider));
    services_->shell = shell.Pass();
A
Adam Barth 已提交
143
  } else {
144 145
    mojo::ConnectToService(incoming_services_.get(),
                           mojo::GetProxy(&vsync_provider));
A
Adam Barth 已提交
146
  }
147
  animator_->set_vsync_provider(vsync_provider.Pass());
148 149
}

A
Adam Barth 已提交
150
void Engine::OnViewportMetricsChanged(ViewportMetricsPtr metrics) {
151
  viewport_metrics_ = metrics.Pass();
152 153
  if (runtime_)
    runtime_->SetViewportMetrics(viewport_metrics_);
154 155
}

156
void Engine::OnLocaleChanged(const mojo::String& language_code,
157
                             const mojo::String& country_code) {
158 159
  language_code_ = language_code;
  country_code_ = country_code;
160 161
  if (runtime_)
    runtime_->SetLocale(language_code_, country_code_);
162 163
}

164
void Engine::OnPointerPacket(pointer::PointerPacketPtr packet) {
165
  TRACE_EVENT0("flutter", "Engine::OnPointerPacket");
166 167 168

  // Convert the pointers' x and y coordinates to logical pixels.
  for (auto it = packet->pointers.begin(); it != packet->pointers.end(); ++it) {
169 170
    (*it)->x /= viewport_metrics_->device_pixel_ratio;
    (*it)->y /= viewport_metrics_->device_pixel_ratio;
171 172
  }

173 174
  if (runtime_)
    runtime_->HandlePointerPacket(packet);
175 176
}

177
void Engine::RunFromSnapshotStream(
178
    const std::string& script_uri,
179
    mojo::ScopedDataPipeConsumerHandle snapshot) {
180
  TRACE_EVENT0("flutter", "Engine::RunFromSnapshotStream");
181
  ConfigureRuntime(script_uri);
182 183
  snapshot_drainer_.reset(new glue::DrainDataPipeJob(
      std::move(snapshot), [this](std::vector<char> snapshot) {
184 185 186
        FTL_DCHECK(runtime_);
        FTL_DCHECK(runtime_->dart_controller());
        runtime_->dart_controller()->RunFromSnapshot(
187 188
            reinterpret_cast<uint8_t*>(snapshot.data()), snapshot.size());
      }));
189 190
}

191 192 193 194 195 196 197
void Engine::ConfigureAssetBundle(const std::string& path) {
  struct stat stat_result = {0};

  if (::stat(path.c_str(), &stat_result) != 0) {
    LOG(INFO) << "Could not configure asset bundle at path: " << path;
    return;
  }
198

199 200 201 202 203 204 205 206 207
  if (S_ISDIR(stat_result.st_mode)) {
    // Directory asset bundle.
    new blink::DirectoryAssetBundle(mojo::GetProxy(&root_bundle_), path,
                                    blink::Threads::IO());
    return;
  }

  if (S_ISREG(stat_result.st_mode)) {
    // Zip asset bundle.
A
Adam Barth 已提交
208 209
    asset_store_ = ftl::MakeRefCounted<blink::ZipAssetStore>(
        blink::GetUnzipperProviderForPath(path), blink::Threads::IO());
210 211 212
    new blink::ZipAssetBundle(mojo::GetProxy(&root_bundle_), asset_store_);
    return;
  }
213 214
}

215
void Engine::ConfigureRuntime(const std::string& script_uri) {
216
  snapshot_drainer_.reset();
217 218 219 220
  runtime_ = blink::RuntimeController::Create(this);
  runtime_->CreateDartController(std::move(script_uri));
  runtime_->SetViewportMetrics(viewport_metrics_);
  runtime_->SetLocale(language_code_, country_code_);
A
Adam Barth 已提交
221
  if (!initial_route_.empty())
222
    runtime_->PushRoute(initial_route_);
223 224
}

225 226
void Engine::RunFromPrecompiledSnapshot(const mojo::String& bundle_path) {
  TRACE_EVENT0("flutter", "Engine::RunFromPrecompiledSnapshot");
227
  ConfigureAssetBundle(bundle_path.get());
228 229
  ConfigureRuntime("http://localhost");
  runtime_->dart_controller()->RunFromPrecompiledSnapshot();
230 231
}

232
void Engine::RunFromFile(const mojo::String& main,
233
                         const mojo::String& packages,
234
                         const mojo::String& bundle) {
235
  RunFromSource(main, packages, bundle);
236 237
}

238 239
void Engine::RunFromBundle(const mojo::String& script_uri,
                           const mojo::String& path) {
240
  TRACE_EVENT0("flutter", "Engine::RunFromBundle");
241
  ConfigureAssetBundle(path);
242 243 244 245
  mojo::DataPipe pipe;
  asset_store_->GetAsStream(blink::kSnapshotAssetKey,
                            std::move(pipe.producer_handle));
  RunFromSnapshotStream(script_uri, std::move(pipe.consumer_handle));
246 247
}

248 249
void Engine::RunFromBundleAndSnapshot(const mojo::String& script_uri,
                                      const mojo::String& bundle_path,
250 251
                                      const mojo::String& snapshot_path) {
  TRACE_EVENT0("flutter", "Engine::RunFromBundleAndSnapshot");
252

253
  ConfigureAssetBundle(bundle_path);
254

255
  asset_store_->AddOverlayFile(blink::kSnapshotAssetKey, snapshot_path);
256 257 258 259
  mojo::DataPipe pipe;
  asset_store_->GetAsStream(blink::kSnapshotAssetKey,
                            std::move(pipe.producer_handle));
  RunFromSnapshotStream(script_uri, std::move(pipe.consumer_handle));
260 261
}

A
Adam Barth 已提交
262
void Engine::PushRoute(const mojo::String& route) {
263 264
  if (runtime_)
    runtime_->PushRoute(route);
A
Adam Barth 已提交
265 266 267 268 269
  else
    initial_route_ = route;
}

void Engine::PopRoute() {
270 271
  if (runtime_)
    runtime_->PopRoute();
A
Adam Barth 已提交
272 273
}

274 275 276 277 278 279 280 281 282 283 284 285
void Engine::OnAppLifecycleStateChanged(sky::AppLifecycleState state) {
  switch (state) {
    case sky::AppLifecycleState::PAUSED:
      activity_running_ = false;
      StopAnimator();
      break;

    case sky::AppLifecycleState::RESUMED:
      activity_running_ = true;
      StartAnimatorIfPossible();
      break;
  }
286

287 288
  if (runtime_)
    runtime_->OnAppLifecycleStateChanged(state);
289 290
}

291 292 293 294 295
void Engine::DidCreateMainIsolate(Dart_Isolate isolate) {
  mojo::ServiceProviderPtr services_from_embedder;
  service_provider_bindings_.AddBinding(
      &service_provider_impl_, mojo::GetProxy(&services_from_embedder));

296 297 298
  blink::MojoServices::Create(isolate, std::move(services_),
                              std::move(services_from_embedder),
                              std::move(root_bundle_));
J
Jason Simmons 已提交
299

300 301
  if (asset_store_)
    FlutterFontSelector::Install(asset_store_);
302 303
}

304 305
void Engine::DidCreateSecondaryIsolate(Dart_Isolate isolate) {
  mojo::ServiceProviderPtr services_from_embedder;
306 307
  auto request = glue::WrapMovable(mojo::GetProxy(&services_from_embedder));
  ftl::WeakPtr<Engine> engine = weak_factory_.GetWeakPtr();
308 309 310 311
  blink::Threads::UI()->PostTask([engine, request]() mutable {
    if (engine)
      engine->BindToServiceProvider(request.Unwrap());
  });
312 313
  blink::MojoServices::Create(isolate, nullptr,
                              std::move(services_from_embedder), nullptr);
314 315 316 317 318 319 320 321
}

void Engine::BindToServiceProvider(
    mojo::InterfaceRequest<mojo::ServiceProvider> request) {
  service_provider_bindings_.AddBinding(&service_provider_impl_,
                                        request.Pass());
}

322 323 324 325 326 327 328 329 330
void Engine::StopAnimator() {
  animator_->Stop();
}

void Engine::StartAnimatorIfPossible() {
  if (activity_running_ && have_surface_)
    animator_->Start();
}

331
void Engine::ScheduleFrame() {
A
Adam Barth 已提交
332 333 334
  animator_->RequestFrame();
}

335 336 337
void Engine::Render(std::unique_ptr<flow::LayerTree> layer_tree) {
  if (!layer_tree)
    return;
338 339 340 341 342 343 344 345 346 347
  if (!viewport_metrics_)
    return;

  SkISize frame_size = SkISize::Make(
      viewport_metrics_->physical_width, viewport_metrics_->physical_height);
  if (frame_size.isEmpty())
    return;

  layer_tree->set_scene_version(viewport_metrics_->scene_version);
  layer_tree->set_frame_size(frame_size);
348 349
  animator_->Render(std::move(layer_tree));
}
350

351 352
}  // namespace shell
}  // namespace sky