[core] Source-driven attribution
Implemented observer callbacks so the style knows when the source’s attribution changes and the map knows when the style’s attribution changes. Also implemented a getter for a tile source’s attribution. Fixes #2723.
This commit is contained in:
committed by
Minh Nguyễn
parent
78af55f30a
commit
f307652548
@@ -155,6 +155,7 @@ public:
|
||||
style::Source* getSource(const std::string& sourceID);
|
||||
void addSource(std::unique_ptr<style::Source>);
|
||||
void removeSource(const std::string& sourceID);
|
||||
std::vector<std::string> getAttributions() const;
|
||||
|
||||
// Layers
|
||||
style::Layer* getLayer(const std::string& layerID);
|
||||
|
||||
@@ -45,7 +45,8 @@ enum MapChange {
|
||||
MapChangeWillStartRenderingMap,
|
||||
MapChangeDidFinishRenderingMap,
|
||||
MapChangeDidFinishRenderingMapFullyRendered,
|
||||
MapChangeDidFinishLoadingStyle
|
||||
MapChangeDidFinishLoadingStyle,
|
||||
MapChangeSourceAttributionDidChange
|
||||
};
|
||||
|
||||
struct Q_DECL_EXPORT CameraOptions {
|
||||
|
||||
@@ -95,7 +95,6 @@ public:
|
||||
NorthLeftwards,
|
||||
};
|
||||
|
||||
|
||||
QMapboxGL(QObject *parent = 0, const QMapboxGLSettings& = QMapboxGLSettings());
|
||||
virtual ~QMapboxGL();
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ static_assert(mbgl::underlying_type(QMapbox::MapChangeWillStartRenderingMap) ==
|
||||
static_assert(mbgl::underlying_type(QMapbox::MapChangeDidFinishRenderingMap) == mbgl::underlying_type(mbgl::MapChangeDidFinishRenderingMap), "error");
|
||||
static_assert(mbgl::underlying_type(QMapbox::MapChangeDidFinishRenderingMapFullyRendered) == mbgl::underlying_type(mbgl::MapChangeDidFinishRenderingMapFullyRendered), "error");
|
||||
static_assert(mbgl::underlying_type(QMapbox::MapChangeDidFinishLoadingStyle) == mbgl::underlying_type(mbgl::MapChangeDidFinishLoadingStyle), "error");
|
||||
static_assert(mbgl::underlying_type(QMapbox::MapChangeSourceAttributionDidChange) == mbgl::underlying_type(mbgl::MapChangeSourceAttributionDidChange), "error");
|
||||
|
||||
namespace QMapbox {
|
||||
|
||||
|
||||
@@ -19,7 +19,8 @@ enum MapChange : uint8_t {
|
||||
MapChangeWillStartRenderingMap = 11,
|
||||
MapChangeDidFinishRenderingMap = 12,
|
||||
MapChangeDidFinishRenderingMapFullyRendered = 13,
|
||||
MapChangeDidFinishLoadingStyle = 14
|
||||
MapChangeDidFinishLoadingStyle = 14,
|
||||
MapChangeSourceAttributionDidChange = 15
|
||||
};
|
||||
|
||||
} // namespace mbgl
|
||||
|
||||
@@ -38,6 +38,7 @@ class Map::Impl : public style::Observer {
|
||||
public:
|
||||
Impl(View&, FileSource&, MapMode, GLContextMode, ConstrainMode, ViewportMode);
|
||||
|
||||
void onSourceAttributionChanged(style::Source&, const std::string&) override;
|
||||
void onUpdate(Update) override;
|
||||
void onStyleLoaded() override;
|
||||
void onStyleError() override;
|
||||
@@ -785,6 +786,10 @@ void Map::removeSource(const std::string& sourceID) {
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> Map::getAttributions() const {
|
||||
return impl->style ? impl->style->getAttributions() : std::vector<std::string>();
|
||||
}
|
||||
|
||||
style::Layer* Map::getLayer(const std::string& layerID) {
|
||||
if (impl->style) {
|
||||
impl->styleMutated = true;
|
||||
@@ -980,6 +985,10 @@ void Map::onLowMemory() {
|
||||
impl->view.invalidate();
|
||||
}
|
||||
|
||||
void Map::Impl::onSourceAttributionChanged(style::Source&, const std::string&) {
|
||||
view.notifyMapChange(MapChangeSourceAttributionDidChange);
|
||||
}
|
||||
|
||||
void Map::Impl::onUpdate(Update flags) {
|
||||
if (flags & Update::Dimensions) {
|
||||
transform.resize(view.getSize());
|
||||
|
||||
@@ -17,6 +17,7 @@ public:
|
||||
virtual ~SourceObserver() = default;
|
||||
|
||||
virtual void onSourceLoaded(Source&) {}
|
||||
virtual void onSourceAttributionChanged(Source&, const std::string&) {}
|
||||
virtual void onSourceError(Source&, std::exception_ptr) {}
|
||||
|
||||
virtual void onTileChanged(Source&, const OverscaledTileID&) {}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <mbgl/style/update_parameters.hpp>
|
||||
#include <mbgl/style/cascade_parameters.hpp>
|
||||
#include <mbgl/style/calculation_parameters.hpp>
|
||||
#include <mbgl/style/tile_source_impl.hpp>
|
||||
#include <mbgl/sprite/sprite_atlas.hpp>
|
||||
#include <mbgl/text/glyph_atlas.hpp>
|
||||
#include <mbgl/geometry/line_atlas.hpp>
|
||||
@@ -25,6 +26,7 @@
|
||||
#include <mbgl/renderer/render_tile.hpp>
|
||||
#include <mbgl/util/constants.hpp>
|
||||
#include <mbgl/util/string.hpp>
|
||||
#include <mbgl/util/tileset.hpp>
|
||||
#include <mbgl/platform/log.hpp>
|
||||
#include <mbgl/math/minmax.hpp>
|
||||
|
||||
@@ -293,6 +295,28 @@ Source* Style::getSource(const std::string& id) const {
|
||||
return it != sources.end() ? it->get() : nullptr;
|
||||
}
|
||||
|
||||
std::vector<std::string> Style::getAttributions() const {
|
||||
std::vector<std::string> result;
|
||||
for (const auto& source : sources) {
|
||||
switch (source->baseImpl->type) {
|
||||
case SourceType::Vector:
|
||||
case SourceType::Raster: {
|
||||
style::TileSourceImpl* tileSource = static_cast<style::TileSourceImpl*>(source->baseImpl.get());
|
||||
auto attribution = tileSource->getAttribution();
|
||||
if (!attribution.empty()) {
|
||||
result.push_back(std::move(attribution));
|
||||
}
|
||||
}
|
||||
|
||||
case SourceType::GeoJSON:
|
||||
case SourceType::Video:
|
||||
case SourceType::Annotations:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Style::hasTransitions() const {
|
||||
return hasPendingTransitions;
|
||||
}
|
||||
@@ -465,6 +489,10 @@ void Style::onSourceLoaded(Source& source) {
|
||||
observer->onUpdate(Update::Repaint);
|
||||
}
|
||||
|
||||
void Style::onSourceAttributionChanged(Source& source, const std::string& attribution) {
|
||||
observer->onSourceAttributionChanged(source, attribution);
|
||||
}
|
||||
|
||||
void Style::onSourceError(Source& source, std::exception_ptr error) {
|
||||
lastError = error;
|
||||
Log::Error(Event::Style, "Failed to load source %s: %s",
|
||||
|
||||
@@ -67,6 +67,7 @@ public:
|
||||
Source* getSource(const std::string& id) const;
|
||||
void addSource(std::unique_ptr<Source>);
|
||||
void removeSource(const std::string& sourceID);
|
||||
std::vector<std::string> getAttributions() const;
|
||||
|
||||
std::vector<const Layer*> getLayers() const;
|
||||
Layer* getLayer(const std::string& id) const;
|
||||
@@ -132,6 +133,7 @@ private:
|
||||
|
||||
// SourceObserver implementation.
|
||||
void onSourceLoaded(Source&) override;
|
||||
void onSourceAttributionChanged(Source&, const std::string&) override;
|
||||
void onSourceError(Source&, std::exception_ptr) override;
|
||||
void onTileChanged(Source&, const OverscaledTileID&) override;
|
||||
void onTileError(Source&, const OverscaledTileID&, std::exception_ptr) override;
|
||||
|
||||
@@ -82,6 +82,7 @@ void TileSourceImpl::loadDescription(FileSource& fileSource) {
|
||||
}
|
||||
|
||||
// Check whether previous information specifies different tile
|
||||
bool attributionChanged = false;
|
||||
if (tileset.tiles != newTileset.tiles) {
|
||||
// Tile URLs changed: force tiles to be reloaded.
|
||||
invalidateTiles();
|
||||
@@ -95,8 +96,8 @@ void TileSourceImpl::loadDescription(FileSource& fileSource) {
|
||||
// This is done automatically when we trigger the onSourceLoaded observer below.
|
||||
|
||||
// Attribution changed: We need to notify the embedding application that this
|
||||
// changed. See https://github.com/mapbox/mapbox-gl-native/issues/2723
|
||||
// This is not yet implemented.
|
||||
// changed.
|
||||
attributionChanged = true;
|
||||
|
||||
// Center/bounds changed: We're not using these values currently
|
||||
}
|
||||
@@ -105,6 +106,9 @@ void TileSourceImpl::loadDescription(FileSource& fileSource) {
|
||||
loaded = true;
|
||||
|
||||
observer->onSourceLoaded(base);
|
||||
if (attributionChanged) {
|
||||
observer->onSourceAttributionChanged(base, newTileset.attribution);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -114,5 +118,9 @@ Range<uint8_t> TileSourceImpl::getZoomRange() {
|
||||
return tileset.zoomRange;
|
||||
}
|
||||
|
||||
std::string TileSourceImpl::getAttribution() const {
|
||||
return loaded ? tileset.attribution : "";
|
||||
}
|
||||
|
||||
} // namespace style
|
||||
} // namespace mbgl
|
||||
|
||||
@@ -33,6 +33,8 @@ public:
|
||||
const variant<std::string, Tileset>& getURLOrTileset() const {
|
||||
return urlOrTileset;
|
||||
}
|
||||
|
||||
std::string getAttribution() const;
|
||||
|
||||
protected:
|
||||
Range<uint8_t> getZoomRange() final;
|
||||
|
||||
@@ -6,7 +6,7 @@ using namespace mbgl;
|
||||
using namespace mbgl::style;
|
||||
|
||||
/**
|
||||
* An implementation of style::Observer that forwards all methods to dynamically-settable lambas.
|
||||
* An implementation of style::Observer that forwards all methods to dynamically-settable lambdas.
|
||||
*/
|
||||
class StubStyleObserver : public style::Observer {
|
||||
public:
|
||||
@@ -30,6 +30,10 @@ public:
|
||||
if (sourceLoaded) sourceLoaded(source);
|
||||
}
|
||||
|
||||
void onSourceAttributionChanged(Source& source, const std::string& attribution) override {
|
||||
if (sourceAttributionChanged) sourceAttributionChanged(source, attribution);
|
||||
}
|
||||
|
||||
void onSourceError(Source& source, std::exception_ptr error) override {
|
||||
if (sourceError) sourceError(source, error);
|
||||
}
|
||||
@@ -52,6 +56,7 @@ public:
|
||||
std::function<void ()> spriteLoaded;
|
||||
std::function<void (std::exception_ptr)> spriteError;
|
||||
std::function<void (Source&)> sourceLoaded;
|
||||
std::function<void (Source&, std::string)> sourceAttributionChanged;
|
||||
std::function<void (Source&, std::exception_ptr)> sourceError;
|
||||
std::function<void (Source&, const OverscaledTileID&)> tileChanged;
|
||||
std::function<void (Source&, const OverscaledTileID&, std::exception_ptr)> tileError;
|
||||
|
||||
@@ -342,3 +342,42 @@ TEST(Source, VectorTileCancel) {
|
||||
|
||||
test.run();
|
||||
}
|
||||
|
||||
TEST(Source, RasterTileAttribution) {
|
||||
SourceTest test;
|
||||
|
||||
std::string mapboxOSM = ("<a href='https://www.mapbox.com/about/maps/' target='_blank'>© Mapbox</a> "
|
||||
"<a href='http://www.openstreetmap.org/about/' target='_blank'>©️ OpenStreetMap</a>");
|
||||
|
||||
test.fileSource.tileResponse = [&] (const Resource&) {
|
||||
Response response;
|
||||
response.noContent = true;
|
||||
return response;
|
||||
};
|
||||
|
||||
test.fileSource.sourceResponse = [&] (const Resource& resource) {
|
||||
EXPECT_EQ("url", resource.url);
|
||||
Response response;
|
||||
response.data = std::make_unique<std::string>(R"TILEJSON({ "tilejson": "2.1.0", "attribution": ")TILEJSON" +
|
||||
mapboxOSM +
|
||||
R"TILEJSON(", "tiles": [ "tiles" ] })TILEJSON");
|
||||
return response;
|
||||
};
|
||||
|
||||
test.observer.sourceAttributionChanged = [&] (Source&, std::string attribution) {
|
||||
EXPECT_EQ(mapboxOSM, attribution);
|
||||
EXPECT_FALSE(mapboxOSM.find("©️ OpenStreetMap") == std::string::npos);
|
||||
test.end();
|
||||
};
|
||||
|
||||
test.observer.tileError = [&] (Source&, const OverscaledTileID&, std::exception_ptr) {
|
||||
FAIL() << "Should never be called";
|
||||
};
|
||||
|
||||
RasterSource source("source", "url", 512);
|
||||
source.baseImpl->setObserver(&test.observer);
|
||||
source.baseImpl->loadDescription(test.fileSource);
|
||||
source.baseImpl->updateTiles(test.updateParameters);
|
||||
|
||||
test.run();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user