diff --git a/include/llmr/style/style_layer.hpp b/include/llmr/style/style_layer.hpp index 19490c928..fe5d3c3a6 100644 --- a/include/llmr/style/style_layer.hpp +++ b/include/llmr/style/style_layer.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -13,13 +14,15 @@ namespace llmr { class StyleBucket; -class RasterizeProperties; class StyleLayer; typedef std::vector> StyleLayerGroup; class StyleLayer { public: + StyleLayer(const std::string &id, std::map &&styles, + std::unique_ptr &&rasterize); + template const T &getProperties() { if (style.is()) { return style.get(); @@ -28,16 +31,18 @@ public: } } + bool isBackground() const; + public: // The name of this layer. - std::string id; + const std::string id; // Bucket information, telling the renderer how to generate the geometries // for this layer (feature property filters, tessellation instructions, ...). std::shared_ptr bucket; // Contains all style classes that can be applied to this layer. - std::map styles; + const std::map styles; // Stores the evaluated, and cascaded styling information, specific to this // layer's type. @@ -46,7 +51,7 @@ public: // Rasterization properties are used for prerendering the tile to a bitmap, // which is then used as a raster image instead of rendering this layer // directly in every frame. - std::unique_ptr rasterize; + const std::unique_ptr rasterize; // Child layer array (if this layer has child layers). std::shared_ptr layers; diff --git a/include/llmr/style/style_parser.hpp b/include/llmr/style/style_parser.hpp index 52866f771..808d3188d 100644 --- a/include/llmr/style/style_parser.hpp +++ b/include/llmr/style/style_parser.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -14,6 +15,8 @@ namespace llmr { +enum class ClassID : uint32_t; + class StyleLayer; typedef std::vector> StyleLayerGroup; @@ -37,9 +40,9 @@ private: std::shared_ptr createLayer(JSVal value); void parseLayers(); void parseLayer(std::pair> &pair); - void parseStyles(JSVal value, std::shared_ptr &layer); + void parseStyles(JSVal value, std::map &styles); void parseStyle(JSVal, ClassProperties &properties); - void parseRasterize(JSVal value, std::shared_ptr &layer); + std::unique_ptr parseRasterize(JSVal value); void parseReference(JSVal value, std::shared_ptr &layer); void parseBucket(JSVal value, std::shared_ptr &layer); void parseRender(JSVal value, std::shared_ptr &layer); @@ -73,6 +76,9 @@ private: // This maps ids to Layer objects, with all items being at the root level. std::unordered_map>> layers; + // Layer IDs that we have encountered previously while parsing this stylesheet. + std::set existing_layer_ids; + // Store a stack of layers we're parsing right now. This is to prevent reference cycles. std::forward_list stack; }; diff --git a/src/map/tile_parser.cpp b/src/map/tile_parser.cpp index 847c57d08..45fa02672 100644 --- a/src/map/tile_parser.cpp +++ b/src/map/tile_parser.cpp @@ -74,7 +74,7 @@ void TileParser::parseStyleLayers(std::shared_ptr layers) { return; } - if (layer_desc->id == "background") { + if (layer_desc->isBackground()) { // background is a special, fake bucket continue; } else if (layer_desc->layers) { diff --git a/src/style/style_layer.cpp b/src/style/style_layer.cpp new file mode 100644 index 000000000..f60f3f064 --- /dev/null +++ b/src/style/style_layer.cpp @@ -0,0 +1,13 @@ +#include + +namespace llmr { + +StyleLayer::StyleLayer(const std::string &id, std::map &&styles, + std::unique_ptr &&rasterize) + : id(id), styles(std::move(styles)), rasterize(std::move(rasterize)) {} + +bool StyleLayer::isBackground() const { + return id == "background"; +} + +} diff --git a/src/style/style_parser.cpp b/src/style/style_parser.cpp index e3453107c..4ecb9a0bc 100644 --- a/src/style/style_parser.cpp +++ b/src/style/style_parser.cpp @@ -382,7 +382,10 @@ std::unique_ptr StyleParser::createLayers(JSVal value) { if (value.IsArray()) { std::unique_ptr layers = std::make_unique(); for (rapidjson::SizeType i = 0; i < value.Size(); ++i) { - layers->emplace_back(createLayer(value[i])); + std::shared_ptr layer = createLayer(value[i]); + if (layer) { + layers->emplace_back(layer); + } } return layers; } else { @@ -391,43 +394,50 @@ std::unique_ptr StyleParser::createLayers(JSVal value) { } std::shared_ptr StyleParser::createLayer(JSVal value) { - std::shared_ptr layer = std::make_shared(); - if (value.IsObject()) { if (!value.HasMember("id")) { - throw Style::exception("layer must have an id"); + fprintf(stderr, "[WARNING] layer must have an id\n"); + return nullptr; } JSVal id = value["id"]; if (!id.IsString()) { - throw Style::exception("layer id must be a string"); + fprintf(stderr, "[WARNING] layer id must be a string\n"); + return nullptr; } - layer->id = { id.GetString(), id.GetStringLength() }; + const std::string layer_id = { id.GetString(), id.GetStringLength() }; - if (layers.find(layer->id) != layers.end()) { - throw Style::exception((std::string("duplicate layer id ") + layer->id).c_str()); + if (existing_layer_ids.find(layer_id) != existing_layer_ids.end()) { + fprintf(stderr, "[WARNING] duplicate layer id %s\n", layer_id.c_str()); + return nullptr; } - // Store the layer ID so we can reference it later. - layers.emplace(layer->id, std::pair> { value, layer }); - - // Parse Styles, as they can't be inherited anyway. - parseStyles(value, layer); + // Parse styles already, as they can't be inherited anyway. + std::map styles; + parseStyles(value, styles); // Parse Rasterization options, as they can't be inherited anyway. + std::unique_ptr rasterize; if (value.HasMember("rasterize")) { - parseRasterize(replaceConstant(value["rasterize"]), layer); + rasterize = parseRasterize(replaceConstant(value["rasterize"])); } + std::shared_ptr layer = std::make_shared( + layer_id, std::move(styles), std::move(rasterize)); + if (value.HasMember("layers")) { layer->layers = createLayers(value["layers"]); } - } else { - throw Style::exception("layer must be an object"); - } - return layer; + // Store the layer ID so we can reference it later. + layers.emplace(layer_id, std::pair> { value, layer }); + + return layer; + } else { + fprintf(stderr, "[WARNING] layer must be an object\n"); + return nullptr; + } } void StyleParser::parseLayers() { @@ -463,16 +473,16 @@ void StyleParser::parseLayer(std::pair> &pair #pragma mark - Parse Styles -void StyleParser::parseStyles(JSVal value, std::shared_ptr &layer) { +void StyleParser::parseStyles(JSVal value, std::map &styles) { rapidjson::Value::ConstMemberIterator itr = value.MemberBegin(); for (; itr != value.MemberEnd(); ++itr) { const std::string name { itr->name.GetString(), itr->name.GetStringLength() }; if (name == "style") { - parseStyle(replaceConstant(itr->value), layer->styles[ClassID::Default]); + parseStyle(replaceConstant(itr->value), styles[ClassID::Default]); } else if (name.compare(0, 6, "style.") == 0 && name.length() > 6) { const ClassID class_id = ClassDictionary::Lookup(name.substr(6)); - parseStyle(replaceConstant(itr->value), layer->styles[class_id]); + parseStyle(replaceConstant(itr->value), styles[class_id]); } } } @@ -560,8 +570,9 @@ void StyleParser::parseStyle(JSVal value, ClassProperties &klass) { parseStyleProperty("background-color", Key::BackgroundColor, klass, value); } -void StyleParser::parseRasterize(JSVal value, std::shared_ptr &layer) { +std::unique_ptr StyleParser::parseRasterize(JSVal value) { // TODO + return nullptr; } void StyleParser::parseReference(JSVal value, std::shared_ptr &layer) {