Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions shell/common/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,8 @@ if (current_toolchain == host_toolchain) {

test_fixtures("shell_unittests_fixtures") {
dart_main = "fixtures/shell_test.dart"

fixtures = [ "fixtures/shelltest_screenshot.png" ]
}

shell_host_executable("shell_unittests") {
Expand Down
Binary file added shell/common/fixtures/shelltest_screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 8 additions & 3 deletions shell/common/rasterizer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -399,9 +399,14 @@ static sk_sp<SkData> ScreenshotLayerTreeAsImage(
SkMatrix root_surface_transformation;
root_surface_transformation.reset();

auto frame = compositor_context.AcquireFrame(surface_context, canvas, nullptr,
root_surface_transformation,
false, nullptr);
// We want to ensure we call the base method for
// CompositorContext::AcquireFrame instead of the platform-specific method.
// Specifically, Fuchsia's CompositorContext handles the rendering surface
// itself which means that we will still continue to render to the onscreen
// surface if we don't call the base method.
auto frame = compositor_context.flutter::CompositorContext::AcquireFrame(
Comment thread
gw280 marked this conversation as resolved.
surface_context, canvas, nullptr, root_surface_transformation, false,
nullptr);
canvas->clear(SK_ColorTRANSPARENT);
frame->Raster(*tree, true);
canvas->flush();
Expand Down
62 changes: 62 additions & 0 deletions shell/common/shell_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <memory>

#include "flutter/flow/layers/layer_tree.h"
#include "flutter/flow/layers/picture_layer.h"
#include "flutter/flow/layers/transform_layer.h"
#include "flutter/fml/command_line.h"
#include "flutter/fml/make_copyable.h"
Expand Down Expand Up @@ -952,5 +953,66 @@ TEST_F(ShellTest, IsolateCanAccessPersistentIsolateData) {
DestroyShell(std::move(shell), std::move(task_runners));
}

TEST_F(ShellTest, Screenshot) {
Comment thread
gw280 marked this conversation as resolved.
auto settings = CreateSettingsForFixture();
fml::AutoResetWaitableEvent firstFrameLatch;
settings.frame_rasterized_callback =
[&firstFrameLatch](const FrameTiming& t) { firstFrameLatch.Signal(); };

std::unique_ptr<Shell> shell = CreateShell(settings);

// Create the surface needed by rasterizer
PlatformViewNotifyCreated(shell.get());

auto configuration = RunConfiguration::InferFromSettings(settings);
configuration.SetEntrypoint("emptyMain");

RunEngine(shell.get(), std::move(configuration));

LayerTreeBuilder builder = [&](std::shared_ptr<ContainerLayer> root) {
SkPictureRecorder recorder;
SkCanvas* recording_canvas =
recorder.beginRecording(SkRect::MakeXYWH(0, 0, 80, 80));
recording_canvas->drawRect(SkRect::MakeXYWH(0, 0, 80, 80),
SkPaint(SkColor4f::FromColor(SK_ColorRED)));
auto sk_picture = recorder.finishRecordingAsPicture();
fml::RefPtr<SkiaUnrefQueue> queue = fml::MakeRefCounted<SkiaUnrefQueue>(
this->GetCurrentTaskRunner(), fml::TimeDelta::FromSeconds(0));
auto picture_layer = std::make_shared<PictureLayer>(
SkPoint::Make(10, 10),
flutter::SkiaGPUObject<SkPicture>({sk_picture, queue}), false, false);
root->Add(picture_layer);
};

PumpOneFrame(shell.get(), 100, 100, builder);
firstFrameLatch.Wait();

std::promise<Rasterizer::Screenshot> screenshot_promise;
auto screenshot_future = screenshot_promise.get_future();
Comment on lines +990 to +991

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, i've never used promises in C++. This is a good use!


fml::TaskRunner::RunNowOrPostTask(
shell->GetTaskRunners().GetGPUTaskRunner(),
[&screenshot_promise, &shell]() {
auto rasterizer = shell->GetRasterizer();
screenshot_promise.set_value(rasterizer->ScreenshotLastLayerTree(
Rasterizer::ScreenshotType::CompressedImage, false));
});

auto fixtures_dir =
fml::OpenDirectory(GetFixturesPath(), false, fml::FilePermission::kRead);

auto reference_png = fml::FileMapping::CreateReadOnly(
fixtures_dir, "shelltest_screenshot.png");

// Use MakeWithoutCopy instead of MakeWithCString because we don't want to
// encode the null sentinel
sk_sp<SkData> reference_data = SkData::MakeWithoutCopy(
reference_png->GetMapping(), reference_png->GetSize());

ASSERT_TRUE(reference_data->equals(screenshot_future.get().data.get()));

DestroyShell(std::move(shell));
}

} // namespace testing
} // namespace flutter