engine.cc 11.9 KB
Newer Older
1 2 3 4 5 6
// 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.

#include "sky/shell/ui/engine.h"

7 8
#include <unistd.h>

9 10
#include "flutter/assets/directory_asset_bundle.h"
#include "flutter/assets/zip_asset_bundle.h"
11
#include "flutter/tonic/dart_library_provider_files.h"
12
#include "glue/movable_wrapper.h"
13 14
#include "glue/trace_event.h"
#include "lib/ftl/files/path.h"
15
#include "mojo/public/cpp/application/connect.h"
A
Adam Barth 已提交
16
#include "sky/engine/bindings/mojo_services.h"
17
#include "sky/engine/core/script/dart_init.h"
18
#include "sky/engine/core/script/ui_dart_state.h"
19
#include "sky/engine/public/platform/Platform.h"
20
#include "sky/engine/public/web/Sky.h"
21
#include "sky/shell/shell.h"
A
Adam Barth 已提交
22
#include "sky/shell/ui/animator.h"
J
Jason Simmons 已提交
23
#include "sky/shell/ui/flutter_font_selector.h"
A
Adam Barth 已提交
24
#include "sky/shell/ui/platform_impl.h"
A
Adam Barth 已提交
25 26
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkPictureRecorder.h"
27 28 29

namespace sky {
namespace shell {
30
namespace {
31

32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
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;
}

48 49
PlatformImpl* g_platform_impl = nullptr;

50 51
}  // namespace

52
Engine::Config::Config() {}
A
Adam Barth 已提交
53

54
Engine::Config::~Config() {}
A
Adam Barth 已提交
55

F
Florian Loitsch 已提交
56
Engine::Engine(const Config& config, rasterizer::RasterizerPtr rasterizer)
57
    : config_(config),
F
Florian Loitsch 已提交
58
      animator_(new Animator(config, rasterizer.Pass(), this)),
59
      binding_(this),
60 61
      activity_running_(false),
      have_surface_(false),
62
      weak_factory_(this) {}
63

64
Engine::~Engine() {}
65

66
ftl::WeakPtr<Engine> Engine::GetWeakPtr() {
67 68 69
  return weak_factory_.GetWeakPtr();
}

70
void Engine::Init() {
71
  TRACE_EVENT0("flutter", "Engine::Init");
A
Adam Barth 已提交
72

73 74 75
  DCHECK(!g_platform_impl);
  g_platform_impl = new PlatformImpl();
  blink::initialize(g_platform_impl);
76 77
}

A
Adam Barth 已提交
78
void Engine::BeginFrame(ftl::TimePoint frame_time) {
79
  TRACE_EVENT0("flutter", "Engine::BeginFrame");
80 81
  if (sky_view_)
    sky_view_->BeginFrame(frame_time);
A
Adam Barth 已提交
82 83
}

84 85 86 87 88
void Engine::RunFromSource(const std::string& main,
                           const std::string& packages,
                           const std::string& assets_directory) {
  TRACE_EVENT0("flutter", "Engine::RunFromSource");
  // Assets.
89
  ConfigureDirectoryAssetBundle(assets_directory);
90
  // .packages.
91 92 93
  std::string packages_path = packages;
  if (packages_path.empty())
    packages_path = FindPackagesPath(main);
94 95 96 97 98 99 100
  DartLibraryProviderFiles* provider = new DartLibraryProviderFiles();
  dart_library_provider_.reset(provider);
  if (!packages_path.empty())
    provider->LoadPackagesMap(packages_path);
  RunFromLibrary(main);
}

101 102 103 104 105 106 107
Dart_Port Engine::GetUIIsolateMainPort() {
  if (!sky_view_) {
    return ILLEGAL_PORT;
  }
  return sky_view_->GetMainPort();
}

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

112 113
void Engine::OnOutputSurfaceCreated(const ftl::Closure& gpu_continuation) {
  config_.gpu_task_runner->PostTask(gpu_continuation);
114 115
  have_surface_ = true;
  StartAnimatorIfPossible();
116
  if (sky_view_)
117
    ScheduleFrame();
118 119
}

120
void Engine::OnOutputSurfaceDestroyed(const ftl::Closure& gpu_continuation) {
121 122
  have_surface_ = false;
  StopAnimator();
123
  config_.gpu_task_runner->PostTask(gpu_continuation);
124 125
}

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

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

A
Adam Barth 已提交
136
  if (services_->frame_scheduler) {
137
    animator_->Reset();
A
Adam Barth 已提交
138
    animator_->set_frame_scheduler(services_->frame_scheduler.Pass());
A
Adam Barth 已提交
139
  } else {
140
#if defined(OS_ANDROID) || defined(OS_IOS) || defined(OS_MACOSX)
A
Adam Barth 已提交
141 142
    vsync::VSyncProviderPtr vsync_provider;
    if (services_->shell) {
143 144 145
      // 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());
A
Adam Barth 已提交
146 147
      mojo::ConnectToService(shell.get(), "mojo:vsync",
                             mojo::GetProxy(&vsync_provider));
148
      services_->shell = shell.Pass();
A
Adam Barth 已提交
149
    } else {
A
Adam Barth 已提交
150 151
      mojo::ConnectToService(incoming_services_.get(),
                             mojo::GetProxy(&vsync_provider));
A
Adam Barth 已提交
152
    }
153
    animator_->Reset();
A
Adam Barth 已提交
154
    animator_->set_vsync_provider(vsync_provider.Pass());
155
#endif
A
Adam Barth 已提交
156
  }
157 158
}

A
Adam Barth 已提交
159
void Engine::OnViewportMetricsChanged(ViewportMetricsPtr metrics) {
160
  viewport_metrics_ = metrics.Pass();
A
Adam Barth 已提交
161
  if (sky_view_)
162
    sky_view_->SetViewportMetrics(viewport_metrics_);
163 164
}

165
void Engine::OnLocaleChanged(const mojo::String& language_code,
166
                             const mojo::String& country_code) {
167 168 169 170 171 172
  language_code_ = language_code;
  country_code_ = country_code;
  if (sky_view_)
    sky_view_->SetLocale(language_code_, country_code_);
}

173
void Engine::OnPointerPacket(pointer::PointerPacketPtr packet) {
174
  TRACE_EVENT0("flutter", "Engine::OnPointerPacket");
175 176 177

  // Convert the pointers' x and y coordinates to logical pixels.
  for (auto it = packet->pointers.begin(); it != packet->pointers.end(); ++it) {
178 179
    (*it)->x /= viewport_metrics_->device_pixel_ratio;
    (*it)->y /= viewport_metrics_->device_pixel_ratio;
180 181 182 183
  }

  if (sky_view_)
    sky_view_->HandlePointerPacket(packet);
184 185
}

186
void Engine::RunFromLibrary(const std::string& name) {
C
Chinmay Garde 已提交
187
  TRACE_EVENT0("flutter", "Engine::RunFromLibrary");
188
  sky_view_ = blink::SkyView::Create(this);
189 190
  sky_view_->CreateView(name);
  sky_view_->RunFromLibrary(name, dart_library_provider_.get());
191
  sky_view_->SetViewportMetrics(viewport_metrics_);
192
  sky_view_->SetLocale(language_code_, country_code_);
A
Adam Barth 已提交
193 194
  if (!initial_route_.empty())
    sky_view_->PushRoute(initial_route_);
195 196
}

197
void Engine::RunFromSnapshotStream(
198
    const std::string& script_uri,
199
    mojo::ScopedDataPipeConsumerHandle snapshot) {
200
  TRACE_EVENT0("flutter", "Engine::RunFromSnapshotStream");
201
  sky_view_ = blink::SkyView::Create(this);
202 203
  sky_view_->CreateView(script_uri);
  sky_view_->RunFromSnapshot(snapshot.Pass());
204
  sky_view_->SetViewportMetrics(viewport_metrics_);
205
  sky_view_->SetLocale(language_code_, country_code_);
A
Adam Barth 已提交
206 207
  if (!initial_route_.empty())
    sky_view_->PushRoute(initial_route_);
208 209
}

210
void Engine::ConfigureZipAssetBundle(const mojo::String& path) {
211 212 213 214
  asset_store_ = ftl::MakeRefCounted<blink::ZipAssetStore>(
      path.get(), ftl::RefPtr<ftl::TaskRunner>(
                      blink::Platform::current()->GetIOTaskRunner()));
  new blink::ZipAssetBundle(mojo::GetProxy(&root_bundle_), asset_store_);
215 216
}

217 218 219 220 221
void Engine::ConfigureDirectoryAssetBundle(const std::string& path) {
  new blink::DirectoryAssetBundle(
      mojo::GetProxy(&root_bundle_), path,
      ftl::RefPtr<ftl::TaskRunner>(
          blink::Platform::current()->GetIOTaskRunner()));
222 223
}

224
void Engine::RunFromPrecompiledSnapshot(const mojo::String& bundle_path) {
C
Chinmay Garde 已提交
225
  TRACE_EVENT0("flutter", "Engine::RunFromPrecompiledSnapshot");
226

227
  ConfigureZipAssetBundle(bundle_path);
228

229
  sky_view_ = blink::SkyView::Create(this);
230
  sky_view_->CreateView("http://localhost");
231
  sky_view_->RunFromPrecompiledSnapshot();
232
  sky_view_->SetViewportMetrics(viewport_metrics_);
233
  sky_view_->SetLocale(language_code_, country_code_);
A
Adam Barth 已提交
234 235
  if (!initial_route_.empty())
    sky_view_->PushRoute(initial_route_);
236 237
}

238
void Engine::RunFromFile(const mojo::String& main,
239
                         const mojo::String& packages,
240
                         const mojo::String& bundle) {
C
Chinmay Garde 已提交
241
  TRACE_EVENT0("flutter", "Engine::RunFromFile");
242
  std::string main_dart(main);
243 244 245 246
  if (bundle.size() != 0) {
    // The specification of an FLX bundle is optional.
    ConfigureZipAssetBundle(bundle);
  }
247 248 249
  std::string packages_path = packages;
  if (packages_path.empty())
    packages_path = FindPackagesPath(main_dart);
250 251 252 253
  DartLibraryProviderFiles* provider = new DartLibraryProviderFiles();
  dart_library_provider_.reset(provider);
  if (!packages_path.empty())
    provider->LoadPackagesMap(packages_path);
254
  RunFromLibrary(main_dart);
255 256
}

257 258
void Engine::RunFromBundle(const mojo::String& script_uri,
                           const mojo::String& path) {
259
  TRACE_EVENT0("flutter", "Engine::RunFromBundle");
260

261
  ConfigureZipAssetBundle(path);
262 263 264 265
  mojo::DataPipe pipe;
  asset_store_->GetAsStream(blink::kSnapshotAssetKey,
                            std::move(pipe.producer_handle));
  RunFromSnapshotStream(script_uri, std::move(pipe.consumer_handle));
266 267
}

268 269
void Engine::RunFromBundleAndSnapshot(const mojo::String& script_uri,
                                      const mojo::String& bundle_path,
270 271
                                      const mojo::String& snapshot_path) {
  TRACE_EVENT0("flutter", "Engine::RunFromBundleAndSnapshot");
272 273

  ConfigureZipAssetBundle(bundle_path);
274

275
  asset_store_->AddOverlayFile(blink::kSnapshotAssetKey, snapshot_path);
276 277 278 279
  mojo::DataPipe pipe;
  asset_store_->GetAsStream(blink::kSnapshotAssetKey,
                            std::move(pipe.producer_handle));
  RunFromSnapshotStream(script_uri, std::move(pipe.consumer_handle));
280 281
}

A
Adam Barth 已提交
282 283 284 285 286 287 288 289 290 291 292 293
void Engine::PushRoute(const mojo::String& route) {
  if (sky_view_)
    sky_view_->PushRoute(route);
  else
    initial_route_ = route;
}

void Engine::PopRoute() {
  if (sky_view_)
    sky_view_->PopRoute();
}

294 295 296 297 298 299 300 301 302 303 304 305
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;
  }
306

307 308
  if (sky_view_)
    sky_view_->OnAppLifecycleStateChanged(state);
309 310
}

311 312 313 314 315
void Engine::DidCreateMainIsolate(Dart_Isolate isolate) {
  mojo::ServiceProviderPtr services_from_embedder;
  service_provider_bindings_.AddBinding(
      &service_provider_impl_, mojo::GetProxy(&services_from_embedder));

A
Adam Barth 已提交
316 317 318
  blink::MojoServices::Create(isolate, services_.Pass(),
                              services_from_embedder.Pass(),
                              root_bundle_.Pass());
J
Jason Simmons 已提交
319

320 321
  if (asset_store_)
    FlutterFontSelector::Install(asset_store_);
322 323
}

324 325
void Engine::DidCreateSecondaryIsolate(Dart_Isolate isolate) {
  mojo::ServiceProviderPtr services_from_embedder;
326 327
  auto request = glue::WrapMovable(mojo::GetProxy(&services_from_embedder));
  ftl::WeakPtr<Engine> engine = weak_factory_.GetWeakPtr();
328
  blink::Platform::current()->GetUITaskRunner()->PostTask(
329 330 331 332 333 334
      [engine, request]() mutable {
        if (engine)
          engine->BindToServiceProvider(request.Unwrap());
      });
  blink::MojoServices::Create(isolate, nullptr,
                              std::move(services_from_embedder), nullptr);
335 336 337 338 339 340 341 342
}

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

343 344 345 346 347 348 349 350 351
void Engine::StopAnimator() {
  animator_->Stop();
}

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

352
void Engine::ScheduleFrame() {
A
Adam Barth 已提交
353 354 355
  animator_->RequestFrame();
}

356 357 358 359
void Engine::FlushRealTimeEvents() {
  animator_->FlushRealTimeEvents();
}

360 361 362 363 364
void Engine::Render(std::unique_ptr<flow::LayerTree> layer_tree) {
  if (!layer_tree)
    return;
  if (viewport_metrics_) {
    layer_tree->set_scene_version(viewport_metrics_->scene_version);
A
Adam Barth 已提交
365 366
    layer_tree->set_frame_size(SkISize::Make(
        viewport_metrics_->physical_width, viewport_metrics_->physical_height));
367 368 369 370 371 372
  } else {
    layer_tree->set_scene_version(0);
    layer_tree->set_frame_size(SkISize::Make(0, 0));
  }
  animator_->Render(std::move(layer_tree));
}
373

374 375
}  // namespace shell
}  // namespace sky