summaryrefslogtreecommitdiff
path: root/include/mbgl/style
diff options
context:
space:
mode:
Diffstat (limited to 'include/mbgl/style')
-rw-r--r--include/mbgl/style/applied_class_properties.hpp39
-rw-r--r--include/mbgl/style/class_dictionary.hpp32
-rw-r--r--include/mbgl/style/class_properties.hpp43
-rw-r--r--include/mbgl/style/filter_comparison.hpp65
-rw-r--r--include/mbgl/style/filter_comparison_private.hpp23
-rw-r--r--include/mbgl/style/filter_expression.hpp54
-rw-r--r--include/mbgl/style/filter_expression_private.hpp75
-rw-r--r--include/mbgl/style/function_properties.hpp79
-rw-r--r--include/mbgl/style/property_fallback.hpp29
-rw-r--r--include/mbgl/style/property_key.hpp57
-rw-r--r--include/mbgl/style/property_transition.hpp15
-rw-r--r--include/mbgl/style/property_value.hpp21
-rw-r--r--include/mbgl/style/rasterize_properties.hpp38
-rw-r--r--include/mbgl/style/style.hpp68
-rw-r--r--include/mbgl/style/style_bucket.hpp88
-rw-r--r--include/mbgl/style/style_layer.hpp94
-rw-r--r--include/mbgl/style/style_layer_group.hpp23
-rw-r--r--include/mbgl/style/style_parser.hpp119
-rw-r--r--include/mbgl/style/style_properties.hpp116
-rw-r--r--include/mbgl/style/style_source.hpp29
-rw-r--r--include/mbgl/style/types.hpp160
-rw-r--r--include/mbgl/style/value.hpp43
-rw-r--r--include/mbgl/style/value_comparison.hpp109
23 files changed, 1419 insertions, 0 deletions
diff --git a/include/mbgl/style/applied_class_properties.hpp b/include/mbgl/style/applied_class_properties.hpp
new file mode 100644
index 0000000000..827f15a2a1
--- /dev/null
+++ b/include/mbgl/style/applied_class_properties.hpp
@@ -0,0 +1,39 @@
+#ifndef MBGL_STYLE_APPLIED_CLASS_PROPERTIES
+#define MBGL_STYLE_APPLIED_CLASS_PROPERTIES
+
+#include <mbgl/style/property_value.hpp>
+#include <mbgl/style/class_dictionary.hpp>
+#include <mbgl/util/time.hpp>
+
+#include <list>
+
+namespace mbgl {
+
+class AppliedClassProperty {
+public:
+ AppliedClassProperty(ClassID class_id, timestamp begin, timestamp end, const PropertyValue &value);
+
+public:
+ const ClassID name;
+ const timestamp begin;
+ const timestamp end;
+ const PropertyValue value;
+};
+
+
+class AppliedClassProperties {
+public:
+ std::list<AppliedClassProperty> properties;
+
+public:
+ // Returns thie ID of the most recent
+ ClassID mostRecent() const;
+ void add(ClassID class_id, timestamp begin, timestamp end, const PropertyValue &value);
+ bool hasTransitions() const;
+ void cleanup(timestamp now);
+ bool empty() const;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/style/class_dictionary.hpp b/include/mbgl/style/class_dictionary.hpp
new file mode 100644
index 0000000000..c7f9c6a284
--- /dev/null
+++ b/include/mbgl/style/class_dictionary.hpp
@@ -0,0 +1,32 @@
+#ifndef MBGL_STYLE_CLASS_DICTIONARY
+#define MBGL_STYLE_CLASS_DICTIONARY
+
+#include <cstdint>
+#include <string>
+#include <unordered_map>
+
+namespace mbgl {
+
+enum class ClassID : uint32_t {
+ Fallback = 0, // These values are from the fallback properties
+ Default = 1, // These values are from the default style for a layer
+ Named = 2 // These values (and all subsequent IDs) are from a named style from the layer
+};
+
+class ClassDictionary {
+public:
+ // Returns an ID for a class name. If the class name does not yet have an ID, one is
+ // auto-generated and stored for future reference.
+ static ClassID Lookup(const std::string &class_name);
+
+ // Returns either Fallback, Default or Named, depending on the type of the class id.
+ static ClassID Normalize(ClassID id);
+
+private:
+ static std::unordered_map<std::string, ClassID> store;
+ static uint32_t offset;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/style/class_properties.hpp b/include/mbgl/style/class_properties.hpp
new file mode 100644
index 0000000000..84b6f483bd
--- /dev/null
+++ b/include/mbgl/style/class_properties.hpp
@@ -0,0 +1,43 @@
+#ifndef MBGL_STYLE_CLASS_PROPERTIES
+#define MBGL_STYLE_CLASS_PROPERTIES
+
+#include <mbgl/style/property_key.hpp>
+#include <mbgl/style/property_value.hpp>
+#include <mbgl/style/property_transition.hpp>
+
+#include <map>
+
+namespace mbgl {
+
+class ClassProperties {
+public:
+ inline ClassProperties() {}
+ inline ClassProperties(ClassProperties &&properties)
+ : properties(std::move(properties.properties)) {}
+
+ inline void set(PropertyKey key, const PropertyValue &value) {
+ properties.emplace(key, value);
+ }
+
+ inline void set(PropertyKey key, const PropertyTransition &transition) {
+ transitions.emplace(key, transition);
+ }
+
+ const PropertyTransition &getTransition(PropertyKey key, const PropertyTransition &defaultTransition) const;
+
+ // Route-through iterable interface so that you can iterate on the object as is.
+ inline std::map<PropertyKey, PropertyValue>::const_iterator begin() const {
+ return properties.begin();
+ }
+ inline std::map<PropertyKey, PropertyValue>::const_iterator end() const {
+ return properties.end();
+ }
+
+public:
+ std::map<PropertyKey, PropertyValue> properties;
+ std::map<PropertyKey, PropertyTransition> transitions;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/style/filter_comparison.hpp b/include/mbgl/style/filter_comparison.hpp
new file mode 100644
index 0000000000..bf48744f1e
--- /dev/null
+++ b/include/mbgl/style/filter_comparison.hpp
@@ -0,0 +1,65 @@
+#ifndef MBGL_STYLE_FILTER_COMPARISON
+#define MBGL_STYLE_FILTER_COMPARISON
+
+#include <mbgl/style/value.hpp>
+
+#include <vector>
+#include <string>
+#include <iosfwd>
+
+namespace mbgl {
+
+class FilterComparison {
+public:
+ enum class Operator : uint8_t {
+ Equal,
+ NotEqual,
+ Greater,
+ GreaterEqual,
+ Less,
+ LessEqual,
+ In,
+ NotIn
+ };
+
+ class Instance {
+ public:
+ Instance(Operator op, std::vector<Value> &&values)
+ : op(op), values(values) {}
+
+ bool compare(const std::vector<Value> &property_values) const;
+
+ private:
+ Operator op = Operator::Equal;
+ std::vector<Value> values;
+
+ friend std::ostream& operator <<(std::ostream &, const Instance &);
+ };
+
+public:
+ FilterComparison(const std::string &field) : field(field) {};
+
+ const std::string &getField() const;
+ template <typename Extractor> inline bool compare(const Extractor &extractor) const;
+
+ template <typename ...Args>
+ inline void add(Args&& ...args) {
+ instances.emplace_back(::std::forward<Args>(args)...);
+ }
+
+private:
+ std::string field;
+ std::vector<Instance> instances;
+
+ friend std::ostream& operator <<(std::ostream &, const FilterComparison &);
+};
+
+std::ostream& operator <<(std::ostream &s, const FilterComparison &comparison);
+std::ostream& operator <<(std::ostream &s, const FilterComparison::Instance &instance);
+
+
+FilterComparison::Operator parseFilterComparisonOperator(const std::string &op);
+
+}
+
+#endif
diff --git a/include/mbgl/style/filter_comparison_private.hpp b/include/mbgl/style/filter_comparison_private.hpp
new file mode 100644
index 0000000000..6486832424
--- /dev/null
+++ b/include/mbgl/style/filter_comparison_private.hpp
@@ -0,0 +1,23 @@
+#ifndef MBGL_STYLE_FILTER_COMPARISON_PRIVATE
+#define MBGL_STYLE_FILTER_COMPARISON_PRIVATE
+
+#include "filter_comparison.hpp"
+
+namespace mbgl {
+
+template <typename Extractor>
+inline bool FilterComparison::compare(const Extractor &extractor) const {
+ const std::vector<Value> values = extractor.getValues(field);
+
+ // All instances are ANDed together.
+ for (const Instance &instance : instances) {
+ if (!instance.compare(values)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+}
+
+#endif
diff --git a/include/mbgl/style/filter_expression.hpp b/include/mbgl/style/filter_expression.hpp
new file mode 100644
index 0000000000..2a6a2927e7
--- /dev/null
+++ b/include/mbgl/style/filter_expression.hpp
@@ -0,0 +1,54 @@
+#ifndef MBGL_STYLE_FILTER_EXPRESSION
+#define MBGL_STYLE_FILTER_EXPRESSION
+
+#include <mbgl/style/filter_comparison.hpp>
+#include <mbgl/util/recursive_wrapper.hpp>
+
+#include <iosfwd>
+
+namespace mbgl {
+
+class FilterExpression {
+public:
+ typedef util::recursive_wrapper<FilterExpression> Wrapper;
+
+ enum class Operator : uint8_t {
+ And,
+ Or,
+ Xor,
+ Nor
+ };
+
+ enum class GeometryType : uint8_t {
+ Any,
+ Point,
+ LineString,
+ Polygon
+ };
+
+public:
+ FilterExpression() = default;
+ FilterExpression(Operator op) : op(op) {};
+
+ bool empty() const;
+
+ template <typename Extractor> bool compare(const Extractor &extractor) const;
+ void add(const FilterComparison &comparison);
+ void add(const FilterExpression &expression);
+ void setGeometryType(GeometryType g);
+
+private:
+ Operator op = Operator::And;
+ GeometryType type = GeometryType::Any;
+ std::vector<FilterComparison> comparisons;
+ std::vector<FilterExpression::Wrapper> expressions;
+
+ friend std::ostream& operator <<(std::ostream &, const FilterExpression &);
+};
+
+std::ostream& operator <<(std::ostream &s, const FilterExpression &expression);
+
+FilterExpression::GeometryType parseGeometryType(const std::string &geometry);
+}
+
+#endif
diff --git a/include/mbgl/style/filter_expression_private.hpp b/include/mbgl/style/filter_expression_private.hpp
new file mode 100644
index 0000000000..9379d250ba
--- /dev/null
+++ b/include/mbgl/style/filter_expression_private.hpp
@@ -0,0 +1,75 @@
+#ifndef MBGL_STYLE_FILTER_EXPRESSION_PRIVATE
+#define MBGL_STYLE_FILTER_EXPRESSION_PRIVATE
+
+#include "filter_expression.hpp"
+#include "filter_comparison_private.hpp"
+
+namespace mbgl {
+
+template <typename Extractor>
+bool FilterExpression::compare(const Extractor &extractor) const {
+ if (type != GeometryType::Any && extractor.getType() != type && extractor.getType() != GeometryType::Any) {
+ return false;
+ }
+
+ switch (op) {
+ case Operator::And:
+ for (const FilterComparison &comparison : comparisons) {
+ if (!comparison.compare(extractor)) {
+ return false;
+ }
+ }
+ for (const FilterExpression &expression: expressions) {
+ if (!expression.compare(extractor)) {
+ return false;
+ }
+ }
+ return true;
+ case Operator::Or:
+ for (const FilterComparison &comparison : comparisons) {
+ if (comparison.compare(extractor)) {
+ return true;
+ }
+ }
+ for (const FilterExpression &expression: expressions) {
+ if (expression.compare(extractor)) {
+ return true;
+ }
+ }
+ return false;
+ case Operator::Xor: {
+ int count = 0;
+ for (const FilterComparison &comparison : comparisons) {
+ count += comparison.compare(extractor);
+ if (count > 1) {
+ return false;
+ }
+ }
+ for (const FilterExpression &expression: expressions) {
+ count += expression.compare(extractor);
+ if (count > 1) {
+ return false;
+ }
+ }
+ return count == 1;
+ }
+ case Operator::Nor:
+ for (const FilterComparison &comparison : comparisons) {
+ if (comparison.compare(extractor)) {
+ return false;
+ }
+ }
+ for (const FilterExpression &expression: expressions) {
+ if (expression.compare(extractor)) {
+ return false;
+ }
+ }
+ return true;
+ default:
+ return true;
+ }
+}
+
+}
+
+#endif
diff --git a/include/mbgl/style/function_properties.hpp b/include/mbgl/style/function_properties.hpp
new file mode 100644
index 0000000000..74ac80f83c
--- /dev/null
+++ b/include/mbgl/style/function_properties.hpp
@@ -0,0 +1,79 @@
+#ifndef MBGL_STYLE_FUNCTION_PROPERTIES
+#define MBGL_STYLE_FUNCTION_PROPERTIES
+
+#include <mbgl/util/variant.hpp>
+
+#include <vector>
+
+namespace mbgl {
+
+template <typename T>
+struct ConstantFunction {
+ inline ConstantFunction(const T &value) : value(value) {}
+ inline T evaluate(float) const { return value; }
+
+private:
+ const T value;
+};
+
+template <typename T>
+struct LinearFunction {
+ inline LinearFunction(const T &value, float z_base, float slope, const T &min, const T &max)
+ : value(value), min(min), max(max), z_base(z_base), slope(slope) {}
+ T evaluate(float z) const;
+
+private:
+ const T value, min, max;
+ const float z_base, slope;
+};
+
+template <typename T>
+struct ExponentialFunction {
+ inline ExponentialFunction(const T &value, float z_base, float exp_base, float slope, const T &min,
+ const T &max)
+ : value(value), min(min), max(max), z_base(z_base), exp_base(exp_base), slope(slope) {}
+ T evaluate(float z) const;
+
+private:
+ const T value, min, max;
+ const float z_base, exp_base, slope;
+};
+
+template <typename T>
+struct StopsFunction {
+ inline StopsFunction(const std::vector<std::pair<float, T>> &values) : values(values) {}
+ T evaluate(float z) const;
+
+private:
+ const std::vector<std::pair<float, T>> values;
+};
+
+template <typename T>
+using Function = util::variant<
+ std::false_type,
+ ConstantFunction<T>,
+ LinearFunction<T>,
+ ExponentialFunction<T>,
+ StopsFunction<T>
+>;
+
+template <typename T>
+struct FunctionEvaluator {
+ typedef T result_type;
+ inline FunctionEvaluator(float z) : z(z) {}
+
+ inline result_type operator()(const std::false_type &) {
+ return result_type();
+ }
+
+ template <template <typename> class Fn>
+ inline result_type operator()(const Fn<T>& fn) {
+ return fn.evaluate(z);
+ }
+private:
+ float z;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/style/property_fallback.hpp b/include/mbgl/style/property_fallback.hpp
new file mode 100644
index 0000000000..5c5eae0cd6
--- /dev/null
+++ b/include/mbgl/style/property_fallback.hpp
@@ -0,0 +1,29 @@
+#ifndef MBGL_STYLE_PROPERTY_FALLBACK
+#define MBGL_STYLE_PROPERTY_FALLBACK
+
+#include <mbgl/style/property_key.hpp>
+#include <mbgl/style/property_value.hpp>
+
+#include <map>
+
+namespace mbgl {
+
+class PropertyFallbackValue {
+public:
+ static const PropertyValue &Get(PropertyKey key) {
+ auto it = properties.find(key);
+ if (it != properties.end()) {
+ return it->second;
+ } else {
+ return defaultProperty;
+ }
+ }
+
+private:
+ static const std::map<PropertyKey, PropertyValue> properties;
+ static const PropertyValue defaultProperty;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/style/property_key.hpp b/include/mbgl/style/property_key.hpp
new file mode 100644
index 0000000000..d9005f2f4a
--- /dev/null
+++ b/include/mbgl/style/property_key.hpp
@@ -0,0 +1,57 @@
+#ifndef MBGL_STYLE_PROPERTY_KEY
+#define MBGL_STYLE_PROPERTY_KEY
+
+namespace mbgl {
+
+enum class PropertyKey {
+ FillAntialias,
+ FillOpacity,
+ FillColor,
+ FillOutlineColor,
+ FillTranslate, // for transitions only
+ FillTranslateX,
+ FillTranslateY,
+ FillTranslateAnchor,
+ FillImage,
+
+ LineOpacity,
+ LineColor,
+ LineTranslate, // for transitions only
+ LineTranslateX,
+ LineTranslateY,
+ LineTranslateAnchor,
+ LineWidth,
+ LineOffset,
+ LineBlur,
+ LineDashArray, // for transitions only
+ LineDashLand,
+ LineDashGap,
+ LineImage,
+
+ IconOpacity,
+ IconRotate,
+ IconRotateAnchor,
+
+ TextOpacity,
+ TextSize,
+ TextColor,
+ TextHaloColor,
+ TextHaloWidth,
+ TextHaloBlur,
+
+ CompositeOpacity,
+
+ RasterOpacity,
+ RasterSpin,
+ RasterBrightnessLow,
+ RasterBrightnessHigh,
+ RasterSaturation,
+ RasterContrast,
+ RasterFade,
+
+ BackgroundColor
+};
+
+}
+
+#endif
diff --git a/include/mbgl/style/property_transition.hpp b/include/mbgl/style/property_transition.hpp
new file mode 100644
index 0000000000..07b7cfe288
--- /dev/null
+++ b/include/mbgl/style/property_transition.hpp
@@ -0,0 +1,15 @@
+#ifndef MBGL_STYLE_PROPERTY_TRANSITION
+#define MBGL_STYLE_PROPERTY_TRANSITION
+
+#include <cstdint>
+
+namespace mbgl {
+
+struct PropertyTransition {
+ uint16_t duration = 0;
+ uint16_t delay = 0;
+};
+
+}
+
+#endif \ No newline at end of file
diff --git a/include/mbgl/style/property_value.hpp b/include/mbgl/style/property_value.hpp
new file mode 100644
index 0000000000..4d148dc029
--- /dev/null
+++ b/include/mbgl/style/property_value.hpp
@@ -0,0 +1,21 @@
+#ifndef MBGL_STYLE_PROPERTY_VALUE
+#define MBGL_STYLE_PROPERTY_VALUE
+
+#include <mbgl/util/variant.hpp>
+#include <mbgl/style/function_properties.hpp>
+#include <mbgl/style/types.hpp>
+
+namespace mbgl {
+
+typedef util::variant<
+ std::string,
+ TranslateAnchorType,
+ RotateAnchorType,
+ Function<bool>,
+ Function<float>,
+ Function<Color>
+> PropertyValue;
+
+}
+
+#endif
diff --git a/include/mbgl/style/rasterize_properties.hpp b/include/mbgl/style/rasterize_properties.hpp
new file mode 100644
index 0000000000..aea90dfbdd
--- /dev/null
+++ b/include/mbgl/style/rasterize_properties.hpp
@@ -0,0 +1,38 @@
+#ifndef MBGL_STYLE_RASTERIZE_PROPERTIES
+#define MBGL_STYLE_RASTERIZE_PROPERTIES
+
+#include <mbgl/style/function_properties.hpp>
+
+namespace mbgl {
+
+// The calculated properties for a layer in a tile.
+class RasterizedProperties {
+public:
+ float buffer = 1.0f / 32.0f;
+ uint16_t size = 256;
+ uint8_t blur = 0;
+};
+
+class RasterizeProperties {
+public:
+ Function<bool> enabled = ConstantFunction<bool>(false);
+ Function<float> buffer = ConstantFunction<float>(1.0f / 32.0f);
+ Function<float> size = ConstantFunction<float>(256);
+ Function<float> blur = ConstantFunction<float>(0);
+
+ inline bool isEnabled(const int8_t z) const {
+ return util::apply_visitor(FunctionEvaluator<bool>(z), enabled);
+ }
+
+ inline RasterizedProperties get(const int8_t z) const {
+ RasterizedProperties properties;
+ properties.buffer = util::apply_visitor(FunctionEvaluator<float>(z), buffer);
+ properties.size = util::apply_visitor(FunctionEvaluator<float>(z), size);
+ properties.blur = util::apply_visitor(FunctionEvaluator<float>(z), blur);
+ return properties;
+ }
+};
+
+}
+
+#endif
diff --git a/include/mbgl/style/style.hpp b/include/mbgl/style/style.hpp
new file mode 100644
index 0000000000..6aab71a4c6
--- /dev/null
+++ b/include/mbgl/style/style.hpp
@@ -0,0 +1,68 @@
+#ifndef MBGL_STYLE_STYLE
+#define MBGL_STYLE_STYLE
+
+#include <mbgl/style/property_transition.hpp>
+#include <mbgl/style/style_source.hpp>
+
+#include <mbgl/util/time.hpp>
+#include <mbgl/util/uv.hpp>
+
+#include <cstdint>
+#include <map>
+#include <string>
+#include <unordered_map>
+#include <vector>
+#include <set>
+#include <memory>
+
+namespace mbgl {
+
+class Sprite;
+class StyleLayer;
+class StyleLayerGroup;
+struct BackgroundProperties;
+
+class Style {
+public:
+ struct exception : std::runtime_error { exception(const char *msg) : std::runtime_error(msg) {} };
+
+public:
+ Style();
+
+ void loadJSON(const uint8_t *const data);
+
+ size_t layerCount() const;
+ void updateProperties(float z, timestamp t);
+
+ void setDefaultTransitionDuration(uint16_t duration_milliseconds = 0);
+
+ void setAppliedClasses(const std::vector<std::string> &classes);
+ const std::vector<std::string> &getAppliedClasses() const;
+ void toggleClass(const std::string &name);
+
+ // Updates the styling information to reflect the current array
+ // of applied classes.
+ void updateClasses();
+
+ bool hasTransitions() const;
+
+ const BackgroundProperties &getBackgroundProperties() const;
+
+public:
+ std::shared_ptr<Sprite> sprite;
+ std::shared_ptr<StyleLayerGroup> layers;
+ std::vector<std::string> appliedClasses;
+ std::string sprite_url;
+ std::string glyph_url;
+
+
+private:
+ PropertyTransition defaultTransition;
+ bool initial_render_complete = false;
+
+ mutable uv::rwlock mtx;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/style/style_bucket.hpp b/include/mbgl/style/style_bucket.hpp
new file mode 100644
index 0000000000..62f072d9cd
--- /dev/null
+++ b/include/mbgl/style/style_bucket.hpp
@@ -0,0 +1,88 @@
+#ifndef MBGL_STYLE_STYLE_BUCKET
+#define MBGL_STYLE_STYLE_BUCKET
+
+#include <mbgl/style/types.hpp>
+#include <mbgl/style/filter_expression.hpp>
+#include <mbgl/style/style_source.hpp>
+#include <mbgl/util/vec.hpp>
+#include <mbgl/util/variant.hpp>
+
+#include <memory>
+#include <forward_list>
+
+namespace mbgl {
+
+class Source;
+
+class StyleBucketFill {
+public:
+ WindingType winding = WindingType::Default;
+};
+
+class StyleBucketLine {
+public:
+ CapType cap = CapType::Default;
+ JoinType join = JoinType::Default;
+ float miter_limit = 2.0f;
+ float round_limit = 1.0f;
+};
+
+class StyleBucketIcon {
+public:
+ uint16_t size = 16;
+ vec2<float> translate {0, 0};
+ TranslateAnchorType translate_anchor = TranslateAnchorType::Default;
+ std::string icon;
+ float spacing = 0.0f;
+ float padding = 2.0f;
+};
+
+class StyleBucketText {
+public:
+ std::string field;
+ TextPathType path = TextPathType::Default;
+ TextTransformType transform = TextTransformType::Default;
+ std::string font;
+ float max_size = 16.0f;
+ float max_width = 15.0f * 24;
+ float line_height = 1.2f * 24;
+ float letter_spacing = 0.0f;
+ float alignment = 0.5f;
+ float vertical_alignment = 0.5;
+ vec2<float> translate {0, 0};
+ TranslateAnchorType translate_anchor = TranslateAnchorType::Default;
+ float max_angle_delta = M_PI;
+ float min_distance = 250.0f;
+ float rotate = 0.0f; // what is this?
+ float padding = 2.0f;
+ float slant = 0.0f;
+ bool always_visible = false;
+};
+
+class StyleBucketRaster {
+public:
+};
+
+typedef util::variant<StyleBucketFill, StyleBucketLine, StyleBucketIcon,
+ StyleBucketText, StyleBucketRaster,
+ std::false_type> StyleBucketRender;
+
+
+class StyleBucket {
+public:
+ typedef std::shared_ptr<StyleBucket> Ptr;
+
+ StyleBucket(StyleLayerType type);
+
+ std::string name;
+ std::shared_ptr<StyleSource> style_source;
+ std::string source_layer;
+ FilterExpression filter;
+ StyleBucketRender render = std::false_type();
+};
+
+
+
+};
+
+#endif
diff --git a/include/mbgl/style/style_layer.hpp b/include/mbgl/style/style_layer.hpp
new file mode 100644
index 0000000000..14d60ed9b6
--- /dev/null
+++ b/include/mbgl/style/style_layer.hpp
@@ -0,0 +1,94 @@
+#ifndef MBGL_STYLE_STYLE_LAYER
+#define MBGL_STYLE_STYLE_LAYER
+
+#include <mbgl/style/class_dictionary.hpp>
+#include <mbgl/style/class_properties.hpp>
+#include <mbgl/style/style_properties.hpp>
+#include <mbgl/style/rasterize_properties.hpp>
+#include <mbgl/style/applied_class_properties.hpp>
+
+#include <vector>
+#include <memory>
+#include <string>
+#include <map>
+#include <set>
+
+namespace mbgl {
+
+class StyleBucket;
+class StyleLayerGroup;
+
+class StyleLayer {
+public:
+ StyleLayer(const std::string &id, std::map<ClassID, ClassProperties> &&styles,
+ std::unique_ptr<const RasterizeProperties> &&rasterize);
+
+ template <typename T> const T &getProperties() {
+ if (properties.is<T>()) {
+ return properties.get<T>();
+ } else {
+ return defaultStyleProperties<T>();
+ }
+ }
+
+ // Determines whether this layer is the background layer.
+ bool isBackground() const;
+
+ // Updates the StyleProperties information in this layer by evaluating all
+ // pending transitions and applied classes in order.
+ void updateProperties(float z, timestamp now);
+
+ // Sets the list of classes and creates transitions to the currently applied values.
+ void setClasses(const std::vector<std::string> &class_names, timestamp now,
+ const PropertyTransition &defaultTransition);
+
+ bool hasTransitions() const;
+
+private:
+ // Applies all properties from a class, if they haven't been applied already.
+ void applyClassProperties(ClassID class_id, std::set<PropertyKey> &already_applied,
+ timestamp now, const PropertyTransition &defaultTransition);
+
+ // Sets the properties of this object by evaluating all pending transitions and
+ // aplied classes in order.
+ template <typename T> void applyStyleProperties(float z, timestamp now);
+ template <typename T> void applyStyleProperty(PropertyKey key, T &, float z, timestamp now);
+
+ // Removes all expired style transitions.
+ void cleanupAppliedStyleProperties(timestamp now);
+
+public:
+ // The name of this layer.
+ const std::string id;
+
+ StyleLayerType type = StyleLayerType::Unknown;
+
+ // Bucket information, telling the renderer how to generate the geometries
+ // for this layer (feature property filters, tessellation instructions, ...).
+ std::shared_ptr<StyleBucket> bucket;
+
+ // Contains all style classes that can be applied to this layer.
+ const std::map<ClassID, ClassProperties> styles;
+
+private:
+ // For every property, stores a list of applied property values, with
+ // optional transition times.
+ std::map<PropertyKey, AppliedClassProperties> appliedStyle;
+
+public:
+ // Stores the evaluated, and cascaded styling information, specific to this
+ // layer's type.
+ StyleProperties properties;
+
+ // 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.
+ const std::unique_ptr<const RasterizeProperties> rasterize;
+
+ // Child layer array (if this layer has child layers).
+ std::shared_ptr<StyleLayerGroup> layers;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/style/style_layer_group.hpp b/include/mbgl/style/style_layer_group.hpp
new file mode 100644
index 0000000000..983dd136f0
--- /dev/null
+++ b/include/mbgl/style/style_layer_group.hpp
@@ -0,0 +1,23 @@
+#ifndef MBGL_STYLE_STYLE_LAYER_GROUP
+#define MBGL_STYLE_STYLE_LAYER_GROUP
+
+#include <mbgl/style/style_layer.hpp>
+
+#include <vector>
+
+namespace mbgl {
+
+class StyleLayerGroup {
+public:
+ void setClasses(const std::vector<std::string> &class_names, timestamp now,
+ const PropertyTransition &defaultTransition);
+ void updateProperties(float z, timestamp t);
+
+ bool hasTransitions() const;
+public:
+ std::vector<std::shared_ptr<StyleLayer>> layers;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/style/style_parser.hpp b/include/mbgl/style/style_parser.hpp
new file mode 100644
index 0000000000..431e3af8db
--- /dev/null
+++ b/include/mbgl/style/style_parser.hpp
@@ -0,0 +1,119 @@
+#ifndef MBGL_STYLE_STYLE_PARSER
+#define MBGL_STYLE_STYLE_PARSER
+
+#include <rapidjson/document.h>
+#include <mbgl/style/style.hpp>
+#include <mbgl/style/style_source.hpp>
+#include <mbgl/style/filter_expression.hpp>
+#include <mbgl/style/class_properties.hpp>
+#include <mbgl/style/rasterize_properties.hpp>
+#include <mbgl/style/style_bucket.hpp>
+
+#include <unordered_map>
+#include <forward_list>
+#include <tuple>
+
+namespace mbgl {
+
+enum class ClassID : uint32_t;
+
+class StyleLayer;
+class StyleLayerGroup;
+
+class StyleParser {
+public:
+ using JSVal = const rapidjson::Value&;
+
+ StyleParser();
+
+ void parse(JSVal document);
+
+ std::shared_ptr<StyleLayerGroup> getLayers() {
+ return root;
+ }
+
+ std::string getSprite() const {
+ return sprite;
+ }
+
+ std::string getGlyphURL() const {
+ return glyph_url;
+ }
+
+private:
+ void parseConstants(JSVal value);
+ JSVal replaceConstant(JSVal value);
+
+ void parseSources(JSVal value);
+
+ std::unique_ptr<StyleLayerGroup> createLayers(JSVal value);
+ std::shared_ptr<StyleLayer> createLayer(JSVal value);
+ void parseLayers();
+ void parseLayer(std::pair<JSVal, std::shared_ptr<StyleLayer>> &pair);
+ void parseStyles(JSVal value, std::map<ClassID, ClassProperties> &styles);
+ void parseStyle(JSVal, ClassProperties &properties);
+ std::unique_ptr<RasterizeProperties> parseRasterize(JSVal value);
+ void parseReference(JSVal value, std::shared_ptr<StyleLayer> &layer);
+ void parseBucket(JSVal value, std::shared_ptr<StyleLayer> &layer);
+ void parseRender(JSVal value, std::shared_ptr<StyleLayer> &layer);
+ void parseSprite(JSVal value);
+ void parseGlyphURL(JSVal value);
+
+ // Parses optional properties into a render bucket.
+ template<typename T>
+ bool parseRenderProperty(JSVal value, T &target, const char *name);
+ template <typename T, typename Parser>
+ bool parseRenderProperty(JSVal value, T &target, const char *name, Parser &parser);
+
+ // Parses optional properties into style class properties.
+ template <typename T>
+ bool parseOptionalProperty(const char *property_name, PropertyKey key, ClassProperties &klass, JSVal value);
+ template <typename T>
+ bool parseOptionalProperty(const char *property_name, const std::vector<PropertyKey> &keys, ClassProperties &klass, JSVal value);
+ template <typename T>
+ bool parseOptionalProperty(const char *property_name, T &target, JSVal value);
+ template <typename T>
+ bool setProperty(JSVal value, const char *property_name, PropertyKey key, ClassProperties &klass);
+ template <typename T>
+ bool setProperty(JSVal value, const char *property_name, T &target);
+
+ template <typename T>
+ std::tuple<bool, T> parseProperty(JSVal value, const char *property_name);
+
+ template <typename T>
+ bool parseFunction(PropertyKey key, ClassProperties &klass, JSVal value);
+ template <typename T>
+ std::tuple<bool, Function<T>> parseFunction(JSVal value);
+ template <typename T>
+ T parseFunctionArgument(JSVal value);
+
+
+ FilterExpression parseFilter(JSVal, FilterExpression::Operator op);
+ FilterExpression parseFilter(JSVal);
+ Value parseValue(JSVal value);
+ std::vector<Value> parseValues(JSVal values);
+
+private:
+ std::unordered_map<std::string, const rapidjson::Value *> constants;
+
+ std::unordered_map<std::string, const std::shared_ptr<StyleSource>> sources;
+
+ // This stores the root layer.
+ std::shared_ptr<StyleLayerGroup> root;
+
+ // This maps ids to Layer objects, with all items being at the root level.
+ std::unordered_map<std::string, std::pair<JSVal, std::shared_ptr<StyleLayer>>> layers;
+
+ // Store a stack of layers we're parsing right now. This is to prevent reference cycles.
+ std::forward_list<StyleLayer *> stack;
+
+ // Base URL of the sprite image.
+ std::string sprite;
+
+ // URL template for glyph PBFs.
+ std::string glyph_url;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/style/style_properties.hpp b/include/mbgl/style/style_properties.hpp
new file mode 100644
index 0000000000..c7606be254
--- /dev/null
+++ b/include/mbgl/style/style_properties.hpp
@@ -0,0 +1,116 @@
+#ifndef MBGL_STYLE_STYLE_PROPERTIES
+#define MBGL_STYLE_STYLE_PROPERTIES
+
+#include <mbgl/util/variant.hpp>
+#include <mbgl/style/types.hpp>
+#include <mbgl/style/function_properties.hpp>
+
+#include <array>
+#include <string>
+#include <type_traits>
+#include <memory>
+
+namespace mbgl {
+
+struct FillProperties {
+ FillProperties() {}
+ bool antialias = true;
+ float opacity = 1.0f;
+ Color fill_color = {{ 0, 0, 0, 1 }};
+ Color stroke_color = {{ 0, 0, 0, -1 }};
+ std::array<float, 2> translate = {{ 0, 0 }};
+ TranslateAnchorType translateAnchor = TranslateAnchorType::Default;
+ std::string image;
+
+ inline bool isVisible() const {
+ return opacity > 0 && (fill_color[3] > 0 || stroke_color[3] > 0);
+ }
+};
+
+struct LineProperties {
+ inline LineProperties() {}
+ float opacity = 1.0f;
+ Color color = {{ 0, 0, 0, 1 }};
+ std::array<float, 2> translate = {{ 0, 0 }};
+ TranslateAnchorType translateAnchor = TranslateAnchorType::Default;
+ float width = 0;
+ float offset = 0;
+ float blur = 0;
+ std::array<float, 2> dash_array = {{ 1, -1 }};
+ std::string image;
+
+ inline bool isVisible() const {
+ return opacity > 0 && color[3] > 0 && width > 0;
+ }
+};
+
+struct IconProperties {
+ inline IconProperties() {}
+ float opacity = 1.0f;
+ float rotate = 0.0f;
+ RotateAnchorType rotate_anchor = RotateAnchorType::Default;
+
+ inline bool isVisible() const {
+ return opacity > 0;
+ }
+};
+
+struct TextProperties {
+ inline TextProperties() {}
+ float opacity = 1.0f;
+ float size = 12.0f;
+ Color color = {{ 0, 0, 0, 1 }};
+ Color halo_color = {{ 1, 1, 1, 0.75 }};
+ float halo_width = 0.25f;
+ float halo_blur = 1.0f;
+
+ inline bool isVisible() const {
+ return opacity > 0 && (color[3] > 0 || halo_color[3] > 0) && size > 0;
+ }
+};
+
+struct CompositeProperties {
+ inline CompositeProperties() {}
+ float opacity = 1.0f;
+
+ inline bool isVisible() const {
+ return opacity > 0;
+ }
+};
+
+struct RasterProperties {
+ inline RasterProperties() {}
+ float opacity = 1.0f;
+ float spin = 0.0f;
+ std::array<float, 2> brightness = {{ 0, 1 }};
+ float saturation = 0.0f;
+ float contrast = 0.0f;
+ float fade = 0.0f;
+
+ inline bool isVisible() const {
+ return opacity > 0;
+ }
+};
+
+struct BackgroundProperties {
+ inline BackgroundProperties() {}
+ Color color = {{ 1, 1, 1, 1 }};
+};
+
+typedef util::variant<
+ FillProperties,
+ LineProperties,
+ IconProperties,
+ TextProperties,
+ CompositeProperties,
+ RasterProperties,
+ BackgroundProperties,
+ std::false_type
+> StyleProperties;
+
+template <typename T>
+const T &defaultStyleProperties();
+
+}
+
+#endif
diff --git a/include/mbgl/style/style_source.hpp b/include/mbgl/style/style_source.hpp
new file mode 100644
index 0000000000..6b86c30907
--- /dev/null
+++ b/include/mbgl/style/style_source.hpp
@@ -0,0 +1,29 @@
+#ifndef MBGL_STYLE_STYLE_SOURCE
+#define MBGL_STYLE_STYLE_SOURCE
+
+#include <mbgl/style/types.hpp>
+
+#include <memory>
+
+namespace mbgl {
+
+class Source;
+
+class StyleSource {
+public:
+ const SourceType type;
+ const std::string url;
+ const uint32_t tile_size;
+ const int32_t min_zoom;
+ const int32_t max_zoom;
+
+ bool enabled = false;
+ std::shared_ptr<Source> source;
+
+ StyleSource(SourceType type = SourceType::Vector, const std::string &url = "",
+ uint32_t tile_size = 512, uint32_t min_zoom = 0, uint32_t max_zoom = 22)
+ : type(type), url(url), tile_size(tile_size), min_zoom(min_zoom), max_zoom(max_zoom) {}
+};
+};
+
+#endif
diff --git a/include/mbgl/style/types.hpp b/include/mbgl/style/types.hpp
new file mode 100644
index 0000000000..ca2061fa91
--- /dev/null
+++ b/include/mbgl/style/types.hpp
@@ -0,0 +1,160 @@
+#ifndef MBGL_STYLE_TYPES
+#define MBGL_STYLE_TYPES
+
+#include <mbgl/util/enum.hpp>
+
+#include <string>
+#include <array>
+
+namespace mbgl {
+
+// Stores a premultiplied color, with all four channels ranging from 0..1
+typedef std::array<float, 4> Color;
+
+enum class StyleLayerType : uint8_t {
+ Unknown,
+ Fill,
+ Line,
+ Icon,
+ Text,
+ Raster,
+ Composite,
+ Background
+};
+
+MBGL_DEFINE_ENUM_CLASS(StyleLayerTypeClass, StyleLayerType, {
+ { StyleLayerType::Unknown, "unknown" },
+ { StyleLayerType::Fill, "fill" },
+ { StyleLayerType::Line, "line" },
+ { StyleLayerType::Icon, "icon" },
+ { StyleLayerType::Text, "text" },
+ { StyleLayerType::Raster, "raster" },
+ { StyleLayerType::Composite, "composite" },
+ { StyleLayerType::Background, "background" },
+ { StyleLayerType(-1), "unknown" },
+});
+
+
+enum class WindingType : uint8_t {
+ EvenOdd,
+ NonZero,
+ Default = NonZero
+};
+
+enum class CapType : uint8_t {
+ None,
+ Round,
+ Butt,
+ Square,
+ Default = None
+};
+
+enum class JoinType : uint8_t {
+ None,
+ Miter,
+ Bevel,
+ Round,
+ Default = None
+};
+
+enum class TextPathType : uint8_t {
+ Horizontal,
+ Curve,
+ Default = Horizontal
+};
+
+enum class TextTransformType : uint8_t {
+ None,
+ Uppercase,
+ Lowercase,
+ Default = None
+};
+
+enum class TranslateAnchorType : uint8_t {
+ Map,
+ Viewport,
+ Default = Map
+};
+
+enum class RotateAnchorType : uint8_t {
+ Map,
+ Viewport,
+ Default = Viewport
+};
+
+enum class SourceType : uint8_t {
+ Vector,
+ Raster,
+ GeoJSON,
+ Video,
+ Default = Vector
+};
+
+inline WindingType parseWindingType(const std::string &type) {
+ if (type == "even-odd") return WindingType::EvenOdd;
+ if (type == "non-zero") return WindingType::NonZero;
+ return WindingType::Default;
+}
+
+inline CapType parseCapType(const std::string &cap) {
+ if (cap == "round") return CapType::Round;
+ if (cap == "butt") return CapType::Butt;
+ if (cap == "square") return CapType::Square;
+ return CapType::None;
+}
+
+inline JoinType parseJoinType(const std::string &join) {
+ if (join == "miter") return JoinType::Miter;
+ if (join == "bevel") return JoinType::Bevel;
+ if (join == "round") return JoinType::Round;
+ return JoinType::None;
+}
+
+inline TextPathType parseTextPathType(const std::string &path) {
+ if (path == "horizontal") return TextPathType::Horizontal;
+ if (path == "curve") return TextPathType::Curve;
+ return TextPathType::Default;
+}
+
+inline TextTransformType parseTextTransformType(const std::string& transform) {
+ if (transform == "uppercase") return TextTransformType::Uppercase;
+ if (transform == "lowercase") return TextTransformType::Lowercase;
+ return TextTransformType::Default;
+};
+
+inline TranslateAnchorType parseTranslateAnchorType(const std::string &anchor) {
+ if (anchor == "map") return TranslateAnchorType::Map;
+ if (anchor == "viewport") return TranslateAnchorType::Viewport;
+ return TranslateAnchorType::Default;
+}
+
+inline RotateAnchorType parseRotateAnchorType(const std::string &anchor) {
+ if (anchor == "map") return RotateAnchorType::Map;
+ if (anchor == "viewport") return RotateAnchorType::Viewport;
+ return RotateAnchorType::Default;
+}
+
+inline float parseAlignmentType(const std::string &alignment) {
+ if (alignment == "right") return 1.0f;
+ if (alignment == "left") return 0.0f;
+ return 0.5f;
+}
+
+inline float parseVerticalAlignmentType(const std::string &alignment) {
+ if (alignment == "bottom") return 1.0f;
+ if (alignment == "top") return 0.0f;
+ return 0.5f;
+}
+
+inline SourceType parseSourceType(const std::string &source) {
+ if (source == "vector") return SourceType::Vector;
+ if (source == "raster") return SourceType::Raster;
+ if (source == "geojson") return SourceType::GeoJSON;
+ if (source == "video") return SourceType::Video;
+ return SourceType::Default;
+}
+
+}
+
+#endif
+
diff --git a/include/mbgl/style/value.hpp b/include/mbgl/style/value.hpp
new file mode 100644
index 0000000000..5e6260e5a6
--- /dev/null
+++ b/include/mbgl/style/value.hpp
@@ -0,0 +1,43 @@
+#ifndef MBGL_STYLE_VALUE
+#define MBGL_STYLE_VALUE
+
+#include <mbgl/util/variant.hpp>
+#include <mbgl/util/pbf.hpp>
+
+#include <cstdlib>
+#include <cerrno>
+
+namespace mbgl {
+
+typedef util::variant<bool, int64_t, uint64_t, double, std::string> Value;
+
+std::string toString(const Value &value);
+
+Value parseValue(pbf data);
+
+namespace util {
+inline bool parseNumericString(const std::string &str, double &result) {
+ char *end = nullptr;
+ const char *begin = str.c_str();
+ result = std::strtod(begin, &end);
+ while (*end != '\0' && isspace(*end)) end++; // eat whitespace after the end
+ return errno == 0 && end - begin == long(str.size());
+}
+}
+
+template <typename T>
+T toNumber(const Value &value) {
+ if (value.is<std::string>()) {
+ double val;
+ return util::parseNumericString(value.get<std::string>(), val) ? val : 0;
+ }
+ else if (value.is<bool>()) return value.get<bool>();
+ else if (value.is<int64_t>()) return value.get<int64_t>();
+ else if (value.is<uint64_t>()) return value.get<uint64_t>();
+ else if (value.is<double>()) return value.get<double>();
+ else return 0;
+}
+
+}
+
+#endif
diff --git a/include/mbgl/style/value_comparison.hpp b/include/mbgl/style/value_comparison.hpp
new file mode 100644
index 0000000000..41c1d44123
--- /dev/null
+++ b/include/mbgl/style/value_comparison.hpp
@@ -0,0 +1,109 @@
+#ifndef MBGL_STYLE_VALUE_COMPARISON
+#define MBGL_STYLE_VALUE_COMPARISON
+
+#include "value.hpp"
+#include <cstdlib>
+#include <cerrno>
+
+namespace mbgl {
+
+namespace util {
+
+namespace detail {
+
+template <typename Operator>
+struct relaxed_operator_visitor {
+ typedef bool result_type;
+
+ inline bool operator()(bool lhs, bool rhs) const { return Operator()(lhs, rhs); }
+
+ template <typename T, class = typename std::enable_if<std::is_arithmetic<T>::value>::type>
+ inline bool operator()(bool lhs, T rhs) const { return Operator()(T(lhs), rhs); }
+
+ template <typename T, class = typename std::enable_if<std::is_arithmetic<T>::value>::type>
+ inline bool operator()(T lhs, bool rhs) const { return Operator()(lhs, T(rhs)); }
+
+ inline bool operator()(int64_t lhs, uint64_t rhs) const {
+ return lhs < 0 ? false : Operator()(uint64_t(lhs), rhs);
+ }
+ inline bool operator()(uint64_t lhs, int64_t rhs) const {
+ return rhs < 0 ? false : Operator()(lhs, uint64_t(rhs));
+ }
+
+ template <typename T, class = typename std::enable_if<std::is_arithmetic<T>::value>::type>
+ inline bool operator()(const std::string &lhs, T rhs) const {
+ double value;
+ return parseNumericString(lhs, value) ? Operator()(value, double(rhs)) : false;
+ }
+
+ template <typename T, class = typename std::enable_if<std::is_arithmetic<T>::value>::type>
+ inline bool operator()(T lhs, const std::string &rhs) const {
+ double value;
+ return parseNumericString(rhs, value) ? Operator()(double(lhs), value) : false;
+ }
+
+ template <typename T0, typename T1>
+ inline bool operator()(T0 lhs, T1 rhs) const { return Operator()(lhs, rhs); }
+};
+
+struct relaxed_equal_operator {
+ template <typename T0, typename T1>
+ inline bool operator()(T0 lhs, T1 rhs) const { return lhs == rhs; }
+};
+
+struct relaxed_not_equal_operator {
+ template <typename T0, typename T1>
+ inline bool operator()(T0 lhs, T1 rhs) const { return lhs != rhs; }
+};
+
+struct relaxed_greater_operator {
+ template <typename T0, typename T1>
+ inline bool operator()(T0 lhs, T1 rhs) const { return lhs > rhs; }
+};
+
+struct relaxed_greater_equal_operator {
+ template <typename T0, typename T1>
+ inline bool operator()(T0 lhs, T1 rhs) const { return lhs >= rhs; }
+};
+
+struct relaxed_less_operator {
+ template <typename T0, typename T1>
+ inline bool operator()(T0 lhs, T1 rhs) const { return lhs < rhs; }
+};
+
+struct relaxed_less_equal_operator {
+ template <typename T0, typename T1>
+ inline bool operator()(T0 lhs, T1 rhs) const { return lhs <= rhs; }
+};
+
+} // end namespace detail
+
+inline bool relaxed_equal(Value const &lhs, Value const &rhs) {
+ return apply_visitor(detail::relaxed_operator_visitor<detail::relaxed_equal_operator>(), lhs, rhs);
+}
+
+inline bool relaxed_not_equal(Value const &lhs, Value const &rhs) {
+ return apply_visitor(detail::relaxed_operator_visitor<detail::relaxed_not_equal_operator>(), lhs, rhs);
+}
+
+inline bool relaxed_greater(Value const &lhs, Value const &rhs) {
+ return apply_visitor(detail::relaxed_operator_visitor<detail::relaxed_greater_operator>(), lhs, rhs);
+}
+
+inline bool relaxed_greater_equal(Value const &lhs, Value const &rhs) {
+ return apply_visitor(detail::relaxed_operator_visitor<detail::relaxed_greater_equal_operator>(), lhs, rhs);
+}
+
+inline bool relaxed_less(Value const &lhs, Value const &rhs) {
+ return apply_visitor(detail::relaxed_operator_visitor<detail::relaxed_less_operator>(), lhs, rhs);
+}
+
+inline bool relaxed_less_equal(Value const &lhs, Value const &rhs) {
+ return apply_visitor(detail::relaxed_operator_visitor<detail::relaxed_less_equal_operator>(), lhs, rhs);
+}
+
+}
+
+}
+
+#endif