Flutter Engine
embedder_unittests_util.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #define FML_USED_ON_EMBEDDER
6 
7 #include <limits>
8 
9 #include "flutter/shell/platform/embedder/tests/embedder_unittests_util.h"
10 
11 namespace flutter {
12 namespace testing {
13 
14 sk_sp<SkSurface> CreateRenderSurface(const FlutterLayer& layer,
15  GrDirectContext* context) {
16  const auto image_info =
17  SkImageInfo::MakeN32Premul(layer.size.width, layer.size.height);
18  auto surface = context ? SkSurface::MakeRenderTarget(
19  context, // context
20  SkBudgeted::kNo, // budgeted
21  image_info, // image info
22  1, // sample count
23  kTopLeft_GrSurfaceOrigin, // surface origin
24  nullptr, // surface properties
25  false // mipmaps
26 
27  )
28  : SkSurface::MakeRaster(image_info);
29  FML_CHECK(surface != nullptr);
30  return surface;
31 }
32 
33 // Normalizes the color-space, color-type and alpha-type for comparison.
34 static sk_sp<SkData> NormalizeImage(sk_sp<SkImage> image) {
35  // To avoid clipping, convert to a very wide gamut, and a high bit depth.
36  sk_sp<SkColorSpace> norm_colorspace = SkColorSpace::MakeRGB(
37  SkNamedTransferFn::kRec2020, SkNamedGamut::kRec2020);
38  SkImageInfo norm_image_info =
39  SkImageInfo::Make(image->width(), image->height(),
40  SkColorType::kR16G16B16A16_unorm_SkColorType,
41  SkAlphaType::kUnpremul_SkAlphaType, norm_colorspace);
42  size_t row_bytes = norm_image_info.minRowBytes();
43  size_t size = norm_image_info.computeByteSize(row_bytes);
44  sk_sp<SkData> data = SkData::MakeUninitialized(size);
45  if (!data) {
46  FML_CHECK(false) << "Unable to allocate data.";
47  }
48 
49  bool success = image->readPixels(norm_image_info, data->writable_data(),
50  row_bytes, 0, 0);
51  if (!success) {
52  FML_CHECK(false) << "Unable to read pixels.";
53  }
54 
55  return data;
56 }
57 
58 bool RasterImagesAreSame(sk_sp<SkImage> a, sk_sp<SkImage> b) {
59  if (!a || !b) {
60  return false;
61  }
62 
63  FML_CHECK(!a->isTextureBacked());
64  FML_CHECK(!b->isTextureBacked());
65 
66  sk_sp<SkData> normalized_a = NormalizeImage(a);
67  sk_sp<SkData> normalized_b = NormalizeImage(b);
68 
69  return normalized_a->equals(normalized_b.get());
70 }
71 
72 bool WriteImageToDisk(const fml::UniqueFD& directory,
73  const std::string& name,
74  sk_sp<SkImage> image) {
75  if (!image) {
76  return false;
77  }
78 
79  auto data = image->encodeToData();
80 
81  if (!data) {
82  return false;
83  }
84 
85  fml::NonOwnedMapping mapping(static_cast<const uint8_t*>(data->data()),
86  data->size());
87  return WriteAtomically(directory, name.c_str(), mapping);
88 }
89 
90 bool ImageMatchesFixture(const std::string& fixture_file_name,
91  sk_sp<SkImage> scene_image) {
92  fml::FileMapping fixture_image_mapping(OpenFixture(fixture_file_name));
93 
94  FML_CHECK(fixture_image_mapping.GetSize() != 0u)
95  << "Could not find fixture: " << fixture_file_name;
96 
97  auto encoded_image = SkData::MakeWithoutCopy(
98  fixture_image_mapping.GetMapping(), fixture_image_mapping.GetSize());
99  auto fixture_image =
100  SkImage::MakeFromEncoded(std::move(encoded_image))->makeRasterImage();
101 
102  FML_CHECK(fixture_image) << "Could not create image from fixture: "
103  << fixture_file_name;
104 
105  FML_CHECK(scene_image) << "Invalid scene image.";
106 
107  auto scene_image_subset = scene_image->makeSubset(
108  SkIRect::MakeWH(fixture_image->width(), fixture_image->height()));
109 
110  FML_CHECK(scene_image_subset)
111  << "Could not create image subset for fixture comparison: "
112  << scene_image_subset;
113 
114  const auto images_are_same =
115  RasterImagesAreSame(scene_image_subset, fixture_image);
116 
117  // If the images are not the same, this predicate is going to indicate test
118  // failure. Dump both the actual image and the expectation to disk to the
119  // test author can figure out what went wrong.
120  if (!images_are_same) {
121  const auto fixtures_path = GetFixturesPath();
122 
123  const auto actual_file_name = "actual_" + fixture_file_name;
124  const auto expect_file_name = "expectation_" + fixture_file_name;
125 
126  auto fixtures_fd = OpenFixturesDirectory();
127 
128  FML_CHECK(
129  WriteImageToDisk(fixtures_fd, actual_file_name, scene_image_subset))
130  << "Could not write file to disk: " << actual_file_name;
131 
132  FML_CHECK(WriteImageToDisk(fixtures_fd, expect_file_name, fixture_image))
133  << "Could not write file to disk: " << expect_file_name;
134 
135  FML_LOG(ERROR) << "Image did not match expectation." << std::endl
136  << "Expected:"
137  << fml::paths::JoinPaths({fixtures_path, expect_file_name})
138  << std::endl
139  << "Got:"
140  << fml::paths::JoinPaths({fixtures_path, actual_file_name})
141  << std::endl;
142  }
143  return images_are_same;
144 }
145 
146 bool ImageMatchesFixture(const std::string& fixture_file_name,
147  std::future<sk_sp<SkImage>>& scene_image) {
148  return ImageMatchesFixture(fixture_file_name, scene_image.get());
149 }
150 
152  const FlutterPlatformViewMutation** mutations,
153  size_t count,
155  std::function<void(const FlutterPlatformViewMutation& mutation)> handler) {
156  if (mutations == nullptr) {
157  return;
158  }
159 
160  for (size_t i = 0; i < count; ++i) {
161  const FlutterPlatformViewMutation* mutation = mutations[i];
162  if (mutation->type != type) {
163  continue;
164  }
165 
166  handler(*mutation);
167  }
168 }
169 
171  const FlutterPlatformView* view,
173  std::function<void(const FlutterPlatformViewMutation& mutation)> handler) {
174  return FilterMutationsByType(view->mutations, view->mutations_count, type,
175  handler);
176 }
177 
179  const FlutterPlatformViewMutation** mutations,
180  size_t count) {
181  SkMatrix collected;
182 
185  [&](const auto& mutation) {
186  collected.preConcat(SkMatrixMake(mutation.transformation));
187  });
188 
189  return collected;
190 }
191 
194  view->mutations_count);
195 }
196 
197 } // namespace testing
198 } // namespace flutter
SkMatrix GetTotalMutationTransformationMatrix(const FlutterPlatformViewMutation **mutations, size_t count)
FlutterPlatformViewMutationType
Definition: embedder.h:992
KeyCallType type
void FilterMutationsByType(const FlutterPlatformViewMutation **mutations, size_t count, FlutterPlatformViewMutationType type, std::function< void(const FlutterPlatformViewMutation &mutation)> handler)
FlutterSize size
The size of the layer (in physical pixels).
Definition: embedder.h:1108
sk_sp< SkSurface > CreateRenderSurface(const FlutterLayer &layer, GrDirectContext *context)
Dart_NativeFunction function
Definition: fuchsia.cc:51
DEF_SWITCHES_START aot vmservice shared library name
Definition: switches.h:32
constexpr std::size_t size(T(&array)[N])
Definition: size.h:13
#define FML_LOG(severity)
Definition: logging.h:65
SkMatrix SkMatrixMake(const FlutterTransformation &xformation)
fml::UniqueFD OpenFixturesDirectory()
Opens the fixtures directory for the unit-test harness.
Definition: testing.cc:21
std::string JoinPaths(std::initializer_list< std::string > components)
Definition: paths.cc:14
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
Definition: switches.h:41
static sk_sp< SkData > NormalizeImage(sk_sp< SkImage > image)
bool RasterImagesAreSame(sk_sp< SkImage > a, sk_sp< SkImage > b)
fml::UniqueFD OpenFixture(std::string fixture_name)
Opens a fixture of the given file name.
Definition: testing.cc:35
const char * GetFixturesPath()
Returns the directory containing the test fixture for the target if this target has fixtures configur...
size_t mutations_count
Definition: embedder.h:1027
double width
Definition: embedder.h:320
const uint8_t * GetMapping() const override
const FlutterPlatformViewMutation ** mutations
Definition: embedder.h:1040
size_t GetSize() const override
#define FML_CHECK(condition)
Definition: logging.h:68
FlView * view
double height
Definition: embedder.h:321
FlutterPlatformViewMutationType type
The type of the mutation described by the subsequent union.
Definition: embedder.h:1009
bool WriteImageToDisk(const fml::UniqueFD &directory, const std::string &name, sk_sp< SkImage > image)
bool ImageMatchesFixture(const std::string &fixture_file_name, sk_sp< SkImage > scene_image)
bool WriteAtomically(const fml::UniqueFD &base_directory, const char *file_name, const Mapping &mapping)
Definition: file_posix.cc:190