[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:
Minh Nguyễn
2016-08-13 11:30:15 -07:00
committed by Minh Nguyễn
parent 78af55f30a
commit f307652548
13 changed files with 103 additions and 6 deletions

View File

@@ -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);

View File

@@ -45,7 +45,8 @@ enum MapChange {
MapChangeWillStartRenderingMap,
MapChangeDidFinishRenderingMap,
MapChangeDidFinishRenderingMapFullyRendered,
MapChangeDidFinishLoadingStyle
MapChangeDidFinishLoadingStyle,
MapChangeSourceAttributionDidChange
};
struct Q_DECL_EXPORT CameraOptions {

View File

@@ -95,7 +95,6 @@ public:
NorthLeftwards,
};
QMapboxGL(QObject *parent = 0, const QMapboxGLSettings& = QMapboxGLSettings());
virtual ~QMapboxGL();

View File

@@ -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 {

View File

@@ -19,7 +19,8 @@ enum MapChange : uint8_t {
MapChangeWillStartRenderingMap = 11,
MapChangeDidFinishRenderingMap = 12,
MapChangeDidFinishRenderingMapFullyRendered = 13,
MapChangeDidFinishLoadingStyle = 14
MapChangeDidFinishLoadingStyle = 14,
MapChangeSourceAttributionDidChange = 15
};
} // namespace mbgl

View File

@@ -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());

View File

@@ -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&) {}

View File

@@ -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",

View File

@@ -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;

View File

@@ -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

View File

@@ -33,6 +33,8 @@ public:
const variant<std::string, Tileset>& getURLOrTileset() const {
return urlOrTileset;
}
std::string getAttribution() const;
protected:
Range<uint8_t> getZoomRange() final;

View File

@@ -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;

View File

@@ -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'>&copy; 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();
}