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
|
#include <mbgl/style/paint_properties_map.hpp>
#include <mbgl/style/property_transition.hpp>
#include <mbgl/style/property_fallback.hpp>
#include <mbgl/style/class_properties.hpp>
#include <mbgl/style/style_cascade_parameters.hpp>
namespace mbgl {
void PaintPropertiesMap::parseEach(const JSVal& layer, std::function<void (ClassProperties &, const JSVal &)> parsePaint) {
paints.clear();
rapidjson::Value::ConstMemberIterator itr = layer.MemberBegin();
for (; itr != layer.MemberEnd(); ++itr) {
const std::string name { itr->name.GetString(), itr->name.GetStringLength() };
if (name == "paint") {
parsePaint(paints[ClassID::Default], itr->value);
} else if (name.compare(0, 6, "paint.") == 0 && name.length() > 6) {
parsePaint(paints[ClassDictionary::Get().lookup(name.substr(6))], itr->value);
}
}
}
void PaintPropertiesMap::cascade(const StyleCascadeParameters& parameters) {
// Stores all keys that we have already added transitions for.
std::set<PropertyKey> alreadyApplied;
// We only apply the default style values if there are no classes set.
if (parameters.classes.empty()) {
cascadeClass(ClassID::Default, alreadyApplied, parameters);
return;
}
// Reverse iterate through all class names and apply them last to first.
for (auto it = parameters.classes.rbegin(); it != parameters.classes.rend(); ++it) {
// From here on, we're only dealing with IDs to avoid comparing strings all the time.
cascadeClass(ClassDictionary::Get().lookup(*it), alreadyApplied, parameters);
}
// As the last class, apply the default class.
cascadeClass(ClassID::Default, alreadyApplied, parameters);
// Make sure that we also transition to the fallback value for keys that aren't changed by
// any applied classes.
for (auto& propertyPair : appliedStyle) {
const PropertyKey key = propertyPair.first;
if (alreadyApplied.find(key) != alreadyApplied.end()) {
// This property has already been set by a previous class, so we don't need to
// transition to the fallback.
continue;
}
AppliedClassPropertyValues &appliedProperties = propertyPair.second;
// Make sure that we don't do double transitions to the fallback value.
if (appliedProperties.mostRecent() == ClassID::Fallback) {
continue;
}
// This property key hasn't been set by a previous class, so we need to add a transition
// to the fallback value for that key.
const TimePoint begin = parameters.now + *parameters.defaultTransition.delay;
const TimePoint end = begin + *parameters.defaultTransition.duration;
const PropertyValue &value = PropertyFallbackValue::Get(key);
appliedProperties.add(ClassID::Fallback, begin, end, value);
}
}
void PaintPropertiesMap::cascadeClass(const ClassID classID,
std::set<PropertyKey>& alreadyApplied,
const StyleCascadeParameters& parameters) {
auto styleIt = paints.find(classID);
if (styleIt == paints.end()) {
// There is no class in this layer with this class_name.
return;
}
// Loop through all the properties in this style, and add transitions to them, if they're
// not already the most recent transition.
const ClassProperties& classProperties = styleIt->second;
for (const auto& propertyPair : classProperties) {
PropertyKey key = propertyPair.first;
if (alreadyApplied.find(key) != alreadyApplied.end()) {
// This property has already been set by a previous class.
continue;
}
// Mark this property as written by a previous class, so that subsequent
// classes won't override this.
alreadyApplied.insert(key);
// If the most recent transition is not the one with the highest priority, create
// a transition.
AppliedClassPropertyValues &appliedProperties = appliedStyle[key];
if (appliedProperties.mostRecent() != classID) {
PropertyTransition transition = classProperties.getTransition(key);
Duration delay = transition.delay ? *transition.delay : *parameters.defaultTransition.delay;
Duration duration = transition.duration ? *transition.duration : *parameters.defaultTransition.duration;
const TimePoint begin = parameters.now + delay;
const TimePoint end = begin + duration;
const PropertyValue &value = propertyPair.second;
appliedProperties.add(classID, begin, end, value);
}
}
}
bool PaintPropertiesMap::hasTransitions() const {
for (const auto& pair : appliedStyle) {
if (pair.second.hasTransitions()) {
return true;
}
}
return hasPendingTransitions;
}
void PaintPropertiesMap::removeExpiredTransitions(const TimePoint& now) {
for (auto it = appliedStyle.begin(); it != appliedStyle.end();) {
AppliedClassPropertyValues& values = it->second;
values.cleanup(now);
// If the current properties object is empty, remove it from the map entirely.
values.empty() ? appliedStyle.erase(it++) : ++it;
}
// Clear the pending transitions flag upon each update.
hasPendingTransitions = false;
}
}
|