#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace mbgl; TileWorker::TileWorker(const OverscaledTileID& id_, std::string sourceID_, SpriteStore& spriteStore_, GlyphAtlas& glyphAtlas_, GlyphStore& glyphStore_, const std::atomic& obsolete_, const MapMode mode_) : id(id_), sourceID(std::move(sourceID_)), spriteStore(spriteStore_), glyphAtlas(glyphAtlas_), glyphStore(glyphStore_), obsolete(obsolete_), mode(mode_) { } TileWorker::~TileWorker() { glyphAtlas.removeGlyphs(reinterpret_cast(this)); } TileParseResult TileWorker::parseAllLayers(std::vector> layers_, std::unique_ptr geometryTile_, PlacementConfig config) { // We're doing a fresh parse of the tile, because the underlying data has changed. pending.clear(); placementPending.clear(); partialParse = false; featureIndex = std::make_unique(); geometryTile = std::move(geometryTile_); // Store the layers for use in redoPlacement. layers = std::move(layers_); // We're storing a set of bucket names we've parsed to avoid parsing a bucket twice that is // referenced from more than one layer std::set parsed; for (auto i = layers.rbegin(); i != layers.rend(); i++) { const Layer* layer = i->get(); if (parsed.find(layer->baseImpl->bucketName()) == parsed.end()) { parsed.emplace(layer->baseImpl->bucketName()); parseLayer(layer); } featureIndex->addBucketLayerName(layer->baseImpl->bucketName(), layer->baseImpl->id); } return prepareResult(config); } TileParseResult TileWorker::parsePendingLayers(const PlacementConfig config) { // Try parsing the remaining layers that we couldn't parse in the first step due to missing // dependencies. for (auto it = pending.begin(); it != pending.end();) { const SymbolLayer& symbolLayer = *it->first; SymbolBucket* symbolBucket = dynamic_cast(it->second.get()); if (!symbolBucket->needsDependencies(glyphStore, spriteStore)) { symbolBucket->addFeatures(reinterpret_cast(this), *symbolLayer.impl->spriteAtlas, glyphAtlas, glyphStore); placementPending.emplace(symbolLayer.impl->bucketName(), std::move(it->second)); pending.erase(it++); continue; } // Advance the iterator here; we're skipping this when erasing an element from this list. ++it; } return prepareResult(config); } TileParseResult TileWorker::prepareResult(const PlacementConfig& config) { result.complete = pending.empty(); if (result.complete) { featureIndex->setCollisionTile(placeLayers(config)); result.featureIndex = std::move(featureIndex); result.geometryTile = std::move(geometryTile); } return std::move(result); } std::unique_ptr TileWorker::placeLayers(const PlacementConfig config) { auto collisionTile = redoPlacement(&placementPending, config); for (auto &p : placementPending) { p.second->swapRenderData(); insertBucket(p.first, std::move(p.second)); } placementPending.clear(); return collisionTile; } std::unique_ptr TileWorker::redoPlacement( const std::unordered_map>* buckets, PlacementConfig config) { auto collisionTile = std::make_unique(config); for (auto i = layers.rbegin(); i != layers.rend(); i++) { const auto it = buckets->find((*i)->baseImpl->id); if (it != buckets->end()) { it->second->placeFeatures(*collisionTile); } } return collisionTile; } void TileWorker::parseLayer(const Layer* layer) { // Cancel early when parsing. if (obsolete) return; // Background and custom layers are special cases. if (layer->is() || layer->is()) return; // Skip this bucket if we are to not render this if ((layer->baseImpl->source != sourceID) || (id.overscaledZ < std::floor(layer->baseImpl->minZoom)) || (id.overscaledZ >= std::ceil(layer->baseImpl->maxZoom)) || (layer->baseImpl->visibility == VisibilityType::None)) { return; } auto geometryLayer = geometryTile->getLayer(layer->baseImpl->sourceLayer); if (!geometryLayer) { // The layer specified in the bucket does not exist. Do nothing. if (debug::tileParseWarnings) { Log::Warning(Event::ParseTile, "layer '%s' does not exist in tile %s", layer->baseImpl->sourceLayer.c_str(), util::toString(id).c_str()); } return; } StyleBucketParameters parameters(id, *geometryLayer, obsolete, reinterpret_cast(this), partialParse, spriteStore, glyphAtlas, glyphStore, *featureIndex, mode); std::unique_ptr bucket = layer->baseImpl->createBucket(parameters); if (layer->is()) { if (partialParse) { // We cannot parse this bucket yet. Instead, we're saving it for later. pending.emplace_back(layer->as(), std::move(bucket)); } else { placementPending.emplace(layer->baseImpl->bucketName(), std::move(bucket)); } } else { insertBucket(layer->baseImpl->bucketName(), std::move(bucket)); } } void TileWorker::insertBucket(const std::string& name, std::unique_ptr bucket) { if (bucket->hasData()) { result.buckets.emplace(name, std::move(bucket)); } }