1 #include <mbgl/sprite/sprite_loader.hpp>
2 #include <mbgl/sprite/sprite_loader_worker.hpp>
3 #include <mbgl/sprite/sprite_loader_observer.hpp>
4 #include <mbgl/sprite/sprite_parser.hpp>
5 #include <mbgl/util/logging.hpp>
6 #include <mbgl/util/platform.hpp>
7 #include <mbgl/util/std.hpp>
8 #include <mbgl/util/constants.hpp>
9 #include <mbgl/util/exception.hpp>
10 #include <mbgl/storage/file_source.hpp>
11 #include <mbgl/storage/resource.hpp>
12 #include <mbgl/storage/response.hpp>
13 #include <mbgl/actor/actor.hpp>
14 #include <mbgl/actor/scheduler.hpp>
15 
16 #include <cassert>
17 
18 namespace mbgl {
19 
20 static SpriteLoaderObserver nullObserver;
21 
22 struct SpriteLoader::Loader {
Loadermbgl::SpriteLoader::Loader23     Loader(Scheduler& scheduler, SpriteLoader& imageManager)
24         : mailbox(std::make_shared<Mailbox>(*Scheduler::GetCurrent())),
25           worker(scheduler, ActorRef<SpriteLoader>(imageManager, mailbox)) {
26     }
27 
28     std::shared_ptr<const std::string> image;
29     std::shared_ptr<const std::string> json;
30     std::unique_ptr<AsyncRequest> jsonRequest;
31     std::unique_ptr<AsyncRequest> spriteRequest;
32     std::shared_ptr<Mailbox> mailbox;
33     Actor<SpriteLoaderWorker> worker;
34 };
35 
SpriteLoader(float pixelRatio_)36 SpriteLoader::SpriteLoader(float pixelRatio_)
37         : pixelRatio(pixelRatio_)
38         , observer(&nullObserver) {
39 }
40 
41 SpriteLoader::~SpriteLoader() = default;
42 
load(const std::string & url,Scheduler & scheduler,FileSource & fileSource)43 void SpriteLoader::load(const std::string& url, Scheduler& scheduler, FileSource& fileSource) {
44     if (url.empty()) {
45         // Treat a non-existent sprite as a successfully loaded empty sprite.
46         observer->onSpriteLoaded({});
47         return;
48     }
49 
50     loader = std::make_unique<Loader>(scheduler, *this);
51 
52     loader->jsonRequest = fileSource.request(Resource::spriteJSON(url, pixelRatio), [this](Response res) {
53         if (res.error) {
54             observer->onSpriteError(std::make_exception_ptr(std::runtime_error(res.error->message)));
55         } else if (res.notModified) {
56             return;
57         } else if (res.noContent) {
58             loader->json = std::make_shared<const std::string>();
59             emitSpriteLoadedIfComplete();
60         } else {
61             // Only trigger a sprite loaded event we got new data.
62             loader->json = res.data;
63             emitSpriteLoadedIfComplete();
64         }
65     });
66 
67     loader->spriteRequest = fileSource.request(Resource::spriteImage(url, pixelRatio), [this](Response res) {
68         if (res.error) {
69             observer->onSpriteError(std::make_exception_ptr(std::runtime_error(res.error->message)));
70         } else if (res.notModified) {
71             return;
72         } else if (res.noContent) {
73             loader->image = std::make_shared<const std::string>();
74             emitSpriteLoadedIfComplete();
75         } else {
76             loader->image = res.data;
77             emitSpriteLoadedIfComplete();
78         }
79     });
80 }
81 
emitSpriteLoadedIfComplete()82 void SpriteLoader::emitSpriteLoadedIfComplete() {
83     assert(loader);
84 
85     if (!loader->image || !loader->json) {
86         return;
87     }
88 
89     loader->worker.self().invoke(&SpriteLoaderWorker::parse, loader->image, loader->json);
90 }
91 
onParsed(std::vector<std::unique_ptr<style::Image>> && result)92 void SpriteLoader::onParsed(std::vector<std::unique_ptr<style::Image>>&& result) {
93     observer->onSpriteLoaded(std::move(result));
94 }
95 
onError(std::exception_ptr err)96 void SpriteLoader::onError(std::exception_ptr err) {
97     observer->onSpriteError(err);
98 }
99 
setObserver(SpriteLoaderObserver * observer_)100 void SpriteLoader::setObserver(SpriteLoaderObserver* observer_) {
101     observer = observer_;
102 }
103 
104 } // namespace mbgl
105