summaryrefslogtreecommitdiff
path: root/src/mbgl/tile/vector_tile_data.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mbgl/tile/vector_tile_data.cpp')
-rw-r--r--src/mbgl/tile/vector_tile_data.cpp183
1 files changed, 183 insertions, 0 deletions
diff --git a/src/mbgl/tile/vector_tile_data.cpp b/src/mbgl/tile/vector_tile_data.cpp
new file mode 100644
index 0000000000..d2eecab975
--- /dev/null
+++ b/src/mbgl/tile/vector_tile_data.cpp
@@ -0,0 +1,183 @@
+#include <mbgl/tile/vector_tile_data.hpp>
+#include <mbgl/tile/geometry_tile.hpp>
+#include <mbgl/style/style_layer.hpp>
+#include <mbgl/util/worker.hpp>
+#include <mbgl/util/work_request.hpp>
+#include <mbgl/style/style.hpp>
+#include <mbgl/storage/file_source.hpp>
+
+namespace mbgl {
+
+VectorTileData::VectorTileData(const TileID& id_,
+ std::unique_ptr<GeometryTileMonitor> monitor_,
+ std::string sourceID,
+ Style& style_,
+ const MapMode mode_,
+ const std::function<void(std::exception_ptr)>& callback)
+ : TileData(id_),
+ style(style_),
+ worker(style_.workers),
+ tileWorker(id_,
+ sourceID,
+ *style_.spriteStore,
+ *style_.glyphAtlas,
+ *style_.glyphStore,
+ state,
+ mode_),
+ monitor(std::move(monitor_))
+{
+ state = State::loading;
+ tileRequest = monitor->monitorTile([callback, this](std::exception_ptr err,
+ std::unique_ptr<GeometryTile> tile,
+ optional<SystemTimePoint> modified_,
+ optional<SystemTimePoint> expires_) {
+ if (err) {
+ callback(err);
+ return;
+ }
+
+ modified = modified_;
+ expires = expires_;
+
+ if (!tile) {
+ // This is a 404 response. We're treating these as empty tiles.
+ workRequest.reset();
+ state = State::parsed;
+ buckets.clear();
+ callback(err);
+ return;
+ }
+
+ if (state == State::loading) {
+ state = State::loaded;
+ } else if (isReady()) {
+ state = State::partial;
+ }
+
+ // Kick off a fresh parse of this tile. This happens when the tile is new, or
+ // when tile data changed. Replacing the workdRequest will cancel a pending work
+ // request in case there is one.
+ workRequest.reset();
+ workRequest = worker.parseGeometryTile(tileWorker, style.getLayers(), std::move(tile), targetConfig, [callback, this, config = targetConfig] (TileParseResult result) {
+ workRequest.reset();
+ if (state == State::obsolete) {
+ return;
+ }
+
+ std::exception_ptr error;
+ if (result.is<TileParseResultBuckets>()) {
+ auto& resultBuckets = result.get<TileParseResultBuckets>();
+ state = resultBuckets.state;
+
+ // Persist the configuration we just placed so that we can later check whether we need to
+ // place again in case the configuration has changed.
+ placedConfig = config;
+
+ // Move over all buckets we received in this parse request, potentially overwriting
+ // existing buckets in case we got a refresh parse.
+ buckets = std::move(resultBuckets.buckets);
+
+ } else {
+ error = result.get<std::exception_ptr>();
+ state = State::obsolete;
+ }
+
+ callback(error);
+ });
+ });
+}
+
+VectorTileData::~VectorTileData() {
+ cancel();
+}
+
+bool VectorTileData::parsePending(std::function<void(std::exception_ptr)> callback) {
+ if (workRequest) {
+ // There's already parsing or placement going on.
+ return false;
+ }
+
+ workRequest.reset();
+ workRequest = worker.parsePendingGeometryTileLayers(tileWorker, targetConfig, [this, callback, config = targetConfig] (TileParseResult result) {
+ workRequest.reset();
+ if (state == State::obsolete) {
+ return;
+ }
+
+ std::exception_ptr error;
+ if (result.is<TileParseResultBuckets>()) {
+ auto& resultBuckets = result.get<TileParseResultBuckets>();
+ state = resultBuckets.state;
+
+ // Move over all buckets we received in this parse request, potentially overwriting
+ // existing buckets in case we got a refresh parse.
+ for (auto& bucket : resultBuckets.buckets) {
+ buckets[bucket.first] = std::move(bucket.second);
+ }
+
+ // Persist the configuration we just placed so that we can later check whether we need to
+ // place again in case the configuration has changed.
+ placedConfig = config;
+
+ } else {
+ error = result.get<std::exception_ptr>();
+ state = State::obsolete;
+ }
+
+ callback(error);
+ });
+
+ return true;
+}
+
+Bucket* VectorTileData::getBucket(const StyleLayer& layer) {
+ const auto it = buckets.find(layer.bucketName());
+ if (it == buckets.end()) {
+ return nullptr;
+ }
+
+ assert(it->second);
+ return it->second.get();
+}
+
+void VectorTileData::redoPlacement(const PlacementConfig newConfig, const std::function<void()>& callback) {
+ if (newConfig != placedConfig) {
+ targetConfig = newConfig;
+
+ redoPlacement(callback);
+ }
+}
+
+void VectorTileData::redoPlacement(const std::function<void()>& callback) {
+ // Don't start a new placement request when the current one hasn't completed yet, or when
+ // we are parsing buckets.
+ if (workRequest) return;
+
+ workRequest = worker.redoPlacement(tileWorker, buckets, targetConfig, [this, callback, config = targetConfig] {
+ workRequest.reset();
+
+ // Persist the configuration we just placed so that we can later check whether we need to
+ // place again in case the configuration has changed.
+ placedConfig = config;
+
+ for (auto& bucket : buckets) {
+ bucket.second->swapRenderData();
+ }
+
+ // The target configuration could have changed since we started placement. In this case,
+ // we're starting another placement run.
+ if (placedConfig != targetConfig) {
+ redoPlacement(callback);
+ } else {
+ callback();
+ }
+ });
+}
+
+void VectorTileData::cancel() {
+ state = State::obsolete;
+ tileRequest.reset();
+ workRequest.reset();
+}
+
+} // namespace mbgl