Flutter Engine
The Flutter Engine
image_decoder_unittests.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#include "flutter/common/task_runners.h"
6#include "flutter/fml/mapping.h"
7#include "flutter/fml/synchronization/waitable_event.h"
8#include "flutter/impeller/core/allocator.h"
9#include "flutter/impeller/core/device_buffer.h"
10#include "flutter/impeller/geometry/size.h"
11#include "flutter/impeller/renderer/context.h"
12#include "flutter/lib/ui/painting/image_decoder.h"
13#include "flutter/lib/ui/painting/image_decoder_impeller.h"
14#include "flutter/lib/ui/painting/image_decoder_no_gl_unittests.h"
15#include "flutter/lib/ui/painting/image_decoder_skia.h"
16#include "flutter/lib/ui/painting/multi_frame_codec.h"
17#include "flutter/runtime/dart_vm.h"
18#include "flutter/runtime/dart_vm_lifecycle.h"
19#include "flutter/testing/dart_isolate_runner.h"
20#include "flutter/testing/elf_loader.h"
21#include "flutter/testing/fixture_test.h"
22#include "flutter/testing/post_task_sync.h"
23#include "flutter/testing/test_dart_native_resolver.h"
24#include "flutter/testing/test_gl_surface.h"
25#include "flutter/testing/testing.h"
26#include "fml/logging.h"
34
35// CREATE_NATIVE_ENTRY is leaky by design
36// NOLINTBEGIN(clang-analyzer-core.StackAddressEscape)
37
38namespace impeller {
39
41 public:
43
44 BackendType GetBackendType() const override { return BackendType::kMetal; }
45
46 std::string DescribeGpuModel() const override { return "TestGpu"; }
47
48 bool IsValid() const override { return true; }
49
50 const std::shared_ptr<const Capabilities>& GetCapabilities() const override {
51 return capabilities_;
52 }
53
54 std::shared_ptr<Allocator> GetResourceAllocator() const override {
55 return std::make_shared<TestImpellerAllocator>();
56 }
57
58 std::shared_ptr<ShaderLibrary> GetShaderLibrary() const override {
59 return nullptr;
60 }
61
62 std::shared_ptr<SamplerLibrary> GetSamplerLibrary() const override {
63 return nullptr;
64 }
65
66 std::shared_ptr<PipelineLibrary> GetPipelineLibrary() const override {
67 return nullptr;
68 }
69
70 std::shared_ptr<CommandQueue> GetCommandQueue() const override {
72 }
73
74 std::shared_ptr<CommandBuffer> CreateCommandBuffer() const override {
76 return nullptr;
77 }
78
79 void Shutdown() override {}
80
81 mutable size_t command_buffer_count_ = 0;
82
83 private:
84 std::shared_ptr<const Capabilities> capabilities_;
85};
86
87} // namespace impeller
88
89namespace flutter {
90namespace testing {
91
92class TestIOManager final : public IOManager {
93 public:
94 explicit TestIOManager(const fml::RefPtr<fml::TaskRunner>& task_runner,
95 bool has_gpu_context = true)
96 : gl_surface_(SkISize::Make(1, 1)),
97 impeller_context_(std::make_shared<impeller::TestImpellerContext>()),
98 gl_context_(has_gpu_context ? gl_surface_.CreateGrContext() : nullptr),
99 weak_gl_context_factory_(
100 has_gpu_context
101 ? std::make_unique<fml::WeakPtrFactory<GrDirectContext>>(
102 gl_context_.get())
103 : nullptr),
104 unref_queue_(fml::MakeRefCounted<SkiaUnrefQueue>(
105 task_runner,
106 fml::TimeDelta::FromNanoseconds(0),
107 gl_context_)),
108 runner_(task_runner),
109 is_gpu_disabled_sync_switch_(std::make_shared<fml::SyncSwitch>()),
110 weak_factory_(this) {
111 FML_CHECK(task_runner->RunsTasksOnCurrentThread())
112 << "The IO manager must be initialized its primary task runner. The "
113 "test harness may not be set up correctly/safely.";
114 weak_prototype_ = weak_factory_.GetWeakPtr();
115 }
116
117 ~TestIOManager() override {
120 [&latch, queue = unref_queue_]() {
121 queue->Drain();
122 latch.Signal();
123 });
124 latch.Wait();
125 }
126
127 // |IOManager|
129 return weak_prototype_;
130 }
131
132 // |IOManager|
134 return weak_gl_context_factory_ ? weak_gl_context_factory_->GetWeakPtr()
136 }
137
138 // |IOManager|
140 return unref_queue_;
141 }
142
143 // |IOManager|
144 std::shared_ptr<const fml::SyncSwitch> GetIsGpuDisabledSyncSwitch() override {
146 return is_gpu_disabled_sync_switch_;
147 }
148
149 // |IOManager|
150 std::shared_ptr<impeller::Context> GetImpellerContext() const override {
151 return impeller_context_;
152 }
153
154 void SetGpuDisabled(bool disabled) {
155 is_gpu_disabled_sync_switch_->SetSwitch(disabled);
156 }
157
159
160 private:
161 TestGLSurface gl_surface_;
162 std::shared_ptr<impeller::Context> impeller_context_;
163 sk_sp<GrDirectContext> gl_context_;
164 std::unique_ptr<fml::WeakPtrFactory<GrDirectContext>>
165 weak_gl_context_factory_;
166 fml::RefPtr<SkiaUnrefQueue> unref_queue_;
167 fml::WeakPtr<TestIOManager> weak_prototype_;
169 std::shared_ptr<fml::SyncSwitch> is_gpu_disabled_sync_switch_;
171
172 FML_DISALLOW_COPY_AND_ASSIGN(TestIOManager);
173};
174
176
177TEST_F(ImageDecoderFixtureTest, CanCreateImageDecoder) {
179 auto thread_task_runner = CreateNewThread();
180 TaskRunners runners(GetCurrentTestName(), // label
181 thread_task_runner, // platform
182 thread_task_runner, // raster
183 thread_task_runner, // ui
184 thread_task_runner // io
185
186 );
187
188 PostTaskSync(runners.GetIOTaskRunner(), [&]() {
189 TestIOManager manager(runners.GetIOTaskRunner());
190 Settings settings;
191 auto decoder = ImageDecoder::Make(settings, runners, loop->GetTaskRunner(),
192 manager.GetWeakIOManager(),
193 std::make_shared<fml::SyncSwitch>());
194 ASSERT_NE(decoder, nullptr);
195 });
196}
197
198/// An Image generator that pretends it can't recognize the data it was given.
200 public:
201 UnknownImageGenerator() : info_(SkImageInfo::MakeUnknown()){};
203 const SkImageInfo& GetInfo() { return info_; }
204
205 unsigned int GetFrameCount() const { return 1; }
206
207 unsigned int GetPlayCount() const { return 1; }
208
209 const ImageGenerator::FrameInfo GetFrameInfo(unsigned int frame_index) {
210 return {std::nullopt, 0, SkCodecAnimation::DisposalMethod::kKeep};
211 }
212
214 return SkISize::Make(info_.width(), info_.height());
215 }
216
218 void* pixels,
219 size_t row_bytes,
220 unsigned int frame_index,
221 std::optional<unsigned int> prior_frame) {
222 return false;
223 };
224
225 private:
226 SkImageInfo info_;
227};
228
229TEST_F(ImageDecoderFixtureTest, InvalidImageResultsError) {
231 auto thread_task_runner = CreateNewThread();
232 TaskRunners runners(GetCurrentTestName(), // label
233 thread_task_runner, // platform
234 thread_task_runner, // raster
235 thread_task_runner, // ui
236 thread_task_runner // io
237 );
238
240 thread_task_runner->PostTask([&]() {
243 auto decoder = ImageDecoder::Make(settings, runners, loop->GetTaskRunner(),
244 manager.GetWeakIOManager(),
245 std::make_shared<fml::SyncSwitch>());
246
247 auto data = flutter::testing::OpenFixtureAsSkData("ThisDoesNotExist.jpg");
248 ASSERT_FALSE(data);
249
250 fml::RefPtr<ImageDescriptor> image_descriptor =
251 fml::MakeRefCounted<ImageDescriptor>(
252 std::move(data), std::make_unique<UnknownImageGenerator>());
253
255 const std::string& decode_error) {
256 ASSERT_TRUE(runners.GetUITaskRunner()->RunsTasksOnCurrentThread());
257 ASSERT_FALSE(image);
258 latch.Signal();
259 };
260 decoder->Decode(image_descriptor, 0, 0, callback);
261 });
262 latch.Wait();
263}
264
265TEST_F(ImageDecoderFixtureTest, ValidImageResultsInSuccess) {
267 TaskRunners runners(GetCurrentTestName(), // label
268 CreateNewThread("platform"), // platform
269 CreateNewThread("raster"), // raster
270 CreateNewThread("ui"), // ui
271 CreateNewThread("io") // io
272 );
273
275
276 std::unique_ptr<TestIOManager> io_manager;
277
278 auto release_io_manager = [&]() {
279 io_manager.reset();
280 latch.Signal();
281 };
282 auto decode_image = [&]() {
284 std::unique_ptr<ImageDecoder> image_decoder = ImageDecoder::Make(
285 settings, runners, loop->GetTaskRunner(),
286 io_manager->GetWeakIOManager(), std::make_shared<fml::SyncSwitch>());
287
288 auto data = flutter::testing::OpenFixtureAsSkData("DashInNooglerHat.jpg");
289
290 ASSERT_TRUE(data);
291 ASSERT_GE(data->size(), 0u);
292
293 ImageGeneratorRegistry registry;
294 std::shared_ptr<ImageGenerator> generator =
296 ASSERT_TRUE(generator);
297
298 auto descriptor = fml::MakeRefCounted<ImageDescriptor>(
299 std::move(data), std::move(generator));
300
302 const std::string& decode_error) {
303 ASSERT_TRUE(runners.GetUITaskRunner()->RunsTasksOnCurrentThread());
304 ASSERT_TRUE(image && image->skia_image());
305 EXPECT_TRUE(io_manager->did_access_is_gpu_disabled_sync_switch_);
306 runners.GetIOTaskRunner()->PostTask(release_io_manager);
307 };
308 EXPECT_FALSE(io_manager->did_access_is_gpu_disabled_sync_switch_);
309 image_decoder->Decode(descriptor, descriptor->width(), descriptor->height(),
310 callback);
311 };
312
313 auto set_up_io_manager_and_decode = [&]() {
314 io_manager = std::make_unique<TestIOManager>(runners.GetIOTaskRunner());
315 runners.GetUITaskRunner()->PostTask(decode_image);
316 };
317
318 runners.GetIOTaskRunner()->PostTask(set_up_io_manager_and_decode);
319 latch.Wait();
320}
321
322TEST_F(ImageDecoderFixtureTest, ImpellerUploadToSharedNoGpu) {
323#if !IMPELLER_SUPPORTS_RENDERING
324 GTEST_SKIP() << "Impeller only test.";
325#endif // IMPELLER_SUPPORTS_RENDERING
326
327 auto no_gpu_access_context =
328 std::make_shared<impeller::TestImpellerContext>();
329 auto gpu_disabled_switch = std::make_shared<fml::SyncSwitch>(true);
330
333 auto bitmap = std::make_shared<SkBitmap>();
334 bitmap->allocPixels(info, 10 * 4);
336 desc.size = bitmap->computeByteSize();
337 auto buffer = std::make_shared<impeller::TestImpellerDeviceBuffer>(desc);
338
340 no_gpu_access_context, buffer, info, bitmap, gpu_disabled_switch);
341 ASSERT_EQ(no_gpu_access_context->command_buffer_count_, 0ul);
342 ASSERT_EQ(result.second, "");
343
345 no_gpu_access_context, bitmap, gpu_disabled_switch,
347 ASSERT_EQ(no_gpu_access_context->command_buffer_count_, 0ul);
348 ASSERT_EQ(result.second, "");
349}
350
351TEST_F(ImageDecoderFixtureTest, ImpellerNullColorspace) {
355 bitmap.allocPixels(info, 10 * 4);
356 auto data = SkData::MakeWithoutCopy(bitmap.getPixels(), 10 * 10 * 4);
358 ASSERT_TRUE(image != nullptr);
359 ASSERT_EQ(SkISize::Make(10, 10), image->dimensions());
360 ASSERT_EQ(nullptr, image->colorSpace());
361
362 auto descriptor = fml::MakeRefCounted<ImageDescriptor>(
363 std::move(data), image->imageInfo(), 10 * 4);
364
365#if IMPELLER_SUPPORTS_RENDERING
366 std::shared_ptr<impeller::Allocator> allocator =
367 std::make_shared<impeller::TestImpellerAllocator>();
368 std::optional<DecompressResult> decompressed =
370 descriptor.get(), SkISize::Make(100, 100), {100, 100},
371 /*supports_wide_gamut=*/true, allocator);
372 ASSERT_TRUE(decompressed.has_value());
373 ASSERT_EQ(decompressed->image_info.colorType(), kRGBA_8888_SkColorType);
374 ASSERT_EQ(decompressed->image_info.colorSpace(), nullptr);
375#endif // IMPELLER_SUPPORTS_RENDERING
376}
377
378TEST_F(ImageDecoderFixtureTest, ImpellerPixelConversion32F) {
382 bitmap.allocPixels(info, 10 * 16);
383 auto data = SkData::MakeWithoutCopy(bitmap.getPixels(), 10 * 10 * 16);
385 ASSERT_TRUE(image != nullptr);
386 ASSERT_EQ(SkISize::Make(10, 10), image->dimensions());
387 ASSERT_EQ(nullptr, image->colorSpace());
388
389 auto descriptor = fml::MakeRefCounted<ImageDescriptor>(
390 std::move(data), image->imageInfo(), 10 * 16);
391
392#if IMPELLER_SUPPORTS_RENDERING
393 std::shared_ptr<impeller::Allocator> allocator =
394 std::make_shared<impeller::TestImpellerAllocator>();
395 std::optional<DecompressResult> decompressed =
397 descriptor.get(), SkISize::Make(100, 100), {100, 100},
398 /*supports_wide_gamut=*/true, allocator);
399
400 ASSERT_TRUE(decompressed.has_value());
401 ASSERT_EQ(decompressed->image_info.colorType(), kRGBA_F16_SkColorType);
402 ASSERT_EQ(decompressed->image_info.colorSpace(), nullptr);
403#endif // IMPELLER_SUPPORTS_RENDERING
404}
405
406TEST_F(ImageDecoderFixtureTest, ImpellerWideGamutDisplayP3Opaque) {
407 auto data = flutter::testing::OpenFixtureAsSkData("DisplayP3Logo.jpg");
409 ASSERT_TRUE(image != nullptr);
410 ASSERT_EQ(SkISize::Make(100, 100), image->dimensions());
411
412 ImageGeneratorRegistry registry;
413 std::shared_ptr<ImageGenerator> generator =
415 ASSERT_TRUE(generator);
416
417 auto descriptor = fml::MakeRefCounted<ImageDescriptor>(std::move(data),
418 std::move(generator));
419
420#if IMPELLER_SUPPORTS_RENDERING
421 std::shared_ptr<impeller::Allocator> allocator =
422 std::make_shared<impeller::TestImpellerAllocator>();
423 std::optional<DecompressResult> wide_result =
425 descriptor.get(), SkISize::Make(100, 100), {100, 100},
426 /*supports_wide_gamut=*/true, allocator);
427
428 ASSERT_TRUE(wide_result.has_value());
429 ASSERT_EQ(wide_result->image_info.colorType(), kBGR_101010x_XR_SkColorType);
430 ASSERT_TRUE(wide_result->image_info.colorSpace()->isSRGB());
431
432 const SkPixmap& wide_pixmap = wide_result->sk_bitmap->pixmap();
433 const uint32_t* pixel_ptr = static_cast<const uint32_t*>(wide_pixmap.addr());
434 bool found_deep_red = false;
435 for (int i = 0; i < wide_pixmap.width() * wide_pixmap.height(); ++i) {
436 uint32_t pixel = *pixel_ptr++;
437 float blue = DecodeBGR10((pixel >> 0) & 0x3ff);
438 float green = DecodeBGR10((pixel >> 10) & 0x3ff);
439 float red = DecodeBGR10((pixel >> 20) & 0x3ff);
440 if (fabsf(red - 1.0931f) < 0.01f && fabsf(green - -0.2268f) < 0.01f &&
441 fabsf(blue - -0.1501f) < 0.01f) {
442 found_deep_red = true;
443 break;
444 }
445 }
446 ASSERT_TRUE(found_deep_red);
447
448 std::optional<DecompressResult> narrow_result =
450 descriptor.get(), SkISize::Make(100, 100), {100, 100},
451 /*supports_wide_gamut=*/false, allocator);
452
453 ASSERT_TRUE(narrow_result.has_value());
454 ASSERT_EQ(narrow_result->image_info.colorType(), kRGBA_8888_SkColorType);
455#endif // IMPELLER_SUPPORTS_RENDERING
456}
457
458TEST_F(ImageDecoderFixtureTest, ImpellerNonWideGamut) {
459 auto data = flutter::testing::OpenFixtureAsSkData("Horizontal.jpg");
461 ASSERT_TRUE(image != nullptr);
462 ASSERT_EQ(SkISize::Make(600, 200), image->dimensions());
463
464 ImageGeneratorRegistry registry;
465 std::shared_ptr<ImageGenerator> generator =
467 ASSERT_TRUE(generator);
468
469 auto descriptor = fml::MakeRefCounted<ImageDescriptor>(std::move(data),
470 std::move(generator));
471
472#if IMPELLER_SUPPORTS_RENDERING
473 std::shared_ptr<impeller::Allocator> allocator =
474 std::make_shared<impeller::TestImpellerAllocator>();
475 std::optional<DecompressResult> result =
477 descriptor.get(), SkISize::Make(600, 200), {600, 200},
478 /*supports_wide_gamut=*/true, allocator);
479
480 ASSERT_TRUE(result.has_value());
481 ASSERT_EQ(result->image_info.colorType(), kRGBA_8888_SkColorType);
482#endif // IMPELLER_SUPPORTS_RENDERING
483}
484
485TEST_F(ImageDecoderFixtureTest, ExifDataIsRespectedOnDecode) {
487 TaskRunners runners(GetCurrentTestName(), // label
488 CreateNewThread("platform"), // platform
489 CreateNewThread("raster"), // raster
490 CreateNewThread("ui"), // ui
491 CreateNewThread("io") // io
492 );
493
495
496 std::unique_ptr<IOManager> io_manager;
497
498 auto release_io_manager = [&]() {
499 io_manager.reset();
500 latch.Signal();
501 };
502
503 SkISize decoded_size = SkISize::MakeEmpty();
504 auto decode_image = [&]() {
506 std::unique_ptr<ImageDecoder> image_decoder = ImageDecoder::Make(
507 settings, runners, loop->GetTaskRunner(),
508 io_manager->GetWeakIOManager(), std::make_shared<fml::SyncSwitch>());
509
510 auto data = flutter::testing::OpenFixtureAsSkData("Horizontal.jpg");
511
512 ASSERT_TRUE(data);
513 ASSERT_GE(data->size(), 0u);
514
515 ImageGeneratorRegistry registry;
516 std::shared_ptr<ImageGenerator> generator =
518 ASSERT_TRUE(generator);
519
520 auto descriptor = fml::MakeRefCounted<ImageDescriptor>(
521 std::move(data), std::move(generator));
522
524 const std::string& decode_error) {
525 ASSERT_TRUE(runners.GetUITaskRunner()->RunsTasksOnCurrentThread());
526 ASSERT_TRUE(image && image->skia_image());
527 decoded_size = image->skia_image()->dimensions();
528 runners.GetIOTaskRunner()->PostTask(release_io_manager);
529 };
530 image_decoder->Decode(descriptor, descriptor->width(), descriptor->height(),
531 callback);
532 };
533
534 auto set_up_io_manager_and_decode = [&]() {
535 io_manager = std::make_unique<TestIOManager>(runners.GetIOTaskRunner());
536 runners.GetUITaskRunner()->PostTask(decode_image);
537 };
538
539 runners.GetIOTaskRunner()->PostTask(set_up_io_manager_and_decode);
540
541 latch.Wait();
542
543 ASSERT_EQ(decoded_size.width(), 600);
544 ASSERT_EQ(decoded_size.height(), 200);
545}
546
547TEST_F(ImageDecoderFixtureTest, CanDecodeWithoutAGPUContext) {
549 TaskRunners runners(GetCurrentTestName(), // label
550 CreateNewThread("platform"), // platform
551 CreateNewThread("raster"), // raster
552 CreateNewThread("ui"), // ui
553 CreateNewThread("io") // io
554 );
555
557
558 std::unique_ptr<IOManager> io_manager;
559
560 auto release_io_manager = [&]() {
561 io_manager.reset();
562 latch.Signal();
563 };
564
565 auto decode_image = [&]() {
567 std::unique_ptr<ImageDecoder> image_decoder = ImageDecoder::Make(
568 settings, runners, loop->GetTaskRunner(),
569 io_manager->GetWeakIOManager(), std::make_shared<fml::SyncSwitch>());
570
571 auto data = flutter::testing::OpenFixtureAsSkData("DashInNooglerHat.jpg");
572
573 ASSERT_TRUE(data);
574 ASSERT_GE(data->size(), 0u);
575
576 ImageGeneratorRegistry registry;
577 std::shared_ptr<ImageGenerator> generator =
579 ASSERT_TRUE(generator);
580
581 auto descriptor = fml::MakeRefCounted<ImageDescriptor>(
582 std::move(data), std::move(generator));
583
585 const std::string& decode_error) {
586 ASSERT_TRUE(runners.GetUITaskRunner()->RunsTasksOnCurrentThread());
587 ASSERT_TRUE(image && image->skia_image());
588 runners.GetIOTaskRunner()->PostTask(release_io_manager);
589 };
590 image_decoder->Decode(descriptor, descriptor->width(), descriptor->height(),
591 callback);
592 };
593
594 auto set_up_io_manager_and_decode = [&]() {
595 io_manager =
596 std::make_unique<TestIOManager>(runners.GetIOTaskRunner(), false);
597 runners.GetUITaskRunner()->PostTask(decode_image);
598 };
599
600 runners.GetIOTaskRunner()->PostTask(set_up_io_manager_and_decode);
601
602 latch.Wait();
603}
604
605TEST_F(ImageDecoderFixtureTest, CanDecodeWithResizes) {
606 const auto image_dimensions =
608 flutter::testing::OpenFixtureAsSkData("DashInNooglerHat.jpg"))
609 ->dimensions();
610
611 ASSERT_FALSE(image_dimensions.isEmpty());
612
613 ASSERT_NE(image_dimensions.width(), image_dimensions.height());
614
616 TaskRunners runners(GetCurrentTestName(), // label
617 CreateNewThread("platform"), // platform
618 CreateNewThread("raster"), // raster
619 CreateNewThread("ui"), // ui
620 CreateNewThread("io") // io
621 );
622
624 std::unique_ptr<IOManager> io_manager;
625 std::unique_ptr<ImageDecoder> image_decoder;
626
627 // Setup the IO manager.
628 PostTaskSync(runners.GetIOTaskRunner(), [&]() {
629 io_manager = std::make_unique<TestIOManager>(runners.GetIOTaskRunner());
630 });
631
632 // Setup the image decoder.
633 PostTaskSync(runners.GetUITaskRunner(), [&]() {
634 Settings settings;
635 image_decoder = ImageDecoder::Make(settings, runners, loop->GetTaskRunner(),
636 io_manager->GetWeakIOManager(),
637 std::make_shared<fml::SyncSwitch>());
638 });
639
640 // Setup a generic decoding utility that gives us the final decoded size.
641 auto decoded_size = [&](uint32_t target_width,
642 uint32_t target_height) -> SkISize {
643 SkISize final_size = SkISize::MakeEmpty();
644 runners.GetUITaskRunner()->PostTask([&]() {
645 auto data = flutter::testing::OpenFixtureAsSkData("DashInNooglerHat.jpg");
646
647 ASSERT_TRUE(data);
648 ASSERT_GE(data->size(), 0u);
649
650 ImageGeneratorRegistry registry;
651 std::shared_ptr<ImageGenerator> generator =
653 ASSERT_TRUE(generator);
654
655 auto descriptor = fml::MakeRefCounted<ImageDescriptor>(
656 std::move(data), std::move(generator));
657
659 [&](const sk_sp<DlImage>& image, const std::string& decode_error) {
660 ASSERT_TRUE(runners.GetUITaskRunner()->RunsTasksOnCurrentThread());
661 ASSERT_TRUE(image && image->skia_image());
662 final_size = image->skia_image()->dimensions();
663 latch.Signal();
664 };
665 image_decoder->Decode(descriptor, target_width, target_height, callback);
666 });
667 latch.Wait();
668 return final_size;
669 };
670
671 ASSERT_EQ(SkISize::Make(3024, 4032), image_dimensions);
672 ASSERT_EQ(decoded_size(3024, 4032), image_dimensions);
673 ASSERT_EQ(decoded_size(100, 100), SkISize::Make(100, 100));
674
675 // Destroy the IO manager
676 PostTaskSync(runners.GetIOTaskRunner(), [&]() { io_manager.reset(); });
677
678 // Destroy the image decoder
679 PostTaskSync(runners.GetUITaskRunner(), [&]() { image_decoder.reset(); });
680}
681
682// Verifies https://skia-review.googlesource.com/c/skia/+/259161 is present in
683// Flutter.
684TEST(ImageDecoderTest,
685 VerifyCodecRepeatCountsForGifAndWebPAreConsistentWithLoopCounts) {
686 auto gif_mapping = flutter::testing::OpenFixtureAsSkData("hello_loop_2.gif");
687 auto webp_mapping =
688 flutter::testing::OpenFixtureAsSkData("hello_loop_2.webp");
689
690 ASSERT_TRUE(gif_mapping);
691 ASSERT_TRUE(webp_mapping);
692
693 ImageGeneratorRegistry registry;
694
695 auto gif_generator = registry.CreateCompatibleGenerator(gif_mapping);
696 auto webp_generator = registry.CreateCompatibleGenerator(webp_mapping);
697
698 ASSERT_TRUE(gif_generator);
699 ASSERT_TRUE(webp_generator);
700
701 // Both fixtures have a loop count of 2.
702 ASSERT_EQ(gif_generator->GetPlayCount(), static_cast<unsigned int>(2));
703 ASSERT_EQ(webp_generator->GetPlayCount(), static_cast<unsigned int>(2));
704}
705
706TEST(ImageDecoderTest, VerifySimpleDecoding) {
707 auto data = flutter::testing::OpenFixtureAsSkData("Horizontal.jpg");
709 ASSERT_TRUE(image != nullptr);
710 ASSERT_EQ(600, image->width());
711 ASSERT_EQ(200, image->height());
712
713 ImageGeneratorRegistry registry;
714 std::shared_ptr<ImageGenerator> generator =
716 ASSERT_TRUE(generator);
717
718 auto descriptor = fml::MakeRefCounted<ImageDescriptor>(std::move(data),
719 std::move(generator));
720 auto compressed_image = ImageDecoderSkia::ImageFromCompressedData(
721 descriptor.get(), 6, 2, fml::tracing::TraceFlow(""));
722 ASSERT_EQ(compressed_image->width(), 6);
723 ASSERT_EQ(compressed_image->height(), 2);
724 ASSERT_EQ(compressed_image->alphaType(), kOpaque_SkAlphaType);
725
726#if IMPELLER_SUPPORTS_RENDERING
727 std::shared_ptr<impeller::Allocator> allocator =
728 std::make_shared<impeller::TestImpellerAllocator>();
730 descriptor.get(), SkISize::Make(6, 2), {100, 100},
731 /*supports_wide_gamut=*/false, allocator);
732 ASSERT_EQ(result_1.sk_bitmap->width(), 6);
733 ASSERT_EQ(result_1.sk_bitmap->height(), 2);
734
736 descriptor.get(), SkISize::Make(60, 20), {10, 10},
737 /*supports_wide_gamut=*/false, allocator);
738 ASSERT_EQ(result_2.sk_bitmap->width(), 10);
739 ASSERT_EQ(result_2.sk_bitmap->height(), 10);
740#endif // IMPELLER_SUPPORTS_RENDERING
741}
742
743TEST(ImageDecoderTest, ImagesWithTransparencyArePremulAlpha) {
744 auto data = flutter::testing::OpenFixtureAsSkData("heart_end.png");
745 ASSERT_TRUE(data);
746 ImageGeneratorRegistry registry;
747 std::shared_ptr<ImageGenerator> generator =
749 ASSERT_TRUE(generator);
750
751 auto descriptor = fml::MakeRefCounted<ImageDescriptor>(std::move(data),
752 std::move(generator));
753 auto compressed_image = ImageDecoderSkia::ImageFromCompressedData(
754 descriptor.get(), 250, 250, fml::tracing::TraceFlow(""));
755 ASSERT_TRUE(compressed_image);
756 ASSERT_EQ(compressed_image->width(), 250);
757 ASSERT_EQ(compressed_image->height(), 250);
758 ASSERT_EQ(compressed_image->alphaType(), kPremul_SkAlphaType);
759}
760
761TEST(ImageDecoderTest, VerifySubpixelDecodingPreservesExifOrientation) {
762 auto data = flutter::testing::OpenFixtureAsSkData("Horizontal.jpg");
763
764 ImageGeneratorRegistry registry;
765 std::shared_ptr<ImageGenerator> generator =
767 ASSERT_TRUE(generator);
768 auto descriptor =
769 fml::MakeRefCounted<ImageDescriptor>(data, std::move(generator));
770
771 // If Exif metadata is ignored, the height and width will be swapped because
772 // "Rotate 90 CW" is what is encoded there.
773 ASSERT_EQ(600, descriptor->width());
774 ASSERT_EQ(200, descriptor->height());
775
777 ASSERT_TRUE(image != nullptr);
778 ASSERT_EQ(600, image->width());
779 ASSERT_EQ(200, image->height());
780
781 auto decode = [descriptor](uint32_t target_width, uint32_t target_height) {
783 descriptor.get(), target_width, target_height,
785 };
786
787 auto expected_data = flutter::testing::OpenFixtureAsSkData("Horizontal.png");
788 ASSERT_TRUE(expected_data != nullptr);
789 ASSERT_FALSE(expected_data->isEmpty());
790
791 auto assert_image = [&](auto decoded_image, const std::string& decode_error) {
792 ASSERT_EQ(decoded_image->dimensions(), SkISize::Make(300, 100));
793 sk_sp<SkData> encoded =
794 SkPngEncoder::Encode(nullptr, decoded_image.get(), {});
795 ASSERT_TRUE(encoded->equals(expected_data.get()));
796 };
797
798 assert_image(decode(300, 100), {});
799}
800
802 MultiFrameCodecCanBeCollectedBeforeIOTasksFinish) {
803 // This test verifies that the MultiFrameCodec safely shares state between
804 // tasks on the IO and UI runners, and does not allow unsafe memory access if
805 // the UI object is collected while the IO thread still has pending decode
806 // work. This could happen in a real application if the engine is collected
807 // while a multi-frame image is decoding. To exercise this, the test:
808 // - Starts a Dart VM
809 // - Latches the IO task runner
810 // - Create a MultiFrameCodec for an animated gif pointed to a callback
811 // in the Dart fixture
812 // - Calls getNextFrame on the UI task runner
813 // - Collects the MultiFrameCodec object before unlatching the IO task
814 // runner.
815 // - Unlatches the IO task runner
816 auto settings = CreateSettingsForFixture();
817 auto vm_ref = DartVMRef::Create(settings);
818 auto vm_data = vm_ref.GetVMData();
819
820 auto gif_mapping = flutter::testing::OpenFixtureAsSkData("hello_loop_2.gif");
821
822 ASSERT_TRUE(gif_mapping);
823
824 ImageGeneratorRegistry registry;
825 std::shared_ptr<ImageGenerator> gif_generator =
826 registry.CreateCompatibleGenerator(gif_mapping);
827 ASSERT_TRUE(gif_generator);
828
829 TaskRunners runners(GetCurrentTestName(), // label
830 CreateNewThread("platform"), // platform
831 CreateNewThread("raster"), // raster
832 CreateNewThread("ui"), // ui
833 CreateNewThread("io") // io
834 );
835
837 std::unique_ptr<TestIOManager> io_manager;
838
839 // Setup the IO manager.
840 PostTaskSync(runners.GetIOTaskRunner(), [&]() {
841 io_manager = std::make_unique<TestIOManager>(runners.GetIOTaskRunner());
842 });
843
844 auto isolate = RunDartCodeInIsolate(vm_ref, settings, runners, "main", {},
846 io_manager->GetWeakIOManager());
847
848 // Latch the IO task runner.
849 runners.GetIOTaskRunner()->PostTask([&]() { io_latch.Wait(); });
850
851 PostTaskSync(runners.GetUITaskRunner(), [&]() {
852 fml::AutoResetWaitableEvent isolate_latch;
853 fml::RefPtr<MultiFrameCodec> codec;
854 EXPECT_TRUE(isolate->RunInIsolateScope([&]() -> bool {
855 Dart_Handle library = Dart_RootLibrary();
856 if (Dart_IsError(library)) {
857 isolate_latch.Signal();
858 return false;
859 }
860 Dart_Handle closure =
861 Dart_GetField(library, Dart_NewStringFromCString("frameCallback"));
862 if (Dart_IsError(closure) || !Dart_IsClosure(closure)) {
863 isolate_latch.Signal();
864 return false;
865 }
866
867 codec = fml::MakeRefCounted<MultiFrameCodec>(std::move(gif_generator));
868 codec->getNextFrame(closure);
869 codec = nullptr;
870 isolate_latch.Signal();
871 return true;
872 }));
873 isolate_latch.Wait();
874
875 EXPECT_FALSE(codec);
876
877 io_latch.Signal();
878 });
879
880 // Destroy the IO manager
881 PostTaskSync(runners.GetIOTaskRunner(), [&]() { io_manager.reset(); });
882}
883
884TEST_F(ImageDecoderFixtureTest, MultiFrameCodecDidAccessGpuDisabledSyncSwitch) {
885 auto settings = CreateSettingsForFixture();
886 auto vm_ref = DartVMRef::Create(settings);
887 auto vm_data = vm_ref.GetVMData();
888
889 auto gif_mapping = flutter::testing::OpenFixtureAsSkData("hello_loop_2.gif");
890
891 ASSERT_TRUE(gif_mapping);
892
893 ImageGeneratorRegistry registry;
894 std::shared_ptr<ImageGenerator> gif_generator =
895 registry.CreateCompatibleGenerator(gif_mapping);
896 ASSERT_TRUE(gif_generator);
897
898 TaskRunners runners(GetCurrentTestName(), // label
899 CreateNewThread("platform"), // platform
900 CreateNewThread("raster"), // raster
901 CreateNewThread("ui"), // ui
902 CreateNewThread("io") // io
903 );
904
905 std::unique_ptr<TestIOManager> io_manager;
908
909 auto validate_frame_callback = [&latch](Dart_NativeArguments args) {
910 EXPECT_FALSE(Dart_IsNull(Dart_GetNativeArgument(args, 0)));
911 latch.Signal();
912 };
913
914 AddNativeCallback("ValidateFrameCallback",
915 CREATE_NATIVE_ENTRY(validate_frame_callback));
916 // Setup the IO manager.
917 PostTaskSync(runners.GetIOTaskRunner(), [&]() {
918 io_manager = std::make_unique<TestIOManager>(runners.GetIOTaskRunner());
919 });
920
921 auto isolate = RunDartCodeInIsolate(vm_ref, settings, runners, "main", {},
923 io_manager->GetWeakIOManager());
924
925 PostTaskSync(runners.GetUITaskRunner(), [&]() {
926 fml::AutoResetWaitableEvent isolate_latch;
927
928 EXPECT_TRUE(isolate->RunInIsolateScope([&]() -> bool {
929 Dart_Handle library = Dart_RootLibrary();
930 if (Dart_IsError(library)) {
931 isolate_latch.Signal();
932 return false;
933 }
934 Dart_Handle closure =
935 Dart_GetField(library, Dart_NewStringFromCString("frameCallback"));
936 if (Dart_IsError(closure) || !Dart_IsClosure(closure)) {
937 isolate_latch.Signal();
938 return false;
939 }
940
941 EXPECT_FALSE(io_manager->did_access_is_gpu_disabled_sync_switch_);
942 codec = fml::MakeRefCounted<MultiFrameCodec>(std::move(gif_generator));
943 codec->getNextFrame(closure);
944 isolate_latch.Signal();
945 return true;
946 }));
947 isolate_latch.Wait();
948 });
949
950 PostTaskSync(runners.GetIOTaskRunner(), [&]() {
951 EXPECT_TRUE(io_manager->did_access_is_gpu_disabled_sync_switch_);
952 });
953
954 latch.Wait();
955
956 // Destroy the Isolate
957 isolate = nullptr;
958
959 // Destroy the MultiFrameCodec
960 PostTaskSync(runners.GetUITaskRunner(), [&]() { codec = nullptr; });
961
962 // Destroy the IO manager
963 PostTaskSync(runners.GetIOTaskRunner(), [&]() { io_manager.reset(); });
964}
965
967 MultiFrameCodecProducesATextureEvenIfGPUIsDisabledOnImpeller) {
968 auto settings = CreateSettingsForFixture();
969 settings.enable_impeller = true;
970 auto vm_ref = DartVMRef::Create(settings);
971 auto vm_data = vm_ref.GetVMData();
972
973 auto gif_mapping = flutter::testing::OpenFixtureAsSkData("hello_loop_2.gif");
974
975 ASSERT_TRUE(gif_mapping);
976
977 ImageGeneratorRegistry registry;
978 std::shared_ptr<ImageGenerator> gif_generator =
979 registry.CreateCompatibleGenerator(gif_mapping);
980 ASSERT_TRUE(gif_generator);
981
982 TaskRunners runners(GetCurrentTestName(), // label
983 CreateNewThread("platform"), // platform
984 CreateNewThread("raster"), // raster
985 CreateNewThread("ui"), // ui
986 CreateNewThread("io") // io
987 );
988
989 std::unique_ptr<TestIOManager> io_manager;
992
993 auto validate_frame_callback = [&latch](Dart_NativeArguments args) {
994 EXPECT_FALSE(Dart_IsNull(Dart_GetNativeArgument(args, 0)));
995 latch.Signal();
996 };
997
998 AddNativeCallback("ValidateFrameCallback",
999 CREATE_NATIVE_ENTRY(validate_frame_callback));
1000
1001 // Setup the IO manager.
1002 PostTaskSync(runners.GetIOTaskRunner(), [&]() {
1003 io_manager = std::make_unique<TestIOManager>(runners.GetIOTaskRunner());
1004 // Mark GPU disabled.
1005 io_manager->SetGpuDisabled(true);
1006 });
1007
1008 auto isolate = RunDartCodeInIsolate(vm_ref, settings, runners, "main", {},
1010 io_manager->GetWeakIOManager());
1011
1012 PostTaskSync(runners.GetUITaskRunner(), [&]() {
1013 fml::AutoResetWaitableEvent isolate_latch;
1014
1015 EXPECT_TRUE(isolate->RunInIsolateScope([&]() -> bool {
1016 Dart_Handle library = Dart_RootLibrary();
1017 if (Dart_IsError(library)) {
1018 isolate_latch.Signal();
1019 return false;
1020 }
1021 Dart_Handle closure =
1022 Dart_GetField(library, Dart_NewStringFromCString("frameCallback"));
1023 if (Dart_IsError(closure) || !Dart_IsClosure(closure)) {
1024 isolate_latch.Signal();
1025 return false;
1026 }
1027
1028 EXPECT_FALSE(io_manager->did_access_is_gpu_disabled_sync_switch_);
1029 codec = fml::MakeRefCounted<MultiFrameCodec>(std::move(gif_generator));
1030 codec->getNextFrame(closure);
1031 isolate_latch.Signal();
1032 return true;
1033 }));
1034 isolate_latch.Wait();
1035 });
1036
1037 PostTaskSync(runners.GetIOTaskRunner(), [&]() {
1038 EXPECT_TRUE(io_manager->did_access_is_gpu_disabled_sync_switch_);
1039 });
1040
1041 latch.Wait();
1042
1043 // Destroy the Isolate
1044 isolate = nullptr;
1045
1046 // Destroy the MultiFrameCodec
1047 PostTaskSync(runners.GetUITaskRunner(), [&]() { codec = nullptr; });
1048
1049 // Destroy the IO manager
1050 PostTaskSync(runners.GetIOTaskRunner(), [&]() { io_manager.reset(); });
1051}
1052
1054 auto context = std::make_shared<impeller::TestImpellerContext>();
1055 auto allocator = ImpellerAllocator(context->GetResourceAllocator());
1056
1057 EXPECT_FALSE(allocator.allocPixelRef(nullptr));
1058}
1059
1060} // namespace testing
1061} // namespace flutter
1062
1063// NOLINTEND(clang-analyzer-core.StackAddressEscape)
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
kUnpremul_SkAlphaType
static sk_sp< Effect > Create()
Definition: RefCntTest.cpp:117
@ kOpaque_SkAlphaType
pixel is opaque
Definition: SkAlphaType.h:28
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
Definition: SkAlphaType.h:29
@ kRGBA_F16_SkColorType
pixel with half floats for red, green, blue, alpha;
Definition: SkColorType.h:38
@ kRGBA_8888_SkColorType
pixel with 8 bits for red, green, blue, alpha; in 32-bit word
Definition: SkColorType.h:24
@ kRGBA_F32_SkColorType
pixel using C float for red, green, blue, alpha; in 128-bit word
Definition: SkColorType.h:40
@ kBGR_101010x_XR_SkColorType
pixel with 10 bits each for blue, green, red; in 32-bit word, extended range
Definition: SkColorType.h:31
static sk_sp< SkData > MakeWithoutCopy(const void *data, size_t length)
Definition: SkData.h:116
bool equals(const SkData *other) const
Definition: SkData.cpp:43
const SkImageInfo & imageInfo() const
Definition: SkImage.h:279
SkColorSpace * colorSpace() const
Definition: SkImage.cpp:156
SkISize dimensions() const
Definition: SkImage.h:297
int width() const
Definition: SkImage.h:285
int height() const
Definition: SkImage.h:291
int width() const
Definition: SkPixmap.h:160
const void * addr() const
Definition: SkPixmap.h:153
int height() const
Definition: SkPixmap.h:166
static DartVMRef Create(const Settings &settings, fml::RefPtr< const DartSnapshot > vm_snapshot=nullptr, fml::RefPtr< const DartSnapshot > isolate_snapshot=nullptr)
static std::pair< sk_sp< DlImage >, std::string > UploadTextureToStorage(const std::shared_ptr< impeller::Context > &context, std::shared_ptr< SkBitmap > bitmap, const std::shared_ptr< fml::SyncSwitch > &gpu_disabled_switch, impeller::StorageMode storage_mode, bool create_mips=true)
Create a host visible texture from the provided bitmap.
static std::pair< sk_sp< DlImage >, std::string > UploadTextureToPrivate(const std::shared_ptr< impeller::Context > &context, const std::shared_ptr< impeller::DeviceBuffer > &buffer, const SkImageInfo &image_info, const std::shared_ptr< SkBitmap > &bitmap, const std::shared_ptr< fml::SyncSwitch > &gpu_disabled_switch)
Create a device private texture from the provided host buffer. This method is only suported on the me...
static DecompressResult DecompressTexture(ImageDescriptor *descriptor, SkISize target_size, impeller::ISize max_texture_size, bool supports_wide_gamut, const std::shared_ptr< impeller::Allocator > &allocator)
static sk_sp< SkImage > ImageFromCompressedData(ImageDescriptor *descriptor, uint32_t target_width, uint32_t target_height, const fml::tracing::TraceFlow &flow)
std::function< void(sk_sp< DlImage >, std::string)> ImageResult
Definition: image_decoder.h:35
static std::unique_ptr< ImageDecoder > Make(const Settings &settings, const TaskRunners &runners, std::shared_ptr< fml::ConcurrentTaskRunner > concurrent_task_runner, fml::WeakPtr< IOManager > io_manager, const std::shared_ptr< fml::SyncSwitch > &gpu_disabled_switch)
Keeps a priority-ordered registry of image generator builders to be used when decoding images....
std::shared_ptr< ImageGenerator > CreateCompatibleGenerator(const sk_sp< SkData > &buffer)
Walks the list of image generator builders in descending priority order until a compatible ImageGener...
The minimal interface necessary for defining a decoder that can be used for both single and multi-fra...
fml::RefPtr< fml::TaskRunner > GetUITaskRunner() const
Definition: task_runners.cc:34
fml::RefPtr< fml::TaskRunner > GetIOTaskRunner() const
Definition: task_runners.cc:38
fml::RefPtr< flutter::SkiaUnrefQueue > GetSkiaUnrefQueue() const override
std::shared_ptr< const fml::SyncSwitch > GetIsGpuDisabledSyncSwitch() override
fml::WeakPtr< IOManager > GetWeakIOManager() const override
std::shared_ptr< impeller::Context > GetImpellerContext() const override
TestIOManager(const fml::RefPtr< fml::TaskRunner > &task_runner, bool has_gpu_context=true)
fml::WeakPtr< GrDirectContext > GetResourceContext() const override
An Image generator that pretends it can't recognize the data it was given.
const SkImageInfo & GetInfo()
Returns basic information about the contents of the encoded image. This information can almost always...
unsigned int GetPlayCount() const
The number of times an animated image should play through before playback stops.
const ImageGenerator::FrameInfo GetFrameInfo(unsigned int frame_index)
Get information about a single frame in the context of a multi-frame image, useful for animation and ...
bool GetPixels(const SkImageInfo &info, void *pixels, size_t row_bytes, unsigned int frame_index, std::optional< unsigned int > prior_frame)
Decode the image into a given buffer. This method is currently always used for sub-pixel image decodi...
SkISize GetScaledDimensions(float scale)
Given a scale value, find the closest image size that can be used for efficiently decoding the image....
unsigned int GetFrameCount() const
Get the number of frames that the encoded image stores. This method is always expected to be called b...
static std::shared_ptr< ConcurrentMessageLoop > Create(size_t worker_count=std::thread::hardware_concurrency())
static void RunNowOrPostTask(const fml::RefPtr< fml::TaskRunner > &runner, const fml::closure &task)
Definition: task_runner.cc:55
virtual void PostTask(const fml::closure &task) override
Definition: task_runner.cc:24
virtual bool RunsTasksOnCurrentThread()
Definition: task_runner.cc:43
To do anything rendering related with Impeller, you need a context.
Definition: context.h:45
std::shared_ptr< CommandQueue > GetCommandQueue() const override
Return the graphics queue for submitting command buffers.
std::shared_ptr< ShaderLibrary > GetShaderLibrary() const override
Returns the library of shaders used to specify the programmable stages of a pipeline.
std::shared_ptr< PipelineLibrary > GetPipelineLibrary() const override
Returns the library of pipelines used by render or compute commands.
void Shutdown() override
Force all pending asynchronous work to finish. This is achieved by deleting all owned concurrent mess...
std::shared_ptr< Allocator > GetResourceAllocator() const override
Returns the allocator used to create textures and buffers on the device.
bool IsValid() const override
Determines if a context is valid. If the caller ever receives an invalid context, they must discard i...
const std::shared_ptr< const Capabilities > & GetCapabilities() const override
Get the capabilities of Impeller context. All optionally supported feature of the platform,...
std::string DescribeGpuModel() const override
BackendType GetBackendType() const override
Get the graphics backend of an Impeller context.
std::shared_ptr< CommandBuffer > CreateCommandBuffer() const override
Create a new command buffer. Command buffers can be used to encode graphics, blit,...
std::shared_ptr< SamplerLibrary > GetSamplerLibrary() const override
Returns the library of combined image samplers used in shaders.
DART_EXPORT Dart_Handle Dart_GetNativeArgument(Dart_NativeArguments args, int index)
struct _Dart_NativeArguments * Dart_NativeArguments
Definition: dart_api.h:3019
DART_EXPORT bool Dart_IsNull(Dart_Handle object)
VkQueue queue
Definition: main.cc:55
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
GAsyncResult * result
#define FML_CHECK(condition)
Definition: logging.h:85
#define FML_UNREACHABLE()
Definition: logging.h:109
fml::RefPtr< fml::TaskRunner > CreateNewThread(const std::string &name)
SK_API sk_sp< SkImage > DeferredFromEncodedData(sk_sp< SkData > encoded, std::optional< SkAlphaType > alphaType=std::nullopt)
SK_API sk_sp< SkImage > RasterFromBitmap(const SkBitmap &bitmap)
SK_API sk_sp< SkDocument > Make(SkWStream *dst, const SkSerialProcs *=nullptr, std::function< void(const SkPicture *)> onEndPage=nullptr)
SK_API bool Encode(SkWStream *dst, const SkPixmap &src, const Options &options)
sk_sp< const SkImage > image
Definition: SkRecords.h:269
Definition: bitmap.py:1
std::string GetCurrentTestName()
Gets the name of the currently running test. This is useful in generating logs or assets based on tes...
Definition: testing.cc:15
TEST_F(DisplayListTest, Defaults)
void PostTaskSync(const fml::RefPtr< fml::TaskRunner > &task_runner, const std::function< void()> &function)
std::string GetDefaultKernelFilePath()
Returns the default path to kernel_blob.bin. This file is within the directory returned by GetFixture...
Definition: testing.cc:19
sk_sp< SkData > OpenFixtureAsSkData(const std::string &fixture_name)
Opens a fixture of the given file name and returns a Skia SkData holding its contents.
Definition: testing.cc:64
std::unique_ptr< AutoIsolateShutdown > RunDartCodeInIsolate(DartVMRef &vm_ref, const Settings &settings, const TaskRunners &task_runners, std::string entrypoint, const std::vector< std::string > &args, const std::string &kernel_file_path, fml::WeakPtr< IOManager > io_manager, std::shared_ptr< VolatilePathTracker > volatile_path_tracker, std::unique_ptr< PlatformConfiguration > platform_configuration)
TEST_F(ImageDecoderFixtureTest, NullCheckBuffer)
TEST(DisplayListComplexity, EmptyDisplayList)
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font manager
Definition: switches.h:218
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
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition: switches.h:126
TEST_F(EngineAnimatorTest, AnimatorAcceptsMultipleRenders)
Definition: ascii_trie.cc:9
RefPtr< T > MakeRefCounted(Args &&... args)
Definition: ref_ptr.h:248
const myers::Point & get(const myers::Segment &)
Definition: ref_ptr.h:256
static DecodeResult decode(std::string path)
Definition: png_codec.cpp:124
const Scalar scale
Definition: SkSize.h:16
static constexpr SkISize MakeEmpty()
Definition: SkSize.h:22
static constexpr SkISize Make(int32_t w, int32_t h)
Definition: SkSize.h:20
constexpr int32_t width() const
Definition: SkSize.h:36
constexpr int32_t height() const
Definition: SkSize.h:37
int width() const
Definition: SkImageInfo.h:365
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)
int height() const
Definition: SkImageInfo.h:371
Info about a single frame in the context of a multi-frame image, useful for animation and blending.
#define CREATE_NATIVE_ENTRY(native_entry)
#define EXPECT_TRUE(handle)
Definition: unit_test.h:678