Skip to content

Commit 31ecf87

Browse files
authored
Read SkSL from json asset (flutter#17861)
Fixes flutter#55219
1 parent d3f1c08 commit 31ecf87

File tree

3 files changed

+66
-26
lines changed

3 files changed

+66
-26
lines changed

shell/common/persistent_cache.cc

Lines changed: 48 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
#include <string>
99
#include <string_view>
1010

11+
#include "rapidjson/document.h"
12+
#include "third_party/skia/include/utils/SkBase64.h"
13+
1114
#include "flutter/fml/base32.h"
1215
#include "flutter/fml/file.h"
1316
#include "flutter/fml/logging.h"
@@ -103,21 +106,35 @@ static std::shared_ptr<fml::UniqueFD> MakeCacheDirectory(
103106
}
104107
} // namespace
105108

109+
sk_sp<SkData> ParseBase32(const std::string& input) {
110+
std::pair<bool, std::string> decode_result = fml::Base32Decode(input);
111+
if (!decode_result.first) {
112+
FML_LOG(ERROR) << "Base32 can't decode: " << input;
113+
return nullptr;
114+
}
115+
const std::string& data_string = decode_result.second;
116+
return SkData::MakeWithCopy(data_string.data(), data_string.length());
117+
}
118+
119+
sk_sp<SkData> ParseBase64(const std::string& input) {
120+
SkBase64 decoder;
121+
auto error = decoder.decode(input.c_str(), input.length());
122+
if (error != SkBase64::Error::kNoError) {
123+
FML_LOG(ERROR) << "Base64 decode error: " << error;
124+
FML_LOG(ERROR) << "Base64 can't decode: " << input;
125+
return nullptr;
126+
}
127+
return SkData::MakeWithCopy(decoder.getData(), decoder.getDataSize());
128+
}
129+
106130
std::vector<PersistentCache::SkSLCache> PersistentCache::LoadSkSLs() {
107131
TRACE_EVENT0("flutter", "PersistentCache::LoadSkSLs");
108132
std::vector<PersistentCache::SkSLCache> result;
109133
fml::FileVisitor visitor = [&result](const fml::UniqueFD& directory,
110134
const std::string& filename) {
111-
std::pair<bool, std::string> decode_result = fml::Base32Decode(filename);
112-
if (!decode_result.first) {
113-
FML_LOG(ERROR) << "Base32 can't decode: " << filename;
114-
return true; // continue to visit other files
115-
}
116-
const std::string& data_string = decode_result.second;
117-
sk_sp<SkData> key =
118-
SkData::MakeWithCopy(data_string.data(), data_string.length());
135+
sk_sp<SkData> key = ParseBase32(filename);
119136
sk_sp<SkData> data = LoadFile(directory, filename);
120-
if (data != nullptr) {
137+
if (key != nullptr && data != nullptr) {
121138
result.push_back({key, data});
122139
} else {
123140
FML_LOG(ERROR) << "Failed to load: " << filename;
@@ -136,11 +153,29 @@ std::vector<PersistentCache::SkSLCache> PersistentCache::LoadSkSLs() {
136153
fml::FilePermission::kRead);
137154
fml::UniqueFD sksl_asset_dir =
138155
fml::OpenDirectoryReadOnly(root_asset_dir, kSkSLSubdirName);
139-
if (sksl_asset_dir.is_valid()) {
140-
FML_LOG(INFO) << "Found sksl asset directory. Loading SkSLs from it...";
141-
fml::VisitFiles(sksl_asset_dir, visitor);
156+
auto sksl_asset_file = fml::OpenFileReadOnly(sksl_asset_dir, kAssetFileName);
157+
if (!sksl_asset_file.is_valid()) {
158+
FML_LOG(INFO) << "No sksl asset file found.";
142159
} else {
143-
FML_LOG(INFO) << "No sksl asset directory found.";
160+
FML_LOG(INFO) << "Found sksl asset. Loading SkSLs from it...";
161+
auto mapping = std::make_unique<fml::FileMapping>(sksl_asset_file);
162+
rapidjson::Document json_doc;
163+
rapidjson::ParseResult parse_result =
164+
json_doc.Parse(reinterpret_cast<const char*>(mapping->GetMapping()),
165+
mapping->GetSize());
166+
if (parse_result != rapidjson::ParseErrorCode::kParseErrorNone) {
167+
FML_LOG(ERROR) << "Failed to parse json file: " << kAssetFileName;
168+
} else {
169+
for (auto& item : json_doc["data"].GetObject()) {
170+
sk_sp<SkData> key = ParseBase32(item.name.GetString());
171+
sk_sp<SkData> sksl = ParseBase64(item.value.GetString());
172+
if (key != nullptr && sksl != nullptr) {
173+
result.push_back({key, sksl});
174+
} else {
175+
FML_LOG(ERROR) << "Failed to load: " << item.name.GetString();
176+
}
177+
}
178+
}
144179
}
145180

146181
return result;

shell/common/persistent_cache.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ class PersistentCache : public GrContextOptions::PersistentCache {
7373
static void MarkStrategySet() { strategy_set_ = true; }
7474

7575
static constexpr char kSkSLSubdirName[] = "sksl";
76+
static constexpr char kAssetFileName[] = "io.flutter.shaders.json";
7677

7778
private:
7879
static std::string cache_base_path_;

shell/common/persistent_cache_unittests.cc

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -150,23 +150,28 @@ TEST_F(ShellTest, CanLoadSkSLsFromAsset) {
150150
auto empty_config = RunConfiguration::InferFromSettings(empty_settings);
151151
std::unique_ptr<Shell> empty_shell = CreateShell(empty_settings);
152152

153+
// The SkSL key is Base32 encoded. "IE" is the encoding of "A" and "II" is the
154+
// encoding of "B".
155+
//
156+
// The SkSL data is Base64 encoded. "eA==" is the encoding of "x" and "eQ=="
157+
// is the encoding of "y".
158+
const std::string kTestJson =
159+
"{\n"
160+
" \"data\": {\n"
161+
" \"IE\": \"eA==\",\n"
162+
" \"II\": \"eQ==\"\n"
163+
" }\n"
164+
"}\n";
165+
153166
// Temp dir for the asset.
154167
fml::ScopedTemporaryDirectory asset_dir;
155168
fml::UniqueFD sksl_asset_dir =
156169
fml::OpenDirectory(asset_dir.fd(), PersistentCache::kSkSLSubdirName, true,
157170
fml::FilePermission::kReadWrite);
158171

159-
// The SkSL filenames are Base32 encoded strings. "IE" is the encoding of "A"
160-
// and "II" is the encoding of "B".
161-
const std::string kFileNames[2] = {"IE", "II"};
162-
const std::string kFileData[2] = {"x", "y"};
163-
164-
// Prepare 2 SkSL files in the asset directory.
165-
for (int i = 0; i < 2; i += 1) {
166-
auto data = std::make_unique<fml::DataMapping>(
167-
std::vector<uint8_t>{kFileData[i].begin(), kFileData[i].end()});
168-
fml::WriteAtomically(sksl_asset_dir, kFileNames[i].c_str(), *data);
169-
}
172+
auto data = std::make_unique<fml::DataMapping>(
173+
std::vector<uint8_t>{kTestJson.begin(), kTestJson.end()});
174+
fml::WriteAtomically(sksl_asset_dir, PersistentCache::kAssetFileName, *data);
170175

171176
// 1st, test that RunConfiguration::InferFromSettings sets the path.
172177
ResetAssetPath();
@@ -213,8 +218,7 @@ TEST_F(ShellTest, CanLoadSkSLsFromAsset) {
213218

214219
// Cleanup.
215220
DestroyShell(std::move(empty_shell));
216-
fml::UnlinkFile(sksl_asset_dir, kFileNames[0].c_str());
217-
fml::UnlinkFile(sksl_asset_dir, kFileNames[1].c_str());
221+
fml::UnlinkFile(sksl_asset_dir, PersistentCache::kAssetFileName);
218222
fml::UnlinkDirectory(asset_dir.fd(), PersistentCache::kSkSLSubdirName);
219223
}
220224

0 commit comments

Comments
 (0)