summaryrefslogtreecommitdiff
path: root/src/mbgl/style/layers/symbol_layer_impl.hpp
blob: 9b63e0e8d6d61d8c149d20c8c0e8107f1c255b70 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#pragma once

#include <mbgl/style/layer_impl.hpp>
#include <mbgl/style/layers/symbol_layer.hpp>
#include <mbgl/style/layers/symbol_layer_properties.hpp>
#include <mbgl/style/expression/literal.hpp>
#include <mbgl/style/expression/format_expression.hpp>
#include <mbgl/style/expression/formatted.hpp>
#include <mbgl/style/expression/format_section_override.hpp>
#include <mbgl/style/expression/value.hpp>

namespace mbgl {
namespace style {

template<typename PaintProperty>
struct FormatSectionOverrides;

template<typename... PaintProperty>
struct FormatSectionOverrides<TypeList<PaintProperty...>> {
    template<typename Property, typename T, typename U>
    static void setOverride(const T& overrides, U& overridable) {
        if (hasOverride<Property>(overrides.template get<TextField>())) {
            auto override =
                    std::make_unique<expression::FormatSectionOverride<typename Property::Type>>(Property::expressionType(),
                                                                                                 std::move(overridable.template get<Property>()),
                                                                                                 Property::name());
            PropertyExpression<typename Property::Type> expr(std::move(override));
            overridable.template get<Property>() = PossiblyEvaluatedPropertyValue<typename Property::Type>(std::move(expr));
        }
    }

    template<typename T, typename U>
    static void setOverrides(const T& overrides, U& overridable) {
        util::ignore({(setOverride<PaintProperty>(overrides, overridable), 0)...});
    }

    template<typename Property, typename T, typename U>
    static void updateOverride(T& evaluated, U& updated) {
        auto property = evaluated.template get<Property>();
        if (!property.isConstant()) {
            const bool hasFormatSectionOverride = property.match(
                    [] (const style::PropertyExpression<typename Property::Type>& e) {
                        return e.getExpression().getKind() == expression::Kind::FormatSectionOverride;
                    },
                    [] (const auto&) {
                        return false;
                    });
            if (hasFormatSectionOverride) {
                updated.template get<Property>() = std::move(property);
            }
        }
    }

    template<typename T, typename U>
    static void updateOverrides(T& evaluated, U& updated) {
        util::ignore({(updateOverride<PaintProperty>(evaluated, updated), 0)...});
    }

    template<typename Property, typename FormattedProperty>
    static bool hasOverride(const FormattedProperty& formatted) {

        const auto checkLiteral = [] (const TextField::Type& literal) {
            for (const auto& section : literal.sections) {
                 if (Property::hasOverride(section)) {
                     return true;
                 }
            }
            return false;
        };

        return formatted.match(
                [&checkLiteral] (const TextField::Type& literal) {
                    return checkLiteral(literal);
                },
                [&checkLiteral] (const PropertyExpression<TextField::Type>& property) {
                    bool expressionHasOverrides = false;
                    const auto checkExpression = [&](const expression::Expression& e) {
                        if (expressionHasOverrides) {
                            return;
                        }

                        if (e.getKind() == expression::Kind::Literal &&
                            e.getType() == expression::type::Formatted) {
                            const auto* literalExpr = static_cast<const expression::Literal*>(&e);
                            const auto formattedValue = expression::fromExpressionValue<expression::Formatted>(literalExpr->getValue());
                            if (formattedValue && checkLiteral(*formattedValue)) {
                                expressionHasOverrides = true;
                            }
                            return;
                        }

                        if (e.getKind() == expression::Kind::FormatExpression) {
                            const auto* formatExpr = static_cast<const expression::FormatExpression*>(&e);
                            for (const auto& section : formatExpr->getSections()) {
                                if (Property::hasOverride(section)) {
                                    expressionHasOverrides = true;
                                    break;
                                }
                            }
                        }
                    };

                    // Check root property expression and return early.
                    checkExpression(property.getExpression());
                    if (expressionHasOverrides) {
                        return true;
                    }

                    // Traverse thru children and check whether any of them have overrides.
                    property.getExpression().eachChild(checkExpression);
                    return expressionHasOverrides;
                },
                [] (const auto&) {
                    return false;
                }
         );
    }

    template <typename FormattedProperty>
    static bool hasOverrides(const FormattedProperty& formatted) {
        bool result = false;
        util::ignore({ (result |= hasOverride<PaintProperty>(formatted))... });
        return result;
    }

    template <typename PaintProperties>
    static bool hasPaintPropertyDifference(const PaintProperties& lhs, const PaintProperties& rhs) {
        bool result = false;
        util::ignore({ (result |= lhs.template get<PaintProperty>().value.isConstant() &&
                                  rhs.template get<PaintProperty>().value.isConstant() &&
                                  (lhs.template get<PaintProperty>().value.asConstant() != rhs.template get<PaintProperty>().value.asConstant()))... });
        return result;
    }
};

using SymbolLayerPaintPropertyOverrides = FormatSectionOverrides<SymbolPaintProperties::OverridableProperties>;

class SymbolLayer::Impl : public Layer::Impl {
public:
    using Layer::Impl::Impl;

    bool hasLayoutDifference(const Layer::Impl&) const override;
    void stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const override;
    void populateFontStack(std::set<FontStack>& fontStack) const final;

    SymbolLayoutProperties::Unevaluated layout;
    SymbolPaintProperties::Transitionable paint;

    DECLARE_LAYER_TYPE_INFO;

private:
    bool hasFormatSectionOverrides() const;
    mutable optional<bool> hasFormatSectionOverrides_;
};

} // namespace style
} // namespace mbgl