window.cc 15.4 KB
Newer Older
M
Michael Goderbauer 已提交
1
// Copyright 2013 The Flutter Authors. All rights reserved.
2 3 4
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5
#include "flutter/lib/ui/window/window.h"
6

7
#include "flutter/lib/ui/compositing/scene.h"
8
#include "flutter/lib/ui/ui_dart_state.h"
A
Adam Barth 已提交
9
#include "flutter/lib/ui/window/platform_message_response_dart.h"
10 11 12 13 14 15
#include "third_party/tonic/converter/dart_converter.h"
#include "third_party/tonic/dart_args.h"
#include "third_party/tonic/dart_library_natives.h"
#include "third_party/tonic/dart_microtask_queue.h"
#include "third_party/tonic/logging/dart_invoke.h"
#include "third_party/tonic/typed_data/dart_byte_data.h"
16

17
namespace flutter {
18 19
namespace {

20
void DefaultRouteName(Dart_NativeArguments args) {
21
  UIDartState::ThrowIfUIOperationsProhibited();
22 23
  std::string routeName =
      UIDartState::Current()->window()->client()->DefaultRouteName();
24
  Dart_SetReturnValue(args, tonic::StdStringToDart(routeName));
25 26
}

27
void ScheduleFrame(Dart_NativeArguments args) {
28
  UIDartState::ThrowIfUIOperationsProhibited();
29
  UIDartState::Current()->window()->client()->ScheduleFrame();
30 31 32
}

void Render(Dart_NativeArguments args) {
33
  UIDartState::ThrowIfUIOperationsProhibited();
34
  Dart_Handle exception = nullptr;
35 36
  Scene* scene =
      tonic::DartConverter<Scene*>::FromArguments(args, 1, exception);
37 38 39 40
  if (exception) {
    Dart_ThrowException(exception);
    return;
  }
41
  UIDartState::Current()->window()->client()->Render(scene);
42 43
}

44
void UpdateSemantics(Dart_NativeArguments args) {
45
  UIDartState::ThrowIfUIOperationsProhibited();
46 47 48 49 50 51 52 53 54 55
  Dart_Handle exception = nullptr;
  SemanticsUpdate* update =
      tonic::DartConverter<SemanticsUpdate*>::FromArguments(args, 1, exception);
  if (exception) {
    Dart_ThrowException(exception);
    return;
  }
  UIDartState::Current()->window()->client()->UpdateSemantics(update);
}

56
void SetIsolateDebugName(Dart_NativeArguments args) {
57
  UIDartState::ThrowIfUIOperationsProhibited();
58 59 60 61 62 63 64
  Dart_Handle exception = nullptr;
  const std::string name =
      tonic::DartConverter<std::string>::FromArguments(args, 1, exception);
  if (exception) {
    Dart_ThrowException(exception);
    return;
  }
65
  UIDartState::Current()->SetDebugName(name);
66 67
}

68
void SetNeedsReportTimings(Dart_NativeArguments args) {
69
  UIDartState::ThrowIfUIOperationsProhibited();
70 71 72 73 74
  Dart_Handle exception = nullptr;
  bool value = tonic::DartConverter<bool>::FromArguments(args, 1, exception);
  UIDartState::Current()->window()->client()->SetNeedsReportTimings(value);
}

75
void ReportUnhandledException(Dart_NativeArguments args) {
76 77
  UIDartState::ThrowIfUIOperationsProhibited();

78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
  Dart_Handle exception = nullptr;

  auto error_name =
      tonic::DartConverter<std::string>::FromArguments(args, 0, exception);
  if (exception) {
    Dart_ThrowException(exception);
    return;
  }

  auto stack_trace =
      tonic::DartConverter<std::string>::FromArguments(args, 1, exception);
  if (exception) {
    Dart_ThrowException(exception);
    return;
  }

  UIDartState::Current()->ReportUnhandledException(std::move(error_name),
                                                   std::move(stack_trace));
}

98 99 100
Dart_Handle SendPlatformMessage(Dart_Handle window,
                                const std::string& name,
                                Dart_Handle callback,
101
                                Dart_Handle data_handle) {
102
  UIDartState* dart_state = UIDartState::Current();
A
Adam Barth 已提交
103

104
  if (!dart_state->window()) {
105 106
    return tonic::ToDart(
        "Platform messages can only be sent from the main isolate");
107 108
  }

109
  fml::RefPtr<PlatformMessageResponse> response;
A
Adam Barth 已提交
110
  if (!Dart_IsNull(callback)) {
111
    response = fml::MakeRefCounted<PlatformMessageResponseDart>(
112 113
        tonic::DartPersistentValue(dart_state, callback),
        dart_state->GetTaskRunners().GetUITaskRunner());
A
Adam Barth 已提交
114
  }
115
  if (Dart_IsNull(data_handle)) {
116
    dart_state->window()->client()->HandlePlatformMessage(
117
        fml::MakeRefCounted<PlatformMessage>(name, response));
118
  } else {
119
    tonic::DartByteData data(data_handle);
120
    const uint8_t* buffer = static_cast<const uint8_t*>(data.data());
121
    dart_state->window()->client()->HandlePlatformMessage(
122
        fml::MakeRefCounted<PlatformMessage>(
123 124 125
            name, std::vector<uint8_t>(buffer, buffer + data.length_in_bytes()),
            response));
  }
126 127

  return Dart_Null();
128 129 130 131 132 133
}

void _SendPlatformMessage(Dart_NativeArguments args) {
  tonic::DartCallStatic(&SendPlatformMessage, args);
}

A
Adam Barth 已提交
134 135 136
void RespondToPlatformMessage(Dart_Handle window,
                              int response_id,
                              const tonic::DartByteData& data) {
137 138 139 140
  if (Dart_IsNull(data.dart_handle())) {
    UIDartState::Current()->window()->CompletePlatformMessageEmptyResponse(
        response_id);
  } else {
141
    // TODO(engine): Avoid this copy.
142 143 144 145 146
    const uint8_t* buffer = static_cast<const uint8_t*>(data.data());
    UIDartState::Current()->window()->CompletePlatformMessageResponse(
        response_id,
        std::vector<uint8_t>(buffer, buffer + data.length_in_bytes()));
  }
A
Adam Barth 已提交
147 148 149 150 151 152
}

void _RespondToPlatformMessage(Dart_NativeArguments args) {
  tonic::DartCallStatic(&RespondToPlatformMessage, args);
}

153
void GetPersistentIsolateData(Dart_NativeArguments args) {
154 155
  UIDartState::ThrowIfUIOperationsProhibited();

156 157 158 159 160 161 162 163 164 165 166 167 168
  auto persistent_isolate_data =
      UIDartState::Current()->window()->client()->GetPersistentIsolateData();

  if (!persistent_isolate_data) {
    Dart_SetReturnValue(args, Dart_Null());
    return;
  }

  Dart_SetReturnValue(
      args, tonic::DartByteData::Create(persistent_isolate_data->GetMapping(),
                                        persistent_isolate_data->GetSize()));
}

169
Dart_Handle ToByteData(const std::vector<uint8_t>& buffer) {
170
  return tonic::DartByteData::Create(buffer.data(), buffer.size());
171 172
}

173 174
}  // namespace

A
Adam Barth 已提交
175
WindowClient::~WindowClient() {}
176

A
Adam Barth 已提交
177
Window::Window(WindowClient* client) : client_(client) {}
178

A
Adam Barth 已提交
179
Window::~Window() {}
180 181

void Window::DidCreateIsolate() {
182 183
  library_.Set(tonic::DartState::Current(),
               Dart_LookupLibrary(tonic::ToDart("dart:ui")));
184 185
}

186
void Window::UpdateWindowMetrics(const ViewportMetrics& metrics) {
187 188
  viewport_metrics_ = metrics;

189
  std::shared_ptr<tonic::DartState> dart_state = library_.dart_state().lock();
190
  if (!dart_state) {
191
    return;
192
  }
193
  tonic::DartState::Scope scope(dart_state);
194 195 196 197 198 199
  tonic::LogIfError(tonic::DartInvokeField(
      library_.value(), "_updateWindowMetrics",
      {
          tonic::ToDart(metrics.device_pixel_ratio),
          tonic::ToDart(metrics.physical_width),
          tonic::ToDart(metrics.physical_height),
D
Dan Field 已提交
200
          tonic::ToDart(metrics.physical_depth),
201 202 203 204 205 206 207 208
          tonic::ToDart(metrics.physical_padding_top),
          tonic::ToDart(metrics.physical_padding_right),
          tonic::ToDart(metrics.physical_padding_bottom),
          tonic::ToDart(metrics.physical_padding_left),
          tonic::ToDart(metrics.physical_view_inset_top),
          tonic::ToDart(metrics.physical_view_inset_right),
          tonic::ToDart(metrics.physical_view_inset_bottom),
          tonic::ToDart(metrics.physical_view_inset_left),
209 210 211 212
          tonic::ToDart(metrics.physical_system_gesture_inset_top),
          tonic::ToDart(metrics.physical_system_gesture_inset_right),
          tonic::ToDart(metrics.physical_system_gesture_inset_bottom),
          tonic::ToDart(metrics.physical_system_gesture_inset_left),
213
      }));
214 215
}

216
void Window::UpdateLocales(const std::vector<std::string>& locales) {
217
  std::shared_ptr<tonic::DartState> dart_state = library_.dart_state().lock();
218
  if (!dart_state) {
219
    return;
220
  }
221
  tonic::DartState::Scope scope(dart_state);
222 223 224 225 226
  tonic::LogIfError(tonic::DartInvokeField(
      library_.value(), "_updateLocales",
      {
          tonic::ToDart<std::vector<std::string>>(locales),
      }));
227 228
}

229
void Window::UpdateUserSettingsData(const std::string& data) {
230
  std::shared_ptr<tonic::DartState> dart_state = library_.dart_state().lock();
231
  if (!dart_state) {
232
    return;
233
  }
234 235
  tonic::DartState::Scope scope(dart_state);

236 237 238 239 240
  tonic::LogIfError(tonic::DartInvokeField(library_.value(),
                                           "_updateUserSettingsData",
                                           {
                                               tonic::StdStringToDart(data),
                                           }));
241 242
}

243 244
void Window::UpdateLifecycleState(const std::string& data) {
  std::shared_ptr<tonic::DartState> dart_state = library_.dart_state().lock();
245
  if (!dart_state) {
246
    return;
247
  }
248 249 250 251 252 253 254 255
  tonic::DartState::Scope scope(dart_state);
  tonic::LogIfError(tonic::DartInvokeField(library_.value(),
                                           "_updateLifecycleState",
                                           {
                                               tonic::StdStringToDart(data),
                                           }));
}

256
void Window::UpdateSemanticsEnabled(bool enabled) {
257
  std::shared_ptr<tonic::DartState> dart_state = library_.dart_state().lock();
258
  if (!dart_state) {
259
    return;
260
  }
261
  tonic::DartState::Scope scope(dart_state);
262
  UIDartState::ThrowIfUIOperationsProhibited();
263

264 265
  tonic::LogIfError(tonic::DartInvokeField(
      library_.value(), "_updateSemanticsEnabled", {tonic::ToDart(enabled)}));
266 267
}

268
void Window::UpdateAccessibilityFeatures(int32_t values) {
269
  std::shared_ptr<tonic::DartState> dart_state = library_.dart_state().lock();
270
  if (!dart_state) {
271
    return;
272
  }
273 274
  tonic::DartState::Scope scope(dart_state);

275 276 277
  tonic::LogIfError(tonic::DartInvokeField(library_.value(),
                                           "_updateAccessibilityFeatures",
                                           {tonic::ToDart(values)}));
278 279
}

280
void Window::DispatchPlatformMessage(fml::RefPtr<PlatformMessage> message) {
281
  std::shared_ptr<tonic::DartState> dart_state = library_.dart_state().lock();
282 283 284 285
  if (!dart_state) {
    FML_DLOG(WARNING)
        << "Dropping platform message for lack of DartState on channel: "
        << message->channel();
286
    return;
287
  }
288
  tonic::DartState::Scope scope(dart_state);
289 290
  Dart_Handle data_handle =
      (message->hasData()) ? ToByteData(message->data()) : Dart_Null();
291 292 293 294
  if (Dart_IsError(data_handle)) {
    FML_DLOG(WARNING)
        << "Dropping platform message because of a Dart error on channel: "
        << message->channel();
295
    return;
296
  }
297

A
Adam Barth 已提交
298 299 300 301 302
  int response_id = 0;
  if (auto response = message->response()) {
    response_id = next_response_id_++;
    pending_responses_[response_id] = response;
  }
303

304 305 306 307
  tonic::LogIfError(
      tonic::DartInvokeField(library_.value(), "_dispatchPlatformMessage",
                             {tonic::ToDart(message->channel()), data_handle,
                              tonic::ToDart(response_id)}));
A
Adam Barth 已提交
308
}
309

A
Adam Barth 已提交
310
void Window::DispatchPointerDataPacket(const PointerDataPacket& packet) {
311
  std::shared_ptr<tonic::DartState> dart_state = library_.dart_state().lock();
312
  if (!dart_state) {
A
Adam Barth 已提交
313
    return;
314
  }
A
Adam Barth 已提交
315 316 317
  tonic::DartState::Scope scope(dart_state);

  Dart_Handle data_handle = ToByteData(packet.data());
318
  if (Dart_IsError(data_handle)) {
A
Adam Barth 已提交
319
    return;
320
  }
321 322
  tonic::LogIfError(tonic::DartInvokeField(
      library_.value(), "_dispatchPointerDataPacket", {data_handle}));
323 324
}

325 326 327
void Window::DispatchSemanticsAction(int32_t id,
                                     SemanticsAction action,
                                     std::vector<uint8_t> args) {
328
  std::shared_ptr<tonic::DartState> dart_state = library_.dart_state().lock();
329
  if (!dart_state) {
330
    return;
331
  }
332 333
  tonic::DartState::Scope scope(dart_state);

334 335
  Dart_Handle args_handle = (args.empty()) ? Dart_Null() : ToByteData(args);

336
  if (Dart_IsError(args_handle)) {
337
    return;
338
  }
339

340
  tonic::LogIfError(tonic::DartInvokeField(
341
      library_.value(), "_dispatchSemanticsAction",
342 343
      {tonic::ToDart(id), tonic::ToDart(static_cast<int32_t>(action)),
       args_handle}));
344 345
}

346
void Window::BeginFrame(fml::TimePoint frameTime) {
347
  std::shared_ptr<tonic::DartState> dart_state = library_.dart_state().lock();
348
  if (!dart_state) {
349
    return;
350
  }
351
  tonic::DartState::Scope scope(dart_state);
352

353
  int64_t microseconds = (frameTime - fml::TimePoint()).ToMicroseconds();
354

355 356 357 358
  tonic::LogIfError(tonic::DartInvokeField(library_.value(), "_beginFrame",
                                           {
                                               Dart_NewInteger(microseconds),
                                           }));
359

360
  UIDartState::Current()->FlushMicrotasksNow();
361

362
  tonic::LogIfError(tonic::DartInvokeField(library_.value(), "_drawFrame", {}));
363 364
}

365 366
void Window::ReportTimings(std::vector<int64_t> timings) {
  std::shared_ptr<tonic::DartState> dart_state = library_.dart_state().lock();
367
  if (!dart_state) {
368
    return;
369
  }
370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390
  tonic::DartState::Scope scope(dart_state);

  Dart_Handle data_handle =
      Dart_NewTypedData(Dart_TypedData_kInt64, timings.size());

  Dart_TypedData_Type type;
  void* data = nullptr;
  intptr_t num_acquired = 0;
  FML_CHECK(!Dart_IsError(
      Dart_TypedDataAcquireData(data_handle, &type, &data, &num_acquired)));
  FML_DCHECK(num_acquired == static_cast<int>(timings.size()));

  memcpy(data, timings.data(), sizeof(int64_t) * timings.size());
  FML_CHECK(Dart_TypedDataReleaseData(data_handle));

  tonic::LogIfError(tonic::DartInvokeField(library_.value(), "_reportTimings",
                                           {
                                               data_handle,
                                           }));
}

391
void Window::CompletePlatformMessageEmptyResponse(int response_id) {
392
  if (!response_id) {
393
    return;
394
  }
395
  auto it = pending_responses_.find(response_id);
396
  if (it == pending_responses_.end()) {
397
    return;
398
  }
399 400 401 402 403
  auto response = std::move(it->second);
  pending_responses_.erase(it);
  response->CompleteEmpty();
}

A
Adam Barth 已提交
404
void Window::CompletePlatformMessageResponse(int response_id,
405
                                             std::vector<uint8_t> data) {
406
  if (!response_id) {
A
Adam Barth 已提交
407
    return;
408
  }
A
Adam Barth 已提交
409
  auto it = pending_responses_.find(response_id);
410
  if (it == pending_responses_.end()) {
A
Adam Barth 已提交
411
    return;
412
  }
A
Adam Barth 已提交
413 414
  auto response = std::move(it->second);
  pending_responses_.erase(it);
415
  response->Complete(std::make_unique<fml::DataMapping>(std::move(data)));
A
Adam Barth 已提交
416 417
}

418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438
Dart_Handle ComputePlatformResolvedLocale(Dart_Handle supportedLocalesHandle) {
  std::vector<std::string> supportedLocales =
      tonic::DartConverter<std::vector<std::string>>::FromDart(
          supportedLocalesHandle);

  std::vector<std::string> results =
      *UIDartState::Current()
           ->window()
           ->client()
           ->ComputePlatformResolvedLocale(supportedLocales);

  return tonic::DartConverter<std::vector<std::string>>::ToDart(results);
}

static void _ComputePlatformResolvedLocale(Dart_NativeArguments args) {
  UIDartState::ThrowIfUIOperationsProhibited();
  Dart_Handle result =
      ComputePlatformResolvedLocale(Dart_GetNativeArgument(args, 1));
  Dart_SetReturnValue(args, result);
}

439
void Window::RegisterNatives(tonic::DartLibraryNatives* natives) {
440
  natives->Register({
441
      {"Window_defaultRouteName", DefaultRouteName, 1, true},
442 443
      {"Window_scheduleFrame", ScheduleFrame, 1, true},
      {"Window_sendPlatformMessage", _SendPlatformMessage, 4, true},
A
Adam Barth 已提交
444
      {"Window_respondToPlatformMessage", _RespondToPlatformMessage, 3, true},
445 446
      {"Window_render", Render, 2, true},
      {"Window_updateSemantics", UpdateSemantics, 2, true},
447
      {"Window_setIsolateDebugName", SetIsolateDebugName, 2, true},
448
      {"Window_reportUnhandledException", ReportUnhandledException, 2, true},
449
      {"Window_setNeedsReportTimings", SetNeedsReportTimings, 2, true},
450
      {"Window_getPersistentIsolateData", GetPersistentIsolateData, 1, true},
451 452
      {"Window_computePlatformResolvedLocale", _ComputePlatformResolvedLocale,
       2, true},
453
  });
454 455
}

456
}  // namespace flutter