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