Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

[core] annotation manager thread safety #9208

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions cmake/core-files.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ set(MBGL_CORE_FILES
src/mbgl/annotation/annotation_manager.hpp
src/mbgl/annotation/annotation_source.cpp
src/mbgl/annotation/annotation_source.hpp
src/mbgl/annotation/annotation_source_impl.cpp
src/mbgl/annotation/annotation_source_impl.hpp
src/mbgl/annotation/annotation_tile.cpp
src/mbgl/annotation/annotation_tile.hpp
src/mbgl/annotation/fill_annotation_impl.cpp
Expand All @@ -30,10 +32,12 @@ set(MBGL_CORE_FILES
src/mbgl/annotation/line_annotation_impl.hpp
src/mbgl/annotation/render_annotation_source.cpp
src/mbgl/annotation/render_annotation_source.hpp
src/mbgl/annotation/shape_annotation_feature.cpp
src/mbgl/annotation/shape_annotation_feature.hpp
src/mbgl/annotation/shape_annotation_impl.cpp
src/mbgl/annotation/shape_annotation_impl.hpp
src/mbgl/annotation/symbol_annotation_impl.cpp
src/mbgl/annotation/symbol_annotation_impl.hpp
src/mbgl/annotation/symbol_annotation_feature.cpp
src/mbgl/annotation/symbol_annotation_feature.hpp

# csscolorparser
src/csscolorparser/csscolorparser.cpp
Expand Down
279 changes: 134 additions & 145 deletions src/mbgl/annotation/annotation_manager.cpp
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
#include <mbgl/annotation/annotation_manager.hpp>
#include <mbgl/annotation/annotation_source.hpp>
#include <mbgl/annotation/annotation_tile.hpp>
#include <mbgl/annotation/symbol_annotation_impl.hpp>
#include <mbgl/annotation/annotation_source_impl.hpp>
#include <mbgl/annotation/line_annotation_impl.hpp>
#include <mbgl/annotation/fill_annotation_impl.hpp>

#include <mbgl/style/style.hpp>
#include <mbgl/style/layers/symbol_layer.hpp>
#include <mbgl/style/layers/symbol_layer_impl.hpp>
#include <mbgl/storage/file_source.hpp>

#include <boost/function_output_iterator.hpp>

namespace mbgl {

Expand All @@ -18,188 +15,131 @@ using namespace style;
const std::string AnnotationManager::SourceID = "com.mapbox.annotations";
const std::string AnnotationManager::PointLayerID = "com.mapbox.annotations.points";

AnnotationManager::AnnotationManager() = default;
AnnotationManager::AnnotationManager()
: ownedSource(std::make_unique<AnnotationSource>()), source(ownedSource.get()) {
};

AnnotationManager::~AnnotationManager() = default;

AnnotationID AnnotationManager::addAnnotation(const Annotation& annotation, const uint8_t maxZoom) {
AnnotationID id = nextID++;
Annotation::visit(annotation, [&] (const auto& annotation_) {
Annotation::visit(annotation, [&](const auto& annotation_) {
this->add(id, annotation_, maxZoom);
});
return id;
}

Update AnnotationManager::updateAnnotation(const AnnotationID& id, const Annotation& annotation, const uint8_t maxZoom) {
return Annotation::visit(annotation, [&] (const auto& annotation_) {
void AnnotationManager::updateAnnotation(const AnnotationID& id, const Annotation& annotation,
const uint8_t maxZoom) {
return Annotation::visit(annotation, [&](const auto& annotation_) {
return this->update(id, annotation_, maxZoom);
});
}

void AnnotationManager::removeAnnotation(const AnnotationID& id) {
if (symbolAnnotations.find(id) != symbolAnnotations.end()) {
symbolTree.remove(symbolAnnotations.at(id));
symbolAnnotations.erase(id);
} else if (shapeAnnotations.find(id) != shapeAnnotations.end()) {
obsoleteShapeAnnotationLayers.insert(shapeAnnotations.at(id)->layerID);
shapeAnnotations.erase(id);
} else {
assert(false); // Should never happen
}
}
// Remove from source
sourceImpl = source->removeAnnotation(id);

void AnnotationManager::add(const AnnotationID& id, const SymbolAnnotation& annotation, const uint8_t) {
auto impl = std::make_shared<SymbolAnnotationImpl>(id, annotation);
symbolTree.insert(impl);
symbolAnnotations.emplace(id, impl);
// Remove from shapes
auto it = shapeAnnotations.find(id);
if (it != shapeAnnotations.end()) {
auto removedLayer = it->second->layerID;
shapeAnnotations.erase(it);
if (style) {
style->removeLayer(removedLayer);
}
}
}

void AnnotationManager::add(const AnnotationID& id, const LineAnnotation& annotation, const uint8_t maxZoom) {
ShapeAnnotationImpl& impl = *shapeAnnotations.emplace(id,
std::make_unique<LineAnnotationImpl>(id, annotation, maxZoom)).first->second;
obsoleteShapeAnnotationLayers.erase(impl.layerID);
void AnnotationManager::add(const AnnotationID& id,
const SymbolAnnotation& annotation,
const uint8_t) {
sourceImpl = source->addAnnotation(id, annotation);
}

void AnnotationManager::add(const AnnotationID& id, const FillAnnotation& annotation, const uint8_t maxZoom) {
ShapeAnnotationImpl& impl = *shapeAnnotations.emplace(id,
std::make_unique<FillAnnotationImpl>(id, annotation, maxZoom)).first->second;
obsoleteShapeAnnotationLayers.erase(impl.layerID);
}
void AnnotationManager::add(const AnnotationID& id,
const LineAnnotation& annotation,
const uint8_t maxZoom) {
// Add to source
sourceImpl = source->addAnnotation(id, annotation.geometry, maxZoom);

Update AnnotationManager::update(const AnnotationID& id, const SymbolAnnotation& annotation, const uint8_t maxZoom) {
Update result = Update::Nothing;
// Add to collection
ShapeAnnotationImpl& impl = *shapeAnnotations
.emplace(id,
std::make_unique<LineAnnotationImpl>(id, annotation, maxZoom)).first->second;

auto it = symbolAnnotations.find(id);
if (it == symbolAnnotations.end()) {
assert(false); // Attempt to update a non-existent symbol annotation
return result;
if (style) {
impl.updateStyle(*style);
}
}

const SymbolAnnotation& existing = it->second->annotation;
void AnnotationManager::add(const AnnotationID& id, const FillAnnotation& annotation,
const uint8_t maxZoom) {
// Add to source
sourceImpl = source->addAnnotation(id, annotation.geometry, maxZoom);

if (existing.geometry != annotation.geometry) {
result |= Update::AnnotationData;
}
// Add to collection
ShapeAnnotationImpl& impl = *shapeAnnotations
.emplace(id,
std::make_unique<FillAnnotationImpl>(id, annotation, maxZoom)).first->second;

if (existing.icon != annotation.icon) {
result |= Update::AnnotationData | Update::AnnotationStyle;
if (style) {
impl.updateStyle(*style);
}

if (result != Update::Nothing) {
removeAndAdd(id, annotation, maxZoom);
}

return result;
}

Update AnnotationManager::update(const AnnotationID& id, const LineAnnotation& annotation, const uint8_t maxZoom) {
auto it = shapeAnnotations.find(id);
if (it == shapeAnnotations.end()) {
assert(false); // Attempt to update a non-existent shape annotation
return Update::Nothing;
}
removeAndAdd(id, annotation, maxZoom);
return Update::AnnotationData | Update::AnnotationStyle;
void AnnotationManager::update(const AnnotationID& id,
const SymbolAnnotation& annotation,
const uint8_t) {
sourceImpl = source->updateAnnotation(id, annotation);
}

Update AnnotationManager::update(const AnnotationID& id, const FillAnnotation& annotation, const uint8_t maxZoom) {
void AnnotationManager::update(const AnnotationID& id,
const LineAnnotation& annotation,
const uint8_t maxZoom) {
auto it = shapeAnnotations.find(id);
if (it == shapeAnnotations.end()) {
assert(false); // Attempt to update a non-existent shape annotation
return Update::Nothing;
}
removeAndAdd(id, annotation, maxZoom);
return Update::AnnotationData | Update::AnnotationStyle;
}

void AnnotationManager::removeAndAdd(const AnnotationID& id, const Annotation& annotation, const uint8_t maxZoom) {
removeAnnotation(id);
Annotation::visit(annotation, [&] (const auto& annotation_) {
this->add(id, annotation_, maxZoom);
});
}

std::unique_ptr<AnnotationTileData> AnnotationManager::getTileData(const CanonicalTileID& tileID) {
if (symbolAnnotations.empty() && shapeAnnotations.empty())
return nullptr;

auto tileData = std::make_unique<AnnotationTileData>();
// Update in collection
shapeAnnotations.erase(it);
ShapeAnnotationImpl& impl = *shapeAnnotations
.emplace(id,
std::make_unique<LineAnnotationImpl>(id, annotation, maxZoom)).first->second;

AnnotationTileLayer& pointLayer = tileData->layers.emplace(PointLayerID, PointLayerID).first->second;
// Update in source
sourceImpl = source->updateAnnotation(id, annotation.geometry, maxZoom);

LatLngBounds tileBounds(tileID);

symbolTree.query(boost::geometry::index::intersects(tileBounds),
boost::make_function_output_iterator([&](const auto& val){
val->updateLayer(tileID, pointLayer);
}));

for (const auto& shape : shapeAnnotations) {
shape.second->updateTileData(tileID, *tileData);
// Update layer
if (style) {
impl.updateStyle(*style);
}

return tileData;
}

void AnnotationManager::updateStyle(Style& style) {
// Create annotation source, point layer, and point bucket
if (!style.getSource(SourceID)) {
style.addSource(std::make_unique<AnnotationSource>());

std::unique_ptr<SymbolLayer> layer = std::make_unique<SymbolLayer>(PointLayerID, SourceID);

layer->setSourceLayer(PointLayerID);
layer->setIconImage({SourceID + ".{sprite}"});
layer->setIconAllowOverlap(true);
layer->setIconIgnorePlacement(true);

style.addLayer(std::move(layer));
}

for (const auto& shape : shapeAnnotations) {
shape.second->updateStyle(style);
}

for (const auto& image : images) {
// Call addImage even for images we may have previously added, because we must support
// addAnnotationImage being used to update an existing image. Creating a new image is
// relatively cheap, as it copies only the Immutable reference. (We can't keep track
// of which images need to be added because we don't know if the style is the same
// instance as in the last updateStyle call. If it's a new style, we need to add all
// images.)
style.addImage(std::make_unique<style::Image>(image.second));
void AnnotationManager::update(const AnnotationID& id,
const FillAnnotation& annotation,
const uint8_t maxZoom) {
auto it = shapeAnnotations.find(id);
if (it == shapeAnnotations.end()) {
assert(false); // Attempt to update a non-existent shape annotation
}

for (const auto& layer : obsoleteShapeAnnotationLayers) {
if (style.getLayer(layer)) {
style.removeLayer(layer);
}
}
// Update in collection
shapeAnnotations.erase(it);
ShapeAnnotationImpl& impl = *shapeAnnotations
.emplace(id,
std::make_unique<FillAnnotationImpl>(id, annotation, maxZoom)).first->second;

for (const auto& image : obsoleteImages) {
if (style.getImage(image)) {
style.removeImage(image);
}
}
// Update in source
sourceImpl = source->updateAnnotation(id, annotation.geometry, maxZoom);

obsoleteShapeAnnotationLayers.clear();
obsoleteImages.clear();
}

void AnnotationManager::updateData() {
for (auto& tile : tiles) {
tile->setData(getTileData(tile->id.canonical));
// Update layer
if (style) {
impl.updateStyle(*style);
}
}

void AnnotationManager::addTile(AnnotationTile& tile) {
tiles.insert(&tile);
tile.setData(getTileData(tile.id.canonical));
}

void AnnotationManager::removeTile(AnnotationTile& tile) {
tiles.erase(&tile);
}

// To ensure that annotation images do not collide with images from the style,
// we prefix input image IDs with "com.mapbox.annotations".
static std::string prefixedImageID(const std::string& id) {
Expand All @@ -209,21 +149,70 @@ static std::string prefixedImageID(const std::string& id) {
void AnnotationManager::addImage(std::unique_ptr<style::Image> image) {
const std::string id = prefixedImageID(image->getID());
images.erase(id);
images.emplace(id,
style::Image(id, image->getImage().clone(), image->getPixelRatio(), image->isSdf()));
obsoleteImages.erase(id);
auto it = images.emplace(
id,
style::Image(id, image->getImage().clone(), image->getPixelRatio(), image->isSdf())
);

if (style) {
style->addImage(std::make_unique<style::Image>(it.first->second));
}
}

void AnnotationManager::removeImage(const std::string& id_) {
const std::string id = prefixedImageID(id_);
images.erase(id);
obsoleteImages.insert(id);

if (style) {
style->removeImage(id);
}
}

double AnnotationManager::getTopOffsetPixelsForImage(const std::string& id_) {
const std::string id = prefixedImageID(id_);
auto it = images.find(id);
return it != images.end() ? -(it->second.getImage().size.height / it->second.getPixelRatio()) / 2 : 0;
return it != images.end() ?
-(it->second.getImage().size.height / it->second.getPixelRatio()) / 2 :
0;
}

void AnnotationManager::onStyleLoaded(style::Style& style_) {
style = &style_;

// Add the annotation source
if (ownedSource) {
style->addSource(std::move(ownedSource));
} else {
style->addSource(sourceImpl ?
std::make_unique<AnnotationSource>(*sourceImpl) :
std::make_unique<AnnotationSource>());
}

source = style->getSource(SourceID)->as<AnnotationSource>();

// Add the Symbol Layer
std::unique_ptr<SymbolLayer> layer = std::make_unique<SymbolLayer>(PointLayerID, SourceID);
layer->setSourceLayer(PointLayerID);
layer->setIconImage({SourceID + ".{sprite}"});
layer->setIconAllowOverlap(true);
layer->setIconIgnorePlacement(true);
style->addLayer(std::move(layer));

// Add all images
for (const auto& image : images) {
// Call addImage even for images we may have previously added, because we must support
// addAnnotationImage being used to update an existing image. Creating a new image is
// relatively cheap, as it copies only the Immutable reference. (We can't keep track
// of which images need to be added because we don't know if the style is the same
// instance as in the last updateStyle call. If it's a new style, we need to add all
// images.)
style->addImage(std::make_unique<style::Image>(image.second));
}

// Add all layers for shape annotations
for (auto& entry : shapeAnnotations) {
entry.second->updateStyle(*style);
}
}

} // namespace mbgl
Loading