1 #include <mbgl/style/parser.hpp>
2 #include <mbgl/style/layer_impl.hpp>
3 #include <mbgl/style/layers/symbol_layer.hpp>
4 #include <mbgl/style/rapidjson_conversion.hpp>
5 #include <mbgl/style/conversion.hpp>
6 #include <mbgl/style/conversion/coordinate.hpp>
7 #include <mbgl/style/conversion/source.hpp>
8 #include <mbgl/style/conversion/layer.hpp>
9 #include <mbgl/style/conversion/light.hpp>
10 #include <mbgl/style/conversion/transition_options.hpp>
11
12 #include <mbgl/util/logging.hpp>
13 #include <mbgl/util/string.hpp>
14
15 #include <mapbox/geojsonvt.hpp>
16
17 #include <rapidjson/document.h>
18 #include <rapidjson/error/en.h>
19
20 #include <algorithm>
21 #include <set>
22 #include <sstream>
23
24 namespace mbgl {
25 namespace style {
26
27 Parser::~Parser() = default;
28
parse(const std::string & json)29 StyleParseResult Parser::parse(const std::string& json) {
30 rapidjson::GenericDocument<rapidjson::UTF8<>, rapidjson::CrtAllocator> document;
31 document.Parse<0>(json.c_str());
32
33 if (document.HasParseError()) {
34 std::stringstream message;
35 message << document.GetErrorOffset() << " - "
36 << rapidjson::GetParseError_En(document.GetParseError());
37
38 return std::make_exception_ptr(std::runtime_error(message.str()));
39 }
40
41 if (!document.IsObject()) {
42 return std::make_exception_ptr(std::runtime_error("style must be an object"));
43 }
44
45 if (document.HasMember("version")) {
46 const JSValue& versionValue = document["version"];
47 const int version = versionValue.IsNumber() ? versionValue.GetInt() : 0;
48 if (version != 8) {
49 Log::Warning(Event::ParseStyle, "current renderer implementation only supports style spec version 8; using an outdated style will cause rendering errors");
50 }
51 }
52
53 if (document.HasMember("name")) {
54 const JSValue& value = document["name"];
55 if (value.IsString()) {
56 name = { value.GetString(), value.GetStringLength() };
57 }
58 }
59
60 if (document.HasMember("center")) {
61 const JSValue& value = document["center"];
62 conversion::Error error;
63 auto convertedLatLng = conversion::convert<LatLng>(value, error);
64 if (convertedLatLng) {
65 latLng = *convertedLatLng;
66 } else {
67 Log::Warning(Event::ParseStyle, "center coordinate must be a longitude, latitude pair");
68 }
69 }
70
71 if (document.HasMember("zoom")) {
72 const JSValue& value = document["zoom"];
73 if (value.IsNumber()) {
74 zoom = value.GetDouble();
75 }
76 }
77
78 if (document.HasMember("bearing")) {
79 const JSValue& value = document["bearing"];
80 if (value.IsNumber()) {
81 bearing = value.GetDouble();
82 }
83 }
84
85 if (document.HasMember("pitch")) {
86 const JSValue& value = document["pitch"];
87 if (value.IsNumber()) {
88 pitch = value.GetDouble();
89 }
90 }
91
92 if (document.HasMember("transition")) {
93 parseTransition(document["transition"]);
94 }
95
96 if (document.HasMember("light")) {
97 parseLight(document["light"]);
98 }
99
100 if (document.HasMember("sources")) {
101 parseSources(document["sources"]);
102 }
103
104 if (document.HasMember("layers")) {
105 parseLayers(document["layers"]);
106 }
107
108 if (document.HasMember("sprite")) {
109 const JSValue& sprite = document["sprite"];
110 if (sprite.IsString()) {
111 spriteURL = { sprite.GetString(), sprite.GetStringLength() };
112 }
113 }
114
115 if (document.HasMember("glyphs")) {
116 const JSValue& glyphs = document["glyphs"];
117 if (glyphs.IsString()) {
118 glyphURL = { glyphs.GetString(), glyphs.GetStringLength() };
119 }
120 }
121
122 // Call for side effect of logging warnings for invalid values.
123 fontStacks();
124
125 return nullptr;
126 }
127
parseTransition(const JSValue & value)128 void Parser::parseTransition(const JSValue& value) {
129 conversion::Error error;
130 optional<TransitionOptions> converted = conversion::convert<TransitionOptions>(value, error);
131 if (!converted) {
132 Log::Warning(Event::ParseStyle, error.message);
133 return;
134 }
135
136 transition = std::move(*converted);
137 }
138
parseLight(const JSValue & value)139 void Parser::parseLight(const JSValue& value) {
140 conversion::Error error;
141 optional<Light> converted = conversion::convert<Light>(value, error);
142 if (!converted) {
143 Log::Warning(Event::ParseStyle, error.message);
144 return;
145 }
146
147 light = std::move(*converted);
148 }
149
parseSources(const JSValue & value)150 void Parser::parseSources(const JSValue& value) {
151 if (!value.IsObject()) {
152 Log::Warning(Event::ParseStyle, "sources must be an object");
153 return;
154 }
155
156 for (const auto& property : value.GetObject()) {
157 std::string id { property.name.GetString(), property.name.GetStringLength() };
158
159 conversion::Error error;
160 optional<std::unique_ptr<Source>> source =
161 conversion::convert<std::unique_ptr<Source>>(property.value, error, id);
162 if (!source) {
163 Log::Warning(Event::ParseStyle, error.message);
164 continue;
165 }
166
167 sourcesMap.emplace(id, (*source).get());
168 sources.emplace_back(std::move(*source));
169 }
170 }
171
parseLayers(const JSValue & value)172 void Parser::parseLayers(const JSValue& value) {
173 std::vector<std::string> ids;
174
175 if (!value.IsArray()) {
176 Log::Warning(Event::ParseStyle, "layers must be an array");
177 return;
178 }
179
180 for (auto& layerValue : value.GetArray()) {
181 if (!layerValue.IsObject()) {
182 Log::Warning(Event::ParseStyle, "layer must be an object");
183 continue;
184 }
185
186 if (!layerValue.HasMember("id")) {
187 Log::Warning(Event::ParseStyle, "layer must have an id");
188 continue;
189 }
190
191 const JSValue& id = layerValue["id"];
192 if (!id.IsString()) {
193 Log::Warning(Event::ParseStyle, "layer id must be a string");
194 continue;
195 }
196
197 const std::string layerID = { id.GetString(), id.GetStringLength() };
198 if (layersMap.find(layerID) != layersMap.end()) {
199 Log::Warning(Event::ParseStyle, "duplicate layer id %s", layerID.c_str());
200 continue;
201 }
202
203 layersMap.emplace(layerID, std::pair<const JSValue&, std::unique_ptr<Layer>> { layerValue, nullptr });
204 ids.push_back(layerID);
205 }
206
207 for (const auto& id : ids) {
208 auto it = layersMap.find(id);
209
210 parseLayer(it->first,
211 it->second.first,
212 it->second.second);
213 }
214
215 for (const auto& id : ids) {
216 auto it = layersMap.find(id);
217
218 if (it->second.second) {
219 layers.emplace_back(std::move(it->second.second));
220 }
221 }
222 }
223
parseLayer(const std::string & id,const JSValue & value,std::unique_ptr<Layer> & layer)224 void Parser::parseLayer(const std::string& id, const JSValue& value, std::unique_ptr<Layer>& layer) {
225 if (layer) {
226 // Skip parsing this again. We already have a valid layer definition.
227 return;
228 }
229
230 // Make sure we have not previously attempted to parse this layer.
231 if (std::find(stack.begin(), stack.end(), id) != stack.end()) {
232 Log::Warning(Event::ParseStyle, "layer reference of '%s' is circular", id.c_str());
233 return;
234 }
235
236 if (value.HasMember("ref")) {
237 // This layer is referencing another layer. Recursively parse that layer.
238 const JSValue& refVal = value["ref"];
239 if (!refVal.IsString()) {
240 Log::Warning(Event::ParseStyle, "layer ref of '%s' must be a string", id.c_str());
241 return;
242 }
243
244 const std::string ref { refVal.GetString(), refVal.GetStringLength() };
245 auto it = layersMap.find(ref);
246 if (it == layersMap.end()) {
247 Log::Warning(Event::ParseStyle, "layer '%s' references unknown layer %s", id.c_str(), ref.c_str());
248 return;
249 }
250
251 // Recursively parse the referenced layer.
252 stack.push_front(id);
253 parseLayer(it->first,
254 it->second.first,
255 it->second.second);
256 stack.pop_front();
257
258 Layer* reference = it->second.second.get();
259 if (!reference) {
260 return;
261 }
262
263 layer = reference->cloneRef(id);
264 conversion::setPaintProperties(*layer, conversion::Convertible(&value));
265 } else {
266 conversion::Error error;
267 optional<std::unique_ptr<Layer>> converted = conversion::convert<std::unique_ptr<Layer>>(value, error);
268 if (!converted) {
269 Log::Warning(Event::ParseStyle, error.message);
270 return;
271 }
272 layer = std::move(*converted);
273 }
274 }
275
fontStacks() const276 std::vector<FontStack> Parser::fontStacks() const {
277 std::set<FontStack> result;
278
279 for (const auto& layer : layers) {
280 if (layer->is<SymbolLayer>() && !layer->as<SymbolLayer>()->getTextField().isUndefined()) {
281 layer->as<SymbolLayer>()->getTextFont().match(
282 [&] (Undefined) {
283 result.insert({"Open Sans Regular", "Arial Unicode MS Regular"});
284 },
285 [&] (const FontStack& constant) {
286 result.insert(constant);
287 },
288 [&] (const auto& function) {
289 for (const auto& value : function.possibleOutputs()) {
290 if (value) {
291 result.insert(*value);
292 } else {
293 Log::Warning(Event::ParseStyle, "Layer '%s' has an invalid value for text-font and will not work offline. Output values must be contained as literals within the expression.", layer->getID().c_str());
294 break;
295 }
296 }
297 }
298 );
299 }
300 }
301
302 return std::vector<FontStack>(result.begin(), result.end());
303 }
304
305 } // namespace style
306 } // namespace mbgl
307