diff options
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); |