From 4a41b02cefcba67d6c4cfa061e7bf2e19a7f49f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Mon, 16 Jun 2014 15:47:37 +0200 Subject: [PATCH] move to std::map for classes --- include/llmr/style/class_description.hpp | 32 +- include/llmr/style/properties.hpp | 190 ++++++--- include/llmr/style/style.hpp | 9 +- include/llmr/style/style_parser.hpp | 18 +- src/style/class_description.cpp | 9 + src/style/style.cpp | 507 +++++++++++++---------- src/style/style_parser.cpp | 157 +++---- 7 files changed, 537 insertions(+), 385 deletions(-) create mode 100644 src/style/class_description.cpp diff --git a/include/llmr/style/class_description.hpp b/include/llmr/style/class_description.hpp index 216ddeb70..6bd2a03c1 100644 --- a/include/llmr/style/class_description.hpp +++ b/include/llmr/style/class_description.hpp @@ -2,21 +2,35 @@ #define LLMR_STYLE_CLASS_DESCRIPTION #include -#include -#include +#include #include "properties.hpp" namespace llmr { class ClassDescription { public: - BackgroundClass background; - std::map fill; - std::map line; - std::map icon; - std::map text; - std::map raster; - std::map composite; + inline const ClassProperties &operator[](const std::string &name) const { + auto it = styles.find(name); + if (it != styles.end()) { + return it->second; + } else { + return defaultProperties; + } + } + + void addClass(const std::string &name, ClassProperties &&properties); + + inline std::unordered_map::const_iterator begin() const { + return styles.begin(); + } + + inline std::unordered_map::const_iterator end() const { + return styles.end(); + } + +private: + std::unordered_map styles; + static const ClassProperties defaultProperties; }; diff --git a/include/llmr/style/properties.hpp b/include/llmr/style/properties.hpp index 487f2d6c6..c31942f94 100644 --- a/include/llmr/style/properties.hpp +++ b/include/llmr/style/properties.hpp @@ -6,9 +6,12 @@ #include #include #include +#include #include +#include #include +#include namespace llmr { @@ -16,7 +19,10 @@ namespace llmr { typedef std::array Color; struct PropertyTransition { - inline PropertyTransition(uint16_t duration, uint16_t delay = 0) : duration(duration), delay(delay) {} + inline PropertyTransition(uint16_t duration, uint16_t delay = 0) + : duration(duration), delay(delay) {} + inline PropertyTransition(const PropertyTransition &transition) + : duration(transition.duration), delay(transition.delay) {} uint16_t duration = 0; uint16_t delay = 0; }; @@ -82,21 +88,124 @@ struct FunctionProperty { std::vector values; inline FunctionProperty() : function(&functions::null) {} + + inline FunctionProperty(const FunctionProperty &property) + : function(property.function), values(property.values) {} + inline FunctionProperty(FunctionProperty &&property) + : function(property.function), values(std::move(property.values)) {} + + + inline void operator=(const FunctionProperty &rhs) { + function = rhs.function; + values = rhs.values; + } + inline FunctionProperty(float value) : function(&functions::constant), values(1, value) {} template inline T evaluate(float z) const { return function(z, values); } }; -struct GenericClass { - boost::optional enabled; - boost::optional> translate; - boost::optional translate_transition; - boost::optional translateAnchor; - boost::optional opacity; - boost::optional opacity_transition; - boost::optional prerender; - boost::optional prerenderBuffer; - boost::optional prerenderSize; - boost::optional prerenderBlur; + +enum class RenderType { + Fill, + Line, + Icon, + Text, + Raster, + Composite, + Background +}; + +enum class ClassPropertyKey { + Enabled, + TranslateX, + TranslateY, + TranslateTransition, + TranslateAnchor, + Opacity, + OpacityTransition, + Prerender, + PrerenderBuffer, + PrerenderSize, + PrerenderBlur, + + FillWinding, + FillAntialias, + FillColor, + FillColorTransition, + FillStrokeColor, + FillStrokeColorTransition, + FillImage, + + LineWidth, + LineWidthTransition, + LineOffset, + LineOffsetTransition, + LineColor, + LineColorTransition, + LineDashLand, + LineDashGap, + LineDashTransition, + + IconSize, + IconColor, + IconColorTransition, + IconImage, + IconRadius, + IconRadiusTransition, + IconBlur, + IconBlurTransition, + + TextColor, + TextColorTransition, + TextHaloColor, + TextHaloColorTransition, + TextHaloRadius, + TextHaloRadiusTransition, + TextHaloBlur, + TextHaloBlurTransition, + TextSize, + TextRotate, + TextAlwaysVisible, + + BackgroundColor, + BackgroundColorTransition, +}; + +typedef util::variant< + FunctionProperty, + PropertyTransition, + TranslateAnchor, + Color, + Winding, + std::string, + bool +> ClassPropertyValue; + +class ClassProperties { +public: + inline ClassProperties(RenderType type) : type(type) {} + inline ClassProperties(ClassProperties &&properties) + : type(properties.type), properties(std::move(properties.properties)) {} + + template + inline const T *get(ClassPropertyKey key) const { + const auto it = properties.find(key); + if (it != properties.end() && it->second.is()) { + return ::std::addressof(it->second.get()); + } else { + return nullptr; + } + } + + template + inline void emplace(Args&& ...args) { + properties.emplace(::std::forward(args)...); + } + + const RenderType type; + +private: + std::map properties; }; struct PrerenderProperties { @@ -137,17 +246,6 @@ struct GenericProperties { } }; -struct IconClass : public GenericClass { - boost::optional size; - boost::optional color; - boost::optional color_transition; - boost::optional image; - boost::optional radius; - boost::optional radius_transition; - boost::optional blur; - boost::optional blur_transition; -}; - struct IconProperties : public GenericProperties { inline IconProperties() : GenericProperties() {} float size = 0; @@ -157,17 +255,6 @@ struct IconProperties : public GenericProperties { float blur = 0; }; -struct LineClass : public GenericClass { - boost::optional width; - boost::optional width_transition; - boost::optional offset; - boost::optional offset_transition; - boost::optional color; - boost::optional color_transition; - boost::optional> dash_array; - boost::optional dash_array_transition; -}; - struct LineProperties : public GenericProperties { inline LineProperties() : GenericProperties() {} float width = 0; @@ -176,16 +263,6 @@ struct LineProperties : public GenericProperties { std::array dash_array = {{ 1, -1 }}; }; -struct FillClass : public GenericClass { - boost::optional winding; - boost::optional antialias; - boost::optional fill_color; - boost::optional fill_color_transition; - boost::optional stroke_color; - boost::optional stroke_color_transition; - boost::optional image; -}; - struct FillProperties : public GenericProperties { inline FillProperties() : GenericProperties() {} Winding winding = Winding::NonZero; @@ -196,20 +273,6 @@ struct FillProperties : public GenericProperties { std::string image; }; -struct TextClass : public GenericClass { - boost::optional color; - boost::optional color_transition; - boost::optional halo; - boost::optional halo_transition; - boost::optional halo_radius; - boost::optional halo_radius_transition; - boost::optional halo_blur; - boost::optional halo_blur_transition; - boost::optional size; - boost::optional rotate; - boost::optional always_visible; -}; - struct TextProperties : public GenericProperties { inline TextProperties() : GenericProperties() {} Color color = {{ 0, 0, 0, 1 }}; @@ -221,26 +284,15 @@ struct TextProperties : public GenericProperties { bool always_visible = false; }; -struct BackgroundClass : public GenericClass { - boost::optional color; - boost::optional color_transition; -}; - struct BackgroundProperties : public GenericProperties { inline BackgroundProperties() : GenericProperties() {} Color color = {{ 1, 1, 1, 1 }}; }; -struct RasterClass : public GenericClass { -}; - struct RasterProperties : public GenericProperties { inline RasterProperties() : GenericProperties() {} }; -struct CompositeClass : public GenericClass { -}; - struct CompositeProperties : public GenericProperties { inline CompositeProperties() : GenericProperties() {} }; diff --git a/include/llmr/style/style.hpp b/include/llmr/style/style.hpp index 58202393d..5dc19a11a 100644 --- a/include/llmr/style/style.hpp +++ b/include/llmr/style/style.hpp @@ -69,7 +69,14 @@ private: uint64_t transitionDuration(const std::string &layer_name, TransitionablePropertyKey key) const; uint64_t transitionDelay(const std::string &layer_name, TransitionablePropertyKey key) const; - void cascadeProperties(GenericProperties &properties, const GenericClass& klass, const std::string& layer_name, const std::string& class_name, float z); + void cascadeProperties(GenericProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z); + void cascadeProperties(FillProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z); + void cascadeProperties(LineProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z); + void cascadeProperties(IconProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z); + void cascadeProperties(TextProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z); + void cascadeProperties(RasterProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z); + void cascadeProperties(CompositeProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z); + void cascadeProperties(BackgroundProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z); private: // Last applied settings. diff --git a/include/llmr/style/style_parser.hpp b/include/llmr/style/style_parser.hpp index 10f367475..0ef260890 100644 --- a/include/llmr/style/style_parser.hpp +++ b/include/llmr/style/style_parser.hpp @@ -30,14 +30,14 @@ private: const std::map &buckets, const std::map &layerBuckets); - void parseGenericClass(GenericClass &klass, JSVal value); - FillClass parseFillClass(JSVal value); - LineClass parseLineClass(JSVal value); - IconClass parseIconClass(JSVal value); - TextClass parseTextClass(JSVal value); - BackgroundClass parseBackgroundClass(JSVal value); - RasterClass parseRasterClass(JSVal value); - CompositeClass parseCompositeClass(JSVal value); + void parseGenericClass(ClassProperties &klass, JSVal value); + ClassProperties parseFillClass(JSVal value); + ClassProperties parseLineClass(JSVal value); + ClassProperties parseIconClass(JSVal value); + ClassProperties parseTextClass(JSVal value); + ClassProperties parseBackgroundClass(JSVal value); + ClassProperties parseRasterClass(JSVal value); + ClassProperties parseCompositeClass(JSVal value); PropertyFilterExpression parseFilterOrExpression(JSVal value); @@ -49,7 +49,7 @@ private: Value parseValue(JSVal value); FunctionProperty::fn parseFunctionType(JSVal type); FunctionProperty parseFunction(JSVal value); - boost::optional parseTransition(JSVal value, std::string property_name); + void parseTransition(ClassProperties &klass, ClassPropertyKey key, JSVal value, std::string property_name); private: std::map constants; diff --git a/src/style/class_description.cpp b/src/style/class_description.cpp new file mode 100644 index 000000000..48cf63930 --- /dev/null +++ b/src/style/class_description.cpp @@ -0,0 +1,9 @@ +#include + +namespace llmr { + +void ClassDescription::addClass(const std::string &name, ClassProperties &&properties) { + styles.emplace(name, std::move(properties)); +} + +} diff --git a/src/style/style.cpp b/src/style/style.cpp index a0c8a1e57..0b842772c 100644 --- a/src/style/style.cpp +++ b/src/style/style.cpp @@ -25,36 +25,272 @@ void Style::reset() { properties_to_transition.clear(); } -void Style::cascadeProperties(GenericProperties &properties, const GenericClass& klass, const std::string& layer_name, const std::string& class_name, float z) { - if (klass.enabled) { - properties.enabled = klass.enabled.get().evaluate(z); +void Style::cascadeProperties(GenericProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z) { + using Key = ClassPropertyKey; + + if (const FunctionProperty *enabled = klass.get(Key::Enabled)) { + properties.enabled = enabled->evaluate(z); } - if (klass.translate) { - properties.translate = {{ klass.translate.get()[0].evaluate(z), - klass.translate.get()[1].evaluate(z) }}; + if (const FunctionProperty *translateX = klass.get(Key::TranslateX)) { + properties.translate[0] = translateX->evaluate(z); computed.effective_classes[layer_name][TransitionablePropertyKey::Translate] = class_name; - if (klass.translate_transition && klass.translate_transition.get().duration) { - properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Translate, klass.translate_transition.get()); + } + + if (const FunctionProperty *translateY = klass.get(Key::TranslateY)) { + properties.translate[1] = translateY->evaluate(z); + computed.effective_classes[layer_name][TransitionablePropertyKey::Translate] = class_name; + } + + if (const PropertyTransition *translateTransition = klass.get(Key::TranslateTransition)) { + if (translateTransition->duration) { + properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Translate, *translateTransition); } } - if (klass.translateAnchor) { - properties.translateAnchor = klass.translateAnchor.get(); + if (const TranslateAnchor *translateAnchor = klass.get(Key::TranslateAnchor)) { + properties.translateAnchor = *translateAnchor; } - if (klass.opacity) { - properties.opacity = klass.opacity.get().evaluate(z); + if (const FunctionProperty *opacity = klass.get(Key::Opacity)) { + properties.opacity = opacity->evaluate(z); computed.effective_classes[layer_name][TransitionablePropertyKey::Opacity] = class_name; - if (klass.opacity_transition && klass.opacity_transition.get().duration) { - properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Opacity, klass.opacity_transition.get()); + } + + if (const PropertyTransition *opacityTransition = klass.get(Key::OpacityTransition)) { + if (opacityTransition->duration) { + properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Opacity, *opacityTransition); } } - properties.prerender = klass.prerender; - properties.prerenderBuffer = klass.prerenderBuffer; - properties.prerenderSize = klass.prerenderSize; - properties.prerenderBlur = klass.prerenderBlur; + if (const FunctionProperty *prerender = klass.get(Key::Prerender)) { + properties.prerender = *prerender; + } + + if (const FunctionProperty *prerenderBuffer = klass.get(Key::PrerenderBuffer)) { + properties.prerenderBuffer = *prerenderBuffer; + } + + if (const FunctionProperty *prerenderSize = klass.get(Key::PrerenderSize)) { + properties.prerenderSize = *prerenderSize; + } + + if (const FunctionProperty *prerenderBlur = klass.get(Key::PrerenderBlur)) { + properties.prerenderBlur = *prerenderBlur; + } +} + +void Style::cascadeProperties(FillProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z) { + cascadeProperties(reinterpret_cast(properties), klass, layer_name, class_name, z); + + using Key = ClassPropertyKey; + + if (const Winding *winding = klass.get(Key::FillWinding)) { + properties.winding = *winding; + } + + if (const FunctionProperty *antialias = klass.get(Key::FillAntialias)) { + properties.antialias = antialias->evaluate(z); + } + + if (const Color *fillColor = klass.get(Key::FillColor)) { + properties.fill_color = *fillColor; + computed.effective_classes[layer_name][TransitionablePropertyKey::FillColor] = class_name; + } + + if (const PropertyTransition *fillColorTransition = klass.get(Key::FillColorTransition)) { + if (fillColorTransition->duration) { + properties_to_transition[layer_name].emplace(TransitionablePropertyKey::FillColor, *fillColorTransition); + } + } + + if (const Color *fillStrokeColor = klass.get(Key::FillStrokeColor)) { + properties.stroke_color = *fillStrokeColor; + computed.effective_classes[layer_name][TransitionablePropertyKey::StrokeColor] = class_name; + } + + if (const PropertyTransition *fillStrokeColorTransition = klass.get(Key::FillStrokeColorTransition)) { + if (fillStrokeColorTransition->duration) { + properties_to_transition[layer_name].emplace(TransitionablePropertyKey::StrokeColor, *fillStrokeColorTransition); + } + } + + if (const std::string *image = klass.get(Key::FillImage)) { + properties.image = *image; + } +} + +void Style::cascadeProperties(LineProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z) { + cascadeProperties(reinterpret_cast(properties), klass, layer_name, class_name, z); + + using Key = ClassPropertyKey; + + if (const FunctionProperty *width = klass.get(Key::LineWidth)) { + properties.width = width->evaluate(z); + computed.effective_classes[layer_name][TransitionablePropertyKey::Width] = class_name; + } + + if (const PropertyTransition *width_transition = klass.get(Key::LineWidthTransition)) { + properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Width, *width_transition); + } + + if (const FunctionProperty *offset = klass.get(Key::LineOffset)) { + properties.offset = offset->evaluate(z); + computed.effective_classes[layer_name][TransitionablePropertyKey::Offset] = class_name; + } + + if (const PropertyTransition *offset_transition = klass.get(Key::LineOffsetTransition)) { + properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Offset, *offset_transition); + } + + if (const Color *color = klass.get(Key::LineColor)) { + properties.color = *color; + computed.effective_classes[layer_name][TransitionablePropertyKey::Color] = class_name; + } + + if (const PropertyTransition *color_transition = klass.get(Key::LineColorTransition)) { + properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Color, *color_transition); + } + + if (const FunctionProperty *dash_array = klass.get(Key::LineDashLand)) { + properties.dash_array[0] = dash_array->evaluate(z); + computed.effective_classes[layer_name][TransitionablePropertyKey::DashArray] = class_name; + } + + if (const FunctionProperty *dash_array = klass.get(Key::LineDashGap)) { + properties.dash_array[1] = dash_array->evaluate(z); + computed.effective_classes[layer_name][TransitionablePropertyKey::DashArray] = class_name; + } + + if (const PropertyTransition *dash_array_transition = klass.get(Key::LineDashTransition)) { + properties_to_transition[layer_name].emplace(TransitionablePropertyKey::DashArray, *dash_array_transition); + } +} + +void Style::cascadeProperties(TextProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z) { + cascadeProperties(reinterpret_cast(properties), klass, layer_name, class_name, z); + + using Key = ClassPropertyKey; + + if (const Color *color = klass.get(Key::TextColor)) { + properties.color = *color; + computed.effective_classes[layer_name][TransitionablePropertyKey::Color] = class_name; + } + + if (const PropertyTransition *colorTransition = klass.get(Key::TextColorTransition)) { + properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Color, *colorTransition); + } + + if (const FunctionProperty *size = klass.get(Key::TextSize)) { + properties.size = size->evaluate(z); + } + + if (const Color *haloColor = klass.get(Key::TextHaloColor)) { + properties.halo = *haloColor; + computed.effective_classes[layer_name][TransitionablePropertyKey::Halo] = class_name; + } + + if (const PropertyTransition *haloColorTransition = klass.get(Key::TextHaloColorTransition)) { + properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Halo, *haloColorTransition); + } + + if (const FunctionProperty *haloRadius = klass.get(Key::TextHaloRadius)) { + properties.halo_radius = haloRadius->evaluate(z); + computed.effective_classes[layer_name][TransitionablePropertyKey::HaloRadius] = class_name; + } + + if (const PropertyTransition *haloRadiusTransition = klass.get(Key::TextHaloRadiusTransition)) { + properties_to_transition[layer_name].emplace(TransitionablePropertyKey::HaloRadius, *haloRadiusTransition); + } + + if (const FunctionProperty *haloBlur = klass.get(Key::TextHaloBlur)) { + properties.halo_blur = haloBlur->evaluate(z); + computed.effective_classes[layer_name][TransitionablePropertyKey::HaloBlur] = class_name; + } + + if (const PropertyTransition *haloBlurTransition = klass.get(Key::TextHaloBlurTransition)) { + properties_to_transition[layer_name].emplace(TransitionablePropertyKey::HaloBlur, *haloBlurTransition); + } + + if (const FunctionProperty *rotate = klass.get(Key::TextRotate)) { + properties.rotate = rotate->evaluate(z); + } + + if (const FunctionProperty *alwaysVisible = klass.get(Key::TextAlwaysVisible)) { + properties.always_visible = alwaysVisible->evaluate(z); + } +} + +void Style::cascadeProperties(IconProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z) { + cascadeProperties(reinterpret_cast(properties), klass, layer_name, class_name, z); + + using Key = ClassPropertyKey; + + if (const Color *color = klass.get(Key::IconColor)) { + properties.color = *color; + computed.effective_classes[layer_name][TransitionablePropertyKey::Color] = class_name; + } + + if (const PropertyTransition *colorTransition = klass.get(Key::IconColorTransition)) { + if (colorTransition->duration) { + properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Color, *colorTransition); + } + } + + if (const FunctionProperty *size = klass.get(Key::IconSize)) { + properties.size = size->evaluate(z); + } + + if (const std::string *image = klass.get(Key::IconImage)) { + properties.image = *image; + } + + if (const FunctionProperty *radius = klass.get(Key::IconRadius)) { + properties.radius = radius->evaluate(z); + computed.effective_classes[layer_name][TransitionablePropertyKey::Radius] = class_name; + } + + if (const PropertyTransition *radiusTransition = klass.get(Key::IconRadiusTransition)) { + if (radiusTransition->duration) { + properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Radius, *radiusTransition); + } + } + + if (const FunctionProperty *blur = klass.get(Key::IconBlur)) { + properties.blur = blur->evaluate(z); + computed.effective_classes[layer_name][TransitionablePropertyKey::Blur] = class_name; + } + + if (const PropertyTransition *blurTransition = klass.get(Key::IconBlurTransition)) { + if (blurTransition->duration) { + properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Blur, *blurTransition); + } + } +} + +void Style::cascadeProperties(RasterProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z) { + cascadeProperties(reinterpret_cast(properties), klass, layer_name, class_name, z); +} + +void Style::cascadeProperties(CompositeProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z) { + cascadeProperties(reinterpret_cast(properties), klass, layer_name, class_name, z); +} + +void Style::cascadeProperties(BackgroundProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z) { + cascadeProperties(reinterpret_cast(properties), klass, layer_name, class_name, z); + + using Key = ClassPropertyKey; + + if (const Color *backgroundColor = klass.get(Key::BackgroundColor)) { + properties.color = *backgroundColor; + computed.effective_classes[layer_name][TransitionablePropertyKey::Color] = class_name; + } + + if (const PropertyTransition *colorTransition = klass.get(Key::TextColorTransition)) { + if (colorTransition->duration) { + properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Color, *colorTransition); + } + } } @@ -85,217 +321,38 @@ void Style::cascade(float z) { const std::string& class_name = class_pair.first; const ClassDescription& sheetClass = class_pair.second; + using Key = ClassPropertyKey; + // Skip if 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; + for (const auto &pair : sheetClass) { + const std::string& layer_name = pair.first; + const ClassProperties& properties = pair.second; - llmr::FillProperties& fill = computed.fills[layer_name]; - - cascadeProperties(fill, layer, layer_name, class_name, z); - - if (layer.winding) { - fill.winding = layer.winding.get(); - } - - if (layer.antialias) { - fill.antialias = layer.antialias.get().evaluate(z); - } - - if (layer.fill_color) { - fill.fill_color = layer.fill_color.get(); - computed.effective_classes[layer_name][TransitionablePropertyKey::FillColor] = class_name; - if (layer.fill_color_transition && layer.fill_color_transition.get().duration) { - properties_to_transition[layer_name].emplace(TransitionablePropertyKey::FillColor, layer.fill_color_transition.get()); - } - } - - if (layer.stroke_color) { - fill.stroke_color = layer.stroke_color.get(); - computed.effective_classes[layer_name][TransitionablePropertyKey::StrokeColor] = class_name; - if (layer.stroke_color_transition && layer.stroke_color_transition.get().duration) { - properties_to_transition[layer_name].emplace(TransitionablePropertyKey::StrokeColor, layer.stroke_color_transition.get()); - } - } - - if (layer.image) { - fill.image = layer.image.get(); - } - } - - // 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; - - llmr::LineProperties& stroke = computed.lines[layer_name]; - - cascadeProperties(stroke, layer, layer_name, class_name, z); - - if (layer.width) { - stroke.width = layer.width.get().evaluate(z); - computed.effective_classes[layer_name][TransitionablePropertyKey::Width] = class_name; - if (layer.width_transition && layer.width_transition.get().duration) { - properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Width, layer.width_transition.get()); - } - - } - - if (layer.offset) { - stroke.offset = layer.offset.get().evaluate(z); - computed.effective_classes[layer_name][TransitionablePropertyKey::Offset] = class_name; - if (layer.offset_transition && layer.offset_transition.get().duration) { - properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Offset, layer.offset_transition.get()); - } - } - - if (layer.color) { - stroke.color = layer.color.get(); - computed.effective_classes[layer_name][TransitionablePropertyKey::Color] = class_name; - if (layer.color_transition && layer.color_transition.get().duration) { - properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Color, layer.color_transition.get()); - } - } - - if (layer.dash_array) { - stroke.dash_array = {{ layer.dash_array.get()[0].evaluate(z), - layer.dash_array.get()[1].evaluate(z) }}; - computed.effective_classes[layer_name][TransitionablePropertyKey::DashArray] = class_name; - if (layer.dash_array_transition && layer.dash_array_transition.get().duration) { - properties_to_transition[layer_name].emplace(TransitionablePropertyKey::DashArray, layer.dash_array_transition.get()); - } - } - } - - // 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; - - llmr::IconProperties& icon = computed.icons[layer_name]; - - cascadeProperties(icon, layer, layer_name, class_name, z); - - if (layer.color) { - icon.color = layer.color.get(); - computed.effective_classes[layer_name][TransitionablePropertyKey::Color] = class_name; - if (layer.color_transition && layer.color_transition.get().duration) { - properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Color, layer.color_transition.get()); - } - } - - if (layer.size) { - icon.size = layer.size.get().evaluate(z); - } - - if (layer.image) { - icon.image = layer.image.get(); - } - - if (layer.radius) { - icon.radius = layer.radius.get().evaluate(z); - computed.effective_classes[layer_name][TransitionablePropertyKey::Radius] = class_name; - if (layer.radius_transition && layer.radius_transition.get().duration) { - properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Radius, layer.radius_transition.get()); - } - } - - if (layer.blur) { - icon.blur = layer.blur.get().evaluate(z); - computed.effective_classes[layer_name][TransitionablePropertyKey::Blur] = class_name; - if (layer.blur_transition && layer.blur_transition.get().duration) { - properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Blur, layer.blur_transition.get()); - } - } - } - - // 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; - - llmr::TextProperties& text = computed.texts[layer_name]; - - cascadeProperties(text, layer, layer_name, class_name, z); - - if (layer.color) { - text.color = layer.color.get(); - computed.effective_classes[layer_name][TransitionablePropertyKey::Color] = class_name; - if (layer.color_transition && layer.color_transition.get().duration) { - properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Color, layer.color_transition.get()); - } - } - - if (layer.size) { - text.size = layer.size.get().evaluate(z); - } - - if (layer.halo) { - text.halo = layer.halo.get(); - computed.effective_classes[layer_name][TransitionablePropertyKey::Halo] = class_name; - if (layer.halo_transition && layer.halo_transition.get().duration) { - properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Halo, layer.halo_transition.get()); - } - } - - if (layer.halo_radius) { - text.halo_radius = layer.halo_radius.get().evaluate(z); - computed.effective_classes[layer_name][TransitionablePropertyKey::HaloRadius] = class_name; - if (layer.halo_radius_transition && layer.halo_radius_transition.get().duration) { - properties_to_transition[layer_name].emplace(TransitionablePropertyKey::HaloRadius, layer.halo_radius_transition.get()); - } - } - - if (layer.halo_blur) { - text.halo_blur = layer.halo_blur.get().evaluate(z); - computed.effective_classes[layer_name][TransitionablePropertyKey::HaloBlur] = class_name; - if (layer.halo_blur_transition && layer.halo_blur_transition.get().duration) { - properties_to_transition[layer_name].emplace(TransitionablePropertyKey::HaloBlur, layer.halo_blur_transition.get()); - } - } - - if (layer.rotate) { - text.rotate = layer.rotate.get().evaluate(z); - } - - if (layer.always_visible) { - text.always_visible = layer.always_visible.get().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; - - llmr::RasterProperties& raster = computed.rasters[layer_name]; - - cascadeProperties(raster, layer, layer_name, class_name, z); - } - - // Cascade composite classes. - for (const auto& composite_pair : sheetClass.composite) { - const std::string& layer_name = composite_pair.first; - const llmr::CompositeClass& layer = composite_pair.second; - - llmr::CompositeProperties& composite = computed.composites[layer_name]; - - cascadeProperties(composite, layer, layer_name, class_name, z); - } - - // Cascade background. - { - cascadeProperties(computed.background, sheetClass.background, "background", class_name, z); - - if (sheetClass.background.color) { - computed.background.color = sheetClass.background.color.get(); - computed.effective_classes["background"][TransitionablePropertyKey::Color] = class_name; - if (sheetClass.background.color_transition && sheetClass.background.color_transition.get().duration) { - properties_to_transition["background"].emplace(TransitionablePropertyKey::Color, sheetClass.background.color_transition.get()); - } + // Find out what bucket this class is + switch (properties.type) { + case RenderType::Fill: + cascadeProperties(computed.fills[layer_name], properties, layer_name, class_name, z); + break; + case RenderType::Line: + cascadeProperties(computed.lines[layer_name], properties, layer_name, class_name, z); + break; + case RenderType::Icon: + cascadeProperties(computed.icons[layer_name], properties, layer_name, class_name, z); + break; + case RenderType::Text: + cascadeProperties(computed.texts[layer_name], properties, layer_name, class_name, z); + break; + case RenderType::Raster: + cascadeProperties(computed.rasters[layer_name], properties, layer_name, class_name, z); + break; + case RenderType::Composite: + cascadeProperties(computed.composites[layer_name], properties, layer_name, class_name, z); + break; + case RenderType::Background: + cascadeProperties(computed.background, properties, layer_name, class_name, z); + break; } } } diff --git a/src/style/style_parser.cpp b/src/style/style_parser.cpp index edce8d2b6..941be502b 100644 --- a/src/style/style_parser.cpp +++ b/src/style/style_parser.cpp @@ -1,4 +1,5 @@ #include +#include #include #include @@ -482,10 +483,10 @@ void StyleParser::parseClass(const std::string &name, JSVal value, ClassDescript const std::string &bucket_name = layer_bucket_it->second; if (bucket_name == "background") { // background buckets are fake - class_desc.background = parseBackgroundClass(value); + class_desc.addClass("background", parseBackgroundClass(value)); } else if (bucket_name.length() == 0) { // no bucket name == composite bucket. - class_desc.composite.insert({ name, std::forward(parseCompositeClass(value)) }); + class_desc.addClass(name, parseCompositeClass(value)); } else { auto bucket_it = buckets.find(bucket_name); if (bucket_it == buckets.end()) { @@ -497,15 +498,15 @@ void StyleParser::parseClass(const std::string &name, JSVal value, ClassDescript BucketType type = bucket_it->second.type; if (type == BucketType::Fill) { - class_desc.fill.insert({ name, std::forward(parseFillClass(value)) }); + class_desc.addClass(name, parseFillClass(value)); } else if (type == BucketType::Line) { - class_desc.line.insert({ name, std::forward(parseLineClass(value)) }); + class_desc.addClass(name, parseLineClass(value)); } else if (type == BucketType::Icon) { - class_desc.icon.insert({ name, std::forward(parseIconClass(value)) }); + class_desc.addClass(name, parseIconClass(value)); } else if (type == BucketType::Text) { - class_desc.text.insert({ name, std::forward(parseTextClass(value)) }); + class_desc.addClass(name, parseTextClass(value)); } else if (type == BucketType::Raster) { - class_desc.raster.insert({ name, std::forward(parseRasterClass(value)) }); + class_desc.addClass(name, parseRasterClass(value)); } else { throw Style::exception("unknown class type name"); } @@ -663,7 +664,7 @@ FunctionProperty StyleParser::parseFunction(JSVal value) { return property; } -boost::optional StyleParser::parseTransition(JSVal value, std::string property_name) { +void StyleParser::parseTransition(ClassProperties &klass, ClassPropertyKey key, JSVal value, std::string property_name) { uint16_t duration = 0, delay = 0; std::string transition_property = std::string("transition-").append(property_name); if (value.HasMember(transition_property.c_str())) { @@ -679,200 +680,212 @@ boost::optional StyleParser::parseTransition(JSVal value, st } if (duration || delay) { - return boost::optional(PropertyTransition { duration, delay }); - } else { - return boost::optional(); + klass.emplace(key, PropertyTransition { duration, delay }); } } -void StyleParser::parseGenericClass(GenericClass &klass, JSVal value) { - if (value.HasMember("enabled")) { - klass.enabled = parseFunction(value["enabled"]); +void StyleParser::parseGenericClass(ClassProperties &klass, JSVal value) { + using Key = ClassPropertyKey; + + if (value.HasMember("enabled")) { + klass.emplace(Key::Enabled, parseFunction(value["enabled"])); } if (value.HasMember("translate")) { std::vector values = parseArray(value["translate"], 2); - klass.translate = std::array {{ values[0], values[1] }}; - klass.translate_transition = parseTransition(value, "translate"); + klass.emplace(Key::TranslateX, std::move(values[0])); + klass.emplace(Key::TranslateY, std::move(values[1])); + parseTransition(klass, Key::TranslateTransition, value, "translate"); } if (value.HasMember("translate-anchor")) { - klass.translateAnchor = parseTranslateAnchor(value["translate-anchor"]); + klass.emplace(Key::TranslateAnchor, parseTranslateAnchor(value["translate-anchor"])); } if (value.HasMember("opacity")) { - klass.opacity = parseFunction(value["opacity"]); - klass.opacity_transition = parseTransition(value, "opacity"); + klass.emplace(Key::Opacity, parseFunction(value["opacity"])); + parseTransition(klass, Key::OpacityTransition, value, "opacity"); } if (value.HasMember("prerender")) { - klass.prerender = parseFunction(value["prerender"]); + klass.emplace(Key::Prerender, parseFunction(value["prerender"])); } if (value.HasMember("prerender-buffer")) { - klass.prerenderBuffer = parseFunction(value["prerender-buffer"]); + klass.emplace(Key::PrerenderBuffer, parseFunction(value["prerender-buffer"])); } if (value.HasMember("prerender-size")) { - klass.prerenderSize = parseFunction(value["prerender-size"]); + klass.emplace(Key::PrerenderSize, parseFunction(value["prerender-size"])); } if (value.HasMember("prerender-blur")) { - klass.prerenderBlur = parseFunction(value["prerender-blur"]); + klass.emplace(Key::PrerenderBlur, parseFunction(value["prerender-blur"])); } } -FillClass StyleParser::parseFillClass(JSVal value) { - FillClass klass; +ClassProperties StyleParser::parseFillClass(JSVal value) { + ClassProperties klass(RenderType::Fill); parseGenericClass(klass, value); + using Key = ClassPropertyKey; + if (value.HasMember("winding")) { throw std::runtime_error("winding in stylesheets not yet supported"); } if (value.HasMember("color")) { - klass.fill_color = parseColor(value["color"]); - klass.fill_color_transition = parseTransition(value, "color"); + klass.emplace(Key::FillColor, parseColor(value["color"])); + parseTransition(klass, Key::FillColorTransition, value, "color"); } if (value.HasMember("stroke")) { - klass.stroke_color = parseColor(value["stroke"]); - klass.stroke_color_transition = parseTransition(value, "stroke"); - } else { - klass.stroke_color = klass.fill_color; + klass.emplace(Key::FillStrokeColor, parseColor(value["stroke"])); + parseTransition(klass, Key::FillStrokeColorTransition, value, "stroke"); + } else if (const Color *fillColor = klass.get(Key::FillColor)) { + klass.emplace(Key::FillStrokeColor, *fillColor); } if (value.HasMember("antialias")) { - klass.antialias = parseBoolean(value["antialias"]); + klass.emplace(Key::FillAntialias, parseBoolean(value["antialias"])); } if (value.HasMember("image")) { - klass.image = parseString(value["image"]); + klass.emplace(Key::FillImage, parseString(value["image"])); } return klass; } -LineClass StyleParser::parseLineClass(JSVal value) { - LineClass klass; +ClassProperties StyleParser::parseLineClass(JSVal value) { + ClassProperties klass(RenderType::Line); parseGenericClass(klass, value); + using Key = ClassPropertyKey; + if (value.HasMember("color")) { - klass.color = parseColor(value["color"]); - klass.color_transition = parseTransition(value, "color"); + klass.emplace(Key::LineColor, parseColor(value["color"])); + parseTransition(klass, Key::LineColorTransition, value, "color"); } if (value.HasMember("width")) { - klass.width = parseFunction(value["width"]); - klass.width_transition = parseTransition(value, "width"); + klass.emplace(Key::LineWidth, parseFunction(value["width"])); + parseTransition(klass, Key::LineWidthTransition, value, "width"); } if (value.HasMember("dasharray")) { std::vector values = parseArray(value["dasharray"], 2); - klass.dash_array = std::array {{ values[0], values[1] }}; - klass.dash_array_transition = parseTransition(value, "dasharray"); + klass.emplace(Key::LineDashLand, std::move(values[0])); + klass.emplace(Key::LineDashGap, std::move(values[1])); + parseTransition(klass, Key::LineDashTransition, value, "dasharray"); } return klass; } -IconClass StyleParser::parseIconClass(JSVal value) { - IconClass klass; +ClassProperties StyleParser::parseIconClass(JSVal value) { + ClassProperties klass(RenderType::Icon); parseGenericClass(klass, value); + using Key = ClassPropertyKey; + if (value.HasMember("color")) { - klass.color = parseColor(value["color"]); - klass.color_transition = parseTransition(value, "color"); + klass.emplace(Key::IconColor, parseColor(value["color"])); + parseTransition(klass, Key::IconColorTransition, value, "color"); } if (value.HasMember("image")) { - klass.image = parseString(value["image"]); + klass.emplace(Key::IconImage, parseString(value["image"])); } if (value.HasMember("size")) { - klass.size = parseFunction(value["size"]); + klass.emplace(Key::IconSize, parseFunction(value["size"])); } if (value.HasMember("radius")) { - klass.radius = parseFunction(value["radius"]); - klass.radius_transition = parseTransition(value, "radius"); + klass.emplace(Key::IconRadius, parseFunction(value["radius"])); + parseTransition(klass, Key::IconRadiusTransition, value, "radius"); } if (value.HasMember("blur")) { - klass.blur = parseFunction(value["blur"]); - klass.blur_transition = parseTransition(value, "blur"); + klass.emplace(Key::IconBlur, parseFunction(value["blur"])); + parseTransition(klass, Key::IconBlurTransition, value, "blur"); } return klass; } -TextClass StyleParser::parseTextClass(JSVal value) { - TextClass klass; +ClassProperties StyleParser::parseTextClass(JSVal value) { + ClassProperties klass(RenderType::Text); parseGenericClass(klass, value); + using Key = ClassPropertyKey; + if (value.HasMember("color")) { - klass.color = parseColor(value["color"]); - klass.color_transition = parseTransition(value, "color"); + klass.emplace(Key::TextColor, parseColor(value["color"])); + parseTransition(klass, Key::TextColorTransition, value, "color"); } if (value.HasMember("stroke")) { - klass.halo = parseColor(value["stroke"]); - klass.halo_transition = parseTransition(value, "stroke"); + klass.emplace(Key::TextHaloColor, parseColor(value["stroke"])); + parseTransition(klass, Key::TextHaloColorTransition, value, "stroke"); } if (value.HasMember("strokeWidth")) { - klass.halo_radius = parseFunction(value["strokeWidth"]); - klass.halo_radius_transition = parseTransition(value, "strokeWidth"); + klass.emplace(Key::TextHaloRadius, parseFunction(value["strokeWidth"])); + parseTransition(klass, Key::TextHaloRadiusTransition, value, "strokeWidth"); } if (value.HasMember("strokeBlur")) { - klass.halo_blur = parseFunction(value["strokeBlur"]); - klass.halo_blur_transition = parseTransition(value, "strokeBlur"); + klass.emplace(Key::TextHaloBlur, parseFunction(value["strokeBlur"])); + parseTransition(klass, Key::TextHaloBlurTransition, value, "strokeBlur"); } if (value.HasMember("size")) { - klass.size = parseFunction(value["size"]); + klass.emplace(Key::TextSize, parseFunction(value["size"])); } if (value.HasMember("rotate")) { - klass.rotate = parseFunction(value["rotate"]); + klass.emplace(Key::TextRotate, parseFunction(value["rotate"])); } if (value.HasMember("alwaysVisible")) { - klass.always_visible = parseFunction(value["alwaysVisible"]); + klass.emplace(Key::TextAlwaysVisible, parseFunction(value["alwaysVisible"])); } return klass; } -RasterClass StyleParser::parseRasterClass(JSVal value) { - RasterClass klass; +ClassProperties StyleParser::parseRasterClass(JSVal value) { + ClassProperties klass(RenderType::Raster); parseGenericClass(klass, value); return klass; } -CompositeClass StyleParser::parseCompositeClass(JSVal value) { - CompositeClass klass; +ClassProperties StyleParser::parseCompositeClass(JSVal value) { + ClassProperties klass(RenderType::Composite); parseGenericClass(klass, value); return klass; } -BackgroundClass StyleParser::parseBackgroundClass(JSVal value) { - BackgroundClass klass; +ClassProperties StyleParser::parseBackgroundClass(JSVal value) { + ClassProperties klass(RenderType::Background); parseGenericClass(klass, value); + using Key = ClassPropertyKey; + if (value.HasMember("color")) { - klass.color = parseColor(value["color"]); - klass.color_transition = parseTransition(value, "color"); + klass.emplace(Key::BackgroundColor, parseColor(value["color"])); + parseTransition(klass, Key::BackgroundColorTransition, value, "color"); } return klass;