#include #include #include #include #include using namespace llmr; Style::Style() { appliedClasses.insert("default"); } void Style::reset() { computed.fills.clear(); computed.lines.clear(); computed.icons.clear(); computed.texts.clear(); computed.rasters.clear(); } void Style::cascade(float z) { reset(); // Accomodate for different tile size. // TODO: Make this per-layer once individual layers have a specific tile size. z += std::log(util::tileSize / 256.0f) / M_LN2; // Recalculate style // Basic cascading for (const auto& class_pair : classes) { const std::string& class_name = class_pair.first; const ClassDescription& sheetClass = class_pair.second; // Not enabled if (appliedClasses.find(class_name) == appliedClasses.end()) continue; // Cascade fill classes for (const auto& fill_pair : sheetClass.fill) { const std::string& layer_name = fill_pair.first; const llmr::FillClass& layer = fill_pair.second; // TODO: This should be restricted to fill styles that have actual // values so as to not override with default values. llmr::FillProperties& fill = computed.fills[layer_name]; fill.enabled = layer.enabled.evaluate(z); fill.translate = {{ layer.translate[0].evaluate(z), layer.translate[1].evaluate(z) }}; fill.translateAnchor = layer.translateAnchor; fill.winding = layer.winding; fill.antialias = layer.antialias.evaluate(z); fill.fill_color = layer.fill_color; fill.stroke_color = layer.stroke_color; fill.opacity = layer.opacity.evaluate(z); fill.image = layer.image; } // Cascade line classes for (const auto& line_pair : sheetClass.line) { const std::string& layer_name = line_pair.first; const llmr::LineClass& layer = line_pair.second; // TODO: This should be restricted to line styles that have actual // values so as to not override with default values. llmr::LineProperties& stroke = computed.lines[layer_name]; stroke.enabled = layer.enabled.evaluate(z); stroke.translate = {{ layer.translate[0].evaluate(z), layer.translate[1].evaluate(z) }}; stroke.translateAnchor = layer.translateAnchor; stroke.width = layer.width.evaluate(z); stroke.offset = layer.offset.evaluate(z); stroke.color = layer.color; stroke.dash_array = {{ layer.dash_array[0].evaluate(z), layer.dash_array[1].evaluate(z) }}; stroke.opacity = layer.opacity.evaluate(z); } // Cascade icon classes for (const auto& icon_pair : sheetClass.icon) { const std::string& layer_name = icon_pair.first; const llmr::IconClass& layer = icon_pair.second; // TODO: This should be restricted to icon styles that have actual // values so as to not override with default values. llmr::IconProperties& icon = computed.icons[layer_name]; icon.enabled = layer.enabled.evaluate(z); icon.translate = {{ layer.translate[0].evaluate(z), layer.translate[1].evaluate(z) }}; icon.translateAnchor = layer.translateAnchor; icon.color = layer.color; icon.size = layer.size.evaluate(z); icon.opacity = layer.opacity.evaluate(z); icon.image = layer.image; icon.radius = layer.radius.evaluate(z); icon.blur = layer.blur.evaluate(z); } // Cascade text classes for (const auto& text_pair : sheetClass.text) { const std::string& layer_name = text_pair.first; const llmr::TextClass& layer = text_pair.second; // TODO: This should be restricted to text styles that have actual // values so as to not override with default values. llmr::TextProperties& text = computed.texts[layer_name]; text.enabled = layer.enabled.evaluate(z); text.translate = {{ layer.translate[0].evaluate(z), layer.translate[1].evaluate(z) }}; text.translateAnchor = layer.translateAnchor; text.color = layer.color; text.size = layer.size.evaluate(z); text.halo = layer.halo; text.halo_radius = layer.halo_radius.evaluate(z); text.halo_blur = layer.halo_blur.evaluate(z); text.rotate = layer.rotate.evaluate(z); text.alwaysVisible = layer.alwaysVisible.evaluate(z); text.opacity = layer.opacity.evaluate(z); } // Cascade raster classes for (const auto& raster_pair : sheetClass.raster) { const std::string& layer_name = raster_pair.first; const llmr::RasterClass& layer = raster_pair.second; // TODO: This should be restricted to raster styles that have actual // values so as to not override with default values. llmr::RasterProperties& raster = computed.rasters[layer_name]; raster.enabled = layer.enabled.evaluate(z); raster.opacity = layer.opacity.evaluate(z); } // Cascade background computed.background.color = sheetClass.background.color; computed.background.opacity = sheetClass.background.opacity.evaluate(z); } } size_t Style::layerCount() const { size_t count = 0; for (const LayerDescription &layer : layers) { count += layer.size(); } return count; } void Style::loadJSON(const uint8_t *const data, size_t bytes) { rapidjson::Document doc; if (bytes <= 0) { return; } if (data[bytes - 1] != 0) { throw exception("style JSON string is not 0-terminated"); } doc.Parse<0>((const char *const)data); const rapidjson::Document& document = doc; buckets.clear(); layers.clear(); classes.clear(); StyleParser parser; if (document.IsObject()) { if (document.HasMember("buckets")) { parser.parseBuckets(document["buckets"], buckets); } if (document.HasMember("structure")) { parser.parseLayers(document["structure"], layers); } if (document.HasMember("constants")) { parser.parseConstants(document["constants"]); } if (document.HasMember("classes")) { parser.parseClasses(document["classes"], classes, buckets, layers); } } else { throw Style::exception("stylesheet root must be an object"); } }