summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/curl_request.cpp2
-rw-r--r--include/mbgl/map/source.hpp13
-rw-r--r--include/mbgl/map/sprite.hpp4
-rw-r--r--include/mbgl/map/tile_data.hpp3
-rw-r--r--include/mbgl/style/style_source.hpp33
-rw-r--r--include/mbgl/text/collision.hpp3
-rw-r--r--include/mbgl/text/types.hpp2
-rw-r--r--include/mbgl/util/mapbox.hpp17
-rw-r--r--include/mbgl/util/threadpool.hpp45
-rw-r--r--include/mbgl/util/url.hpp14
-rw-r--r--include/mbgl/util/utf.hpp7
-rw-r--r--include/mbgl/util/vec.hpp2
-rwxr-xr-xscripts/travis_script.sh3
-rwxr-xr-xsetup-libraries.sh8
-rw-r--r--src/map/map.cpp6
-rw-r--r--src/map/source.cpp59
-rw-r--r--src/map/sprite.cpp4
-rw-r--r--src/map/tile_data.cpp23
-rw-r--r--src/renderer/symbol_bucket.cpp4
-rw-r--r--src/style/style_parser.cpp22
-rw-r--r--src/style/style_source.cpp77
-rw-r--r--src/text/collision.cpp4
-rw-r--r--src/text/glyph_store.cpp6
-rw-r--r--src/text/rotation_range.cpp2
-rw-r--r--src/util/mapbox.cpp44
-rw-r--r--src/util/threadpool.cpp54
-rw-r--r--src/util/url.cpp29
-rw-r--r--styles/bright/style.json2
-rw-r--r--styles/outdoors/style.json2
-rw-r--r--test/headless.cpp2
30 files changed, 301 insertions, 195 deletions
diff --git a/common/curl_request.cpp b/common/curl_request.cpp
index 88b7712f66..416ed90cd1 100644
--- a/common/curl_request.cpp
+++ b/common/curl_request.cpp
@@ -315,7 +315,7 @@ void async_add_cb(uv_async_t * /*async*/) {
curl_easy_setopt(handle, CURLOPT_URL, (*req)->url.c_str());
curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, curl_write_cb);
curl_easy_setopt(handle, CURLOPT_WRITEDATA, &(*req)->res->body);
- curl_easy_setopt(handle, CURLOPT_ACCEPT_ENCODING, "deflate");
+ curl_easy_setopt(handle, CURLOPT_ACCEPT_ENCODING, "gzip, deflate");
curl_easy_setopt(handle, CURLOPT_SHARE, curl_share);
curl_multi_add_handle(curl_multi, handle);
}
diff --git a/include/mbgl/map/source.hpp b/include/mbgl/map/source.hpp
index a9ff29e80a..4bc4c86dd0 100644
--- a/include/mbgl/map/source.hpp
+++ b/include/mbgl/map/source.hpp
@@ -25,7 +25,9 @@ struct box;
class Source : public std::enable_shared_from_this<Source>, private util::noncopyable {
public:
- Source(SourceInfo info, const std::string &access_token = "");
+ Source(SourceInfo& info);
+
+ void load(Map &map);
bool update(Map &map);
void updateMatrices(const mat4 &projMatrix, const TransformState &transform);
@@ -39,11 +41,6 @@ public:
std::forward_list<Tile *> getLoadedTiles() const;
void updateClipIDs(const std::map<Tile::ID, ClipID> &mapping);
- static std::string normalizeSourceURL(const std::string &url, const std::string &access_token);
-
-public:
- const SourceInfo info;
-
private:
bool findLoadedChildren(const Tile::ID& id, int32_t maxCoveringZoom, std::forward_list<Tile::ID>& retain);
bool findLoadedParent(const Tile::ID& id, int32_t minCoveringZoom, std::forward_list<Tile::ID>& retain);
@@ -56,7 +53,9 @@ private:
double getZoom(const TransformState &state) const;
-private:
+ SourceInfo& info;
+ bool loaded = false;
+
// Stores the time when this source was most recently updated.
timestamp updated = 0;
diff --git a/include/mbgl/map/sprite.hpp b/include/mbgl/map/sprite.hpp
index 967f1d6614..7bc6665570 100644
--- a/include/mbgl/map/sprite.hpp
+++ b/include/mbgl/map/sprite.hpp
@@ -19,7 +19,7 @@ class FileSource;
class SpritePosition {
public:
explicit SpritePosition() {}
- explicit SpritePosition(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint8_t pixelRatio = 1);
+ explicit SpritePosition(uint16_t x, uint16_t y, uint16_t width, uint16_t height, float pixelRatio = 1.0f);
operator bool() const {
return !(width == 0 && height == 0 && x == 0 && y == 0);
@@ -27,7 +27,7 @@ public:
uint16_t x = 0, y = 0;
uint16_t width = 0, height = 0;
- uint8_t pixelRatio = 1;
+ float pixelRatio = 1.0f;
};
class Sprite : public std::enable_shared_from_this<Sprite>, private util::noncopyable {
diff --git a/include/mbgl/map/tile_data.hpp b/include/mbgl/map/tile_data.hpp
index 9bc76727a1..9aaef84e04 100644
--- a/include/mbgl/map/tile_data.hpp
+++ b/include/mbgl/map/tile_data.hpp
@@ -71,9 +71,6 @@ protected:
public:
const SourceInfo &source;
- // Request-related information.
- const std::string url;
-
protected:
std::weak_ptr<platform::Request> req;
std::string data;
diff --git a/include/mbgl/style/style_source.hpp b/include/mbgl/style/style_source.hpp
index fa5c8dfb34..b598550c65 100644
--- a/include/mbgl/style/style_source.hpp
+++ b/include/mbgl/style/style_source.hpp
@@ -4,6 +4,10 @@
#include <mbgl/style/types.hpp>
#include <memory>
+#include <vector>
+#include <string>
+
+#include <rapidjson/document.h>
namespace mbgl {
@@ -11,27 +15,32 @@ class Source;
class SourceInfo {
public:
- const SourceType type;
- const std::string url;
- const uint32_t tile_size;
- const int32_t min_zoom;
- const int32_t max_zoom;
-
- SourceInfo(SourceType type = SourceType::Vector, const std::string &url = "",
- uint32_t tile_size = 512, int32_t min_zoom = 0, int32_t max_zoom = 22)
- : type(type), url(url), tile_size(tile_size), min_zoom(min_zoom), max_zoom(max_zoom) {}
+ SourceType type = SourceType::Vector;
+ std::string url;
+ std::vector<std::string> tiles;
+ uint16_t tile_size = 512;
+ uint16_t min_zoom = 0;
+ uint16_t max_zoom = 22;
+ std::string attribution;
+ std::array<float, 3> center = {{0, 0, 0}};
+ std::array<float, 4> bounds = {{-180, -90, 180, 90}};
+
+ void parseTileJSONProperties(const rapidjson::Value&);
};
-class StyleSource {
+class StyleSource : public std::enable_shared_from_this<StyleSource> {
public:
- const SourceInfo info;
+ SourceInfo info;
bool enabled = false;
std::shared_ptr<Source> source;
- StyleSource(const SourceInfo &info) : info(info) {}
+ StyleSource(const SourceInfo &info)
+ : info(info)
+ {}
};
+
}
#endif
diff --git a/include/mbgl/text/collision.hpp b/include/mbgl/text/collision.hpp
index 7e65e979da..8eec30f216 100644
--- a/include/mbgl/text/collision.hpp
+++ b/include/mbgl/text/collision.hpp
@@ -5,8 +5,9 @@
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
+#ifdef __clang__
#pragma GCC diagnostic ignored "-Wdeprecated-register"
-#ifndef __clang__
+#else
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#endif
diff --git a/include/mbgl/text/types.hpp b/include/mbgl/text/types.hpp
index e2539bff62..dbb483ea8f 100644
--- a/include/mbgl/text/types.hpp
+++ b/include/mbgl/text/types.hpp
@@ -101,7 +101,7 @@ struct PlacementProperty {
: zoom(zoom), rotationRange(rotationRange) {}
inline operator bool() const {
- return !isnan(zoom) && zoom != std::numeric_limits<float>::infinity() &&
+ return !std::isnan(zoom) && zoom != std::numeric_limits<float>::infinity() &&
rotationRange[0] != rotationRange[1];
}
diff --git a/include/mbgl/util/mapbox.hpp b/include/mbgl/util/mapbox.hpp
new file mode 100644
index 0000000000..0fbb9a91ed
--- /dev/null
+++ b/include/mbgl/util/mapbox.hpp
@@ -0,0 +1,17 @@
+#ifndef MBGL_UTIL_MAPBOX
+#define MBGL_UTIL_MAPBOX
+
+#include <string>
+
+namespace mbgl {
+namespace util {
+namespace mapbox {
+
+std::string normalizeSourceURL(const std::string& url, const std::string& accessToken);
+std::string normalizeGlyphsURL(const std::string& url, const std::string& accessToken);
+
+}
+}
+}
+
+#endif
diff --git a/include/mbgl/util/threadpool.hpp b/include/mbgl/util/threadpool.hpp
deleted file mode 100644
index 497d4e3083..0000000000
--- a/include/mbgl/util/threadpool.hpp
+++ /dev/null
@@ -1,45 +0,0 @@
-#ifndef MBGL_UTIL_THREADPOOL
-#define MBGL_UTIL_THREADPOOL
-
-#include <pthread.h>
-#include <forward_list>
-#include <queue>
-
-namespace mbgl {
-namespace util {
-
-class Threadpool {
-private:
- class Worker {
- public:
- Worker(Threadpool& pool);
- ~Worker();
- static void *loop(void *ptr);
-
- private:
- Threadpool& pool;
- pthread_t thread;
- };
-
-public:
- Threadpool(int max_workers = 4);
- typedef void (*Callback)(void *);
- void add(Callback callback, void *data);
-
-private:
- typedef std::pair<Callback, void *> Task;
- const int max_workers;
- pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
- pthread_cond_t condition = PTHREAD_COND_INITIALIZER;
- std::forward_list<Worker> workers;
- int worker_count = 0;
- std::queue<Task> tasks;
-};
-
-extern std::unique_ptr<Threadpool> threadpool;
-
-}
-}
-
-#endif
-
diff --git a/include/mbgl/util/url.hpp b/include/mbgl/util/url.hpp
new file mode 100644
index 0000000000..14d9dd3160
--- /dev/null
+++ b/include/mbgl/util/url.hpp
@@ -0,0 +1,14 @@
+#ifndef MBGL_UTIL_URL
+#define MBGL_UTIL_URL
+
+#include <string>
+
+namespace mbgl {
+namespace util {
+
+std::string percentEncode(const std::string&);
+
+}
+}
+
+#endif
diff --git a/include/mbgl/util/utf.hpp b/include/mbgl/util/utf.hpp
index 5dfc4ad2d1..bb63179123 100644
--- a/include/mbgl/util/utf.hpp
+++ b/include/mbgl/util/utf.hpp
@@ -4,14 +4,13 @@
#include <memory>
// g++/libstdc++ is missing c++11 codecvt support
-#ifdef __linux__
+#if ! defined(__clang__) || defined(__linux__)
#pragma GCC diagnostic push
-#ifndef __clang__
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
-#endif
#include <boost/locale.hpp>
#pragma GCC diagnostic pop
#else
+// Assume that codecvt is present on clang on non-linux systems
#include <codecvt>
#include <locale>
#endif
@@ -20,7 +19,7 @@ namespace mbgl {
namespace util {
-#ifdef __linux__
+#if ! defined(__clang__) || defined(__linux__)
class utf8_to_utf32 {
public:
diff --git a/include/mbgl/util/vec.hpp b/include/mbgl/util/vec.hpp
index 0b9bf63d53..a5fbee477b 100644
--- a/include/mbgl/util/vec.hpp
+++ b/include/mbgl/util/vec.hpp
@@ -71,7 +71,7 @@ struct vec2 {
template<typename U = T, typename std::enable_if<std::numeric_limits<U>::has_quiet_NaN, int>::type = 0>
inline operator bool() const {
- return !isnan(x) && !isnan(y);
+ return !std::isnan(x) && !std::isnan(y);
}
template<typename U = T, typename std::enable_if<!std::numeric_limits<U>::has_quiet_NaN, int>::type = 0>
diff --git a/scripts/travis_script.sh b/scripts/travis_script.sh
index 4f02c5b7e5..a13d7531eb 100755
--- a/scripts/travis_script.sh
+++ b/scripts/travis_script.sh
@@ -10,7 +10,8 @@ if [[ ${TRAVIS_OS_NAME} == "linux" ]]; then
make linux -j4 BUILDTYPE=${BUILDTYPE}
make test -j4 BUILDTYPE=${BUILDTYPE}
./scripts/run_tests.sh
- (cd ./node_modules/mapbox-gl-test-suite/ && (./bin/compare_images.js || true; ./bin/deploy_results.sh))
+ (cd ./node_modules/mapbox-gl-test-suite/ && (./bin/compare_images.js || true; [[ $TRAVIS_PULL_REQUEST = "false" ]] && ./bin/deploy_results.sh))
+
elif [[ ${TRAVIS_OS_NAME} == "osx" ]]; then
#
# build OS X
diff --git a/setup-libraries.sh b/setup-libraries.sh
index 9c83595a37..93107817fc 100755
--- a/setup-libraries.sh
+++ b/setup-libraries.sh
@@ -112,9 +112,9 @@ source MacOSX.sh
./scripts/make_universal.sh
-if [ ! -z "${TRAVIS:-}" ]; then
+if [[ $TRAVIS_PULL_REQUEST = "false" ]]; then
tar -zcf out/build-cpp11-libcpp-universal_${MP_HASH}.tar.gz out/build-cpp11-libcpp-universal
- aws s3 cp out/build-cpp11-libcpp-universal_${MP_HASH}.tar.gz s3://mapbox-gl-testing/dependencies/
+ aws s3 cp --acl public-read out/build-cpp11-libcpp-universal_${MP_HASH}.tar.gz s3://mapbox-gl-testing/dependencies/
fi
fi
@@ -143,10 +143,10 @@ source Linux.sh
if [ ! -f out/build-cpp11-libstdcpp-gcc-x86_64-linux/lib/libcurl.a ] ; then ./scripts/build_curl.sh ; fi
if [ ! -f out/build-cpp11-libstdcpp-gcc-x86_64-linux/lib/libboost_regex.a ] ; then ./scripts/build_boost.sh --with-regex ; fi
-if [ ! -z "${TRAVIS:-}" ]; then
+if [[ $TRAVIS_PULL_REQUEST = "false" ]]; then
if ! tar --compare -zf out/build-cpp11-libstdcpp-gcc-x86_64-linux.tar.gz ; then
tar -zcf out/build-cpp11-libstdcpp-gcc-x86_64-linux.tar.gz out/build-cpp11-libstdcpp-gcc-x86_64-linux
- aws s3 cp out/build-cpp11-libstdcpp-gcc-x86_64-linux.tar.gz s3://mapbox-gl-testing/dependencies/
+ aws s3 cp --acl public-read out/build-cpp11-libstdcpp-gcc-x86_64-linux.tar.gz s3://mapbox-gl-testing/dependencies/
fi
fi
diff --git a/src/map/map.cpp b/src/map/map.cpp
index d6597565b7..86f7f9812a 100644
--- a/src/map/map.cpp
+++ b/src/map/map.cpp
@@ -11,6 +11,7 @@
#include <mbgl/util/constants.hpp>
#include <mbgl/util/uv_detail.hpp>
#include <mbgl/util/std.hpp>
+#include <mbgl/util/mapbox.hpp>
#include <mbgl/style/style.hpp>
#include <mbgl/text/glyph_store.hpp>
#include <mbgl/geometry/glyph_atlas.hpp>
@@ -211,7 +212,7 @@ void Map::setStyleJSON(std::string newStyleJSON, const std::string &base) {
sprite.reset();
style->loadJSON((const uint8_t *)styleJSON.c_str());
fileSource->setBase(base);
- glyphStore->setURL(style->glyph_url);
+ glyphStore->setURL(util::mapbox::normalizeGlyphsURL(style->glyph_url, getAccessToken()));
update();
}
@@ -469,7 +470,8 @@ void Map::updateSources() {
for (const std::shared_ptr<StyleSource> &style_source : activeSources) {
if (style_source->enabled) {
if (!style_source->source) {
- style_source->source = std::make_shared<Source>(style_source->info, getAccessToken());
+ style_source->source = std::make_shared<Source>(style_source->info);
+ style_source->source->load(*this);
}
} else {
style_source->source.reset();
diff --git a/src/map/source.cpp b/src/map/source.cpp
index ecb0be8efa..3fe5bf42fa 100644
--- a/src/map/source.cpp
+++ b/src/map/source.cpp
@@ -6,40 +6,59 @@
#include <mbgl/util/raster.hpp>
#include <mbgl/util/string.hpp>
#include <mbgl/util/texturepool.hpp>
+#include <mbgl/util/filesource.hpp>
#include <mbgl/util/vec.hpp>
#include <mbgl/util/std.hpp>
+#include <mbgl/util/mapbox.hpp>
#include <mbgl/geometry/glyph_atlas.hpp>
#include <mbgl/style/style_layer.hpp>
-
+#include <mbgl/platform/log.hpp>
#include <mbgl/map/vector_tile_data.hpp>
#include <mbgl/map/raster_tile_data.hpp>
namespace mbgl {
-Source::Source(SourceInfo info, const std::string &access_token)
- : info(
- info.type,
- normalizeSourceURL(info.url, access_token),
- info.tile_size,
- info.min_zoom,
- info.max_zoom
- ) {}
-
-std::string Source::normalizeSourceURL(const std::string &url, const std::string &access_token) {
- const std::string t = "mapbox://";
- if (url.compare(0, t.length(), t) == 0) {
- if (access_token.empty()) {
- throw std::runtime_error("You must provide a Mapbox API access token for Mapbox tile sources");
- }
- return std::string("https://api.tiles.mapbox.com/v4/") + url.substr(t.length()) + "/{z}/{x}/{y}.vector.pbf?access_token=" + access_token;
- } else {
- return url;
+Source::Source(SourceInfo& info)
+ : info(info)
+{
+}
+
+// Note: This is a separate function that must be called exactly once after creation
+// The reason this isn't part of the constructor is that calling shared_from_this() in
+// the constructor fails.
+void Source::load(Map& map) {
+ if (info.url.empty()) {
+ loaded = true;
+ return;
}
+
+ std::string url = util::mapbox::normalizeSourceURL(info.url, map.getAccessToken());
+ std::shared_ptr<Source> source = shared_from_this();
+
+ map.getFileSource()->load(ResourceType::JSON, url, [source, &map](platform::Response *res) {
+ if (res->code != 200) {
+ Log::Warning(Event::General, "failed to load source TileJSON");
+ return;
+ }
+
+ rapidjson::Document d;
+ d.Parse<0>(res->body.c_str());
+
+ if (d.HasParseError()) {
+ Log::Warning(Event::General, "invalid source TileJSON");
+ return;
+ }
+
+ source->info.parseTileJSONProperties(d);
+ source->loaded = true;
+
+ map.update();
+ });
}
bool Source::update(Map &map) {
- if (map.getTime() > updated) {
+ if (loaded && map.getTime() > updated) {
return updateTiles(map);
} else {
return false;
diff --git a/src/map/sprite.cpp b/src/map/sprite.cpp
index 88e940c00e..a8f4f97185 100644
--- a/src/map/sprite.cpp
+++ b/src/map/sprite.cpp
@@ -13,7 +13,7 @@
using namespace mbgl;
-SpritePosition::SpritePosition(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint8_t pixelRatio)
+SpritePosition::SpritePosition(uint16_t x, uint16_t y, uint16_t width, uint16_t height, float pixelRatio)
: x(x),
y(y),
width(width),
@@ -122,7 +122,7 @@ void Sprite::parseJSON() {
uint16_t y = 0;
uint16_t width = 0;
uint16_t height = 0;
- uint8_t pixelRatio = 1;
+ float pixelRatio = 1.0f;
if (value.HasMember("x")) x = value["x"].GetInt();
if (value.HasMember("y")) y = value["y"].GetInt();
diff --git a/src/map/tile_data.cpp b/src/map/tile_data.cpp
index 4333e2d2fd..57afb8dadb 100644
--- a/src/map/tile_data.cpp
+++ b/src/map/tile_data.cpp
@@ -14,13 +14,6 @@ TileData::TileData(Tile::ID id, Map &map, const SourceInfo &source)
state(State::initial),
map(map),
source(source),
- url(util::replaceTokens(source.url, [&](const std::string &token) -> std::string {
- if (token == "z") return std::to_string(id.z);
- if (token == "x") return std::to_string(id.x);
- if (token == "y") return std::to_string(id.y);
- if (token == "ratio") return (map.getState().getPixelRatio() > 1.0 ? "@2x" : "");
- return "";
- })),
debugBucket(debugFontBuffer) {
// Initialize tile debug coordinates
const std::string str = util::sprintf<32>("%d/%d/%d", id.z, id.x, id.y);
@@ -36,11 +29,23 @@ const std::string TileData::toString() const {
}
void TileData::request() {
+ if (source.tiles.empty())
+ return;
+
+ std::string url = source.tiles[(id.x + id.y) % source.tiles.size()];
+ url = util::replaceTokens(url, [&](const std::string &token) -> std::string {
+ if (token == "z") return std::to_string(id.z);
+ if (token == "x") return std::to_string(id.x);
+ if (token == "y") return std::to_string(id.y);
+ if (token == "ratio") return (map.getState().getPixelRatio() > 1.0 ? "@2x" : "");
+ return "";
+ });
+
state = State::loading;
// Note: Somehow this feels slower than the change to request_http()
std::weak_ptr<TileData> weak_tile = shared_from_this();
- map.getFileSource()->load(ResourceType::Tile, url, [weak_tile](platform::Response *res) {
+ map.getFileSource()->load(ResourceType::Tile, url, [weak_tile, url](platform::Response *res) {
std::shared_ptr<TileData> tile = weak_tile.lock();
if (!tile || tile->state == State::obsolete) {
// noop. Tile is obsolete and we're now just waiting for the refcount
@@ -54,7 +59,7 @@ void TileData::request() {
tile->reparse();
} else {
#if defined(DEBUG)
- fprintf(stderr, "[%s] tile loading failed: %d, %s\n", tile->url.c_str(), res->code, res->error_message.c_str());
+ fprintf(stderr, "[%s] tile loading failed: %d, %s\n", url.c_str(), res->code, res->error_message.c_str());
#endif
}
});
diff --git a/src/renderer/symbol_bucket.cpp b/src/renderer/symbol_bucket.cpp
index e8c0fd1829..f953f0716e 100644
--- a/src/renderer/symbol_bucket.cpp
+++ b/src/renderer/symbol_bucket.cpp
@@ -296,7 +296,7 @@ void SymbolBucket::addFeature(const std::vector<Coordinate> &line, const Shaping
}
// Insert final placement into collision tree and add glyphs/icons to buffers
- if (glyphScale) {
+ if (glyphScale && std::isfinite(glyphScale)) {
if (!properties.text.ignore_placement) {
collision.insert(glyphPlacement.boxes, anchor, glyphScale, glyphRange,
horizontalText);
@@ -304,7 +304,7 @@ void SymbolBucket::addFeature(const std::vector<Coordinate> &line, const Shaping
if (inside) addSymbols(text, glyphPlacement.shapes, glyphScale, glyphRange);
}
- if (iconScale) {
+ if (iconScale && std::isfinite(iconScale)) {
if (!properties.icon.ignore_placement) {
collision.insert(iconPlacement.boxes, anchor, iconScale, iconRange, horizontalIcon);
}
diff --git a/src/style/style_parser.cpp b/src/style/style_parser.cpp
index c2689162e2..2fccf1f404 100644
--- a/src/style/style_parser.cpp
+++ b/src/style/style_parser.cpp
@@ -1,3 +1,4 @@
+#include <mbgl/style/style_source.hpp>
#include <mbgl/style/style_parser.hpp>
#include <mbgl/style/style_layer_group.hpp>
#include <mbgl/util/constants.hpp>
@@ -175,21 +176,14 @@ void StyleParser::parseSources(JSVal value) {
rapidjson::Value::ConstMemberIterator itr = value.MemberBegin();
for (; itr != value.MemberEnd(); ++itr) {
std::string name { itr->name.GetString(), itr->name.GetStringLength() };
- SourceType type = SourceType::Vector;
- std::string url;
- uint16_t tile_size = 512;
- int32_t min_zoom = 0;
- int32_t max_zoom = 22;
-
- parseRenderProperty<SourceTypeClass>(itr->value, type, "type");
- parseRenderProperty(itr->value, url, "url");
- if (type == SourceType::Raster) {
- parseRenderProperty(itr->value, tile_size, "tileSize");
- }
- parseRenderProperty(itr->value, min_zoom, "minZoom");
- parseRenderProperty(itr->value, max_zoom, "maxZoom");
+ SourceInfo info;
+
+ parseRenderProperty<SourceTypeClass>(itr->value, info.type, "type");
+ parseRenderProperty(itr->value, info.url, "url");
+ parseRenderProperty(itr->value, info.tile_size, "tileSize");
+ info.parseTileJSONProperties(itr->value);
- sources.emplace(std::move(name), std::make_shared<StyleSource>(SourceInfo { type, url, tile_size, min_zoom, max_zoom }));
+ sources.emplace(std::move(name), std::make_shared<StyleSource>(info));
}
} else {
Log::Warning(Event::ParseStyle, "sources must be an object");
diff --git a/src/style/style_source.cpp b/src/style/style_source.cpp
new file mode 100644
index 0000000000..f46a6fb09b
--- /dev/null
+++ b/src/style/style_source.cpp
@@ -0,0 +1,77 @@
+#include <mbgl/style/style_source.hpp>
+#include <mbgl/platform/platform.hpp>
+#include <mbgl/platform/log.hpp>
+
+#include <limits>
+
+namespace mbgl {
+
+void parse(const rapidjson::Value& value, std::vector<std::string>& target, const char *name) {
+ if (!value.HasMember(name))
+ return;
+
+ const rapidjson::Value& property = value[name];
+ if (!property.IsArray())
+ return;
+
+ for (rapidjson::SizeType i = 0; i < property.Size(); i++)
+ if (!property[i].IsString())
+ return;
+
+ for (rapidjson::SizeType i = 0; i < property.Size(); i++)
+ target.emplace_back(std::string(property[i].GetString(), property[i].GetStringLength()));
+}
+
+void parse(const rapidjson::Value& value, std::string& target, const char* name) {
+ if (!value.HasMember(name))
+ return;
+
+ const rapidjson::Value& property = value[name];
+ if (!property.IsString())
+ return;
+
+ target = { property.GetString(), property.GetStringLength() };
+}
+
+void parse(const rapidjson::Value& value, uint16_t& target, const char* name) {
+ if (!value.HasMember(name))
+ return;
+
+ const rapidjson::Value& property = value[name];
+ if (!property.IsUint())
+ return;
+
+ unsigned int uint = property.GetUint();
+ if (uint > std::numeric_limits<uint16_t>::max())
+ return;
+
+ target = uint;
+}
+
+template <size_t N>
+void parse(const rapidjson::Value& value, std::array<float, N>& target, const char* name) {
+ if (!value.HasMember(name))
+ return;
+
+ const rapidjson::Value& property = value[name];
+ if (!property.IsArray() || property.Size() != N)
+ return;
+
+ for (rapidjson::SizeType i = 0; i < property.Size(); i++)
+ if (!property[i].IsNumber())
+ return;
+
+ for (rapidjson::SizeType i = 0; i < property.Size(); i++)
+ target[i] = property[i].GetDouble();
+}
+
+void SourceInfo::parseTileJSONProperties(const rapidjson::Value& value) {
+ parse(value, tiles, "tiles");
+ parse(value, min_zoom, "minzoom");
+ parse(value, max_zoom, "maxzoom");
+ parse(value, attribution, "attribution");
+ parse(value, center, "center");
+ parse(value, bounds, "bounds");
+}
+
+}
diff --git a/src/text/collision.cpp b/src/text/collision.cpp
index 89e91d6844..6326bea825 100644
--- a/src/text/collision.cpp
+++ b/src/text/collision.cpp
@@ -166,10 +166,10 @@ float Collision::getPlacementScale(const GlyphBoxes &glyphs, float minPlacementS
float s4 = (ob.br.y - nb.tl.y + padding) /
(na.y - oa.y); // scale at which new box is to the bottom of old box
- if (isnan(s1) || isnan(s2)) {
+ if (std::isnan(s1) || std::isnan(s2)) {
s1 = s2 = 1;
}
- if (isnan(s3) || isnan(s4)) {
+ if (std::isnan(s3) || std::isnan(s4)) {
s3 = s4 = 1;
}
diff --git a/src/text/glyph_store.cpp b/src/text/glyph_store.cpp
index 09f2fbc7b3..65941e91f7 100644
--- a/src/text/glyph_store.cpp
+++ b/src/text/glyph_store.cpp
@@ -4,6 +4,7 @@
#include <mbgl/util/string.hpp>
#include <mbgl/util/utf.hpp>
#include <mbgl/util/pbf.hpp>
+#include <mbgl/util/url.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/util/token.hpp>
#include <mbgl/util/math.hpp>
@@ -141,14 +142,11 @@ GlyphPBF::GlyphPBF(const std::string &glyphURL, const std::string &fontStack, Gl
{
// Load the glyph set URL
std::string url = util::replaceTokens(glyphURL, [&](const std::string &name) -> std::string {
- if (name == "fontstack") return fontStack;
+ if (name == "fontstack") return util::percentEncode(fontStack);
if (name == "range") return std::to_string(glyphRange.first) + "-" + std::to_string(glyphRange.second);
return "";
});
- // TODO: Find more reliable URL normalization function
- std::replace(url.begin(), url.end(), ' ', '+');
-
#if defined(DEBUG)
fprintf(stderr, "%s\n", url.c_str());
#endif
diff --git a/src/text/rotation_range.cpp b/src/text/rotation_range.cpp
index 3ebdfe91cb..664ea9c709 100644
--- a/src/text/rotation_range.cpp
+++ b/src/text/rotation_range.cpp
@@ -95,7 +95,7 @@ rotatingRotatingCollisions(const CollisionRect &a, const CollisionRect &b,
std::vector<float> f;
for (size_t i = 0; i < c.size(); i++) {
// Check if they are close enough to collide
- if (!isnan(c[i]) && d_sq <= e[i]) {
+ if (!std::isnan(c[i]) && d_sq <= e[i]) {
// So far, angles have been calulated as relative to the vector
// between anchors.
// Convert the angles to angles from north.
diff --git a/src/util/mapbox.cpp b/src/util/mapbox.cpp
new file mode 100644
index 0000000000..277b647f34
--- /dev/null
+++ b/src/util/mapbox.cpp
@@ -0,0 +1,44 @@
+#include <mbgl/util/mapbox.hpp>
+
+#include <stdexcept>
+
+namespace mbgl {
+namespace util {
+namespace mapbox {
+
+const std::string mapbox = "mapbox://";
+
+std::string normalizeURL(const std::string& url, const std::string& accessToken) {
+ if (accessToken.empty())
+ throw std::runtime_error("You must provide a Mapbox API access token for Mapbox tile sources");
+
+ return std::string("https://api.tiles.mapbox.com/v4/")
+ + url.substr(mapbox.length())
+ + "?access_token="
+ + accessToken;
+}
+
+std::string normalizeSourceURL(const std::string& url, const std::string& accessToken) {
+ if (url.compare(0, mapbox.length(), mapbox) != 0)
+ return url;
+
+ std::string result = normalizeURL(url + ".json", accessToken);
+
+ // TileJSON requests need a secure flag appended to their URLs so
+ // that the server knows to send SSL-ified resource references.
+ if (url.compare(0, 5, "https") == 0)
+ result += "&secure";
+
+ return result;
+}
+
+std::string normalizeGlyphsURL(const std::string& url, const std::string& accessToken) {
+ if (url.compare(0, mapbox.length(), mapbox) != 0)
+ return url;
+
+ return normalizeURL(url, accessToken);
+}
+
+}
+}
+}
diff --git a/src/util/threadpool.cpp b/src/util/threadpool.cpp
deleted file mode 100644
index f19032ee01..0000000000
--- a/src/util/threadpool.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-#include <mbgl/util/threadpool.hpp>
-#include <mbgl/util/std.hpp>
-#include <thread>
-#include <memory>
-
-using namespace mbgl::util;
-
-std::unique_ptr<Threadpool> mbgl::util::threadpool = std::make_unique<Threadpool>(std::thread::hardware_concurrency());
-
-Threadpool::Threadpool(int max_workers)
- : max_workers(max_workers) {
-}
-
-void Threadpool::add(Callback callback, void *data) {
- if (worker_count < max_workers) {
- worker_count++;
- workers.emplace_front(*this);
- }
-
- pthread_mutex_lock(&mutex);
- tasks.push(std::make_pair(callback, data));
- pthread_mutex_unlock(&mutex);
- pthread_cond_signal(&condition);
-}
-
-Threadpool::Worker::Worker(Threadpool& pool)
- : pool(pool) {
- pthread_create(&thread, nullptr, loop, (void *)this);
-}
-
-Threadpool::Worker::~Worker() {
- pthread_cancel(thread);
-}
-
-
-void *Threadpool::Worker::loop(void *ptr) {
- Worker *worker = static_cast<Worker *>(ptr);
- Threadpool& pool = worker->pool;
-
- pthread_mutex_lock(&pool.mutex);
- while (true) {
- if (pool.tasks.size()) {
- Threadpool::Task task = pool.tasks.front();
- pool.tasks.pop();
- pthread_mutex_unlock(&pool.mutex);
- task.first(task.second);
- pthread_mutex_lock(&pool.mutex);
- } else {
- pthread_cond_wait(&pool.condition, &pool.mutex);
- }
- }
-
- return nullptr;
-}
diff --git a/src/util/url.cpp b/src/util/url.cpp
new file mode 100644
index 0000000000..b1a721d860
--- /dev/null
+++ b/src/util/url.cpp
@@ -0,0 +1,29 @@
+#include <mbgl/util/url.hpp>
+
+#include <cctype>
+#include <iomanip>
+#include <sstream>
+#include <string>
+
+namespace mbgl {
+namespace util {
+
+std::string percentEncode(const std::string& input) {
+ std::ostringstream encoded;
+
+ encoded.fill('0');
+ encoded << std::hex;
+
+ for (auto c : input) {
+ if (std::isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') {
+ encoded << c;
+ } else {
+ encoded << '%' << std::setw(2) << int(c);
+ }
+ }
+
+ return encoded.str();
+}
+
+}
+}
diff --git a/styles/bright/style.json b/styles/bright/style.json
index d132efe982..917244648c 100644
--- a/styles/bright/style.json
+++ b/styles/bright/style.json
@@ -1,7 +1,7 @@
{
"version": 4,
"sprite": "img/sprite",
- "glyphs": "https://mapbox.s3.amazonaws.com/gl-glyphs-256/{fontstack}/{range}.pbf",
+ "glyphs": "mapbox://fontstack/{fontstack}/{range}.pbf",
"constants": {
"@name": "{name_en}",
"@sans": "Open Sans Regular, Arial Unicode MS Regular",
diff --git a/styles/outdoors/style.json b/styles/outdoors/style.json
index 9abf917868..a9085c17d0 100644
--- a/styles/outdoors/style.json
+++ b/styles/outdoors/style.json
@@ -1,7 +1,7 @@
{
"version": 4,
"sprite": "https://www.mapbox.com/mapbox-gl-styles/sprites/outdoors",
- "glyphs": "https://mapbox.s3.amazonaws.com/gl-glyphs-256/{fontstack}/{range}.pbf",
+ "glyphs": "mapbox://fontstack/{fontstack}/{range}.pbf",
"constants": {
"@land": "rgb(244,239,225)",
"@water": "#cdd",
diff --git a/test/headless.cpp b/test/headless.cpp
index bd84e37681..a2f58e98d9 100644
--- a/test/headless.cpp
+++ b/test/headless.cpp
@@ -47,7 +47,7 @@ TEST_P(HeadlessTest, render) {
ResolveLocalURL(styleDoc["sprite"], styleDoc);
}
- ResolveLocalURL(styleDoc["sources"]["mapbox"]["url"], styleDoc);
+ ResolveLocalURL(styleDoc["sources"]["mapbox"]["tiles"][rapidjson::SizeType(0)], styleDoc);
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);