1 #include <mbgl/text/glyph_manager.hpp>
2 #include <mbgl/text/glyph_manager_observer.hpp>
3 #include <mbgl/text/glyph_pbf.hpp>
4 #include <mbgl/storage/file_source.hpp>
5 #include <mbgl/storage/resource.hpp>
6 #include <mbgl/storage/response.hpp>
7 #include <mbgl/util/tiny_sdf.hpp>
8 
9 namespace mbgl {
10 
11 static GlyphManagerObserver nullObserver;
12 
GlyphManager(FileSource & fileSource_,std::unique_ptr<LocalGlyphRasterizer> localGlyphRasterizer_)13 GlyphManager::GlyphManager(FileSource& fileSource_, std::unique_ptr<LocalGlyphRasterizer> localGlyphRasterizer_)
14     : fileSource(fileSource_),
15       observer(&nullObserver),
16       localGlyphRasterizer(std::move(localGlyphRasterizer_)) {
17 }
18 
19 GlyphManager::~GlyphManager() = default;
20 
getGlyphs(GlyphRequestor & requestor,GlyphDependencies glyphDependencies)21 void GlyphManager::getGlyphs(GlyphRequestor& requestor, GlyphDependencies glyphDependencies) {
22     auto dependencies = std::make_shared<GlyphDependencies>(std::move(glyphDependencies));
23 
24     // Figure out which glyph ranges need to be fetched. For each range that does need to
25     // be fetched, record an entry mapping the requestor to a shared pointer containing the
26     // dependencies. When the shared pointer becomes unique, we know that all the dependencies
27     // for that requestor have been fetched, and can notify it of completion.
28     for (const auto& dependency : *dependencies) {
29         const FontStack& fontStack = dependency.first;
30         Entry& entry = entries[fontStack];
31 
32         const GlyphIDs& glyphIDs = dependency.second;
33         GlyphRangeSet ranges;
34         for (const auto& glyphID : glyphIDs) {
35             if (localGlyphRasterizer->canRasterizeGlyph(fontStack, glyphID)) {
36                 if (entry.glyphs.find(glyphID) == entry.glyphs.end()) {
37                     entry.glyphs.emplace(glyphID, makeMutable<Glyph>(generateLocalSDF(fontStack, glyphID)));
38                 }
39             } else {
40                 ranges.insert(getGlyphRange(glyphID));
41             }
42         }
43 
44         for (const auto& range : ranges) {
45             auto it = entry.ranges.find(range);
46             if (it == entry.ranges.end() || !it->second.parsed) {
47                 GlyphRequest& request = entry.ranges[range];
48                 request.requestors[&requestor] = dependencies;
49                 requestRange(request, fontStack, range);
50             }
51         }
52     }
53 
54     // If the shared dependencies pointer is already unique, then all dependent glyph ranges
55     // have already been loaded. Send a notification immediately.
56     if (dependencies.unique()) {
57         notify(requestor, *dependencies);
58     }
59 }
60 
generateLocalSDF(const FontStack & fontStack,GlyphID glyphID)61 Glyph GlyphManager::generateLocalSDF(const FontStack& fontStack, GlyphID glyphID) {
62     Glyph local = localGlyphRasterizer->rasterizeGlyph(fontStack, glyphID);
63     local.bitmap = util::transformRasterToSDF(local.bitmap, 8, .25);
64     return local;
65 }
66 
requestRange(GlyphRequest & request,const FontStack & fontStack,const GlyphRange & range)67 void GlyphManager::requestRange(GlyphRequest& request, const FontStack& fontStack, const GlyphRange& range) {
68     if (request.req) {
69         return;
70     }
71 
72     request.req = fileSource.request(Resource::glyphs(glyphURL, fontStack, range), [this, fontStack, range](Response res) {
73         processResponse(res, fontStack, range);
74     });
75 }
76 
processResponse(const Response & res,const FontStack & fontStack,const GlyphRange & range)77 void GlyphManager::processResponse(const Response& res, const FontStack& fontStack, const GlyphRange& range) {
78     if (res.error) {
79         observer->onGlyphsError(fontStack, range, std::make_exception_ptr(std::runtime_error(res.error->message)));
80         return;
81     }
82 
83     if (res.notModified) {
84         return;
85     }
86 
87     Entry& entry = entries[fontStack];
88     GlyphRequest& request = entry.ranges[range];
89 
90     if (!res.noContent) {
91         std::vector<Glyph> glyphs;
92 
93         try {
94             glyphs = parseGlyphPBF(range, *res.data);
95         } catch (...) {
96             observer->onGlyphsError(fontStack, range, std::current_exception());
97             return;
98         }
99 
100         for (auto& glyph : glyphs) {
101             entry.glyphs.erase(glyph.id);
102             entry.glyphs.emplace(glyph.id, makeMutable<Glyph>(std::move(glyph)));
103         }
104     }
105 
106     request.parsed = true;
107 
108     for (auto& pair : request.requestors) {
109         GlyphRequestor& requestor = *pair.first;
110         const std::shared_ptr<GlyphDependencies>& dependencies = pair.second;
111         if (dependencies.unique()) {
112             notify(requestor, *dependencies);
113         }
114     }
115 
116     request.requestors.clear();
117 
118     observer->onGlyphsLoaded(fontStack, range);
119 }
120 
setObserver(GlyphManagerObserver * observer_)121 void GlyphManager::setObserver(GlyphManagerObserver* observer_) {
122     observer = observer_ ? observer_ : &nullObserver;
123 }
124 
notify(GlyphRequestor & requestor,const GlyphDependencies & glyphDependencies)125 void GlyphManager::notify(GlyphRequestor& requestor, const GlyphDependencies& glyphDependencies) {
126     GlyphMap response;
127 
128     for (const auto& dependency : glyphDependencies) {
129         const FontStack& fontStack = dependency.first;
130         const GlyphIDs& glyphIDs = dependency.second;
131 
132         Glyphs& glyphs = response[fontStack];
133         Entry& entry = entries[fontStack];
134 
135         for (const auto& glyphID : glyphIDs) {
136             auto it = entry.glyphs.find(glyphID);
137             if (it != entry.glyphs.end()) {
138                 glyphs.emplace(*it);
139             } else {
140                 glyphs.emplace(glyphID, std::experimental::nullopt);
141             }
142         }
143     }
144 
145     requestor.onGlyphsAvailable(response);
146 }
147 
removeRequestor(GlyphRequestor & requestor)148 void GlyphManager::removeRequestor(GlyphRequestor& requestor) {
149     for (auto& entry : entries) {
150         for (auto& range : entry.second.ranges) {
151             range.second.requestors.erase(&requestor);
152         }
153     }
154 }
155 
156 } // namespace mbgl
157