From e97662972fef0e56132a03f2c2510c0da8537aad Mon Sep 17 00:00:00 2001 From: Lucas Wojciechowski Date: Thu, 20 Aug 2015 15:50:39 -0700 Subject: [PATCH] Support v8 sprite, glyph, and style mapbox:// urls --- include/mbgl/storage/resource.hpp | 4 +- platform/default/sqlite_cache.cpp | 2 +- src/mbgl/map/sprite.cpp | 5 +- src/mbgl/storage/default_file_source.cpp | 5 ++ src/mbgl/util/mapbox.cpp | 83 ++++++++++++++++-------- src/mbgl/util/mapbox.hpp | 1 + test/miscellaneous/mapbox.cpp | 16 +++-- 7 files changed, 81 insertions(+), 35 deletions(-) diff --git a/include/mbgl/storage/resource.hpp b/include/mbgl/storage/resource.hpp index 2fcb3b1b7..0c2a27e9d 100644 --- a/include/mbgl/storage/resource.hpp +++ b/include/mbgl/storage/resource.hpp @@ -13,8 +13,8 @@ struct Resource { Source, Tile, Glyphs, - JSON, - Image + SpriteImage, + SpriteJSON }; const Kind kind; diff --git a/platform/default/sqlite_cache.cpp b/platform/default/sqlite_cache.cpp index 775c2a68a..9d5d0541e 100644 --- a/platform/default/sqlite_cache.cpp +++ b/platform/default/sqlite_cache.cpp @@ -217,7 +217,7 @@ void SQLiteCache::Impl::put(const Resource& resource, std::shared_ptrbind(6 /* expires */, response->expires); std::string data; - if (resource.kind != Resource::Image) { + if (resource.kind != Resource::SpriteImage) { // Do not compress images, since they are typically compressed already. data = util::compress(response->data); } diff --git a/src/mbgl/map/sprite.cpp b/src/mbgl/map/sprite.cpp index 84fbce606..d5628b05b 100644 --- a/src/mbgl/map/sprite.cpp +++ b/src/mbgl/map/sprite.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include @@ -49,7 +50,7 @@ Sprite::Sprite(const std::string& baseUrl, float pixelRatio_) loader = std::make_unique(); FileSource* fs = util::ThreadContext::getFileSource(); - loader->jsonRequest = fs->request({ Resource::Kind::JSON, jsonURL }, util::RunLoop::getLoop(), + loader->jsonRequest = fs->request({ Resource::Kind::SpriteJSON, jsonURL }, util::RunLoop::getLoop(), [this, jsonURL](const Response& res) { loader->jsonRequest = nullptr; if (res.status == Response::Successful) { @@ -65,7 +66,7 @@ Sprite::Sprite(const std::string& baseUrl, float pixelRatio_) }); loader->spriteRequest = - fs->request({ Resource::Kind::Image, spriteURL }, util::RunLoop::getLoop(), + fs->request({ Resource::Kind::SpriteImage, spriteURL }, util::RunLoop::getLoop(), [this, spriteURL](const Response& res) { loader->spriteRequest = nullptr; if (res.status == Response::Successful) { diff --git a/src/mbgl/storage/default_file_source.cpp b/src/mbgl/storage/default_file_source.cpp index 12db28c98..c33728db1 100644 --- a/src/mbgl/storage/default_file_source.cpp +++ b/src/mbgl/storage/default_file_source.cpp @@ -55,6 +55,11 @@ Request* DefaultFileSource::request(const Resource& resource, url = util::mapbox::normalizeGlyphsURL(resource.url, accessToken); break; + case Resource::Kind::SpriteImage: + case Resource::Kind::SpriteJSON: + url = util::mapbox::normalizeSpriteURL(resource.url, accessToken); + break; + default: url = resource.url; } diff --git a/src/mbgl/util/mapbox.cpp b/src/mbgl/util/mapbox.cpp index 05e778dfb..dee0e0f8f 100644 --- a/src/mbgl/util/mapbox.cpp +++ b/src/mbgl/util/mapbox.cpp @@ -1,59 +1,90 @@ #include #include +#include namespace mbgl { namespace util { namespace mapbox { -const std::string mapbox = "mapbox://"; +const std::string protocol = "mapbox://"; +const std::string baseURL = "https://api.mapbox.com/"; -std::string normalizeURL(const std::string& url, const std::string& pathPrefix, const std::string& accessToken) { - if (accessToken.empty()) - throw std::runtime_error("You must provide a Mapbox API access token for Mapbox tile sources"); +bool isMapboxURL(const std::string& url) { + return url.compare(0, protocol.length(), protocol) == 0; +} - return std::string("https://api.tiles.mapbox.com") - + pathPrefix - + url.substr(mapbox.length()) - + "?access_token=" - + accessToken; +std::vector getMapboxURLPathname(const std::string& url) { + std::vector pathname; + std::size_t startIndex = protocol.length(); + while (startIndex < url.length()) { + std::size_t endIndex = url.find("/", startIndex); + if (endIndex == std::string::npos) endIndex = url.length(); + pathname.push_back(url.substr(startIndex, endIndex - startIndex)); + startIndex = endIndex + 1; + } + return pathname; } std::string normalizeSourceURL(const std::string& url, const std::string& accessToken) { - if (url.compare(0, mapbox.length(), mapbox) != 0) + if (!isMapboxURL(url)) { return url; + } - std::string result = normalizeURL(url + ".json", "/v4/", accessToken); + if (accessToken.empty()) { + throw std::runtime_error("You must provide a Mapbox API access token for Mapbox tile sources"); + } - // TileJSON requests need a secure flag appended to their URLs so - // that the server knows to send SSL-ified resource references. - result += "&secure"; - - return result; + return baseURL + "v4/" + url.substr(protocol.length()) + ".json?access_token=" + accessToken + "&secure"; } std::string normalizeStyleURL(const std::string& url, const std::string& accessToken) { - if (url.compare(0, mapbox.length(), mapbox) != 0) + if (!isMapboxURL(url)) { return url; + } - const std::string user = url.substr(mapbox.length(), url.find('.') - mapbox.length()); + std::vector pathname = getMapboxURLPathname(url); + std::string user = pathname[1]; + std::string id = pathname[2]; + bool isDraft = pathname.size() > 3; + return baseURL + "styles/v1/" + user + "/" + id + (isDraft ? "/draft" : "") + "?access_token=" + accessToken; +} - return normalizeURL(url, "/styles/v1/" + user + "/", accessToken); +std::string normalizeSpriteURL(const std::string& url, const std::string& accessToken) { + if (!isMapboxURL(url)) { + return url; + } + + std::vector pathname = getMapboxURLPathname(url); + std::string user = pathname[1]; + bool isDraft = pathname.size() > 3; + + std::string id, extension; + if (isDraft) { + size_t index = pathname[3].find_first_of("@."); + id = pathname[2]; + extension = pathname[3].substr(index); + } else { + size_t index = pathname[2].find_first_of("@."); + id = pathname[2].substr(0, index); + extension = pathname[2].substr(index); + } + + return baseURL + "styles/v1/" + user + "/" + id + "/" + (isDraft ? "draft/" : "") + "sprite" + extension + "?access_token=" + accessToken; } std::string normalizeGlyphsURL(const std::string& url, const std::string& accessToken) { - if (url.compare(0, mapbox.length(), mapbox) != 0) { + if (!isMapboxURL(url)) { return url; - } else { - const std::string prefix = "mapbox://fonts/"; - const std::string user = url.substr(prefix.length(), url.find("/", prefix.length()) - prefix.length()); - return normalizeURL("mapbox://" + user + "/{fontstack}/{range}.pbf", "/fonts/v1/", accessToken); } + + std::vector pathname = getMapboxURLPathname(url); + std::string user = pathname[1]; + return baseURL + "fonts/v1/" + user + "/{fontstack}/{range}.pbf?access_token=" + accessToken; } std::string normalizeTileURL(const std::string& url, const std::string& sourceURL, SourceType sourceType) { - if (sourceURL.empty() || sourceURL.compare(0, mapbox.length(), mapbox) != 0 || - sourceType != SourceType::Raster) { + if (sourceURL.empty() || !isMapboxURL(sourceURL) || sourceType != SourceType::Raster) { return url; } diff --git a/src/mbgl/util/mapbox.hpp b/src/mbgl/util/mapbox.hpp index 86ea349b8..9c24dda0e 100644 --- a/src/mbgl/util/mapbox.hpp +++ b/src/mbgl/util/mapbox.hpp @@ -10,6 +10,7 @@ namespace mapbox { std::string normalizeSourceURL(const std::string& url, const std::string& accessToken); std::string normalizeStyleURL(const std::string& url, const std::string& accessToken); +std::string normalizeSpriteURL(const std::string& url, const std::string& accessToken); std::string normalizeGlyphsURL(const std::string& url, const std::string& accessToken); std::string normalizeTileURL(const std::string& url, const std::string& sourceURL, SourceType sourceType); diff --git a/test/miscellaneous/mapbox.cpp b/test/miscellaneous/mapbox.cpp index 1030dc6eb..f1febd729 100644 --- a/test/miscellaneous/mapbox.cpp +++ b/test/miscellaneous/mapbox.cpp @@ -8,21 +8,29 @@ using namespace mbgl; TEST(Mapbox, SourceURL) { - EXPECT_EQ(mbgl::util::mapbox::normalizeSourceURL("mapbox://user.map", "key"), "https://api.tiles.mapbox.com/v4/user.map.json?access_token=key&secure"); - EXPECT_EQ(mbgl::util::mapbox::normalizeSourceURL("mapbox://user.map", "token"), "https://api.tiles.mapbox.com/v4/user.map.json?access_token=token&secure"); + EXPECT_EQ(mbgl::util::mapbox::normalizeSourceURL("mapbox://user.map", "key"), "https://api.mapbox.com/v4/user.map.json?access_token=key&secure"); + EXPECT_EQ(mbgl::util::mapbox::normalizeSourceURL("mapbox://user.map", "token"), "https://api.mapbox.com/v4/user.map.json?access_token=token&secure"); EXPECT_THROW(mbgl::util::mapbox::normalizeSourceURL("mapbox://user.map", ""), std::runtime_error); } TEST(Mapbox, GlyphsURL) { - EXPECT_EQ(mbgl::util::mapbox::normalizeGlyphsURL("mapbox://fonts/boxmap/{fontstack}/{range}.pbf", "key"), "https://api.tiles.mapbox.com/fonts/v1/boxmap/{fontstack}/{range}.pbf?access_token=key"); + EXPECT_EQ(mbgl::util::mapbox::normalizeGlyphsURL("mapbox://fonts/boxmap/{fontstack}/{range}.pbf", "key"), "https://api.mapbox.com/fonts/v1/boxmap/{fontstack}/{range}.pbf?access_token=key"); EXPECT_EQ(mbgl::util::mapbox::normalizeGlyphsURL("http://path", "key"), "http://path"); } TEST(Mapbox, StyleURL) { - EXPECT_EQ(mbgl::util::mapbox::normalizeStyleURL("mapbox://user.style", "key"), "https://api.tiles.mapbox.com/styles/v1/user/user.style?access_token=key"); + EXPECT_EQ(mbgl::util::mapbox::normalizeStyleURL("mapbox://styles/user/style", "key"), "https://api.mapbox.com/styles/v1/user/style?access_token=key"); + EXPECT_EQ(mbgl::util::mapbox::normalizeStyleURL("mapbox://styles/user/style/draft", "key"), "https://api.mapbox.com/styles/v1/user/style/draft?access_token=key"); EXPECT_EQ(mbgl::util::mapbox::normalizeStyleURL("http://path", "key"), "http://path"); } +TEST(Mapbox, SpriteURL) { + EXPECT_EQ(mbgl::util::mapbox::normalizeSpriteURL("map/box/sprites@2x.json", "key"), "map/box/sprites@2x.json"); + EXPECT_EQ(mbgl::util::mapbox::normalizeSpriteURL("mapbox://sprites/mapbox/streets-v8.json", "key"), "https://api.mapbox.com/styles/v1/mapbox/streets-v8/sprite.json?access_token=key"); + EXPECT_EQ(mbgl::util::mapbox::normalizeSpriteURL("mapbox://sprites/mapbox/streets-v8@2x.png", "key"), "https://api.mapbox.com/styles/v1/mapbox/streets-v8/sprite@2x.png?access_token=key"); + EXPECT_EQ(mbgl::util::mapbox::normalizeSpriteURL("mapbox://sprites/mapbox/streets-v8/draft@2x.png", "key"), "https://api.mapbox.com/styles/v1/mapbox/streets-v8/draft/sprite@2x.png?access_token=key"); +} + TEST(Mapbox, TileURL) { try { EXPECT_EQ(mbgl::util::mapbox::normalizeTileURL("http://path.png/tile.png", "mapbox://user.map", SourceType::Raster), "http://path.png/tile{ratio}.png");