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