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
18#include "gmock/gmock.h"
19#include "gtest/gtest.h"
20
21#if IMPELLER_SUPPORTS_RENDERING
24#endif // IMPELLER_SUPPORTS_RENDERING
25
26// CREATE_NATIVE_ENTRY is leaky by design
27// NOLINTBEGIN(clang-analyzer-core.StackAddressEscape)
28
29#pragma GCC diagnostic ignored "-Wunreachable-code"
30
31namespace flutter {
32namespace testing {
33
34namespace {
35fml::AutoResetWaitableEvent message_latch;
36
37class MockSyncSwitch {
38 public:
39 struct Handlers {
40 Handlers& SetIfTrue(const std::function<void()>& handler) {
42 return *this;
43 }
44 Handlers& SetIfFalse(const std::function<void()>& handler) {
46 return *this;
47 }
48 std::function<void()> true_handler = [] {};
49 std::function<void()> false_handler = [] {};
50 };
51
52 MOCK_METHOD(void, Execute, (const Handlers& handlers), (const));
53 MOCK_METHOD(void, SetSwitch, (bool value));
54};
55} // namespace
56
57TEST_F(ShellTest, EncodeImageGivesExternalTypedData) {
58 auto native_encode_image = [&](Dart_NativeArguments args) {
59 auto image_handle = Dart_GetNativeArgument(args, 0);
60 image_handle =
61 Dart_GetField(image_handle, Dart_NewStringFromCString("_image"));
62 ASSERT_FALSE(Dart_IsError(image_handle)) << Dart_GetError(image_handle);
63 ASSERT_FALSE(Dart_IsNull(image_handle));
64 auto format_handle = Dart_GetNativeArgument(args, 1);
65 auto callback_handle = Dart_GetNativeArgument(args, 2);
66
67 intptr_t peer = 0;
68 Dart_Handle result = Dart_GetNativeInstanceField(
69 image_handle, tonic::DartWrappable::kPeerIndex, &peer);
70 ASSERT_FALSE(Dart_IsError(result));
71 CanvasImage* canvas_image = reinterpret_cast<CanvasImage*>(peer);
72
73 int64_t format = -1;
74 result = Dart_IntegerToInt64(format_handle, &format);
75 ASSERT_FALSE(Dart_IsError(result));
76
77 result = EncodeImage(canvas_image, format, callback_handle);
78 ASSERT_TRUE(Dart_IsNull(result));
79 };
80
81 auto nativeValidateExternal = [&](Dart_NativeArguments args) {
82 auto handle = Dart_GetNativeArgument(args, 0);
83
84 auto typed_data_type = Dart_GetTypeOfExternalTypedData(handle);
85 EXPECT_EQ(typed_data_type, Dart_TypedData_kUint8);
86
87 message_latch.Signal();
88 };
89
90 Settings settings = CreateSettingsForFixture();
91 TaskRunners task_runners("test", // label
92 GetCurrentTaskRunner(), // platform
93 CreateNewThread(), // raster
94 CreateNewThread(), // ui
95 CreateNewThread() // io
96 );
97
98 AddNativeCallback("EncodeImage", CREATE_NATIVE_ENTRY(native_encode_image));
99 AddNativeCallback("ValidateExternal",
100 CREATE_NATIVE_ENTRY(nativeValidateExternal));
101
102 std::unique_ptr<Shell> shell = CreateShell(settings, task_runners);
103
104 ASSERT_TRUE(shell->IsSetup());
105 auto configuration = RunConfiguration::InferFromSettings(settings);
106 configuration.SetEntrypoint("encodeImageProducesExternalUint8List");
107
108 shell->RunEngine(std::move(configuration), [&](auto result) {
109 ASSERT_EQ(result, Engine::RunStatus::Success);
110 });
111
112 message_latch.Wait();
113 DestroyShell(std::move(shell), task_runners);
114}
115
116TEST_F(ShellTest, EncodeImageAccessesSyncSwitch) {
117 Settings settings = CreateSettingsForFixture();
118 TaskRunners task_runners("test", // label
119 GetCurrentTaskRunner(), // platform
120 CreateNewThread(), // raster
121 CreateNewThread(), // ui
122 CreateNewThread() // io
123 );
124
125 auto native_encode_image = [&](Dart_NativeArguments args) {
126 auto image_handle = Dart_GetNativeArgument(args, 0);
127 image_handle =
128 Dart_GetField(image_handle, Dart_NewStringFromCString("_image"));
129 ASSERT_FALSE(Dart_IsError(image_handle)) << Dart_GetError(image_handle);
130 ASSERT_FALSE(Dart_IsNull(image_handle));
131 auto format_handle = Dart_GetNativeArgument(args, 1);
132
133 intptr_t peer = 0;
134 Dart_Handle result = Dart_GetNativeInstanceField(
135 image_handle, tonic::DartWrappable::kPeerIndex, &peer);
136 ASSERT_FALSE(Dart_IsError(result));
137 CanvasImage* canvas_image = reinterpret_cast<CanvasImage*>(peer);
138
139 int64_t format = -1;
140 result = Dart_IntegerToInt64(format_handle, &format);
141 ASSERT_FALSE(Dart_IsError(result));
142
143 auto io_manager = UIDartState::Current()->GetIOManager();
145
146 task_runners.GetIOTaskRunner()->PostTask([&]() {
147 auto is_gpu_disabled_sync_switch =
148 std::make_shared<const MockSyncSwitch>();
149 EXPECT_CALL(*is_gpu_disabled_sync_switch, Execute)
150 .WillOnce([](const MockSyncSwitch::Handlers& handlers) {
151 handlers.true_handler();
152 });
153 ConvertToRasterUsingResourceContext(canvas_image->image()->skia_image(),
154 io_manager->GetResourceContext(),
155 is_gpu_disabled_sync_switch);
156 latch.Signal();
157 });
158
159 latch.Wait();
160
161 message_latch.Signal();
162 };
163
164 AddNativeCallback("EncodeImage", CREATE_NATIVE_ENTRY(native_encode_image));
165
166 std::unique_ptr<Shell> shell = CreateShell(settings, task_runners);
167
168 ASSERT_TRUE(shell->IsSetup());
169 auto configuration = RunConfiguration::InferFromSettings(settings);
170 configuration.SetEntrypoint("encodeImageProducesExternalUint8List");
171
172 shell->RunEngine(std::move(configuration), [&](auto result) {
173 ASSERT_EQ(result, Engine::RunStatus::Success);
174 });
175
176 message_latch.Wait();
177 DestroyShell(std::move(shell), task_runners);
178}
179
180#if IMPELLER_SUPPORTS_RENDERING
181using ::impeller::testing::MockAllocator;
182using ::impeller::testing::MockBlitPass;
183using ::impeller::testing::MockCommandBuffer;
184using ::impeller::testing::MockCommandQueue;
185using ::impeller::testing::MockDeviceBuffer;
186using ::impeller::testing::MockImpellerContext;
187using ::impeller::testing::MockTexture;
188using ::testing::_;
189using ::testing::DoAll;
190using ::testing::Invoke;
191using ::testing::InvokeArgument;
192using ::testing::Return;
193
194namespace {
195std::shared_ptr<impeller::Context> MakeConvertDlImageToSkImageContext(
196 std::vector<uint8_t>& buffer) {
197 auto context = std::make_shared<MockImpellerContext>();
198 auto command_buffer = std::make_shared<MockCommandBuffer>(context);
199 auto allocator = std::make_shared<MockAllocator>();
200 auto blit_pass = std::make_shared<MockBlitPass>();
201 auto command_queue = std::make_shared<MockCommandQueue>();
202 impeller::DeviceBufferDescriptor device_buffer_desc;
203 device_buffer_desc.size = buffer.size();
204 auto device_buffer = std::make_shared<MockDeviceBuffer>(device_buffer_desc);
205 EXPECT_CALL(*allocator, OnCreateBuffer).WillOnce(Return(device_buffer));
206 EXPECT_CALL(*blit_pass, IsValid).WillRepeatedly(Return(true));
207 EXPECT_CALL(*command_buffer, IsValid).WillRepeatedly(Return(true));
208 EXPECT_CALL(*command_buffer, OnCreateBlitPass).WillOnce(Return(blit_pass));
209 EXPECT_CALL(*context, GetResourceAllocator).WillRepeatedly(Return(allocator));
210 EXPECT_CALL(*context, CreateCommandBuffer).WillOnce(Return(command_buffer));
211 EXPECT_CALL(*device_buffer, OnGetContents).WillOnce(Return(buffer.data()));
212 EXPECT_CALL(*command_queue, Submit(_, _, _))
213 .WillRepeatedly(
214 DoAll(InvokeArgument<1>(impeller::CommandBuffer::Status::kCompleted),
215 Return(fml::Status())));
216 EXPECT_CALL(*context, GetCommandQueue).WillRepeatedly(Return(command_queue));
217 return context;
218}
219} // namespace
220
221TEST_F(ShellTest, EncodeImageRetries) {
222#ifndef FML_OS_MACOSX
223 GTEST_SKIP() << "Only works on macos currently.";
224#endif
225 Settings settings = CreateSettingsForFixture();
226 settings.enable_impeller = true;
227 TaskRunners task_runners("test", // label
228 GetCurrentTaskRunner(), // platform
229 CreateNewThread(), // raster
230 CreateNewThread(), // ui
231 CreateNewThread() // io
232 );
233
234 std::unique_ptr<Shell> shell = CreateShell({
235 .settings = settings,
236 .task_runners = task_runners,
237 });
238
239 auto turn_off_gpu = [&](Dart_NativeArguments args) {
240 auto handle = Dart_GetNativeArgument(args, 0);
241 bool value = true;
242 ASSERT_TRUE(Dart_IsBoolean(handle));
243 Dart_BooleanValue(handle, &value);
244 TurnOffGPU(shell.get(), value);
245 };
246
247 AddNativeCallback("TurnOffGPU", CREATE_NATIVE_ENTRY(turn_off_gpu));
248
249 auto validate_not_null = [&](Dart_NativeArguments args) {
250 auto handle = Dart_GetNativeArgument(args, 0);
251 EXPECT_FALSE(Dart_IsNull(handle));
252 message_latch.Signal();
253 };
254
255 AddNativeCallback("ValidateNotNull", CREATE_NATIVE_ENTRY(validate_not_null));
256
257 ASSERT_TRUE(shell->IsSetup());
258
259 auto configuration = RunConfiguration::InferFromSettings(settings);
260 configuration.SetEntrypoint("toByteDataRetries");
261
262 shell->RunEngine(std::move(configuration), [&](auto result) {
263 ASSERT_EQ(result, Engine::RunStatus::Success);
264 });
265
266 message_latch.Wait();
267 DestroyShell(std::move(shell), task_runners);
268}
269
270TEST_F(ShellTest, EncodeImageRetryOverflows) {
271#ifndef FML_OS_MACOSX
272 GTEST_SKIP() << "Only works on macos currently.";
273#endif
274 Settings settings = CreateSettingsForFixture();
275 settings.enable_impeller = true;
276 TaskRunners task_runners("test", // label
277 GetCurrentTaskRunner(), // platform
278 CreateNewThread(), // raster
279 CreateNewThread(), // ui
280 CreateNewThread() // io
281 );
282
283 std::unique_ptr<Shell> shell = CreateShell({
284 .settings = settings,
285 .task_runners = task_runners,
286 });
287
288 auto turn_off_gpu = [&](Dart_NativeArguments args) {
289 auto handle = Dart_GetNativeArgument(args, 0);
290 bool value = true;
291 ASSERT_TRUE(Dart_IsBoolean(handle));
292 Dart_BooleanValue(handle, &value);
293 TurnOffGPU(shell.get(), value);
294 };
295
296 AddNativeCallback("TurnOffGPU", CREATE_NATIVE_ENTRY(turn_off_gpu));
297
298 auto validate_not_null = [&](Dart_NativeArguments args) {
299 auto handle = Dart_GetNativeArgument(args, 0);
300 EXPECT_FALSE(Dart_IsNull(handle));
301 message_latch.Signal();
302 };
303
304 AddNativeCallback("ValidateNotNull", CREATE_NATIVE_ENTRY(validate_not_null));
305
306 ASSERT_TRUE(shell->IsSetup());
307
308 auto configuration = RunConfiguration::InferFromSettings(settings);
309 configuration.SetEntrypoint("toByteDataRetryOverflows");
310
311 shell->RunEngine(std::move(configuration), [&](auto result) {
312 ASSERT_EQ(result, Engine::RunStatus::Success);
313 });
314
315 message_latch.Wait();
316 DestroyShell(std::move(shell), task_runners);
317}
318
319TEST_F(ShellTest, ToImageRetries) {
320#ifndef FML_OS_MACOSX
321 GTEST_SKIP() << "Only works on macos currently.";
322#endif
323 Settings settings = CreateSettingsForFixture();
324 settings.enable_impeller = true;
325 TaskRunners task_runners("test", // label
326 GetCurrentTaskRunner(), // platform
327 CreateNewThread(), // raster
328 CreateNewThread(), // ui
329 CreateNewThread() // io
330 );
331
332 std::unique_ptr<Shell> shell = CreateShell({
333 .settings = settings,
334 .task_runners = task_runners,
335 });
336
337 auto turn_off_gpu = [&](Dart_NativeArguments args) {
338 auto handle = Dart_GetNativeArgument(args, 0);
339 bool value = true;
340 ASSERT_TRUE(Dart_IsBoolean(handle));
341 Dart_BooleanValue(handle, &value);
342 TurnOffGPU(shell.get(), value);
343 };
344
345 AddNativeCallback("TurnOffGPU", CREATE_NATIVE_ENTRY(turn_off_gpu));
346
347 auto validate_not_null = [&](Dart_NativeArguments args) {
348 auto handle = Dart_GetNativeArgument(args, 0);
349 EXPECT_FALSE(Dart_IsNull(handle));
350 message_latch.Signal();
351 };
352
353 AddNativeCallback("ValidateNotNull", CREATE_NATIVE_ENTRY(validate_not_null));
354
355 ASSERT_TRUE(shell->IsSetup());
356 auto configuration = RunConfiguration::InferFromSettings(settings);
357 configuration.SetEntrypoint("toImageRetries");
358
359 shell->RunEngine(std::move(configuration), [&](auto result) {
360 ASSERT_EQ(result, Engine::RunStatus::Success);
361 });
362
363 message_latch.Wait();
364 DestroyShell(std::move(shell), task_runners);
365}
366TEST_F(ShellTest, ToImageRetryOverflow) {
367#ifndef FML_OS_MACOSX
368 GTEST_SKIP() << "Only works on macos currently.";
369#endif
370 Settings settings = CreateSettingsForFixture();
371 settings.enable_impeller = true;
372 TaskRunners task_runners("test", // label
373 GetCurrentTaskRunner(), // platform
374 CreateNewThread(), // raster
375 CreateNewThread(), // ui
376 CreateNewThread() // io
377 );
378
379 std::unique_ptr<Shell> shell = CreateShell({
380 .settings = settings,
381 .task_runners = task_runners,
382 });
383
384 auto turn_off_gpu = [&](Dart_NativeArguments args) {
385 auto handle = Dart_GetNativeArgument(args, 0);
386 bool value = true;
387 ASSERT_TRUE(Dart_IsBoolean(handle));
388 Dart_BooleanValue(handle, &value);
389 TurnOffGPU(shell.get(), value);
390 };
391
392 AddNativeCallback("TurnOffGPU", CREATE_NATIVE_ENTRY(turn_off_gpu));
393
394 auto validate_not_null = [&](Dart_NativeArguments args) {
395 auto handle = Dart_GetNativeArgument(args, 0);
396 EXPECT_FALSE(Dart_IsNull(handle));
397 message_latch.Signal();
398 };
399
400 AddNativeCallback("ValidateNotNull", CREATE_NATIVE_ENTRY(validate_not_null));
401
402 ASSERT_TRUE(shell->IsSetup());
403 auto configuration = RunConfiguration::InferFromSettings(settings);
404 configuration.SetEntrypoint("toImageRetryOverflows");
405
406 shell->RunEngine(std::move(configuration), [&](auto result) {
407 ASSERT_EQ(result, Engine::RunStatus::Success);
408 });
409
410 message_latch.Wait();
411 DestroyShell(std::move(shell), task_runners);
412}
413
414TEST_F(ShellTest, EncodeImageFailsWithoutGPUImpeller) {
415#ifndef FML_OS_MACOSX
416 // Only works on macos currently.
417 GTEST_SKIP();
418#endif
419 Settings settings = CreateSettingsForFixture();
420 settings.enable_impeller = true;
421 TaskRunners task_runners("test", // label
422 GetCurrentTaskRunner(), // platform
423 CreateNewThread(), // raster
424 CreateNewThread(), // ui
425 CreateNewThread() // io
426 );
427
428 auto native_validate_error = [&](Dart_NativeArguments args) {
429 auto handle = Dart_GetNativeArgument(args, 0);
430
431 EXPECT_FALSE(Dart_IsNull(handle));
432
433 message_latch.Signal();
434 };
435
436 AddNativeCallback("ValidateError",
437 CREATE_NATIVE_ENTRY(native_validate_error));
438
439 std::unique_ptr<Shell> shell = CreateShell({
440 .settings = settings,
441 .task_runners = task_runners,
442 });
443
444 auto turn_off_gpu = [&](Dart_NativeArguments args) {
445 auto handle = Dart_GetNativeArgument(args, 0);
446 bool value = true;
447 ASSERT_TRUE(Dart_IsBoolean(handle));
448 Dart_BooleanValue(handle, &value);
449 TurnOffGPU(shell.get(), true);
450 };
451
452 AddNativeCallback("TurnOffGPU", CREATE_NATIVE_ENTRY(turn_off_gpu));
453
454 auto flush_awaiting_tasks = [&](Dart_NativeArguments args) {
455 fml::WeakPtr io_manager = shell->GetIOManager();
456 task_runners.GetIOTaskRunner()->PostTask([io_manager] {
457 if (io_manager) {
458 std::shared_ptr<impeller::Context> impeller_context =
459 io_manager->GetImpellerContext();
460 // This will cause the stored tasks to overflow and start throwing them
461 // away.
462 for (int i = 0; i < impeller::Context::kMaxTasksAwaitingGPU; i++) {
463 impeller_context->StoreTaskForGPU([] {}, [] {});
464 }
465 }
466 });
467 };
468
469 AddNativeCallback("FlushGpuAwaitingTasks",
470 CREATE_NATIVE_ENTRY(flush_awaiting_tasks));
471
472 ASSERT_TRUE(shell->IsSetup());
473 auto configuration = RunConfiguration::InferFromSettings(settings);
474 configuration.SetEntrypoint("toByteDataWithoutGPU");
475
476 shell->RunEngine(std::move(configuration), [&](auto result) {
477 ASSERT_EQ(result, Engine::RunStatus::Success);
478 });
479
480 message_latch.Wait();
481 DestroyShell(std::move(shell), task_runners);
482}
483
484TEST(ImageEncodingImpellerTest, ConvertDlImageToSkImage16Float) {
485 sk_sp<MockDlImage> image(new MockDlImage());
486 EXPECT_CALL(*image, GetSize) //
487 .WillRepeatedly(Return(DlISize(100, 100)));
490 auto texture = std::make_shared<MockTexture>(desc);
491 EXPECT_CALL(*image, impeller_texture).WillOnce(Return(texture));
492 std::vector<uint8_t> buffer;
493 buffer.reserve(100 * 100 * 8);
494 auto context = MakeConvertDlImageToSkImageContext(buffer);
495 bool did_call = false;
496 MockSnapshotDelegate snapshot_delegate;
497 EXPECT_CALL(snapshot_delegate, MakeRenderContextCurrent)
498 .WillRepeatedly(Return(true));
500 image,
501 [&did_call](const fml::StatusOr<sk_sp<SkImage>>& image) {
502 did_call = true;
503 ASSERT_TRUE(image.ok());
504 ASSERT_TRUE(image.value());
505 EXPECT_EQ(100, image.value()->width());
506 EXPECT_EQ(100, image.value()->height());
507 EXPECT_EQ(kRGBA_F16_SkColorType, image.value()->colorType());
508 EXPECT_EQ(nullptr, image.value()->colorSpace());
509 },
510 snapshot_delegate.GetWeakPtr(), context);
511 EXPECT_TRUE(did_call);
512}
513
514TEST(ImageEncodingImpellerTest, ConvertDlImageToSkImage10XR) {
515 sk_sp<MockDlImage> image(new MockDlImage());
516 EXPECT_CALL(*image, GetSize) //
517 .WillRepeatedly(Return(DlISize(100, 100)));
520 auto texture = std::make_shared<MockTexture>(desc);
521 EXPECT_CALL(*image, impeller_texture).WillOnce(Return(texture));
522 std::vector<uint8_t> buffer;
523 buffer.reserve(100 * 100 * 4);
524 auto context = MakeConvertDlImageToSkImageContext(buffer);
525 bool did_call = false;
526 MockSnapshotDelegate snapshot_delegate;
527 EXPECT_CALL(snapshot_delegate, MakeRenderContextCurrent)
528 .WillRepeatedly(Return(true));
530 image,
531 [&did_call](const fml::StatusOr<sk_sp<SkImage>>& image) {
532 did_call = true;
533 ASSERT_TRUE(image.ok());
534 ASSERT_TRUE(image.value());
535 EXPECT_EQ(100, image.value()->width());
536 EXPECT_EQ(100, image.value()->height());
537 EXPECT_EQ(kBGR_101010x_XR_SkColorType, image.value()->colorType());
538 EXPECT_EQ(nullptr, image.value()->colorSpace());
539 },
540 snapshot_delegate.GetWeakPtr(), context);
541 EXPECT_TRUE(did_call);
542}
543
544TEST(ImageEncodingImpellerTest, PngEncoding10XR) {
545 int width = 100;
546 int height = 100;
547 SkImageInfo info = SkImageInfo::Make(
548 width, height, kBGR_101010x_XR_SkColorType, kUnpremul_SkAlphaType);
549
550 auto surface = SkSurfaces::Raster(info);
551 SkCanvas* canvas = surface->getCanvas();
552
553 SkPaint paint;
554 paint.setColor(SK_ColorBLUE);
555 paint.setAntiAlias(true);
556
557 canvas->clear(SK_ColorWHITE);
558 canvas->drawCircle(width / 2, height / 2, 100, paint);
559
560 sk_sp<SkImage> image = surface->makeImageSnapshot();
561
563 EXPECT_TRUE(png.ok());
564}
565
566namespace {
567struct PngMemoryReader {
568 const uint8_t* data;
569 size_t offset;
570 size_t size;
571};
572
573void PngMemoryRead(png_structp png_ptr,
574 png_bytep out_bytes,
575 png_size_t byte_count_to_read) {
576 PngMemoryReader* memory_reader =
577 reinterpret_cast<PngMemoryReader*>(png_get_io_ptr(png_ptr));
578 if (memory_reader->offset + byte_count_to_read > memory_reader->size) {
579 png_error(png_ptr, "Read error in PngMemoryRead");
580 }
581 memcpy(out_bytes, memory_reader->data + memory_reader->offset,
582 byte_count_to_read);
583 memory_reader->offset += byte_count_to_read;
584}
585
586fml::StatusOr<std::vector<uint32_t>> ReadPngFromMemory(const uint8_t* png_data,
587 size_t png_size) {
588 png_structp png =
589 png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
590 if (!png) {
591 return fml::Status(fml::StatusCode::kAborted, "unknown");
592 }
593
594 png_infop info = png_create_info_struct(png);
595 if (!info) {
596 png_destroy_read_struct(&png, nullptr, nullptr);
597 return fml::Status(fml::StatusCode::kAborted, "unknown");
598 }
599
600 fml::ScopedCleanupClosure png_cleanup(
601 [&png, &info]() { png_destroy_read_struct(&png, &info, nullptr); });
602
603 if (setjmp(png_jmpbuf(png))) {
604 return fml::Status(fml::StatusCode::kAborted, "unknown");
605 }
606
607 PngMemoryReader memory_reader = {
608 .data = png_data, .offset = 0, .size = png_size};
609 png_set_read_fn(png, &memory_reader, PngMemoryRead);
610
611 png_read_info(png, info);
612
613 int width = png_get_image_width(png, info);
614 int height = png_get_image_height(png, info);
615 png_byte color_type = png_get_color_type(png, info);
616 png_byte bit_depth = png_get_bit_depth(png, info);
617
618 if (bit_depth == 16) {
619 png_set_strip_16(png);
620 }
621 if (color_type == PNG_COLOR_TYPE_PALETTE) {
622 png_set_palette_to_rgb(png);
623 }
624
625 png_read_update_info(png, info);
626 std::vector<uint32_t> result(width * height);
627 std::vector<png_bytep> row_pointers;
628 row_pointers.reserve(height);
629
630 for (int i = 0; i < height; ++i) {
631 row_pointers.push_back(
632 reinterpret_cast<png_bytep>(result.data() + i * width));
633 }
634
635 png_read_image(png, row_pointers.data());
636
637 return result;
638}
639} // namespace
640
641TEST(ImageEncodingImpellerTest, PngEncodingBGRA10XR) {
642 int width = 100;
643 int height = 100;
644 SkImageInfo info = SkImageInfo::Make(
645 width, height, kBGRA_10101010_XR_SkColorType, kUnpremul_SkAlphaType);
646
647 auto surface = SkSurfaces::Raster(info);
648 SkCanvas* canvas = surface->getCanvas();
649
650 SkPaint paint;
651 paint.setColor(SK_ColorBLUE);
652 paint.setAntiAlias(true);
653
654 canvas->clear(SK_ColorRED);
655 canvas->drawCircle(width / 2, height / 2, 25, paint);
656
657 sk_sp<SkImage> image = surface->makeImageSnapshot();
658
660 ASSERT_TRUE(png.ok());
662 ReadPngFromMemory(png.value()->bytes(), png.value()->size());
663 ASSERT_TRUE(pixels.ok());
664 EXPECT_EQ(pixels.value()[0], 0xff0000ff);
665 int middle = 100 * 50 + 50;
666 EXPECT_EQ(pixels.value()[middle], 0xffff0000);
667}
668
669#endif // IMPELLER_SUPPORTS_RENDERING
670
671} // namespace testing
672} // namespace flutter
673
674// NOLINTEND(clang-analyzer-core.StackAddressEscape)
sk_sp< DlImage > image() const
Definition image.h:42
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:79
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
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)
std::shared_ptr< const fml::Mapping > data