Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
image_encoding_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 "png.h"
6
9
19#include "gmock/gmock.h"
20#include "gtest/gtest.h"
21
22#if IMPELLER_SUPPORTS_RENDERING
25#endif // IMPELLER_SUPPORTS_RENDERING
26
27// CREATE_NATIVE_ENTRY is leaky by design
28// NOLINTBEGIN(clang-analyzer-core.StackAddressEscape)
29
30#pragma GCC diagnostic ignored "-Wunreachable-code"
31
32namespace flutter {
33namespace testing {
34
35namespace {
36fml::AutoResetWaitableEvent message_latch;
37
38class MockSyncSwitch {
39 public:
40 struct Handlers {
41 Handlers& SetIfTrue(const std::function<void()>& handler) {
43 return *this;
44 }
45 Handlers& SetIfFalse(const std::function<void()>& handler) {
47 return *this;
48 }
49 std::function<void()> true_handler = [] {};
50 std::function<void()> false_handler = [] {};
51 };
52
53 MOCK_METHOD(void, Execute, (const Handlers& handlers), (const));
54 MOCK_METHOD(void, SetSwitch, (bool value));
55};
56} // namespace
57
58TEST_F(ShellTest, EncodeImageGivesExternalTypedData) {
59 auto native_encode_image = [&](Dart_NativeArguments args) {
60 auto image_handle = Dart_GetNativeArgument(args, 0);
61 image_handle =
62 Dart_GetField(image_handle, Dart_NewStringFromCString("_image"));
63 ASSERT_FALSE(Dart_IsError(image_handle)) << Dart_GetError(image_handle);
64 ASSERT_FALSE(Dart_IsNull(image_handle));
65 auto format_handle = Dart_GetNativeArgument(args, 1);
66 auto callback_handle = Dart_GetNativeArgument(args, 2);
67
68 intptr_t peer = 0;
69 Dart_Handle result = Dart_GetNativeInstanceField(
70 image_handle, tonic::DartWrappable::kPeerIndex, &peer);
71 ASSERT_FALSE(Dart_IsError(result));
72 CanvasImage* canvas_image = reinterpret_cast<CanvasImage*>(peer);
73
74 int64_t format = -1;
75 result = Dart_IntegerToInt64(format_handle, &format);
76 ASSERT_FALSE(Dart_IsError(result));
77
78 result = EncodeImage(canvas_image, format, callback_handle);
79 ASSERT_TRUE(Dart_IsNull(result));
80 };
81
82 auto nativeValidateExternal = [&](Dart_NativeArguments args) {
83 auto handle = Dart_GetNativeArgument(args, 0);
84
85 auto typed_data_type = Dart_GetTypeOfExternalTypedData(handle);
86 EXPECT_EQ(typed_data_type, Dart_TypedData_kUint8);
87
88 message_latch.Signal();
89 };
90
91 Settings settings = CreateSettingsForFixture();
92 TaskRunners task_runners("test", // label
93 GetCurrentTaskRunner(), // platform
94 CreateNewThread(), // raster
95 CreateNewThread(), // ui
96 CreateNewThread() // io
97 );
98
99 AddNativeCallback("EncodeImage", CREATE_NATIVE_ENTRY(native_encode_image));
100 AddNativeCallback("ValidateExternal",
101 CREATE_NATIVE_ENTRY(nativeValidateExternal));
102
103 std::unique_ptr<Shell> shell = CreateShell(settings, task_runners);
104
105 ASSERT_TRUE(shell->IsSetup());
106 auto configuration = RunConfiguration::InferFromSettings(settings);
107 configuration.SetEntrypoint("encodeImageProducesExternalUint8List");
108
109 shell->RunEngine(std::move(configuration), [&](auto result) {
110 ASSERT_EQ(result, Engine::RunStatus::Success);
111 });
112
113 message_latch.Wait();
114 DestroyShell(std::move(shell), task_runners);
115}
116
117TEST_F(ShellTest, EncodeImageAccessesSyncSwitch) {
118 Settings settings = CreateSettingsForFixture();
119 TaskRunners task_runners("test", // label
120 GetCurrentTaskRunner(), // platform
121 CreateNewThread(), // raster
122 CreateNewThread(), // ui
123 CreateNewThread() // io
124 );
125
126 auto native_encode_image = [&](Dart_NativeArguments args) {
127 auto image_handle = Dart_GetNativeArgument(args, 0);
128 image_handle =
129 Dart_GetField(image_handle, Dart_NewStringFromCString("_image"));
130 ASSERT_FALSE(Dart_IsError(image_handle)) << Dart_GetError(image_handle);
131 ASSERT_FALSE(Dart_IsNull(image_handle));
132 auto format_handle = Dart_GetNativeArgument(args, 1);
133
134 intptr_t peer = 0;
135 Dart_Handle result = Dart_GetNativeInstanceField(
136 image_handle, tonic::DartWrappable::kPeerIndex, &peer);
137 ASSERT_FALSE(Dart_IsError(result));
138 CanvasImage* canvas_image = reinterpret_cast<CanvasImage*>(peer);
139
140 int64_t format = -1;
141 result = Dart_IntegerToInt64(format_handle, &format);
142 ASSERT_FALSE(Dart_IsError(result));
143
144 auto io_manager = UIDartState::Current()->GetIOManager();
146
147 task_runners.GetIOTaskRunner()->PostTask([&]() {
148 auto is_gpu_disabled_sync_switch =
149 std::make_shared<const MockSyncSwitch>();
150 EXPECT_CALL(*is_gpu_disabled_sync_switch, Execute)
151 .WillOnce([](const MockSyncSwitch::Handlers& handlers) {
152 handlers.true_handler();
153 });
154 auto skia_image = canvas_image->image()
155 ? canvas_image->image()->asSkiaImage()
156 : nullptr;
158 skia_image ? skia_image->skia_image() : nullptr,
159 io_manager->GetResourceContext(), is_gpu_disabled_sync_switch);
160
161 latch.Signal();
162 });
163
164 latch.Wait();
165
166 message_latch.Signal();
167 };
168
169 AddNativeCallback("EncodeImage", CREATE_NATIVE_ENTRY(native_encode_image));
170
171 std::unique_ptr<Shell> shell = CreateShell(settings, task_runners);
172
173 ASSERT_TRUE(shell->IsSetup());
174 auto configuration = RunConfiguration::InferFromSettings(settings);
175 configuration.SetEntrypoint("encodeImageProducesExternalUint8List");
176
177 shell->RunEngine(std::move(configuration), [&](auto result) {
178 ASSERT_EQ(result, Engine::RunStatus::Success);
179 });
180
181 message_latch.Wait();
182 DestroyShell(std::move(shell), task_runners);
183}
184
185#if IMPELLER_SUPPORTS_RENDERING
186using ::impeller::testing::MockAllocator;
187using ::impeller::testing::MockBlitPass;
188using ::impeller::testing::MockCommandBuffer;
189using ::impeller::testing::MockCommandQueue;
190using ::impeller::testing::MockDeviceBuffer;
191using ::impeller::testing::MockImpellerContext;
192using ::impeller::testing::MockTexture;
193using ::testing::_;
194using ::testing::DoAll;
195using ::testing::Invoke;
196using ::testing::InvokeArgument;
197using ::testing::Return;
198
199namespace {
200std::shared_ptr<impeller::Context> MakeConvertDlImageToSkImageContext(
201 std::vector<uint8_t>& buffer) {
202 auto context = std::make_shared<MockImpellerContext>();
203 auto command_buffer = std::make_shared<MockCommandBuffer>(context);
204 auto allocator = std::make_shared<MockAllocator>();
205 auto blit_pass = std::make_shared<MockBlitPass>();
206 auto command_queue = std::make_shared<MockCommandQueue>();
207 impeller::DeviceBufferDescriptor device_buffer_desc;
208 device_buffer_desc.size = buffer.size();
209 auto device_buffer = std::make_shared<MockDeviceBuffer>(device_buffer_desc);
210 EXPECT_CALL(*allocator, OnCreateBuffer).WillOnce(Return(device_buffer));
211 EXPECT_CALL(*blit_pass, IsValid).WillRepeatedly(Return(true));
212 EXPECT_CALL(*command_buffer, IsValid).WillRepeatedly(Return(true));
213 EXPECT_CALL(*command_buffer, OnCreateBlitPass).WillOnce(Return(blit_pass));
214 EXPECT_CALL(*context, GetResourceAllocator).WillRepeatedly(Return(allocator));
215 EXPECT_CALL(*context, CreateCommandBuffer).WillOnce(Return(command_buffer));
216 EXPECT_CALL(*device_buffer, OnGetContents).WillOnce(Return(buffer.data()));
217 EXPECT_CALL(*command_queue, Submit(_, _, _))
218 .WillRepeatedly(
219 DoAll(InvokeArgument<1>(impeller::CommandBuffer::Status::kCompleted),
220 Return(fml::Status())));
221 EXPECT_CALL(*context, GetCommandQueue).WillRepeatedly(Return(command_queue));
222 return context;
223}
224} // namespace
225
226TEST_F(ShellTest, EncodeImageRetries) {
227#ifndef FML_OS_MACOSX
228 GTEST_SKIP() << "Only works on macos currently.";
229#endif
230 Settings settings = CreateSettingsForFixture();
231 settings.enable_impeller = true;
232 TaskRunners task_runners("test", // label
233 GetCurrentTaskRunner(), // platform
234 CreateNewThread(), // raster
235 CreateNewThread(), // ui
236 CreateNewThread() // io
237 );
238
239 std::unique_ptr<Shell> shell = CreateShell({
240 .settings = settings,
241 .task_runners = task_runners,
242 });
243
244 auto turn_off_gpu = [&](Dart_NativeArguments args) {
245 auto handle = Dart_GetNativeArgument(args, 0);
246 bool value = true;
247 ASSERT_TRUE(Dart_IsBoolean(handle));
248 Dart_BooleanValue(handle, &value);
249 TurnOffGPU(shell.get(), value);
250 };
251
252 AddNativeCallback("TurnOffGPU", CREATE_NATIVE_ENTRY(turn_off_gpu));
253
254 auto validate_not_null = [&](Dart_NativeArguments args) {
255 auto handle = Dart_GetNativeArgument(args, 0);
256 EXPECT_FALSE(Dart_IsNull(handle));
257 message_latch.Signal();
258 };
259
260 AddNativeCallback("ValidateNotNull", CREATE_NATIVE_ENTRY(validate_not_null));
261
262 ASSERT_TRUE(shell->IsSetup());
263
264 auto configuration = RunConfiguration::InferFromSettings(settings);
265 configuration.SetEntrypoint("toByteDataRetries");
266
267 shell->RunEngine(std::move(configuration), [&](auto result) {
268 ASSERT_EQ(result, Engine::RunStatus::Success);
269 });
270
271 message_latch.Wait();
272 DestroyShell(std::move(shell), task_runners);
273}
274
275TEST_F(ShellTest, EncodeImageRetryOverflows) {
276#ifndef FML_OS_MACOSX
277 GTEST_SKIP() << "Only works on macos currently.";
278#endif
279 Settings settings = CreateSettingsForFixture();
280 settings.enable_impeller = true;
281 TaskRunners task_runners("test", // label
282 GetCurrentTaskRunner(), // platform
283 CreateNewThread(), // raster
284 CreateNewThread(), // ui
285 CreateNewThread() // io
286 );
287
288 std::unique_ptr<Shell> shell = CreateShell({
289 .settings = settings,
290 .task_runners = task_runners,
291 });
292
293 auto turn_off_gpu = [&](Dart_NativeArguments args) {
294 auto handle = Dart_GetNativeArgument(args, 0);
295 bool value = true;
296 ASSERT_TRUE(Dart_IsBoolean(handle));
297 Dart_BooleanValue(handle, &value);
298 TurnOffGPU(shell.get(), value);
299 };
300
301 AddNativeCallback("TurnOffGPU", CREATE_NATIVE_ENTRY(turn_off_gpu));
302
303 auto validate_not_null = [&](Dart_NativeArguments args) {
304 auto handle = Dart_GetNativeArgument(args, 0);
305 EXPECT_FALSE(Dart_IsNull(handle));
306 message_latch.Signal();
307 };
308
309 AddNativeCallback("ValidateNotNull", CREATE_NATIVE_ENTRY(validate_not_null));
310
311 ASSERT_TRUE(shell->IsSetup());
312
313 auto configuration = RunConfiguration::InferFromSettings(settings);
314 configuration.SetEntrypoint("toByteDataRetryOverflows");
315
316 shell->RunEngine(std::move(configuration), [&](auto result) {
317 ASSERT_EQ(result, Engine::RunStatus::Success);
318 });
319
320 message_latch.Wait();
321 DestroyShell(std::move(shell), task_runners);
322}
323
324TEST_F(ShellTest, ToImageRetries) {
325#ifndef FML_OS_MACOSX
326 GTEST_SKIP() << "Only works on macos currently.";
327#endif
328 Settings settings = CreateSettingsForFixture();
329 settings.enable_impeller = true;
330 TaskRunners task_runners("test", // label
331 GetCurrentTaskRunner(), // platform
332 CreateNewThread(), // raster
333 CreateNewThread(), // ui
334 CreateNewThread() // io
335 );
336
337 std::unique_ptr<Shell> shell = CreateShell({
338 .settings = settings,
339 .task_runners = task_runners,
340 });
341
342 auto turn_off_gpu = [&](Dart_NativeArguments args) {
343 auto handle = Dart_GetNativeArgument(args, 0);
344 bool value = true;
345 ASSERT_TRUE(Dart_IsBoolean(handle));
346 Dart_BooleanValue(handle, &value);
347 TurnOffGPU(shell.get(), value);
348 };
349
350 AddNativeCallback("TurnOffGPU", CREATE_NATIVE_ENTRY(turn_off_gpu));
351
352 auto validate_not_null = [&](Dart_NativeArguments args) {
353 auto handle = Dart_GetNativeArgument(args, 0);
354 EXPECT_FALSE(Dart_IsNull(handle));
355 message_latch.Signal();
356 };
357
358 AddNativeCallback("ValidateNotNull", CREATE_NATIVE_ENTRY(validate_not_null));
359
360 ASSERT_TRUE(shell->IsSetup());
361 auto configuration = RunConfiguration::InferFromSettings(settings);
362 configuration.SetEntrypoint("toImageRetries");
363
364 shell->RunEngine(std::move(configuration), [&](auto result) {
365 ASSERT_EQ(result, Engine::RunStatus::Success);
366 });
367
368 message_latch.Wait();
369 DestroyShell(std::move(shell), task_runners);
370}
371TEST_F(ShellTest, ToImageRetryOverflow) {
372#ifndef FML_OS_MACOSX
373 GTEST_SKIP() << "Only works on macos currently.";
374#endif
375 Settings settings = CreateSettingsForFixture();
376 settings.enable_impeller = true;
377 TaskRunners task_runners("test", // label
378 GetCurrentTaskRunner(), // platform
379 CreateNewThread(), // raster
380 CreateNewThread(), // ui
381 CreateNewThread() // io
382 );
383
384 std::unique_ptr<Shell> shell = CreateShell({
385 .settings = settings,
386 .task_runners = task_runners,
387 });
388
389 auto turn_off_gpu = [&](Dart_NativeArguments args) {
390 auto handle = Dart_GetNativeArgument(args, 0);
391 bool value = true;
392 ASSERT_TRUE(Dart_IsBoolean(handle));
393 Dart_BooleanValue(handle, &value);
394 TurnOffGPU(shell.get(), value);
395 };
396
397 AddNativeCallback("TurnOffGPU", CREATE_NATIVE_ENTRY(turn_off_gpu));
398
399 auto validate_not_null = [&](Dart_NativeArguments args) {
400 auto handle = Dart_GetNativeArgument(args, 0);
401 EXPECT_FALSE(Dart_IsNull(handle));
402 message_latch.Signal();
403 };
404
405 AddNativeCallback("ValidateNotNull", CREATE_NATIVE_ENTRY(validate_not_null));
406
407 ASSERT_TRUE(shell->IsSetup());
408 auto configuration = RunConfiguration::InferFromSettings(settings);
409 configuration.SetEntrypoint("toImageRetryOverflows");
410
411 shell->RunEngine(std::move(configuration), [&](auto result) {
412 ASSERT_EQ(result, Engine::RunStatus::Success);
413 });
414
415 message_latch.Wait();
416 DestroyShell(std::move(shell), task_runners);
417}
418
419TEST_F(ShellTest, EncodeImageFailsWithoutGPUImpeller) {
420#ifndef FML_OS_MACOSX
421 // Only works on macos currently.
422 GTEST_SKIP();
423#endif
424 Settings settings = CreateSettingsForFixture();
425 settings.enable_impeller = true;
426 TaskRunners task_runners("test", // label
427 GetCurrentTaskRunner(), // platform
428 CreateNewThread(), // raster
429 CreateNewThread(), // ui
430 CreateNewThread() // io
431 );
432
433 auto native_validate_error = [&](Dart_NativeArguments args) {
434 auto handle = Dart_GetNativeArgument(args, 0);
435
436 EXPECT_FALSE(Dart_IsNull(handle));
437
438 message_latch.Signal();
439 };
440
441 AddNativeCallback("ValidateError",
442 CREATE_NATIVE_ENTRY(native_validate_error));
443
444 std::unique_ptr<Shell> shell = CreateShell({
445 .settings = settings,
446 .task_runners = task_runners,
447 });
448
449 auto turn_off_gpu = [&](Dart_NativeArguments args) {
450 auto handle = Dart_GetNativeArgument(args, 0);
451 bool value = true;
452 ASSERT_TRUE(Dart_IsBoolean(handle));
453 Dart_BooleanValue(handle, &value);
454 TurnOffGPU(shell.get(), true);
455 };
456
457 AddNativeCallback("TurnOffGPU", CREATE_NATIVE_ENTRY(turn_off_gpu));
458
459 auto flush_awaiting_tasks = [&](Dart_NativeArguments args) {
460 fml::WeakPtr io_manager = shell->GetIOManager();
461 task_runners.GetIOTaskRunner()->PostTask([io_manager] {
462 if (io_manager) {
463 std::shared_ptr<impeller::Context> impeller_context =
464 io_manager->GetImpellerContext();
465 // This will cause the stored tasks to overflow and start throwing them
466 // away.
467 for (int i = 0; i < impeller::Context::kMaxTasksAwaitingGPU; i++) {
468 impeller_context->StoreTaskForGPU([] {}, [] {});
469 }
470 }
471 });
472 };
473
474 AddNativeCallback("FlushGpuAwaitingTasks",
475 CREATE_NATIVE_ENTRY(flush_awaiting_tasks));
476
477 ASSERT_TRUE(shell->IsSetup());
478 auto configuration = RunConfiguration::InferFromSettings(settings);
479 configuration.SetEntrypoint("toByteDataWithoutGPU");
480
481 shell->RunEngine(std::move(configuration), [&](auto result) {
482 ASSERT_EQ(result, Engine::RunStatus::Success);
483 });
484
485 message_latch.Wait();
486 DestroyShell(std::move(shell), task_runners);
487}
488
489TEST(ImageEncodingImpellerTest, ConvertDlImageToSkImage16Float) {
490 sk_sp<MockDlImage> image(new MockDlImage());
491 EXPECT_CALL(*image, GetSize) //
492 .WillRepeatedly(Return(DlISize(100, 100)));
493
496 auto texture = std::make_shared<MockTexture>(desc);
497 EXPECT_CALL(*image, GetImpellerTexture(::testing::_))
498 .WillOnce(Return(texture));
499 std::vector<uint8_t> buffer;
500 buffer.reserve(100 * 100 * 8);
501 auto context = MakeConvertDlImageToSkImageContext(buffer);
502 bool did_call = false;
503 MockSnapshotDelegate snapshot_delegate;
504 EXPECT_CALL(snapshot_delegate, MakeRenderContextCurrent)
505 .WillRepeatedly(Return(true));
507 image,
508 [&did_call](const fml::StatusOr<sk_sp<SkImage>>& image) {
509 did_call = true;
510 ASSERT_TRUE(image.ok());
511 ASSERT_TRUE(image.value());
512 EXPECT_EQ(100, image.value()->width());
513 EXPECT_EQ(100, image.value()->height());
514 EXPECT_EQ(kRGBA_F16_SkColorType, image.value()->colorType());
515 EXPECT_EQ(nullptr, image.value()->colorSpace());
516 },
517 snapshot_delegate.GetWeakPtr(), context);
518 EXPECT_TRUE(did_call);
519}
520
521TEST(ImageEncodingImpellerTest, ConvertDlImageToSkImage10XR) {
522 sk_sp<MockDlImage> image(new MockDlImage());
523 EXPECT_CALL(*image, GetSize) //
524 .WillRepeatedly(Return(DlISize(100, 100)));
525
528 auto texture = std::make_shared<MockTexture>(desc);
529 EXPECT_CALL(*image, GetImpellerTexture(::testing::_))
530 .WillOnce(Return(texture));
531 std::vector<uint8_t> buffer;
532 buffer.reserve(100 * 100 * 4);
533 auto context = MakeConvertDlImageToSkImageContext(buffer);
534 bool did_call = false;
535 MockSnapshotDelegate snapshot_delegate;
536 EXPECT_CALL(snapshot_delegate, MakeRenderContextCurrent)
537 .WillRepeatedly(Return(true));
539 image,
540 [&did_call](const fml::StatusOr<sk_sp<SkImage>>& image) {
541 did_call = true;
542 ASSERT_TRUE(image.ok());
543 ASSERT_TRUE(image.value());
544 EXPECT_EQ(100, image.value()->width());
545 EXPECT_EQ(100, image.value()->height());
546 EXPECT_EQ(kBGR_101010x_XR_SkColorType, image.value()->colorType());
547 EXPECT_EQ(nullptr, image.value()->colorSpace());
548 },
549 snapshot_delegate.GetWeakPtr(), context);
550 EXPECT_TRUE(did_call);
551}
552
553TEST(ImageEncodingImpellerTest, PngEncoding10XR) {
554 int width = 100;
555 int height = 100;
556 SkImageInfo info = SkImageInfo::Make(
557 width, height, kBGR_101010x_XR_SkColorType, kUnpremul_SkAlphaType);
558
559 auto surface = SkSurfaces::Raster(info);
560 SkCanvas* canvas = surface->getCanvas();
561
562 SkPaint paint;
563 paint.setColor(SK_ColorBLUE);
564 paint.setAntiAlias(true);
565
566 canvas->clear(SK_ColorWHITE);
567 canvas->drawCircle(width / 2, height / 2, 100, paint);
568
569 sk_sp<SkImage> image = surface->makeImageSnapshot();
570
572 EXPECT_TRUE(png.ok());
573}
574
575namespace {
576struct PngMemoryReader {
577 const uint8_t* data;
578 size_t offset;
579 size_t size;
580};
581
582void PngMemoryRead(png_structp png_ptr,
583 png_bytep out_bytes,
584 png_size_t byte_count_to_read) {
585 PngMemoryReader* memory_reader =
586 reinterpret_cast<PngMemoryReader*>(png_get_io_ptr(png_ptr));
587 if (memory_reader->offset + byte_count_to_read > memory_reader->size) {
588 png_error(png_ptr, "Read error in PngMemoryRead");
589 }
590 memcpy(out_bytes, memory_reader->data + memory_reader->offset,
591 byte_count_to_read);
592 memory_reader->offset += byte_count_to_read;
593}
594
595fml::StatusOr<std::vector<uint32_t>> ReadPngFromMemory(const uint8_t* png_data,
596 size_t png_size) {
597 png_structp png =
598 png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
599 if (!png) {
600 return fml::Status(fml::StatusCode::kAborted, "unknown");
601 }
602
603 png_infop info = png_create_info_struct(png);
604 if (!info) {
605 png_destroy_read_struct(&png, nullptr, nullptr);
606 return fml::Status(fml::StatusCode::kAborted, "unknown");
607 }
608
609 fml::ScopedCleanupClosure png_cleanup(
610 [&png, &info]() { png_destroy_read_struct(&png, &info, nullptr); });
611
612 if (setjmp(png_jmpbuf(png))) {
613 return fml::Status(fml::StatusCode::kAborted, "unknown");
614 }
615
616 PngMemoryReader memory_reader = {
617 .data = png_data, .offset = 0, .size = png_size};
618 png_set_read_fn(png, &memory_reader, PngMemoryRead);
619
620 png_read_info(png, info);
621
622 int width = png_get_image_width(png, info);
623 int height = png_get_image_height(png, info);
624 png_byte color_type = png_get_color_type(png, info);
625 png_byte bit_depth = png_get_bit_depth(png, info);
626
627 if (bit_depth == 16) {
628 png_set_strip_16(png);
629 }
630 if (color_type == PNG_COLOR_TYPE_PALETTE) {
631 png_set_palette_to_rgb(png);
632 }
633
634 png_read_update_info(png, info);
635 std::vector<uint32_t> result(width * height);
636 std::vector<png_bytep> row_pointers;
637 row_pointers.reserve(height);
638
639 for (int i = 0; i < height; ++i) {
640 row_pointers.push_back(
641 reinterpret_cast<png_bytep>(result.data() + i * width));
642 }
643
644 png_read_image(png, row_pointers.data());
645
646 return result;
647}
648} // namespace
649
650TEST(ImageEncodingImpellerTest, PngEncodingBGRA10XR) {
651 int width = 100;
652 int height = 100;
653 SkImageInfo info = SkImageInfo::Make(
654 width, height, kBGRA_10101010_XR_SkColorType, kUnpremul_SkAlphaType);
655
656 auto surface = SkSurfaces::Raster(info);
657 SkCanvas* canvas = surface->getCanvas();
658
659 SkPaint paint;
660 paint.setColor(SK_ColorBLUE);
661 paint.setAntiAlias(true);
662
663 canvas->clear(SK_ColorRED);
664 canvas->drawCircle(width / 2, height / 2, 25, paint);
665
666 sk_sp<SkImage> image = surface->makeImageSnapshot();
667
669 ASSERT_TRUE(png.ok());
671 ReadPngFromMemory(png.value()->bytes(), png.value()->size());
672 ASSERT_TRUE(pixels.ok());
673 EXPECT_EQ(pixels.value()[0], 0xff0000ff);
674 int middle = 100 * 50 + 50;
675 EXPECT_EQ(pixels.value()[middle], 0xffff0000);
676}
677
678#endif // IMPELLER_SUPPORTS_RENDERING
679
680} // namespace testing
681} // namespace flutter
682
683// NOLINTEND(clang-analyzer-core.StackAddressEscape)
sk_sp< DlImage > image() const
Definition image.h:56
static void ConvertDlImageToSkImage(const sk_sp< DlImage > &dl_image, std::function< void(fml::StatusOr< sk_sp< SkImage > >)> encode_task, const fml::TaskRunnerAffineWeakPtr< SnapshotDelegate > &snapshot_delegate, const std::shared_ptr< impeller::Context > &impeller_context)
static RunConfiguration InferFromSettings(const Settings &settings, const fml::RefPtr< fml::TaskRunner > &io_worker=nullptr, IsolateLaunchType launch_type=IsolateLaunchType::kNewGroup)
Attempts to infer a run configuration from the settings object. This tries to create a run configurat...
fml::RefPtr< fml::TaskRunner > GetIOTaskRunner() const
fml::WeakPtr< IOManager > GetIOManager() const
static UIDartState * Current()
Wraps a closure that is invoked in the destructor unless released by the caller.
Definition closure.h:32
const T & value() const
Definition status_or.h:77
bool ok() const
Definition status_or.h:75
virtual void PostTask(const fml::closure &task) override
static constexpr int32_t kMaxTasksAwaitingGPU
Definition context.h:83
int32_t value
FlutterVulkanImage * image
VkSurfaceKHR surface
Definition main.cc:65
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
const gchar FlBinaryMessengerMessageHandler handler
uint32_t uint32_t * format
std::shared_ptr< ImpellerAllocator > allocator
std::function< void()> true_handler
std::function< void()> false_handler
FlTexture * texture
fml::RefPtr< fml::TaskRunner > CreateNewThread(const std::string &name)
fml::RefPtr< fml::TaskRunner > GetCurrentTaskRunner()
TEST_F(DisplayListTest, Defaults)
TEST(NativeAssetsManagerTest, NoAvailableAssets)
impeller::ISize32 DlISize
it will be possible to load the file into Perfetto s trace viewer use test Running tests that layout and measure text will not yield consistent results across various platforms Enabling this option will make font resolution default to the Ahem test font on all disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
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 switch_defs.h:36
sk_sp< SkImage > ConvertToRasterUsingResourceContext(const sk_sp< SkImage > &image, const fml::WeakPtr< GrDirectContext > &resource_context, const std::shared_ptr< const SyncSwitch > &is_gpu_disabled_sync_switch)
Dart_Handle EncodeImage(CanvasImage *canvas_image, int format, Dart_Handle callback_handle)
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 disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set profile Make the profiler discard new samples once the profiler sample buffer is full When this flag is not the profiler sample buffer is used as a ring buffer
Definition switch_defs.h:98
static id< MTLCommandBuffer > CreateCommandBuffer(id< MTLCommandQueue > queue)
uint32_t color_type
int32_t height
int32_t width
A lightweight object that describes the attributes of a texture that can then used an allocator to cr...
#define CREATE_NATIVE_ENTRY(native_entry)