#include #include #include #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::Impl::Impl(FileSource& fileSource_, float pixelRatio) : fileSource(fileSource_), spriteLoader(std::make_unique(pixelRatio)), light(std::make_unique()), observer(&nullObserver) { spriteLoader->setObserver(this); light->setObserver(this); } Style::Impl::~Impl() = default; void Style::Impl::loadJSON(const std::string& json_) { lastError = nullptr; observer->onStyleLoading(); url.clear(); parse(json_); } void Style::Impl::loadURL(const std::string& url_) { lastError = nullptr; observer->onStyleLoading(); loaded = false; url = url_; styleRequest = fileSource.request(Resource::style(url), [this](Response res) { // Don't allow a loaded, mutated style to be overwritten with a new version. if (mutated && loaded) { return; } if (res.error) { const std::string message = "loading style failed: " + res.error->message; Log::Error(Event::Setup, message.c_str()); observer->onStyleError(std::make_exception_ptr(util::StyleLoadException(message))); observer->onResourceError(std::make_exception_ptr(std::runtime_error(res.error->message))); } else if (res.notModified || res.noContent) { return; } else { parse(*res.data); } }); } void Style::Impl::parse(const std::string& json_) { Parser parser; if (auto error = parser.parse(json_)) { 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; } mutated = false; loaded = false; json = json_; sources.clear(); layers.clear(); images.clear(); transitionOptions = parser.transition; for (auto& source : parser.sources) { addSource(std::move(source)); } for (auto& layer : parser.layers) { addLayer(std::move(layer)); } name = parser.name; defaultCamera.center = parser.latLng; defaultCamera.zoom = parser.zoom; defaultCamera.bearing = parser.bearing; defaultCamera.pitch = parser.pitch; setLight(std::make_unique(parser.light)); spriteLoaded = false; spriteLoader->load(parser.spriteURL, fileSource); glyphURL = parser.glyphURL; loaded = true; observer->onStyleLoaded(); } std::string Style::Impl::getJSON() const { return json; } std::string Style::Impl::getURL() const { return url; } void Style::Impl::setTransitionOptions(const TransitionOptions& options) { transitionOptions = options; } TransitionOptions Style::Impl::getTransitionOptions() const { return transitionOptions; } void Style::Impl::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); auto item = sources.add(std::move(source)); item->loadDescription(fileSource); } std::unique_ptr Style::Impl::removeSource(const std::string& id) { // Check if source is in use for (const auto& layer: layers) { if (layer->getSourceID() == id) { 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::Impl::getLayers() { return layers.getWrappers(); } std::vector Style::Impl::getLayers() const { auto wrappers = layers.getWrappers(); return std::vector(wrappers.begin(), wrappers.end()); } Layer* Style::Impl::getLayer(const std::string& id) const { return layers.get(id); } Layer* Style::Impl::addLayer(std::unique_ptr layer, optional before) { // TODO: verify source if (Source* source = sources.get(layer->getSourceID())) { if (!source->supportsLayerType(layer->baseImpl->getTypeInfo())) { std::ostringstream message; message << "Layer '" << layer->getID() << "' is not compatible with source '" << layer->getSourceID() << "'"; throw std::runtime_error(message.str()); } } if (layers.get(layer->getID())) { throw std::runtime_error(std::string{"Layer "} + layer->getID() + " already exists"); } layer->setObserver(this); Layer* result = layers.add(std::move(layer), before); observer->onUpdate(); return result; } std::unique_ptr Style::Impl::removeLayer(const std::string& id) { std::unique_ptr layer = layers.remove(id); if (layer) { layer->setObserver(nullptr); observer->onUpdate(); } return layer; } void Style::Impl::setLight(std::unique_ptr light_) { light = std::move(light_); light->setObserver(this); onLightChanged(*light); } Light* Style::Impl::getLight() const { return light.get(); } std::string Style::Impl::getName() const { return name; } CameraOptions Style::Impl::getDefaultCamera() const { return defaultCamera; } std::vector Style::Impl::getSources() { return sources.getWrappers(); } std::vector Style::Impl::getSources() const { auto wrappers = sources.getWrappers(); return std::vector(wrappers.begin(), wrappers.end()); } Source* Style::Impl::getSource(const std::string& id) const { return sources.get(id); } bool Style::Impl::isLoaded() const { if (!loaded) { return false; } if (!spriteLoaded) { return false; } for (const auto& source: sources) { if (!source->loaded) { return false; } } return true; } void Style::Impl::addImage(std::unique_ptr image) { images.remove(image->getID()); // We permit using addImage to update. images.add(std::move(image)); observer->onUpdate(); } void Style::Impl::removeImage(const std::string& id) { images.remove(id); } const style::Image* Style::Impl::getImage(const std::string& id) const { return images.get(id); } void Style::Impl::setObserver(style::Observer* observer_) { observer = observer_; } void Style::Impl::onSourceLoaded(Source& source) { sources.update(source); observer->onSourceLoaded(source); observer->onUpdate(); } void Style::Impl::onSourceChanged(Source& source) { sources.update(source); observer->onSourceChanged(source); observer->onUpdate(); } void Style::Impl::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::Impl::onSourceDescriptionChanged(Source& source) { sources.update(source); observer->onSourceDescriptionChanged(source); if (!source.loaded) { source.loadDescription(fileSource); } } void Style::Impl::onSpriteLoaded(std::vector>&& images_) { for (auto& image : images_) { addImage(std::move(image)); } spriteLoaded = true; observer->onUpdate(); // For *-pattern properties. } void Style::Impl::onSpriteError(std::exception_ptr error) { lastError = error; Log::Error(Event::Style, "Failed to load sprite: %s", util::toString(error).c_str()); observer->onResourceError(error); // Unblock rendering tiles (even though sprite request has failed). spriteLoaded = true; observer->onUpdate(); } void Style::Impl::onLayerChanged(Layer& layer) { layers.update(layer); observer->onUpdate(); } void Style::Impl::onLightChanged(const Light&) { observer->onUpdate(); } void Style::Impl::dumpDebugLogs() const { Log::Info(Event::General, "styleURL: %s", url.c_str()); for (const auto& source : sources) { source->dumpDebugLogs(); } } const std::string& Style::Impl::getGlyphURL() const { return glyphURL; } Immutable>> Style::Impl::getImageImpls() const { return images.getImpls(); } Immutable>> Style::Impl::getSourceImpls() const { auto impls = sources.getImpls(); mutate(impls, [&] (auto& impls_) { std::sort(impls_.begin(), impls_.end(), [](const auto& a, const auto& b) { return a->id < b->id; }); }); return impls; } Immutable>> Style::Impl::getLayerImpls() const { return layers.getImpls(); } } // namespace style } // namespace mbgl