engine.cc 13.1 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/shell/common/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
#include "flutter/lib/ui/mojo_services.h"
18
#include "flutter/runtime/asset_font_selector.h"
19 20
#include "flutter/runtime/dart_controller.h"
#include "flutter/runtime/dart_init.h"
21
#include "flutter/runtime/runtime_init.h"
22
#include "flutter/shell/common/animator.h"
23
#include "flutter/sky/engine/public/web/Sky.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

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 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
blink::PointerData::Change GetChangeFromPointerType(pointer::PointerType type) {
  switch (type) {
    case pointer::PointerType::DOWN:
      return blink::PointerData::Change::kDown;
    case pointer::PointerType::UP:
      return blink::PointerData::Change::kUp;
    case pointer::PointerType::MOVE:
      return blink::PointerData::Change::kMove;
    case pointer::PointerType::CANCEL:
      return blink::PointerData::Change::kCancel;
  }
  FTL_NOTREACHED();
  return blink::PointerData::Change::kCancel;
}

blink::PointerData::DeviceKind GetDeviceKindFromPointerKind(
    pointer::PointerKind kind) {
  switch (kind) {
    case pointer::PointerKind::TOUCH:
      return blink::PointerData::DeviceKind::kTouch;
    case pointer::PointerKind::MOUSE:
      return blink::PointerData::DeviceKind::kMouse;
    case pointer::PointerKind::STYLUS:
      return blink::PointerData::DeviceKind::kStylus;
    case pointer::PointerKind::INVERTED_STYLUS:
      return blink::PointerData::DeviceKind::kInvertedStylus;
  }
  FTL_NOTREACHED();
  return blink::PointerData::DeviceKind::kTouch;
}

79 80
}  // namespace

81 82
Engine::Engine(Rasterizer* rasterizer)
    : animator_(new Animator(rasterizer, this)),
83
      binding_(this),
84 85
      activity_running_(false),
      have_surface_(false),
86
      weak_factory_(this) {}
87

88
Engine::~Engine() {}
89

90
ftl::WeakPtr<Engine> Engine::GetWeakPtr() {
91 92 93
  return weak_factory_.GetWeakPtr();
}

94
void Engine::Init() {
95
  blink::InitRuntime();
96 97
}

A
Adam Barth 已提交
98
void Engine::BeginFrame(ftl::TimePoint frame_time) {
99
  TRACE_EVENT0("flutter", "Engine::BeginFrame");
100 101
  if (runtime_)
    runtime_->BeginFrame(frame_time);
A
Adam Barth 已提交
102 103
}

104 105
void Engine::RunFromSource(const std::string& main,
                           const std::string& packages,
106
                           const std::string& bundle) {
107
  TRACE_EVENT0("flutter", "Engine::RunFromSource");
108 109 110
  std::string packages_path = packages;
  if (packages_path.empty())
    packages_path = FindPackagesPath(main);
111
  if (!bundle.empty())
112
    ConfigureAssetBundle(bundle);
113 114
  ConfigureRuntime(main);
  runtime_->dart_controller()->RunFromSource(main, packages_path);
115 116
}

117
Dart_Port Engine::GetUIIsolateMainPort() {
118
  if (!runtime_)
119
    return ILLEGAL_PORT;
120
  return runtime_->GetMainPort();
121 122
}

123 124 125 126 127 128 129
std::string Engine::GetUIIsolateName() {
  if (!runtime_) {
    return "";
  }
  return runtime_->GetIsolateName();
}

130 131
void Engine::ConnectToEngine(mojo::InterfaceRequest<SkyEngine> request) {
  binding_.Bind(request.Pass());
132 133
}

134
void Engine::OnOutputSurfaceCreated(const ftl::Closure& gpu_continuation) {
135
  blink::Threads::Gpu()->PostTask(gpu_continuation);
136 137
  have_surface_ = true;
  StartAnimatorIfPossible();
138
  if (runtime_)
139
    ScheduleFrame();
140 141
}

142
void Engine::OnOutputSurfaceDestroyed(const ftl::Closure& gpu_continuation) {
143 144
  have_surface_ = false;
  StopAnimator();
145
  blink::Threads::Gpu()->PostTask(gpu_continuation);
146 147
}

148
void Engine::SetServices(sky::ServicesDataPtr services) {
149 150
  services_ = services.Pass();

A
Adam Barth 已提交
151
  if (services_->incoming_services) {
A
Adam Barth 已提交
152 153
    incoming_services_ =
        mojo::ServiceProviderPtr::Create(services_->incoming_services.Pass());
154
    service_provider_impl_.set_fallback_service_provider(
A
Adam Barth 已提交
155
        incoming_services_.get());
156 157
  }

158 159
  vsync::VSyncProviderPtr vsync_provider;
  if (services_->shell) {
160 161
    // We bind and unbind our Shell here, since this is the only place we
    // use
162 163 164 165 166
    // 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 已提交
167
  } else {
168 169
    mojo::ConnectToService(incoming_services_.get(),
                           mojo::GetProxy(&vsync_provider));
A
Adam Barth 已提交
170
  }
171
  animator_->set_vsync_provider(vsync_provider.Pass());
172 173
}

174
void Engine::OnViewportMetricsChanged(sky::ViewportMetricsPtr metrics) {
175
  viewport_metrics_ = metrics.Pass();
176 177
  if (runtime_)
    runtime_->SetViewportMetrics(viewport_metrics_);
178 179
}

180
void Engine::OnLocaleChanged(const mojo::String& language_code,
181
                             const mojo::String& country_code) {
182 183
  language_code_ = language_code;
  country_code_ = country_code;
184 185
  if (runtime_)
    runtime_->SetLocale(language_code_, country_code_);
186 187
}

188 189
void Engine::DispatchPointerDataPacket(const PointerDataPacket& packet) {
  TRACE_EVENT0("flutter", "Engine::DispatchPointerDataPacket");
190
  if (runtime_)
191
    runtime_->DispatchPointerDataPacket(packet);
192 193 194 195
}

// TODO(abarth): Remove pointer::PointerPacketPtr and route PointerDataPacket
// here.
196
void Engine::OnPointerPacket(pointer::PointerPacketPtr packetPtr) {
197
  TRACE_EVENT0("flutter", "Engine::OnPointerPacket");
198 199
  if (runtime_) {
    const size_t length = packetPtr->pointers.size();
200
    PointerDataPacket packet(length);
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
    for (size_t i = 0; i < length; ++i) {
      const pointer::PointerPtr& pointer = packetPtr->pointers[i];
      blink::PointerData pointer_data;
      pointer_data.time_stamp = pointer->time_stamp;
      pointer_data.pointer = pointer->pointer;
      pointer_data.change = GetChangeFromPointerType(pointer->type);
      pointer_data.kind = GetDeviceKindFromPointerKind(pointer->kind);
      pointer_data.physical_x = pointer->x;
      pointer_data.physical_y = pointer->y;
      pointer_data.buttons = pointer->buttons;
      pointer_data.obscured = pointer->obscured ? 1 : 0;
      pointer_data.pressure = pointer->pressure;
      pointer_data.pressure_min = pointer->pressure_min;
      pointer_data.pressure_max = pointer->pressure_max;
      pointer_data.distance = pointer->distance;
      pointer_data.distance_max = pointer->distance_max;
      pointer_data.radius_major = pointer->radius_major;
      pointer_data.radius_minor = pointer->radius_minor;
      pointer_data.radius_min = pointer->radius_min;
      pointer_data.radius_max = pointer->radius_max;
      pointer_data.orientation = pointer->orientation;
      pointer_data.tilt = pointer->tilt;
      packet.SetPointerData(i, pointer_data);
    }
225
    runtime_->DispatchPointerDataPacket(packet);
226
  }
227 228
}

229
void Engine::RunFromSnapshotStream(
230
    const std::string& script_uri,
231
    mojo::ScopedDataPipeConsumerHandle snapshot) {
232
  TRACE_EVENT0("flutter", "Engine::RunFromSnapshotStream");
233
  ConfigureRuntime(script_uri);
234 235
  snapshot_drainer_.reset(new glue::DrainDataPipeJob(
      std::move(snapshot), [this](std::vector<char> snapshot) {
236 237 238
        FTL_DCHECK(runtime_);
        FTL_DCHECK(runtime_->dart_controller());
        runtime_->dart_controller()->RunFromSnapshot(
239 240
            reinterpret_cast<uint8_t*>(snapshot.data()), snapshot.size());
      }));
241 242
}

243 244 245 246 247 248 249
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;
  }
250

251 252 253 254 255 256 257 258 259
  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 已提交
260 261
    asset_store_ = ftl::MakeRefCounted<blink::ZipAssetStore>(
        blink::GetUnzipperProviderForPath(path), blink::Threads::IO());
262 263 264
    new blink::ZipAssetBundle(mojo::GetProxy(&root_bundle_), asset_store_);
    return;
  }
265 266
}

267
void Engine::ConfigureRuntime(const std::string& script_uri) {
268
  snapshot_drainer_.reset();
269 270 271 272
  runtime_ = blink::RuntimeController::Create(this);
  runtime_->CreateDartController(std::move(script_uri));
  runtime_->SetViewportMetrics(viewport_metrics_);
  runtime_->SetLocale(language_code_, country_code_);
A
Adam Barth 已提交
273
  if (!initial_route_.empty())
274
    runtime_->PushRoute(initial_route_);
275 276
}

277 278
void Engine::RunFromPrecompiledSnapshot(const mojo::String& bundle_path) {
  TRACE_EVENT0("flutter", "Engine::RunFromPrecompiledSnapshot");
279
  ConfigureAssetBundle(bundle_path.get());
280 281
  ConfigureRuntime("http://localhost");
  runtime_->dart_controller()->RunFromPrecompiledSnapshot();
282 283
}

284
void Engine::RunFromFile(const mojo::String& main,
285
                         const mojo::String& packages,
286
                         const mojo::String& bundle) {
287
  RunFromSource(main, packages, bundle);
288 289
}

290 291
void Engine::RunFromBundle(const mojo::String& script_uri,
                           const mojo::String& path) {
292
  TRACE_EVENT0("flutter", "Engine::RunFromBundle");
293
  ConfigureAssetBundle(path);
294 295 296 297
  mojo::DataPipe pipe;
  asset_store_->GetAsStream(blink::kSnapshotAssetKey,
                            std::move(pipe.producer_handle));
  RunFromSnapshotStream(script_uri, std::move(pipe.consumer_handle));
298 299
}

300 301
void Engine::RunFromBundleAndSnapshot(const mojo::String& script_uri,
                                      const mojo::String& bundle_path,
302 303
                                      const mojo::String& snapshot_path) {
  TRACE_EVENT0("flutter", "Engine::RunFromBundleAndSnapshot");
304

305
  ConfigureAssetBundle(bundle_path);
306

307
  asset_store_->AddOverlayFile(blink::kSnapshotAssetKey, snapshot_path);
308 309 310 311
  mojo::DataPipe pipe;
  asset_store_->GetAsStream(blink::kSnapshotAssetKey,
                            std::move(pipe.producer_handle));
  RunFromSnapshotStream(script_uri, std::move(pipe.consumer_handle));
312 313
}

A
Adam Barth 已提交
314
void Engine::PushRoute(const mojo::String& route) {
315 316
  if (runtime_)
    runtime_->PushRoute(route);
A
Adam Barth 已提交
317 318 319 320 321
  else
    initial_route_ = route;
}

void Engine::PopRoute() {
322 323
  if (runtime_)
    runtime_->PopRoute();
A
Adam Barth 已提交
324 325
}

326 327 328 329 330 331 332 333 334 335 336 337
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;
  }
338

339 340
  if (runtime_)
    runtime_->OnAppLifecycleStateChanged(state);
341 342
}

343 344 345 346 347
void Engine::DidCreateMainIsolate(Dart_Isolate isolate) {
  mojo::ServiceProviderPtr services_from_embedder;
  service_provider_bindings_.AddBinding(
      &service_provider_impl_, mojo::GetProxy(&services_from_embedder));

348 349 350
  blink::MojoServices::Create(isolate, std::move(services_),
                              std::move(services_from_embedder),
                              std::move(root_bundle_));
J
Jason Simmons 已提交
351

352
  if (asset_store_)
353
    blink::AssetFontSelector::Install(asset_store_);
354 355
}

356 357
void Engine::DidCreateSecondaryIsolate(Dart_Isolate isolate) {
  mojo::ServiceProviderPtr services_from_embedder;
358 359
  auto request = glue::WrapMovable(mojo::GetProxy(&services_from_embedder));
  ftl::WeakPtr<Engine> engine = weak_factory_.GetWeakPtr();
360 361 362 363
  blink::Threads::UI()->PostTask([engine, request]() mutable {
    if (engine)
      engine->BindToServiceProvider(request.Unwrap());
  });
364 365
  blink::MojoServices::Create(isolate, nullptr,
                              std::move(services_from_embedder), nullptr);
366 367 368 369 370 371 372 373
}

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

374 375 376 377 378 379 380 381 382
void Engine::StopAnimator() {
  animator_->Stop();
}

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

383
void Engine::ScheduleFrame() {
A
Adam Barth 已提交
384 385 386
  animator_->RequestFrame();
}

387 388 389
void Engine::Render(std::unique_ptr<flow::LayerTree> layer_tree) {
  if (!layer_tree)
    return;
390 391 392
  if (!viewport_metrics_)
    return;

393 394
  SkISize frame_size = SkISize::Make(viewport_metrics_->physical_width,
                                     viewport_metrics_->physical_height);
395 396 397 398 399
  if (frame_size.isEmpty())
    return;

  layer_tree->set_scene_version(viewport_metrics_->scene_version);
  layer_tree->set_frame_size(frame_size);
400 401
  animator_->Render(std::move(layer_tree));
}
402

403 404
void Engine::UpdateSemantics(std::vector<blink::SemanticsNode> update) {}

405
}  // namespace shell