Skip to content

Commit 1f320fd

Browse files
authored
Cancel pending style request when loading style JSON (#3989)
Signed-off-by: Bart Louwers <[email protected]>
1 parent 421eab6 commit 1f320fd

File tree

5 files changed

+69
-3
lines changed

5 files changed

+69
-3
lines changed

src/mbgl/style/style_impl.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,15 @@ Style::Impl::Impl(std::shared_ptr<FileSource> fileSource_, float pixelRatio, con
3939

4040
Style::Impl::~Impl() = default;
4141

42+
void Style::Impl::cancelPendingRequest() noexcept {
43+
styleRequest.reset();
44+
}
45+
4246
void Style::Impl::loadJSON(const std::string& json_) {
4347
lastError = nullptr;
4448
observer->onStyleLoading();
4549

50+
cancelPendingRequest();
4651
url.clear();
4752
parse(json_);
4853
}

src/mbgl/style/style_impl.hpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,14 @@ class Style::Impl : public SpriteLoaderObserver,
4545
void loadJSON(const std::string&);
4646
void loadURL(const std::string&);
4747

48+
/**
49+
* @brief Cancels any pending style request.
50+
*
51+
* This will cancel any in-progress style URL load. Has no effect if no
52+
* style load is in progress.
53+
*/
54+
void cancelPendingRequest() noexcept;
55+
4856
std::string getJSON() const;
4957
std::string getURL() const;
5058

test/src/mbgl/test/stub_file_source.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,7 @@ StubFileSource::~StubFileSource() = default;
6363
std::unique_ptr<AsyncRequest> StubFileSource::request(const Resource& resource, Callback callback) {
6464
auto req = std::make_unique<StubFileRequest>(*this);
6565
if (type == ResponseType::Synchronous) {
66-
std::optional<Response> res = response(resource);
67-
if (res) {
66+
if (const std::optional<Response> res = response(resource)) {
6867
callback(*res);
6968
}
7069
} else {
@@ -79,6 +78,18 @@ void StubFileSource::remove(AsyncRequest* req) {
7978
pending.erase(it);
8079
}
8180
}
81+
void StubFileSource::respondToAll() {
82+
if (type != ResponseType::Manual) {
83+
throw std::runtime_error("this method can only be called with ResponseType::Manual");
84+
}
85+
for (const auto& [key, value] : pending) {
86+
auto& [resource, responseFunction, callback] = value;
87+
if (const std::optional<Response> res = responseFunction(resource)) {
88+
callback(*res);
89+
}
90+
pending.erase(key);
91+
}
92+
}
8293

8394
void StubFileSource::setProperty(const std::string& key, const mapbox::base::Value& value) {
8495
properties[key] = value;

test/src/mbgl/test/stub_file_source.hpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ class StubFileSource : public FileSource {
1616
public:
1717
enum class ResponseType {
1818
Asynchronous = 0,
19-
Synchronous
19+
Synchronous,
20+
Manual
2021
};
2122

2223
StubFileSource(const ResourceOptions&, const ClientOptions&, ResponseType = ResponseType::Asynchronous);
@@ -26,6 +27,8 @@ class StubFileSource : public FileSource {
2627
std::unique_ptr<AsyncRequest> request(const Resource&, Callback) override;
2728
bool canRequest(const Resource&) const override { return true; }
2829
void remove(AsyncRequest*);
30+
void respondToAll();
31+
2932
void setProperty(const std::string&, const mapbox::base::Value&) override;
3033
mapbox::base::Value getProperty(const std::string&) const override;
3134

test/style/style.test.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#include <chrono>
12
#include <mbgl/test/util.hpp>
23
#include <mbgl/test/stub_file_source.hpp>
34
#include <mbgl/test/fixture_log_observer.hpp>
@@ -9,6 +10,7 @@
910
#include <mbgl/style/layers/line_layer.hpp>
1011
#include <mbgl/util/io.hpp>
1112
#include <mbgl/util/run_loop.hpp>
13+
#include <mbgl/util/client_options.hpp>
1214

1315
#include <memory>
1416

@@ -110,6 +112,43 @@ TEST(Style, RemoveSourceInUse) {
110112
EXPECT_EQ(log.count(logMessage), 1u);
111113
}
112114

115+
TEST(Style, LoadJSONCancelsPendingLoadURL) {
116+
util::RunLoop loop;
117+
118+
auto fileSource = std::make_shared<::StubFileSource>(
119+
ResourceOptions::Default(), ClientOptions(), StubFileSource::ResponseType::Manual);
120+
Style::Impl style{fileSource, 1.0, {Scheduler::GetBackground(), {}}};
121+
122+
// Start loading a URL (this will be pending)
123+
auto url = "http://some-url";
124+
fileSource->styleResponse = [](const Resource&) {
125+
Response result;
126+
result.data = std::make_shared<std::string>(util::read_file("test/fixtures/resources/style_vector.json"));
127+
return result;
128+
};
129+
style.loadURL(url);
130+
131+
// Before the URL request completes, load JSON directly
132+
const std::string json = R"STYLE({
133+
"version": 8,
134+
"name": "Test Style",
135+
"sources": {},
136+
"layers": []
137+
})STYLE";
138+
style.loadJSON(json);
139+
140+
// The style should now be loaded with our JSON content
141+
ASSERT_EQ("Test Style", style.getName());
142+
ASSERT_EQ("", style.getURL());
143+
ASSERT_TRUE(style.getJSON().find("Test Style") != std::string::npos);
144+
145+
fileSource->respondToAll();
146+
147+
// The style should still show our JSON content, not the URL content
148+
ASSERT_EQ("Test Style", style.getName());
149+
ASSERT_NE("Streets", style.getName());
150+
}
151+
113152
TEST(Style, SourceImplsOrder) {
114153
util::RunLoop loop;
115154
auto fileSource = std::make_shared<StubFileSource>();

0 commit comments

Comments
 (0)