#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace mbgl { namespace style { static Observer nullObserver; Style::Style(Scheduler& scheduler_, FileSource& fileSource_, float pixelRatio) : scheduler(scheduler_), fileSource(fileSource_), spriteLoader(std::make_unique(pixelRatio)), light(std::make_unique()), observer(&nullObserver) { spriteLoader->setObserver(this); light->setObserver(this); } Style::~Style() { for (const auto& layer : layers) { if (auto* customLayer = layer->as()) { customLayer->impl().deinitialize(); } } } void Style::setTransitionOptions(const TransitionOptions& options) { transitionOptions = options; } TransitionOptions Style::getTransitionOptions() const { return transitionOptions; } void Style::setJSON(const std::string& json) { sources.clear(); layers.clear(); images.clear(); transitionOptions = {}; transitionOptions.duration = util::DEFAULT_TRANSITION_DURATION; Parser parser; auto error = parser.parse(json); if (error) { std::string message = "Failed to parse style: " + util::toString(error); Log::Error(Event::ParseStyle, message.c_str()); observer->onStyleError(std::make_exception_ptr(util::StyleParseException(message))); observer->onResourceError(error); return; } for (auto& source : parser.sources) { addSource(std::move(source)); } for (auto& layer : parser.layers) { addLayer(std::move(layer)); } name = parser.name; defaultLatLng = parser.latLng; defaultZoom = parser.zoom; defaultBearing = parser.bearing; defaultPitch = parser.pitch; setLight(std::make_unique(parser.light)); spriteLoader->load(parser.spriteURL, scheduler, fileSource); glyphURL = parser.glyphURL; loaded = true; observer->onStyleLoaded(); } void Style::addSource(std::unique_ptr source) { if (sources.get(source->getID())) { std::string msg = "Source " + source->getID() + " already exists"; throw std::runtime_error(msg.c_str()); } source->setObserver(this); source->loadDescription(fileSource); sources.add(std::move(source)); } struct SourceIdUsageEvaluator { const std::string& sourceId; bool operator()(BackgroundLayer&) { return false; } bool operator()(CustomLayer&) { return false; } template bool operator()(LayerType& layer) { return layer.getSourceID() == sourceId; } }; std::unique_ptr Style::removeSource(const std::string& id) { // Check if source is in use SourceIdUsageEvaluator sourceIdEvaluator {id}; auto layerIt = std::find_if(layers.begin(), layers.end(), [&](const auto& layer) { return layer->accept(sourceIdEvaluator); }); if (layerIt != layers.end()) { Log::Warning(Event::General, "Source '%s' is in use, cannot remove", id.c_str()); return nullptr; } std::unique_ptr source = sources.remove(id); if (source) { source->setObserver(nullptr); } return source; } std::vector Style::getLayers() { return layers.getWrappers(); } Layer* Style::getLayer(const std::string& id) const { return layers.get(id); } Layer* Style::addLayer(std::unique_ptr layer, optional before) { // TODO: verify source if (layers.get(layer->getID())) { throw std::runtime_error(std::string{"Layer "} + layer->getID() + " already exists"); } if (auto* customLayer = layer->as()) { customLayer->impl().initialize(); } layer->setObserver(this); return layers.add(std::move(layer), before); } std::unique_ptr Style::removeLayer(const std::string& id) { std::unique_ptr layer = layers.remove(id); if (layer) { layer->setObserver(nullptr); if (auto* customLayer = layer->as()) { customLayer->impl().deinitialize(); } } return layer; } void Style::setLight(std::unique_ptr light_) { light = std::move(light_); light->setObserver(this); onLightChanged(*light); } Light* Style::getLight() const { return light.get(); } std::string Style::getName() const { return name; } LatLng Style::getDefaultLatLng() const { return defaultLatLng; } double Style::getDefaultZoom() const { return defaultZoom; } double Style::getDefaultBearing() const { return defaultBearing; } double Style::getDefaultPitch() const { return defaultPitch; } std::vector Style::getSources() { return sources.getWrappers(); } Source* Style::getSource(const std::string& id) const { return sources.get(id); } bool Style::isLoaded() const { if (!loaded) { return false; } if (!spriteLoaded) { return false; } for (const auto& source: sources) { if (!source->loaded) { return false; } } return true; } void Style::addImage(std::unique_ptr image) { images.remove(image->getID()); // We permit using addImage to update. images.add(std::move(image)); } void Style::removeImage(const std::string& id) { images.remove(id); } const style::Image* Style::getImage(const std::string& id) const { return images.get(id); } void Style::setObserver(style::Observer* observer_) { observer = observer_; } void Style::onSourceLoaded(Source& source) { sources.update(source); observer->onSourceLoaded(source); observer->onUpdate(Update::Repaint); } void Style::onSourceChanged(Source& source) { sources.update(source); observer->onSourceChanged(source); } void Style::onSourceError(Source& source, std::exception_ptr error) { lastError = error; Log::Error(Event::Style, "Failed to load source %s: %s", source.getID().c_str(), util::toString(error).c_str()); observer->onSourceError(source, error); observer->onResourceError(error); } void Style::onSourceDescriptionChanged(Source& source) { sources.update(source); observer->onSourceDescriptionChanged(source); if (!source.loaded) { source.loadDescription(fileSource); } } void Style::onSpriteLoaded(std::vector>&& images_) { for (auto& image : images_) { addImage(std::move(image)); } spriteLoaded = true; observer->onUpdate(Update::Repaint); // For *-pattern properties. } void Style::onSpriteError(std::exception_ptr error) { lastError = error; Log::Error(Event::Style, "Failed to load sprite: %s", util::toString(error).c_str()); observer->onResourceError(error); } void Style::onLayerChanged(Layer& layer) { layers.update(layer); observer->onUpdate(Update::Repaint); } void Style::onLightChanged(const Light&) { observer->onUpdate(Update::Repaint); } void Style::dumpDebugLogs() const { for (const auto& source : sources) { source->dumpDebugLogs(); } } const std::string& Style::getGlyphURL() const { return glyphURL; } Immutable>> Style::getImageImpls() const { return images.getImpls(); } Immutable>> Style::getSourceImpls() const { return sources.getImpls(); } Immutable>> Style::getLayerImpls() const { return layers.getImpls(); } } // namespace style } // namespace mbgl