提交 0a3c0b5e 编写于 作者: C Chinmay Garde 提交者: GitHub

Allow platform frameworks to snapshot FlutterView contents. (#3281)

上级 03f68e99
......@@ -53,6 +53,7 @@ shared_library("flutter_framework_dylib") {
deps = [
"//base:base",
"//dart/runtime:libdart",
"//flutter/flow",
"//flutter/glue",
"//flutter/lib/ui",
"//flutter/shell/common",
......
......@@ -3,6 +3,12 @@
// found in the LICENSE file.
#include "flutter/shell/platform/darwin/ios/framework/Source/FlutterView.h"
#include "flutter/common/threads.h"
#include "flutter/flow/layers/layer_tree.h"
#include "flutter/shell/common/rasterizer.h"
#include "flutter/shell/common/shell.h"
#include "lib/ftl/synchronization/waitable_event.h"
#include "third_party/skia/include/utils/mac/SkCGUtils.h"
@interface FlutterView ()<UIInputViewAudioFeedback>
......@@ -30,4 +36,91 @@
return YES;
}
void SnapshotRasterizer(ftl::WeakPtr<shell::Rasterizer> rasterizer,
CGContextRef context,
bool is_opaque) {
if (!rasterizer) {
return;
}
// Access the layer tree and assess the description of the backing store to
// create for this snapshot.
flow::LayerTree* layer_tree = rasterizer->GetLastLayerTree();
if (layer_tree == nullptr) {
return;
}
auto size = layer_tree->frame_size();
if (size.isEmpty()) {
return;
}
auto info =
SkImageInfo::MakeN32(size.width(), size.height(),
is_opaque ? SkAlphaType::kOpaque_SkAlphaType
: SkAlphaType::kPremul_SkAlphaType);
// Create the backing store and prepare for use.
SkBitmap bitmap;
bitmap.setInfo(info);
if (!bitmap.tryAllocPixels()) {
return;
}
// Create a canvas from the backing store and a single use compositor context
// to draw into the canvas.
SkAutoLockPixels pixel_lock(bitmap, true);
SkCanvas canvas(bitmap);
{
flow::CompositorContext compositor_context;
auto frame = compositor_context.AcquireFrame(nullptr, &canvas,
false /* instrumentation */);
layer_tree->Raster(frame, false /* ignore raster cache. */);
}
canvas.flush();
// Draw the bitmap to the system provided snapshotting context.
SkCGDrawBitmap(context, bitmap, 0, 0);
}
void SnapshotContents(CGContextRef context, bool is_opaque) {
// TODO(chinmaygarde): Currently, there is no way to get the rasterizer for
// a particular platform view from the shell. But, for now, we only have one
// platform view. So use that. Once we support multiple platform views, the
// shell will need to provide a way to get the rasterizer for a specific
// platform view.
std::vector<ftl::WeakPtr<shell::Rasterizer>> registered_rasterizers;
shell::Shell::Shared().GetRasterizers(&registered_rasterizers);
for (auto& rasterizer : registered_rasterizers) {
SnapshotRasterizer(rasterizer, context, is_opaque);
}
}
void SnapshotContentsSync(CGContextRef context, UIView* view) {
auto gpu_thread = blink::Threads::Gpu();
if (!gpu_thread) {
return;
}
ftl::AutoResetWaitableEvent latch;
gpu_thread->PostTask([&latch, context, view]() {
SnapshotContents(context, [view isOpaque]);
latch.Signal();
});
latch.Wait();
}
// Override the default CALayerDelegate method so that APIs that attempt to
// screenshot the view display contents correctly. We cannot depend on
// reading
// GPU pixels directly because:
// 1: We dont use retained backing on the CAEAGLLayer.
// 2: The call is made of the platform thread and not the GPU thread.
// 3: There may be a software rasterizer.
- (void)drawLayer:(CALayer*)layer inContext:(CGContextRef)context {
SnapshotContentsSync(context, self);
}
@end
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册