From ea0e620ea1ada26e8bbc3b46244fd3115878ee9f Mon Sep 17 00:00:00 2001 From: Jason Simmons Date: Thu, 26 Oct 2017 14:35:26 -0700 Subject: [PATCH] Add an SkPicture screenshot handler to the service protocol (flutter/engine#4284) This will replace the one in the diagnostic server --- .../common/platform_view_service_protocol.cc | 66 +++++++++++++++++++ .../common/platform_view_service_protocol.h | 9 +++ 2 files changed, 75 insertions(+) diff --git a/engine/src/flutter/shell/common/platform_view_service_protocol.cc b/engine/src/flutter/shell/common/platform_view_service_protocol.cc index 02c15487a0..9a82f8d7fb 100644 --- a/engine/src/flutter/shell/common/platform_view_service_protocol.cc +++ b/engine/src/flutter/shell/common/platform_view_service_protocol.cc @@ -122,6 +122,11 @@ void PlatformViewServiceProtocol::RegisterHook(bool running_precompiled_code) { // Screenshot. Dart_RegisterRootServiceRequestCallback(kScreenshotExtensionName, &Screenshot, nullptr); + + // SkPicture Screenshot. + Dart_RegisterRootServiceRequestCallback(kScreenshotSkpExtensionName, + &ScreenshotSkp, nullptr); + // The following set of service protocol extensions require debug build if (running_precompiled_code) { return; @@ -316,6 +321,67 @@ void PlatformViewServiceProtocol::ScreenshotGpuTask(SkBitmap* bitmap) { canvas->flush(); } +const char* PlatformViewServiceProtocol::kScreenshotSkpExtensionName = + "_flutter.screenshotSkp"; + +bool PlatformViewServiceProtocol::ScreenshotSkp(const char* method, + const char** param_keys, + const char** param_values, + intptr_t num_params, + void* user_data, + const char** json_object) { + fxl::AutoResetWaitableEvent latch; + sk_sp picture; + blink::Threads::Gpu()->PostTask([&latch, &picture]() { + picture = ScreenshotSkpGpuTask(); + latch.Signal(); + }); + + latch.Wait(); + + SkDynamicMemoryWStream stream; + PngPixelSerializer serializer; + picture->serialize(&stream, &serializer); + sk_sp skp_data(stream.detachAsData()); + + size_t b64_size = + SkBase64::Encode(skp_data->data(), skp_data->size(), nullptr); + SkAutoTMalloc b64_data(b64_size); + SkBase64::Encode(skp_data->data(), skp_data->size(), b64_data.get()); + + std::stringstream response; + response << "{\"type\":\"ScreenshotSkp\"," + << "\"skp\":\"" << std::string{b64_data.get(), b64_size} << "\"}"; + *json_object = strdup(response.str().c_str()); + return true; +} + +sk_sp PlatformViewServiceProtocol::ScreenshotSkpGpuTask() { + std::vector> rasterizers; + Shell::Shared().GetRasterizers(&rasterizers); + if (rasterizers.size() != 1) + return nullptr; + + Rasterizer* rasterizer = rasterizers[0].get(); + if (rasterizer == nullptr) + return nullptr; + + flow::LayerTree* layer_tree = rasterizer->GetLastLayerTree(); + if (layer_tree == nullptr) + return nullptr; + + SkPictureRecorder recorder; + recorder.beginRecording(SkRect::MakeWH(layer_tree->frame_size().width(), + layer_tree->frame_size().height())); + + flow::CompositorContext compositor_context(nullptr); + flow::CompositorContext::ScopedFrame frame = compositor_context.AcquireFrame( + nullptr, recorder.getRecordingCanvas(), false); + layer_tree->Raster(frame); + + return recorder.finishRecordingAsPicture(); +} + const char* PlatformViewServiceProtocol::kFlushUIThreadTasksExtensionName = "_flutter.flushUIThreadTasks"; diff --git a/engine/src/flutter/shell/common/platform_view_service_protocol.h b/engine/src/flutter/shell/common/platform_view_service_protocol.h index 20149abb53..aedf542c5d 100644 --- a/engine/src/flutter/shell/common/platform_view_service_protocol.h +++ b/engine/src/flutter/shell/common/platform_view_service_protocol.h @@ -48,6 +48,15 @@ class PlatformViewServiceProtocol { const char** json_object); static void ScreenshotGpuTask(SkBitmap* bitmap); + static const char* kScreenshotSkpExtensionName; + static bool ScreenshotSkp(const char* method, + const char** param_keys, + const char** param_values, + intptr_t num_params, + void* user_data, + const char** json_object); + static sk_sp ScreenshotSkpGpuTask(); + // This API should not be invoked by production code. // It can potentially starve the service isolate if the main isolate pauses // at a breakpoint or is in an infinite loop.