|
13 | 13 | #include "flutter/flow/layers/picture_layer.h" |
14 | 14 | #include "flutter/flow/layers/transform_layer.h" |
15 | 15 | #include "flutter/fml/command_line.h" |
| 16 | +#include "flutter/fml/dart/dart_converter.h" |
16 | 17 | #include "flutter/fml/make_copyable.h" |
17 | 18 | #include "flutter/fml/message_loop.h" |
18 | 19 | #include "flutter/fml/synchronization/count_down_latch.h" |
@@ -1014,5 +1015,143 @@ TEST_F(ShellTest, Screenshot) { |
1014 | 1015 | DestroyShell(std::move(shell)); |
1015 | 1016 | } |
1016 | 1017 |
|
| 1018 | +enum class MemsetPatternOp { |
| 1019 | + kMemsetPatternOpSetBuffer, |
| 1020 | + kMemsetPatternOpCheckBuffer, |
| 1021 | +}; |
| 1022 | + |
| 1023 | +//------------------------------------------------------------------------------ |
| 1024 | +/// @brief Depending on the operation, either scribbles a known pattern |
| 1025 | +/// into the buffer or checks if that pattern is present in an |
| 1026 | +/// existing buffer. This is a portable variant of the |
| 1027 | +/// memset_pattern class of methods that also happen to do assert |
| 1028 | +/// that the same pattern exists. |
| 1029 | +/// |
| 1030 | +/// @param buffer The buffer |
| 1031 | +/// @param[in] size The size |
| 1032 | +/// @param[in] op The operation |
| 1033 | +/// |
| 1034 | +/// @return If the result of the operation was a success. |
| 1035 | +/// |
| 1036 | +static bool MemsetPatternSetOrCheck(uint8_t* buffer, |
| 1037 | + size_t size, |
| 1038 | + MemsetPatternOp op) { |
| 1039 | + if (buffer == nullptr) { |
| 1040 | + return false; |
| 1041 | + } |
| 1042 | + |
| 1043 | + auto pattern = reinterpret_cast<const uint8_t*>("dErP"); |
| 1044 | + constexpr auto pattern_length = 4; |
| 1045 | + |
| 1046 | + uint8_t* start = buffer; |
| 1047 | + uint8_t* p = buffer; |
| 1048 | + |
| 1049 | + while ((start + size) - p >= pattern_length) { |
| 1050 | + switch (op) { |
| 1051 | + case MemsetPatternOp::kMemsetPatternOpSetBuffer: |
| 1052 | + memmove(p, pattern, pattern_length); |
| 1053 | + break; |
| 1054 | + case MemsetPatternOp::kMemsetPatternOpCheckBuffer: |
| 1055 | + if (memcmp(pattern, p, pattern_length) != 0) { |
| 1056 | + return false; |
| 1057 | + } |
| 1058 | + break; |
| 1059 | + }; |
| 1060 | + p += pattern_length; |
| 1061 | + } |
| 1062 | + |
| 1063 | + if ((start + size) - p != 0) { |
| 1064 | + switch (op) { |
| 1065 | + case MemsetPatternOp::kMemsetPatternOpSetBuffer: |
| 1066 | + memmove(p, pattern, (start + size) - p); |
| 1067 | + break; |
| 1068 | + case MemsetPatternOp::kMemsetPatternOpCheckBuffer: |
| 1069 | + if (memcmp(pattern, p, (start + size) - p) != 0) { |
| 1070 | + return false; |
| 1071 | + } |
| 1072 | + break; |
| 1073 | + } |
| 1074 | + } |
| 1075 | + |
| 1076 | + return true; |
| 1077 | +} |
| 1078 | + |
| 1079 | +TEST_F(ShellTest, CanConvertToAndFromMappings) { |
| 1080 | + const size_t buffer_size = 2 << 20; |
| 1081 | + |
| 1082 | + uint8_t* buffer = static_cast<uint8_t*>(::malloc(buffer_size)); |
| 1083 | + ASSERT_NE(buffer, nullptr); |
| 1084 | + ASSERT_TRUE(MemsetPatternSetOrCheck( |
| 1085 | + buffer, buffer_size, MemsetPatternOp::kMemsetPatternOpSetBuffer)); |
| 1086 | + |
| 1087 | + std::unique_ptr<fml::Mapping> mapping = |
| 1088 | + std::make_unique<fml::NonOwnedMapping>( |
| 1089 | + buffer, buffer_size, [](const uint8_t* buffer, size_t size) { |
| 1090 | + ::free(const_cast<uint8_t*>(buffer)); |
| 1091 | + }); |
| 1092 | + |
| 1093 | + ASSERT_EQ(mapping->GetSize(), buffer_size); |
| 1094 | + |
| 1095 | + fml::AutoResetWaitableEvent latch; |
| 1096 | + AddNativeCallback( |
| 1097 | + "SendFixtureMapping", CREATE_NATIVE_ENTRY([&](auto args) { |
| 1098 | + auto mapping_from_dart = |
| 1099 | + tonic::DartConverter<std::unique_ptr<fml::Mapping>>::FromDart( |
| 1100 | + Dart_GetNativeArgument(args, 0)); |
| 1101 | + ASSERT_NE(mapping_from_dart, nullptr); |
| 1102 | + ASSERT_EQ(mapping_from_dart->GetSize(), buffer_size); |
| 1103 | + ASSERT_TRUE(MemsetPatternSetOrCheck( |
| 1104 | + const_cast<uint8_t*>(mapping_from_dart->GetMapping()), // buffer |
| 1105 | + mapping_from_dart->GetSize(), // size |
| 1106 | + MemsetPatternOp::kMemsetPatternOpCheckBuffer // op |
| 1107 | + )); |
| 1108 | + latch.Signal(); |
| 1109 | + })); |
| 1110 | + |
| 1111 | + AddNativeCallback( |
| 1112 | + "GetFixtureMapping", CREATE_NATIVE_ENTRY([&](auto args) { |
| 1113 | + tonic::DartConverter<tonic::DartConverterMapping>::SetReturnValue( |
| 1114 | + args, mapping); |
| 1115 | + })); |
| 1116 | + |
| 1117 | + auto settings = CreateSettingsForFixture(); |
| 1118 | + auto configuration = RunConfiguration::InferFromSettings(settings); |
| 1119 | + configuration.SetEntrypoint("canConvertMappings"); |
| 1120 | + std::unique_ptr<Shell> shell = CreateShell(settings); |
| 1121 | + ASSERT_NE(shell.get(), nullptr); |
| 1122 | + RunEngine(shell.get(), std::move(configuration)); |
| 1123 | + latch.Wait(); |
| 1124 | + DestroyShell(std::move(shell)); |
| 1125 | +} |
| 1126 | + |
| 1127 | +TEST_F(ShellTest, CanDecompressImageFromAsset) { |
| 1128 | + fml::AutoResetWaitableEvent latch; |
| 1129 | + AddNativeCallback("NotifyWidthHeight", CREATE_NATIVE_ENTRY([&](auto args) { |
| 1130 | + auto width = tonic::DartConverter<int>::FromDart( |
| 1131 | + Dart_GetNativeArgument(args, 0)); |
| 1132 | + auto height = tonic::DartConverter<int>::FromDart( |
| 1133 | + Dart_GetNativeArgument(args, 1)); |
| 1134 | + ASSERT_EQ(width, 100); |
| 1135 | + ASSERT_EQ(height, 100); |
| 1136 | + latch.Signal(); |
| 1137 | + })); |
| 1138 | + |
| 1139 | + AddNativeCallback( |
| 1140 | + "GetFixtureImage", CREATE_NATIVE_ENTRY([](auto args) { |
| 1141 | + auto fixture = OpenFixtureAsMapping("shelltest_screenshot.png"); |
| 1142 | + tonic::DartConverter<tonic::DartConverterMapping>::SetReturnValue( |
| 1143 | + args, fixture); |
| 1144 | + })); |
| 1145 | + |
| 1146 | + auto settings = CreateSettingsForFixture(); |
| 1147 | + auto configuration = RunConfiguration::InferFromSettings(settings); |
| 1148 | + configuration.SetEntrypoint("canDecompressImageFromAsset"); |
| 1149 | + std::unique_ptr<Shell> shell = CreateShell(settings); |
| 1150 | + ASSERT_NE(shell.get(), nullptr); |
| 1151 | + RunEngine(shell.get(), std::move(configuration)); |
| 1152 | + latch.Wait(); |
| 1153 | + DestroyShell(std::move(shell)); |
| 1154 | +} |
| 1155 | + |
1017 | 1156 | } // namespace testing |
1018 | 1157 | } // namespace flutter |
0 commit comments